2010-04-26 6 views
8

Ich habe eine einfache Grammatik:ANTLR AST Regeln scheitern mit RewriteEmptyStreamException

grammar sample; 
options { output = AST; } 
assignment 
    : IDENT ':=' expr ';' 
    ; 
expr  
    : factor ('*' factor)* 
    ; 
factor 
    : primary ('+' primary)* 
    ; 
primary 
    : NUM 
    | '(' expr ')' 
    ; 
IDENT : ('a'..'z')+ ; 
NUM : ('0'..'9')+ ; 
WS : (' '|'\n'|'\t'|'\r')+ {$channel=HIDDEN;} ; 

Jetzt möchte ich einige Rewrite-Regeln fügen Sie ein AST zu erzeugen. Von dem, was ich habe online und in der Sprache Patterns Buch lesen, soll ich in der Lage sein, die Grammatik wie folgt zu ändern:

assignment 
    : IDENT ':=' expr ';' -> ^(':=' IDENT expr) 
    ; 
expr  
    : factor ('*' factor)* -> ^('*' factor+) 
    ; 
factor 
    : primary ('+' primary)* -> ^('+' primary+) 
    ; 
primary 
    : NUM 
    | '(' expr ')' -> ^(expr) 
    ; 

Aber es funktioniert nicht. Obwohl es kompiliert, wenn ich den Parser ausführen, erhalte ich einen RewriteEmptyStreamException Fehler. Hier wird es komisch.

Wenn ich die Pseudo-Token ADD und MULT definiere und sie anstelle der Tree-Node-Literale verwende, funktioniert es ohne Fehler.

tokens { ADD; MULT; } 

expr  
    : factor ('*' factor)* -> ^(MULT factor+) 
    ; 
factor 
    : primary ('+' primary)* -> ^(ADD primary+) 
    ; 

Alternativ kann, wenn ich den Knoten Suffix-Notation, wie es scheint auch zu funktionieren:

expr  
    : factor ('*'^ factor)* 
    ; 
factor 
    : primary ('+'^ primary)* 
    ; 

Ist diese Diskrepanz im Verhalten ein Fehler?

Antwort

10

Nein, kein Fehler, AFAIK. Nehmen Sie sich expr Regel zum Beispiel:

expr  
    : factor ('*' factor)* -> ^('*' factor+) 
    ; 

seit den * möglicherweise nicht vorhanden sein, sollte es auch nicht sein in Ihrem AST Rewrite-Regel. Also, das obige ist falsch und ANTLR beschwert sich ist korrekt.

Nun, wenn Sie eine imaginären Token wie MULT stattdessen einfügen:

expr  
    : factor ('*' factor)* -> ^(MULT factor+) 
    ; 

alles in Ordnung sind, da die Regel immer eine oder mehr factor ‚s produzieren.

Was Sie wahrscheinlich zu tun ist gemeint, so etwas wie dieses: Baum Bau von The Definitive ANTLR Reference:

expr  
    : (factor -> factor) ('*' f=factor -> ^('*' $expr $f))* 
    ; 

Auch Kapitel 7 sehen. Insbesondere die Absätze Regeln in Unterregeln umschreiben (Seite 173) und Referenzieren der vorherigen Regel ASTs in Rewrite-Regeln (Seite 174/175).

7

Falls Sie ein N-ary Baum für die ‚*‘ Operator mit allen Kindern auf der gleichen Ebene erzeugen möchten, können Sie dies tun:

expr 
    : (s=factor -> factor) (('*' factor)+ -> ^('*' $s factor+))? 
    ; 

Hier sind einige Beispiele dafür, was diese zurück:

Tokens: AST 
factor: factor 
factor '*' factor: ^('*' factor factor) 
factor '*' factor '*' factor: ^('*' factor factor factor) 

oben drittes Beispiel des Barts wird einen verschachtelten Baum, da das Ergebnis von $ expr für jede nachfolgende Iteration ist ein Knoten mit zwei Kindern, wie diese produziert:

factor * factor * factor: ^('*' factor ^('*' factor factor)) 

die Sie wahrscheinlich nicht brauchen, da die Multiplikation kommutativ ist.

+0

Danke eine Tonne @JoelPM. Genau das habe ich gesucht. Wir hatten ein Problem mit tief verschachtelten Baum- und Stapelüberläufen während der Auswertung.Dies gibt uns die Möglichkeit, einen N-ary-Baum zu erzeugen und die Baumtiefe drastisch zu reduzieren –