我有一个解析BASIC语言的antlr4语法文件。有没有办法在我的扩展baseListener类中插入更多的代码?
例如,如果我正在解析以下代码:
10 print "hello world"
%include "moreCode.bas"
print "after include"
moreCode.bas可能类似于:
for t% = 1% to 10%
print t%
next t%
我需要检测include命令,并将内容包含到正在遍历的文件中,然后作为一个整体继续遍历它。
所以我想,在侦听器类的enterIncludeCommand方法中,我会为moreCode.bas启动一个新的解析器,然后以某种方式将令牌/上下文插入到我当前的解析器中。
正确的方法是什么?
没有一个正确的模式。也就是说,一种有效的方法是让您的main启动解析器,方法是始终通过构造函数调用,该构造函数将状态对象和源路径作为参数
public class BasicParser {
public static void main(String[] args) {
...
StateModel state = new StateModel()
RecurseParser rp = new RecurseParser(state, pathname);
...
}
}
public class RecurseParser {
public RecurseParser(StateModel state, String pathname) {
this.state = state;
this.pathname = pathname; // source text to parse
...
}
public StateModel getResults() {
return this.state
}
在enterIncludeStatement
方法中,直接创建并运行一个新的RecurseParser实例。在exitIncludeStatement
中,检索新的当前状态,并根据需要验证/检查错误。
由于状态模型封装了符号表等,所以在森林中行走时可以保持连续性——递归实际上是免费的。
应该提到的是,相对于符号表,执行include本质上与调用子例程相同。
相关:符号表
我有两个解决方案,我选择了最后一个。格罗森伯格也有一个好主意。
1) 使用TokenStreamRewriter,并在enterIncludeStatement中使用重写器insertBefore、insertAfter和/或replace方法。在该特定侦听器对象的遍历结束时,调用重写器getText(),它将为您提供组合字符串。你必须重新分析该文本才能进入下一个监听器通道
2) 在侦听器类的enterIncludeStatement方法中,获取include文件名,在其上运行lexer/parser,然后获取第一个StatementContext(在我的情况下),并使用IncludeContext.AddChile(myStatement)将其注入当前树中。对include文件中的每个语句行进行循环。棘手的部分是将语句包含在正确的位置,但最终会得到一个完整的树,您可以在下一个监听器类阶段中使用它。
我使用了选项2,到目前为止它对我有效,但我不确定使用addChild方法是最好的方法,因为我真的插入了兄弟姐妹而不是孩子。考虑到这个兄弟姐妹/孩子的问题,也许grosenberg的递归想法是最好的。