Как я могу получить доступ к альтернативным меток в ANTLR4, в то время как в общем случае просматривает дерево разбора?

Как я могу получить доступ к альтернативным меток в ANTLR4, в то время как в общем случае просматривает дерево разбора? Или, альтернативно, есть ли способ воспроизвести функциональность оператора ^ ANTLR3, поскольку это могло бы сделать трюк.

Я пытаюсь написать симпатичный принтер AST для любой грамматики ANTLR4, придерживающейся простой методологии (например, названия игр с альтернативными метками). Я хотел бы иметь возможность напечатать такой термин, как 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_..." и elide все остальные. Это отлично работало для избавления от +, сохраняя 3 и 5 в выходе. Это можно сделать с помощью ! в ANTLR3.

Примечание 2: Я понимаю, что я мог написать специализированный симпатичный принтер или использовать действия для каждого выпуска данного языка, но я бы хотел использовать ANTLR4 для анализа и создания АСТ для разных языков, и это похоже на Я должен был бы написать такой простой симпатичный принтер в целом. С другой стороны, я забочусь только о получении АСТ, и я бы предпочел не обременять каждую грамматику специальным принтером, чтобы получить АСТ. Возможно, мне стоит вернуться к ANTLR3?

Ответы

Ответ 1

Я предлагаю реализовать симпатичный принтер как реализацию listener с вложенным классом посетителей, чтобы получить имена различных объектов контекста.

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";
    }
}