| CB-I im WS99/00 Blatt 2 mit Lösungen |
Aufgabe 1
Sei eine Grammatik
G=(N,T,P,S)
in
Chomsky-Normalform gegeben und
w
ein Wort aus
L(G)
mit
|w|=n
.
- Gelte
S ->kw
. Bestimmen Sie
k
.
-
Geben Sie eine Abschätzung für die maximale Tiefe des
Strukturbaums der Ableitung von
w
an.
Lösung:
-
Zunächst benötigt man
n
Reduktionen, um einstellige
Terminalsymbole in einstellige Nichtterminale zu reduzieren.
Dann benötigt man jeweils eine Reduktion, um aus zwei
Nichtterminalen ein Nichtterminal zu reduzieren - also die
verbleibende "Wortlänge" m
um 1
zu
verkürzen. Da das
Startsymbol übrigbleibt, muß man das (n-1)
-mal
machen, insgesamt
k = n + (n-1) = 2n - 1
-
Die Reduktion der Terminalsymbole auf die zugeordneten
Nichtterminale kann man auf jeden Fall parallel machen.
Danach ist der worst case offenbar, wenn pro Ebene
des Strukturbaums nur eine Reduktion stattfinden kann (und
das ist auch erreichbar, man denke sich eine kleines
Beispiel aus!). Ergibt, mit den obigen Überlegungen,
an notwendigen Baumebenen:
1 + (n-1) = n
Aufgabe 2
Geben Sie zu
G=({A,B,C,D,E},{a,b},P,S)
mit
P={ S::=AB|CA, A::=DE, B::=BC|AB, C::=aB|b,
D::=eps, E::=A|a}
eine äquivalente kontextfreie
Grammatik an, die keine nutzlosen Symbole, keine Ketten- und
eps-Produktionen enthält.
In der Originalaufgabe war versehentlich C::=aB|B
angegeben worden. Wir behandeln hier die o.g. Aufgabe.
Lösung:
Man kann das natürlich "von Hand" machen, und hoffen, das man es
richtig macht. Besser ist, man folgt den folgenden Algorithmen:
Zunächst machen wir die Grammatik
eps-frei, indem wir
alle
eps streichen und für alle Produktionen, in denen auf
der rechten Seite Nichtterminale stehe, die zu
eps abgeleitet
werden konnten, Produktionen ohne diese Nichtterminale
hinzufügen:
P1 = {
S::=AB|CA ,
A::=DE ,
A::=E ,
B::=BC|AB ,
C::=aB|b ,
E::=A|a
}
Dann entfernen wir alle nutzlosen Symbole, also alle
Nichtterminale, die nicht zu Wörtern führen, mit folgendem
Algorithmus (nach Aho/Ullman,
The Theory of
Parsing, Translation and Compiling, 143ff). Wir bauen dazu die
Nichtterminalsymbole neu auf, indem wir zunächt die "von unten",
also von den Terminalen erreichbaren, hinzunehmen, von denen
dann die "von
oben", also vom Startsymbol, herleitbaren verwenden:
Wir konstruieren induktiv die Menge der Nichtterminale neu.
Sei ein KFG G=(N,T,P,S)
gegeben. Wir definieren
N0:={}
, und i=1
; Dann
setzen wir solange Ni:= {A | A::=a
ist aus
P
und
a
ist aus
(Ni-1U
T)*}
U
Ni-1
, bis
Ni=Ni-1
erreicht ist.
Hier:
N1={C,E}
,
N2={A,C,E}
,
N3={S,A,C,E}
,
N4={S,A,C,E}
.
Damit wird
N4
unser neues
N1
, und wir müssen noch die
Produktionen um die bereinigen, die nicht mehr verfügbare
Symbole benutzen:
P2 = { S::=CA , A::=E , C::=b , E::=A|a }
Nun müssen wir ggf. aus
G2=(N1,T,P2,S)
noch unerreichbare Symbole entfernen.
Wir konstruieren (wieder induktiv) die Menge der erreichbaren
Symbole V
(Nichtterminale und Terminale), beginnen aber mit
V0:={S}
. Dann bestimmen wir
Vi:= {X | es gibt A::=aXb in P und A ist aus
Vi-1} U Vi-1
und iterieren wieder
solange, bis Vi=Vi-1
ist. Dann bereinigen wir die Mengen durch Schnitt mit der
resultierenden Vi
, so daß nur noch
erlaubte Symbole und Produktionen vorkommen, und erhalten
G3=(N2,T1,P3,S)
.
In diesem Fall:
V0:={S}
,
V1:={S,C,A}
,
V2:={S,C,A,b,E}
,
V3:={S,C,A,b,E,a}
,
V4:={S,C,A,b,E,a}
,
also ist hier
G3=G2
.
Bleibt die Entfernung der Kettenproduktionen, die darauf
hinausläuft, die 'single Produktions' zu entfernen, also die
Reglen, dessen rechte Seite aus genau einem Nichtterminal
besteht. Algorithmus:
Für alle A
aus N
wird iterativ die
Menge der aus A herleitbaren Nichtterminale
NA
konstruiert:
N0={A}
, und i:=1
Ni={C|B->C ist in P, C ist aus N, und B ist aus
Ni-1} U Ni-1
- Führe das Verfahren fort, bis
Ni=Ni-1
. Dann setze
NA:=Ni
Dann konstruieren wir die neuen Produktionen
P4
so:
Wenn B->alpha
aus P3
ist, und es ist keine Single-Produktion, dann nehme für alle
A
aus NB
die Regel
A->alpha
in P4
auf.
Hier:
NS:={S}
,
NA:={A,E}
,
NC:={C}
,
NE:={E,A}
, also
betr.
S::=CA
:
P41 =
{S::=CA}
betr.
C::=b
:
P42 =
{S::=CA,C::=b}
betr.
E::=a
:
P43 =
{S::=CA,C::=b,A::=a,E::=a}
Jetzt müssen wir noch einmal unerreichbare Symbole entfernen,
und erhalten schließlich:
G4=({S,A,C},{a,b},P5,S)
mit
P5={ S::=CA, C::=b, A::=a }
Aufgabe 3
Gegeben sei eine Bücherliste der Form
Author :: Titel :: Erscheinungsjahr :: Verlag
also beispielsweise
Aho,Sethi,Ullman :: Compilerbau :: 1988 :: Addison-Wesley
Helmut Kopka :: LaTeX - Eine Einführung :: 1991 :: Addison-Wesley
Sie wollen diese, als Textdatei vorliegende Liste, in eine
html-Version verwandeln, und dafür Techniken des Compilerbaus
verwenden. Wie gehen Sie vor? Geben Sie Tokenklassen und
Automaten für die lexikalische Analyse, und eine Grammatik für
die syntaktische Analyse an!
Lösung:
Das ist eine Bastelaufgabe, die unterschiedlich ausfallen
kann. Man sollte solche oder ähnliche Aufgaben zur Übung lösen,
damit man mit den Techniken (reg. Ausdrücke, KFG) vertraut wird.
Eine mögliche einfache Herangehensweise:
Liste ::= Zeile | Zeile Liste
Zeile ::= Autoren STOP Titel STOP Jahr STOP Verlag
Autoren ::= Autor | Autor ', ' Autoren
Titel ::= Wörter
Verlag ::= Wörter
Jahr ::= ZAHL
Wörter ::= WORT | WORT Wörter
mit den aus der lexikalischen Analyse stammenden Terminalen
STOP
,
ZAHL
und
WORDS
aus
(in
lex
-ähnlicher Angabe):
' '+*::' '+ liefert STOP
[0-9]+ liefert ZAHL
[A-Za-zäöüÄÖÜ-]+ liefert WORT
In dieser Form dürfen noch mehr Leerzeichen die Felder trennen,
aber Jahresangaben dürfen noch sehr merkwürdig sein - da kann
man naoch einiges verbessern!
Aufgabe 4
Geben Sie einen endlichen Automaten an, der alle Vielfachen von
3 in binärer Darstellung akzeptiert.
Lösung:
Man kann das folgendermassen angehen: Eine Binärzahl kann man von
links lesen. Der Wert ist dann der bereits gelesene Wert, mit zwei
multipliziert, plus 1, falls man dann eine 1 liest, und plus 0
sonst. (Bsp:
(110)2 = (1*2+1)*2+0 =
6
). Ein Automat kann nun die Reste bei Dision durch 3
betrachten (mod 3-Rechnung):
Ist der Rest 0 (Zustand q0), war
der Wert durch 3 teilbar. Lese ich dann eine 0, bleibt er das -
und der Zustand bleibt q0. Lese ich eine 1, bleibt ein Rest von 1, und
wir gehen in den Zustand q1, unsere gelesenen Zahl ist
x=n*3+1
.
Lesen wir aus q1 eine 1, erhalten wir
x2=2*x+1=2*n*3+2*1+1=2*(n+1)*3
, also
einen Rest 0, und wir wechseln wieder nach q0. Lesen wir aus q1
eine 0, erhalten wir
x2=2*x+0=2*n*3+2*1=m*3+2
, also einen
Rest 2, und wechseln in den Zustand q2.
Lesen wir aus q2 eine 1, erhalten wir
x3=2*x2+1=2*(m*3+2)+1=k*3+2
,
wir bleiben also im Zustand q2. Lesen wir eine 0, erhalten wir
x3=2*x2+0=2*(m*3+2)+0=l*3+1
,
also Rest 1, und wir wechseln wieder in Zustand q1.
Der entsprechende Automat
A = ({q0,q1,q2},{0,1},d,q0,{q0})
d(q0,0) = q0 d(q1,0) = q2 d(q2,0) = q1
d(q0,1) = q1 d(q1,1) = q0 d(q2,1) = q2
Man kann das auch allgemeiner zeigen siehe z.Bsp. van Leeuven,
Handbook of theoretical computer science Vol B, pp 36. |
Dietmar Lammers
Last modified: Mon Dec 20 17:39:02 MET 1999