Die erweiterte Backus-Naur-Form (EBNF), benannt nach J.W. Backus
und P. Naur
, dient zur knappen und übersichtlichen Darstellung der Produktionen einer kontextfreien Grammatik. Gegenüber der einfachen Backus-Naur-Form erlaubt die erweiterte Backus-Naur-Form die Verwendung von Optionen und Iterationen. Hierdurch wird zugleich auch die Programmierung von Recursive-Descent-Parsern und -Übersetzern erleichtert.
In der erweiterten Backus-Naur-Form werden ähnlich wie in regulären Ausdrücken das hochgestellte Fragezeichen ? für eine Option sowie der Stern * für die Iteration und das hochgestellte Pluszeichen + für die nichtleere Iteration verwendet.
In der folgenden Darstellung werden zudem die Zeichen unterschiedlicher Funktion in unterschiedlichen Farben gekennzeichnet:
| rot | Terminalzeichen der Grammatik, die letztlich in der erzeugten Sprache vorkommen, | |
| blau | Nicht-Terminalzeichen der Grammatik, die für den Ableitungsprozess gebraucht werden, (in den untenstehenden Beispielen Wortsymbole wie z.B. expr oder term), | |
| schwarz | Meta-Zeichen, die zur Darstellung der Produktionen der Grammatik dienen. |
Eine Produktion einer kontextfreien Grammatik schreiben Sie in Backus-Naur-Form beispielsweise wie folgt:
| expr | ![]() | term + expr |
In einem Recursive-Descent-Parser implementieren Sie diese Produktion dann als folgende Funktion:
Die Funktion erhält denselben Namen wie das Nicht-Terminalzeichen auf der linken Seite der Produktion, hier expr. Jede Variable auf der rechten Seite der Produktion setzen Sie in einen entsprechenden Funktionsaufruf um, jedes Terminalzeichen in einen Aufruf der Funktion match. Die Funktion match arbeitet das entsprechende Terminalzeichen vom Eingabewort ab.
Eine Produktion mit mehreren Alternativen implementieren Sie, indem Sie eine Fallunterscheidung treffen. Je nach dem nächsten Zeichen des Eingabewortes wenden Sie diejenige Alternative an, die mit diesem Zeichen beginnt, oder die mit einer Variablen beginnt, aus der sich ein Wort ableiten lässt, das mit diesem Zeichen beginnt 1).
Beispielsweise implementieren Sie die Produktion
| factor | ![]() | number | ( expr ) |
wie folgt:
Ein Spezialfall mehrerer Alternativen ist die Option. Eine Option liegt vor, wenn eine der Alternativen das leere Wort ε ist.
Eine Produktion der Form
| X | ![]() | u | ε |
schreiben Sie in erweiterter Backus-Naur-Form als
| X | ![]() | u? |
Eine Produktion mit einer Option, beispielsweise
| secondterm | ![]() | (+ term)? |
implementieren Sie folgendermaßen:
Sie versuchen also, + term abzuarbeiten. Wenn dies nicht möglich ist, weil das Zeichen + nicht kommt, tun Sie nichts.
Eine rekursive Produktion der Form
| X | ![]() | uX | ε |
oder
| X | ![]() | Xu | ε |
kürzen Sie in erweiterter Backus-Naur-Form ab als
| X | ![]() | u* |
Eine Produktion mit einer Iteration, beispielsweise
| moreterms | ![]() | (+ term)* |
implementieren Sie folgendermaßen:
Solange also ein weiteres Pluszeichen kommt, arbeiten Sie + term ab.
Eine rekursive Produktion der Form
| X | ![]() | uX | u |
oder
| X | ![]() | Xu | u |
kürzen Sie in erweiterter Backus-Naur-Form ab als
| X | ![]() | u+ |
Eine Produktion mit einer nichtleeren Iteration wie beispielsweise
| number | ![]() | digit+ |
implementieren Sie normalerweise mit einer Do-Schleife. In Python gibt es jedoch keine Do-Schleifen, daher implementieren Sie u+ wie uu*:
1) Wenn sich das leere Wort ε aus der Variablen ableiten lässt, sind noch weitergehende Betrachtungen erforderlich.