我是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中做这些事情,还是我的方向非常错误?
答案 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,你会发现有趣的 这个变换的逆用作例子。