2017-04-14 5 views
0

Ich verwende das ANTLR 4-Plugin in IntelliJ, und ich habe den bizarrsten Fehler. Ich werde mit den entsprechenden Parser/Lexer Regeln beginnen:ANTLR 4: erkennt 'und' aber nicht 'oder' ohne Leerzeichen

// Take care of whitespace. 
WS : [ \r\t\f\n]+ -> skip; 

OTHER: . -> skip; 

STRING 
: '"' [A-z ]+ '"' 
; 

evaluate // starting rule. 
: textbox? // could be an empty textbox. 
; 

textbox 
: (row '\n')* 
; 

row 
: ability 
| ability_list 

ability 
: activated_ability 
| triggered_ability 
| static_ability 

triggered_ability 
: trigger_words ',' STRING 
; 

trigger_words 
: ('when'|'whenever'|'as') whenever_triggers|'at' 
; 

whenever_triggers 
: triggerer (('or'|'and') triggerer)* // this line has the issue. 
; 

triggerer 
: self 

self: '~' 

ich es passieren diesen Text: whenever ~ or ~, und es scheitert an der or und sagte line 1:10 mismatched input ' or' expecting {'or', 'and'}. Wenn ich jedoch der whenever_triggers Regel or eine Zeichenfolge hinzufügen (so dass es ' or'|'and' macht), funktioniert es gut.

Die seltsamste Sache ist, dass, wenn ich versuche whenever ~ and ~, es funktioniert auch ohne die Regel mit einem Leerzeichen in der and Zeichenfolge. Das ändert sich nicht, wenn ich auch eine Lexer-Regel 'and'|'or' mache. Es ist einfach bizarr. Ich habe bestätigt, dass dieser Fehler beim Ausführen des "Test-Rigs" in Antlrworks 2 auftritt, also ist es nicht nur eine IntelliJ-Sache.

Dies ist ein Bild des Baumes Parse wenn der Fehler auftritt:

enter image description here

+0

Ihre "STRING" -Regel wird nicht gefunden, da die Eingabe immer als "OTHER" betrachtet wird, bevor die "STRING" -Regel überprüft wird. Und ich bin mir nicht sicher über die impliziten Lexer-Definitionen in Ihrer Grammatik und darüber, wie sie die "OTHER" -Regel stören könnten ... Versuchen Sie, es am Ende der Grammatik zu setzen und zu sehen, ob sich das ändert – Raven

+0

http: // stackoverflow .com/documentation/antlr/3271/lexer-rules-in-v4/11235/priority-rules # t = 201704141056079647247 –

+0

@Raven Ich habe die SONSTIGE Regel am Ende und sogar entfernt, es hat nichts geändert. Die STRING-Regel war nur ein Platzhalter, den ich gemacht habe, kommt für mein Beispiel nicht einmal ins Spiel. LucasTrzesniewski Ich habe die Dokumente gelesen, aber nichts in Bezug auf Leerzeichen/Leerzeichen gesehen, die meinem Problem helfen. – IronWaffleMan

Antwort

2

Okay Sie die Antwort mehr oder weniger von selbst gefunden haben, mit dieser Antwort von mir, damit ich auf die Erläuterung konzentrieren, warum die Problem aufgetreten an erster Stelle.

Zunächst einmal - für alle, die auf diese Frage stolpern - das Problem war, dass er eine andere implizite Lexer-Regel definiert hatte, die so aussah ' or' (beachten Sie die Leerzeichen). Das Ändern zu 'or' löste das Problem.

Aber warum war das ein Problem?
Um zu verstehen, müssen Sie verstehen, was ANTLR macht, wenn Sie '<something>' in einer Ihrer Parser-Regeln schreiben: Beim Kompilieren der Grammatik erzeugt es eine neue Lexer-Regel für jede dieser Deklarationen. Diese Lexerregeln werden vor den in Ihrer Grammatik definierten Lexerregeln erstellt. Der Lexer selbst passt die gegebene Eingabe in Tokens an und verarbeitet dafür jede Lexer-Regel in der Reihenfolge, in der sie deklariert wurden. Daher wird es immer mit den impliziten Token-Definitionen beginnen und dann zur obersten "echten" Lexer-Regel übergehen.
Das Problem ist, dass der Lexer ist nicht zu schlau über diesen Prozess, das bedeutet, sobald es einige Eingabe mit der aktuellen Lexer-Regel übereinstimmt, wird es ein entsprechendes Token erstellen und weiter mit der abschließenden Eingabe.

Als Ergebnis wird eine Lexer-Regel, die danach kommt, die Eingabe ebenfalls abgeglichen (aber als ein anderes Token, da es eine andere Lexer-Regel ist) übersprungen, so dass die entsprechende Eingabe möglicherweise nicht den erwarteten Token-Typ hat Die Lexerregeln haben sich selbst überschrieben. In Ihrem Beispiel lauten die Regeln zum Selbstüberschreiben ' or' (Token 1) und 'or' (Token 2). Jede dieser impliziten Lexer-Regeldelkarationen führt zu einer anderen Lexer-Regel, und da die erste Übereinstimmung gefunden wurde, nehme ich an, dass sie vor der zweiten deklariert wird. Nun schauen Sie sich Ihre Eingabe an: whenever ~ or ~ Der Lexer wird anfangen zu interpretieren und die erste Regel, auf die es stößt, ist ' or' (Nach dem Start wird natürlich angepasst) und es passt die Eingabe da es wirklich ein Leerzeichen vor der or ist. Daher wird es als Token 1 abgeglichen.
Der Parser auf der anderen Seite erwartet zu diesem Zeitpunkt ein Token 2, so dass es sich über die gegebene Eingabe beschweren wird (obwohl es sich wirklich über den falschen Token-Typ beschwert). Wenn Sie den Eingang auf whenever ~or ~ ändern, führt dies zu einer korrekten Interpretation.

Genau dies ist der Grund, warum Sie keine impliziten Token-Definitionen in Ihrer Grammatik verwenden sollten (außer es ist wirklich klein). Erstellen Sie eine neue Lexer-Regel für jede Eingabe und beginnen Sie mit den spezifischsten Regeln. Das bedeutet, dass Regeln, die mit speziellen Zeichenfolgen (z. B. Schlüsselwörtern) übereinstimmen, vor allgemeinen Lexer-Regeln wie ID oder STRING oder etwas ähnlichem deklariert werden sollten. Regeln, die mit allen Zeichen übereinstimmen, um zu verhindern, dass der Lexer einen Fehler bei nicht erkannter Eingabe verursacht, müssen als letztes deklariert werden, da sie jede nachfolgende Lexer-Regel überschreiben würden.

+0

Danke für diese Erklärung, es hilft mir auf jeden Fall, das zu verstehen. Mein Plan ist nun, eine einzelne Lexer-Regel für jeden zu verwendenden String zu erstellen (zB 'OR: 'oder';') und dann diese Lexer in anderen Lexer/Parser-Regeln zu verwenden, damit ich diese Art von Verwechslungen nicht mehr bekomme Ist das in der Regel der richtige Ansatz? – IronWaffleMan

+1

Ja ist es. Es wird Ihnen auch helfen, Tippfehler zu vermeiden;) – Raven

Verwandte Themen