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?