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