7 Allgemeine Grammatiken (nicht im Sommersemester 2025)

Wir haben nun ausführlich über kontextfreie Grammatiken gesprochen und auch Sprachen gesehen, die nicht mit kontextfreien Grammatiken zu beschreiben (und somit auch nicht mit Parsern oder allgemein mit Kellerautomaten) zu entscheiden sind. Da stellen sich die folgenden Fragen:

  1. Wie mann man die Definition kontextfreier Grammatiken sinnvoll erweitern, so dass sie beispielsweise auch Sprachen wie {anbncn | n0} umfassen?
  2. Gibt es eine natürliche Barriere, jenseits derer es keinen vernünftigen Begriff des "Beschreiben könnens" gibt? Oder kann man immer noch allgemeinere Regelwerke zulassen?
  3. Gibt es für die (noch zu definierende) allgemeinere Art von Grammatiken auch eine Art Automat, so wie die endlichen Automaten für die regulären Grammatiken und die Kellerautomaten für die kontextfreien?
Punkt 1 werden wir in diesem Kapitel diskutieren. Punkt 2 und 3 werden Gegenstand des nächsten Kapitels sein, in welchem wir die Turing-Maschinen einführen.

Allgemeine formale Grammatiken

Definition 7.1 (formale Grammatik) Eine formale Grammatik ist gegeben durch ein endliches Alphabet Σ aus Terminalsymbolen, einer endlichen Menge N von Nichtterminalen, einem Startsymbol SN und einer endlichen Menge an Produktionen αβ wobei β(ΣΓ) und α(ΣΓ)Σ. Letzeres bedeutet einfach, dass die linke Seite α mindestens ein Nichtterminal enthalten muss.

Die Definition formaler Grammatik umschließt offensichtlich die der kontextfreien: sie verbietet nicht, dass alle linken Seiten α aus genau einem Nichtterminal bestehen; in diesem Falle hätten wir eine kontextfreie Grammatik. Sie verbietet auch nicht, dass zusätzlich alle rechten Seiten βΣ×NΣ sind, also höchstens ein Nichtterminal enthalten, welches ganz rechts stehen muss. In diesem Falle würde es sich um eine reguläre Grammatik handeln.

Definition 7.2 (Ableitung und erzeugte Sprache). Sei G eine formale Grammtik und γ1,γ2(ΣN) zwei Wortformen. Wir schreiben γ1γ2, wenn wir γ1=uαvγ2=uβv schreiben können für Wortformen u,v, sodass αβ eine Produktion von G ist.
Beispiel 7.3 Betrachten wir die allgemeine Grammatik mit Terminalalphabet Σ={a,b,c}, Nichtterminalsymbolen N={S,A,B,C}, Startsymbol S und den Produktionen S1ABCS | ϵAB2BABA3ABAC4CACA5ACBC6CBCB7BCA8aB9bC10c

Nun schauen wir uns eine Beispielableitung an:

S1ABCS1ABCABCS2ABCABC5ABACBC3AABCBC8,8,9,9,10,10aabcbc

Die obige Beispielableitung illustriert, dass allgemeine formale Grammatiken etwas können, das kontextfreie Grammatiken nicht bieten konnten: das Vertauschen von Symbolen. Das mag nicht als besonders viel erscheinen, wird sich aber als Game Changer herausstellen.

Sobald wir eine Wortform erreicht haben, die nur aus Terminalsymbolen besteht (also ein Wort geworden ist), muss unsere Ableitung aufhören: wir können keine weitere Produktion anwenden, da jede linke Seite mindestens ein Nichtterminal enthält. Diese Einschränkung in der Definition allgemeiner formaler Grammatiken ist nicht wirklich notwenig, sie macht Dinge allerdings klar, wo eine Ableitung zu Ende ist / sein muss. Es handelt sich also gewissermaßen um das Gegenteil von Syntax-Antizucker (mir ist gerade keine Substanz eingefallen, deren Geschmack universell als abstoßend empfunden wird). Wir können Grammatiken, die verbotene Produktionen der Form αβ mit αΣ enthalten, immer "auf Linie" bringen, indem wir jedes Terminalsymbol x in den Produktionen durch ein neues Nichtterminal X ersetzen und schließlich Produktionen Xx einführen.

Beispiel 7.4 Versuchen wir nun, eine allgemeine formale Grammatik für die Sprache L={anbncn | n0} zu erstellen. Wir haben ja bereits gesehen, dass es zu dieser Sprache keine kontextfreie Grammatik gibt. Als ersten Versuch kopieren wir die obige Grammatik, allerdings lassen wir nur die Vertauschungsregeln zu, die die Buchstaben in die richtige Reihenfolge bringen: SABCS | ϵBAABCAACCBBCAaBbCc Offensichtlich kann jedes Wort in L erzeugt werden, allerdings auch Wörter wie abcabc, die nicht in L sind. Können wir die erzeugte Sprache beschreiben? Ich glaube, es ist die Sprache aller abc-Wörter w mit gilt #a(w)#b(w)#c(w)und#a(v)#b(v)#c(v)für alle Präfixe v von w wobei #b(v) die Anzahl der in v enthaltenen b ist.

Nachdem also unser erster Versuch gescheitert ist, unternehmen wir einen zweiten. Wir stellen uns die Ableitung als aus zwei Phasen bestehend vor. In der ersten wird eine Wortform w{A,B,C} erzeugt mit #A(w)=#B(w)=#C(w) erzeugt. In einer zweiten wandert ein Kontrollsymbol von links nach rechts durch und wandelt jeden Großbuchstaben in einen Kleinbuchstaben um, weigert sich aber bei Großbuchstaben, die in der falschen Reihenfolge stehen. Wir brauchen nun sieben Nichtterminale N={S,A,B,C,X,Y,Z}. Für S haben wir die Produktionen S1SABCS2X so dass SX(ABC)n gilt. Als nächstes brauchen wir die Vertauschregeln, um alles in die richtige Reihenfolge zu bringen: BA3ABCA4ACCB5BC Die Nichtterminale X,Y,Z stehen für folgendes:

  • X: will A in a umwandeln: XA6aX Zu jedem Zeitpunkt können wir beschließen, nun keine A in a mehr umzuwandeln, sondern nun B-Symbole zu erwarten: X7Y
  • Y: will B in b umwandeln oder mit C fortfahren: YB8bYY9Z
  • Z: will C in c umwandeln. Wir können aber auch einfach aufhören, zum Beispiel wenn wir den rechten Rand erreicht haben: ZC10cZZ11ϵ

Nun müssen wir zeigen, dass die Grammatik die Sprache L erzeugt. Für jedes Wort anbncnL müssen wir zeigen, dass wir es ableiten können: S1S(ABC)n2X(ABC)n3,4,5XAnBnCn6anXBnCn7anYBnCn8anbnYCn9anbnZCn10anbncnZ11anbncn

Als zweites müssen wir zeigen, dass jedes abgeleitete Wort Sw{a,b,c} auch in L ist, also die Form anbncn haben. Wir machen das nur zu 80% formal.

Die erste Beobachtung ist: solange S in der Wortform β vorkommt, hat diese die Form β=Sγ mit γ{A,B,C} enthält gleich viele A wie B wie C.

Behauptung 7.5 Sei #A,a(β) die Anahl der A und a in der Wortform β. Wenn Sβ, dann gilt
  1. #A,a(β)=#B,b(β)=#C,c(β)
  2. Außer A,a,B,b,C,c enthält β höchstens ein weiteres Symbol, und dies ist in {S,X,Y,Z}.
  3. Wenn das Symbol enthält, dann ist . Wenn es enthält, dann ist . Wenn es enthält, dann ist es . In allen drei Fällen enthält keine Terminalsymbole.
  4. Wenn es kein Symbol in enthält, dann ist es von der Form und enthält keine Terminalsymbole.
Wir behaupten also, dass das in Punkt 3 aus den Nichtterminalen besteht, die jedoch nicht in der korrekten Reihenfolge sein müssen. Wir können auch gar nicht verbieten, dass in einer Ableitung die Vertausch-Regeln 3,4,5 und die Kontroll-Regeln 6,7,8,9,10,11 vermischt angewandt werden.

Die Behauptung kann man beispielsweise mit Induktion über die Länge der Ableitung zeigen. Intuitiv gesprochen: Sie gilt unmittelbar, nachdem angewandt wurde; danach überträgt sich ihre Gültigkeit Schritt für Schritt (z.B. weil Terminalsymbol immer nur links vom Symbol erzeugt werden können).

Wenn nun also und kein Nichtterminal enthält, also , dann können keine weiteren Produktionen angewandt werden und die Ableitung endet. Wenn das also ein Wort sein soll, muss gelten und somit gelten. Da nach Behauptung die Anzahl der drei Symbole gleich sein muss, gilt also und somit .

Beispiel 7.6 Im Teilkapitel 5.10 gab es Übungsaufgabe 5.10.2, in der zu zeigen war, dass nicht kontextfrei ist. Allerdings ist kein sehr kompliziertes Gebilde. So könnten Sie recht einfach ein Programm schreiben, dass für ein Eingabewort prüft, ob es in ist. Können wir also auch eine formale Grammatik schreiben?

Dies geht sogar nohc einfacher als die obigen Sprachen. Wir schaffen eine Startregel: Die Nichtterminale und zeigen den linken und rechten Rand an. Wir können am linken Rand einen "Verdopplungssymbol" erzeugen. Dies kann nur nach rechts durchwandern und bei verschwinden und verdoppelt dabei jede , die es trifft: Schlussendlich definieren wir End-Produktionen, die die Randmarkierungen löschen: Hier sehen Sie nun ein Beispiel für eine Ableitung:

Wagen wir ein letztes Beispiel: die Sprache aller Wörter, deren Länge eine Quadratzahl ist. Spätestens dieses Beispiel sollte Sie davon überzeugen, dass allgemeine formale Gramatiken, im Gegensatz zu kontextfreien und regulären, nicht nur Formate syntaktisch beschreiben, sondern komplizierte Rechnungen durchführen können. Sie stellen somit ein völlig andersartiges Biest dar.

Beispiel 7.7 Sei die Sprache aller Wörter über , deren Länge eine Quadratzahl ist. Wir werden als erstes eine Multiplikationsgrammatik erzeugen. Dies soll eine Menge von Produktionen sein, die Ableitungen der Form ermöglicht. Wenn wir dies geschafft haben, sind wir fertig. Mittels können wir alle ableiten. Die Multiplikationsgrammatik wandelt uns dies in um. Schlussendlich führen wir ein Killersymbol ein, das bei entsteht und sich nach links durcharbeitet, dabei die in durch ersetzt: Es bleibt also, die Multiplikationsgrammatik zu entwerfen, die, um es zu wiederholen, ermöglicht, aber nicht wirklich viel mehr. Wir erschaffen die Produktion Das neue Nichtterminal bedeutet soviel wie "ein , das bereits abgearbeitet worden ist." Das Nichtterminal bedeutet: erzeuge rechts vom -Block einen -Block gleicher Länge. Wir wollen also Die einfachste Möglichkeit ist vielleicht, das nach rechts durchrutschen zu lassen und dabei jedes durch ein ersetzen zu lassen: Das erzeugt also von seinem Entstehen bis zu seinem Verschwinden bei genau viele -Symbole. Wir erstellen nun Regeln, die uns zwingen, jedes nach rechts laufen zu lassen, wo sie in ein umgewandelt werden können: Überzeugen wir uns, dass dies den gewünschten Effekt hat.
  • Wir können nur loswerden, indem wir es in das Killersymbol umwandeln. Das Killersymbol kann nur bei verschwinden. Dazwischen kann es nur die Zeichen passieren. Zum Zeitpunkt, wo wir anwenden, darf die Wortform also keine -Symbole mehr enthalten.
  • Wir können eine nur verschwinden lassen durch und nur auf diese Weise entstehen lassen. Wir produzieren also, wenn wir mit beginnen, im Laufe der Ableitung genau mal ein .
  • Um ein wieder verschwinden zu lassen, muss es den ganzen -Block durchlaufen und produziert damit insgesamt viele (\tilde{C}\).
  • Da wir insgesamt viele produzieren und jedes insgesamt viele produziert, werden insgesamt viele erzeugt.
  • Jedes kann nur in ein umgewandelt werden. Es entstehen also insgesamt viele .
Wenn wir also aus ein Wort ableiten, so muss zum Zeitpunkt der Produktion die Wortform so aussehen: Wir können die Produktion zwar schon früher anwenden; wenn da allerdings noch - oder -Symbole enthalten sind, ist es game over: wir könnten die nie mehr in Terminale umwandeln.

In einer leichten Variation können wir auch die Sprache erzeugen.

Die Sprache \{a^m b^n c^{m+n}\} können wir eh: die ist sogar kontextfrei. Wir können also Arithmetik mit formalen Grammatiken "programmieren".

Übungsaufgabe 7.1 Geben Sie ein formale Grammatik für an. Dies ist auch ein Paradebeispiel für eine Sprache, die nicht kontextfrei ist.
Überlegen Sie, wie man "lineare Suche" implementieren könnte:

Übungsaufgabe 7.2 Sei die Sprache über mit mit . Sie implementiert also im Prinzip die Funktion
List.member x list
die überprüft, ob in der angegebenen Liste enthalten ist: Tip: das ist einfach, wenn Sie bereits eine Grammatik für das vorherige Problem haben. Erzeugen Sie und lassen dann aus und den Rest der Liste entstehen.

Sie haben sicherlich gemerkt, dass wir die Grammatikproduktionen nun nicht mehr nur zum Erzeugen verwenden wie bei kontextfreien Sprachen, sondern zum Umformen, Rumschieben, Kopieren etc. Es ist nun an der Zeit, die Welt der Grammatiken zu verlassen und zu formalisieren, was man mit Umformen, Rumschieben, Kopieren erreichen kann. In anderen Worten: eine Formalisierung des Begriffs des Berechnens.