Professional Documents
Culture Documents
Preda Van Japp 1
Preda Van Japp 1
i f ( x ==3 ) skener (IF,-) (LP,-) (ID, “x”) (EQ,-) (NUM,3) ... Deterministički konačni automati
niz znakova niz tokena
(klasa, vrednost)
1
Graf prelaza konačnog automata Algoritam rada DKA
•Algoritam rada automata:
0
tekuće_stanje := St; { St – startno stanje}
1
0 0 tekući_ulaz := prvi simbol ulazne sekvence;
A D B •Čvorovi: stanja while not (kraj ulazne sekvence)
•Grane: prelazi tekuće_stanje := ( tekuće_stanje, tekući ulaz );
1 0
1
1 0
tekući_ulaz := sledeći znak ulazne sekvence;
•Stanja prihvatanja: end while;
1 1 poduplano if ( tekuće_stanje P ) {P – skup stanja prihvatanja}
F C E then ulazna sekvenca se prihvata;
0 else ulazna sekvenca se ne prihvata;
endif;
Programski prevodioci © 2004-2009 Dragan Bojić 7 Programski prevodioci © 2004-2009 Dragan Bojić 8
Programski prevodioci © 2004-2009 Dragan Bojić 9 Programski prevodioci © 2004-2009 Dragan Bojić 10
a b b
Specifičnosti automata:
S0 ima prelaz za (tzv. prazna sekvenca, automat može da
preĎe iz s0 u s1 a da pri tom ne konzumira nijedan simbol
sa ulaza)
S1 ima dva različita prelaza za a
U pitanju je nedeterministički konačni automat (NKA)
2
Nedeterministički konačni automat Rad datog NKA za ulaz abb
Opisan je ureĎenom petorkom (S, U, , St, P) gde: a,b
Programski prevodioci © 2004-2009 Dragan Bojić 17 Programski prevodioci © 2004-2009 Dragan Bojić 18
3
NKA DKA
Algoritam koristi istu ideju kao algoritam rada NKA, samo
što ne posmatra jednu ulaznu sekvencu, nego sistematski
odreĎuje tabelu prelaza DKA.
Regularni izrazi
Alternativni formalizam za opis jezika
Regularni izrazi opisuju tačno isti skup
Regularni izrazi
jezika kao konačni automati:
Za svaki regularni izraz može se naći
konačni automat koji opisuje isti jezik kao
taj izraz
Za svaki konačni automat može se naći
regularni izraz koji opisuje isti jezik kao taj
automat
4
Definicija regularnog izraza Definicija regularnog izraza (2)
Regularni izraz s opisuje regularni skup nizova složeniji regularni izrazi dobijaju se od regularnih izraza A i
B primenom operacija:
znakova L(s).
Opcije A?, L(A?) = L(A) {}
Regularni izrazi definišu se na sledeći način: unije A|B, L(A|B) = L(A) L(B) = {x | x A ili x B}
je regularan izraz koji opisuje prazan skup L()=. konkatenacije (nadovezivanja) AB ili AB
L(AB)=L(A) x L(B)={xy | x A, y B}
je regularan izraz koji opisuje skup {} L()={}. Konvencija:
A A
n
...
A A A 0 {ε}
(sekvenca dužine nula znakova, tzv. prazna sekvenca)
zvezdastog zatvaranja A*
n
niz znakova n je regularni izraz koji opisuje skup {n}
A*=A0|A1|A2|A3|… (beskonačan broj članova)
L(n)={n}.
pozitivnog zatvaranja A+
A+ = A1|A2|A3|…
Programski prevodioci © 2004-2009 Dragan Bojić 25 Programski prevodioci © 2004-2009 Dragan Bojić 26
Programski prevodioci © 2004-2009 Dragan Bojić 29 Programski prevodioci © 2004-2009 Dragan Bojić 30
5
Primer primene Tompsonovog algoritma 2 Automatizacija konstrukcije skenera
4. a ( b | c )* Formalna metodologija dobijanja programskog
S4
b
S5
koda na osnovu specifikacije jezika:
S0
a
S1
S2
S3 S8
S9 1 Napisati RE za zadati ulazni jezik
S6
c
S7 2 Konstruisati NKA za dati RE Tompsonovim
alg.
3 Konstruisati DKA ekvivalentan dobijenom NKA
Posle konverzije u DKA i minimizacije broja stanja: 4 (Po potrebi) odrediti minimalan DKA
b|c
5 Implementirati DKA iz tačke 4. programom
a
S0 S1
Generatori skenera rade po opisanom principu:
Lex, Flex, jlex, jflex,...
Programski prevodioci © 2004-2009 Dragan Bojić 31 Programski prevodioci © 2004-2009 Dragan Bojić 32
6
D B C
2 3
Prva pozicija za svaki čvor stabla predstavlja skup
pozicija listova koji se mogu pojaviti na prvom mestu
A sekvence koju generiše podizraz sa korenom u datom
čvoru. Računanje prvih pozicija:
1. prva_pozicija(ab) =
prva _ pozicija(a), a nije poništiv
prva _ pozicija(a) prva _ pozicija( b), a je poništiv
B C
2. prva_pozicija(a|b) = prva_pozicija(a)
Pozicijama se označavaju listovi sintaksnog stabla
prva_pozicija(b)
(osim ) redom pri obilasku stabla sa leva u desno.
3. prva_pozicija(a*) = prva_pozicija(a).
Poslednja pozicija za svaki čvor stabla predstavlja skup
pozicija listova koji se mogu pojaviti na poslednjem
mestu sekvence koju generiše podizraz sa korenom u
5 datom čvoru. Računanje poslednjih pozicija:
1. poslednja_pozicija(ab) =
D poslednja _ poz.(b), b nije poništiv
poslednja _ poz.(b) poslednja _ poz.(a), b je poništiv
4
pozicija
A 2. poslednja_pozicija(a|b) = poslednja_pozicija(a)
1 poslednja_pozicija(b)
3. poslednja_pozicija(a*) = poslednja_pozicija(a).
{1,2,4} {5}
B C
2 3 {1,2,4} {4} {5} {5}
5
Čvor sintaksnog stabla je poništiv ako podizraz sa
korenom u datom čvoru može generisati praznu
sekvencu. Računanje poništivosti: {1,2} {1,3} {4} D {4}
1. Listovi nisu poništivi, osim ako su označeni sa . 4
Programski prevodioci © 2006 Dragan Bojić 3 Programski prevodioci © 2006 Dragan Bojić 4
Primer Primer...
1
1. korak – Konstruisanje prepoznavača 2. korak - dodavanje akcija
Ulazna azbuka {DIGIT, •, E, SIGN}
prelazi razmatranjem karakterističnih primera ulaza DIGIT E • SIGN ─┤
3 8 . 7 E - 3 . 9 E 21 0 1a 7
0 1 1 2 3 4 5 6 0 7 3 4 6 6 1 1b 4a 23c YES1
DIGIT E • SIGN 23 23a 4b YES2
inicijalno stanje 0 1 7 0 4 6a 5
cifra pre opcione tačke 1 1 4 2 1 5 6b
opciona decimalna tačka 2 3 4 1 6 6c YES3
cifra nakon decimalne tačke 3 3 4 1 7 23b
slovo E 4 6 5 0
predznak eksponenta 5 6 0
cifra eksponenta 6 6 1
tačka iza koje mora ići cifra 7 3 0
Programski prevodioci © 2006 Dragan Bojić 7 Programski prevodioci © 2006 Dragan Bojić 8
Programski prevodioci © 2006 Dragan Bojić 11 Programski prevodioci © 2006 Dragan Bojić 12
2
Implicitno predstavljanje stanja Eksplicitno predstavljanje stanja
enum Boolean DKA(char *ulaz) {
#include<stdio.h> enum Boolean DKA(char *ulaz) { #include<stdio.h> enum Stanje {A,B,NO1,YES1};
#define ENDM '\0' /*marker kraja */ A: switch (*ulaz++) { #define ENDM '\0' /*marker kraja */ enum Stanje tabela[2][3] =
case 'a': goto B; {B,NO1,YES1,A,B,NO1};
enum Boolean {NO, YES}; enum Boolean {NO, YES};
case 'b': return NO; int znak, tekuce=A;
case ENDM: return YES; while(1) {
enum Boolean DKA(char *ulaz){…} enum Boolean DKA(char *ulaz){…}
default: return NO; switch (*ulaz++) {
} case 'a': znak=0; break;
main () { main () {
B: switch (*ulaz++) { case 'b': znak=1; break;
char s[80]; char s[80];
case 'a': goto A; case ENDM: znak=2; break;
scanf("%s",s); scanf("%s",s);
case 'b': goto B; default: return NO;
printf("%u\n",DKA(s)); printf("%u\n",DKA(s));
case ENDM: return NO; }
} }
default: return NO; tekuce=tabela[tekuce][znak];
} if(tekuce>B) return tekuce-
NO1;
}
}
}
Programski prevodioci © 2006 Dragan Bojić 13 Programski prevodioci © 2006 Dragan Bojić 14
OO implementacija KA…
Objektno-orijentisana implementacija KA
3
Uloga sintaksno/semantičke analize
Programski prevodioci IR4PP1 Gramatike
Višeznačnost gramatika
Gramatike i regularni izrazi
Lekcija – Sintaksna analiza Klasifikacija gramatika
Programski prevodioci © 2006 Dragan Bojić 3 Programski prevodioci © 2006 Dragan Bojić 4
1
EBNF Notacija Primer: Gramatika za aritmetičke izraze
Extended Backus-Naur form John Backus: razvio prvi Fortran compiler Smene
Peter Naur: editovao Algol60 speficikaciju
(BNF + reg. izrazi) Expr = [ "+" | "-" ] Term { ( "+" | "-" ) Term }.
simbol značenje primeri Term = Factor { ( "*" | "/" ) Factor }. Expr
Factor = ident | number | "(" Expr ")".
string Predstavlja “sam sebe” "=", "while"
ime predstavlja T ili NT simbol ident, Statement Terminalni simboli
= razdvaja strane smene A= b c d . Obični TS: "+", "-", "*", "/", "(", ")" Term
. završava smenu (samo 1 instanca)
| Razdvaja alternative a | b | c značenje a or b or c
klase TS: ident, number
(...) grupiše alternative a ( b | c ) značenje ab | ac
(više instanci) Factor
[...] opcioni deo [a]b značenje ab | b
{...} { a } b značenje b | ab | aab | aaab | ... Neterminalni simboli
ponavljajući deo
Expr, Term, Factor
Konvencije
Startni simbol
• Terminalni simboli počinju malim slovom (npr. ident)
Expr
• Neterminalni simboli počinju velikim slovima (npr. Statement)
Programski prevodioci © 2006 Dragan Bojić 7 Programski prevodioci © 2006 Dragan Bojić 8
Programski prevodioci © 2006 Dragan Bojić 9 Programski prevodioci © 2006 Dragan Bojić 10
2
Terminologija (nastavak)
Stablo izvođenja je Uloga sintaksno/semantičke analize
grafička predstava S a A c B a a c B a a c b
izvođenja 1 7 8 Gramatike
Izvođenje <X> Y Z
<S> Višeznačnost gramatika
V se u stablu izvođenja Gramatike i regularni izrazi
predstavlja na taj način <A> c <B>
što čvor <X> ima a Klasifikacija gramatika
čvorove naslednike Y,
Z i V navedenim a b
redosledom..
Programski prevodioci © 2006 Dragan Bojić 13 Programski prevodioci © 2006 Dragan Bojić 14
Programski prevodioci © 2006 Dragan Bojić 15 Programski prevodioci © 2006 Dragan Bojić 16
Primer: Dangling Else (viseće Else) Primer: Dvosmislenost kao posledica preklapanja identifikatora
<Stmt> if <Expr> then <Stmt> a = f(17)
| if <Expr> then <Stmt> else <Stmt>
| other Stmts Da li je f funkcija, ili vektor (u npr. Algolu)?
Razmotrimo sentencu: Da bi se ova dvosmislenost razrešila,
If E1 then if E2 then S1 else S2 neophodan je semantički kontekst:
Ova sentenca ima dva stabla izvođenja.
• potrebno je poznavati tip simbola f
Moguće rešenje (else se pridružuje najbližem neuparenom then)
<Stmt> <Matched>
| <Unmatched>
<Matched> if <Expr> then <Matched> else <Matched>
| other Stmts
<Unmatched> if <Expr> then <Stmt>
| if <Expr> then <Matched> else <Unmatched>
Programski prevodioci © 2006 Dragan Bojić 17 Programski prevodioci © 2006 Dragan Bojić 18
3
Ograničenja regularnih jezika
Programski prevodioci © 2006 Dragan Bojić 19 Programski prevodioci © 2006 Dragan Bojić 20
Gramatike koje opisuju regularne jezike automata. Startnom neterminalu odgovara startno
nazivaju se regularnim gramatikama. stanje automata.
Proizvoljnom prelazu automata iz stanja A u stanje
Definicija:
B pod ulazom x, odgovara smena <A> x<B>.
Svaka smena regularne gramatike ima jedan
Proizvoljno stanje prihvatanja A indukuje
od sledeća dva oblika: dodavanje smene: <A> .
1. <A> b <C>
2. <A> - prazna sekvenca
Programski prevodioci © 2006 Dragan Bojić 21 Programski prevodioci © 2006 Dragan Bojić 22
Programski prevodioci © 2006 Dragan Bojić 23 Programski prevodioci © 2006 Dragan Bojić 24
4
Transformacija desno-linearne u
regularnu gramatiku Primer transformacije
Primenom tri pravila: <A> <B>
<B> 1 <A> 1 1. <A> ab<B> 4. <B> <A>
1. <A> ab<B>
<A> w zameniti sa <A> w<> <B> 2 zameniti sa <A> 2 2. <A> ac<> 5. <B>
w – terminali <> ... ... 2. <A> ac
<> je novo uvedeni neterminal <B> n <A> n 3. <B> <A> 3. <>
Klasifikacija gramatika
Noam Chomsky (1956)
5
Uvod
Programski prevodioci 1 BU parser u vidu potisnog automata
SHIFT-REDUCE Parsiranje
Konstrukcija LR(0) parsera
Lekcija – Parsiranje od dna ka Konflikti u SHIFT-REDUCE parsiranju
vrhu, prvi deo
Programski prevodioci © 2006 Dragan Bojić 3 Programski prevodioci © 2006 Dragan Bojić 4
Programski prevodioci © 2006 Dragan Bojić 5 Programski prevodioci © 2006 Dragan Bojić 6
1
Primer Rad potisnog automata
1. <S> <S> <S> a Automat startuje sa definisanom startnom
2. <S> <S> b konfiguracijom steka ().
3. <S> <S> <S> <S> c
Automat skenira sekvencu koja se sastoji od ulaznih
4. <S> d simbola a,b,c,d,-| s leva na desno, znak po znak.
a b c d -| U svakom koraku rada, akcija automata se određuje
SHIFT ACCEPT čitanjem kontrolne tabele (reprezentuje kontrolnu
<S> SHIFT SHIFT SHIFT funkciju), za tekući vrh steka i tekući ulazni simbol (i
tekuće stanje, u slučaju da ima više stanja).
a REDUCE(1) REDUCE(1) REDUCE(1) REDUCE(1) REDUCE(1) Akcija se sastoji od ažuriranja ulaza, steka i stanja.
b REDUCE(2) REDUCE(2) REDUCE(2) REDUCE(2) REDUCE(2)
c REDUCE(3) REDUCE(3) REDUCE(3) REDUCE(3) REDUCE(3)
d REDUCE(4) REDUCE(4) REDUCE(4) REDUCE(4) REDUCE(4)
Programski prevodioci © 2006 Dragan Bojić 7 Programski prevodioci © 2006 Dragan Bojić 8
Programski prevodioci © 2006 Dragan Bojić 9 Programski prevodioci © 2006 Dragan Bojić 10
Programski prevodioci © 2006 Dragan Bojić 11 Programski prevodioci © 2006 Dragan Bojić 12
2
Operacije potisnog automata Operacije potisnog automata
ACCEPT – kraj rada automata pri čemu određene operacije nad stekom
se ulazna sekvenca prihvata (ili ACCEPT/REJECT),
REJECT – kraj rada pri čemu se ulazna promene stanja u određeno stanje s S i
sekvenca odbija određene operacije nad ulazom.
Programski prevodioci © 2006 Dragan Bojić 13 Programski prevodioci © 2006 Dragan Bojić 14
Programski prevodioci © 2006 Dragan Bojić 17 Programski prevodioci © 2006 Dragan Bojić 18
3
Rad potisnog BU parsera Parsiranje od dna ka vrhu (BU)
u svakom koraku važi: Koncept BU parsiranja
stek + ulaz = sentencijalna forma u Kod pristupa 'odozdo-nagore' parser otkriva
strukturu stabla izvođenja počev od listova
krajnje desnom izvođenju ulaza iz <S> stabla nagore, određujući čvorove roditelja
parser potiskuje (akcija SHIFT) simbole prepoznavanjem leve strane smena na
sa ulaza na stek dok ne kompletira osnovu poznate desne strane.
ručku
redosled smena koje parser prepoznaje
SHIFT ≡ PUSH(tekući ulazni simbol), tokom rada obrnut od redosleda pri krajnje
ADVANCE desnom izvođenju date sentence
tada se ručka zamenjuje levom stranom
smene (akcija REDUCE)
Programski prevodioci © 2006 Dragan Bojić 19 Programski prevodioci © 2006 Dragan Bojić 20
Programski prevodioci © 2006 Dragan Bojić 21 Programski prevodioci © 2006 Dragan Bojić 22
Programski prevodioci © 2006 Dragan Bojić 23 Programski prevodioci © 2006 Dragan Bojić 24
4
Primer SHIFT-REDUCE parsera Elementi SR parsera
1.<S> <A><A><S> Skup ulaznih simbola parsera sastoji se
2.<S> od skupa terminalnih simbola zadate
<S> <A> a a -|
3.<S> a
<S> <A>11 ax SHIFT REDUCE(2) gramatike proširenog simbolom -|.
4.<A> a
<S> <S> REJECT ACCEPT
<A>
11 <A>12 a4 <A>
11
SHIFT REJECT
ax a x REDUCE(4)REDUCE(3)
<A>12 <S> <A>
11 ax <A>12
SHIFT REDUCE(2)
a4 a4 REDUCE(4) REDUCE(4)
<S> <S> REJECT REDUCE(1)
(a)potisna tabela (b) kontrolna tabela
Programski prevodioci © 2006 Dragan Bojić 25 Programski prevodioci © 2006 Dragan Bojić 26
Programski prevodioci © 2006 Dragan Bojić 27 Programski prevodioci © 2006 Dragan Bojić 28
Elementi SR parsera(...)
<S> <A>11 ax SHIFT REDUCE(2)
SR parsera <S>
<A> <A>
<S> REJECT
SHIFT
ACCEPT
REJECT
11 12 a4 <A>
11
5
Konstrukcija SR parsera za LR(0)
gramatike
Programski prevodioci © 2006 Dragan Bojić 31 Programski prevodioci © 2006 Dragan Bojić 32
Programski prevodioci © 2006 Dragan Bojić 33 Programski prevodioci © 2006 Dragan Bojić 34
Primer Primer
LR(0) konfiguracije 2. smene za praznu smenu <X> jedna
konfiguracija zatvaranja (tačka na početku)
konfiguracija, u oznaci
<S> ( <S> <R>
<X> ili <X>
bazične konfiguracije (tačka nije na početku):
<S> ( <S> <R> proširenje gramatike (uniformiše pravila
<S> ( <S> <R> konstrukcije parsera)
<S> ( <S> <R> 0. <S’> <S> ─┤
druga oznaka za poslednju konfiguraciju
<R>3
Programski prevodioci © 2006 Dragan Bojić 35 Programski prevodioci © 2006 Dragan Bojić 36
6
Konstrukcija karakterističnog LR(0) Konstrukcija karakterističnog LR(0)
automata – detektora ručki automata – detektora ručki
Programski prevodioci © 2006 Dragan Bojić 37 Programski prevodioci © 2006 Dragan Bojić 38
Operacija Goto0 nad stanjem s i Startno stanje detektora ručki se dobija kao
Closure0({<S’> <S> ─┤}).
ulaznim simbolom X:
Stanje S' u koje se prelazi iz nekog stanja S
Goto0(s,X)=Closure0({<A> X | pod ulazom X, dobija se kao rezultat
<A> Xs} procedure GoTo0(S,X).
Polazeći od startnog stanja, sistematski se
određuju prelazi za svaki ulazni simbol, što
... generiše nova stanja.
X
<A> X <A> X Ova stanja se procesiraju na isti način kao
... startno, sve dok postoji neko neobrađeno
stanje.
Programski prevodioci © 2006 Dragan Bojić 39 Programski prevodioci © 2006 Dragan Bojić 40
Closure0
Programski prevodioci © 2006 Dragan Bojić 41 Programski prevodioci © 2006 Dragan Bojić 42
7
Karakteristični automat za Karakteristični automat za
gramatiku iz primera gramatiku iz primera
<S>0 <S>0
<S’> –> <S> --| <S> <S’> –> <S> --| <S>
<S’> –> <S> --| <S’> –> <S> --|
<S> –> a <S> –> a
startno <S> –> (<S> <R> a a1 startno <S> –> (<S> <R> a a1
stanje stanje
<S>–> a <S>–> a
(
(
(2
GOTO0 na
(2
<S> –> ( <S> <R>
<S> –> ( <S> <R>
<S> –> a
<S> –> (<S> <R>
CLOSURE0 na nova stanja
Programski prevodioci © 2006 Dragan Bojić 43 Programski prevodioci © 2006 Dragan Bojić 44
( a ( a
8
Konflikti u SR parsiranju
Programski prevodioci © 2006 Dragan Bojić 49 Programski prevodioci © 2006 Dragan Bojić 50
prazne smene uvek izazivaju konflikt tada gramatika nije LR(0) i (teorijski)
=> LR(0) ne dozvoljava prazne smene nije moguće napraviti LR(0) parser;
<S’> <S> ─┤ u praksi (yacc):
<S> a S/R konflikt uvek razrešava u korist S, osim
ako se %prec direktivom eksplicitno ne
<S>
zada drugačije
R/R konflikt (ozbiljniji problem) prema
redosledu navođenja smena
Programski prevodioci © 2006 Dragan Bojić 51 Programski prevodioci © 2006 Dragan Bojić 52
9
Parsiranje od dna ka vrhu
(Nastavak)
Poništivost neterminala
Neterminal <X> je poništiv ako i samo ako se iz njega može izvesti prazna sekvenca:
<X> ,*
Sekvenca gramatičkih simbola je poništiva ako i samo ako se sastoji od nula ili više poništivih
neterminala.
Skup poništivih neterminala P formiramo na sledeći način:
1. U skup P staviti sve neterminale koji se pojavljuju na levoj strani neke prazne smene.
2. Razmatrati redom smene čije se desne strane sastoje isključivo od neterminala, a leva strana se ne
nalazi u skupu P. Ako se svi neterminali desne strane pojavljuju u skupu P, dodati levu stranu smene
u P.
3. Sve dok postoji promena u skupu P ponavljati korak 2, u suprotnom završiti postupak.
First skupovi
Skup FIRST(<X>) za proizvoljan neterminal <X> predstavlja skup svih terminalnih simbola kojima
može početi sentencijalna forma izvedena iz <X>:
FIRST(<X>) = { t | t Vt V* <X> * t }
Moguće je definisati FIRST skupove sentencijalnih formi: Neka je = A1A2...AiAi+1...An proizvoljna
sentencijalna forma u kojoj prvih i simbola predstavlja poništive neterminale. Tada skup FIRST()
predstavlja uniju FIRST skupova svih simbola sa levog kraja sekvence zaključno sa prvim koji nije
poništiv:
FIRST()=FIRST(A1) FIRST(A2) ... FIRST(Ai+1)
Ukoliko je simbol A terminal, onda je FIRST(A) = {A}.
U opštem slučaju, na osnovu datih pravila formira se sistem skupovnih jednakosti koji se rešava
iterativno:
1. Inicijalno se usvoji da su svi FOLLOW skupovi prazni.
2. Usvojene vrednosti se uvrste u jednakosti čime se dobijaju nove vrednosti FOLLOW skupova.
3. Korak 2. ponavlja se sve dok postoji promena bar u jednom skupu. Krajnje vrednosti predstavljaju
konačno rešenje.
Rešenje
Odredimo prvo poništive neterminale u datoj gramatici, zatim FIRST, a potom i FOLLOW skupove.
1.<A>a<B><C> Pon = { <A>, <B>}
2. <A> b<B> FIRST(<A>)=a, b
3. <A> FIRSTB>)=a
4. <B> a<B>b
FIRSTC>)=b, c
5. <B>
6. <C> b<C> FOLLOWA> = ─┤
7. <C> c FOLLOW(<B>) FIRST(<C>)
FOLLOW(<B>) FIRST() FOLLOW(<A>)
FOLLOW(<B>) {b}
FOLLOW(<B>)=FIRST(<C>)FOLLOW(<A>){b}
= {b, c, ─┤}
FOLLOW(<C>) FIRST() FOLLOW(<C>)
FOLLOW(<C>) FIRST()FOLLOW(<A>)=─┤
Karakteristični automat i potisna tabela SLR(1) parsera identični su karakterističnom automatu i potisnoj
tabeli LR(0) parsera.
LALR(1) parsiranje
bx
<S’> <S> ─┤ <S> b c <A>c
<S> <A> a b
<A> b
<S> b c <A> c
<A> b
u okviru simbola steka LALR(1) parsera može se pojaviti samo podskup LR(1) konfiguracija koje
nazivamo pravilnim.
LR(1) konfiguraciju <X> , t nazivamo pravilnom LR(1) konfiguracijom ako i samo ako je:
1. t FOLLOW(<X>), ili
veza prosleðivanja
Primer
Za gramatiku:
1. <S> <A><S>
2. <S>
3. <A> <B>b<B>c
4. <A> <C>c<B>
5. <B> a<D>
6. <C> a<D>
7. <D>
Sledeća slika prikazuje stanje početno stanje pri računanju predikcionih simbola za ovu gramatiku.
LR(0) konfiguracijama u svakom stanju LR(0) detektora ručki dodati su SLA skupovi predikcija.
Isprekidane linije predstavljaju veze prosleđivanja.
state state <S> state
0 0
<S>
<S'> <S> {} <S'> <S> {} <S'> <S> {}
<S> <A><S> {}
state <A>
<S> {} 1 state <S>
1
<A> <B>b<B>c{a} <A> <S> <A> <S> {} <S>
<S> <A><S> {}
<A> <C>c<B>{a}
<B> a<D>{b} <S> <A><S> {}
<S> {}
<C> a<D>{c} state <D>
<A> <B>b<B>c{a} <A> x
<A> <C>c<B>{a} <B> a<D> {}
a
<C> <B> a<D>{b} <C> a<D> {}
ax <C> a<D>
{ c}
<B> <D>
<C> <B> <C> a state a
4 x
<B> a <D> {}
state <B> state <C> <C> a <D> {}
31 4
<A> <B> b<B>c{} <A> <C> c<B>{} <D> {}
b
c
state b state c
3 4 state <B>
4
<A> <B>b <B>c{} <A> <C>c <B>{}
<A> <C>c<B> {}
<B> a<D>{c} <B> a<D>{} <B>
<B> a a
state <B> state a
33 5
<A> <B>b<B> c{} <B> a <D>{}
<D> {}
c
state c <D>
3
state <D>
<A> <B>b<B>c {} 5
<B> a<D> {}
Svi ulazi tabele koji nisu obuhvaćeni gornjim pravilima sadrže REJECT akciju.
Ako svaki ulaz u kontrolnoj tabeli, posle njihovog popunjavanja prema navedenim pravilima, sadrži
jedinstvenu akciju zadata gramatika pripada klasi LALR(1) gramatika i konstrukcija parsera je
okončana.
U suprotnom slučaju, zadata gramatika ne pripada klasi LALR(1) gramatika, pa se za nju ne može
konstruisati LALR(1) parser.
LR(0)
SLR(1)
LALR(1)
LR(1)
Sve bezkontekstne gramatike
Ulazna . . . . . . . . . . . . . . . . . . . .
sekvenca
simbol povrede
Parser ima svojstvo ispravnog prefiksa ako za sve neispravne ulazne sekvence niz simbola pre
simbola povrede predstavlja prefiks nekog prihvatljivog ulaznog niza.
Kod takvih parsera možemo modifikacijom preostalog ulaza učiniti ceo ulayni niz prihvatljivim
Parseri konstruisani metodima koje proučavamo na kursu imaju ovo svojstvo
Poruka o grešci najčešće se formuliše na osnovu vršnog simbola steka i tekućeg ulaznog simbola, uz
navođenje linije i pozicije na liniji koda na kojoj je nastupila greška.
Potom se vrši oporavak parsera od greške, koji potencijalno može da prouzrokuje nove nepostojeće
greške. Kvalitet oporavka ceni se po tome koliko malo nepostojećih grešaka se prijavljuje.
izložićemo osnovne (i najčešće primenjivane) varijante "paničnog" oporavka. Ideja je da pri pojavi
greške, parser pokušava da izađe iz jezičkog konstrukta u kome je nastala greška, tražeći siguran
ulazni simbol (kao što je terminator naredbe ili početna ključna reč sledeće naredbe i slično) od koga
može da nastavi normalno parsiranje.
Definišemo skup tzv. sigurnih simbola (kao što su terminatori iskaza i konstrukcija ; end --| itd.)
(1) Kada parser detektuje grešku, sa ulaza se redom uklanjaju simboli dok se ne naiđe na neki od
sigurnih simbola.
(2) Tada se sa steka parsera skidaju simboli sve dok se ne naiđe na neki koji može da potisne sigurni
simbol na ulazu na stek.
Ovaj algoritam najbolje funkcioniše kod nestrukturiranih jezika, kakvi su Basic ili Fortran; ideja je da se
parser izvuče iz pogrešnog konstrukta tako što detektuje njegov kraj i posle normalno nastavi parsiranje.
Poboljšanje za strukturirane jezike je da se pored skupa sigurnih simbola definiše i skup simbola zaglavlja
(header), kao što su begin, then i slično.
(1) Kada parser detektuje grešku, sa ulaza se redom uklanjaju simboli dok se ne naiđe na neki od
sigurnih simbola ili simbola zaglavlja.
(2a) Ako je naišao siguran simbol, tada se sa steka parsera skidaju simboli sve dok se ne naiđe na neki
koji može da potisne sigurni simbol na ulazu na stek.
(2b) Ako je naišao simbol zaglavlja, tada se on potiskuje na stek i posebno markira.
(3) Parsiranje se posle toga nastavlja na uobičajen način. Kada se redukcijom neke smene ukloni
markirani simbol sa steka, prelazi se ponovo na korak (1).
pri nastanku sintaksne greške u izgenerisanom parseru, poziva se funkcija yyerror() kojoj se
prosleđuje opis greške u stringu
Po povratku iz yyerror(), parser može izvršiti oporavak od greške ako u gramatici postoje
odgovarajuća pravila. U suprotnom, yyparse() završava rad i vraća nenultu vrednost (neusprešan
kraj).
Oporavak od greške
oporavak od grešaka je pod kontrolom korisnika: postoji poseban gramatički simbol error.
Simbol error tretira se kao specijalan neterminal, čija se zamena ne definiše smenama, već se
razmatra se jedino u slučaju da parser detektuje grešku.
Tada parser pokušava da odgovarajuću pojavu error u gramatici upari sa pogrešnim delom ulazne
sekvence i potom nastavi parsiranje.
Smena sa error znači da ako ulazni niz ne odgovara ni jednoj od “normalnih” smena za stmt, parser
prelazi u režim oporavka “gutajući” pogrešne ulazne simbole (tj. uparujući ih sa error) sve dok ne
naiđe na “;”.
Parser izlazi iz režima oporavka ako može da nastavi o dove tačke normalno parsiranje (SHIFT-uje
bar tri tokena na uobičajen način).
Po detektovanju greške, parser skida sa steka stanja dok ne dođe do stanja koje ima neposredan
oporavak od greške ( konfiguraciju X…error…).
Tada parser počinje “preskakanje” ulaznih tokena do trenutka kada dođe neki koji očekuje.
Tada nastavlja parsiranje ali bez izvršavanja semantičkih akcija. Ako uspešno procesira bar tri tokena
sa ulaza, ulaz se resetuje na stanje kada je prestalo preskakanje tokena i parsiranje se ponavlja
normalno, ovaj put izvršavajući sve akcije.
Ako parser nije uspeo uspešno da isprocesira tri tokena, parser odbacuje sledeći token sa ulaza i
pokušava da nastavi parsiranje.
Ako se u pokušajima oporavka dođe do kraja ulaza ili isprazni parserski stek (na primer nije bilo
odgovarajućeg stanja koje ima oporavak) parser neuspešno završava rad.
Jednostavna i efikasna strategija oporavka je da se preskoči ostatak tekuće linije programa (ili ostatak
tekućeg iskaza):
stmnt: error ';' /* on error, skip
until ';' is read */
Takođe je korisno upariti zatvorenu zagradu za već parsiranu otvorenu zagradu (ili neki sličan par
delimitera). U suprotnom, zatvorena zagrada bi izgledala neuparena i generisala dodatnu suvišnu
prijavu greške:
primary: '(' expr ')'
| '(' error ')'
...
;
Da bi suzbio suvišne prijave grešaka, parser ne prijavljuje sintaksne greške neposredno posle prve
prijave. Tek posle tri ispravno procesirana ulazna tokena, ponovo se omogućava prijavljivanje
grešaka.
Ako se u semantičkoj akcija pravila za oporavak od greške upotrebi yyerrok, parser će odmah
omogućiti prijavu novih grešaka (neće čekati da prođu tri uspešna tokena), na primer:
primary: '(' error ')' { yyerrok; }
Primetiti da pravila za oporavak od greške mogu sadržati akcije, kao i obična pravila.
Translacione gramatike
Programski prevodioci 1 Atributivno-translacione gramatike
Sintaksno-upravljano prevođenje od
dna ka vrhu
Lekcija – Sintaksno upravljano prevođenje
Programski prevodioci © 2007 Dragan Bojić 3 Programski prevodioci © 2007 Dragan Bojić 4
1
Atributivno-translacione
gramatike (ATG)
Programski prevodioci © 2007 Dragan Bojić 7 Programski prevodioci © 2007 Dragan Bojić 8
(ako se naruše, gramatika nema smisla) 3. Za svaki nasleđeni atribut koji se pojavljuje
1. Atributi se moraju slagati po broju i tipu za na desnoj strani smene mora postojati
pravilo za izračunavanje
sve pojave istog simbola X (ne moraju i po
može zavisiti od nasleđenih sa leve strane i od
imenu). bilo kog sa desne strane.
2. Za svaki sintetizovani atribut koji se 4. Vrednost nasleđenih atributa startnog
pojavljuje na levoj strani smene mora neterminala (na levoj strani) mora biti
postojati pravilo za izračunavanje unapred zadata.
može zavisiti od nasleđenih atributa sa leve 5. Vrednosti atributa ulaznih simbola se ne
strane i od bilo kog sa desne strane. računaju, nego moraju biti unapred zadate.
Programski prevodioci © 2007 Dragan Bojić 11 Programski prevodioci © 2007 Dragan Bojić 12
2
Računanje vrednosti atributa Računanje vrednosti atributa...
a1 b2 a3 b4 c5 b2 c6 c7.
(indeksi predstavljaju vrednosti atributa A <S> b C <A> d
a <S> b c <A> d
e c
Programski prevodioci © 2007 Dragan Bojić 13 Programski prevodioci © 2007 Dragan Bojić 14
e c5
Programski prevodioci © 2007 Dragan Bojić 15 Programski prevodioci © 2007 Dragan Bojić 16
a1 <S> 1,1 b2 C1,1 <A> 3,1 d3,2,1 Ulaznu sekvencu (izostavimo akcione simbole):
a1 b2 a3 b4 c5 b2 c6 c7
b2 <A> 6,2 <A> 7,2 +6,7,3
3
Drugi primer ATG Prvo rešenje
Dodeliti atribute sledećoj gramatici: samo sintetizovani atributi
1. <integer> digit <more digits> 1. <integer>value digitval <more digits>v, b
2. <more digits> digit <more digits> value val * 10b + v
3. <more digits> e 2. <more digits>v, b digitval <more digits> v1, b1
tako da neterminalni simbol <integer> ima v val * 10b1 + v1 b b1 + 1
sintetizovani atribut jednak vrednosti celog 3. <more digits> v, b e
broja koji ovaj simbol generiše. v0 b0
Pretpostaviti da ulazni simbol digit ima
atribut jednak vrednosti odgovarajuće cifre.
Programski prevodioci © 2007 Dragan Bojić 19 Programski prevodioci © 2007 Dragan Bojić 20
Drugo rešenje
nasleđeni i sintetizovani, izbegava se Translacione gramatike
stepenovanje
1. <integer>value digitval <more digits>i,s Atributivno-translacione gramatike
value s i val Sintaksno-upravljano prevođenje od
Napomena: i nasleđen, s sintetizovan
dna ka vrhu
2. <more digits>i,s digitval <more digits>i1,s1
i1 10i + val s s1
Programski prevodioci © 2007 Dragan Bojić 21 Programski prevodioci © 2007 Dragan Bojić 22
Programski prevodioci © 2007 Dragan Bojić 23 Programski prevodioci © 2007 Dragan Bojić 24
4
Poljska translaciona gramatika S-atributivna gramatika
Ukoliko gramatika nije poljska, možemo je Gramatika je S - atributivna, ako:
transformisati:
Svi atributi neterminalnih simbola su
1. <X> A {y} B
sintetizovani.
transformišemo u:
Nijedan sintetizovani atribut ne može da zavisi
<X> <N> B
od drugog sintetizovanog atributa iste pojave
<N> A {y} simbola u gramatici.
Druga varijanta:
Nasleđeni atributi akcionih simbola smeju da
1. <X> A <M> B zavise samo od atributa onih simbola produkcije
transformišemo u: koji su levo od tog akcionog simbola.
<M> {y}
Programski prevodioci © 2007 Dragan Bojić 25 Programski prevodioci © 2007 Dragan Bojić 26
Primer Primer
1. <E>p ( <E>q + <E>r ) ADD s1,s2,s3 Data S-atributivna poljska translaciona
s1 q, s2 r, p,s3 NEWT gramatika prevodi izraz u niz sastavljen od
atoma ADDp,q,r i MULTp,q,r gde su p, q i r
respektivno ukazatelji na levi operand, desni
2. <E>p ( <E>q * <E>r ) MULT s1,s2,s3 operand i rezultat operacije u tabeli simbola
s2 q, s2 r, p,s3 NEWT (ekvivalent asemblerskom kodu).
Novi ulaz u tabelu generišemo pozivom
funkcije NEWT.
3. <E>p Ir Atribut tokena I je ukazatalj na tabelu
simbola, na simbol koji odgovara tokenu I.
pr
Programski prevodioci © 2007 Dragan Bojić 27 Programski prevodioci © 2007 Dragan Bojić 28
5
Proširene REDUCE akcije za tekući primer
REDUCE(1): REDUCE(3) : Primer rada potisnog procesora za tekući primer
BEFORE AFTER BEFORE AFTER
Stek Tek.ul Akc. Izlaz
) <E> I <E> 1. ( I1 + ( I2 * I3 ) ) -| SHIFT
2. ( I1 + ( I2 * I3 ) ) -| SHIFT
3. ( I1 + ( I2 * I3 ) ) -| REDUCE(3)
<E> NEWT vredn. r vredn. r 4. ( <E>1 + ( I2 * I3 ) ) -| SHIFT
5. ( <E>1 + ( I2 * I3 ) ) -| SHIFT
vredn. r .... ... ... 6. ( <E>1 + ( I2 * I3 ) ) -| SHIFT
7. ( <E>1 + ( I2 * I3 ) ) -| REDUCE(3)
+ 8. ( <E>1 + ( <E>2 * I3 ) ) -| SHIFT
9. ( <E>1 + ( <E>2 * I3 ) ) -| SHIFT
<E> 10. ( <E>1 + ( <E>2 * I3 ) ) -| REDUCE(3)
11. ( <E>1 + ( <E>2 * <E>3 ) ) -| SHIFT
vredn. q REDUCE(2) je kao i REDUCE(1) samo 12. ( <E>1 + ( <E>2 * <E>3) ) -| REDUCE(2) {MUL2,3,4}
( <E>1 + <E>4 ) -| SHIFT
umesto "+" stoji "*", a akcija je
13.
Konačni izlaz:
{MULT 2,3, 4}
{ADD 1,4, 5}
Konačna tabela simbola:
RB Naziv Tip
1 1 C
2 a V
3 2 C
4 t1 T
5 t2 T
Programski prevodioci © 2007 Dragan Bojić 33
6
Uvod
Programski prevodioci 1 Konstrukcija parsera od vrha ka dnu
Selekcioni skupovi i LL(1) gramatike
Transformacije gramatika u LL(1)
Lekcija – Parsiranje od vrha ka Sintaksno-upravljano prevođenje od
dnu (Top Down) vrha ka dnu
Programski prevodioci © 2006 Dragan Bojić 3 Programski prevodioci © 2006 Dragan Bojić 4
Primer Primer
Programski prevodioci © 2006 Dragan Bojić 5 Programski prevodioci © 2006 Dragan Bojić 6
1
Primer Primer
Parser primenjuje izabranu smenu u prvom
na parser bira smenu za <S> na koraku levog izvođenja:
osnovu tekućeg ulaza. U primeru, to je <S> =>lm a <A><B>=> ? => acdd
smena 1. Novo stanje:
<S> =>lm a <A><B>=> ? => acdd
U opštem slučaju, smena se bira ako je
tekući ulaz neki terminalni simbol iz tekući simbol tekući ulaz
selekcionog skupa te smene. Sada vidimo da se a u sentencijalnoj formi i a u
završnoj sentenci uparuju, pa tekući postaju:
<S> => lm a <A><B>=> ? => acdd
tekući simbol tekući ulaz
Programski prevodioci © 2006 Dragan Bojić 7 Programski prevodioci © 2006 Dragan Bojić 8
Primer Primer
biramo smenu 3. za zamenu <A>: uparivanje tekućeg terminala i tekućeg ulaza:
<S> =>lm a <A><B>=>lm a c <B> <B> => ? => acdd <S> =>lm a <A><B>=>lm a c <B> <B> =>lm a c d <B> => ? => acdd
tekući simbol tekući ulaz tekući simbol tekući ulaz
Uparivanje tekućeg terminala i tekućeg ulaza:
<S> =>lm a <A><B>=>lm a c <B> <B> => ? => acdd sada biramo smenu 4:
<S> =>lm a <A><B>=>lm a c <B> <B> =>lm a c d d => ? => acdd
tekući simbol tekući ulaz
biramo smenu 4 na osnovu tekućeg ulaznog tekući simbol tekući ulaz
simbola:
uparivanjem tekućeg terminala i tekućeg ulaza
<S> =>lm a <A><B>=>lm a c <B> <B> =>lm a c d <B> => ? => acdd
konstatujemo da je rekonstrukcija levog
izvođenja uspešno okončana
tekući simbol tekući ulaz
Programski prevodioci © 2006 Dragan Bojić 9 Programski prevodioci © 2006 Dragan Bojić 10
Programski prevodioci © 2006 Dragan Bojić 11 Programski prevodioci © 2006 Dragan Bojić 12
2
Metod rekurzivnog spusta Principi konstrukcije
Primer gramatike za koju želimo da konstruišemo Programsko rešenje čini glavni program i niz
parser: uzajamno rekurzivnih potprograma. Za svaki
1. <E> <T> <E_list> neterminal gramatike obezbeđuje se jedan
2. <E_List> + <T> <E_List> potprogram (u konkretnom slučaju imaćemo
3. <E_list>
potprograme PROCE, PROCE_LIST, PROCT,
PROCT_LIST i PROCP).
4. <T> <P> <T_list>
Potprogram za određeni neterminal ima ulogu
5. <T_List> * <P> <T_List> da prepozna primenu neke od smena sa
6. <T_list> datim neterminalom na levoj strani i upari
7. <P> ( <E> ) neterminal sa ulazom u skladu sa
8. <P> I prepoznatom smenom.
Programski prevodioci © 2006 Dragan Bojić 13 Programski prevodioci © 2006 Dragan Bojić 14
globalna promenljiva IN
Primer predstavlja tekući ulazni Kod za prepoznavanje smene
znak
procedure PROCP: generalno, segmenti koda odgovaraju
case IN of pojedinim gramatičkim simbolima desne
‘I’ : goto P8; strane smene
‘(’ : goto P7; neterminalu odgovara poziv odgovarajućeg
potprogrma, npr. za <E> je PROCE
‘+’, ‘*’, ‘)’, ‘─┤’: REJECT; terminalu generalno odgovara sekvenca u
end case; kojoj se uparuje terminal u smeni sa tekućim
P8: kod za prepoznavanje 8. smene ulazom:
P7: kod za prepoznavanje 7. smene ispituje da li je tekući ulaz jednak neterminalu,
end procedure; ako jeste, procedurom NEXTCHAR se čita sledeći
primena pojedinih znak sa ulaza ()
smena prepoznaje se ako nije, akcijom REJECT se odbija ulazna
koristeći njihove sekvenca
selekcione skupove
Programski prevodioci © 2006 Dragan Bojić 15 Programski prevodioci © 2006 Dragan Bojić 16
Programski prevodioci © 2006 Dragan Bojić 17 Programski prevodioci © 2006 Dragan Bojić 18
3
procedure PROCE_LIST:
case IN of
Kompletan primer ‘+’ : goto P2;
‘)’, ‘ ─┤’ : goto P3;
procedure PROCP: ‘I’, ‘(’, ‘*’ : REJECT;
case IN of end case;
Glavni program:
‘I’ : goto P8;
IN = NEXTCHAR();
call PROCE;
‘(’ : goto P7;
P2: IN = NEXTCHAR();
call PROCT;
Uvod
‘+’,‘*’,‘)’,‘─┤’:REJECT;
if (IN = ‘─┤’)
then ACCEPT;
end case;
call PROCE_LIST;
return;; Konstrukcija parsera od vrha ka dnu
P8: IN = NEXTCHAR();
Selekcioni skupovi i LL(1) gramatike
else REJECT; P3: return;
return;
end if; end procedure;
P7: IN = NEXTCHAR();
Transformacije gramatika u LL(1)
end; call PROCE;
if ( IN = ‘)’)
procedure PROCT_LIST:
procedure PROCE: case IN of
Sintaksno-upravljano prevođenje od
then IN=NEXTCHAR();
case IN of ‘*’ : goto P5;
procedure PROCT:
‘I’, ‘(’: goto P1; ‘+’, ‘)’, ‘ ─┤’ : goto P6;
‘+’,‘*’,‘)’,‘─┤’:REJECT;
case IN of
‘I’, ‘(’: goto P4;
‘I’, ‘(’ : REJECT; vrha ka dnu
end case; end case;
‘+’,‘*’,‘)’,‘─┤’: REJECT;
P1: call PROCT; P5: IN = NEXTCHAR();
end case;
call PROCE_LIST; call PROCP;
P4:call PROCP; call PROCT_LIST;
return;
call PROCT_LIST; return;
end procedure;
return; P6: return;
end procedure; end procedure;
Programski prevodioci © 2006 Dragan Bojić 19 Programski prevodioci © 2006 Dragan Bojić 20
Programski prevodioci © 2006 Dragan Bojić 21 Programski prevodioci © 2006 Dragan Bojić 22
Programski prevodioci © 2006 Dragan Bojić 23 Programski prevodioci © 2006 Dragan Bojić 24
4
Primer Primer
Moramo odrediti poništive neterminale, FIRST i SELECT(1)={a}
FOLLOW skupove: SELECT(2)={b}
1. <A> a<B><C> Pon = { <A>, <B>}
b<B> SELECT(3)=FOLLOW(<A>)={─┤}
2. <A> FIRST(<A>)= {a, b }
3. <A> FIRST (<B>)={a} SELECT(4)={a}
4. <B> a<B>b SELECT(5)=FOLLOW(<B={ b, c, ─┤}
FIRST (<C>)= {b, c }
5. <B>
b<C> FOLLOW (<A>)= {─┤} SELECT(6)={b}
6. <C>
FOLLOW(<B>)=
7. <C> c SELECT(7)={c}
FIRST(<C>) FOLLOW(<A>) {b}= {b, c, ─┤}
FOLLOW(<C>) = Ovo jeste LL(1) gramatika jer ispunjava uslov da smene
FIRST( )FOLLOW(<A>)= {─┤} koje imaju identične leve strane, imaju disjunktne
selekcione skupove.
Programski prevodioci © 2006 Dragan Bojić 25 Programski prevodioci © 2006 Dragan Bojić 26
Primer
Provera za smene 1. , 2. i 3. : Uvod
SELECT(1) SELECT(2) = Konstrukcija parsera od vrha ka dnu
SELECT(1) SELECT(3) = Selekcioni skupovi i LL(1) gramatike
SELECT(2) SELECT(3) = Transformacije gramatika u LL(1)
Provera za smene 4. i 5. :
Sintaksno-upravljano prevođenje od
SELECT(4) SELECT(5)= vrha ka dnu
Provera za smene 6. i 7. :
SELECT(6) SELECT(7)=
Programski prevodioci © 2006 Dragan Bojić 27 Programski prevodioci © 2006 Dragan Bojić 28
Transformacije gramatika za
dovođenje u LL(1) oblik Uklanjanje direktne leve rekurzije
Programski prevodioci © 2006 Dragan Bojić 29 Programski prevodioci © 2006 Dragan Bojić 30
5
Uklanjanje indirektne leve
Uklanjanje direktne leve rekurzije rekurzije
Programski prevodioci © 2006 Dragan Bojić 31 Programski prevodioci © 2006 Dragan Bojić 32
Primer Primer
usvajamo redosled <S>, <E>, <T> i=3, j=1, <A>i = <T>, <A>j = <S>, nema
prva iteracija, i=1, <A>i = <S>, ne ulazi se u unutrašnju petlju, promene
nema direktne leve rekurzije po <S>, nema promene gramatike
i=2, j=1, <A>i = <E>, <A>j = <S>, u unutrašnjoj petlji nema i=3, j=2, <A>i = <T>, <A>j = <E>, menja
promena, u spoljašnjoj eliminacija dir. rekurzije po <E>: se 5. smena
<S> <E>
<E> <T> <E'> <S> <E>
<E'> + <T> <E'> <E> <T> <E'>
<E'>
<T> <E> - <T>
<E'> + <T> <E'>
<T> id <E'>
<T> <T> <E'> - <T>
<T> id
Programski prevodioci © 2006 Dragan Bojić 35 Programski prevodioci © 2006 Dragan Bojić 36
6
Primer Primer
i=3, <A>i = <T>, eliminacija direktne leve i=4, <A>i = <E'>, za j=1, 2, 3 nema promene
rekurzije po <T>: i=5, <A>i = <T'>, za j=1, 2, 3 nema promene, za
<S> <E> j=4, <A>j = <E'>:
<S> <E>
<E> <T> <E'> <E> <T> <E'>
<E'> + <T> <E'> <E'> + <T> <E'>
<E'> <E'>
<T> id <T'> <T> id <T'>
<T'> <E'> - <T> <T'> <T'> +<T> - <T> <T'>
<T'> <T'> - <T> <T'>
<T'>
Programski prevodioci © 2006 Dragan Bojić 37 Programski prevodioci © 2006 Dragan Bojić 38
Leva faktorizacija
Programski prevodioci © 2006 Dragan Bojić 39 Programski prevodioci © 2006 Dragan Bojić 40
Programski prevodioci © 2006 Dragan Bojić 41 Programski prevodioci © 2006 Dragan Bojić 42
7
Sintaksno-upravljano prevođenje od Sintaksno-upravljano prevođenje od
vrha ka dnu vrha ka dnu
Kojim redom rekurz. parser pri prepoznavanju
Kojim redom rekurz. parser pri prepoznavanju smene <A> <B><C> određuje atribute?
smene <A> <B><C> određuje atribute? 5. posle uparivanja sa ulazom <C> saznajemo
nasleđeni atributi X su ulazni parametri za PROCX sintetizovane atribute od <C>
sintetizovani atr. X su izlazni parametri za PROCX 6. kad uparimo celu desnu stranu izračunavamo
1. nasleđeni atributi od <A> su već poznati (prosleđuje sintetizovane atribute od <A>
pozivalac). 7. vraćanje kontrole pozivaocu sa sint. atr. <A>
2. nasleđeni atributi od <B> zavise od nasleđenih od moraju se uvesti ograničenja u pravila
<A> i oni se izračunavaju izračunavanja atributa, da bi parser paralelno sa
3. posle uparivanja <B> sa ulazom saznaćemo konstrukcijom stabla izvođenja (od vrha ka dnu)
sintetizovane atribute <B> računao vrednosti svih atributa).
4. nasleđeni atributi od <C> zavise od nasleđenih od Gramatike koje zadovoljavaju ova pravila nazivaju
<A> i bilo kog atributa <B> se L-atributivne gramatike
Programski prevodioci © 2006 Dragan Bojić 43 Programski prevodioci © 2006 Dragan Bojić 44
Programski prevodioci © 2006 Dragan Bojić 45 Programski prevodioci © 2006 Dragan Bojić 46
8
Primer Preuređena gramatika
1. <S>q ax1 <A>x,y,z <S>q1 {bw} 1. <S>q ax <A>x,y,z <S>q {bw}
(x1 postalo x, q1 postalo q)
w y * z + q1 x x1 q q1 wy*z+q
2. <S>r1 b ay {cw} <A>u,r,x {bv} <S>q b ay {cw} <A>u,r,x {bv}
(r1 postalo q, r postalo q)
wy+3 r1 r vr*x-w u wy+3 vq*x-w uw+2
w+2 <A>x,y,z1 aq {cv} <A>x,z1,u1 <A>u,t,y
3. <A>x,y,z1 aq {cv} <A>x1,z,u1 <A>u,t,y1 (x1 postalo x, z postalo z1, y1 postalo y)
vx-q u3
vx-q x1 x y y1 z1 z <A>x,y,z1 b aq {bx} as2
u3 (t i t1 postali x, s postalo y, s1 postalo z1)
(y,z1) s2
4. <A>t,s,s1 b aq {bt1} as2
t1 t (s,s1) s2
Programski prevodioci © 2006 Dragan Bojić 49 Programski prevodioci © 2006 Dragan Bojić 50
9
Uvod
Programski prevodioci 1 Organizacija tabele simbola
Predstavljanje informacija o objektima
Predstavljanje informacija o opsezima
Lekcija – Konstrukcija tabele imena
simbola Operacije nad tabelom simbola
Programski prevodioci © 2006 Dragan Bojić 3 Programski prevodioci © 2006 Dragan Bojić 4
Programski prevodioci © 2006 Dragan Bojić 5 Programski prevodioci © 2006 Dragan Bojić 6
1
Organizacija tabele simbola: moguće
strukture podataka TS u vidu jednostruko ulančane liste
Primer deklaracija mikroJave:
Jednostruko ulančana (neuređena) lista final int n=10;
class T {…}
Binarno leksički uređeno stablo int a, b, c;
Heš tabela void m(){…}
Programski prevodioci © 2006 Dragan Bojić 7 Programski prevodioci © 2006 Dragan Bojić 8
Programski prevodioci © 2006 Dragan Bojić 9 Programski prevodioci © 2006 Dragan Bojić 10
Zapisi o objektima
Programski prevodioci © 2006 Dragan Bojić 11 Programski prevodioci © 2006 Dragan Bojić 12
2
Informacije o objektu Informacije o objektu: adrese
Globalnih promenljivih
Za sve vrste objekata:
ime, vrsta, tip, sledeći zapis U mjVM se čuvaju u oblasti globalnih podataka:
Dodatne specifične informacije:
Za konstante: vrednost
Za promenljive: adresa, nivo deklarisanosti
(lokalne, globalne)
Za polja klase: pomeraj Svaka mJ promenljiva zauzima po 1 memorijsku reč
Za metode: adresa, broj parametara, lista Adrese promenljivih su relativne u odnosu na početak
formalnih parametara i lokalnih objekata oblasti globalnih podataka
Adrese se dodeljuju sukcesivno
Programski prevodioci © 2006 Dragan Bojić 13 Programski prevodioci © 2006 Dragan Bojić 14
3
Struktura podataka za
Preddeklarisana imena preddeklarisana imena
Posebna lista objekata:
Programski prevodioci © 2006 Dragan Bojić 21 Programski prevodioci © 2006 Dragan Bojić 22
Programski prevodioci © 2006 Dragan Bojić 23 Programski prevodioci © 2006 Dragan Bojić 24
4
Pretraga imena u TS
Programski prevodioci © 2006 Dragan Bojić 25 Programski prevodioci © 2006 Dragan Bojić 26
Programski prevodioci © 2006 Dragan Bojić 29 Programski prevodioci © 2006 Dragan Bojić 30
5
Obrada opsega Obrada opsega
Dva nova metoda u interfejsu tabele simbola: Za zatvaranje opsega:
za otvaranje i zatvaranje opsega
static void closeScope() {
topScope = topScope.outer;
Za otvaranje opsega:
}
static void openScope() {
Scope s = new Scope(); Poziva se kada parser naiđe na kraj opsega
s.outer = topScope; topScope = s; (kraj programa, } od klase ili metoda)
}
Sa vrha steka opsega skida tekući opseg
Poziva se kada parser naiđe na početak
opsega (početak programa, iza imena klase,
ili metoda)
Na vrh steka opsega stavlja novi opseg
Programski prevodioci © 2006 Dragan Bojić 31 Programski prevodioci © 2006 Dragan Bojić 32
Programski prevodioci © 2006 Dragan Bojić 33 Programski prevodioci © 2006 Dragan Bojić 34
Programski prevodioci © 2006 Dragan Bojić 35 Programski prevodioci © 2006 Dragan Bojić 36
6
Primer upotrebe Interfejs tabele simbola (finalno)
class Tab {
static Scope topScope; // current top scope
static int level; // nesting level of current scope
static Struct intTyp; // predeclared types
static Struct charTyp;
static Struct nullTyp;
static Struct noTyp;
static Obj chrObj; // predeclared objects
static Obj ordObj;
static Obj lenObj;
static Obj noObj;
static Obj insert (int kind, String name, Struct typ);
static Obj find (String name);
static void openScope();
static void closeScope();
}
Programski prevodioci © 2006 Dragan Bojić 37 Programski prevodioci © 2006 Dragan Bojić 38
7
Semantička analiza – Tipovi podataka
Predstavljanje tipova
class Struct {
static final int // kinds of types
None = 0, Int = 1, Char = 2, Arr = 3; Class = 4;
int kind; // None, Int, Char, Arr, Class
Struct elemTyp; // Arr: element type
int n; // Class: number of fields
Obj fields; // Class: list of fields
}
dva tipa su ekvivalentna ako su reprezentovana istim čvorom tipa u grafu (tj. imaju isto ime).
a i b imaju isti tip.
u Mikrojavi ekvivalentnost tipova je po imenu, sa izuzetkom nizova: dva niza su ekvivalentna
ako su im tipovi elemenata ekvivalentni.
class Struct {
...
// checks, if two types are compatible (e.g. in comparisons)
public bool CompatibleWith (Struct other) {
return this.Equals(other) ||
this == Tab.nullType && other.IsRefType() ||
other == Tab.nullType && this.isRefType();
}
// checks, if this can be assigned to dest
public bool AssignableTo (Struct dest) {
return this.Equals(dest) ||
this == Tab.nullType && dest.IsRefType() ||
kind == Kinds.Arr && dest.kind == Kinds.Arr && // for len()
dest.elemType == Tab.noType;
}
// checks, if two types are equal (structural equivalence for array,
// name equivalence otherwise)
public bool Equals (Struct other) {
if (kind == Kinds.Arr)
return other.kind == Kinds.Arr && elemType.Equals(other.elemType);
return other == this;
}
public bool IsRefType() { return kind == Kinds.Class || kind = Kinds.Arr; }
}
Bilo koja linija koda sadrži se unutar jedne programske jedinice ili više programskih jedinica koje
definišu opseg važenja imena. Većina savremenih jezika je blokovski strukturirana - dozvoljava
da opseg važenja imena bude ugnježden.
linija koda
Tekući opseg važenja je opseg važenja imena definisan trenutnim najdubljim ugnježdenjem.
Otvoreni opsezi su tekući opseg važenja i svi opsezi koji okružuju tekuću liniju koda.
Zatvoreni opsezi su opsezi važenja imena definisani bilo kojom programskom jedinicom koja ne
okružuje posmatranu liniju izvornog koda.
Tekući opseg važenja nije fiksan već s menja dinamički zavisno od tumačenja.
Kod pojedinačnih tabela simbola za svaki opseg važenja stek mehanizam je pogodan za
realizaciju. Pri otvaranju novog opsega stavlja se tabela simbola na stek, a po zatvaranju opsega
skida se sa steka. Umesto cele tabele može se koristiti i samo ukazatelj na tabelu.
Nedostaci ovog pristupa su:
i) Ako želimo da pristupimo nekom nelokalnom imenu moramo pristupati većem broju tabela
simbola, pogotovo ako želimo da pristupimo nekom globalnom imenu.
ii) Ako su tabele realizovane kao heš tabele, za svaki opseg važenja se rezerviše memorijski
prostor za tabelu simbola. Na duboko ugnježdenim nivoima gde ima malo imena gubitak prostora
je najveći (nije veliki problem danas kada računari imaju puno memorije). Ovaj problem se ne
javlja ako su tabele organizovane u obliku binarnog stabla.
Sva imena koja se pojave u toku prevodjenja se smeštaju u jedinstvenu tabelu simbola. Pošto se
može desiti da u različitim opsezima važenja imamo ista imena, svakom imenu se pridruži opseg
važenja za koji je to ime definisano. (Posebna globalna promenljiva „broji” trenutno otvorene
opsege, inkrementira se pri otvaranju opsega, dekrementira pri zatvaranju).
Primer:
{ int M, A, L;
…
{float X, Y;
…
}
{char A, C, M;
…
/* trenutna pozicija*/
}
}
Jedinstvena tabela se može realizovati kao heš tabela
A(2 ) L(1) A(1)
C(2 ) M(1)
M(2)
heš tabela
Prednosti heš tabele simbola su:
i) Brži je pristup simbolu jer se pretražuje samo jedna tabela, i obično su ti traženi simboli na
početku lanaca.
ii) Memorijski prostor je efikasnije iskorišćen jer imamo samo jedno zaglavlje tabele, ali je taj
dobitak umanjen zato što se uz svako ime dodaje prostor za opseg važenja.
Realizacija jedinstvene tabele simbola korišćenjem binarnog, leksikografski
uređenog, stabla
Kod ovog načina realizacije tabele simbola, svi simboli formiraju stablo. Ubacivanje novih simbola
pri otvaranju novog opsega važenja i izbacivanje simbola pri zatvaranju opsega važenja zahteva
pretraživanje stabla do listova, što nije baš efikasno pa se ne preporučuje ova struktura podataka
ukoliko imamo jednu tabelu za sve opsege važenja. Binarno stablo se može koristiti kada imamo
pojedinačne tabele za sve opsege važenja.
Primer:
{ int M, A, L;
…
{float X, Y;
…
}
{char A, C, M;
…
/* trenutna pozicija*/
}
}
M(1)
A(1) L(1)
U tom slučaju na vrhu steka se nalaze simboli iz tekućeg opsega važenja, i razdvojeni su od
simbola iz predhodnog opsega važenja sa markerom. Kada se opseg zatvara sve što se nalazi na
steku iznad markera se skida sa steka. Ovakva tabela je korišćena u ranim verzijama prevodilaca.
markeri
Izvršno okruženje
Uvod
oblast programskog
koda
0
Slika 1
Za oblast steka najčešće se koristi procesorski stek (mada nije obavezno, na primer kada stek
procesora nije u operativnoj memoriji).
S obzirom da se veličine steka i oblasti dinamičkih podataka menjaju u toku izvršavanja programa,
nije određena fiksna granica između ove dve oblasti već se svaka od njih može proširivati po potrebi
do trenutka njihovog eventualnog međusobnog susreta.
U ovom kontekstu termin statički generalno se koristi za veličine koje su poznate u vreme
prevođenja programa (pre njegovog izvršavanja), dok se termin dinamički odnosi na veličine koje
nisu poznate u vreme prevođenja, to jest, menjaju se tokom izvršavanja programa.
Memorijske klase promenljivih
Vrednost neke promenljive u toku izvršavanja programa može se čuvati na različitim mestima:
o u procesorskom registru (takozvane registarske promenljive);
o u oblasti statičkih podataka (takozvane statičke promenljive);
o u oblasti steka (takozvane automatske promenljive) ili
o u oblasti dinamičkih podataka (takozvane dinamičke promenljive).
Drugim rečima, promenljive poseduju različite memorijske klase (engl. storage class).
Kod mikroprocesora Intel 8086 za rad sa stekom koriste se 16-bitni registri SP (Stack Pointer) i BP (Base
Pointer) i instrukcije navedene u tabeli 1
Tabela 1
Instrukcija Objašnjenje
PUSH r/m stavlja vrednost operanda na stek
POP r/m skida vrednost sa vrha steka i dodeljuje je operandu
CALL r/m stavlja tekuću vrednost brojača naredbi IP na stek i vrši skok na adresu
specificiranu operandom
RET [c] SP uvećava za vrednost specificiranu operandom c; skida vrednost sa vrha steka i
dodeljuje brojaču naredbi IP
ADD dst, src Sabira vrednost operanda src sa operandom dst i rezultat smešta u dst
SUB dst, src Oduzima vrednost operanda src sa operandom dst i rezultat smešta u dst
MOV dst, src Dodeljuje operandu dst vrednost operanda src
Načini adresiranja koje koristi 8086 mikroprocesor navedeni su u tabeli 2. Stek raste prema nižim
memorijskim lokacijama i registar SP ukazuje na poslednju popunjenu lokaciju. Adresiranje je bajtovsko, a
na steku se čuvaju isključivo 16-bitne veličine. Mikroprocesor 8086 poseduje i 16-bitne registre opšte
namene AX, BX, CX i DX i 16-bitne indeksne registre SI i DI.
Tabela 2
Primeri sintakse Objašnjenje Naziv
100 vrednost operanda je neposredno
100
labela adresa operanda je memorijsko direktno
[100] zadata vrednost
AX vrednost operanda je registarsko direktno
BP sadržaj registra
[BP] adresa operanda je registarsko indirektno
[SI] sadržaj nekog od
[DI] registara BP, SI, DI.
[BP+4] adresa operanda je bazno ili indeksno
[DI-100] sadržaj registra
[SI-20] konstanta
Primer
Rešenje
r=s
Pretpostavimo da je promenljivoj r dodeljen procesorski registar SI, da je adresa promenljive s u
statičkoj oblasti (određena u vreme prevođenja programa) jednaka 200. Prevodilac za naredbu
dodele
r = s;
generiše sledeći asemblerski kod:
MOV SI,[0200]
Izvorišni (desni) operand zadat je memorijskim direktnim, a odredišni registarskim adresiranjem.
a=*d;
Pod pretpostavkom da je a jedina automatska (lokalna) promenljiva u posmatranoj proceduri, njen
pomeraj u odnosu na registar BP će biti -2 i biće poznat u vreme prevođenja programa
Takođe možemo pretpostaviti da je adresa promenljive d u statičkoj oblasti podataka jednaka 202.
U vreme izvršavanja, pozivom funkcije malloc, dodeljuje se memorija u dinamičkoj oblasti podataka
neimenovanoj dinamičkoj celobrojnoj promenljivoj i adresa te promenljive upisuje u promenljivu d.
Posle toga neimenovanoj dinamičkoj promenljivoj može se pristupati preko ukazivača d (u C
programu se piše *d što označava vrednost promenljive na koju ukazuje d).
Prema tome, naredba
a = *d;
kopira sadržaj neimenovane promenljive u promenljivu a. Ovoj naredbi odgovara sledeći asemblerski
kod:
MOV BX,[0202] ; u BX ide sadržaj promenljive d
MOV AX,[BX] ; u AX ide sadržaj *d
MOV [BP-02],AX ; a:=*d
Korišćenje registra AX pri ovom transferu je bilo neophodno, jer ne postoji instrukcija transfera iz
memorije u memoriju (na primer MOV [BP-02], [BX]).
Pri svakom pozivu procedure u toku izvršavanja programa, na vrh steka se stavlja blok podataka koje
koristi pozvana procedura u svom radu. Ovaj blok zove se aktivacioni zapis procedure ili okvir
(engl. frame).
AZ na steku ostaje sve dok pozvana procedura ne vrati kontrolu pozivaocu, kada se AZ pozvane
procedure skida sa vrha steka.
Primer
Ukoliko, na primer iz procedure X usledi poziv procedure Y, a iz ove procedure poziv procedure Z,
na vrhu steka će biti aktivacioni zapis za Z, ispod njega aktivacioni zapis za Y, a ispod njega
aktivacioni zapis za X (slika 2).
aktivacioni zapis
procedura Y procedure Y
...
aktivacioni zapis
CALL Z procedure Z
SP
procedura Z
Slika 2
Kada usledi povratak iz procedure Z sa steka se skida vršni aktivacioni zapis, po povratku iz Y drugi, a po
povratku iz X u glavni program i treći aktivacioni zapis.
viže
memorijske
adrese
kontrolna veza aktivacioni zapis
pozivaoca
stvarni parametri
povratna adresa
aktivacioni zapis
kontrolna veza pozvane procedure
BP
lokalne promenljive
niže
memorijske
adrese
SP
Slika 3
Registar SP u svakom trenutku ukazuje na vrh steka. Registar BP ukazuje na polje kontrolne (ili
dinamičke) veze i služi za pristup stvarnim parametrima i lokalnim promenljivama procedure.
Stvarnim parametrima pristupa se baznim adresiranjem [BP+pomeraj] gde je vrednost pomeraja za
svaki od parametara poznata u vreme prevođenja.
Lokalnim promenljivama pristupa se baznim adresiranjem [BP-pomeraj] gde je vrednost pomeraja
takođe poznata u vreme prevođenja.
U polju kontrolne veze čuva se adresa istoimenog polja u aktivacionom zapisu pozivaoca (drugim
rečima, to je ukazivač na istoimeno polje u aktivacionom zapisu pozivaoca). Radi se, u stvari, o
staroj vrednosti koju je registar BP imao pre poziva, i koja će biti vraćena u ovaj registar po povratku
iz pozvane procedure. Kontrolne veze svih aktivacionih zapisa koji se u određenom trenutku nalaze
na steku čine lanac kontrolnih veza.
Sekvenca pozivanja
Niz aktivnosti koje pri pozivu neke procedure izvršavaju pozivalac i pozvana procedura da bi uspostavili
aktivacioni zapis pozvane procedure naziva se sekvenca pozivanja.
Aktivnosti započinje procedura-pozivalac:
Na stek se redom stavljaju stvarni parametri za pozvanu proceduru.
Izvršava se CALL naredba koja na stek stavlja povratnu adresu i prenosi kontrolu pozvanoj proceduri
Pozvana procedura:
Na stek stavlja sadržaj registra BP (radi se o polju kontrolne veze).
Sadržaj registra SP, koji u tom trenutku ukazuje na kontrolnu vezu, kopira u BP.
Od sadržaja registra SP oduzima broj N koji je poznat u vreme prevođenja. Radi se o broju memorijskih
lokacija potrebnih za smeštaj lokalnih promenljivih. Na ovaj način se na steku alocira potreban prostor
za lokalne promenljive.
Nakon završetka sekvence pozivanja, izvršava se kod pozvane procedure za inicijalizaciju lokalnih
promenljivih itd.
Sekvenca povratka
Primer
Napisati 80x86 asemblerski potprogram ekvivalentan datom programu na C-u. Koja sekvenca asemblerskog
koda odgovara pozivu primer(10,20) u glavnom programu?
void primer(int a,b) {
int c;
c=a;
}
Rešenje
Poziv primer(10,20) prevodi se sa:
; smeštanje drugog parametra na stek
MOV AX,20
PUSH AX
; smeštanje prvog parametra na stek
MOV AX,10
PUSH AX
; poziv procedure primer
CALL primer
; skidanje parametara sa steka
; alternativa navedenim je operacija ADD SP,4
POP CX
POP CX
; kraj poziva
Napomene:
1. Ukazivač steka SP se pri svakom skidanju podatka sa steka uvećava za dva, a pri svakom smeštanju na
stek umanjuje za 2, jer su na steku 16-bitne veličine, a adresa je bajtovska.
2. Glavni program u C-u je funkcija main kojoj takođe odgovara na steku aktivacioni zapis.
Kod za proceduru primer je:
; smeštanje sadržaja BP u polje kontrolne veze
PUSH BP
; nova vrednost BP treba da ukazuje na kontrolnu vezu
MOV BP,SP
; alociranje prostora za lokalnu promenljivu c
;
SUB SP,2
; u AX ide vrednost stvarnog parametra a
MOV AX,[BP+04]
; u lokalnu promenljivu c ide vrednost iz AX
MOV [BP-02],AX
; oslobađanje prostora dodeljenog promenljivoj c
MOV SP,BP
; restauracija vrednosti BP iz kontrolne veze
POP BP
; povratak u pozivajuću proceduru
RET
adresa sadržaj
[BP+6] 20 (vrednost parametra b)
[BP+4] 10 (vrednost parametra a)
[BP+2] adresa instrukcije POP CX
[BP+0] vrednost BP pozivaoca
n=2 BP
[BP-2] vrednost parametra c
SP
Slika 4
Diskusija
1. U prethodnom primeru redosled smeštanja na stek stvarnih parametara je takav da na stek prvo ide krajnje
desni parametar. Ova konvencija odgovara C programima kod kojih se procedura može pozivati sa
promenljivim brojem parametara. Ovaj redosled obezbeđuje da se uvek zna da je pomeraj za prvi
parametar (pod pretpostavkom da je celobrojni) +2, za drugi +4 itd.
2. Postavlja se pitanje da li je registar BP neophodan za pristup parametrima i lokalnim promenljivama
procedure. Drugim rečima, da li se za pristup može koristiti bazno adresiranje sa registrom SP i
odgovarajućim pomerajem (koji bi u ovom slučaju bio uvek pozitivan) i time izbeći rezervacija
posebnog registra?
Poseban registar je ipak neophodan iz sledećeg razloga: vrednost baznog registra ne sme se menjati
tokom izvršavanja procedure da bi se za pristup određenoj promenljivoj mogla koristiti uvek ista
vrednost pomeraja, izračunata još u vreme prevođenja. Registar SP ne zadovoljava ovaj zahtev u šta se
možemo uveriti na jednostavnom primeru. Neka u proceduri A postoji poziv primer(X,1) gde je X
lokalna promenljiva procedure A. Tokom sekvence pozivanja, na stek će biti smeštena prvo vrednost
desnog parametra - konstanta 1. Potom treba da usledi smeštanje prvog parametra što znači da treba
pristupiti promenljivoj X koristeći vrednost pomeraja izračunatu u toku prevođenja. Međutim,
smeštanjem konstante 1 na stek vrednost SP je umanjena za 2, i time je promenjena vrednost potrebnog
pomeraja za X. Na vrh steka se, takođe, smeštaju međurezultati izračunavanja složenijih aritmetičkih
izraza jer oni imaju privremen karakter - samo dok se ne izračuna krajnji rezultat.
3. Postavlja se takođe pitanje: zašto se lokalne promenljive alociraju na steku umesto da se koristi statička
oblast memorije? Programski jezici koji ne dozvoljavaju rekurzivne procedure (primer je FORTRAN)
zaista mogu statički alocirati lokalne promenljive a stek koristiti samo za čuvanje povratnih adresa pri
pozivu procedura. Međutim, C i Pascal koji dozvoljavaju rekurziju moraju obezbediti način da u
određenom trenutku izvršavanja programa jednoj istoj proceduri odgovara veći broj različitih
aktivacionih zapisa u memoriji.
Rekurzija: primer
Data je C funkcija proba. Pratiti tok izvršavanja poziva fakt(3) i odrediti izgled procesorskog steka u
trenutku neposredno pre prvog povratka iz funkcije.
int fakt(int n) {
return (n>0)?(n * fakt(n-1)):1;
}
Rešenje
Razmotrimo aktivnosti koje se odvijaju tokom izvršavanja poziva fakt(3):
Iz glavnog programa poziva se funkcija fakt sa parametrom n = 3. Pri ovome se na steku formira
aktivacioni zapis funkcije fakt. Prenos parametra je po vrednosti, pa pozivalac pre naredbe CALL na
stek stavlja vrednost 3.
U funkciji fakt, pre nego što se izvrši return naredba mora se izračunati vrednosti izraza navedenog
u okviru te naredbe. Radi se o uslovnom izrazu. S obzirom da je n >0 potrebno je izračunati proizvod n
* fakt(n-1). Da bi se odredio drugi faktor proizvoda, poziva se funkcija fakt, ovaj put sa vrednošću
parametra n - 1 = 2. Ovaj poziv se realizuje kao i svaki drugi poziv funkcije, formiranjem novog
aktivacionog zapisa na steku. Ovaj aktivacioni zapis uključuje i parametar, vrednost 2 tako da za novu
aktivaciju funkcije fakt važi da je n =2.
Kontrola izvršavanja se ponovo prenosi na početak funkcije fakt. Pre povratka iz funkcije, ponovo se
mora izračunati vrednost drugog faktora proizvoda navedenog u naredbi return. Stoga ponovo sledi
poziv funkcije fakt, ovaj put sa vrednošću parametra 1. Formira se novi aktivacioni zapis na vrhu steka
koji u polju parametra ima vrednost 1, tako da za novu aktivaciju funkcije važi n = 1.
Izvršavajući ponovo funkciju fakt od početne naredbe, ustanovljava se da je n >0 te stoga opet treba
izračunati drugi faktor proizvoda n * fakt(n-1). Zato sledi poziv fakt(0) pri čemu se na vrhu
steka formira novi aktivacioni zapis.
U novoj aktivaciji važi da je n =0 pa nije ispunjen uslov n>0. Zato je vrednost uslovnog izraza jednaka 1.
U trenutku neposredno pred povratak iz ove aktivacije funkcije fakt, na steku se još uvek nalaze sva
četiri aktivaciona zapisa funkcije fakt (slika 5). Po izvršenju naredbe return, sa vrha steka skida se
poslednji stavljeni aktivacioni zapis. Funkcija fakt može da prosledi rezultat pozivaocu u nekom
procesorskom registru, ili alternativno preko steka. U ovom drugom slučaju u okviru polja parametara
potrebno je rezervisati lokaciju za smeštaj rezultata (na slici 5 je prikazan slučaj kada se rezultat vraća u
registru).
Po povratku iz četvrte u treću aktivaciju funkcije fakt računa se proizvod vrednosti parametra n=1 i
vraćenog rezultata fakt(0) = 1 i dobijeni rezultat 1 vraća pozivaocu, pri čemu se uklanja aktivacioni
zapis sa vrha steka.
Na isti način, druga aktivacija računa proizvod parametra n=2 i vraćenog rezultata fakt(1)=1 i rezultat
2 vraća pozivaocu, pri čemu se skida naredni aktivacioni zapis sa vrha steka.
Prva aktivacija računa konačni rezultat 3 * 2 = 6 i vraća ga glavnom programu, pri čemu se sa steka
skida i poslednji aktivacioni zapis funkcije fakt. Time je u potpunosti obrađen poziv fakt(3).
Aktivacioni zapis za main
n=3
povratna adresa Aktivacioni zapis za fakt(3)
n=2
povratna adresa Aktivacioni zapis za fakt(2)
n=1
povratna adresa Aktivacioni zapis za fakt(1)
n=0
povratna adresa Aktivacioni zapis za fakt(0)
BP,SP
Slika 5
Polje pristupne veze neke procedure ukazuje na AZ (preciznije, na polje kontrolne veze toga zapisa)
neposredno okružujuće procedure (u listingu programa). Ova procedura, u opštem slučaju, razlikuje
se od procedure pozivaoca.
viže
memorijske aktivacioni zapis
adrese procedure u kojoj
je deklarisana
pozvana procedura
. . .
aktivacioni zapis
pozivaoca
stvarni parametri
pristupna veza
povratna adresa
aktivacioni zapis
pozvane procedure
kontrolna veza
BP
niže
lokalne promenljive
memorijske
adrese
SP
Slika 6
ii) Deklaracija B je ugneždena u istoj proceduri X (ili u glavnom programu) kao i deklaracija
A; tada važi da su A i B na istom leksičkom nivou ugneždavanja.
procedure X;
procedure B; begin...end;
procedure A; begin B end;
begin ... end.
U ovom slučaju, pristupna veza A kopira se u polje pristupne veze B, tako da obe ukazuju
na AZ(X).
iii) Leksički nivo ugneždavanja A je veći od nivoa B. Razlika leksičkih nivoa A i B označena
sa N može da bude veća od jedan;
procedure X
procedure B;
procedure Y
procedure A; begin B end;
begin A; end;
begin Y; end;
begin B; end;
u ovom slučaju potrebno je slediti lanac od pristupnih veza počev od pristupne veze A i u
polje pristupne veze za B iskopirati sadržaj N-tog polja u lancu. (Za N=1 to je polje na
koje ukazuje polje pristupne veze za A, itd.)
Sekvenca pozivanja
Sekvenca povratka
Primer
Odrediti 80x86 asemblerski ekvivalent datog Pascal programa . Kako izgleda procesorski stek u trenutku
neposredno pre prvog povratka iz procedure?
program glavni;
procedure jedan
var local1: integer;
procedure tri; forward;
procedure dva;
begin {dva}
tri {II slučaj kod formiranja pristupne veze}
end; {dva}
procedure tri;
begin {tri}
local1:=10;
end; {tri}
begin {jedan}
dva {I slučaj kod formiranja pristupne veze}
end; {jedan}
begin {glavni}
jedan
end. {glavni}
Rešenje
procedura dva
; sadržaj registra BP definise sadržaj polja kopntrolne veze
PUSH BP
; BP ukazuje na polje kontrolne veze
MOV BP,SP
; počinje sekvenca poziva procedure tri
; uspostavlja se sadržaj polja kontrolne veze u aktivacionom
zapisu
; procedure tri,
; kopiranjem sadržaja polja kontrolne veze u akt. zapisu procedure
dva
; (ii slučaj algoritma)
PUSH [BP+04]
; poziv procedure tri
CALL tri
; sekvenca povratka iz procedure dva
; dealocira se deo aktivacionog zapisa iza polja kontrolne veze
MOV SP,BP
; restaurira se sadržaj registra BP potreban pozivaocu i dealocira
; polje kontrolne veze sa steka
POP BP
; povratak pozivaocu uz dealociranje polja pristupne veze
RET 0002
procedura tri
; definisanje polja kontrolne veze
PUSH BP
; BP ukazuje na polje kontrolne veze
MOV BP,SP
; prevod naredbe local1 := 10
MOV DI,[BP+04]
MOV [DI-02],10*
; sekvenca povratka
MOV SP,BP
POP BP
RET 0002
procedura jedan
; definisanje polja kontrolne veze
PUSH BP
; BP ukazuje na polje kontrolne veze
MOV BP,SP
; alociranje prostora za promenljivu local1
SUB SP,+02
*
Na 8086 asembleru sintaksa ove instrukcije glasi MOV SS:WORD PTR [DI-2],10
SS: označava da se pristupa segmentu steka (podrazumevana vrednost za registar DI je segment podataka DS),
WORD PTR označava da se prenosti jedna reč, a ne jedan bajt.
; definisanja pristupne veze za proceduru dva (slučaj i)
PUSH BP
; poziv procedure dva
CALL dva
; sekvenca povratka
MOV SP,BP
POP BP
RET
glavni program - sekvenca poziva
; polje pristupne veze nije potrebno proceduri jedan pošto su
; promenljive glavnog programa statički alocirane
CALL jedan
U vreme izvršavanja procedure tri, izgled procesorskog steka je prikazan na slici 7. Pristupna veza u
aktivacionom zapisu procedura dva i tri ukazuje na početak aktivacionog zapisa procedure jedan.
Promenljivoj local1 prostor je dodeljen na steku u aktivacionom zapisu procedure jedan. Glavni program ne
poseduje aktivacioni zapis jer se promenljive glavnog programa alociraju statički, pa zbog toga ni procedura
jedan ne poseduje pristupnu vezu. Deo programa koji upisuje vrednost 10 u promenljivu local1 u proceduri
tri ima sledeći izgled:
MOV DI,[BP+4]
MOV [DI-2], 10*
Prva naredba dodeljuje registru DI sadržaj polja pristupne veze, odnosno adresu polja kontrolne veze u
aktivacionom zapisu procedure jedan. Sada se u drugoj naredbi promenljivoj local1 pristupa indeksnim
adresiranjem uz korišćenje registra DI i pomeraja poznatog u vreme prevođenja programa.
viže
memorijske
adrese
povratna adresa
aktivacioni zapis
kontrolna veza procedure jedan
local1
pristupna veza
aktivacioni zapis
povratna adresa procedure dva
kontrolna veza
pristupna veza
niže
aktivacioni zapis
memorijske povratna adresa procedure tri
adrese
kontrolna veza
BP, SP
Slika 7
Diskusija
1. Kod C-a se problem pristupa nelokalnim promenljivama ne javlja, jer su sve promenljive kojima se
pristupa u proceduri ili lokalne (kada im se pristupa baznim adresiranjem uz korišenje registra BP) ili su
globalne, statički alocirane (pa su ima adrese poznate u vreme prevođenja programa).
2. Da li je pristupna veza neophodna ili se za pristup nelokalnim promenljivama mogu koristiti kontrolne
veze? U cilju nalaženja odgovora osmatrajmo opet program iz tačke a). U slučaju korišćenja kontrolnih
veza, naredba dodele u proceduri tri mogla bi se realizovati na sledeći način:
; u DI ide sadržaj polja kontrolne veze aktivacionog zapisa
procedure tri
MOV DI,[BP]
; u DI ide sadržaj polja kontrolne veze aktivacionog zapisa
procedure dva
MOV DI,[DI]
; DI ukazuje na kontrolnu vezu procedure jedan pa se uz poznati
; pomeraj pristupa promenljivoj local1
MOV [DI-2],10
Razmotrimo, međutim slučaj koji bi nastao da procedura jedan pozove proceduru tri posle završetka
procedure dva. Pošto je procedura dva završena, sa steka su uklonjeni aktivacioni zapisi procedura jedan i tri
pa je na steku ostao samo aktivacioni zapis procedure jedan. Pri ponovnom pozivu procedure tri, na vrh
steka se stavlja aktivacioni zapis za ovu novu aktivaciju procedure tri. Sada bi naredba dodele morala biti
realizovana na sledeći način uz korišćenje kontrolnih veza:
; u DI ide sadržaj polja kontrolne veze procedure tri
MOV DI,[BP]
; DI ukazuje na kontrolnu vezu procedure jedan pa se uz
; poznati pomeraj pristupa promenljivoj local1
MOV [DI-2],10
Prema tome, potreban je jedan nivo indirekcije manje jer se aktivacioni zapis procedure jedan sada nalazi na
steku neposredno ispod aktivacionog zapisa procedure tri. Drugim rečima, naredba dodele u proceduri tri se
različito prevodi u zavisnosti sa kog mesta je pozvana procedura tri što je nedopustivo. Pristupna veza je, u
skladu sa tim, neophodna.
Pokazivači displeja mogu se čuvati u registrima procesora, u statičkoj zoni memorije ili u
aktivacionom zapisu procedure.
Primer
program glavni;
procedure jedan;
var local1: integer;
procedure dva;
procedure tri;
begin {tri}
local1:=10
end; {tri}
begin {dva}
tri
end; {dva}
begin {jedan}
dva
end; {jedan}
begin {glavni}
jedan
end. {glavni}
procedura tri iz tačke b) postavke koja se nalazi na leksičkom nivou tri (glavni program je na nivou
nula), imala bi tri1 pokazivača u displeju kako je prikazano na slici 8.
STEK
Aktivacioni zapis
procedure jedan
Aktivacioni zapis
Display1
Display2 procedure dva
Display3 BP
Aktivacioni zapis
Displej za proceduru tri procedure tri
Slika 8
Pod pretpostavkom da su pokazivači statički alocirani, naredbi local1:=10 bi odgovarao sledeći
segment asemblerskog koda:
MOV DI, Display1 ; u SI ide adresa aktivacionog zapisa procedure
jedan
MOV [DI-4], 10 ; u promenljivu local1 se upisuje 10
; (pomeraj se zna u vreme prevođenja)
Prednost displeja u odnosu na lanac pristupnih veza je u efikasnijem pristupu nelokalnim
promenljivama; nedostatak je u povećanoj režiji u sekvenci pozivanja procedure, kada je potrebno
definisati sadržaj displeja.
Pri svakom pozivu i povratku ažuriraju se registri displeja da odgovaraju trenutno aktivnoj proceduri
(onoj čiji je AZ na vrhu steka).
Procedura na nivou ugneždavanja N koristi N registara displeja.
U svakoj situaciji dovoljno je ažurirati jedan registar displeja (to je onaj koji odgovara nivou
ugeždavanja N na kome se nalazi pozvana procedura P):
o pri pozivu, stari sadržaj displej registra N čuva se u akt. zapisu procedure P
o u displej registar N stavlja se pokazivač na upravo formirani AZ(P)
o pri povratku iz P, sačuvana vrednost displej registra N restaurira se.
1
Dovoljna su i dva pokazivača jer se lokalnim promenljivama može pristupiti koristeći registar BP. Treći pokazivač
koristi se pri uspostavljanju displeja prilikom sekvence pozivanja.
Poređenje sa pristupnim vezama na datom primeru
Naslednici procesora 8086 imaju dve mašinske instrukcije za podršku izvršnoj organizaciji memorije kod
viših programskih jezika:
ENTER Size, Level
LEAVE
Struktura aktivacionog zapisa za ENTER i LEAVE
Na slici * prikazan je izgled aktivacionog zapisa koji odgovara ovim naredbama. Za pristup nelokalnim
promenljivama koristi se displej alociran u aktivacionom zapisu procedure.
više
memorijske
adrese aktivacioni zapis
pozivaoca
stvarni parametri
povratna adresa
kontrolna veza
BP
aktivacioni zapis
pozvane procedure
displej
niže lokalne promenljive
memorijske
adrese SP
Naredba ENTER realizuje deo sekvence pozivanja koji izvršava pozvana procedura.
Ova naredba ima dva operanda.
o Size (16-bitna veličina) definiše koliko memorije treba alocirati u aktivacionom zapisu za
lokalne promenljive.
o Level (8-bitna veličina) predstavlja leksički nivo pozvane procedure.
Ova naredba izvršava se kao prva naredba pozvane procedure na sledeći način:
1. Sadržaj registra BP ide na stek (čime se definiše polje kontrolne veze)
2. U registar BP upisuje se sadržaj registra SP (čime je BP postavljen da ukazuje na polje kontrolne
veze).
3. Ako je Level = 0 preskače se sledeći korak (Level = 0 važi za procedure u C-u kod koga se ne javlja
problem pristupa nelokalnim promenljivim).
4. Označimo vrednost Level -1 sa N, a sadržaj polja kontrolne veze sa A. Na stek se smešta N reči koje
se kopiraju redom počev od lokacije A-2 ka nižim memorijskim lokacijama. Potom se na stek smešta
adresa polja kontrolne veze. Ovime je uspostavljen displej pozvane procedure.
5. Registar SP umanjuje se za vrednost operanda Size čime se alocira prostor za lokalne promenljive
pozvane procedure.
Naredba LEAVE
Naredba LEAVE realizuje deo sekvence povratka koji izvršava pozvana procedura.
Ova naredba neposredno prethodi naredbi RET i izvršava se na sledeći način:
1. Sadržaj registra BP kopira se u registar SP. Ovime se dealocira sa steka deo aktivacionog zapisa
pozivaoca ispod kontrolne veze.
2. Sa steka se skida sadržaj polja kontrolne veze i smešta u registar BP. Time je BP namešten za
pozivaoca, a polje kontrolne veze pozvane procedure je uklonjeno sa steka.
Primer
Asemberski kod koji odgovara datom Pascal programu bez korišćenja naredbi ENTER i LEAVE dat je u
ranijem primeru. Za dati Pascal program, asemblerski ekvivalent uz korišćenje naredbi ENTER i LEAVE bi
imao sledeći izgled:
procedura dva
; nema lokalnih promenljivih a leksički nivo je jednak 2
ENTER 0,2
; poziv procedure tri
CALL tri
; sekvenca povratka iz procedure dva
; dealocira se deo aktivacionog zapisa iza polja kontrolne veze
LEAVE
; povratak pozivaocu uz dealociranje polja pristupne veze
; nema stvarnih parametara za dealociranje pa je upotrebljena
; naredba RET bez argumenta
RET
procedura tri
; nema lokalnih promenljivih a leksički nivo je jednak 3
ENTER 0,3
; prevod naredbe local1 := 10
; u DI se kopira pokazivač koji odgovara leksičkom nivou 1
MOV DI,[BP-02]
; u kativacionom zapisu procedure jedan displej ima samo jedan
pokazivač
; promenljiva local1 nalazi se odmah ispod toga pokazivača
MOV [DI-04],10*
; sekvenca povratka
LEAVE
RET
procedura jedan
; rezervišu se dva bajta za promenljivu local1
; leksički nivo je jednak 1
ENTER 2,1
; poziv procedure dva
CALL dva
; sekvenca povratka
LEAVE
RET
*
Na 8086 asembleru sintaksa ove instrukcije glasi MOV SS:WORD PTR [DI-2],10
SS: označava da se pristupa segmentu steka (podrazumevana vrednost za registar DI je segment podataka DS),
WORD PTR označava da se prenosti jedna reč, a ne jedan bajt.
Generisanje međukoda
Prednosti upotrebe međukoda nad direktnim generisanjem mašinskog koda iz izvornog programa:
prednji kraj kompajlera (sintaksno-semantički analizator i generator međukoda) su mašinski nezavisni.
Kompajler se lako prilagođava novoj mašini izmenom zadnjeg kraja kompajlera (generatora mašinskog
koda iz međukoda).
ako prednji krajevi kompajlera za različite jezike generišu isti međukod, moguće je za ciljnu mašinu
napraviti samo jedan generator koda za sve jezike.
optimizaciju je moguće sprovoditi na međukodu, čime se pravi mašinski nezavistan optimizator.
sintaksno stablo ili aciklički graf (u grafu se eliminišu ponavljanja usled zajedničkih podizraza)
postfiksna notacija
troadresni kod
graf toka kontrole na nivou bazičnih blokova
SSA – Static Single Assignment Form
Akcija {MKLEAF}x,y, z konstruiše čvor – list sintaksnog stabla, pri čemu x (nasl. atribut) označava tip čvora,
a y (nasleđ. atribut) ime promenljive koja je predstavljena tim čvorom (ili pointer u tabelu simbola gde se
nalazi ta promenljiva). Sintetizovani atribut z je pokazivač na konstruisani čvor.
Akcija {MKNODE}a,b,c,d konstruiše unutrašnji čvor sintaksnog stabla, a (nasl. atr.) označava operator, a b i c
(nasl. atr.) pokazivače na čvorove naslednike. Sintetizovani atribut d je pokazivač na konstruisani čvor.
Neterminal <E> ima sintetizovani atr. koji predstavlja pokazivač na deo sintaksnog stabla koji odgovara
izrazu koji <E> uparuje.
Neterminal <S> ima sint. atr. koji predstavlja pokazivač na kompletno sint. stablo koje odgovara iskazu
dodele.
Terminal id ima atribut koji predstavlja ime promenljive (ili pokazivač na tabelu simbola gde se nalazi ta
promenljiva).
Aciklički graf će biti konstruisan istom ovom gramatikom, pod uslovom da akcije {MKLEAF} i
{MKNODE} za iste ulazne parametre vraćaju uvek isti čvor, a ne da prave u svakom pozivu novi čvor.
Primer
Postfiksna notacija za iskaz: a:= b * -c + b * -c
a b c uminus * b c uminus * + assign
Forma postfiksne notacije pogodna je za izvršavanje na stek mašini (npr. mikrojava virtuelna mašina).
Atributivno-translaciona gramatika koja prevodi iskaz dodele u postfiksnu notaciju
(na izlaz ide ono što je unutar vitičastih zagrada):
1. <S> <ID> := <E> {assign}
2. <E> <E> + <E> {+}
3. <E> <E> * <E> {*}
4. <E> – <E> {uminus}
5. <E> ( <E> )
6. <E> <ID>
7. <ID> a {a}
8. <ID> b {b}
9. <ID> c {c}
(Ova forma može se dobiti i postorder obilaskom sintaksnog stabla – kod njega se prvo ispišu levi i desni
naslednik svakog čvora, pa onda sam čvor).
Ovo je koncept, a jedna konkretna realizacija ovog koncepta je mikrojava bajtkod.
Osnovni blok je skup iskaza međukoda koji se izvršavaju u sekvenci (bez grananja) izuzev krajnjeg iskaza u
bloku koji može biti uslovni ili bezuslovni skok.
Dekompozicija programa na osnovne blokove:
Odrediti vođe (prve iskaze) osnovnih blokova: prvi iskaz u programu, iskazi koji predstavalju odredišta
uslovnih ili bezuslovnih skokova i iskazi koji neposredno slede bezuslovne ili uslovne skokove.
Svakom vođi pridružiti iskaze koji ga slede do prvog sledećeg vođe (isključujući taj iskaz) ili do kraja
programa.
U grafu toka kontrole, osnovni blokovi predstavljaju čvorove grafa. Od bloka B1 postoji orijetisana grana
ka bloku B2, ako B2 neposredno sledi B1 u nekoj izvršnoj sekvenci, odnosno ako:
postoji uslovan ili bezuslovan skok od poslednjeg iskaza B1 ka vođi B2, ili
B2 neposredno sledi B1 u međukodu, a B1 nema na kraju bezuslovni skok.
Primer
Programskom fragmentu:
prod = 0; i = 1;
do {
prod = prod + a[i] * b[i];
i = i + 1;
} while ( i <= 20 );
odgovara sledeći međukod i graf toka kontrole:
1. prod = 0
2. i = 1 prod = 0
3. t1 = 4 * i i=1
4. t2 = a[t1]
5. t3 = 4 * i
6. t4 = b[t3] t1 = 4 * i
7. t5 = t2 * t4 t2 = a[t1]
t3 = 4 * i
8. t6 = prod + t5 t4 = b[t3]
9. prod = t6 t5 = t2 * t4
10. t7 = i + 1 t6 = prod + t5
11. i = t7 prod = t6
12. if i <= 20 goto 3 t7 = i + 1
i = t7
if i <= 20 goto 3
Predstavljanje međukoda statičkom formom jedinstvene dodele (engl. Static Single Assignment form
– SSA)
Vrednost ove -funkcija je jednaka X0 ako kontrola u poslednji bazični blok ulazi iz then dela IFa, odnosno
X1 ako kontrola ulazi kroz else deo.
U opštem slučaju, vrednost funkcije (V1, V2, …, VN) u osnovnom bloku B sa N blokova prethodnika u
grafu kontrole toka na nivou bloka, P1, P2, .. , PN, iznosi Vj ako tok izvršavanja prenosi kontrolu programa sa
Pj na blok B.
-funkcija Ima tačno toliko argumenata koliko posmatrani blok ima ulaznih grana.
≥
≥
Iz SSA forme i -funkcija nikada se direktno ne generiše kod, nego se neka druga međuforma (npr.
troadresne naredbe) privremeno transformiše u SSA da bi se olakšala optimizacija koda na nivou SSA, a
zatim se iz SSA konvertuje natrag u polaznu međuformu.
Izvorni kod
for (v=g1; g3; v+=g2 )
a[i]=2;
međukod (četvorke)
v=g1
t2=g2
t3=g3
L1: if v > t3 goto L2
t4 = &a
t5 = 4*i
t6=t4+t5
*t6=2
v=v+t2
goto L1
L2:
međukod (SSA forma)
v1=g1
B1 t2=g2
t3=g3
B2 v2=(v1,v3)
v2>t3
T F
t4=&a
t5=4*i
B3 t6=t4+t5
*t6=2
v3=v2+t2
Pogodnosti za korišćenje SSA forme su u eksplicitnoj predstavi informacija vezanih za tok podataka što
olakšava optimizacije koje su zasnovane na analizi toka podataka. Mane SSA forme su u tome što je
ograničena na skalarne vrednosti (ceo niz se mora tretirati kao veliki scalar) i uvođenje suvišnih dodela
vrednosti kada se konvertuje iz SSA u običan međukod.
Generisanje koda
Ulaz u generator koda je međukod programa, izlaz je mašinski kod za ciljnu mašinu.
(moguće varijante: apsolutizovani mašinski kod, objektni kod obrađivan u predmetu sistemski
softver/programiranje, asemblerski izvorni kod-ako izlaz ide potom u asembler).
Napomena: kod reg. indirektnog mogu se samo koristiti registri BX, SI, DI. Kod indeksnog samo registri
BX, BP, SI, DI.
u prvom koraku određuju se informacije o životu i sledećem korišćenju za svaku pojavu promenljivih u
bazičnom bloku.
Promenljiva x je živa u iskazu i programa ako postoji putanja do nekog iskaza j po kojoj se x ne menja, a u
iskazu j promenljiva x se koristi kao operand. Tada iskaz j predstavlja sledeće korišćenje promenjive x. U
suprotnom, za promenljivu x se kaže da je mrtva.
Primer
Generisati mašinski kod za sledeću instrukciju :
d := (a – b) + (a – c) + (a – c).
Međukod : 1. t := a – b t = (ž , 3) a = (ž , 2) b = (ž , -)
2. u := a – c u = (ž , 3) a = (ž , -) c = (ž , -)
3. v := t + u v = (ž , 4) t = (m , -) u = (ž , 4)
4. d := v + u d = (ž , -) v = (m , -) u = (m , -)
Tabela simbola
a b c d t u v
(ž , -) (ž , -) (ž , -) (ž , -) (m , -) (m , -) (m , -)
(ž , 2) (ž , 1) (ž , 2) (m , -) (ž , 3) (ž , 4) (ž , 4)
(ž , 1) (m , -) (ž , 3) (m , -)
(m , -)
Generator koda koristi desktriptor registra za svaki registar i desktriptor adresa za svaku promenljivu.
Deskriptor registara sadrži spisak imena promenljivih čije vrednosti se nalaze u pojedinim registrima
(na početku bloka prazan).
Primer : AX : a, b, c
Deskriptor adresa pokazuje u kojim se sve registrima i memorijskim lokacijama nalazi vrednost neke
promenljive (na početku bloka sve korisničke prom. su u memoriji)
Primer : a : AX, BX, a’
1. Poziva se potprogram getreg da bi se dobila lokacija L u koji će biti smešten rezultat x. Obično funkcija
vraća registar, a ređe fizičku lokaciju operativne memorije
2. Ako y nije u L onda se generiše mašinska instrukcija:
MOV L, y’
gde je y' tekuća lokacija za y (najbolje ako je neki registar).
3. Generiše se mašinska instrukcija
op L, z’
gde je z' tekuća lokacija za z (najbolje ako je neki registar).
Dodati L u adresni deskriptor za x. Ako je L registar, dodati x u reg. deskriptor za L.
4. Ako y i z nisu živi u i-toj četvorci, udaljiti ih iz deskriptora registara u kojima se trenutno nalaze.
5. Posle procesiranja svih četvorki, na kraju bazičnog bloka, generisati instrukciju:
MOV m, R
za sve promenljive koje su žive, a nalaze se isključivo u nekom od registara R.
Getreg (četvorka x:=y OP z , fleg da li je neophodan registar):izlaz: registar R ili mem. lokacija za y
1. Ako je y jedina promenljiva u nekom registru R i y je mrtvo u posmatranoj četvorci, izbaciti R iz adr.
deskriptora za y i vratiti R
2. Ako (1) ne uspe, vratiti prazan registar (ako ima takav).
3. Ako (2) ne uspe, i ako x ima sledeću upotrebu u tom bloku ili ako je op operator koji obavezno zahteva
registar (npr. indeksiranje) pronaći neki zauzeti registar. Sa MOV upisati u memoriju vrednosti svih
promenljivih iz R koje nisu u mem., izbaciti R iz adr. deskriptora tih promenljivih i vratiti R.
4. Ako tačka (3) ne uspe, vratiti memorijsku lokaciju za x.
- Za raniji primer :