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

Podobne dokumenty