2013-10-15 12 views
14

Wie kann ich auf alternative Beschriftungen in ANTLR4 zugreifen, während generisch einen Parsebaum durchläuft? Oder gibt es alternativ eine Möglichkeit, die Funktionalität des ^-Operators von ANTLR3 zu replizieren, wie dies der Fall wäre.Wie kann ich auf alternative Beschriftungen in ANTLR4 zugreifen, während ein Parsebaum generisch durchlaufen wird?

Ich versuche, einen AST hübschen Drucker für jede ANTLR4 Grammatik zu schreiben, die einer einfachen Methodologie folgt (wie das Benennen von Produktionen mit alternativen Bezeichnungen). Ich möchte in der Lage sein, zu recht einen Begriff wie 3 + 5 als (int_expression (plus (int_literal 3) (int_literal 5))) zu drucken, oder etwas ähnliches, da eine Grammatik wie folgt aus:

int_expression 
    : int_expression '+' int_expression # plus 
    | int_expression '-' int_expression # minus 
    | raw_int       # int_literal 
    ; 
raw_int 
    : Int 
    ; 
Int : [0-9]+ ; 

ich nicht in der Lage bin, um effektiv Namen zu den plus und minus Produktionen zu geben, denn Wenn man sie in ihre eigene Produktion zieht, beschwört das Werkzeug, dass die Regeln gegenseitig rekursiv sind. Wenn ich sie nicht herausziehen kann, wie kann ich diesen Produktionen Namen geben?

Anmerkung 1: Ich war in der Lage methodologisch das + Arguments, um loszuwerden, durch „gut“ Terminals setzen (beispielsweise die Int oben) in Sonderproduktionen (Produktionen mit einem speziellen Präfix beginnen, wie raw_). Dann könnte ich nur die Terminals drucken, deren Elternproduktionen den Namen "raw_ ..." haben und allen anderen Eliden. Dies funktionierte großartig, um + loszuwerden, während 3 und 5 in der Ausgabe gehalten werden. Dies könnte mit einem ! in ANTLR3 getan werden.

Hinweis 2: Ich verstehe, dass ich einen spezialisierten hübschen Drucker schreiben oder Aktionen für jede Produktion einer bestimmten Sprache verwenden könnte, aber ich möchte ANTLR4 verwenden, um ASTs für eine Vielzahl von Sprachen zu analysieren und zu generieren wie sollte ich in der Lage sein, einen solchen einfachen hübschen Drucker generisch zu schreiben. Anders gesagt, ich interessiere mich nur dafür, ASTs zu bekommen, und ich möchte lieber nicht jede Grammatik mit einem maßgeschneiderten hübschen Drucker belasten, nur um einen AST zu bekommen. Vielleicht sollte ich einfach zurück zu ANTLR3 gehen?

Antwort

1

Ich empfehle, den hübschen Drucker als Listener-Implementierung mit einer verschachtelten Besucherklasse zu implementieren, um die Namen der verschiedenen Kontextobjekte zu erhalten.

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

Ich bin auf der Suche nach einer allgemeinen Möglichkeit, dies zu tun, ohne einen spezialisierten hübschen Drucker für jede Sprache zu schreiben. Gibt es keine Möglichkeit, dies zu tun? Aus der Sicht des Benutzers verstehe ich nicht, warum nicht, da die alternativen Labels genau da sind. –