Formale Sprachen und Automaten Kapitel 6: Syntaxanalyse
Vorlesung an der DHBW Karlsruhe
Thomas Worsch Karlsruher Institut für Technologie, Fakultät für Informatik
Wintersemester 2012
Kapitel 6
Syntaxanalyse
Einleitung Lexikalische Analyse Lexer-Generatoren Syntaktische Analyse Der Algorithmus von Cocke, Younger und Kasami Der Algorithmus von Earley LR Parsing Nach der Syntaxanalyse
Inhalt
2/112
Einleitung Lexikalische Analyse Lexer-Generatoren Syntaktische Analyse Der Algorithmus von Cocke, Younger und Kasami Der Algorithmus von Earley LR Parsing Nach der Syntaxanalyse
Einleitung
3/112
6.3 Phasen eines Übersetzers I
Analyseteil I I I I
I
Vorverarbeitung (Makroersetzung) lexikalische Analyse syntaktische Analyse semantische Analyse
Syntheseteil I I I I
Erzeugung des Zwischencodes Optimierung des Zwischencodes Erzeugung des Maschinencodes Optimierung des Maschinencodes
quer dazu I
Verwaltung der Symboltabelle
I
Fehlerbehandlung
Einleitung
4/112
T-Diagramme I
Übersetzer C von Quellsprache S nach Zielsprache T implementiert in Programmiersprache I : S C T I
I
Beispielaufgabe: P I
Gegeben: zwei Übersetzer
C1 M2 P C2 M1 M1 P und M2
P I
Gesucht: ein Übersetzer
Einleitung
M2
5/112
T-Diagramme (2) M2
P I
Gesucht: ein Übersetzer
M2
:
P C3 M2 1. Schritt: P C1 M2 P P C2 M1 M1 M1 2. Schritt:
I
P C1 M2 P C4 M2 P C1 M2 P P C3 M2 M2 P P C2 M1 M1 M1
Falls M1 = M2 = M:
P C1 M P C4 M P C1 M P P C3 M M P P C2 M M M
Einleitung
6/112
Einleitung Lexikalische Analyse Lexer-Generatoren Syntaktische Analyse Der Algorithmus von Cocke, Younger und Kasami Der Algorithmus von Earley LR Parsing Nach der Syntaxanalyse
Lexikalische Analyse
7/112
6.5 I
Ein Programm(teil), das die lexikalische Analyse durchführt, heißt auch Lexer oder Scanner.
I
Im Deutschen manchmal: Symbolentschlüssler.
Lexikalische Analyse
8/112
6.6 Aufgaben des Lexers I
Eingabetext an passenden Stellen in eine Folge von Lexemen aufteilen.
I
Jedes Lexem passt zu einem Muster, oft durch reguläre Ausdrücke beschrieben.
I
Daraus kann automatisch eine effizient arbeitende Implementierung des Lexers erzeugt werden.
Lexikalische Analyse
9/112
6.6 Aufgaben des Lexers (2) Schnittstelle des Lexers: I I
Prozeduren zur Initialisierung und Beendigung nextToken: Aufruf führt dazu, dass I I
I
I
Token besteht aus Typ und unter Umständen noch weiteren Attributen. Beispiel: Token für Variablennamen I I
I
der Lexer im Eingabestrom nach dem nächsten Lexem sucht, für das er ein Token zurückliefert.
Typ: id Attribute: Name der Variable oder Verweis auf den Eintrag des Namens in der Symboltabelle
Die Token sind die Terminalsymbole der Grammatik, die den „kontextfreien Anteil“ der Programmiersprachensyntax beschreibt.
Lexikalische Analyse
10/112
6.7 Kommentare I
Einen Kommentar kann man als Lexem auffassen, für das kein Token erzeugt wird.
I
Leerzeichen kann der Lexer auch überlesen, sofern sie für das Programm bedeutungslos sind.
I
Es gibt allerdings Programmiersprachen (Fortran, Occam, Python, . . . ), bei denen die Position eines Lexems im Quellprogramm von Bedeutung sein kann. In einem solchen Fall ist der Lexer entsprechend aufwendiger zu implementieren.
Lexikalische Analyse
11/112
6.8 Beispiel I
I
Eingabe: erna = hugo + 1; aufeinanderfolgende Aufrufe von nextToken liefern: I I I I I I
I
(id,erna) (assignOp,) (id,hugo) (plusOp,) (num,1) (semi,)
Die syntaktische Analyse muss überprüfen, ob die Zeichenfolge id assignOp id plusOp num semi in der Grammatik ableitbar ist.
Lexikalische Analyse
12/112
Einleitung Lexikalische Analyse Lexer-Generatoren Syntaktische Analyse Der Algorithmus von Cocke, Younger und Kasami Der Algorithmus von Earley LR Parsing Nach der Syntaxanalyse
Lexer-Generatoren
13/112
6.10 Lexer-Generatoren I
Lexer-Generator: Programm zur automatischen Erzeugung von Lexern Eingabe: Datei, in der insbesondere mit Hilfe regulärer Ausdrücke beschrieben ist, Lexeme welcher Struktur zu suchen sind, und welche Token daraus zu erzeugen sind. Ausgabe: Quelle eines Programmes, das als Lexer auf die gewünschte Art arbeitet.
I
Beispiele: lex, flex und JLex, Werkzeuge in Übersetzergenerator-Suiten wie cocktail und Eli
Lexer-Generatoren
14/112
6.11 Reguläre Definitionen I
zur besseren Lesbarkeit regulärer Ausdrücke
I
Teilausdrücke können mit Namen bezeichnet werden Beispiel:
I
I I I I
I
digit → [0-9] letter → [a-zA-Z] id → letter (letter|digit)* /*[-+]?digit+)? num → digit+ (/.digit+)? (O
Wichtig: I
I
Auf der rechten Seite dürfen nur Namen regulärer Ausdrücke benutzen darf, die vorher definiert wurden. Direkte oder indirekte Rekursionen sind verboten.
Lexer-Generatoren
15/112
6.12 Eingabedatei für Lexergenerator I
reguläre Definitionen
I
Regeln, die einigen regulären Ausdrücken Aktionen zuordnen.
I
Programmstücke, die in den erzeugten Lexer mit eingebaut werden.
I
Aktion gibt an, was der Lexer tun soll, wenn nextToken aufgerufen wird und das zum nächsten Token gehörende Lexem zum jeweiligen regulären Ausdruck gehört. Zum Beispiel könnte für den regulären Ausdruck id als Aktion spezifiziert sein, dass
I
I
I
der gefundene Name in der Symboltabelle zu suchen und gegebenenfalls einzutragen ist und der Rückgabewert das Token id und als Attribut der Verweis auf den Symboltabelleneintrag zu liefern ist.
Lexer-Generatoren
16/112
6.13 Wichtig: I
I
Lexer versucht, zu einem regulären Ausdruck eine möglichst lange passende Folge von Eingabezeichen zu finden. Beispiel: aus Eingabe 123.45E67 wird vom Lexer I I
I
I
ein Token num mit Attribut 123.45E67 gemacht und nicht z. B. zwei num-Token mit Attributen 123.4 und 5E67.
Wenn das gleiche maximal lange Präfix der Eingabe auf die regulären Ausdrücke mehrerer Lexerregeln passt, wird bei vielen Lexergeneratoren ein Lexer erzeugt, der immer die erste passende Regel benutzt. Beispiel: I
I
reguläre Definition keyword → for|do|if|then mit Aktion für keyword vor der Aktion für id (wie oben) Dann wird der Lexer für die Zeichenfolge if in der Eingabe ein Token keyword zurückliefern und nicht ein Token id. Lexer-Generatoren
17/112
6.15 Beispiel: Lexerspezifikation für JLex Grobstruktur: hBenutzer-Codei %% hreguläre Definitioneni %% hRegeln mit Aktioneni
Lexer-Generatoren
18/112
6.15 Beispiel: Lexerspezifikation für JLex (2) Beispiel: I hBenutzer-Codei: import java.lang.System; class Simple { public static void main(String argv[]) .... { Yylex yy = new Yylex(System.in); Yytoken t; while ((t = yy.yylex()) != null) System.out.println(t); } } class Yytoken { Yytoken(int index, String text) { .... } private static final String tokName[] = { "UNKNOWN", "FLOAT", "INT", "ID" }; public int m_index; public String m_text; public String toString() {return .... } } I
%% Lexer-Generatoren
19/112
6.15 Beispiel: Lexerspezifikation für JLex (3) I
hreguläre Definitioneni: ALPHA = [A-Za-z] DIGIT = [0-9] ID = {ALPHA}({ALPHA}|{DIGIT}|_)* INT = {DIGIT}+ FLOAT = {INT}\.{INT} WHITE_SPACE_CHAR = [\n\ \t\b\012]
I
%%
Lexer-Generatoren
20/112
6.15 Beispiel: Lexerspezifikation für JLex (4) I
hRegeln mit Aktioneni: {WHITE_SPACE_CHAR}+ { } {FLOAT} { return (new Yytoken(1,yytext())); } {INT} { return (new Yytoken(2,yytext())); } {ID} { return (new Yytoken(3,yytext())); } . { return (new Yytoken(0,yytext())); } Lexer-Generatoren
21/112
6.16 Arbeiten mit JLex Voraussetzungen: I obige JLex-Spezifikation in Datei simple.lex I JLex irgendwo im CLASSPATH verfügbar Dann: I java JLex.Main simple.lex I I
erzeugt Datei simple.lex.java: Java-Quelle eines Lexers Ausgaben von JLex: Processing first section -- user code. Processing second section -- JLex declarations. Processing third section -- lexical rules. Creating NFA ..... Creating DFA ..... Minimizing DFA .....
I
I
javac simple.lex.java erzeugt den lauffähigen Lexer java Simple startet den Lexer. Lexer-Generatoren
22/112
6.19 I
Viele (aber nicht alle) Lexergeneratoren erzeugen tabellengesteuerte Lexer.
I
Sie bestehen im wesentlichen immer aus dem gleichen Code, der die endlichen Automaten simuliert,
I
die in Form einer Tabelle gespeichert sind.
Lexer-Generatoren
23/112
6.20 Kommentare in Programmiersprachen I
Angenommen, die lexikalische Analyse soll: I I
I
alle Kommentare aus dem Programm entfernen durch endlichen Automaten erledigt werden
Programmiersprachen, bei denen Kommentare durch ausgezeichnete Zeichenketten am Anfang und am Ende gekennzeichnet sind (z. B. /* und */ in C) I
geschachtelte Kommentare verboten
I
Man müsste die Eingabe auf korrekte Klammerstruktur überprüfen, und das kann ein endlicher Automat nicht.
I
andererseits: ein einfacher Zähler für die Schachtelungstiefe würde genügen
I
Manche Lexergeneratoren unterstützen den Anwender bei solchen Problemen.
Lexer-Generatoren
24/112
Einleitung Lexikalische Analyse Lexer-Generatoren Syntaktische Analyse Der Algorithmus von Cocke, Younger und Kasami Der Algorithmus von Earley LR Parsing Nach der Syntaxanalyse
Syntaktische Analyse
25/112
6.21 Wie kommt man von den nichtdeterministischen Kellerautomaten weg? I
Benutze nicht Kellerautomaten, sondern „andere Algorithmen“.
I
Einschränkung auf eine echte Teilklasse aller kontextfreien Grammatiken, damit deterministischen Kellerautomaten oder wenigstens eine „einfache“ Erweiterung davon reichen.
Syntaktische Analyse
26/112
Einleitung Lexikalische Analyse Lexer-Generatoren Syntaktische Analyse Der Algorithmus von Cocke, Younger und Kasami Der Algorithmus von Earley LR Parsing Nach der Syntaxanalyse
Der Algorithmus von Cocke, Younger und Kasami
27/112
6.22 Definition Grammatik in Chomsky-Normalform: I
Jede Produktion X → w mit X 6= S hat als rechte Seite I I
I
entweder ein Wort w ∈ N 2 (genau zwei Nichtterminalsymbole) oder ein Wort w ∈ T (genau ein Terminalsymbol).
Wenn es die Produktion S → ε gibt, dann kommt S bei keiner Produktion auf der rechten Seite vor.
Der Algorithmus von Cocke, Younger und Kasami
28/112
6.23 Satz Zu jeder kontextfreien Grammatik G gibt es eine kontextfreie Grammatik G 0 in Chomsky-Normalform, die zu G äquivalent ist (also L(G ) = L(G 0 )).
Der Algorithmus von Cocke, Younger und Kasami
29/112
6.24 Lemma Für jede kontextfreie Grammatik G kann man die Menge EPS(G ) = {X ∈ N | X ⇒∗ ε} aller Nichtterminalsymbole berechnen, aus denen das leere Wort ableitbar ist.
Der Algorithmus von Cocke, Younger und Kasami
30/112
6.25 Beweisskizze Algorithmus: i ←0 M0 ← {X | X → ε ∈ P} do i ←i +1 ∗ Mi ← Mi−1 ∪ {X | ∃w ∈ Mi−1 : X → w ∈ P} until Mi = Mi−1 return Mi
Der Algorithmus von Cocke, Younger und Kasami
31/112
6.26 Beispiel Grammatik G = ({X , Y , Z }, {a}, X , P) mit Produktionenmenge P = {X → YZ , Y → ZZ , Z → a|ε} Der obige Algorithmus berechnet nacheinander: M0 = {Z } M1 = {Z , Y }
wegen Y → ZZ ∈ P
M2 = {Z , Y , X }
wegen X → YZ ∈ P
M3 = {Z , Y , X }
(keine Änderung mehr)
Also ist EPS(G ) = {X , Y , Z }.
Der Algorithmus von Cocke, Younger und Kasami
32/112
6.27 Lemma Zu jeder kontextfreien Grammatik G = (N, T , S, P) kann man eine kontextfreie Grammatik G 0 = (N, T , S, P 0 ) berechnen, für die gilt: I
L(G 0 ) = L(G ) r {ε} und
I
keine Produktion von G 0 hat ε als rechte Seite.
Der Algorithmus von Cocke, Younger und Kasami
33/112
6.28 Beweisskizze In P 0 nimmt man alle Produktionen X → w 0 auf, für die gilt: I
w 0 6= ε und
I
es gibt eine Produktion X → w ∈ P, so dass w 0 aus w entsteht, indem man einige Vorkommen von Symbolen aus EPS(G ) entfernt.
Der Algorithmus von Cocke, Younger und Kasami
34/112
6.29 Lemma Zu jeder kontextfreien Grammatik G = (N, T , S, P) kann man eine ¯ = (N, T , S, ¯ P) ¯ berechnen, äquivalente kontextfreie Grammatik G für die gilt: ¯ keine Produktion ε als rechte I Wenn ε ∈ / L(G ) ist, dann hat G Seite. ¯ → ε die einzige Produktion von I Wenn ε ∈ L(G ) ist, dann ist S ¯ G mit ε als rechter Seite und S¯ kommt bei keiner Produktion auf der rechten Seite vor.
Der Algorithmus von Cocke, Younger und Kasami
35/112
6.30 Beweisskizze I
I I
Konstruiere wie in Lemma 6.27 eine Grammatik G 0 mit L(G 0 ) = L(G ) r {ε}. ¯ = G 0 setzen und ist fertig. Wenn ε ∈ / L(G ) ist, kann man G Ist ε ∈ L(G ), denn erweitert man G 0 um ein neues ¯ das Startsymbol von G ¯ wird und setzt Nichtterminalsymbol S, 0 0 ¯ = P ∪ {S¯ → ε, S¯ → S }. P
Der Algorithmus von Cocke, Younger und Kasami
36/112
6.23 Satz Zu jeder kontextfreien Grammatik G gibt es eine kontextfreie Grammatik G 0 in Chomsky-Normalform, die zu G äquivalent ist (also L(G ) = L(G 0 )).
Der Algorithmus von Cocke, Younger und Kasami
37/112
6.31 Beweis (von Satz 6.23) Es sei G0 = (N0 , T , S, P0 ) eine beliebige kontextfreie Grammatik. Konstruiere äquivalente kontextfreie Grammatik G4 in Chomsky-Normalform in vier Schritten: 1. Konstruiere aus G eine äquivalente Grammatik G1 , bei der Terminalsymbole a ∈ T nur in Produktionen der Form X → a vorkommen. 2. Konstruiere aus G1 eine äquivalente Grammatik G2 wie in Lemma 6.29 beschrieben. 3. Konstruiere aus G2 eine äquivalente Grammatik G3 , die keine Produktionen der Form X → Y enthält. 4. Konstruiere aus G3 eine äquivalente Grammatik G4 , die keine Produktionen der Form X → Y1 Y2 · · · Yk mit k ≥ 3 enthält.
Der Algorithmus von Cocke, Younger und Kasami
38/112
6.31 Beweis (2) 1. Konstruiere aus G eine äquivalente Grammatik G1 , bei der Terminalsymbole a ∈ T nur in Produktionen der Form X → a vorkommen:
Der Algorithmus von Cocke, Younger und Kasami
39/112
6.31 Beweis (2) 1. Konstruiere aus G eine äquivalente Grammatik G1 , bei der Terminalsymbole a ∈ T nur in Produktionen der Form X → a vorkommen: I
I
Führe für jedes Terminalsymbol a ∈ T ein neues Nichtterminalsymbol Za ein: N1 = N0 ∪ {Za | a ∈ T }. Produktionenmenge P1 enthält I I
alle Produktionen der Form Za → a und alle Produktionen, die man erhält, indem man in jeder Produktion aus P0 jedes Vorkommen eines Terminalsymboles a durch Za ersetzt.
Der Algorithmus von Cocke, Younger und Kasami
39/112
6.31 Beweis (3) 2. Konstruiere aus G1 eine äquivalente Grammatik G2 wie in Lemma 6.29 beschrieben:
Der Algorithmus von Cocke, Younger und Kasami
40/112
6.31 Beweis (3) 2. Konstruiere aus G1 eine äquivalente Grammatik G2 wie in Lemma 6.29 beschrieben: Nun sind alle Produktionen I I
von der Form X → a oder von der Form X → Y1 · · · Yk mit k ≥ 1 (evtl. Ausnahme S → ε)
Der Algorithmus von Cocke, Younger und Kasami
40/112
6.31 Beweis (4) 3. Konstruiere aus G2 eine äquivalente Grammatik G3 , die keine Produktionen der Form X → Y enthält:
Der Algorithmus von Cocke, Younger und Kasami
41/112
6.31 Beweis (4) 3. Konstruiere aus G2 eine äquivalente Grammatik G3 , die keine Produktionen der Form X → Y enthält: I
I
I
I
Für jedes X ∈ N2 berechnet man die Menge M(X ) = {X 0 | X ⇒∗ X 0 } der aus X ableitbaren Nichtterminalsymbole. i ←0 M0 (X ) ← {X } do i ←i +1 Mi (X ) ← Mi−1 (X ) ∪ {X 0 | ∃Y ∈ Mi−1 (X ) : Y → X 0 ∈ P} until Mi (X ) = Mi−1 (X ) return Mi (X ) Aus P2 streicht man zunächst alle Produktionen der Form X → X 0. Für verbliebene Produktion X 0 → Y1 · · · Yk nimmt man alle X → Y10 · · · Yk0 hinzu, sofern X 0 ∈ M(X ) und für alle i, 1 ≤ i ≤ k, auch Yi0 ∈ M(Yi ) ist. Das ergibt P3 .
Der Algorithmus von Cocke, Younger und Kasami
41/112
6.31 Beweis (5) 4. Konstruiere aus G3 eine äquivalente Grammatik G4 , die keine Produktionen der Form X → Y1 Y2 · · · Yk mit k ≥ 3 enthält.
Der Algorithmus von Cocke, Younger und Kasami
42/112
6.31 Beweis (5) 4. Konstruiere aus G3 eine äquivalente Grammatik G4 , die keine Produktionen der Form X → Y1 Y2 · · · Yk mit k ≥ 3 enthält. P4 erhält man aus P3 , indem man I
I
I
jede Produktion der Form X → Y1 · · · Yk mit k ≥ 3 entfernt und ersetzt durch die k − 1 Produktionen X → Y1 V1 , V1 → Y2 V2 , . . . , Vk−1 → Yk−1 Yk . Dabei seien die Vi jeweils neue Nichtterminalsymbole (die natürlich alle zu N4 hinzugenommen werden).
Der Algorithmus von Cocke, Younger und Kasami
42/112
6.32 Beispiel Grammatik mit Startsymbol E und den Produktionen: E
→ E +F | F
F
→ (E ) | a
1. Schritt: Behandlung der Terminalsymbole ergibt: E → E Z+ F | F
Z+ → +
Za → a
F → Z( E Z) | Za
Z( → (
Z) → )
Für das Terminalsymbol a ist das Vorgehen natürlich überflüssig. 2. Schritt: keine ε-Produktionen vorhanden, also ändert sich nichts. Der Algorithmus von Cocke, Younger und Kasami
43/112
6.32 Beispiel (2) 3. Schritt: I
I
I
Berechne zunächst X M0 (X ) E {E } F {F }
die Mengen Mi (X ): M1 (X ) M2 (X ) {E , F } {E , F , Za } {F , Za } {F , Za }
M3 (X ) {E , F , Za } {F , Za }
Die Produktionen E → F und F → Za werden entfernt und dafür neue aufgenommen. Aus E → E Z+ F entstehen: E
→ E Z+ F | F Z+ F | Za Z+ F | E Z+ Za | F Z+ Za | Za Z+ Za
I
Aus F → Z( E Z) ergeben sich F
→ Z( E Z) | Z( F Z) | Z( Za Z)
E
→ Z( E Z) | Z( F Z) | Z( Za Z)
Der Algorithmus von Cocke, Younger und Kasami
44/112
6.32 Beispiel (3) 4. Schritt: Jede Produktion mit drei Nichtterminalzeichen auf der rechten Seite wird ersetzt durch zwei Produktionen mit nur zwei Nichtterminalzeichen auf der rechten Seite. I
I
I
Zum Beispiel: E → E Z+ F ersetzt durch E → E V1 und V1 → Z+ F . Analog in allen anderen Fällen vor, wobei jedes Mal neue zusätzliche Nichtterminalsymbole V2 , V3 , . . . eingeführt werden. Jedenfalls verlangt das der Algorithmus so. Scharfes Hinsehen ergibt hier, dass man sparsamer sein kann: E → E V1 | F V1 | Za V1
V1 → Z+ F
E → E V2 | F V2 | Za V2
V2 → Z+ Za
E → Z( V3 | Z( V4 | Z( V5
V3 → E Z )
F → Z( V3 | Z( V4 | Z( V5
V4 → F Z ) V5 → Za Z)
Der Algorithmus von Cocke, Younger und Kasami
45/112
6.33 I
Der Algorithmus von Cocke, Younger und Kasami (kurz CYK) kann für jede Grammatik G = (N, T , S, P) in Chomsky-Normalform und jedes Wort w ∈ T ∗ auf deterministische Weise feststellen, ob w ∈ L(G ) ist oder nicht.
I
Eingabe w = x1 · · · xn ∈ T n ist mit n + 1 „Trennstellen“ versehen, die neben den einzelnen Symbolen liegen. |a|b|b|a|b| 0
1
2
3
4
5
I
Es sei w (i, j] das Teilwort zwischen den Trennstellen | und |,
I
also w (i, j] = xi+1 · · · xj (für 0 ≤ i < j ≤ n). Beispiele:
i
I I
j
w (0, n] = w w (i, i] = ε
Der Algorithmus von Cocke, Younger und Kasami
46/112
6.34 Algorithmus (Cocke, Younger, Kasami) I
CYK berechnet eine Pyramiden-Datenstruktur. D[0, 5] D[0, 4] D[0, 3] D[0, 2] D[0, 1] | 0
x1
D[1, 4]
D[1, 3]
D[1, 2] | 1
D[1, 5]
x2
D[2, 5]
D[2, 4]
D[2, 3] | 2
x3
D[3, 5]
D[3, 4] | 3
x4
D[4, 5] | 4
x5
| 5
I
Die einzelnen Komponenten D[i, j] sind (möglicherweise leere) Teilmengen von Nichtterminalsymbolen.
I
Ziel: D[i, j] = {X | X ⇒∗ w (i, j] }
Der Algorithmus von Cocke, Younger und Kasami
47/112
6.34 Algorithmus CYK (2) for i ← 0 to n − 1 do D[i, i + 1] = {X | X → xi+1 ∈ P} od for k ← 2 to n do for i ← 0 to n − k do D[i, i + k] ← ∅ for m ← i + 1 to i + k − 1 do if X → YZ ∈ P ∧ Y ∈ D[i, m] ∧ Z ∈ D[m, i + k] then D[i, i + k] ← D[i, i + k] ∪ {X } fi od od od
Der Algorithmus von Cocke, Younger und Kasami
48/112
6.34 Algorithmus CYK (3) I
Drei ineinander geschachelte Schleifen, I I I
für die ersten n/4 Durchläufe der äußersten und die letzten n/4 Durchläufe der mittleren Schleife wird die innerste jeweils mindestens n/4 mal durchlaufen.
I
Der Test für die if-Anweisung benötigt konstante Zeit.
I
Also ist die Laufzeit des Algorithmus in Θ(n3 ).
I
Es ist auch nicht schwer, einzusehen, dass am Ende in der Tat D[i, j] = {X | X ⇒∗ xi+1 · · · xj } ist.
I
Also ist x1 · · · xn genau dann aus L(G ), wenn S ∈ D[0, n] ist.
Der Algorithmus von Cocke, Younger und Kasami
49/112
6.35 Beispiel für Grammatik aus Beispiel 6.32: {E, F } {V3 } {E} {V2 } {Z( } | 0
(
{Za } | 1
a
{Z+ } | 2
+
{V5 } {Za }
| 3
a
{Z) } | 4
)
| 5
leere Kästchen: D[i, j] = ∅.
Der Algorithmus von Cocke, Younger und Kasami
50/112
Zur Vorbereitung auf den Algorithmus von Earley: einfache Umformung von CYK Der Algorithmus von Earley ist nicht relevant für die Klausur. Deswegen springen wir jetzt zum Abschnitt über LR Parsing
Der Algorithmus von Cocke, Younger und Kasami
51/112
6.36 Algorithmus Andere Darstellung der Pyramide: D[0, 5]
D[0, 1] | 0
x1
| 1
D[0, 4]
D[1, 5]
D[0, 3]
D[1, 4]
D[2, 5]
D[0, 2]
D[1, 3]
D[2, 4]
D[3, 5]
D[1, 2]
D[2, 3]
D[3, 4]
D[4, 5]
x2
| 2
x3
| 3
x4
| 4
x5
| 5
neue Berechnungsreihenfolge: I
spaltenweise von links nach rechts und
I
innerhalb jeder Spalte von unten nach oben.
Der Algorithmus von Cocke, Younger und Kasami
52/112
6.36 Algorithmus (2) for j ← 1 to n do D[j − 1, j] ← {X | X → xj ∈ P} for i ← j − 1 downto 0 do D[i, j] ← ∅ for m ← i + 1 to j do if X → YZ ∈ P ∧ Y ∈ D[i, m] ∧ Z ∈ D[m, j] then D[i, j] ← D[i, j] ∪ {X } fi od od od
Der Algorithmus von Cocke, Younger und Kasami
53/112
6.37 Weitere Transformation von CYK
S0
S1
S2
S3
S4
S5 D[4, 5]
| 0
x1
D[3, 4]
D[3, 5]
D[2, 3]
D[2, 4]
D[2, 5]
D[1, 2]
D[1, 3]
D[1, 4]
D[1, 5]
D[0, 1]
D[0, 2]
D[0, 3]
D[0, 4]
D[0, 5]
|
|
|
|
1
x2
2
Der Algorithmus von Cocke, Younger und Kasami
x3
3
x4
4
x5
| 5
54/112
6.38 Beispiel Für obige Grammatik ergibt sich mit zusätzlicher Angabe der Produktionen und relevanten Trennstellen:
S0
S1
S2
S3
S4
S5 E → | Z( V3 | 0
5
V3 → | EZ) | 1
5
E → | Za V2 | 1
Z( → | ( | 0
| 0
(
| 1
Za → | a |
1
1
a
| 2
Der Algorithmus von Cocke, Younger und Kasami
Z+ → | + |
2
2
+
| 3
4
V2 → | Z+ Za |
V5 → | Za Z) |
2
3
4
Z) → | ) |
Za → | a |
3
3
a
| 4
5
4
4
)
5
| 5
55/112
6.38 Beispiel (2) I
Angabe der rechten Trennstelle redundant
I
stattdessen dicker Punkt: •
S0
S1
S2
S3
S4
S5 E → | Z( V3 • 0
V3 → | EZ) • 1
E → | Za V2 • 1
V2 → | Z+ Za •
V5 → | Za Z) •
2
Z( → | ( •
Za → | a •
0
| 0
(
| 1
Z+ → | + •
1
a
| 2
Der Algorithmus von Cocke, Younger und Kasami
Za → | a •
2
+
| 3
3
Z) → | ) •
3
a
| 4
4
)
| 5
56/112
Einleitung Lexikalische Analyse Lexer-Generatoren Syntaktische Analyse Der Algorithmus von Cocke, Younger und Kasami Der Algorithmus von Earley LR Parsing Nach der Syntaxanalyse
Der Algorithmus von Earley
57/112
Achtung Dieser Abschnitt ist nicht relevant für die Klausur.
Der Algorithmus von Earley
58/112
6.39 In der vorangegangenen Abbildung gibt es I I
für eine Eingabe der Länge n Mengen S0 , S1 ,. . . , Sn , die sogenannte Items enthalten: I I
Produktionen mit einem Markierungspunkt •, bei denen an der gleiche Stelle oder links davon noch eine Trennstelle angegeben ist.
Der Algorithmus von Earley
59/112
6.40 Bei CYK gilt für die Items: I
Hat die Trennstelle Nummer i und ist das Item in Sj , so ist sicher, dass man aus dem, was auf der rechten Seite der Produktion zwischen Trennstelle und • steht, das Teilwort w (i, j] der Eingabe ableiten kann.
I
Eine Produktion X → | YZ • wird in Sj aufgenommen, wenn i
es ein m gibt, so dass ein Item Y → | v • in Sm ist und ein Item Z → | v 0 • in Sj .
i
m
Beim Algorithmus von Earley ändern sich I
die Form der Items und
I
die Regeln zur Berechung der Sj .
Der Algorithmus von Earley
60/112
6.41 Definition I
Ein Item hat die Form X → | v1 • v2 . i
I
Dabei ist X → v1 v2 eine ursprünglichen Produktion.
I
Präfix v1 und Suffix v2 sind ansonsten nicht eingeschränkt.
I
Z. B. erlaubt: Items der Form X → | • w i
Ein Item X → | v1 • v2 wird immer nur zu Mengen Sj mit i ≤ j i
gehören.
Der Algorithmus von Earley
61/112
6.42 Bedeutung der Items Für ein Item X → | v1 • v2 , das in Sj ist, gilt: i I
• markiert die Stelle j, „bis zu der man schon gekommen ist“,
I
und aus dem, was zwischen Trennstelle | und • steht, kann i
man das Teilwort w (i, j] ableiten. I
Für das Suffix hinter dem •, wird noch offen sein, ob aus ihm ein weiteres Stück der Eingabe ableitbar ist.
Der Algorithmus von Earley
62/112
6.43 Algorithmus von Earley Wie kommt ein Item X → | v1 • v2 in eine Menge Sj ? i
1. Lexer-Regel 2. Completer-Regel 3. Predictor-Regel
Der Algorithmus von Earley
63/112
6.43 Algorithmus von Earley (2) Wann kann man • an einem Terminalsymbol „vorbeischieben“? I Prüfe, ob das nächste Eingabesymbol gerade a ist. Falls I
ja, dann füge X → | v1 a • v2 zu Sj+1 hinzu.
I
nein, dann lässt man das.
i
1. Lexer-Regel: Wenn X → | v1 • av2 in Sj und a = w (j, j + 1], dann kommt i
X → | v1 a • v2 zu Sj+1 hinzu. i
Der Algorithmus von Earley
64/112
6.43 Algorithmus von Earley (3) Wann • an Y in X → | v1 • Yv2 aus Sm „vorbeischieben“? i I
Sinnvoll, wenn man aus Y ein Teilwort der Eingabe ableiten kann, das an Trennstelle m beginnt.
I
Das soll man aber gerade daran ablesen können, dass ein Item Y → | v • in einem Sj ist für ein j > m. m
2. Completer-Regel: Wenn X → | v1 • Yv2 in Sm ist und Y → | v • in Sj , dann m
i
kommt X → | v1 Y • v2 zu Sj hinzu. i
Der Algorithmus von Earley
65/112
6.43 Algorithmus von Earley (4) Woher kommen Items der Form Y → | • v2 mit dem • am Anfang? i I
Plausibel: Item Y → | • v2 dann zu einem Sj hinzuzunehmen, i
wenn man „das Y brauchen kann“. 3. Predictor-Regel: Wenn X → | v1 • Yv2 in Sj ist, dann kommt Y → | • v zu Sj i
j
hinzu für jede ProduktionY → v .
Der Algorithmus von Earley
66/112
6.43 Algorithmus von Earley (5) Der Algorithmus von Earley (genauer gesagt die Variante, die ohne sogenannten Look-Ahead in der Eingabe arbeitet) für eine Grammatik G = (N, T , S, P) ergibt sich nun einfach wie folgt: I
Man beginnt mit der Menge S0 , die genau alle Items der Form S → | • w für jede Produktion der Form S → w ∈ P (S ist 0
das Startsymbol der Grammatik). I
Auf eine Menge Sj werden solange die Lexer-, Completer- und Predictor-Regeln angewendet, bis sich nichts mehr ändert.
I
Dann fährt man mit Sj+1 fort.
Der Algorithmus von Earley
67/112
6.43 Algorithmus von Earley (6) Ende des Algorithmus: I
Ist einmal ein Sj = ∅, dann ist die Eingabe nicht ableitbar.
I
Andernfalls muss man am Ende überprüfen, ob Sn ein Item der Form S → | w • enthält.
I
Wenn das der Fall ist (und nur dann), ist die Eingabe in der Grammatik ableitbar.
0
Der Nachweis, dass dieser Algorithmus wirklich das Richtige tut, wurde von Jay Earley geführt.
Der Algorithmus von Earley
68/112
6.44 Beispiel Betrachte sehr einfache Grammatik G = (N, T , S, P) mit I N = {S, X , A, B, C }, T = {a, b, c}, Startsymbol S I P = {S → AX , X → BC , A → a, B → b, C → c}. I Eingabe abc: S0
S1
S → | • AX
S → | A•X
S → | AX •
0
0
0
A → | •a
S2
X → | • BC
X → | B•C
X → | BC •
1
1
1
B → | •b
0
C → | •c
1
2
A → | a•
B → | b•
0
| 0
a
S3
| 1
Der Algorithmus von Earley
C → | c•
1
b
| 2
2
c
| 3
69/112
6.44 Beispiel (2) I
Lexer-Regel: durchgezogene Linien
I
Predictor-Regel: gestrichelte Linien
I
Completer-Regel: gepunktete Linien. S0
S1
S2
S → | • AX
S → | A•X
S → | AX •
0
0
0
X → | • BC
X → | B•C
X → | BC •
1
1
1
B → | •b
A → | •a 0
C → | •c
1
2
A → | a•
B → | b•
0
| 0
a
S3
| 1
Der Algorithmus von Earley
C → | c•
1
b
| 2
2
c
| 3
70/112
Einleitung Lexikalische Analyse Lexer-Generatoren Syntaktische Analyse Der Algorithmus von Cocke, Younger und Kasami Der Algorithmus von Earley LR Parsing Nach der Syntaxanalyse
LR Parsing
71/112
Achtung Dieser Abschnitt und die folgenden sind wieder relevant für die Klausur.
LR Parsing
72/112
6.45 Beispielgrammatik
E
→ E +T | T
T
→ T *F | F
F
→ (E ) | a
LR Parsing
73/112
6.46 Vereinbarung Stets Eingabebegrenzungen vorhanden: E0 → a E ` E
→ E +T | T
T
→ T *F | F
F
→ (E ) | a
LR Parsing
74/112
6.47 Definition I
Eine Grammatik hat die Eigenschaft LR(k) für ein k ∈ N0 , wenn für zwei beliebige Rechtsableitungen r
r
r
r
r
r
S ⇒∗ ξ1 A1 ωη1 ⇒ ξ1 γ1 ωη1 ⇒∗ αωη1 ∈ T ∗ S ⇒∗ ξ2 A2 τ2 ⇒ ξ1 γ1 ωη2 ⇒∗ αωη2 ∈ T ∗ mit |ω| = k oder η1 = η2 = ε immer gilt: ξ2 A2 τ2 = ξ1 A1 ωη2 . I
M.a.W.: Wenn τ2 ∈ T ∗ ist, wenn also A2 das zuletzt durch eine Reduktion entstandene Zeichen ist, dann ist A1 = A2 , ξ1 = ξ2 und τ2 = ωη2 .
I
D. h. durch den Kellerinhalt (ξ1 γ1 ) und die nächsten k Eingabezeichen (ω) ist der nächste Reduktionsschritt bei der Bottom-Up-Syntaxanalyse eindeutig bestimmt.
LR Parsing
75/112
6.49 Prinzip der Syntaxanalyse für LR(k)-Grammatiken I
Erweiterung der Kellerautomaten um „Zustandskeller“
I
„Zustand“ z(κ): Äquivalenzklasse von Kellerinhalten
I
Aktionen: shift- und reduce-Schritte außerdem accept und error shift reduce A → γ act(z(κ), ω) = accept error
I
Funktion goto zur einfachen Berechnung neuer Zustände: goto(z(κ), X ) = z(κX )
I
zunächst Annahme: Funktionen act und goto liegen schon vor
LR Parsing
76/112
6.49 Prinzip der Syntaxanalyse für LR(k)-Grammatiken (2) Automatenmodell: Zustandskeller
z
Symbolkeller
Eingabe
z = z(κ)
κ
α
LR Parsing
ω
η
77/112
6.49 Prinzip der Syntaxanalyse für LR(k)-Grammatiken (3) Shift-Aktion: vorher Zustandskeller
z
Symbolkeller
Eingabe
z = z(κ)
κ
α
LR Parsing
ω
η
78/112
6.49 Prinzip der Syntaxanalyse für LR(k)-Grammatiken (3) Shift-Aktion: nachher Zustandskeller
z
Symbolkeller
Eingabe
κ
α
LR Parsing
z0
z 0 = goto(z, a)
a
a
ω0
η0
79/112
6.49 Prinzip der Syntaxanalyse für LR(k)-Grammatiken (4) Reduce-Aktion: vorher z 00
Zustandskeller
Symbolkeller
Eingabe
ξ
z
γ
α
LR Parsing
ω
η
80/112
6.49 Prinzip der Syntaxanalyse für LR(k)-Grammatiken (4) Reduce-Aktion: nachher z 00 z 0
Zustandskeller
Symbolkeller
Eingabe
ξ
α
LR Parsing
z 0 = goto(z 00 , A)
A
ω
η
81/112
6.49 Prinzip der Syntaxanalyse für LR(k)-Grammatiken (5) I
Beginn der Analyse: I I
I
in den Symbolkeller wird unten ein a gelegt und in den Zustandskeller entsprechend z(a)
Ende der Analyse: I I I
im Symbolkeller ist nur noch a S ` das kann zu S 0 reduziert werden Der Kellerautomat kann schon akzeptieren, wenn im Symbolkeller a S steht und als letztes Eingabesymbol ` ansteht.
LR Parsing
82/112
6.50 Beispiel
E0 → a E ` E
→ E +T | T
1 | 2
T
→ T *F | F
3 | 4
F
→ (E ) | a
5 | 6
LR Parsing
83/112
6.50 Beispiel (2) I
Die folgenden Tabellen kann man algorithmisch finden
I
wie, verraten wir gleich
I
Es ist hier |ω| = 1.
z 0 1 2 3 4 5 6 7 8 9 10 11
κ a aE · · · (E · · · E+ · · · E +T · · · (T ···T* · · · T *F · · · (F ···( · · · (E ) ···a
a S
+
act(z, ω) * ( S
S S
)
`
a 11
A S
R1 R2
S S
R3 R4
R3 R4
R5 R6
R5 R6
S
11 R1 R2
R1 R2
R3 R4
R3 R4
R5 R6
R5 R6
S
S
S
LR Parsing
*
3 3
S
S
+
goto(z, X ) ( ) E 9 1 10 9
T 5
F 8
4
8
6 6 11
9
11
9
7
2
5
8
84/112
6.50 Beispiel (3)
0 a
0 a 0 a 0 a 0 a 9 (
0 a 9 ( 9 ( 9 ( 9 ( 2 E
κ 0 a 9 ( 11 a 8 F 5 T 2 E 3 +
ω
η
···
(
a
+
a
)
*
a
a
+
a
)
*
a
`
+
a
)
*
a
`
+
a
)
*
a
`
+
a
)
*
a
`
+
a
)
*
a
`
a
)
*
a
`
LR Parsing
`
85/112
6.50 Beispiel (4)
0 a 0 a 0 a
0 a 9 ( 9 ( 9 (
0 a
9 ( 2 E 2 E 2 E 0 a 9 (
2 E 3 + 3 + 3 + 9 ( 2 E 0 a
3 + 11 a 8 F 4 T 2 E 10 ) 8 F
a
)
*
a
)
*
a
`
)
*
a
`
)
*
a
`
)
*
a
`
*
a
`
*
a
`
LR Parsing
`
86/112
6.50 Beispiel (5)
0 a 0 a
0 a 5 T 5 T
0 a 0 a 5 T 6 * 6 * 0 a 0 a
8 F 5 T 6 * 11 a 7 F 5 T 1 E
*
a
`
*
a
`
a
`
` ` ` `
LR Parsing
87/112
6.51 Definition I
Zu jeder Produktion A → X1 X2 · · · Xk (mit Xi ∈ N ∪ T ) gehören die k + 1 markierten Produktionen (Items) I I I I I
I
A → • X1 X2 · · · Xk A → X1 • X2 · · · Xk .. . A → X1 X2 · · · • Xk A → X1 X2 · · · Xk •
Zu A → ε gehört A → •
LR Parsing
88/112
6.52 Konstruktion der Zustände: I
Jeder Zustand ist eine Menge markierter Produktionen.
I
Beginne mit „Zustandskern“ M0 = {S 0 →a • S `}. Vervollständigungsregel:
I
I
I
I
Mi wird erweitert zu zi = kompl (Mi ) ⊇ Mi gemäß folgender „Predictor-Regel“: Wenn A → µ • Bν ∈ kompl (Mi ) und B → γ ∈ P, dann auch B → • γ ∈ kompl (Mi )
Fortschreibungsregel: erzeuge Kerne für neue M-Mengen gemäß: I
wenn A → µ • X ν ∈ z(κ), dann A → µX • ν ∈ z(κX )
anschließend Vervollständigung
LR Parsing
89/112
6.52 (2) Wenn man das so macht, dann gilt: z(κ) enthält genau diejenigen A → µ • ν, für die gilt: I
A → µν ∈ P,
I
∃ξ ∈ V ∗ : κ = ξµ und
I
∃η ∈ T ∗ : S 0 ⇒∗ ξAη
r
LR Parsing
90/112
6.53 großes Beispiel an der Tafel
LR Parsing
91/112
6.54 I
Also: z(κX ) = kompl ({A → µX • ν | A → µ • X ν ∈ z(κ)}).
I
Damit hat man auch schon goto(z(κ), X ) = z(κX ).
LR Parsing
92/112
6.55 Beispiel z0 z1 z2 z3 z4 z5 z6 z7 z8 z9 z10 z11 z12 z13
E z1 z6 z6 z6 z6 z10 z6 z6
T z2 z6 z6 z6 z6 z2 z6 z11
F z3 z6 z6 z6 z6 z3 z6 z3
a z4 z6 z6 z6 z6 z4 z6 z4
( z5 z6 z6 z6 z6 z5 z6 z5
) z6 z6 z6 z6 z6 z6 z6 z6
+ z6 z7 z6 z6 z6 z6 z6 z6
* z6 z6 z9 z6 z6 z6 z6 z6
` z6 z8 z6 z6 z6 z6 z6 z6
z6 z6 z6 z6 z6
z6 z6 z6 z6 z6
z12 z6 z6 z6 z6
z4 z6 z6 z6 z6
z5 z6 z6 z6 z6
z6 z13 z6 z6 z6
z6 z7 z6 z6 z6
z6 z6 z9 z6 z6
z6 z6 z6 z6 z6
LR Parsing
93/112
6.56 Wie findet man die Funktion act? I
Idee: I
I
I
Look-ahead-Mengen la(z, A → µ • ν) ⊂ T und la(z, shift) ⊂ T , so dass für jedes z alle diese Mengen disjunkt sind.
Dann definieren die folgenden Festlegungen act konsistent und sinnvoll: reduce A → γ falls a ∈ la(z, A → µ •) falls a ∈ la(z, shift) shift f (z, a) = accept falls z = z(a S ` •) (oder falls a S • `∈ z und a =` ) error sonst
LR Parsing
94/112
6.57 Mitteilung I
Für verschieden „nette“ Grammatiken kann man auf mehr oder weniger einfache Weise geeignete Look-ahead-Mengen konstruieren.
I
Zum Beispiel ist eine Grammatik LALR(1), wenn die wie folgt definierten la-Mengen paarweise disjunkt sind: I I I
la(z, S 0 →a • S `) = ∅ a ∈ la(z, A → µ • Bν) ∧ b ∈ anf (νa) =⇒ b ∈ la(z, B → • γ) a ∈ la(z, A → µ • X ν) =⇒ a ∈ la(goto(z, X ), A → µX • ν)
LR Parsing
95/112
Einleitung Lexikalische Analyse Lexer-Generatoren Syntaktische Analyse Der Algorithmus von Cocke, Younger und Kasami Der Algorithmus von Earley LR Parsing Nach der Syntaxanalyse
Nach der Syntaxanalyse
96/112
6.59 Grammatiken mit semantischen Aktionen I
„Produktionen“ der Form A → {code 0 } X1 {code 1 } X2 · · · Xm {code m }
I
Codefragment am Ende wird nach der Reduktion auf dem Keller gemäß der kontextfreien Produktion ausgeführt.
I
Für andere Codestücke stelle man sich vor: A → M0 X1 M1 X2 · · · Xm {code m } M0 → ε {code 0 } M1 → ε {code 1 } .. . Mm−1 → ε {code m−1 }
Nach der Syntaxanalyse
97/112
6.60 Beispiel E E T T F F
→ → → → → →
E +T T T *F F (E ) a
{ { { { { {
printf("Reduktion printf("Reduktion printf("Reduktion printf("Reduktion printf("Reduktion printf("Reduktion
Nach der Syntaxanalyse
mit mit mit mit mit mit
E E T T F F
-> -> -> -> -> ->
E+T T T*F F (E) a
\n"); \n"); \n"); \n"); \n"); \n");
} } } } } }
98/112
6.61 Anwendung semantischer Aktionen: Berechnung von Werten für Attribute von Kellersymbolen
Nach der Syntaxanalyse
99/112
6.62 Beispiel (Auswertung arithmetischer Ausdrücke) I
Attribut val für Terminal- und Nichtterminalsymbole
I
Indizes zur Unterscheidung mehrerer Vorkommen des gleichen Symbols in einer Produktion E0 E0 T0 T0 F0 F0
→ → → → → →
E1 +T1 T1 T1 *F1 F1 (E1 ) num
{ { { { { {
E0 .val = E1 .val + T1 .val } E0 .val = T1 .val } T0 .val = T1 .val · F1 .val } T0 .val = F1 .val } F0 .val = E1 .val } F0 .val = num.val }
Nach der Syntaxanalyse
100/112
6.62 Beispiel (2) Sinnvoll: I Auswertung von unten nach oben E.val =?
E.val =?
T .val =?
+
T .val =?
F.val =?
F.val =?
num.val = 3
*
F.val =?
num.val = 4
num.val = 2 Nach der Syntaxanalyse
101/112
6.62 Beispiel (2) Sinnvoll: I Auswertung von unten nach oben E.val =?
E.val =?
T .val =?
+
T .val =?
F.val = 3
F.val = 2
num.val = 3
*
F.val = 4
num.val = 4
num.val = 2 Nach der Syntaxanalyse
101/112
6.62 Beispiel (2) Sinnvoll: I Auswertung von unten nach oben E.val =?
E.val =?
T .val = 12
+
T .val = 2
F.val = 3
F.val = 2
num.val = 3
*
F.val = 4
num.val = 4
num.val = 2 Nach der Syntaxanalyse
101/112
6.62 Beispiel (2) Sinnvoll: I Auswertung von unten nach oben E.val =?
E.val = 2
T .val = 12
+
T .val = 2
F.val = 3
F.val = 2
num.val = 3
*
F.val = 4
num.val = 4
num.val = 2 Nach der Syntaxanalyse
101/112
6.62 Beispiel (2) Sinnvoll: I Auswertung von unten nach oben E.val = 14
E.val = 2
T .val = 12
+
T .val = 2
F.val = 3
F.val = 2
num.val = 3
*
F.val = 4
num.val = 4
num.val = 2 Nach der Syntaxanalyse
101/112
6.63 Attributierte Grammatik I
I
Kontextfreie Grammatik G (N, T , S, P) mit endlicher Menge A von Attributen a ∈ A (mit je einem Wertebereich Va ). Zu jedem Symbol X ∈ N ∪ T disjunkte Attributmengen I
I
DX ⊂ A sogenannter synthetisierter Attribute (engl. synthesized oder derived) IX ⊂ A sogenannter vererbter (engl. inherited) Attribute
Nach der Syntaxanalyse
102/112
6.63 Attributierte Grammatik (2) I
Zu jedem p : X0 → X1 · · · Xm für jedes a ∈ DX0 eine Funktion, die in Abhängigkeit von allen Attributen aller auf der rechten Seite vorkommenden Symbole einen Wert für das Attribut a festlegt.
I
Zu p : X0 → X1 · · · Xm für jedes i = 1, . . . , n und a ∈ IXi eine Funktion, die in Abhängigkeit von allen Attributen aller vorkommenden Symbole einen Wert für das Attribut a festlegt.
Nach der Syntaxanalyse
103/112
6.64 S-attributierte Grammatik I
nur synthetisierte Attribute
I
Solche Grammtiken sind sehr nützlich und für Bottom-up-Syntaxanalyse gut geeignet.
I
Kellerautomat: Bei Reduktion gemäß Produktion A → w berechnet er aus den Attributwerten der Symbole in w die Attributwerte für A.
Nach der Syntaxanalyse
104/112
6.65 Beispiel Kellersymbole Attributwerte a
noch nicht gelesene Eingabe (
2
+
3
)
*
4 `
a
(
2
+
3
)
*
4
a
(
+
3
)
*
4
`
a
(
+
3
)
*
4
`
a
(
+
3
)
*
4
`
a
(
2 2 F 2 T 2 E 2
+
3
)
*
4
`
Nach der Syntaxanalyse
`
105/112
6.65 Beispiel (2) a
(
a
(
a
(
a
(
E 2 E 2 E 2 a
a
(
E 2 + + + ( E 5 a
+
3
)
*
4
3 3 F 3 T 3 E 5 )
)
*
4
`
)
*
4
`
)
*
4
`
)
*
4
`
*
4
`
F 5
*
4
`
Nach der Syntaxanalyse
`
106/112
6.65 Beispiel (3) a a a a
T 5 T 5
T 5 * * a a
Nach der Syntaxanalyse
T 5 *
*
4
4
`
4 4 F 4 T 20 E 20
`
`
` ` `
107/112
6.66 L-attributierte Grammatik I
nur synthetisierte Attribute und solche vererbte Attribute, für die gilt: In jeder Produktion A → X1 · · · Xm hängen die vererbten Attribute jedes Xj nur I I
I
von den vererbten Attributen von A und von den links von Xj stehenden Symbolen X1 , . . . , Xj−1 ab.
auch noch für Bottom-up-Syntaxanalyse gut geeignet
Nach der Syntaxanalyse
108/112
6.67 Beispiel I
Ableitungsbäume enthalten manchmal „überflüssige“ Knoten. Z. B. kompaktere Darstellung arithmetischer Ausdrücke:
I
So genannter abstrakter Syntaxbaum (AST); analog etwa bei Produktionen für Kontrollstrukturen
Nach der Syntaxanalyse
109/112
6.67 Beispiel (2) I
Die Kontruktion eines Syntaxbaumes aus Ableitungsbaum kann man mit Hilfe eines synthetisiserten Attributes ast (die englische Abkürzung für „abstract syntax tree“) durchführen.
I
Attributwert für ein Nichtterminalsymbol A ist dabei ein Zeiger auf die Wurzel des Syntax(teil)baumes, der A entspricht.
Nach der Syntaxanalyse
110/112
6.68 Beispiel I
I
Einfache (!) Codeerzeugung (nur die, aber immerhin) kann man auch mit attributierten Grammatiken machen. synthetisierte Attribute I I
I
code für den erzeugten Code temp für den Namen einer Hilfsvariable, z. B. der Form H4711
Beispiel-Produktion E0 → E1 +T1 I
I
neuer Name für Hilfsvariable: E0 .temp = H gefolgt von 1 + Maximum der Nummern von E1 .temp und T1 .temp alten Code übernehmen und zusätzlichen Code anhängen: E0 .code
= E1 .code; T1 .code; E0 .temp ← E1 .temp + T1 .temp
I
primitive Methode, sie demonstriert aber das Prinzip Nach der Syntaxanalyse
111/112
Parser-Generatoren I
I
lesen eine Eingabedatei, in der im wesentlichen eine kontextfreie Grammatik G beschrieben ist, und erzeugen als Ausgabedatei ein Programm, dass I I I
I
die Syntaxanalyse fur G macht, (implizit) den Ableitungsbaum erzeugt und evtl. Berechnung von Attributwerten durchführt
Beispiele: in der Shell
Nach der Syntaxanalyse
112/112