使用Antlr中的访问者编辑AST

时间:2015-10-28 21:35:16

标签: java antlr antlr4 visitor

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

我想要做的是在我解析了一个源文件(当然我有一个有效的语法)并且我在内存中有AST时,去更改一些东西,然后通过访问者将其打印出来API。

e.g。

int foo() {
    y = x ? 1 : 2;
}

并将其转换为:

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中做这些事情,还是我的方向非常错误?

2 个答案:

答案 0 :(得分:0)

我会使用一个监听器,是的,您可以在浏览时修改AST。

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

答案 1 :(得分:0)

你可以通过粉碎AST节点和链接来做这个ANTLR。您将创建所有替换子树节点并将它们拼接到位。然后你将不得不实现“吐出源文本”树步行;我建议您为此目的调查“字符串模板”。

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

如果您想要做的是用另一套语法替换另一组语法,那么您真正想要的是program transformation system。这些工具旨在具有上述所有内置功能,因此您无需重新创建所有内置工具。它们通常还具有源到源的转换,这些转换使得完成的任务类似于您展示的任务,更容易实现。

要使用我们的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具有内置的prettyprinters来重新生成文本。关键点 所有这一切都是为了让你继续修改你的任务 代码,而不是在你可以之前创建一个全新的工程工作 做你的任务。请轻松阅读我的文章“解析后的生活” 通过我的生物或Google搜索找到有关此主题的更多信息。

[如果你去DMS wikipedia page,你会发现有趣的 这个变换的逆用作例子。