WEAIiE-6-Parsery-LL1
Transkrypt
WEAIiE-6-Parsery-LL1
Parsery LL(1) Teoria kompilacji Dr inŜ. Janusz Majewski Katedra Informatyki Zadanie analizy generacyjnej (zstępującej, top-down) Odtworzenie wywodu lewostronnego metodą top-down Istota gramatyki i parsera LL(k) pierwszy od lewej nieterminal Jeśli odpowiedź na kaŜdorazowe pytanie: „Którą produkcję A → β zastosować?” – jest zawsze jednoznaczna, gramatyka jest klasy LL(k) } juŜ wyprowadzone analizowany łańcuch podglądana część wejścia (na ogół k=1) Nierekurencyjny analizator top-down Konfiguracja parsera LL Konfiguracja: (ZXXZY, bbb$, 3122) stos nieprzeczytana część wejścia wyjście Parser LL(k) G=<V, Σ, P, S> – gramatyka opisująca składnię A = <Σ, Γ, Z0, ∆, M, $> Σ – zbiór symboli terminalnych Γ – zbiór symboli stosowych Γ=V∪Σ Z0 = S – symbol początkowy stosu oraz gramatyki ∆ – alfabet wyjściowy: zbiór numerów produkcji M – tablica sterująca parsera M : V × ( Σ ∪ {$} ) * (V ∪ Σ )* × ∆ ֏ ERROR $ - ogranicznik końca słowa wejściowego Parser LL(k) Konfiguracja parsera: (α Y , x, π ) αY - zawartość stosu Y - wierzchołek stosu x - nieprzeczytana część wejścia π - łańcuch numerów produkcji na wyjściu Parser podgląda na wejściu u = FIRSTK ( x) Działanie parsera LL(k) • Automat widzi wierzchołek stosu i k symboli wejściowych. • Tablicę M wykorzystuje się, gdy na wierzchołku stosu znajduje się nieterminal. • Konfiguracja początkowa: (S, ω$, ε) , przy czym: ω – analizowane słowo; S – symbol początkowy gramatyki Działanie parsera LL(k) Konfiguracja parsera: (αY , x, π ) zaś u = FIRSTk ( x ) (1) if Y ∈ Σ then /*pop*/ if Y = a then (αa, aγ , π ) ֏ (α , γ , π ) else ERROR; (2) if Y ∈ V then if M (Y , u ) = (β , i ) then (αY , x, π ) ֏ (αβ /* wyprowadzenie */ ) , x, πi /* Y→β jest produkcją o numerze i */ else ERROR; (3) R if (Y = ε ) then if x = $ then ACCEPT else ERROR; Działanie parsera LL(k) Konfiguracja końcowa akceptująca: ( ε , $, π ) π - ciąg numerów produkcji opisujący rozkład lewostronny słowa ω ∈ T * w gramatyce G. Wówczas ω ∈ L (G ) Krok „pop” Krok „pop” Krok „wyprowadzenia” A→Bb Krok „wyprowadzenia” A→Bb Konstrukcja tablicy sterującej M Konstrukcja tablicy M dla parsera LL(1) We: G = N , T , P, Z ∈ G BK G – jest klasy LL(1) * Wy: tablica M : V × ( Σ ∪ {$} ) ֏ (V ∪ Σ ) × ∆ ERROR gdzie: ∆ - zbiór numerów produkcji w gramatyce G Konstrukcja tablicy sterującej M for ( A → β ) ∈ P and A → β - produkcja numer i do begin (1) for kaŜde a ∈ FIRST1 (β ) : a ≠ ε do M ( A, a ) := (β , i ) ; (2) if ε ∈ FIRST1 (β ) then for kaŜde b ∈ FOLLOW1 ( A) do M ( A, b ) := (β , i ) ; end; for kaŜde niezdefiniowane M ( A, a ) do M ( A, a ) := ERROR ; Projektowanie tablicy parsera LL Mając przekształconą gramatykę języka oraz wyznaczone (dla symboli nieterminalnych tej gramatyki) zbiory FIRST1 i FOLLOW1 moŜemy przystąpić do projektowania tablicy parsera LL. 1) 2) 3) 4) 5) 6) 7) 8) E → TE’ E’ → +TE’ E’ → ε T → FT’ T’ → *FT’ T’ → ε F → (E) F → id Tablica parsera FIRST FOLLOW E (, id $, ) E’ +, ε $, ) T (, id +, $, ) T’ *, ε +, $, ) F (, id *, +, $, ) id + * ( ) 1) 2) 3) 4) 5) 6) 7) 8) $ E → TE’ E’ → +TE’ E’ → ε T → FT’ T’ → *FT’ T’ → ε F → (E) F → id Tablica parsera FOLLOW id E (, id $, ) E→TE’ (1) E’ +, ε $, ) FIRST T (, id +, $, ) T’ *, ε +, $, ) F (, id *, +, $, ) + * ( ) $ E→TE’ (1) 1) 2) 3) 4) 5) 6) 7) 8) E → TE’ E’ → +TE’ E’ → ε T → FT’ T’ → *FT’ T’ → ε F → (E) F → id Tablica parsera FOLLOW id E (, id $, ) E→TE’ (1) E→TE’ (1) E’ +, ε $, ) T→FT’ (4) T→FT’ 2) E’ → +TE’ (4) FIRST T (, id +, $, ) T’ *, ε +, $, ) F (, id *, +, $, ) + * ( ) $ 1) E → TE’ 3) 4) 5) 6) 7) 8) E’ → ε T → FT’ T’ → *FT’ T’ → ε F → (E) F → id Tablica parsera FIRST FOLLOW id + * ( ) E (, id $, ) E→TE’ (1) E→TE’ (1) E’ +, ε $, ) T (, id +, $, ) T→FT’ (4) T→FT’ (4) T’ *, ε +, $, ) F (, id *, +, $, ) F→id (8) F→(E) (7) 1) 2) 3) 4) 5) 6) 7) 8) $ E → TE’ E’ → +TE’ E’ → ε T → FT’ T’ → *FT’ T’ → ε F → (E) F → id Tablica parsera FOLLOW id E (, id $, ) E→TE’ (1) E→TE’ (1) E’ +, ε $, ) T→FT’ (4) T→FT’ 2) E’ → +TE’ (4) 3) E’ → ε FIRST + * ( ) $ 1) E → TE’ T (, id +, $, ) *, ε +, $, ) T’ F (, id *, +, $, ) T’→*FT’ (5) F→id (8) 4) 5) 6) F→(E) 7) (7) 8) T → FT’ T’ → *FT’ T’ → ε F → (E) F → id Tablica parsera FOLLOW id E (, id $, ) E→TE’ (1) E→TE’ (1) E’ +, ε $, ) T→FT’ (4) T→FT’ (4) FIRST T (, id +, $, ) T’ *, ε +, $, ) F (, id *, +, $, ) + T’→εε (6) * ( T’→*FT’ (5) F→id (8) ) $ T’→εε (6) T’→εε (6) ) $ E’→εε (3) E’→εε (3) T’→ε (6) T’→ε (6) F→(E) (7) Tablica parsera FOLLOW id E (, id $, ) E→TE’ (1) E’ +, ε $, ) FIRST T (, id +, $, ) T’ *, ε +, $, ) F (, id *, +, $, ) + E’→+TE’ (2) T→FT’ (4) T’→ε (6) F→id (8) * 1) 2) 3) 4) 5) 6) 7) 8) ( E → TE’ E’ → +TE’ E’ → ε T → FT’ T’ → *FT’ T’ → ε F → (E) F → id T’→*FT’ (5) F→(E) (7) Tablica parsera FOLLOW id E (, id $, ) E→TE’ (1) E’ +, ε $, ) FIRST T (, id +, $, ) T’ *, ε +, $, ) F (, id *, +, $, ) + * ( $ E’→ε (3) E’→ε (3) T’→ε (6) T’→ε (6) E→TE’ (1) E’→+TE’ (2) T→FT’ (4) T→FT’ (4) T’→ε (6) F→id (8) ) T’→*FT’ (5) F→(E) (7) Symulacja działania parsera LL Stos E E’T E’T’F E’T’id E’T’ E’ E’T+ E’T E’T’F E’T’id E’T’ E’ ε Wejście id+id$ id+id$ id+id$ id+id$ +id$ +id$ +id$ id$ id$ id$ $ $ $ akceptacja Wyjście ε 1 14 148 148 1486 14862 14862 148624 1486248 1486248 14862486 148624863 Metoda zejść rekurencyjnych (1) Dla kaŜdego symbolu nieterminalnego gramatyki budujemy procedurę (funkcję) rekurencyjną. Z programu nadrzędnego (głównego) wywoływana jest procedura (funkcja) dla symbolu początkowego gramatyki. (2) Wewnątrz procedury (funkcji) dokonuje się wyboru produkcji na podstawie tokenu podglądanego na wejściu (lookahead). Po dokonaniu wyboru zapewnia się zanotowanie numeru wybranej produkcji (raport). Następnie kaŜdy symbol nieterminalny prawej strony produkcji przekształca się w wywołanie odpowiadającej mu procedury (funkcji), kaŜdy symbol terminalny prowadzi do wywołania operacji „match”, która sprawdza obecność tego symbolu na wejściu. W przypadku zgodności czyta następny token, w przeciwnym razie sygnalizuje błąd. Symbole z prawej strony produkcji znajdują swoje odpowiedniki w procedurze w tej kolejności, w jakiej są one umieszczone w prawej stronie produkcji. NiemoŜność dokonania wyboru produkcji wewnątrz procedury sygnalizowana jest błędem. Metoda zejść rekurencyjnych E id (1) E → TE1 E1 T (4)T → FT1 T1 F + * ( (1) E → TE1 (2) E1 → +TE1 $ (3) E1 → ε (3) E1 → ε (6)T1 → ε (6)T1 → ε (4)T → FT1 (6)T1 → ε (8) F → id ) (5)T1 → *FT1 ( 7) F → ( E ) E() { if (lookahead == ID || lookahead == ’(’) { raport(1); T(); E1(); } else error(); } Metoda zejść rekurencyjnych E id (1) E → TE1 E1 T ( 4)T → FT1 T1 F + * ( (1) E → TE1 ( 2) E1 → +TE1 ) $ (3) E1 → ε (3) E1 → ε (6)T1 → ε (6)T1 → ε ( 4)T → FT1 (6)T1 → ε (5)T1 → *FT1 (8) F → id ( 7) F → ( E ) E1() { if(lookahead == ’+’) { raport(2); match(’+’); T(); E1(); } else if (lookahead == ’)’ || lookahead == ’$’) raport(3); else error(); } Metoda zejść rekurencyjnych E id (1) E → TE1 E1 T (4)T → FT1 T1 F (8) F → id + * ( (1) E → TE1 (2) E1 → +TE1 ) $ (3) E1 → ε (3) E1 → ε (6)T1 → ε (6)T1 → ε (4)T → FT1 (6)T1 → ε (5)T1 → *FT1 (7 ) F → ( E ) T() { if(lookahead == ID || lookahead == ’(’) { raport(4); F(); T1(); } else error(); } Metoda zejść rekurencyjnych E id (1) E → TE1 E1 T (4)T → FT1 + * ( (1) E → TE1 (2) E1 → +TE1 $ (3) E1 → ε (3) E1 → ε (6)T1 → ε (6)T1 → ε (4)T → FT1 (6)T1 → ε T1 F ) (5)T1 → *FT1 (8) F → id (7 ) F → ( E ) T1() { if (lookahead == ’*’) { raport(5); match(’*’); F(); T1(); } else if(lookahead == ’+’ || lookahead == ’)’ || lookahead == ’$’) raport(6); else error(); } Metoda zejść rekurencyjnych E id (1) E → TE1 E1 T ( 4)T → FT1 T1 F + * ( (1) E → TE1 ( 2) E1 → +TE1 $ (3) E1 → ε (3) E1 → ε (6)T1 → ε (6)T1 → ε ( 4)T → FT1 (6)T1 → ε (8) F → id ) (5)T1 → *FT1 (7 ) F → ( E ) F() { if(lookahead == ID) { raport(8); match(ID); } else if(lookahead == ’(’) { raport(7); match(’(’); E(); match(’)’); } else error(); } Metoda zejść rekurencyjnych error() { ....... } match(t) int t; { if(lookahead == t) lookahead=gettoken(); else error(); } raport() { ....... } gettoken() { ....... } int lookahead; main() { lookahead=gettoken(); E(); /*wywołanie procedury dla symbolu początkowego gramatyki*/ } Metoda zejść rekurencyjnych Wejście: id + id * id