2013-10-15 11 views
14

Come posso accedere ad etichette alternative in ANTLR4 mentre si attraversa genericamente un albero di analisi? Oppure, in alternativa, esiste un modo per replicare la funzionalità dell'operatore ^ di ANTLR3, in quanto tale sarebbe il trucco.Come posso accedere ad etichette alternative in ANTLR4 mentre si attraversa genericamente un albero di analisi?

Sto provando a scrivere una stampante AST carina per qualsiasi grammatica ANTLR4 aderente a una metodologia semplice (come denominare produzioni con etichette alternative). Mi piacerebbe essere in grado di stampare praticamente un termine come 3 + 5 come (int_expression (plus (int_literal 3) (int_literal 5))), o qualcosa di simile, data una grammatica come la seguente:

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

non sono in grado di dare in modo efficace i nomi alle plus e minus produzioni, perché estraendoli alla propria produzione fa sì che lo strumento si lamenti del fatto che le regole sono mutuamente ricorsive. Se non riesco a estrarli, come posso dare questi nomi alle produzioni?

Nota 1: Sono stato in grado di sbarazzarsi dell'argomento + metodologicamente mettendo terminali "buoni" (ad esempio, la Int sopra) in produzioni speciali (produzioni iniziano con un prefisso speciale, come raw_). Quindi potrei stampare solo quei terminali le cui produzioni parentali sono denominate "raw_ ..." ed elide tutte le altre. Questo ha funzionato alla grande per liberarsi di +, mantenendo 3 e 5 nell'output. Questo potrebbe essere fatto con un ! in ANTLR3.

Nota 2: Capisco che potrei scrivere una stampante carina specializzata o utilizzare azioni per ogni produzione di un determinato linguaggio, ma mi piacerebbe usare ANTLR4 per analizzare e generare AST per una varietà di lingue, e sembra come dovrei essere in grado di scrivere genericamente una stampante così semplice e carina. Detto in un altro modo, mi interessa solo ottenere AST, e preferirei non dover ingombrare ogni grammatica con una stampante carina su misura solo per ottenere un AST. Forse dovrei tornare su ANTLR3?

risposta

1

Suggerisco di implementare la bella stampante come implementazione di listener con una classe di visitatore annidata per ottenere i nomi dei vari oggetti di contesto.

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

Sto cercando un modo generico per farlo senza scrivere una stampante carina specializzata per ogni lingua. Non c'è modo di fare questo? Dal punto di vista dell'utente, non capisco perché non ci sia, dal momento che le etichette alternative sono proprio lì. –

Problemi correlati