5.4 Von einer regulären Grammatik zu einem endlichen Automaten an einem Beispiel
5.4 Von einer regulären Grammatik zu einem endlichen Automaten an einem Beispiel
Theorem 5.4.1 Zu jeder kontextfreien Grammatik $G = (\Sigma, N, S, P)$ gibt es einen Kellerautomaten $M = (\Sigma, Q, \Gamma, \qstart, \delta)$, der die gleiche Sprache akzeptiert, also $L(G) = L(M)$.
In diesem Unterkapitel wollen wir das Gelernte an einem konkreten Beispiel anwenden. Wir beginnen (1) mit einer Beschreibung eines Formats in natürlicher Sprache; (2) basteln uns daraus mit Hilfe des "Baukastenprinzips" eine reguläre Sprache; (3) säubern diese, indem wir Regeln der Form $X \rightarrow Y$ und $X \rightarrow a$ eliminieren; (4) bauen einen nichtdeterministischen endlichen Automaten; (5) transformieren diesen in einen deterministischen endlichen Automaten.
Unsere Sprache $L$ soll so ähnlich sein wie die der
erlaubten Domainnamen, allerdings mit ein paar
Abänderungen, um die obigen Transformationen spannender zu
machen. Ein Wort in unserer Sprache besteht aus einer
nichtleeren Folge von
Labels
die jeweils durch einen
.
separiert sind. Jedes Label ist eine nichtleere Folge von
Blöcken (ein nichtleerer String aus Buchstaben und Zahlen),
separiert durch
:
oder
-
aber niemals durch beides
innerhalb eines Blockes. Also:
bla:bla:blue.xyz-12-zx.b:x:yyy:xxx:aaa
ist ein Wort in $L$, aber
a:b-c.hello
ist kein Wort in
$L$,
da das erste Label die Separatoren
:
und
-
mischt. Habe ich $L$ genau genug beschrieben?
Stellen wir eine Meta-Frage: Was zählt überhaupt als
genaue Beschreibung
einer Sprache? Wir können uns dem
Mund fusselig reden und Beispiele und Nicht-Beispiele
angeben, am Ende aber werden wir irgendwann beginnen,
formale Regeln aufzustellen, die unsere Sprache beschreiben
- wir werden also im Prinzip eine
Grammatik
schreiben.
Tun wir dies also.
Beginnen wir mit dem Alphabet. Da es 62 alphanumerische
Zeichen gibt:
a..zA..Z0..9
und wir uns keine unnötige
Arbeit machen wollen, beschränken wir uns auf ein Zeichen:
a.
Dazu kommen die Separatoren
:-..
Also:
$\Sigma = \{a,.,:,-\}$.
Stellen Sie sich einfach vor, $a$
stehe für beliebige alphanumerische Zeichen. Sowohl
Grammatik als auch Automaten lassen sich einfach anpassen.
Wir beginnen ganz unten und schreiben eine Grammatik für
Blöcke, also nichtleere Strings aus alphanumerischen
Zeichen.
Als nächstes führen wir ein nichtterminales Symbole $C$
für Labels mit
:
ein und ein Nichtterminal $D$ für
Labels mit
-.
Wir wählen die Buchstaben
$C,D$,
weil
:
auf Englisch
colon
und
-
dash
heißt.
$C$-Labels
können wir uns nach dem Baukastenprizip bauen, in dem wir
Theorem 5.1.14
anwenden. Wir fügen zur
"End-Produktion" $B \rightarrow a$ eine weiter Produktion
$B \rightarrow a:B$ hinzu und tun das gleiche für
$B \rightarrow b$.
Allerdings benennen wir $B$ in $C$ um,
damit keine Verwechslungsgefahr mit dem ursprünglichen $B$
aufkommt. Das gleiche machen wir für
$D$.
Von $L$ lassen sich nun also alle Labels ableiten. Wir
brauchen nun zum Schluss wieder eine Folge von
$L$,
mit
.
separiert, müssen also wieder
Theorem 5.1.14
anwenden, dieses mal auf die von $T$ erzeugte Sprache. Im
Ergebnis benennen wir das Startsymbol in $S$ um.
Um eine "richtig" reguläre Sprache zu erhalten, entzerren wir die erweitert regulären Produktionen wie $C \rightarrow a{:}C$. Dafür brauchen wir neue Symbole $C', D', S'$:
Wir wollen nun alle Produktionen der Form $Y \rightarrow x$ eliminieren. Hierfür nehmen wir uns ein neues Nichtterminal $E$ und ersetzen $Y \rightarrow x$ durch $Y \rightarrow xE$ und fügen die Produktion $E \rightarrow \epsilon$ hinzu.
In einem zweiten Schritt wollen wir die Produktionen $S \rightarrow C$ und $S \rightarrow D$ eliminieren, sodass wir nur noch Produktionen der From $X \rightarrow aY$ und $E \rightarrow \epsilon$ haben. Wir gehen vor wie in Theorem 5.1.7 beschrieben. Wir ersetzen $S \rightarrow C$ also durch alle Produktionen der Form $S \rightarrow \alpha$, wobei $\alpha$ eine Wortform ist, die sich aus $C$ ableiten lässt und nicht nur aus einem einzelnen Nichtterminal besteht; dies trifft glücklicherweise auf alle rechten Seiten der $C$-Produktionen zu; gleiches gilt für $D$. Wir erhalten:
Dies sollte nun einfach sein. Wir erschaffen Zustände $S, C, C', D, D', S', E$ und übersetzen jeden Grammatik-Pfeil in einen Automaten-Pfeil.
Ich habe die Zeichen
.:-
rot unterlegt, weil man sie
sonst kaum erkennen würde in dem Automaten.
Unser nichtdeterministischer endlicher Automat hat Zustandsmenge $Q = \{S, S', C, C', D, D', E\}$, also insgesamt sieben Zustände. Wenn wir genau nach Buch vorgingen, müssten wir den endlichen Automaten auf der Zustandsmenge $2^Q$ definieren, er hätte also $2^7 = 128$ viele Zustände. Das wäre jetzt für einen Rechner kein Problem, aber in diesem vorlesungsskript doch etwas ungünstig. Wir gehen lazy vor, erschaffen Zustände in $2^Q$ also nur dann, wenn wir sie brauchen. Wir beginnen mit dem Zustand $\{S\}$ und legen dann an jeden Zustand Kanten an, jeweils mit $a, :, -, .$ beschriftet, und erschaffen, falls nötig, dabei neue Zustände. In der folgenden Animation sehen Sie manchmal den mit einem Kreuz markierten Fehlerzustand (trap state). Die akzeptierenden Zustände sind mit fettem Rand markiert.
Dieser Automat hat deutlich weniger also 128 Zustände, nämlich mit nur sieben genau so viele wie der nichtdeterministische (es ist Zufall, dass beide gleich viele Zustände haben; messen Sie dieser Tatsache keine Bedeutung bei). Wir könnten nun von diesem Automaten ausgehend wiederum eine reguläre Grammtik bauen, die in diesem Falle sogar einfacher und klarer wäre als die ursprüngliche. Wenn wir erweitert reguläre Grammatiken erlauben, so können wir den deterministischen Automaten besonders konzise in eine Grammatik fassen:
Die Zustände des deterministischen Automaten beschreiben
im Prinzip das, was wir uns merken müssen, wenn wir so
einen String "parsen": Zustand
$\{C',C,E,D,D',S'\}$,
der
in der Grammatik dann zum Nichtterminal $T$ wird, bedeutet
beispielsweise
das Label hat schon begonnen, wir wissen
aber noch nicht, ob es eines mit
:
oder eines mit
-
ist. Der Zustand $\{C',C,E,S'\}$ bzw. das Nichtterminal $C$
heißt dann
:
wir
sind innerhalb eines Labels mit_
:.
Übungsaufgabe 5.4.1 Erinnern Sie sich an Aufgabe 5.3.1. Hier sehen Sie einen nichtdeterministischen endlichen Automaten für die Sprache $L_4 \cup L_6$, also die Sprache aller Wörter $1^n$ für ein $n$, das durch 4 oder 6 teilbar ist. Da unser Alphabet $\Sigma = \{1\}$ eh nur aus einem Zeichen besteht, habe ich auf die Beschriftung der Kanten verzichtet.
Dieser Automat hat 11 Zustände. Sein Potenzmengenautomat hätte also $2^{11} = 2048$ Zustände. Führen Sie die Konstruktion lazy durch, indem Sie vom Startzustand $\{S\}$ ausgehend die Folgezustände konstruieren. Wieviele Zustände bekommen Sie?