Parser zstępujący — problemy

Transkrypt

Parser zstępujący — problemy
Wykład 8, str. 1
Parser zstępujący — problemy
Lewostronna rekursja w gramatyce powoduje nieskończone obliczenie
Wykład 8, str. 1
Parser zstępujący — problemy
Lewostronna rekursja w gramatyce powoduje nieskończone obliczenie
Przykład: inna
gramatyka —
MhWi ::= hSi hWi+hSi
Wykład 8, str. 1
Parser zstępujący — problemy
Lewostronna rekursja w gramatyce powoduje nieskończone obliczenie
Przykład: inna
gramatyka —
MhWi ::= hSi hWi+hSi
void fW (Boolean* ok, drzewo* t) {
drzewo t1 , t2 ;
fS (ok, &t1 );
if (*ok) *t = &(drzewo zrobione z t1 );
else {
fW (ok, &t1 );
if (*ok) {
if (wejście == ’+’) {
nast leks(); fS (ok, &t2 );
if (*ok) *t = &(drzewo zrobione z t1 , +, t2 );
else blad();
}
else *ok = FALSE;
}
}
}
Wykład 8, str. 1
Parser zstępujący — problemy
Lewostronna rekursja w gramatyce powoduje nieskończone obliczenie
Przykład: inna
gramatyka —
MhWi ::= hSi hWi+hSi
void fW (Boolean* ok, drzewo* t) {
drzewo t1 , t2 ;
fS (ok, &t1 );
if (*ok) *t = &(drzewo zrobione z t1 );
else {
fW (ok, &t1 );
if (*ok) {
if (wejście == ’+’) {
nast leks(); fS (ok, &t2 );
if (*ok) *t = &(drzewo zrobione z t1 , +, t2 );
else blad();
}
else *ok = FALSE;
}
}
}
Wykład 8, str. 2
Leczenie lewostronnej rekursji
Problem: produkcje gramatyczne postaci
hNi ::=
. . . hNi . . . . . .
(czyli lewostronnie rekursywne) prowadzą do zapętlenia parsera zstępującego.
Wykład 8, str. 2
Leczenie lewostronnej rekursji
Problem: produkcje gramatyczne postaci
hNi ::=
. . . hNi . . . . . .
(czyli lewostronnie rekursywne) prowadzą do zapętlenia parsera zstępującego. Takie produkcje potrzebne są dla często spotykanej w składni języków
programowania konstrukcji „ciąg . . . grupowany do lewej”.
Wykład 8, str. 2
Leczenie lewostronnej rekursji
Problem: produkcje gramatyczne postaci
hNi ::=
. . . hNi . . . . . .
(czyli lewostronnie rekursywne) prowadzą do zapętlenia parsera zstępującego. Takie produkcje potrzebne są dla często spotykanej w składni języków
programowania konstrukcji „ciąg . . . grupowany do lewej”.
Przykład:
M
hliczbai ::= hcyfrai hcyfrai hliczbai
— ciąg cyfr grupowany do prawej (nie ma problemu)
345 = 3x45y = 3 · 102 + 45
Wykład 8, str. 2
Leczenie lewostronnej rekursji
Problem: produkcje gramatyczne postaci
hNi ::=
. . . hNi . . . . . .
(czyli lewostronnie rekursywne) prowadzą do zapętlenia parsera zstępującego. Takie produkcje potrzebne są dla często spotykanej w składni języków
programowania konstrukcji „ciąg . . . grupowany do lewej”.
Przykład:
M
hliczbai ::= hcyfrai hcyfrai hliczbai
— ciąg cyfr grupowany do prawej (nie ma problemu)
345 = 3x45y = 3 · 102 + 45
hliczbai
::= hcyfrai hliczbai hcyfrai
— ciąg cyfr grupowany do lewej (jest problem)
345 = x34y5 = 34 · 10 + 5
Wykład 8, str. 3
Leczenie lewostronnej rekursji
Wyjście: do gramatyk wprowadzić specjalną konstrukcję oznaczającą
„ciąg . . . grupowany do lewej”:
Wykład 8, str. 3
Leczenie lewostronnej rekursji
Wyjście: do gramatyk wprowadzić specjalną konstrukcję oznaczającą
„ciąg . . . grupowany do lewej”:
Przykład:
M
Żeby wyrazić „liczba to niepusty ciąg cyfr grupowany do lewej” —
zamiast
hliczbai ::=
piszemy
hcyfrai hliczbai hcyfrai
hliczbai ::= hcyfrai hcyfrai∗
Wykład 8, str. 3
Leczenie lewostronnej rekursji
Wyjście: do gramatyk wprowadzić specjalną konstrukcję oznaczającą
„ciąg . . . grupowany do lewej”:
Przykład:
M
Żeby wyrazić „liczba to niepusty ciąg cyfr grupowany do lewej” —
zamiast
hliczbai ::=
piszemy
hcyfrai hliczbai hcyfrai
hliczbai ::= hcyfrai hcyfrai∗
liczba
- cyfra
-
Wykład 8, str. 4
Leczenie lewostronnej rekursji
Wyjście: do gramatyk wprowadzić specjalną konstrukcję oznaczającą
„ciąg . . . grupowany do lewej”:
Przykład:
M
Żeby wyrazić „wyrażenie to niepusty ciąg składników porozdzielanych plusami i minusami grupowany do lewej” —
zamiast
piszemy
hwyrażeniei + hskładniki
hwyrażeniei ::= hskładniki
hwyrażeniei − hskładniki
nn o
o
hwyrażeniei ::= hskładniki
+ − hskładniki ∗
Wykład 8, str. 4
Leczenie lewostronnej rekursji
Wyjście: do gramatyk wprowadzić specjalną konstrukcję oznaczającą
„ciąg . . . grupowany do lewej”:
Przykład:
M
Żeby wyrazić „wyrażenie to niepusty ciąg składników porozdzielanych plusami i minusami grupowany do lewej” —
zamiast
piszemy
hwyrażeniei + hskładniki
hwyrażeniei ::= hskładniki
hwyrażeniei − hskładniki
nn o
o
hwyrażeniei ::= hskładniki
+ − hskładniki ∗
wyrażenie
- składnik
+ − -
Wykład 8, str. 5
Leczenie lewostronnej rekursji
Gramatyka oryginalna
z lewostronną rekursją:
hWi ::=
hSi ::=
hCi ::=
hLi ::=
hSi hWi + hSi hWi hWi - hSi
hCi hSi * hCi hCi hSi / hCi
hLi ( hWi )
0 1 hLi 0 hLi 1
Gramatyka wyleczona
z iteracją:
hWi ::= hSi
nn
o
o
+ − hSi ∗
hSi ::=
nn o
o
hCi ∗ / hCi ∗
hCi ::=
( hWi ) hLi
n on o
0 1 0 1 ∗
hLi ::=
Wykład 8, str. 5
Leczenie lewostronnej rekursji
Gramatyka oryginalna
z lewostronną rekursją:
hWi ::=
hSi ::=
hCi ::=
hLi ::=
hSi hWi + hSi hWi hWi - hSi
hCi hSi * hCi hCi hSi / hCi
hLi ( hWi )
0 1 hLi 0 hLi 1
Gramatyka wyleczona
z iteracją:
hWi ::= hSi
nn
o
o
+ − hSi ∗
hSi ::=
nn o
o
hCi ∗ / hCi ∗
hCi ::=
hLi ( hWi )
n on o
0 1 0 1 ∗
hLi ::=
Wykład 8, str. 5
Leczenie lewostronnej rekursji
Gramatyka oryginalna
z lewostronną rekursją:
hWi ::=
hSi ::=
hCi ::=
hLi ::=
hSi hWi + hSi hWi hWi - hSi
hCi hSi * hCi hCi hSi / hCi
hLi ( hWi )
0 1 hLi 0 hLi 1
Gramatyka wyleczona
z iteracją:
hWi ::= hSi
nn
o
o
+ − hSi ∗
hSi ::=
nn o
o
hCi ∗ / hCi ∗
hCi ::=
hLi ( hWi )
n on o
0 1 0 1 ∗
hLi ::=
Wykład 8, str. 5
Leczenie lewostronnej rekursji
Gramatyka oryginalna
z lewostronną rekursją:
hWi ::=
hSi ::=
hCi ::=
hLi ::=
hSi hWi + hSi hWi hWi - hSi
hCi hSi * hCi hCi hSi / hCi
hLi ( hWi )
0 1 hLi 0 hLi 1
Gramatyka wyleczona
z iteracją:
hWi ::= hSi
nn
o
o
+ − hSi ∗
hSi ::=
o
nn o
hCi ∗ / hCi ∗
hCi ::=
hLi ( hWi )
n on o
0 1 0 1 ∗
hLi ::=
Wykład 8, str. 5
Leczenie lewostronnej rekursji
Gramatyka oryginalna
z lewostronną rekursją:
hWi ::=
hSi ::=
hCi ::=
hLi ::=
hSi hWi + hSi hWi hWi - hSi
hCi hSi * hCi hCi hSi / hCi
hLi ( hWi )
0 1 hLi 0 hLi 1
Gramatyka wyleczona
z iteracją:
hWi ::= hSi
nn
o
o
+ − hSi ∗
hSi ::=
o
nn o
hCi ∗ / hCi ∗
hCi ::=
hLi ( hWi )
n on o
0 1 0 1 ∗
hLi ::=
Wykład 8, str. 5
Leczenie lewostronnej rekursji
Gramatyka oryginalna
z lewostronną rekursją:
hWi ::=
hSi ::=
hCi ::=
hLi ::=
hSi hWi + hSi hWi hWi - hSi
hCi hSi * hCi hCi hSi / hCi
hLi ( hWi )
0 1 hLi 0 hLi 1
Gramatyka wyleczona
z iteracją:
hWi ::= hSi
nn
o
o
+ − hSi ∗
hSi ::= hCi
nn
o
o
∗ / hCi ∗
hCi ::=
hLi ::=
hLi ( hWi )
n on o
0 1 0 1 ∗
Wykład 8, str. 5
Leczenie lewostronnej rekursji
Gramatyka oryginalna
z lewostronną rekursją:
hWi ::=
hSi ::=
hCi ::=
hLi ::=
hSi hWi + hSi hWi hWi - hSi
hCi hSi * hCi hCi hSi / hCi
hLi ( hWi )
0 1 hLi 0 hLi 1
Gramatyka wyleczona
z iteracją:
hWi ::= hSi
nn
o
o
+ − hSi ∗
hSi ::= hCi
nn
o
o
∗ / hCi ∗
hCi ::=
hLi ::=
( hWi ) hLi
n on o
0 1 0 1 ∗
Wykład 8, str. 5
Leczenie lewostronnej rekursji
Gramatyka oryginalna
z lewostronną rekursją:
hWi ::=
hSi ::=
hCi ::=
hLi ::=
hSi hWi + hSi hWi hWi - hSi
hCi hSi * hCi hCi hSi / hCi
hLi ( hWi )
0 1 hLi 0 hLi 1
Gramatyka wyleczona
z iteracją:
hWi ::= hSi
nn
o
o
+ − hSi ∗
hSi ::= hCi
nn
o
o
∗ / hCi ∗
hCi ::=
hLi ::=
( hWi ) hLi
n on o
0 1 0 1 ∗
Wykład 8, str. 5
Leczenie lewostronnej rekursji
Gramatyka oryginalna
z lewostronną rekursją:
hWi ::=
hSi ::=
hCi ::=
hLi ::=
hSi hWi + hSi hWi hWi - hSi
hCi hSi * hCi hCi hSi / hCi
hLi ( hWi )
0 1 hLi 0 hLi 1
Gramatyka wyleczona
z iteracją:
hWi ::= hSi
nn
o
o
+ − hSi ∗
hSi ::= hCi
nn
o
o
∗ / hCi ∗
hCi ::=
hLi ::=
( hWi ) hLi
n o n o
0 1 0 1 ∗
Wykład 8, str. 6
Leczenie lewostronnej rekursji
hliczbai ::=
hcyfrai hliczbai hcyfrai
// <liczba> ::= <cyfra> | <liczba> <cyfra>
void liczba (int* nr_leksemu, drzewo* drz, Boolean* ok)
{
drzewo drz1;
cyfra (nr_leksemu, drz1, ok);
if (ok)
{ // <cyfra> jest w porzadku
. . .
}
else
{ // <cyfra> nieobecna, probujemy <liczba> <cyfra>
liczba (nr_leksemu, drz1, ok);
. . .
}
}
Wykład 8, str. 7
Leczenie lewostronnej rekursji
hliczbai ::= hcyfrai hcyfrai∗
// <liczba> ::= <cyfra> <cyfra>*
void liczba (int* nr_leksemu, drzewo* drz, Boolean* ok)
{ drzewo drz1;
cyfra (nr_leksemu, drz, ok);
if (ok)
{ // <cyfra> jest w porzadku
. . .
do { cyfra (nr_leksemu, drz1, ok);
if (ok)
{ // jest kolejna <cyfra>
. . .
}
}
while (ok);
ok = TRUE;
}
}
Wykład 8, str. 8
Program „wyleczonego” parsera zstępującego
Wykład 8, str. 8
Program „wyleczonego” parsera zstępującego
• Nieterminalowi hnnni gramatyki odpowiada funkcja o nagłówku
void nnn(drzewo* drz)
której ciało wynika z postaci prawych stron produkcji z hnnni (patrz
niżej).
Wykład 8, str. 8
Program „wyleczonego” parsera zstępującego
• Nieterminalowi hnnni gramatyki odpowiada funkcja o nagłówku
void nnn(drzewo* drz)
której ciało wynika z postaci prawych stron produkcji z hnnni (patrz
niżej).
• Wystąpieniu nieterminala hnnni po prawej stronie produkcji odpowiada wywołanie
nnn(drz); if (ok) ...
Wykład 8, str. 8
Program „wyleczonego” parsera zstępującego
• Nieterminalowi hnnni gramatyki odpowiada funkcja o nagłówku
void nnn(drzewo* drz)
której ciało wynika z postaci prawych stron produkcji z hnnni (patrz
niżej).
• Wystąpieniu nieterminala hnnni po prawej stronie produkcji odpowiada wywołanie
nnn(drz); if (ok) ...
• Wystąpieniu terminala t po prawej stronie produkcji odpowiada
wywołanie
if (leks == ’t’) { nowyleks(); ...
Wykład 8, str. 8
Program „wyleczonego” parsera zstępującego
• Nieterminalowi hnnni gramatyki odpowiada funkcja o nagłówku
void nnn(drzewo* drz)
której ciało wynika z postaci prawych stron produkcji z hnnni (patrz
niżej).
• Wystąpieniu nieterminala hnnni po prawej stronie produkcji odpowiada wywołanie
nnn(drz); if (ok) ...
• Wystąpieniu terminala t po prawej stronie produkcji odpowiada
wywołanie
if (leks == ’t’) { nowyleks(); ...
• Gwiazdce ∗ odpowiada pętla.
Wykład 8, str. 8
Program „wyleczonego” parsera zstępującego
• Nieterminalowi hnnni gramatyki odpowiada funkcja o nagłówku
void nnn(drzewo* drz)
której ciało wynika z postaci prawych stron produkcji z hnnni (patrz
niżej).
• Wystąpieniu nieterminala hnnni po prawej stronie produkcji odpowiada wywołanie
nnn(drz); if (ok) ...
• Wystąpieniu terminala t po prawej stronie produkcji odpowiada
wywołanie
if (leks == ’t’) { nowyleks(); ...
• Gwiazdce ∗ odpowiada pętla.
• Alternatywie odpowiada budowanie drzewa oraz else .
Wykład 8, str. 9
Program „wyleczonego” parsera zstępującego
Przykład:
∗
Mhaaai ::= hccci − haaai + hbbbi
Wykład 8, str. 9
Program „wyleczonego” parsera zstępującego
Przykład:
∗
Mhaaai ::= hccci − haaai + hbbbi
void aaa(drzewo* drz) {
drzewo drz1;
ccc(&drz1);
if (ok) {
/* z drz1 zrobic nowe drz z aaa w korzeniu */
while (leks == ’-’ || leks == ’+’) {
if (leks == ’-’) {
nowyleks(); aaa(&drz1);
if (ok) /* z drz , - i *drz1 zrobić nowe drz */
else blad(’po - nie wystapil aaa’);
}
else if (leks == ’+’) {
nowyleks(); bbb(&drz1);
if (ok) /* z drz , + i *drz1 zrobić nowe drz */
else blad(’po + nie wystapil bbb’);
} } } }
Wykład 8, str. 10
Parser zstępujący bez nawrotów
Przykład:
hwagai
hmiarai ::= hodległośći
M hodległośći ::=
hwagai ::=
n
o n
0 . . . 9 0 . . . n
o n
0 ... 9 0 ...
hmiarai
⇒
hodległośći
hmiarai
⇒
hwagai
⇒∗
⇒∗
9 ∗m
o
9 ∗ kg
o
11111m
11111kg
Wykład 8, str. 10
Parser zstępujący bez nawrotów
Przykład:
hwagai
hmiarai ::= hodległośći
M hodległośći ::=
hwagai ::=
n
o n
0 . . . 9 0 . . . n
o n
0 ... 9 0 ...
hmiarai
⇒
hodległośći
hmiarai
⇒
hwagai
⇒∗
⇒∗
9 ∗m
o
9 ∗ kg
o
11111m
11111kg
Do którego nieterminala redukować? — nie da się postanowić na podstawie
pierwszej cyfry, bo nie wiadomo jeszcze, czy na końcu będzie m czy kg.
Wykład 8, str. 10
Parser zstępujący bez nawrotów
Przykład:
hwagai
hmiarai ::= hodległośći
M hodległośći ::=
hwagai ::=
n
o n
0 . . . 9 0 . . . n
o n
0 ... 9 0 ...
hmiarai
⇒
hodległośći
hmiarai
⇒
hwagai
⇒∗
⇒∗
9 ∗m
o
9 ∗ kg
o
11111m
11111kg
Do którego nieterminala redukować? — nie da się postanowić na podstawie
pierwszej cyfry, bo nie wiadomo jeszcze, czy na końcu będzie m czy kg.
Parsery zstępujące nadają się nie do wszystkich
gramatyk bezkontekstowych;
nadają się tylko do t.zw. gramatyk LL(1).

Podobne dokumenty