Java 在Antlr中使用访问者编辑AST

Java 在Antlr中使用访问者编辑AST,java,antlr,antlr4,visitor,Java,Antlr,Antlr4,Visitor,我是AntLR的新手,我正在努力做到以下几点: 我想做的是在我解析了一个源文件(当然我有一个有效的语法)并且在内存中有了AST之后,去修改一些东西,然后通过visitor API打印出来 e、 g 并将其转化为: int foo() { if (x) { y = 1; else { y = 2; } } 到目前为止,我有适当的语法来解析这种语法,并且我还创建了一些访问者方法,当我处于正确的位置时,这些方法会被调用。让我困惑的是,在访问期间,我

我是AntLR的新手,我正在努力做到以下几点:

我想做的是在我解析了一个源文件(当然我有一个有效的语法)并且在内存中有了AST之后,去修改一些东西,然后通过visitor API打印出来

e、 g

并将其转化为:

int foo() {
    if (x) {
       y = 1;
    else {
       y = 2;
    }
}
到目前为止,我有适当的语法来解析这种语法,并且我还创建了一些访问者方法,当我处于正确的位置时,这些方法会被调用。让我困惑的是,在访问期间,我无法更改文本

理想情况下,我想要这样的东西:

public Void visitTernExpr(SimpleCParser.TernExprContext ctx) { 
  ctx.setText("something");
  return null; 
}
在我的主要观点中,我想让不同的访问者来编辑这个AST,他们每个人都有自己的专长。像这样:

ANTLRInputStream input = new ANTLRInputStream(new FileInputStream(filename));
SimpleCLexer lexer = new SimpleCLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
SimpleCParser parser = new SimpleCParser(tokens);
ProgramContext ctx = parser.program();

MyChecker1 mc1 = new MyChecker1();
mc1.visit(ctx);
MyChecker2 mc2 = new MyChecker2();
mc1.visit(ctx);

ctx.printToFile("myfile");

在AntLR中有没有什么方法可以做这些事情,或者我走的方向非常错误?

我会使用一个侦听器,是的,您可以在遍历AST时修改它


您可以创建if/else上下文的新实例,然后用它替换三元运算符上下文。这是可能的,因为您有一个对规则父级的引用和一个广泛的API来处理每个规则子级。

您可以通过粉碎AST节点和链接来实现这一点。您将创建所有替换子树节点并将它们拼接到位。然后,您必须实现“spit源文本”树漫游;我建议您为此调查“字符串模板”

但最终你必须做很多工作才能达到这个效果。这是因为ANTLR工具的目标主要集中在“解析”上,而“解析”将其余部分推给您

如果您想要做的是用另一组语法替换一组语法,那么您真正想要的是一个。这些工具的设计目的是让上述所有功能都已经内置,这样您就不必重新设计。它们通常还有源代码到源代码的转换,这使得完成像您所展示的任务更加容易实现

为了使用我们的DMS程序转换引擎完成您的示例,您需要编写一个转换规则,然后应用它:

rule replace_ternary_assignment_by_ifthenelse
   (l: left_hand_side, c: expression, e1: expression, e2: expression):
       statement -> statement
    "\l = \c ? \e1 : \e2;"
=>  " if (\c)  \l = \e1; else \l = \e2 ";
DMS解析您的代码,构建AST,查找重写的匹配项,为您构建/拼接所有这些替换节点。最后 DMS有内置的预打印机来重新生成文本。重点 所有这些都是为了让你继续你的任务,修改你的 代码,而不是在您可以 完成你的任务。轻松阅读我的文章《解析后的生活》 通过我的个人简历或谷歌搜索找到更多关于此主题的信息

如果你去看电影,你会发现很有趣 此变换的逆变换用作示例]

rule replace_ternary_assignment_by_ifthenelse
   (l: left_hand_side, c: expression, e1: expression, e2: expression):
       statement -> statement
    "\l = \c ? \e1 : \e2;"
=>  " if (\c)  \l = \e1; else \l = \e2 ";