2016-12-23 4 views
0

In einem kleinen Test-Parser, den ich gerade geschrieben habe, stieß ich auf ein seltsames Problem, das ich nicht ganz verstehe.Antlr4 Parsing Inkonsistenz

es bis ins kleinste Beispiel Stripping das Problem zeigt, lassen Sie uns mit der folgenden Grammatik beginnen:

Testing.g4:

grammar Testing; 

cscript       // This is the construct I shortened 
    : (statement_list)* ; 

statement_list 
    : statement ';' statement_list? 
    | block 
    ; 

statement 
    : assignment_statement 
    ; 

block : '{' statement_list? '}' ; 

expression 
    : left=expression op=('*'|'/') right=expression    # arithmeticExpression 
    | left=expression op=('+'|'-') right=expression    # arithmeticExpression 
    | left=expression op=Comparison_operator right=expression # comparisonExpression 
    | ID               # variableValueExpression 
    | constant             # ignore // will be executed with the rule name 
    ; 

assignment_statement 
    : ID op=Assignment_operator expression 
    ; 

constant 
    : INT 
    | REAL; 

Assignment_operator : ('=' | '+=' | '-=') ; 

Comparison_operator : ('<' | '>' | '==' | '!=') ; 

Comment : '//' .*? '\n' -> skip; 

fragment NUM : [0-9]; 

INT : NUM+; 
REAL 
    : NUM* '.' NUM+ 
    | '.' NUM+ 
    | INT 
    ; 

ID : [a-zA-Z_] [a-zA-Z_0-9]*; 

WS : [ \t\r\n]+ -> skip; 

die Eingabe Mit

z = x + y; 

alles ist in Ordnung Wir erhalten einen Syntaxbaum, der von cscript zu statement_list, statement, assignment_statement, id und expression führt. Groß!

Nun, wenn ich die Möglichkeit hinzufügen, Variablen zu deklarieren, geht alles den Bach runter:

Dies ist die Änderung der Grammatik:

cscript 
    : (statement_list | variable_declaration ';')* ; 

variable_declaration 
    : type ID ('=' expression)? 
    ; 

type 
    : 'int' 
    | 'real' 
    ; 

statement_list 
    : statement ';' statement_list? 
    | block 
    ; 

statement 
    : assignment_statement 
    ; 

// (continue as before) 

Ganz plötzlich, der gleiche Test-Eingang wird fälschlicherweise in zwei statement_lists zerlegt, die jeweils zu einer Anweisung mit einer "missing;" - Warnung weitergeführt werden, wobei die erste zu einer unvollständigen assignment_statement von "z =" und die zweite zu einer unvollständigen assignment_statement "x +" geht.

Mein Versuch, den Parsing-Baum in Textform zu zeigen:

cscript 
    statement_list 
     statement 
      assignment_statement 
       'z' 
       '=' [marked as error] 
     [warning: missing ';'] 
    statement_list 
     statement 
      assignment_statement 
       'x' 
       '+' [marked as error] 
     'y' [marked as error] 
     ';' 

Kann mir jemand sagen, was das Problem ist? (Und wie man es beheben ;-)?)


Bearbeiten auf 2016.12.26, nachdem Mike Kommentar:

Nachdem alle impliziten Lexer Regeln mit ausdrücklichen Erklärungen zu ersetzen, ganz plötzlich , die Eingabe "z = x + y" hat funktioniert. (Daumen nach oben)

Das nächste, was ich tat, war mehr der ursprünglichen Beispiel die Wiederherstellung ich im Sinn hatte, und das Hinzufügen einer neuen Eingabezeile

int x = 22; 

mit dem Eingang (die vorher gearbeitet, aber tat nicht ins minimale Beispiel). Jetzt , dass Zeile fehlschlägt. Dies ist der -token Ausgang des Prüfstandes:

[@0,0:2='int',<4>,1:0] 
[@1,4:4='x',<22>,1:4] 
[@2,6:6='=',<1>,1:6] 
[@3,8:9='22',<20>,1:8] 
[@4,10:10=';',<12>,1:10] 
[@5,13:13='z',<22>,2:0] 
[@6,15:15='=',<1>,2:2] 
[@7,17:17='x',<22>,2:4] 
[@8,19:19='+',<18>,2:6] 
[@9,21:21='y',<22>,2:8] 
[@10,22:22=';',<12>,2:9] 
[@11,25:24='<EOF>',<-1>,3:0] 
line 1:6 mismatched input '=' expecting '=' 

Da das Problem im variable_declaration Teil zu sein schien, ich habe sogar versucht, diese in zwei Parsing-Regeln wie folgt aufgeteilt:

cscript 
    : (statement_list | variable_declaration_and_assignment SEMICOLON | variable_declaration SEMICOLON)* ; 

variable_declaration_and_assignment 
    : type ID EQUAL expression 
    ; 

variable_declaration 
    : type ID 
    ; 

Mit das Ergebnis:

line 1:6 no viable alternative at input 'intx=' 

Noch stecken :-( BTW: Splitting der "int x = 22;" in "int x;" und "x = 22;" funktioniert.Seufzer


Bearbeiten auf 2016.12.26, nächsten Kommentar Mike:

doppelt geprüft, und alles ist Lexer Regeln. Dennoch hat mich die Diskrepanz zwischen '=' und '=' (die ich leider nicht mehr rekonstruieren kann) auf die Idee gebracht, die Token-Typen zu überprüfen. Der aktuelle Status ist:

(Verkürzte Grammatik)

cscript 
    : (statement_list | variable_declaration)* ; 

... 

variable_declaration 
    : type ID (EQUAL expression)? SEMICOLON 
    ; 

... 

Assignment_operator : (EQUAL | PLUS_EQ | MINUS_EQ) ; 

// among others 
PLUS_EQ : '+='; 
MINUS_EQ : '-='; 
EQUAL: '='; 

... 

Verkürzte Ausgabe:

[@0,0:2='int',<4>,1:0] 
[@1,4:4='x',<22>,1:4] 
[@2,6:6='=',<1>,1:6] 
... 
line 1:6 mismatched input '=' expecting ';' 

Hier wird, wenn ich das richtig verstehe, ist die '=' analysiert Typ 1-Token, die - entsprechend der lexer.tokens-Ausgabe - ist Assignment_Operator, während die erwartete EQUAL wäre 13.

Könnte das das Problem sein?

+0

Seltsames Problem. Beginnen Sie damit, alle lexikalischen Elemente als Lexerregeln zu definieren. Keine impliziten Literale in Parser-Regeln. Lassen Sie dann Ihre gepufferte Token-Zeichenfolge alle gefundenen Token ('stream.fill()' und dann iterieren über 'stream.getTokens();' mit einem token.toString() -Aufruf. Welche Tokens siehst du in dieser Liste? –

+0

@MikeLischke Danke für Ihre Eingabe! Ich habe die Frage bearbeitet, um die Tokenergebnisse und das nächste resultierende Problem einzubeziehen. – mtj

+0

Dieser Fehler: "Zeile 1: 6 nicht übereinstimmende Eingabe" = "erwartet" = "" ist normalerweise ein Zeichen, dass es mehrere '=' Definitionen gibt (z. B. in Parser-Regeln eingebettete Literale). Überprüfen Sie Ihre Token-Deklarationen. Sind alle Token-Literale durch Lexer-Regeln abgedeckt, anstatt direkt in einer Parser-Regel verwendet zu werden? –

Antwort

1

Ok, scheint der wichtigste Weg hier ist: Denken Sie über Ihre Definitionen und wie Sie sie definieren. Erstellen Sie explizite Lexerregeln für Ihre Literale, anstatt sie implizit in den Parserregeln zu definieren. Überprüfen Sie die Token-Werte, die Sie vom Lexer erhalten, wenn der Parser Ihnen seltsame Fehler gibt, weil sie an erster Stelle korrekt sein müssen oder Ihr Parse keine Chance hat, seine Arbeit zu machen.

+0

Vielen Dank! :) – mtj

+0

Btw, du hast das Kopfgeld noch nicht vergeben ;-) –

+0

Sorry, first-timer. Sollte jetzt gemacht werden. – mtj