You are on page 1of 11

LR parser

Arhitektura LR parsera

Slika 1. Arhitekture bottom-up parsera.

Parser se sastoji od:

 ulaznog bafera
 steka koji čuva stanja
 tabele prelazaka (goto table) koja nam govori koje je novo stanje
 tabele akcija (action table) koj nam govori koju kaciju treba uraditi za dato tekuće stanje i
dati terminalni simbol na ulazu

Algoritam parsiranja

LR parser čita ulaz slijeva udesno ali treba da napravi desnu derivaciju, pa zbog toga koristi
redukciju umjesto derivacije. Algoritam kreira "leftmost redukciju" ulaznog niza, pa je krajnji
rezultat obrnuta desna derivacija.

Algoritam:

1. Stek se inicijalizuje sa stanjem [0]. Tekuće stanje je uvijek ono koje je na vrhu steka.
2. Za dato tekuće stanje i dati ulazni simbol provjeravamo tabelu akcija. Postoje 4 mogućnosti:
o shift sn:
 tekući simbol se uklanja iz ulaznog niza
 stanje n se stavlja na stek (operacija push) i postaje tekuće stanje
o reduce rm:
 broj m se upisuje u izlazni tok (ovo je samo radi evidencije)
 za svaki simbol sa desne strane pravila m gramatike uklanjamo po jedan
simbol sa steka (operacija pop)
 za stanje koje je na vrhu steka i lijevu stranu pravila m gramatike pogledamo
odgovarajuće polje u tabeli prelazaka i stanje iz tog polja upišemo na stek
o acc - string je prihvaćen (accepted)
o nema akcija (prazno polje) - prijavljujemo sintaksnu grešku
3. Ponavljamo korak 2 sve dok string ne bude prihvaćen ili dok se prijavi greška

Primjer

Data je sljedeća gramatika:

(1) E → E * B
(2) E → E + B
(3) E → B
(4) B → 0
(5) B → 1

Parsiramo sljedeći ulazni niz:

1+1

Tabele akcija i prelazaka

action goto
state * + 0 1 $   E B
0     s1 s2     3 4
1 r4 r4 r4 r4 r4    
2 r5 r5 r5 r5 r5    
3 s5 s6   acc      
4 r3 r3 r3 r3 r3      
5     s1 s2     7
6     s1 s2     8
7 r1 r1 r1 r1 r1      
8 r2 r2 r2 r2 r2      

Redovi tabela označeni su stanjima parsera. Kolone tabele akcija terminalni simboli (uključujući
specijalni simbol $ koji označava kraj ulaznog niza). Akcije u toj tabeli mogu biti:

 shift, koji zapisujemo kao 'sn', što znači da je sljedeće stanje n


 reduce, koji zapisujemo kao 'rm', što znači da radimo redukciju pravila m
 accept, koji zapisujemo kao 'acc', što znači da parser prihvata ulazni niz.

Kolone tabele prelazaka su neterminalni simboli gramatike a polja te tabele sadrže stanja parsera.
Stanje u toj tabeli znači da je ono sljedeće stanje parsera kada se prepozna određeni netreminalni
simbol.

Procedura parsiranja

State Input Stream Output Stream Stack Next Action


0 1+1$ [0] Shift 2
2 +1$ [0,2] Reduce 5
4 +1$ 5 [0,4] Reduce 3
3 +1$ 5,3 [0,3] Shift 6
6 1$ 5,3 [0,3,6] Shift 2
2 $ 5,3 [0,3,6,2] Reduce 5
8 $ 5,3,5 [0,3,6,8] Reduce 2
3 $ 5,3,5,2 [0,3] Accept

Parser počinje rad sa stekom koji sadrži samo početno stanje ('0'):

[0]

Prvi simbol u ulaznom nizu je '1'. U polju Action[0,1] () je tekuće stanje a 1 je tekući simbol) stoji
s2, tj. akcija je shift 2, p se stanje 2 stavlja na stek i prelazimo na sljedeći ulazni simbol (tj. +).
Rezultujući stek je

[0 '1' 2]

gdje je 2 na vrhu steka. Zbog lakšeg praćenja postupka pokazujemo i simbol (npr. '1', B) koji je
uzrok prelaska u sljedeće stanje, iako formalno on nije dio steka.

Posmatramo polje Action[2,+] u kome je r5, tj. redukcija pravila 5. Intuitivno, to yna;I da je parser
prepoynao desnu stranu produkcije 5, što se zaista i desilo. Upisujemo 5 u izlazni niz, uklanjamo
jedno stanje sa steka (jer sa desne strane pravila 5 imamo samo jedan simbol). Sada je satnje 0 na
vrhu steka pa provjeravamo polje Goto[0,B], jer je B desna strana pravila 5. Kako u polju Goto[0,B]
upisano 4, na stek stavljamo stanje 4. Rezultujući stek je:

[0 B 4]

Sada provjeravamo polje Action[4,+], u kome piše r3. Upisujemo 3 u izlazni niz i uklanjamo jedno
stanje sa steka (jer desna strana pravila 5 ima jedan simbol). Sada je na vrhu steka stanje 0, pa
provjeravamo polje Goto[0,E], jer je E desna strana pravila 3. U tom polju je stanje 3, pa to stanje
stavljamo na stek i ono postaje novo tekuće stanje.

[0 E 3]

Provjeravamo polje Action[3,’+’] u kojem je s6, pa stavljamo stanje 6 na stek. Stek ima sljedeći
izgled:

[0 E 3 '+' 6]

Primjetite da ovako napisan stek možete posmatrati kao istorijat rada konačnog automata koji je
“pročitao” neterminal E a zatim terminal ‘+’. Tabela prelazaka tog automata definisina je shift-
akcijama tabele akcija i goto-akcijama tabele prelazaka.

Sljedeći simbol na ulazu je '1', pa posmatramo polje Action[6,’1’]=s2, što znači da vršimo shift tj.
stanje 2 stavljamo na vrh steka i prelazimo na sljedeći simbol u ulaznom nizu:

[0 E 3 '+' 6 '1' 2]
Kako je Action[2,$]=r5, vršimo redukcija pravila 5 tj. uklanjamo 2 sa steka, Goto[6,B]=8,a
postavljamo 8 na vrh steka i dobijamo:

[0 E 3 '+' 6 B 8]

U stanju 8 uvijek vršimo redukciju (Action[8,$]=r2). Kako desna strana produkcije 2 ima tri
simbola (dva neterminalna i jedan treminalni), sa steka uklanjamo tri stanja tj. 8, 6 i 3. Sda je na
vrhu steka 0, pa posmatramo polje Goto[0,E] jer je E lijeva strana pravila 2. Kako je Goto[0,E]=3,
na stek stavljamo stanje 3, pa sada stek ima izgled:

[0 E 3]

Kona;no, čitamo '$' iz ulaznog niza a koako je Action[3,$]=acc, ulazni string se prihvata. Izlazni
string nam pokazuje redosljed primjene pravila gramatike obrnut desnoj derivaciji ulaznog stringa.

Konstruisanje tabele LR(0) parsera


Konstrukcija se zasniva na pojmu LR(0) ajtema ili LR(0) elementa – pravila gramatike sa ta;kom na
proizvoljnoj poziciji sa desne strane. Npr. za pravilo E → E + B imamo sljedeća 4 LR(0) ajtema:

E→•E+B
E→E•+B
E→E+•B
E→E+B•

Pravila oblika A → ε imaju samo jedan ajtem A → •. Ovi ajtemi označavaju stanja parsera. Npr.
ajtem E → E • + B, označava da je parser prepoznao string koji odgovara neterminalnom simbolu E
i očekuje da pročita simbol '+' a zatim i ostatak stringa koji bi trebalo da odgovara neterminalnom
simbolu B.

Skupovi ajtema

Najčešće nije moguće opisati stanje parsera samo jednim ajtemom jer nije moguće unaprijed znati
koje će pravilo biti primjenjeno za redukciju. Npr. ako postoji i pravilo E → E * B, tada oba ajtema
E → E • + B i E → E • * B mogu biti primjenjena pošto se pročita string koji odgovara neterminalu
E. Zbog toga će ova dva ajtema biti u istom stanju tj. skupu { E → E • + B, E → E • * B }.

Zatvorenje skupa ajtema

Ako u skup ajtema postoji ajtem oblika A → v • Bw i ako u gramatici postoji pravilo oblika B → w'
tada i ajtem B → • w' treba dodati u skup ajtema. Dodavanje ajtema nastaviti sve dok je to moguće.
Na taj način dobija se zatvorenje skupa ajtema (slično tranzitivnom zatvorenju grafa).

Proširena gramatika

Prije nego što počnemo da određujemo skupove ajteme (tj. stanja parsera), u gramatiku dodajemo
novo pravilo

(0) S → E

gdje je S novi početni simbol gramatike a E je stari početni simbol gramatike.


Nadgrađena gramatika ima oblik:

(0) S → E
(1) E → E * B
(2) E → E + B
(3) E → B
(4) B → 0
(5) B → 1

Konstrukcija tabele
U skup S0 dodajemo ajtem S → • E i tražimo njegovo zatvorenje:

S0 : S → • E

Dodajemo E → • E * B , E → • E + B i E → • B, jer se u ajtemu S → • E simbol • nalazi ispred


neterminalnog simbola E.
Dodajemo i B → • 0 i B → • 1 , jer se u ajtemu E → • B simbol • nalazi ispred neterminalnog
simbola B.

S0 : S → • E
E→•E*B
E→•E+B
E → • B,
B→•0
B→•1

Počevši sa stanjem S0, odredićemo skup prelasaka iz ovog stanja u druga stanja. Posmatramo sve
simbole (terminalne i neterminalne) koji se nalaze desno od simbola •. Procedura za prelaske je
sljedeća:

1. Za svaki ajtem iz skupa S, odrediti simbole x ipred kojih se nalazi simbol •


2. Za svaki ajtem iz S, pomjeriti simbol • desno od simbola x.
3. Odrediti zatvorenje dobijenog skupa ajtema.

Za terminal '0' odredimo Prelazak(S0, ‘0’) B → 0 • (simbol • nalazi se samo ispred simbola 0 u
petom ajtemu u skupu S0). Zatim odredimo zatvorenje ajtema B → 0 • , što daje skup S1:

S1
B→0•

Na isti način za terminal '1' dobijamo:

S2
B→1•

Za neterminal E imamo Prelazak(S0,E) daje S → E • , E → E • * B , E → E • + B. Zatvorenje


ovog skupa daje

S3
S→E•
E→E•*B
E→E•+B

Na isti način za neterminal B dobijamo:

S4
E→B•

Primjetite da u ovom slučaju zatvorenje nije dodalo nove ajteme. Nastavaljamo ovak postupak sve
dok moženo dodavati nove skupove ajtema. Z skupove S1, S2 i S4 nema prelaza, jer se simbol •
nalazi na kraju (krajnji desni simbol). Za skup S3 moguće je napraviti prelaske na simbole '*' i '+'.
Tako za simbol '*' dobijamo:

S5
E→E*•B
B → • 0 /* dodato zbog E → E * • B */
B → • 1 /* dodato zbog E → E * • B */

Za simbol '+' imamo:

S6
E→E+•B
B → • 0 /* dodato zbog E → E + • B */
B → • 1 /* dodato zbog E → E + • B */

Iz skupa S5 možemo preći na terminale '0' i '1' i na neterminal B. Lako se vidi da je Prelazak(S5,
'0' ) = S1 i Prelazak(S5, '1' ) = S2. Za neterminal B imamo Prelazak(S5, B):

S7
E→E*B•

Iz skupa S6 možemo preći na terminale '0' i '1' i na neterminal B. Lako se vidi da je Prelazak(S6,
'0')=S1 i Prelazak(S6, '1' ) = S2. Za neterminal B imamo Prelazak(S6, B):

S8
E→E+B•

Iz skupova S7 i S8 nema prelazaka.

Konačna tabela prelazaka ima sljedeći oblik:

Skup * + 0 1 E B

0 1 2 3 4

3 5 6

5 1 2 7
6 1 2 8

Konstrukcija tabele akcija i prelazaka

Iz ove tabele prelazaka:

1. Kolone neterminalnih simbola kopiraju se u tabelu prelazaka (Goto tabela)


2. Kolone terminalnih simbola kopiraju se u tabelu akcija kao shift-akcije
3. Dodaje se kolona za simbol '$' (end of input) i u njoj se upisuje acc za svaki sklup ajtema
koji sadrži S → E •.
4. Ako skup ajtema i sadrži ajtem oblika A → w • i A → w je pravilo m (m > 0) u gramatici,
tada u redu i upisujemo akciju rm.

Konflikti

Moguća su dva tipa konflikata: shift-reduce conflict i reduce-reduce conflict. Ako se to dogodi
kažemo da grmatika nije LR(0) gramatika.

Primjer gramatike koja ima shift-reduce konflikt:

(1) E → 1 E
(2) E → 1

Kada tražimo skupove ajtema dobijamo:

S1
E→1•E
E→1•
E→•1E
E→•1

Crvenom bojom označeno je mjesto konflikta.

Primjer gramatike koja ima reduce -reduce konflikt:

(1) E → A 1
(2) E → B 2
(3) A → 1
(4) B → 1

Kada tražimo skupove ajtema dobijamo:

S1
A→1•
B→1•
LR(0) primjer
Primjer gramatike (u Bison notaciji):
0) S: stmt
1) stmt: ID ':=' expr
2) expr: expr '+' ID
3) expr: expr '-' ID
4) expr: ID

Kreiranje skupova ajtema


Stanje 0
0) S: • stmt
1) stmt: • ID ':=' expr
GOTO 2 on stmt
SHIFT 1 on ID

Stanje 1
1) stmt: ID • ':=' expr
SHIFT 3 on ':='

Stanje 2
0) S: stmt •
SHIFT 4 on

Stanje 3
1) stmt: ID ':=' • expr
2) expr: • expr '+' ID
3) expr: • expr '-' ID
4) expr: • ID
GOTO 6 on expr
SHIFT 5 on ID

Stanje 4
0) $S: stmt •
Stanje 5
4) expr: ID •
Stanje 6
1) stmt: ID ':=' expr •
2) expr: expr • '+' ID
3) expr: expr • '-' ID
SHIFT 7 on '+'
SHIFT 8 on '-'

Stanje 7
2) expr: expr '+' • ID
SHIFT 9 on ID

Stanje 8
3) expr: expr '-' • ID
SHIFT 10 on ID

Stanje 9
2) expr: expr '+' ID •
Stanje 10
3) expr: expr '-' ID •

Tabele parsera
Tabele parsera
  Akcije Prelasci
  ID ':=' '+' '-' <EOF> stmt expr
0 s1         g2  
1   s3          
2         s4    
3 s5           g6
4 acc acc acc acc acc    
5 r4 r4 r4 r4 r4    
6 r1 r1 s7 s8 r1    
7 s9            
8 s10            
9 r2 r2 r2 r2 r2    
10 r3 r3 r3 r3 r3    

Primjer rada parsera

Stek Preostali ulaz Akcija


0/$S a:= b + c - d s1
0/$S 1/a := b + c - d s3
0/$S 1/a 3/:= b + c - d s5
0/$S 1/a 3/:= 5/b + c - d r4
0/$S 1/a 3/:= + c - d g6 on expr
0/$S 1/a 3/:= 6/expr + c - d s7
0/$S 1/a 3/:= 6/expr 7/+ c - d s9
0/$S 1/a 3/:= 6/expr 7/+ 9/c - d r2
0/$S 1/a 3/:= - d g6 on expr
0/$S 1/a 3/:= 6/expr - d s8
0/$S 1/a 3/:= 6/expr 8/- d s10
0/$S 1/a 3/:= 6/expr 8/- 10/d <EOF> r3
0/$S 1/a 3/:= <EOF> g6 on expr
0/$S 1/a 3/:= 6/expr <EOF> r1
0/$S <EOF> g2 on stmt
0/$S 2/stmt <EOF> s4
0/$S 2/stmt 4/<EOF>   accept
SLR parser
Gramatika koje se može parsirati SLR parserem ali ne i LR(0) parserom (već je dodato novo
početno stanje S):

(0) S → E
(1) E → 1 E
(2) E → 1

Konstrukcijom skupova ajtema dobijamo:

S0
S→•E
E→•1E
E→•1
S1
E→1•E
E→1•
E→•1E
E→•1
S2
S→E•
S3
E→1E•

Tabele akcija i prelazaka LR(0) parsera:

action goto
stanje 1 $ E
0 s1 2
1 s1/r2 r2 3
2 acc
3 r1 r1

Postoji shift-reduce konflikt za stanje 1 i terminalni simbol '1'.

Konstrukcija tabele akcija i prelazaka

Iz ove tabele prelazaka:

1. Kolone neterminalnih simbola kopiraju se u tabelu prelazaka (Goto tabela)


2. Kolone terminalnih simbola kopiraju se u tabelu akcija kao shift-akcije
3. Dodaje se kolona za simbol '$' (end of input) i u njoj se upisuje acc za svaki sklup ajtema
koji sadrži S → E •.
4. Ako skup ajtema i sadrži ajtem oblika A → w • i A → w je pravilo m (m > 0) u gramatici,
tada u redu i upisujemo akciju rm za svaki terminalni simbol iz skupa Follow(A).

Žutom bojom označena je razlika u odnosu na LR(0) tabelu.


Kako je Follow(E) ={$}, to će tabela SLR parsera imati sljedeći oblik:

action goto
state 1 $ E
0 s1 2
1 s1 r2 3
2 acc
3 r1

Sada ne postoji konflikt.

You might also like