Bitte schicken Sie Korrekturen, Verbesserungsvorschläge und weitere Fragen, die in den Kommentaren zu den Beispielen nicht behandelt werden an mich: nino@complang.tuwien.ac.at. Genauer erklärte Musterlösungen kommen Ihren Kollegen zugute und wir freuen uns immer über gute Ergebnisse.
![[Bild]](ang1.gif)
Bestimmen Sie die First- und Follow-Mengen aller Nonterminale.
| Nonterminal | First-Menge | Follow-Menge |
|---|---|---|
| DEF | {class,interface} | {$} |
| CLASS | {class} | {$} |
| INTERFACE | {interface} | {$} |
| EXTENDS | {extends, } | {implements,"{"} |
| IMPLEMENTS | {implements, } | {"{"} |
| FIELDS | {field} | {"}"} |
![[Bild]](ang2.gif)
Erzeugen Sie für das obige Programmstück Quadrupel-Code nach der Kontrollflußmethode. Ein INTEGER ist 4 Byte groß. Die Untergrenze aller Indexbereiche ist 0. Optimieren Sie den Code NICHT.
if i < 5 goto L1
goto IFFALSE
L1: if j < 8 goto WBEGIN
goto IFFALSE
WBEGIN: t1 := i * 8
t2 := t1 + j
t3 := t2 * 4
t4 := t3 + adr(a)
t5 := @t4
if t5 < 12 goto WTRUE
goto WFALSE
WTRUE: t6 := i * 8 (* 1 *)
t7 := t6 + j
t8 := t7 * 4
t9 := t8 + adr(a)
@t9 := k
t10 := k * 4
t11 := t10 + adr(b)
t12 := @t11
k := t12
t13 := k * 4 (* 2 *)
t14 := t13 + adr(b)
@t14 = 1
goto WBEGIN
WFALSE: goto IFEND
IFELSE: k := 0
IFEND: (* ENDE *)
k := b[k]
b[k] := 1
sondern diesem:
k1 := k
k := b[k]
b[k1] := 1
Sie sehen also, daß "Optimierungen" dieser Art nicht nur nicht der vorgeschriebenen Vorgangsweise im Skriptum entsprechen, sondern auch die Semantik des erzeugten Codes ändern können.
Für a[i,j] wird die Formel im Skriptum zu (i*8+j)*4 + adr(a), da i1 = i, i2 = j, n2 = 8 und w = 4 ist.
a) (10%)
Geben Sie eine Reguläre Definition für Ausdrücke an, die folgendermaßen definiert sind: eine Ziffer n von 0 bis 5, gefolgt von höchstens n Großbuchstaben, falls n gerade (oder 0) ist und höchstens n Kleinbuchstaben, falls n ungerade ist (ohne Umlaute), das ganze beliebig oft wiederholt. Beispiel: 3ab4AAA002BB15. (0 ist hier die Ziffer Null, nicht Buchstabe O)
b) (15%)
Geben Sie eine Reguläre Definition für Bit-Ketten an, deren Länge ein Vielfaches von 8 ist (8, 16, 24 ...), mit gerader Parität in jedem 8-Bit-Block (gerade Anzahl von 1ern, oder nur 0en), an. Beispiel: 00010010 01110010 00001111.
K = [a-z]? G = [A-Z]? EXPR = ( 0 | 1 K | 2 G G | 3 K K K | 4 G G G G | 5 K K K K K ) +
U2 = 01 | 10 G2 = 00 | 11 U4 = U2 G2 | G2 U2 G4 = U2 U2 | G2 G2 B = U4 U4 | G4 G4 EXPR = ( B )+Oder auch
G4 = 0000 | 0011 | 0101 | 0110 | 1001 | 1010 | 1100 | 1111 U4 = 0001 | 0010 | 0100 | 0111 | 1000 | 1011 | 1101 | 1110 B = U4 U4 | G4 G4 EXPR = ( B )+Oder gar
B = 00000000 | 00000011 | 00000101 | ... EXPR = ( B )+... wobei alle Möglichkeiten aufgezählt werden (nicht empfehlenswert) oder eindeutig beschrieben werden (mit Erklärung, was da stehen sollte). Auch diese Lösung ist korrekt.
Folgende Grammatik beschreibt verschachtelte Flächen mit Position und Farbe (Grauton):
Die 4 Zahlen nach flaeche sind die Eckpunkte x1,y1,x2,y2 für die gilt: x2>=x1 und y2>=y1. Die Zahl nach grau gibt den Helligkeitswert an (Weiß = 1, Schwarz = 0). Die Flächen überschneiden sich nicht. Erweitern Sie die Grammatik zu einer attributierten Grammatik, die im Attribut grau von S den durchschnittlichen Helligkeitswert der gesamten Fläche berechnet (Summe aller Teilflächen multipliziert mit ihren Helligkeitswerten, dividiert durch die Gesamtfläche). Mit inum.val und rnum.val erhalten Sie die Zahlenwerte. Achten Sie darauf, daß Sie keine Bereiche doppelt zählen. Beispiel:
F -> schwarz { F.g := 0 }
F -> weiss { F.g := 1 }
F -> grau rnum { F.g := rnum.val }
Hier werden die Helligkeitswerte initialisiert und nach oben im
Attribut g weitergegeben.
FARBE -> F { FARBE.v := FARBE.s * F.g }
Hier sind wir in einem Reckteck ohne Teilflächen. Wir benötigen also den
Helligkeitswert (wird in F.g synthetisiert) und die Fläche des
Rechtecks, die wir von FARBE bekommen werden und können nun
einen Wert berechnen, der der Helligkeit dieser rechteckigen Fläche
multipliziert mit ihrer Fläche entspricht. Alternativ dazu könnte man die Multiplikation auch in der nächsten Regel durchführen.
FLAECHE -> flaeche inum1 inum2 inum3 inum4 FARBE
{
FLAECHE.s := (inum2.val - inum1.val)
* (inum4.val - inum3.val)
FARBE.s := FLAECHE.s
FLAECHE.v := FARBE.v
}
In dieser Regel wird die Fläche des angegebenen Rechtecks berechnet und
zur nach unten weitergegeben, damit dort die Berechnung des Attributs
v durchgeführt werden kann. Bisher funktioniert das nur für
Rechtecke ohne enthaltene Teilflächen, wir müssen also noch die
nachfolgende Regel für diesen Fall implementieren.
FARBE -> "(" F FLAECHEN ")"
{
FARBE.v := (FARBE.s - FLAECHEN.s)
* F.g + FLAECHEN.v
}
Wir gehen hier davon aus, daß wir die Gesamtfläche der enthaltenen Teilflächen
in FLAECHEN.s synthetisiert haben, sowie deren Helligkeitswerte
gewichtet mit den Flächen (deren Größe) in FLAECHEN.v bekommen.
Somit können wir den gewichteten Gesamt-Helligkeitswert für die umgebende Fläche
und die enthaltenen Flächen berechnen. Dazu ziehen wir die Gesamtfläche der
Teilflächen von der umgebenden Fläche ab, um keine Bereiche doppelt zu zählen.
FLAECHEN -> FLAECHE { FLAECHEN.s := FLAECHE.s; FLAECHEN.v := FLAECHE.v }
FLAECHEN -> FLAECHEN2 FLAECHE
{
FLAECHEN.s := FLAECHEN2.s + FLAECHE.s
FLAECHEN.v := FLAECHEN2.v + FLAECHE.v
}
Hier werden die Größen einer Liste von Teilflächen sowie deren
gewichtete Helligkeitswerte aufsummiert.Es fehlt nur mehr die endgültige Berechnung der durchschnittlichen Helligkeit der gesamten Fläche. Wir benötigen dazu die Gesamtfläche (das ist jene der auf der obersten Ebene definierten, also des umgebenden Rechtecks) sowie den gewichteten Helligkeitswert für diese Fläche.
S -> FLAECHE { S.grau := FLAECHE.v / FLAECHE.s }
Bei dieser Prüfung war die attributierte Grammatik anscheinend viel leichter als bisher, da fast alle Teilnehmer relativ gut damit zurecht kamen. Fehler gab es u.a. bei der Berechnung der Fläche und manchmal wurden Attribute nicht bei allen Produktionen fuer ein Nonterminal berechnet.