Recursive-descent-parser-Implementierung
Ich bin auf der Suche zu schreiben einige Pseudocode für eine rekursive Abstieg parser. Nun, ich habe keine Erfahrung mit dieser Art der Codierung. Ich habe einige Beispiele online, aber Sie arbeiten nur auf eine Grammatik, die verwendet mathematische Ausdrücke. Hier ist die Grammatik ich bin auf Basis der parser auf.
S -> if E then S | if E then S else S | begin S L | print E
L -> end | ; S L
E -> i
Muss ich schreiben Methoden S()
L()
und E()
und wieder einige Fehlermeldungen, aber die tutorials die ich gefunden habe online noch nicht viel geholfen. Kann jemand mich in die richtige Richtung und geben Sie mir einige Beispiele nennen?.
Möchte ich schreiben, es in C# oder Java-syntax, da ist es für mich einfacher zu beziehen.
Update
public void S() {
if (currentToken == "if") {
getNextToken();
E();
if (currentToken == "then") {
getNextToken();
S();
if (currentToken == "else") {
getNextToken();
S();
Return;
}
} else {
throw new IllegalTokenException("Procedure S() expected a 'then' token " + "but received: " + currentToken);
} else if (currentToken == "begin") {
getNextToken();
S();
L();
return;
} else if (currentToken == "print") {
getNextToken();
E();
return;
} else {
throw new IllegalTokenException("Procedure S() expected an 'if' or 'then' or else or begin or print token " + "but received: " + currentToken);
}
}
}
public void L() {
if (currentToken == "end") {
getNextToken();
return;
} else if (currentToken == ";") {
getNextToken();
S();
L();
return;
} else {
throw new IllegalTokenException("Procedure L() expected an 'end' or ';' token " + "but received: " + currentToken);
}
}
public void E() {
if (currentToken == "i") {
getNextToken();
return;
} else {
throw new IllegalTokenException("Procedure E() expected an 'i' token " + "but received: " + currentToken);
}
}
InformationsquelleAutor der Frage user1072706 | 2012-03-21
Du musst angemeldet sein, um einen Kommentar abzugeben.
Grundsätzlich in recursive-descent-parsing jedes nicht-terminal der Grammatik übersetzt, in einer Prozedur, dann in jede Prozedur, die Sie überprüfen, um zu sehen, ob das aktuelle token sind Sie auf der Suche übereinstimmt, was Sie erwarten würden, um zu sehen, auf der rechten Seite der nicht-terminal-symbol der entsprechenden Verfahren, wenn es dann funktioniert, weiterhin anwenden der Produktion, wenn nicht, dann haben Sie einen Fehler festgestellt und muss einige Maßnahmen ergreifen.
So, in Ihrem Fall, wie Sie oben erwähnt haben Sie Verfahren:
S()
L()
undE()
werde ich ein Beispiel geben, wieL()
umgesetzt werden könnten, und dann können Sie versuchen und tunS()
undE()
auf Ihrem eigenen.Es ist auch wichtig zu beachten, dass Sie benötigen, ein anderes Programm für die tokenisierung der Eingabe für Sie, dann können Sie nur bitten, das Programm für das nächste token aus der Eingabe.
Nun versuchen Sie
S()
undE()
und nach zurück.Auch als Kristopher Punkte heraus, Ihre Grammatik hat, sowas nennt man dangling else, meaing, dass Sie eine Produktion beginnt mit der gleichen Sache bis zu einem Punkt:
Also dies wirft die Frage auf, ob Ihre parser sieht eine 'wenn' - token, die Produktion sollte es wählen, Sie zu verarbeiten die Eingabe? Die Antwort ist, es hat keine Ahnung, was man zu wählen, weil im Gegensatz zum Menschen kann der compiler nicht, Blick nach vorne in die Eingabe-stream für die Suche nach einem 'else' - token. Dies ist ein einfaches problem zu beheben, durch die Anwendung einer Regel bekannt als Links-Factoring, sehr ähnlich wie Sie den Faktor einer algebra problem.
Alles, was Sie tun müssen ist, erstellen Sie ein neues nicht-terminal-symbol S' (E-prime), deren Rechte Seite halten die Stücke von den Produktionen, die nicht üblich, so dass Ihre
S
- Produktionen keine wird:InformationsquelleAutor der Antwort Hunter McMillen
Dies ist nicht die einfachste Grammatik, mit zu beginnen, weil Sie haben eine unbegrenzte Menge der lookahead-Funktion auf Ihrem ersten produktionsregel:
betrachten
Wenn bestimmen wir, diese blöde anderes?
Bedenken Sie auch,
Nun, war, dass
else
soll, zu binden, um dieif 5 then
fragment? Wenn nicht, das ist eigentlich cool, aber eindeutig sein.Schreiben Sie Ihre Grammatik (möglicherweise, je nach else rule"), gleichbedeutend wie:
Die möglicherweise oder möglicherweise nicht, was Sie wollen. Aber der pseudocode Art von Sprüngen aus.
Für jede Alternative, ich habe eine if-Anweisung, schaute sich die eindeutigen Präfix. Die endgültige sonst auf alle match-Versuch ist immer ein Fehler. Ich konsumiere keywords und rufen die entsprechenden Funktionen der Produktion Regeln, wie ich Ihnen begegnen.
Übersetzung von pseudocode zu echten code ist nicht zu kompliziert, aber es ist nicht trivial. Diese peeks und verbraucht wohl nicht wirklich funktionieren auf strings. Es ist viel einfacher, mit zu arbeiten-Token. Und einfach nur einen Satz und konsumieren es ist nicht ganz das gleiche wie analysiert wird. Sie wollen etwas tun, als Sie verbrauchen den Stücken, die eventuell den Aufbau der parse-Baum (was bedeutet, dass diese Funktionen wohl wieder etwas). Und werfen, dass ein Fehler möglicherweise korrigieren auf hohem Niveau, aber würden Sie wollen, um einige aussagekräftige Informationen in der Fehlermeldung. Auch werden die Dinge komplexer, wenn Sie benötigen lookahead.
Ich würde empfehlen, Language Implementation Patterns von Terence Parr (der Kerl, der schrieb antlr, eine rekursive Abstieg parser-generator), wenn Sie diese Arten von Problemen. Das Dragon Book (Aho, et al, empfohlen in einem Kommentar) ist auch gut (es ist wahrscheinlich immer noch die dominierende lehrbuch in der compiler-Kurse).
InformationsquelleAutor der Antwort ccoakley
Habe ich gelernt (eigentlich nur, half) die Analyse-Abschnitt in einem PL-Klasse als letztes semester. Ich wirklich empfehlen, sich auf die Analyse von Folien, die von unserer Seite: hier. Grundsätzlich ist für die recursive-descent-parsing, Fragen Sie sich die folgende Frage:
Ihre Grammatik -- -- weist eine sehr häufige Mehrdeutigkeit sogenannte "dangling else", die seit dem Algol Tage. In shift reduzieren Parser (in der Regel produziert von parser-Generatoren) generiert dies ein shift /reduce-Konflikt, wo Sie in der Regel wählen, um beliebig verlagern, anstatt zu reduzieren, so dass Sie die gemeinsamen "maximal viel" - Prinzip. (Also, wenn Sie sehen, "wenn (b) dann if (b2) S1 else S2" Sie Lesen es als "if (b) then { if (b2) { s1; } else { s2; } }")
Let ' s werfen Sie dies aus Ihrer Grammatik, und arbeiten mit einem etwas einfacher Grammatik:
wir gehen auch davon ausgehen, dass NUM ist etwas, das man aus dem lexer (d.h., es ist nur ein token). Diese Grammatik ist LL(1), das heißt, Sie können analysieren, es mit einem recursive descent-parser implementiert, mit einem naiven Algorithmus. Der Algorithmus funktioniert wie folgt:
Siehst du das Muster hier:
Beachten Sie bitte auch, dass diese Art der Analyse in der Regel nicht produzieren, was Sie wollen, für Arithmetik. Recursive descent Parser (es sei denn, Sie verwenden einen kleinen trick mit tail recursion?) nicht produzieren leftmost-Ableitungen. Insbesondere können Sie nicht schreiben, Links-rekursive Regeln wie "a -> a - a", wo die Links-Assoziativität ist wirklich notwendig! Dies ist, warum Menschen in der Regel verwenden schicker parser-generator-tools. Aber der rekursive Abstieg trick noch Wert ist, wissen über und spielen, um mit.
InformationsquelleAutor der Antwort Kristopher Micinski