Chu*_*son 14 pretty-print abstract-syntax-tree antlr4
如何在通用遍历解析树的同时访问ANTLR4中的备用标签?或者,是否有任何方法可以复制^ANTLR3 的运算符的功能,因为这样可以解决问题.
我正在尝试为任何符合简单方法的ANTLR4语法编写AST漂亮的打印机(比如用替代标签命名产品).我希望能够打印出更漂亮的一个术语类似3 + 5的(int_expression (plus (int_literal 3) (int_literal 5))),或类似的东西,给出类似下面的语法:
int_expression
: int_expression '+' int_expression # plus
| int_expression '-' int_expression # minus
| raw_int # int_literal
;
raw_int
: Int
;
Int : [0-9]+ ;
Run Code Online (Sandbox Code Playgroud)
我无法有效地为制作plus和minus制作命名,因为将它们拉到自己的制作中会导致工具抱怨规则是相互左递归的.如果我不能把它们拉出来,我怎么能给这些作品命名呢?
注1:+通过将"好"终端(例如,Int上面的)放在特殊制作中(以特殊前缀开头的制作等raw_),我能够在方法论上摆脱论证.然后,我只能打印那些父作品被命名为" raw_......"而终止所有其他作品的终端.这非常适合摆脱+,同时保持3和5输出.这可以通过!ANTLR3完成.
注意2:我知道我可以编写一个专门的漂亮的打印机或为给定语言的每个产生使用动作,但我想使用ANTLR4来解析和生成各种语言的AST,看起来我应该是能够编写如此简单漂亮的打印机.换句话说,我只关心获得AST,而我宁愿不用每个语法来使用量身定制的漂亮打印机来获取AST.也许我应该回到ANTLR3?
我建议将漂亮的打印机实现为具有嵌套访问者类的侦听器实现,以获取各种上下文对象的名称。
private MyParser parser; // you'll have to assign this field
private StringBuilder builder = new StringBuilder();
@Override
public void enterEveryRule(@NotNull ParserRuleContext ctx) {
if (!builder.isEmpty()) {
builder.append(' ');
}
builder.append('(');
}
@Override
public void visitTerminalNode(@NotNull TerminalNode node) {
// TODO: print node text to builder
}
@Override
public void visitErrorNode(@NotNull TerminalNode node) {
// TODO: print node text to builder
}
@Override
public void exitEveryRule(@NotNull ParserRuleContext ctx) {
builder.append(')');
}
protected String getContextName(@NotNull ParserRuleContext ctx) {
return new ContextNameVisitor().visit(ctx);
}
protected class ContextNameVisitor extends MyParserBaseVisitor<String> {
@Override
public String visitChildren() {
return parser.getRuleNames()[ctx.getRuleIndex()];
}
@Override
public String visitPlus(@NotNull PlusContext ctx) {
return "plus";
}
@Override
public String visitMinus(@NotNull MinusContext ctx) {
return "minus";
}
@Override
public String visitInt_literal(@NotNull MinusContext ctx) {
return "int_literal";
}
}
Run Code Online (Sandbox Code Playgroud)