一般遍历解析树时,如何在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]+ ;
我无法有效地给
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";
}
}