Erläuterungen zu Grammatiken, Lexern und Parsern

8

Hintergrundinfo ( Mai überspringen ): Ich arbeite an einer Aufgabe, die wir an der Uni gestellt haben und in der wir eine Grammatik für eine DSL entwerfen müssen, die uns zur Verfügung gestellt wurde. Die Grammatik muss in BNF oder EBNF sein. Neben anderen Dingen werden wir anhand der lexikalischen Regeln in der Grammatik und der Parsing-Regeln bewertet - z. B. ob Regeln für die Sprachuntermenge geeignet sind, wie umfassend diese Regeln sind, wie klar die Regeln sind usw.

Was ich nicht verstehe, ist, wenn diese Regeln in einer in BNF definierten Grammatik behandelt werden (es ist ein neues Thema für uns).

Die Frage : Enthält / liefert eine Grammatik für eine bestimmte Sprache, die entweder in BNF oder EBNF definiert wurde, Regeln für die lexikalische Analyse und / oder das Parsen ? ( oder müssen diese woanders angegeben werden? )

Was wäre auch eine lexikalische Regel? Und was wäre eine Parsing-Regel?

The_Neo
quelle
1
BNF ist nur eine Syntax, die die Grammatik vollständig beschreibt, genau wie Regex eine reguläre Sprache vollständig beschreibt
Ratschenfreak
4
Ja, Sie können sowohl Lexing als auch Parsing in einer einzigen BNF-ähnlichen Beschreibung definieren - siehe beispielsweise PEGs. Die Unterscheidung zwischen Lexing und Parsing ist ziemlich willkürlich und veraltet.
SK-Logik

Antworten:

8

Ja, eine BNF-Grammatik enthält alle Regeln, die Sie für die lexikalische Analyse und Analyse benötigen. Der Unterschied zwischen den beiden ist ein wenig verschwommen. Ein gutes Beispiel für eine lexikalische Regel in EBNF wäre:

number = [ "-" ], digit, { digit } ;
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;

Normalerweise können Lexer mit relativ einfachem Code implementiert werden. Sie können eine Zeichenfolge nach dem nächsten Leerzeichen durchsuchen und dann prüfen, ob Ihr Ergebnis mit einem optionalen "-" beginnt, danach mindestens eine Ziffer enthält und danach nur noch Ziffern enthält . Lexer waren früher fast immer ein separater Schritt, werden aber heutzutage normalerweise zusammen mit dem Parser zusammengefasst. Daher die Unschärfe.

Eine Parser- Regel würde das numberNicht-Terminal verwenden, um etwas größer zu machen, wie den folgenden Additionsausdruck.

add = number, "+", number

Auch wenn sie in derselben Datei verwechselt sind, wird Ihr Professor dennoch eine klare Unterscheidung zwischen "Lexer" -Regeln und "Parser" -Regeln wünschen. Tun Sie dies beispielsweise nicht :

add = {"0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" }, "+",
      {"0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" }

Dieser Fehler ist nicht nur anfällig, sondern auch schwer zu lesen und schwer zu implementieren.

Karl Bielefeldt
quelle
Vielen Dank, der Abschnitt über die klare Unterscheidung zwischen "Lexer" -Regeln und "Parser" -Regeln hat mir wirklich geholfen zu verstehen, wofür wir evaluiert werden!
The_Neo
4

Die Grammatik für die lexikalische Analyse wird normalerweise über reguläre Ausdrücke angegeben (insbesondere für Projekte vom Typ Universität). Es akzeptiert eine reguläre Sprache.

Ein Parser akzeptiert normalerweise eine kontextfreie Sprache, die über BNF angegeben werden kann.

Die Unterscheidung zwischen einem Parser und einem Scanner (oder lexikalischen Analysator) ist etwas künstlich, erleichtert jedoch das Schreiben von Parsern.

Siehe http://en.wikipedia.org/wiki/Chomsky_hierarchy

Mike Harris
quelle
Sie sprechen einen guten Punkt darüber an, dass Universitätsprojekte oft anders sind. Es ist seine Aufgabe, die genauen Anforderungen mit seinem Professor zu klären.
Karl Bielefeldt
2

Die Antwort auf Ihre Frage lautet sicherlich Ja. Sowohl Parsing- als auch Lexing-Regeln können und werden mithilfe eines EBNF (der eigentlich nur eine kompaktere Form eines BNF ist) angegeben. Bei Compilern mit Produktionsqualität ist der nächste Teil der Antwort jedoch anders.

Die meisten Sprachen haben eine Grammatik, die kontextfrei ist und einer Reihe von Regeln entspricht, die mit Lookahead und Backtracking zu tun haben. Die gebräuchlichsten Grammatiken sind LL (1) und LR (1). LL (1) -Grammatiken ermöglichen eine einfache rekursive Abstiegsgrammatik, die häufig von Hand codiert wird, während LR (1) normalerweise einen Parsergenerator wie YACC bedeutet. Dieser Teil der Grammatik geht auf Token (Terminals) zurück, aber nicht niedriger.

Die Symbole werden normalerweise separat mit einer noch einfacheren Grammatik definiert, beispielsweise einer Operatorgrammatik. [Sie können diese Begriffe nach besseren Definitionen durchsuchen, als ich hier angeben kann.] Der Lexer, der diese Symbole liest, ist normalerweise für den größten Teil der Leistung des Compilers verantwortlich, sodass er meiner Erfahrung nach immer handcodiert ist. LEX ist klobig (und nur C) und Regex ist zu langsam.

Der Punkt ist zu verstehen, dass die Parsing-Regeln die Technologie steuern, die für Ihren Parser benötigt wird, und die Lexing-Regeln ebenso für Ihren Lexer. Die klare Unterscheidung zwischen ihnen besteht darin, ob sie für die Verwendung von Token (Terminals) oder deren Konstruktion gelten.

Dies hilft möglicherweise nicht Ihrem akademischen Fortschritt, aber es ist wichtig, wenn Sie über Spielzeugprojekte hinausgehen.

david.pfx
quelle