我想支持类似于C ++使用ANTLR4进行预处理宏替换的功能,该功能要求解析器稍稍退出并重新扫描修改后的输入文件。
例如,在标准C ++中:
#define a(x) b(x+1)
#define b(x) cc(x)
#define p1 a
....
p1(p1);
在标准C ++预处理器中,标识符p1
将被a
替换为a(a)
,然后C ++预处理器仅重新扫描此特定行< / strong>查看是否应再次应用宏替换以将a(a)
转换为b(a+1)
,最后重新扫描该行以获取cc(a+1)
。
我可以在遍历解析树时使用TokenStreamRewriter
来实现ANTLR4的宏替换功能。但是在第一次用p1
替换a
之后,我需要保存修改后的输入文件并重新调用解析器来扫描整个输入文件并获取另一个解析树而不是仅重新扫描我已替换的行。是否有任何可能的方法将重新扫描限制为我修改的行(可能在运行中重新生成部分解析树)?输入文件很大,并且有很多这样的替换,在每次替换后重新扫描整个文件将是一个很好的性能问题。
Parser中是否有任何功能可以将解析回滚到以前的“保存点”?
答案 0 :(得分:5)
在ANTLR 4中,当你解析时,对输入进行大量操作已经太晚了。您需要通过以下方式之一实现此功能:
通过在将结果传递给ANTLR之前对输入进行外部预处理。这就是我们在自适应LL(*)研究论文中为C11语法报告的性能分析所做的工作。
使用自定义TokenStream
实现来预处理输入令牌,因此流的输入是在输入中找到的令牌,输出是准备好解析的预处理令牌流。
使用解析器执行预处理,然后将结果反馈给令牌流以进行语言解析(这主要是使用ANTLR本身实现上面的第1项)。
如果您发现您的方法相当简单并且认为它在其他语言中有用,我们将非常感激您是否能够尽最大努力将其记录下来并将其贡献给ANTLR项目。预处理是我不会考虑解决的一个领域(至少不是干净利落)。