Die Präsentation wird geladen. Bitte warten

Die Präsentation wird geladen. Bitte warten

Vorlesung Compilertechnik Sommersemester 2008 Syntaktische Analyse M. Schölzel.

Ähnliche Präsentationen


Präsentation zum Thema: "Vorlesung Compilertechnik Sommersemester 2008 Syntaktische Analyse M. Schölzel."—  Präsentation transkript:

1 Vorlesung Compilertechnik Sommersemester 2008 Syntaktische Analyse M. Schölzel

2 2 Einbettung des Parsers in den Compiler Kontext- prüfung Parser Token Syntax- baum Parser Symbol- tabelle Zwischencode-/ Zielcodeerzeugung

3 3 Aufgabe des Parsers Verarbeitung der Tokenfolge, die vom Scanner geliefert wird und Überführung in eine strukturierte Darstellung, z.B. einen Syntaxbaum, der die syntaktische Struktur des Quellprogramms repräsentiert: Deklarationen Anweisungsfolgen Anweisungen Ausdrücke Die syntaktische Struktur ist im Allgemeinen durch eine kfG spezifiziert. Der Parser muss eine Ableitung aus dem Startsymbol der kfG für die vom Scanner gelieferte Morphemfolge finden oder syntaktische Fehler erkennen und diese lokalisieren.

4 4 Der PDA mit Ausgabe als theoretisches Modell Push-Down-Automat P = (Z,, z, f,, M) – ein endliches Eingabealphabet Z – ein endliches Kelleralphabet mit Z M – Metasymbole einer Grammatik (für die Ausgabe) z Z * – Die Startbelegung des Kellers f Z * – Kellerinhalt für akzeptierenden Zustand : Z * * ( (Z* (M )) (Z * )) – Überführungsrelation Unterschiede zu klassischen PDAs: P hat nur einen Zustand P darf eine endliche Anzahl Kellersymbole in einem Takt lesen P darf eine endliche Anzahl (mehr als eins) Symbole der Eingabe sehen P erzeugt eine Ausgabe (linearisierter abstrakter Syntaxbaum) Situation (,, ) – Kellerinhalt (Kellerspitze rechts) – Eingabe – linearisierter abstrakter Syntaxbaum Takt (Situationsübergang) (,, ) (,, (A,i)), falls Z * und * und (,(A,i)) (, ) (, a, ) (,, ), falls Z * und a * und (,a ) Akzeptierte Sprache eines PDA P: L(P) := { | (z,, ) * (,, ) und = f }

5 5 Einteilung Analyseverfahren Top-Down-VerfahrenBottom-Up-Verfahren Universelle Verfahren Automatenbasiert Berechnung des Ableitungsbaums Cocke-Younger-Kasami Algorithmus nicht- deterministisch Backtracking- frei nicht- deterministisch mit Backtracking deterministisch Backtracking- frei deterministisch mit Backtracking

6 6 Top-Down-Verfahren Gegeben sind eine kfG G und ein Wort w. Ausgehend vom Startsymbol S in G wird eine Linksableitung nach w gesucht. In jedem Ableitungsschritt wird das am weitesten links stehende Metasymbol durch eine seiner Alternativen ersetzt: Wahl der Alternative nichtdeterministisch oder Nach einem festen Schema; bei falscher Wahl endet die Ableitung in einer Sackgasse: S * * w * ' * w Beginn der Sackgasse, falls * w Erkennung der Sackgasse, falls * und ' und w

7 7 Grammatik in Top-Down PDA transformieren Es sei G = (, M, S, R) eine kfG Der PDA P = (V,, z,, M) mit L(P) = L(G) ist definiert als: z := S V := M (a,a) : a ([A,i],(A,i)) (A, ) : (A,[A,i]) R Der nichtdeterministische PDA P hat damit folgendes Verhalten: Startsituation (S,, ) ( A,, ) ( [A,i],, (A,i)) ( a, a, ) (,, ) (,, ) akzeptierende Endsituation

8 8 Zusammenhang Analysesituation des Top- Down-PDA und Ableitung in Grammatik Eine Analysesituation (,, ) eines PDA P zur Grammatik G = (, M, S, R) mit (S,, ) * (,, ) entspricht der Linkssatzform in der Linksableitung S * *. D.h. aus S wurde ein Präfix der Eingabe abgeleitet und es wird erwartet, dass aus die terminale Zeichenkette abgeleitet werden kann. ist die Folge der angewendeten Ableitungen bei S * ist für (S,, ) * (,, ) die Präfixlinearisierung des abstrakten Syntaxbaums zu.

9 9 Bottom-Up-Analyse Gegeben sind eine Grammatik G und ein Wort w. Ausgehend von w wird versucht eine Reduktion (Rückwärtsableitung) nach S zu finden. In jedem Rückwärtsableitungsschritt wird in der aktuellen Satzform ein Teilwort gesucht, das einer Alternative eines Metasymbols entspricht und durch das entsprechende Metasymbol ersetzt. (Reduktionsschritt): Wahl der Alternative und der Ersetzungsposition nichtdeterministisch oder Nach einem festen Schema; bei falscher Wahl endet die Rückwärtsableitung in einer Sackgasse: w * * S * ' S Beginn der Sackgasse, falls * S Erkennung der Sackgasse, falls z.B. kein Teilwort von ' eine Alternative eines Metasymbols ist

10 10 Grammatik in Bottom-Up PDA transformieren Es sei G = (, M, S, R) eine kfG Der PDA P = (V,, z,, M) mit L(P) = L(G) ist definiert als: z := V := M (A, (A,i)) ([A,i], ) : (A,[A,i]) R a (,a) : a Der nichtdeterministische PDA P hat damit folgendes Verhalten: Startsituation (,, ) ( [A,i],, ) ( A,, (A,i)) (, a, ) ( a,, ) (S,, ) akzeptierende Endsituation

11 11 Zusammenhang Analysesituation und Ableitung bei Bottom-Up Eine Analysesituation (,, ) eines PDA P zur Grammatik G = (, M, S, R) mit (,, ) * (,, ) entspricht der Rechtssatzform in der Rechtsableitung S * * (bzw. * * S). D.h. wurde bereits eingestapelt (gesehen) und zu reduziert und es wird erwartet, dass zu S reduziert werden kann. ist die Folge der angewendeten Ableitungen bei *. ist für (,, ) * (S,, ) die Postfixlinearisierung des abstrakten Syntaxbaums zu.

12 12 Top-Down-Analyse mit Backtracking durch Berechnung des Ableitungsbaums -Regeln eliminieren Regeln der Form A B eliminieren Dadurch: Ableitungsschritt verlängert das Wort oder überführt Meta- in Terminalsymbol(e) Abbruchkriterium: Wenn abgeleitetes Nicht- terminales Wort länger als das gegebene Wort w Untersuchung bis zu einer maximalen Anzahl von 2|w| - 1 Ableitungsschritten

13 13 Ableitungsbaum Ableitungsbaum zu einer Grammatik G = (, M, S, R) ist ein geordneter Baum B mit der Beschriftung : B V * für den gilt: B darf unendlich sein ( ) = S hat genau so viele Söhne, wie das in ( ) am weitesten links stehende Metasymbol Alternativen hat Für.i B gilt: * V * : (.i) = [A,i+1] und ( ) = A und (A,[A,i+1]) R In dem Ableitungsbaum werden Linksableitungen betrachtet. Um festzustellen, ob w L(G) genügt es in B die Beschriftungen von Adressen zu untersuchen, für die gilt: | | < 2|w|

14 14 Cocke-Younger-Kasami-Algorithmus Eingabe: kfG (, M, S, R) in Chomsyk-Normalform und Wort w = w 1 …w n (w k ). Konstruktion der Ableitung durch Berechnung der Mengen t i,j, wobei t i,j die Metasymbole enthält, aus denen die Zeichenkette w i …w i+j-1 abgeleitet werden kann. Berechnung durch: t i,1 := {A | (A,w i ) R} Berechnung von t i,j+1 := {A | k: 1 k < j+1 und (A,BC) R und B t i,k und C t i+k,j+1-k } ist möglich, weil k < j+1 und j+1-k < j+1. Falls S t 1,n, dann ist w aus S ableitbar. Rekonstruktion der Ableitung beginnend bei t 1,n.

15 15 Benötigte Operationen auf Wort(meng)en für Backtrackingfreie Analyse pre k : * * ist definiert als:. k. : ( * ) ( * ) ist definiert als: A k B := {pre k ( ) | A und B}

16 16 Backtrackingfreie Analyse Ziel: In jeder Situation Wahl des richtigen Takts und der richtigen Alternative im Ableitungs-/Reduktionstakt, so dass Sackgassen vermieden werden. Entscheidung basiert auf: einer endlichen Vorausschau in der Eingabe um eine feste Anzahl von k vielen Morphemen (Look-Ahead), evtl. dem Wissen über die bisher gesehene Eingabe. Eingabe wird um k Morpheme der Art verlängert, um auch am Ende des zu analysierenden Wortes immer eine Vorausschau von k Morphemen zu haben. Dafür Transformation der ursprünglichen Grammatik G in Grammatik G' mit der Regel S' S k zum neuen Startsymbol S' und dem alten Startsymbol S. Vereinbarung: Im Folgenden wird in den Situationen des PDA der linearisierte abstrakte Syntaxbaum weggelassen.

17 17 Backtrackingfreie Top-Down-Analyse Analysesituation ( A, ) bedeutet, dass erwartet wird, die Resteingabe aus A ableiten zu können: A *. Das ist offensichtlich nur dann möglich, wenn durch Wahl der richtigen Alternative i von A gilt: [A,i] *. Bei Verwendung einer Vorausschau von k Zeichen muss sich aus [A,i] eine Zeichenkette ableiten lassen, die in den ersten k Terminalzeichen mit übereinstimmt. Im folgenden Betrachtung verschiedener Klassen von Grammatiken, für die diese Entscheidung eindeutig getroffen werden kann.

18 18 Einfache LL(k)-Grammatiken Eine Grammatik ist eine einfache LL(k)- Grammatik, wenn für jedes Metasymbol A gilt: |[A]| = 1 oder 1 i |[A]|: pre k ([A,i]) k und 1 i j |[A]|: pre k ([A,i]) pre k ([A,j]) Offensichtlich ist dann in der Analysesituation ( A, ) die Auswahl einer Alternative eindeutig möglich durch: ( A, ) ( [A,i], ) : pre k ([A,i]) = pre k ( ).

19 19 Beispiel: Einfache LL(1)-Grammatik S'::= S S ::= if Id then S else S fi | while Id do S od | begin S end | Id := Id E E ::= + Id Q| * Id Q Q ::= Id := Id E | ;

20 20 Syntaxgebundene Implementierung Für jedes Metasymbol A der Grammatik wird eine Funktion int A() definiert mit Rückgabe 0 für Fehler in der Eingabe oder Rückgabe 1 bei erfolgreicher Ableitung eines Präfixes der Eingabe aus A Globale Variablen für Aktuelle Vorausschau Bisher erzeugten Syntaxbaum Jede Funktion int A() trifft auf Grund der aktuellen Vorausschau die Auswahl einer Alternativ von A. Abarbeitung der Symbole der Alternative von links nach rechts durch: Terminalsymbol: Prüfen, ob aktuelles Symbol in der Eingabe mit dem Terminalsymbol in der Alternative übereinstimmt: Ja: Eingabe konsumieren Nein: Fehler in der Eingabe Metasymbol: Rekursiver Aufruf der Funktion zum Metasymbol in der Alternative und Rückgabe des Fehlerwertes

21 21 Beispiel für syntaxgebundene Implementierung int E() { switch(nextMor()) { case PLUS: printf("(E_1)"); if(nextMor() == ID && Q()) return 1; return 0; case MAL: printf("(E_2)"); if(nextMor() == ID && Q()) return 1; return 0; } return 0; } S'::= S S ::= if id then S else S fi | while id do S od | begin S end | id := id E E ::= + id Q| * id Q Q ::= id := id E | ; int Q(){ switch(nextMor()) { case ID: printf("(Q_1)"); if(nextMor() == ASSIGN && nextMor() == ID && E()) return 1; return 0; case SEMIKOLON: printf("(Q_2)"); return 1; } return 0; } Quelltextausschnitt: Grammatik Vollständiger Quelltext (h, c, l) Ausführbares ProgrammhclAusführbares Programm

22 22 Starke LL(k)-Grammatiken Einfache LL(k)-Grammatiken sind für viele praktisch benötigte Programmstrukturen nicht ausreichend. Aufhebung der Forderung, dass die ersten k Symbole jeder Alternative Terminalsymbole sein müssen. Weiterhin muss aber anhand der Vorausschau von k Symbolen eine Alternative für das am weitesten links stehende Metasymbol in einer Linkssatzform eindeutig bestimmbar sein. Es sei G = (, M, R, S) eine Grammatik und k. Dann ist G eine starke LL(k)- Grammatik, wenn gilt: Existieren zwei Linksableitungen mit pre k ( ) = pre k ( '), dann folgt, dass = ', wobei,, ', ' *, S,A M und,, ', ' V * Folgerungen: Jede starke LL(k)-Grammatik ist eindeutig Jede einfache LL(k)-Grammatik ist eine starke LL(k)-Grammatik S * * A * 'A ' ' ' ' * ' '

23 23 Prüfen der starken LL(k)-Eigenschaft Es sei G = (, M, R, S) eine Grammatik und k. Dann ist G eine starke LL(k)- Grammatik, wenn gilt: Existieren zwei Linksableitungen mit pre k ( ) = pre k ( '), dann folgt, dass = ', wobei,, ', ' *, S,A M und,, ', ' V * Beispielgrammatik, die für kein k die starke LL(k)-Eigenschaft besitzt Beispielgrammatik Die Entscheidung zwischen zwei verschiedenen Alternative und ' von A kann nur dann eindeutig getroffen werden, wenn alle aus ableitbaren terminalen Zeichenketten sich in den ersten k Symbolen von allen aus ' ' ableitbaren terminalen Zeichenketten unterscheiden: {pre k ( ) | * und * }) {pre k ( ') | * und ' ' * '} = Zur Überprüfung dieser Eigenschaft werden die First k - und Follow k -Mengen eingeführt. S * * A * 'A ' ' ' ' * ' '

24 24 Beispielgrammatik Grammatik 1 für reguläre Ausdrücke: REG ALT ALT KON | KON "|" ALT KON SYM | SYM "." KON SYM a | … | Z | $ | "(" ALT ")" | "(" ALT ")" "*" Grammatik 1 hat für kein k die starke LL(k)-Eigenschaft Links-Faktorisierte Grammatik 2: REG ALT ALT KON A A | "|" ALT KON SYM K K | "." KON SYM a | … | Z | $ | "(" ALT ")" S S | "*" Links-Faktorisierte Grammatik hat die starke LL(k)-Eigenschaft für k = 1 Zurück

25 25 First k -Menge First k ( ) = {pre k ( ) | * und * } für V * Berechnung durch Lösung eines Mengengleichungssystems, das sich aus den folgenden Regeln ergibt: First k (a 1 …a n ) = First k (a 1 ) k … k First k (a n ) für a i V mit 1 i n First k (a) = {a} für a First k (A) = First k ([A,1]) … First k ([A,|[A]|]) für A M First k ( ) = { }

26 26 Beispiel: Ergebnis der Berechnung der First 1 - Menge für Grammatik 2 ItFirst 1 (REG)First 1 (ALT)First 1 (A)First 1 (KON)First 1 (K)First 1 (SYM)First 1 (S) 0 1 { } { }{a,…,Z,$}{, *} 2 { }{a,…,Z,$}{ }{a,…,Z,$}{, *} 3 {a,…,Z,$}{ }{a,…,Z,$}{,. }{a,…,Z,$}{, *} 4{a,…,Z,$} {, | }{a,…,Z,$}{,. }{a,…,Z,$,(}{, *} 5{a,…,Z,$} {, | }{a,…,Z,$,(}{,. }{a,…,Z,$,(}{, *} 6{a,…,Z,$}{a,…,Z,$,(}{, | }{a,…,Z,$,(}{,. }{a,…,Z,$,(}{, *} 7{a,…,Z,$,(} {, | }{a,…,Z,$,(}{,. }{a,…,Z,$,(}{, *} 8{a,…,Z,$,(} {, | }{a,…,Z,$,(}{,. }{a,…,Z,$,(}{, *} Beispielgrammatik 2

27 27 Follow k -Menge Es interessieren alle terminalen Zeichenketten der Länge k, die in irgendeiner Satzform hinter einem Metasymbol A auftreten können: S' * A und * Follow k (A) = {First k ( ) | S' * A } Berechnung durch: Follow k (A) = {First k ( ) k Follow k (B) | B A } Auch das ursprüngliche Startsymbol S der Grammatik hat in seiner Follow k -Menge nur Zeichenketten der Länge k, weil die Grammatik um die Regel S' S k mit dem neuen Startsymbol S' ergänzt wurde. Follow k (S') = { }

28 28 Beispiel: Ergebnis der Berechnung der Follow 1 -Menge für Grammatik 2 Beispielgrammatik 2 ItFollow 1 (REG)Follow 1 (ALT)Follow 1 (A)Follow 1 (KON)Follow 1 (K)Follow 1 (SYM)Follow 1 (S) 0 1{ } 2{ } 3{ } {, | } 4{ } {, | } {, |,. } 5{ }{, )}{ }{, | } {, |,. } 6{ }{, )} {, ), | }{, | }{, |,. } 7{ }{, )} {, ), | } {, |, ),. }{, |,. } 8{ }{, )} {, ), | } {, |, ),. } 9{ }{, )} {, ), | } {, |, ),. }

29 29 Prüfen der starken LL(k)-Eigenschaft Zur Erinnerung; gezeigt werden sollte für S * A und S * 'A ' ' ' ' : {pre k ( ) | * und * } {pre k ( ') | * und ' ' * '} = und ' waren verschiedene Alternativen des Metasymbols A an der Stapelspitze. aus und ' lassen sich terminale Zeichenketten ableiten, deren Präfixe Elemente der Follow k -Mengen des Metasymbols A sind Die obige Eigenschaft kann somit umgeschrieben werden zu: First k ([A,i]) k Follow k (A) First k ([A,j]) k Follow k (A) = für alle 1 i j |[A]| Eine Grammatik ist damit genau dann eine starke LL(k)-Grammtik, wenn letztere Eigenschaft gilt. In der Parsersituation ( A, ) ist damit die Alternative i von A zu wählen, für die gilt: pre k ( ) First k ([A,i]) k Follow k (A)

30 30 Beispiel: Prüfen der starken LL(1)-Eigenschaft Grammatik: REG ALT ALT KON A A | "|" ALT KON SYM K K | "." KON SYM "a" | … | "Z" | $ | "(" ALT ")" S S | "*" First 1 -Mengen: Follow 1 -Mengen: Test für REG, ALT, KON nicht notwendig. Für A, K und S ergibt sich: First 1 ([A,1]) 1 Follow 1 (A) First 1 ([A,2]) 1 Follow 1 (A) = First 1 ([K,1]) 1 Follow 1 (K) First 1 ([K,2]) 1 Follow 1 (K) = First 1 ([S,1]) 1 Follow 1 (S) First 1 ([S,2]) 1 Follow 1 (S) = Test für SYM auch klar. First 1 (REG)First 1 (ALT)First 1 (A)First 1 (KON)First 1 (K)First 1 (SYM)First 1 (S) {a,…,Z,$,(} {, | }{a,…,Z,$,(}{,. }{a,…,Z,$,(}{, *} Follow 1 (REG)Follow 1 (ALT)Follow 1 (A)Follow 1 (KON)Follow 1 (K)Follow 1 (SYM)Follow 1 (S) { }{, )} {, ), | } {, |, ),. }

31 31 Syntaxgesteuerter starker LL(k)-Parser Berechnung einer Steuerfunktion T : M k durch: Steuerung der Analyse mit dem PDA durch diese Funktion mittels: ( a,a ) (, ), falls a ( A, ) ( [A,i], ), falls A M und i = T(A,pre k ( )) Fehler, in den Situationen: ( a,b ), falls a b und a,b ( A, ), falls A M und T(A,pre k ( )) = error

32 32 Beispiel: Steuerfunktion (-tabelle) Ta…Z$()|.* REG1…111 ALT1…111 A121 KON1…111 K1121 SYM1… S11121 Leere Felder markieren Fehlerzustände (Eintrag = error)

33 33 Syntaxgebundener starker LL(k)-Parser Berechnung der Steuerfunktion T wie im syntaxgesteuerten Fall. Für jedes Metasymbol A Implementierung einer Funktion int A(): Funktion A wählt eine Alternative von A auf Grund der k Look-Ahead Symbole und leitet einen Präfix der anliegenden Eingabe aus dieser Alternative ab, indem: Für Metasymbole die zugehörige Funktion aufgerufen wird. Für Terminalsymbole überprüft wird, ob diese in der Eingabe auftreten. Rückgabewert gibt Auskunft über eine erfolgreiche Ableitung.

34 34 Beispiel: Syntaxgebundene Implementierung für SYM und S in Grammatik 2 int SYM() { char buf[8]; if((currMor() >= 'a' && currMor() <= 'z') || currMor() == '$') { if(currMor() == '$') sprintf(buf,"SYM_27"); else sprintf(buf,"SYM_%d",currMor() - 'a' + 1); outSyn(buf); nextMor(); return 1; } if(currMor() == OPENPAR) { nextMor(); outSyn("SYM_28"); if(!ALT()) return 0; if(currMor() != CLOSEPAR) return 0; nextMor(); return S(); } return 0; } int S() { if(nextMor() == '*') { nextMor(); outSyn("S_2"); return 1; } if(currMor() == ENDOF || currMor() == CLOSEPAR || currMor() == PIPE || currMor() == DOT) { outSyn("SYM_1"); return 1; } return 0; }

35 35 Beispiel: Syntaxgebundene Implementierung für Grammatik 1 Links-Faktorisierung direkt implementierbar Dadurch Erzeugung einer Postfixlinearisierung des Syntaxbaums erforderlich. int ALT() { int res; if(!KON()) return 0; if(currMor() == PIPE) { nextMor(); res = ALT(); outSyn("ALT_2"); return res; } if(currMor() == ENDOF || currMor() == CLOSEPAR) { outSyn("ALT_1"); return 1; } return 0; } int KON() { int res; if(!SYM()) return 0; if(currMor() == DOT) { nextMor(); res = KON(); outSyn("KON_2"); return res; } if(currMor() == ENDOF || currMor() == CLOSEPAR || currMor() == PIPE) { outSyn("KON_1"); return 1; } return 0; } Vollständiger Quelltext mit FehlerbehandlungVollständiger Quelltext mit Fehlerbehandlung Ausführbares ProgrammAusführbares Programm

36 36 Behandlung von Linksrekursivitäten Generell können linksrekursive Grammatiken nicht mit deterministischen tabellengesteuerten Top-Down-Parsern behandelt werden. Grammatik A A "+" M | A "–" M | M M M "*" T | M "/" T | T T "n" | "(" A ")" muss entweder transformiert werden (vgl. Folie 30 im Kapitel Grundlagen) oder Lösung bei syntaxgebundener Implementierung: Behandlung der Linksrekursivität wie eine Rechtsrekursivität Aufbau des Syntaxbaums als Postfixlinearisierung Dadurch entsteht der Syntaxbaum der linksrekursiven Grammatik Vollständiger Quelltext mit FehlerbehandlungVollständiger Quelltext mit Fehlerbehandlung Ausführbare DateiAusführbare Datei

37 37 Motivation schwache LL(k)-Grammatiken Es gibt Grammatiken, bei denen Faktorisierung nicht hilft: S aSab | bSba | cA A a | ab | cA Problem ist, dass für jedes k genügend lange und in Follow k (A) existieren, so dass: First k ([A,i]) k { } First k ([A,j]) k { } Aber: Bei der Entscheidung zwischen [A,i] und [A,j] folgen in der Analysesituation ( A, ) dem A nicht beliebige Zeichenketten oder aus Follow k (A) sondern nur solche, die aus (Stapelinhalt) ableitbar sind. Deshalb: Einbeziehung des Stapelinhalts in die Entscheidung für eine Alternative.

38 38 Definition schwache LL(k)-Grammatik Es sei G = (, M, R, S) eine Grammatik und k. Dann ist G eine schwache LL(k)- Grammatik, wenn gilt: Existieren zwei Linksableitungen und pre k ( ) = pre k ( '), dann folgt, dass = ', wobei,, ' *, S,A M und,, ' V * Unterschied zur Definition einer starken LL(k)-Grammatik: Existieren zwei Linksableitungen und pre k ( ) = pre k ( ') dann folgt, dass = ', wobei,, ', ' *, S,A M und,, ', ' V * Folgerungen: Jede schwache LL(k)-Grammatik ist eindeutig Jede starke LL(k)-Grammatik ist eine schwache LL(k)-Grammatik S * * A * 'A ' ' ' ' * ' ' S * A * ' * ' Entscheidung in Analysesituation ( A, ) Entscheidung in Analysesituation ( A, ') Entscheidung in Analysesituation ( A, ) Entscheidung in Analysesituation ( 'A, ')

39 39 Prüfen der schwachen LL(k)-Eigenschaft Es sei G = (, M, R, S) eine Grammatik und k. Dann ist G eine schwache LL(k)- Grammatik, wenn gilt: Existieren zwei Linksableitungen und pre k ( ) = pre k ( '), dann folgt, dass = ', wobei,, ' *, S,A M und,, ' V * Die Entscheidung zwischen zwei verschiedenen Alternativen und ' kann damit nur dann eindeutig getroffen werden, wenn alle aus ableitbaren terminalen Zeichenketten sich in den ersten k Symbolen von allen aus ' ableitbaren terminalen Zeichenketten unterscheiden: {pre k ( ) | *, * } {pre k ( ) | *, ' * '} = Zur Überprüfung dieser Eigenschaft müssen die Präfixmengen der verschiedenen Rechts- Kontexte, die hinter A in einer Linksableitung auftreten können, separat berechnet werden. Ziel: Berechnung einer Menge F k (A) := {First k ( ) | S * A ist Linksableitung} S * A * ' * '

40 40 Herleitung für Berechnung der F k (A)-Mengen Verschiedene Rechts-Kontexte entstehen durch die Wahl verschiedener Alternativen in vorangegangenen Ableitungsschritten: Da die Wahl einer Alternative von A in Abhängigkeit vom konkreten Rechts-Kontext getroffen werden soll, muss unterschieden werden, ob A durch die Regel B' ' n A ' n oder B n A n entstanden ist. Es müssen für diese Regeln die wohl unterschiedenen Follow k -Mengen First k ( ) und First k ( ') gebildet werden. Falls First k ( ') und/oder First k ( ) für eine Alternative von A nicht genügend lange Zeichenketten enthalten, muss diese Betrachtung für die Entstehung von B bzw. B' wiederholt werden. Da B und B' sich selbst auch in verschiedenen Rechts-Kontexten {F 1,…F n } bzw. {F' 1,…,F' n } befinden können, kann sich A in den Rechts-Kontexten First k ( ) F 1,…, First k ( ) F n, First k ( ) F' 1,…, First k ( ) F' n befinden. Wir erhalten deshalb allgemein: F k (A) = {First k ( ) k F | B A und F F k (B)} S * * 1 '… n-2 'C' n-2 '… 1 ' 1 '… n-1 'B' n-1 '… 1 ' 1 '… n 'A n '… 1 ' = 'A ' 1 … n-2 C n-2 … 1 1 … n-1 B n-1 … 1 1 … n A n … 1 = A

41 41 Berechnung der F k (A)-Mengen Durch F k (A) = {First k ( ) k F | B A und F F k (B)} wird für die Metasymbole einer Grammatik ein Mengengleichungssytem definiert, dessen kleinster Fixpunkt die F k (A)-Mengen der Metasymbole A sind. Beispielgrammatik S' S S aSab | bSba | cA A a | ab | cA Mengengleichungssystem für k = 3: F 3 (S')={{ }} F 3 (S)={First 3 (ab) 3 F, First 3 (ba) 3 F | F F 3 (S)} {First 3 ( ) 3 F | F F 3 (S')} F 3 (A)={First 3 ( ) 3 F | F F 3 (S)} {First 3 ( ) 3 F | F F 3 (A)} ItF 3 (S')F 3 (S)F 3 (A) 0 1{{ }} 2{{ }} 3{{ }}{{ab },{ba },{ }}{{ }} 4 {{aba},{abb},{ab },{baa},{bab},{ba },{ }}{{ab },{ba },{ }} 5{{ }}{{aba},{abb},{ab },{baa},{bab},{ba },{ }} 6{{ }}{{aba},{abb},{ab },{baa},{bab},{ba },{ }}

42 42 Prüfen der schwachen LL(k)-Eigenschaft Eine Grammatik G hat genau dann die schwache LL(k)-Eigenschaft, wenn ein k existiert, so dass A M 1 i j |[A]| F F k (A) gilt First k ([A,i]) k F First k ([A,j]) k F =. Beispielgrammatik S' S S aSab | bSba | cA A a | ab | cA F 3 -Mengen: Test für [A,1] und [A,2] und k = 3: F 3 (S')F 3 (S)F 3 (A) {{ }}{{aba},{abb},{ab },{baa},{bab},{ba },{ }} F 3 (A){aba}{abb}{ab }{baa}{bab}{ba }{ } First k ([A,1]) k F{aab} {aba} {a } First k ([A,2]) k F{aba} {abb} {ab }

43 43 Schwacher LL(k)-Automat Falls die schwache LL(k)-Eigenschaft für eine Grammatik G abgesichert ist, kann der PDA wie folgt arbeiten: Steuerung der Analyse durch: ( a,a ) (, ), falls a ( A, ) ( [A,i], ), falls A M und pre k ( ) First k ([A,i] ) Fehler, in den Situationen: ( a,b ), falls a b und a,b ( A, ), falls A M und für alle 1 i |[A]| pre k ( ) First k ([A,i] ) Problem: bei jedem Takt der Art 2 muss die First k -Menge des Kellerinhalts berechnet werden. Ziel: Berechnung einer Steuertabelle wie bei starken LL(k)- Grammatiken

44 44 Vereinfachung der Berechnung während der Analyse Prinzip: Jedes Metasymbol A im Stapel wird mit der First k -Menge F des darunter befindlichen Stapelinhalts markiert: A F. Einfache Berechnung der Markierung neu eingestapelter Metasymbole durch: A F aktueller Kellerinhalt mit First k ( ) = F Jedes Metasymbol B in Alternative B von A wird beim Ersetzen von A durch diese Alternative markiert mit First k ( ) k First k ( ) = First k ( ) k F. Startsituation des PDA: (S' { }, ). First k ( ) kann auch im Voraus berechnet werden.

45 45 Vereinfachter schwacher LL(k)-Automat Mit den markierten Metasymbolen im Stapel kann die Arbeitsweise des PDA vereinfacht werden: Steuerung der Analyse durch: ( a,a ) (, ), falls a ( A F, ) ( [A,i], ), falls A M und pre k ( ) First k ([A,i]) k F, wobei jedes Metasymbol in [A,i] beim Einstapeln wie auf voriger Folie beschrieben markiert wird. Fehler, in den Situationen: ( a,b ), falls a b und a,b ( A F, ), falls A M und für alle 1 i |[A]| pre k ( ) First k ([A,i]) k F

46 46 Transformation einer schwachen LL(k)- Grammatik Fakt 1: In der Situation ( A F, ) ändert sich bei Ersetzung von A F durch Alternative die Markierung eines Metasymbols in nach dem Einstapeln nicht mehr und hängt nur von der Markierung von A und ab Fakt 2: Markierungen eines Metasymbols A sind nur Elemente aus F k (A). Dadurch ist die Berechnung aller möglichen Markierungen in im Voraus möglich. Man erhält zur schwachen LL(k)-Grammatik (, M, S',R) die transformierte Grammatik (, M m, S' { },R m ) durch: M m := {A F | A M und F F k (A)}

47 47 Beispiel für Transformation F{ }{aba}{abb}{ab }{baa}{bab}{ba }{ } Nummer S' S S aSab | bSba | cA A a | ab | cA S' 0 S 7 S 7 aS 3 ab | bS 6 ba | cA 7 S 6 aS 2 ab | bS 5 ba | cA 6 S 5 aS 2 ab | bS 5 ba | cA 5 S 3 aS 1 ab | bS 4 ba | cA 3 S 4 aS 2 ab | bS 5 ba | cA 4 S 2 aS 1 ab | bS 4 ba | cA 2 S 1 aS 1 ab | bS 4 ba | cA 1 A 7 a | ab | cA 7 A 6 a | ab | cA 6 A 5 a | ab | cA 5 A 4 a | ab | cA 4 A 3 a | ab | cA 3 A 2 a | ab | cA 2 A 1 a | ab | cA 1 Transformierte Grammatik: Ursprüngliche Grammatik:Transformationsregel: Nummerierung der F F 3 -Mengen

48 48 PDA für transformierte schwache LL(k)- Grammatik Da in jeder Regel bereits alle Metasymbole markiert sind, kann die Berechnung der Markierungen während der Analyse entfallen. Steuerung der Analyse durch: ( a,a ) (, ), falls a ( A F, ) ( [A F,i], ), falls A F M m und pre k ( ) First k ([A F,i]) k F Fehler, in den Situationen: ( a,b ), falls a b und a,b ( A F, ), falls A F M m und für alle 1 i |[A F ]| pre k ( ) First k ([A F,i]) k F Entscheidung für eine Alternative i von A F basiert nur noch auf den Mengen First k ([A F,i]) und F Konsequenz: Konstruktion einer Steuerfunktion möglich

49 49 Steuerfunktion für transformierte schwache LL(k)-Grammatiken Berechnung einer Steuerfunktion T : M m k durch: Steuerung der Analyse mit dem PDA durch diese Funktion mittels: ( a,a ) (, ), falls a ( A F, ) ( [A F,i], ), falls A F M m und i = T(A F,pre k ( )) Fehler, in den Situationen: ( a,b ), falls a b und a,b ( A F, ), falls A F M m und T(A F,pre k ( )) = error Dieser PDA ist ein PDA für eine starke LL(k)-Grammatik, weil für jedes A F M m gilt: Follow k (A F ) = F.

50 50 Zusammenfassung LL(k)-Grammatiken Jede schwache LL(k)-Grammatik kann in eine bedeutungsäquivalente starke LL(k)-Grammatik transformiert werden. Jede Sprache, die mit einer schwachen LL(k)- Grammatik analysiert werden kann, kann auch mit einer starken LL(k)-Grammatik analysiert werden. Es gibt Sprachen, die mit LL(k) aber nicht mit LL(k- 1) (für 1 k) analysierbar sind. Es gibt deterministisch analysierbare Sprachen, die nicht mit LL(k)-Verfahren analysierbar sind.

51 51 LR(k)-Grammatik Es sei S * A eine Rechtsableitung zu einer kontextfreien Grammatik G = (, M, R, S). Dann heißt Griff der Rechtssatzform. Bei eindeutigen Grammatiken ist der Griff das nächste Teilwort, das im Keller des Bottom-Up-PDA ersetzt wird. Jeder Präfix von heißt zuverlässiger Präfix von G. Solche Präfix einer Rechtssatzform, erstrecken sich nicht über den Griff dieser Rechtssatzform hinaus. Sie sind somit Kellerinhalt des Bottom-Up-PDA. Es sei G eine kfG und k. Dann besitzt G die LR(k)-Eigenschaft, falls gilt: Existieren zwei Rechtsableitungen und pre k ( ) = pre k ( ), dann folgt, dass A = A', = ' und = ', wobei S, A, A' M und,, ' * und,, ' V *. Das bedeutet, dass für jedes w L(G) in jeder Rechtssatzform der Ableitung von w der längste zuverlässige Präfix und der Griff eindeutig durch die ersten k Symbole nach dem Griff (in ) bestimmt sind. S * * A 'A' '

52 52 LR(k)-Item [A., ] ist genau dann ein gültiges LR(k)-Item für die Grammatik G, wenn S * A eine Rechtsableitung und = pre k ( ), wobei *, V * und A R. Zu einem zuverlässigen Präfix gehört somit die Menge der gültigen Items: Items( ) = {[A., ] | S * A und = pre k ( )} Wichtig: Aus [A.B, ] Items( ) und B R folgt: Für alle ' (First k ( ) gilt [B., '] Items( ).(Closure) Ein Item [A., ] Items( ) repräsentiert eine Analysesituation (, ) des Bottom-Up-PDA, in der der PDA bereits einen Anfang * der Eingabe verarbeitet hat: (, ) * (, ) Die Analyse sich gerade in einem Teil des Wortes befindet, der aus abgeleitet wurde. D.h. es gibt u, v * mit * u und * v, wobei : u bereits gelesen wurde ( = wu) und erwartet wird, dass mit v beginnt ( = v z) Nachdem v gesehen und zu reduziert wurde, kann dann zu A reduziert werden Das entspricht der zu [A., ] Items( ) existierenden Rechtsableitung S * A z z * v z *, wobei A, S M und,, V * und v,, z *.

53 53 LR(k)-Analyse Es gilt: G hat die LR(k)-Eigenschaft, gdw. für jeden zuverlässigen Präfix gilt: Wenn [A., ] Items( ), dann gilt für alle [B., '] Items( ), dass aus First k ( ') folgt: A = B, =, = und damit = '. Dadurch ist in jeder Satzform einer Rechtsableitung der Griff eindeutig bestimmt und der Bottom-Up-PDA muss wie folgt arbeiten: (, ) ( A, ) gdw. [A.,pre k ( )] Items( )(Reduzieren) (, a ) ( a, ) gdw. = ' und [A., ] Items( ) und pre k (a ) First k ( ) und V + (Schieben)

54 54 LR(k)-Analyse mit dem PDA Damit ist abgesichert, dass für jeden möglichen Kellerinhalt (zuverlässigen Präfix) eindeutig entschieden werden kann, ob und wenn ja nach welcher Regel reduziert werden muss. Das heißt: Es gibt keine Konflikte beim Schieben und Reduzieren, weil für jeden zuverlässigen Präfix und die Resteingabe gilt: [A.,pre k ( )] Items( ) und [B.,pre k ( )] Items( ), dann A = B und =. [A.,pre k ( )] Items( ) und [B.,pre k ( )] Items( ) und pre k ( ) First k ( pre k ( )), dann A = B und = und =. Problem: Für jeden Kellerinhalt muss während der Analyse Items( ) berechnet werden.

55 55 Mitführen des Stapelzustandes Lösung: Zu jedem Symbol a i V im Keller mit Inhalt a 1 …a n wird die zugehörige Menge Items(a 1 …a i ) mitgeführt für 1 i n. Aus diesen bekannten Item-Mengen soll beim Einstapeln (Schieben) eines neuen Symbols a die Menge Items(a 1 …a n a) berechnet werden, beim Reduzieren nach A a k …a n die Menge Items(a 1 …a k- 1 A) berechnet werden. Die Menge aller möglichen gültigen Items ist endlich, damit auch die Menge aller ihrer Teilmengen. Somit ist eine Vorausberechnung möglich.

56 56 Vorausberechnung der Items beim Einstapeln Beziehung zwischen Items( ) und Items( a) beim Einstapeln von a: Aus Einstapeln von a bei Stapelinhalt folgt: Es ex. eine Rechtssatzform S * A a, weil [A.a, pre k ( )] Items( ). Falls = b ', dann gibt es eine Rechtsableitung S * A ab ' und somit [A a., pre k ( )] Items( a) Falls =, dann gibt es eine Rechtsableitung S * A a und somit [A a., pre k ( )] Items( a) Falls = B ', dann gibt es eine Rechtsableitung S * aB ' * aB ' und somit [A a.B ', pre k ( )] Items( a). Außerdem [B., ] Items( a) für alle First k ( ' ), weil aB ' a ' eine Rechtsableitung ist (Closure auf Folie 51). Konsequenz: Konstruktion von Items( a) ist mittels der Menge Items( ) und der Regeln der Grammatik möglich!

57 57 Konstruktion der erforderlichen Item-Mengen für Schiebe-Takte Für die zu einem Kellerinhalt gehörenden Itemmenge I am obersten Kellersymbol kann für die Items [A.a, ] I, die ein Einstapeln des Symbols a verlangen, die zugehörige neue Itemmenge I' berechnet werden durch: I' := {[A a., ] | [A.a, ] I} I' := closure(I'), wobei closure(I) = I {[B., '] |[A.B, ] I und B R und ' (First k ( )} Ist also das Symbol an der Kellerspitze mit I beschriftet und a wird eingestapelt, dann wird a mit I' beschriftet. Zu der Startsituation (,w) des Parsers, gehört die Itemmenge closure({[S'.S k, ]}). Es verbleibt die Vorausberechnung der Analysesituationen, die der Parser nach einem Reduktionstakt einnimmt.

58 58 Vorausberechnung der Items beim Reduzieren Beziehung zwischen Items( ) und Items( A) beim Reduzieren nach A : Aus Reduzieren nach A bei Stapelinhalt folgt: Es ex. S * A, weil [A., pre k ( )] Items( ). Damit ex. auch S' * 'B ' ' A ' ' * ' A = A. Damit ist [B A. ', pre k ( ')] Items( A), weil = '. Zur Berechnung von Items( A) wird die Menge Items( ) verwendet, weil gilt: [B A. ', pre k ( ')] Items( A), gdw. [B.A ', pre k ( ')] Items( ). Konsequenz: Konstruktion von Items( A) ist bei Stapelinhalt aus der Menge Items( ) möglich, die mit dem obersten Symbol in gespeichert wurde.

59 59 Konstruktion der erforderlichen Item-Mengen für Reduktions-Takte Falls bei Kellerinhalt nach A reduziert wird, so ergibt sich die Itemmenge für das neue Symbol A an der Spitze des Stapelinhalts A durch: Ausstapeln von und Lesen der Itemmenge I an der Spitze des Stapelinhalts, I' := {[B A. ', ] | [B.A ', ] Items( )}, I' := closure(I'). Da durch Ausstapeln eines jede zuvor eingestapelte Itemmenge an der Stapelspitze freigelegt werden kann, die ein Item der Form [B.A ', ] enthält, ergibt sich folgender Algorithmus zur Konstruktion aller Itemmengen:

60 60 Berechnung der Item-Mengen Berechnung aller Itemmengen; I ist eine Menge von Itemmengen Berechnung der Übergänge von einer Itemmenge in eine andere I := {closure([S'.S, k ])} := do I ' := I for each z I do ( I, ) := goto(z,( I, )) while( I I ') goto(z,( I, )) for each x V do z' := for each [A. x, ] z do z' := z' {[A x., ] } od if z' then I := I closure(z') := (z,x,z') fi od return (I, ) ; closure(z) do z' := z; for each [A. B, ] z do z := z {(B., )|B R und First k (, )} od while(z z') return z; Beispiel

61 61 Eigenschaften des konstruierten Automaten Die beschriebene Konstruktion erzeugt einen Automaten (I,V,closure([S'.S, k ]),I, ) für den gilt: Seine Zustandsmenge ist endlich Die Zustandsübergänge sind deterministisch Der Automat erkennt genau die zuverlässigen Präfixe der Grammatik (Beweis durch Induktion über die Anzahl der Zustandsübergänge) Dieser Automat wird als kanonischer DEA bezeichnet, kurz: (I, ).

62 62 Konstruktion der kanonischen Steuerfunktion Es sei (I, ) der kanonische DEA. Die Steuerfunktion T : I k I ist dann definiert als: Kellerelemente sind Zweitupel aus I V. Startsituation ((closure([S'.S, k ]),S'), ). Verhalten des Automaten: ( (I,x),a ) ( (I,x)(I',a), ), falls T(I,pre k (a )) = shift und (I,a,I') ( (I 0,x 0 )…(I n,x n ),a ) ( (I 0,x 0 )(I,A),a ), falls T(I n,pre k (a )) = reduce(A ) und | | = n und (I 0,A,I) ( (I,S), k ) mit (closure([S'.S, k ]),S,I) ist akzeptierender Endzustand Offensichtlich genügt es sogar nur die Items im Keller zu speichern. Damit Vereinfachung der kanonischen Steuerfunktion.

63 63 Vereinfachung der kanonischen Steuerfunktion Es sei (I, ) der kanonische DEA. Die Steuerfunktion T : I ( k M) I ist dann definiert als: Kellerelemente sind Itemmengen. Verhalten des Automaten: ( I,a ) ( II', ), falls T(I,pre k (a )) = shift I' ( I 0 I 1 …I n,a ) ( I,a ), falls T(I n,pre k (a )) = reduce(A ) und | | = n und T(I 0,A) = I (I, ) ist akzeptierende Situation, falls T(I,pre k ( )) = accept Error in allen anderen Situationen

64 64 Konflikte Schiebe-Reduktions-Konflikt: Ein Schiebe-Reduktions-Konflikt ist in der Itemmenge I vorhanden, falls es Items [A., ] I und [B.c, '] I mit,, V * und c und First k (c ') gibt. Reduktions-Reduktions-Konflikt: Ein Reduktions-Reduktions-Konflikt ist in der Itemmenge I vorhanden, falls es verschiedene Items [A., ] I und [B., '] I mit, V * und = ' gibt. Konflikte treten genau dann auf, wenn die Grammatik nicht die LR(k)- Eigenschaft hat. Konstruktion des kanonische DEA ist damit ein Test für die LR(k)- Eigenschaft. Auflösen von Konflikten durch: Umschreiben der Grammatik. Definition der Steuerfunktion entsprechend eines Items. D.h., Auflösen des Konflikts bzgl. Schieben oder Reduzieren nach einer bestimmten Regel.

65 65 LALR (Lookahead-LR) Der Kern kern(I) einer Itemmenge I ist definiert als {[A. ] | : [A., ] I} Verkleinerung der Zustandsmenge I eines kanonischen LR(1) DEA durch Zusammenfassen von Itemmengen mit dem gleichen Kern: I' := { [I] | I I und [I] := {I' | kern(I) = kern(I')}} '([I],x) := [I'], falls (I,x) := I' Konstruktion der LALR-Steuertabelle entspricht der Konstruktion der kanonischen Steuertabelle. Verkleinerung der Zustandsmenge in praktischen Programmiersprachen dadurch in etwa um den Faktor 10.

66 66 Beispiel: kanonischer DEA [S'.S, ] [S.CC, ] [C.cC,c] [C.cC,d] [C.d,c] [C.d,d] [S' S., ] I0I0 I1I1 [S C.C, ] [C c.C, ] [C.d, ] I2I2 [S CC., ] I5I5 [C c.C, ] [C.cC, ] [C.d, ] I6I6 [C d., ] I7I7 [C c.C,c] [C c.C,d] [C.cC,c] [C.cC,d] [C.d,c] [C.d,d] I3I3 [C d., c] [C d., d] I4I4 [C cC.,c] [C cC.,d] I8I8 [C cC., ] I9I9 S C c d d c C d c d C C Grammatik: S' S S C C C c C | d c

67 67 Beispiel: LALR-DEA [S'.S, ] [S.CC, ] [C.cC,c] [C.cC,d] [C.d,c] [C.d,d] [S' S., ] I0I0 I1I1 [S C.C, ] [C c.C, ] [C.d, ] I2I2 [S CC., ] I5I5 [C c.C, ] [C.cC, ] [C.d, ] [C c.C,c] [C c.C,d] [C.cC,c] [C.cC,d] [C.d,c] [C.d,d] I6I6 [C d., c] [C d., d] [C d., ] I 4 /I 7 [C cC., ] [C cC.,c] [C cC.,d] I 8 /I 9 S C c d c d c d C C Grammatik: S' S S C C C c C | d

68 68 Eigenschaften LALR-Steuertabelle Eigenschaften dieser Transformation: Der entstehende Endliche Automat ist wieder deterministisch. Hatten die Zustände des kanonischen DEA keine Schiebe- Reduziere-Konflikte, dann haben auch die Zustände des LALR-DEA solche Konflikte nicht. Es können Reduziere-Reduziere-Konflikte entstehen. Konsequenz: Es gibt Grammatiken, für die eine kanonische Steuerfunktion aber keine LALR-Steuerfunktion existiert.

69 69 Beispiel Grammatik S' S S a A d | b B d | a B e | b A e A c B c besitzt eine kanonische LR(1) Steuertabelle aber keine LALR-Steuertabelle, weil Items(ac) = {[A c., d], [B c., e]} Items(bc) = {[A c., e], [B c., d]} Damit entsteht im LALR-DEA eine Reduktions- Reduktions-Konflikt.

70 70 SLR (Simple LR) Verkleinerung der Menge I durch Verzicht auf die Vorschau in den Itemmengen. I besteht damit nur noch aus den Kernen: I' = {kern(I) | I I} '(kern(I),x) := kern(I'), falls (I,x) := I' Konsequenz: Der SLR-DEA hat genauso viele Zustände wie der LALR-DEA. Die Berechnung des SLR-DEA vereinfacht sich jedoch.

71 71 Berechnung der Item-Mengen für SLR-DEA Berechnung aller Itemmengen; I ist eine Menge von Itemmengen Berechnung der Übergänge von einer Itemmenge in eine andere I := {closure([S'.S])} := do I ' := I for each z I do ( I, ) := goto(z,( I, )) while( I I ') goto(z,( I, )) for each x V do z' := for each [A. x ] z do z' := z' {[A x. ]} od if z then I := I closure(z') := (z,x,z') fi od return (I, ) ; closure(z) do z' := z; for each [A. B ] z do z := z {[B. ]|B R} od while(z z') return z;

72 72 SLR Steuerfunktion Da in den Items die Vorausschau fehlt, muss mit den Follow k -Mengen gearbeitet werden:

73 73 Beispiel: SLR(1)-Grammatik Grammatik (vereinfacht) für arithmetische Ausdrücke ist SLR(1): S' A A A + M | M M M * T | T T Number | ( A ) [S'.A] [A.A+M] [A.M] [M.M*T] [M.T] [T.Number] [T.( A )] [S' A.] [S' A.+M] I0I0 I1I1 [A M.] [M M.*T] I2I2 A M [T Number.] I5I5 [T (.A)] [A.A+M] [A.M] [M.M*T] [M.T] [T.Number] [T.( A )] I4I4 [M T.] I3I3 [S' A+.M] [M.M*T] [M.T] [T.Number] [T.( A )] I6I6 [M M*.T] [T.Number] [T.( A )] I7I7 [A A.+M] [T (A.)] I8I8 [S' A+M.] [M M.*T] I9I9 [M M*T.] I 10 [T (A).] I 11 Number T ( + * T M ( A + ( ( T M * T )

74 74 Beispiel: Nicht SLR(1)-Grammatik Grammatik, die nicht SLR(1) aber LALR(1) ist: S L = R L * R | Id R L Follow 1 (R) enthält = (wegen der Ableitung S L=R *R = R) [S'.S] [S.L=R] [S.R] [L.*R] [L.Id] [R.L] I0I0 [S' S.] I1I1 [S L.=R] [R L.] I2I2 [S R.] I3I3 [L *.R] [R.L] [L.*R] [L.Id] I4I4 [L Id.] I5I5 [S L=.R] [R.L] [L.*R] [L.Id] I6I6 [L *R.] I7I7 [R L.] I8I8 [S L=R.] I9I9 S L= R L * * R R Id

75 75 Bison Zur Generierung des C-Quelltextes eines Parsers. Die vom Parser akzeptierte Sprache wird durch die Regeln einer kfG spezifiziert. Jeder Alternative eines Metasymbols kann eine Aktion in Form von C-Quelltext zugeordnet werden. Einfache Einbindung eines mit Flex generierten Scanners. Lex Quelltext name.l Lex Quelltext name.l Lex Aufruf: lex name.l Scanner als C- Datei: Lex.yy.c Scanner als C- Datei: Lex.yy.c C-Compiler Aufruf: gcc lex.yy.c name.tab.c Ausführ- bare Datei: a.exe Ausführ- bare Datei: a.exe Bison Quelltext name.y Bison Quelltext name.y Bison Aufruf: bison name.y Parser als C- Datei: name.tab. c Parser als C- Datei: name.tab. c Morphem- arten: name.tab.. h Morphem- arten: name.tab.. h -d Parser- tabelle -v

76 76 Struktur eines Bison-Quelltextes Deklarationsabschnitt: Token-Deklaration Vereinbarung von Typen für Grammatiksymbole C-Code-Fragmente Regelabschnitt: Grammatikregeln in BNF Optional zu jeder Regel eine Aktion in Form von C-Code Funktionsabschnitt C-Funktionen, die in die erzeugte C-Datei kopiert werden Deklarationsabschnitt % Regelabschnitt % Funktionsabschnitt

77 77 Ablauf der Generierung des Parserquelltextes … % A1 :[A1,1] {Aktion 1.1} |[A1,2] {Aktion 1.2} |… … An :[An,1] {Aktion n.1} |[An,2] {Aktion n.2} |… % … % A1 :[A1,1] {Aktion 1.1} |[A1,2] {Aktion 1.2} |… … An :[An,1] {Aktion n.1} |[An,2] {Aktion n.2} |… % … Parser als C-Datei: y.tab.c Parser als C-Datei: y.tab.c … LALR-DEA … Simulator für PDA LALR- Steuer- tabelle Look-Ahead Parserstapel Wertestapel Scanner

78 78 Deklarationsabschnitt Deklaration von C-Code Eingeschlossen in %{ und %} Deklarieren von Bezeichnern/Typen, die im Regel- oder Funktionsabschnitt benutzt werden Deklaration von Grammatiksymbolen Deklaration von Morphemen durch %token Bezeichner Bezeichner kann in der Regelsektion von bison und flex verwendet werden. Deklaration von Präzedenzen %left Bezeichner, %right Bezeichner, %nonassoc Bezeichner Deklaration von spezifischen Typen

79 79 Regelabschnitt BFN-Regel A ::= 1 | … | n wird geschrieben als: A: 1 {Aktion 1 } | 2 {Aktion 2 } … | n {Aktion n }; Aktion i ist C-Code, in dem verwendet werden kann: $$, $1,…,$k, wobei $$ der mit A und $i der mit n (i-1) assoziierte Wert ist. {Aktion i } ist optional; Standardaktion: $$ = $1. Terminalsymbole definiert als Morphemart oder in ' ' eingeschlossen; dann ist ASCII-Code des ersten Zeichens die Morphemart. -Regel durch Angabe einer leeren Alternative. Übrige Symbole sind Metasymbole.

80 80 Beispiel: Einfaches Bison-Programm %{ #include void yyerror(char*); int yylex(); %} %token DIGIT % line : expr '\n' {printf("%d\n",$1);} ; expr : expr '+' term {$$ = $1 + $3;} | term ; term : term '*' factor {$$ = $1 * $3;} | factor ; factor: '(' expr ')' {$$ = $2;} | DIGIT ; % int yylex() { int c; c = getchar(); if(isdigit(c)) { yylval = c - '0'; return DIGIT; } return c; } void yyerror(char* err) { printf("%s",err); } int main(int argc, char* argv[]) { return yyparse(); } Vollständiger QuelltextVollständiger Quelltext Ausführbares ProgrammAusführbares Programm

81 81 Beispiel: Mehrdeutige Grammatik %{ #include %} %token DIGIT % line : expr '\n' {printf("%d\n",$1);} ; expr : expr '+' expr {$$ = $1 + $3;} | expr '-' expr {$$ = $1 - $3;} | expr '*' expr {$$ = $1 * $3;} | expr '/' expr {$$ = $1 / $3;} | DIGIT ; % int yylex() { int c; c = getchar(); if(isdigit(c)) { yylval = c - '0'; return DIGIT; } return c; } Vollständiger Quelltext Ausführbares Programm Ausgabe nach Bison-Aufruf mit Option -v

82 82 LALR-DEA zum vereinfachten Beispiel [S'.E, ] [E.E+E, |+|*] [E.E*E, |+|*] [E.z, |+|*] [S' z., |+|* ] I0I0 I1I1 [S' E., ] [E E.+E, |+|*] [E E.*E, |+|*] I2I2 z Grammatik: S' E E E + E E E * E E z [E E*.E, |+|*] [E.E+E, |+|*] [E.E*E, |+|*] [E.z, |+|*] I5I5 E* [E E+.E, |+|*] [E.E+E, |+|*] [E.E*E, |+|*] [E.z, |+|*] I3I3 + [E E+E., |+|*] [E E.+E, |+|*] [E E.*E, |+|*] I4I4 E [E E*E., |+|*] [E E.+E, |+|*] [E E.*E, |+|*] I6I6 E* + + * z z

83 83 Auflösen von Konflikten beim Erstellen der Steuertabelle In der Steuertabelle werden die Konflikte entweder durch Schieben oder Reduzieren aufgelöst. Durch Reduzieren wird dem letzten eingestapelten Operator eine höhere Priorität als dem nächsten Operator in der Eingabe gegeben. Falls beide Operatoren gleich sind entspricht das einer Linksassoziativität. Entsprechend wird durch Schieben dem nächsten Operator in der Eingabe eine höhere Priorität als dem letzten eingestapelten Operator gegeben. Steuertabelle zum LALR-DEA auf voriger Folie: Zustandz+* E 0Shift 12 1Reduce E z 2Shift 3Shift 5Accept 3Shift 14 4Shift 3*Shift 5 ** Reduce E E + E 5Shift 16 6Reduce E E * E * macht + rechtsassoziativ ** gibt * Vorrang vor +

84 84 Standardbehandlung von Konflikten in Bison Konflikte in den Itemmengen werden von Bison angezeigt und beim Erstellen der Steuertabelle automatisch wie folgt aufgelöst: Reduktion-Reduktion-Konflikt: Es wird nach der Regel reduziert, die zuerst in der Bison-Datei aufgeführt wurde. Reduktion-Schiebe-Konflikt: Schieben wird bevorzugt. Zum manuellen Beheben von Konflikten erzeugen des LALR-DEA in der Datei y.output mit Option –v.

85 85 Auflösen der Konflikte mit Bison Zuordnung von Assoziativitäten zu Terminalsymbolen durch folgende Vereinbarungen im Deklarationsabschnitt: %left Morphemartenfolge %right Morphemartenfolge %nonassoc Morphemartenfolge und Prioritäten durch die Reihenfolge der obigen Deklarationen (erste Deklaration hat niedrigste Priorität). Bei Konflikt zwischen zwei Items [A.,a] und [B.a,b] wird reduziert, falls Priorität von höher ist, als Priorität von a oder Priorität von und a ist gleich und Assoziativität von ist links In allen anderen Fällen wird geschoben Priorität und Assoziativität von entsprechen der des am weitesten rechts stehenden Terminalsymbols in. Priorität und Assoziativität von kann explizit festgelegt werden durch Anhängen von %prec Terminalsymbol an, wobei Priorität und Assoziativität von Terminalsymbol im Deklarationsteil festgelegt wurde (dieses Symbol muss sonst nirgends verwendet werden)

86 86 Beispiel: Konflikte aufgelöst %{ #include %} %token DIGIT %left '+' '-' %right '*' '/' % line : expr '\n' {printf("%d\n",$1);} ; expr : expr '+' expr {$$ = $1 + $3;} | expr '-' expr {$$ = $1 - $3;} | expr '*' expr {$$ = $1 * $3;} | expr '/' expr {$$ = $1 / $3;} | DIGIT ; % int yylex() { int c; c = getchar(); if(isdigit(c)) { yylval = c - '0'; return DIGIT; } return c; } Vollständiger QuelltextVollständiger Quelltext Ausführbares ProgrammAusführbares Programm

87 87 Gemeinsame Nutzung von Bison und Flex Die Funktion yyparse() fordert Token durch Aufruf von yylex() an. Flex kann abhängig von der Morphemart Werte unterschiedlicher Datentypen in yylval speichern. Dafür Deklaration der Datentypen im Deklarationsabschnitt durch: %union { C-Datentyp Bezeichner; … }; Zuordnung der Datentypen zu Morphemarten und Metasymbolen der Grammatik im Deklarationsteil durch: %token Tokenbezeichner %type Metasymbol Ausdrücke $$ bzw. $i haben dann den Typ, der dem zugehörigen Symbol zugeordnet wurde. Vollständiges Beispiel (y, l, ast.c, ast.h, main.c, exe, Quelltext)ylast.cast.hmain.cexeQuelltext

88 88 Zusammenfassung LR(k)-Grammatiken Jede starke LL(k)-Grammatik ist auch LR(k)- Grammatik. Jede mit einem deterministischen PDA analysierbare Sprache besitzt eine LR(k)- Grammatik. Jede LR(k)-Grammatik kann in eine bedeutungsäquivalente LR(1)-Grammatik transformiert werden.

89 Ende der syntaktischen Analyse Weiter zur KontextprüfungKontextprüfung


Herunterladen ppt "Vorlesung Compilertechnik Sommersemester 2008 Syntaktische Analyse M. Schölzel."

Ähnliche Präsentationen


Google-Anzeigen