6.4 LL(k)-Grammatiken (nicht im Sommersemester 2025)

Definition 6.4.1Grenzform Sei G=(Σ,N,S,P) eine kontextfreie Grammatik. Eine Wortform Aα - also eine Wortform, die mit einem Nichtterminal beginnt - heißt Grenzform, wenn es ein wΣ gibt, so dass es eine Linksableitung SwAα gibt. In anderen Worten: eine Grenzform ist das, was bei einem Kellerautomaten auf dem Stack liegt, wenn ein Nichtterminal ganz oben liegt.
Grenzformen sind also diejenigen Wortformen, bei denen der Kellerautomat eine Entscheidung treffen muss, weil er eventuell mehrere Produktionen Aβ zur Auswahl hat. In diesem Teilkapitel wollen wir herausarbeiten, unter welchen Umständen wir die richtige Auswahl treffen können, auch wenn wir nur wenige weitere Zeichen unseres Inputwortes lesen dürfen.
Definition 6.4.2 Für ein Wort wΣ und eine natürliche Zahl kN sei firstk(w) wie folgt definiert: firstk(w):={w wenn |w|<ku wenn w=uv und |u|=k In Worten: firstk(w) besteht aus den ersten k Zeichen von w (oder aus ganz w, falls es weniger als k lang ist).
Definition 6.4.3 LL(k)-Grammatiken Eine kontextfreie Grammatik G=(Σ,N,S,P) ist eine LL(k)-Grammatik, wenn für jede Grenzform Aα und für jedes Paar A1βA2γ verschiedener Produktionen (also βγ) folgendes gilt: wenn Aα1βαxAα2γαy dann müssen sich x und y in den ersten k Zeichen unterscheiden, also firstk(x)firstk(y) .
Intuitiv gesprochen: wenn wir bereits eine ersten Teil w unseres Zielwortes abgeleitet haben, dann können wir die nächste anzuwendende Produktion eindeutig bestimmen, indem wir die nächsten k Zeichen des Zielwortes lesen.
Übungsaufgabe 6.4.1 Negieren Sie die Definition, d.h., schreiben Sie eine Aussage der Form Wenn G nicht LL(k) ist, dann gibt es...
Beispiel 6.4.4 Die Klammern-Grammatik S1ϵS2(S)S ist LL(1).
Beweis. Folgen wir der Definition von LL(1): für jedes Paar verschiedener Regeln muss etwas gelten. Wir haben hier keine Auswahl, denn es gibt ja nur ein Paar. Also müssen wir zeigen, dass, falls SwSα1wαwxSwSα2w(S)Sαwy gilt, dann auch first1(x)first2(y) gilt. Offensichtlich ist first2(y)= "(". Was kann firstk(x) sein?

Behauptung. Wenn Sδ(ΣN), dann steht jedes S in δ entweder am Ende von δ oder unmittelbar vor einem ")".

Das folgt per Induktion über die Länge der Ableitung. Wenn es also für δ gilt und wir die Produktion S(S)S auf δ anwenden, dann gilt es für jedes "alte" S und auch für die beiden neu erzeugten; wenn wir Sϵ anwenden, dann verschwindet ein S, die Behauptung gilt aber nach wie vor für alle anderen S in δ.

Wir folgern also, dass für das α den beiden obigne Herleitungen firstk(α){ϵ,)} gilt. Keines davon ist ein Nichtterminal, und so muss auch firstk(α)=firstk(x) gelten. Zusammenfassend gesagt: firstk(x){ϵ,)}firsty(y)=( , und somit sind sie verschieden. Wir folgern, dass G eine LL(1)-Grammatik ist.

Sehen Sie, dass die LL(k)-Bedingung der Aussage "der Backtrack-Baum hat keine langen Sackgassen" ähnelt (aber nicht völlig äquivalent dazu ist). Wenn G eine LL(k)-Grammatik ist und wir den Backtrack-Baum für ein Wort bauen, dann gilt: sobald wir in einer Sackgasse k neue Terminalsymbole am "Terminalpräfix" der Wortform hergeleitet haben, merken wir, dass wir in einer Sackgasse sind. Mit Terminalpräfix meine ich den längsten Präfix einer Wortform, der ausschließlich aus Terminalen besteht. Allerdings muss nicht jeder Ableitungsschritt den Terminalpräfix wachsen lassen (Regeln wie XYbZ zum Beispiel ersetzen einfach das erste Nichtterminal), aber "moralisch" geschieht etwas ähnliches).

Wenn umgekehrt eine Grammatik nicht LL(k) ist, dann muss der Backtrack-Baum beiden Ableitungen wAαwβαwAαwγα mindestens so lange weiterverfolgen, bis der Terminalpräfix k weitere Zeichen dazugewonnen hat. Der Baum bekommt also dementsprechend lange Sackgassen.

Übungsaufgabe 6.4.2 (Beispiel 5.3 aus The Theory of Parsing, Translation, and Compiling von Alfred V. Aho und Jeffrey D. Ullman). Betrachten wir die Grammatik S1ϵS2abAA3SaaA4b Zeigen Sie, dass diese Grammatik LL(2) ist, aber nicht LL(1).

Tip. Leiten Sie erst einmal ein Dutzend verschiedene Wörter ab und finden dann eine "normalsprachliche" Beschreibung dieser Sprache. Beschreiben Sie dann alle möglichen Wortformen α mit Sα.

Übungsaufgabe 6.4.3 Schreiben Sie eine äquivalente Grammatik zu der vorherigen Sprache, die LL(1) ist. (Warnung: Ich weiß nicht, ob das überhaupt geht).
Übungsaufgabe 6.4.4 Betrachten wir die Grammatik G: S1aSbS2aSS3ϵ Sie erzeugt die Sprache L(G):={am+kbm | m,kN} , also Wörter, wo auf beliebig viele a's eine Folge von höchstens so vielen b's folgt.

Geben Sie diese Grammatik in den Parser-Simulator ein und finden Wörter mit langen Sackgassen.

Zeigen Sie, dass diese Grammatik nicht LL(k) ist, für kein kN.

Übungsaufgabe 6.4.5 Sei tN eine feste, im Voraus bekannte Zahl. Betrachten wir die Sprache Lt:={am+lbm | m0,lt} , also die Wörter der Form ambn mit nmn+t.

Schreiben Sie für L3 eine Grammatik, geben Sie diese im Parser-Simulator ein und schauen, wie lang die Sackgassen werden können.

Zeigen Sie, dass L3 eine LL(k)-Grammatik ist. Für welchen Wert von k? Ist Lt (für im Voraus bekanntes t) eine LL(k)-Grammatik? Für welchen Wert von k?

LL(k)-Grammatiken parsen

Wir wollen nun erarbeiten, wie wir für eine LL(k)-Grammatik einen Parser, also im Prinzip einen deterministischen Pushdown-Automaten schreiben können. Wir tasten uns langsam voran. Wir beginnen mit einer Verallgemeinerung von firstk von Wörtern auf Wortformen (die also Nichtterminale beinhalten können).
Definition 6.4.5 Sei eine kontextfreie Grammatik G=(Σ,N,S,P) und eine Wortform α(ΣN) gegeben. Wir definieren FIRSTk(α):={firstk(w) | wΣ,αw}
Wir können nun die LL(k)-Bedingung äquivalent formulieren:
Definition/Beobachtung 6.4.6 Eine Grammatik G ist LL(k) genau dann, wenn für alle Grenzformen Aα und alle Produktionen mit A auf der linken Seite, also Aβ1Aβ2Aβl die Mengen FIRST(βiα) paarweise disjunkt sind (wenn also keine zwei dieser Mengen ein gemeinsames Element enthalten).

Nehmen wir eine Momentaufnahme unseres Kellerautomaten. Er hat den Präfix des Eingabewortes gelesen und eine Linksableitung durchgeführt. Die Wortform ist genau das, was im Moment auf dem Stack des Automaten liegt (um ganz genau zu sein: liegt auf dem Stack). Wenn mit einem Terminalsymbol beginnt, so ist klar, was wir machen müssen: wir schauen, ob mit beginnt. Wenn ja, lesen wir und poppen es vom Stack. Der schwierige Fall ist, wenn mit einem Nichtterminal beginnt.

Nochmal von vorn: im schwierigen Fall liegt auf dem Stack (oberhalb vom ) eine Wortform, die mit einem Nichtterminal beginnt, also . Das bedeutet, dass der Automat per Linksableitung bis jetzt hergeleitet hat. Der Automat muss sich nun zwischen allen Regeln für entscheiden: Der Automat betrachtet nun die nächsten Eingabesymbole, also (wir gehen mal davon aus, dass er das kann; programmieren könnten wir das auf jeden Fall; ob man es im strengen Framework des Kellerautomaten hinkriegt, werden wir später sehen). Wenn eine LL-Grammatik ist, dann gibt es höchstens eine Regel mit da ja nach obiger Beobachtung diese Mengen disjunkt sind. Wenn in keiner dieser Mengen enthalten ist, so kann die Ableitung offensichtlich nicht vervollständigt werden, und wir schließen, dass ist. Wenn es genau ein gibt mit , dann ist die "richtige" Produktion. Wir wenden sie an, ersetzen also auf dem Stack durch . Falls es zwei oder mehr Produktionen gibt mit , dann ist die Grammatik nicht LL; wir beenden den Parsing-Prozess mit einer Laufzeitfehlermeldung. Hier ist ein Entwurf eines allgemeinen Algorithmus für LL-Grammatiken:

Generischer Algorithmus zum Parsen von LL-Gramatiken

  1. Lege auf den Stack.
  2. while Stack nicht leer
    1. Sei das Resteingabewort.
    2. Wenn das oberste Symbol auf dem Stack ein Terminalsymbol ist:
      • Lies das nächste Eingabesymbol .
      • Wenn , poppe vom Stack;
      • ansonsten Reject.
    3. Wenn das oberste Symbol auf dem Stack ein Nichtterminalsymbol ist:
      1. Schreibe den Stack als
      2. Seien alle Produktionen mit auf der linken Seite.
      3. Berechne für alle und schaue, welches enthält
        • Wenn es genau eine solche Produktion gibt: wende Sie an; es ist die richtige Produktion.
        • Wenn es keine gibt: Reject. Das Wort kann nicht abgeleitet werden.
        • Wenn es mehrere gibt: ende mit einem Laufzeitfehler; die Grammatik ist nicht LL.
    4. Wenn das oberste Symbol ist: wenn Eingabewort zu Ende Accept ansonsten Reject

Die rot und fett gedruckte Zeile ist das "Herz" dieses Algorithmus. Um den Algorithmus implementieren zu können, müssen wir es schaffen, die Menge zu berechnen.

und berechnen.

Definition 6.4.7 Seien zwei Mengen. Mit bezeichnen wir die Menge (Diese Definition haben Sie schon im Kapitel über reguläre Sprachen kennengelernt). Für eine natürliche Zahl definieren wir Weiterhin bezeichnen wir mit die Menge

Im Allgemeinen gilt . In Worten: der -Operator bildet alle möglichen Kombinationen von Wörtern und nimmt von jedem die ersten Zeichen.

Beispiel 6.4.8 Sei Dann ist und somit
Beobachtung 6.4.9 - Wie man berechnet. Sei eine Wortform gegeben, also . Wir berechnen , indem wir als erstes aussschreiben als wobei jedes ein Terminalsymbol oder ein Nichtterminalsymbol ist, und berechnen dann wie folgt:

Wir können dies schön der Reihe nach tun:

  1. Initialisiere
  2. for down to 1 do:
    • // ist jetzt
  3. return

Wir müssen nur noch herausfinden, wie wir für einzelne Zeichen berechnen.

Für ein Terminalsymbol ist es trivial, zu berechnen: es ist , da sich aus natürlich nur das Wort ableiten lässt. Für Nichtterminale müssen wir uns anstrengen. Die erste Idee ist, dass wir für eine Gleichung schreiben können, die verwendet.
Beobachtung 6.4.10 Sei ein Nichtterminal und die Produktionen der Grammatik mit auf der linken Seite. Dann gilt Was ja eigentlich offensichtlich ist: wenn sich ein Wort aus ableiten lässt, dann muss dies mittels einer der obigen Produktionen geschehen: , und somit gilt .

Die Gleichungen und leuchten zwar ein, scheinen aber erstmal nicht hilfreich, diese Mengen auch tatsächlich zu berechnen. Denn eventuell taucht selbst wieder auf einer rechten Seite auf, sagen wir . Um zu berechnen, müssen wir also laut die Menge kennen; um diese zu berechnen, brauchen wir laut allerdings zuerst unter Anderem die Menge . Wo sollen wir also anfangen?

In solchen Situationen, wo sich "die Katze in den Schwanz beißt", hilft es oft, die Definition vorerst komplexere un genauer zu machen. Wir führen nun, zusätzlich zu und , noch eine feinere Unterteilung an:

Definition 6.4.11 Sei ein Symbol und . Dann ist
Beispiel 6.4.12 Sei unsere Grammatik Dann ist beispielsweise
ein Ableitungsbaum der Höhe 2 von , und somit gilt Ein Baum der Höhe 1, der mit beginnt, könnte ja nur ableiten und somit gar kein Wort. Es gilt also Für eine Wortform definieren wir Eine Ableitung der Höhe maximal entspricht also einer Folge von Ableitungsbäumen, von denen jeder Höhe maximal hat.

Mit dieser Definition können wir nun Gleichungen für und angeben. Seien die Produktionen mit auf der linken Seite. Dann gilt für :

Lemma. 6.4.13 Für gilt Für gilt und schließlich

Die Gleichungen sagen, dass wir, falls wir für alle Nichtterminale kennen, dann auch berechnen können. Daraus folgt auch: wenn für alle , dann auch für alle , und somit werden die Mengen für alle von nun an gleich bleiben.

Beobachtung 6.4.14 Falls für alle , dann gilt für alle .
Demo. 6.4.15 - Berechnung der Menge für die Nichtterminale einer Sprache. Wir betrachten die Grammatik