1ognjen/programski prevodioci... · web viewfaza generisanja koda je praktično poslednja faza u...

24
Analizator međukod Optimizator Generator koda međukod Tabela simbola Izvorni kod 12. Generisanje koda Faza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi informacije sačuvane u Tabeli simbola, Sl. 12.1. Kod nekih kompilatora se nakon generisanja koda vrši njegova optimizacija mada se veoma često optimizacija koda vrši i na nivou međukoda, o čemu će biti reči u narednom poglavlju. Osnovni zadatak generatora koda je da generiše ispravan kod pri čemu je bitno da taj kod bude i što je moguće efikasniji. Slika 12.1 Pozicija generatora koda u procesu prevođenja Generator koda može da bude realizovan na tako da generiše direktno mašinski kod sa apsolutnim adresama, mašinski kod sa relativnim adresama ili asemblerski kod koji zatim prolazi kroz proces asembliranja. Kada se generiše mašinski kod sa apsolutnim adresama on se direktno smešta u memoriske lokacije i neposredno posle toga izvršava. Ovo je pristup koji se obično primenjuje kod manjih kompilatora koji se realizuju kao studentski projekti. U slučaju kada se generiše kod sa relativnim adresama delovi programa, kao što su potprogrami mogu da se prevode nezavisno pa da se naknadno povezuju pomoću linkera i ubacuju u memoriju pomoću loadrea. Kada generator koda generiše asemblerski jezik sam generator se lakše realizuje, koriste se simboličke naredbe asemblerskog jezika kao i raspoložive makro naredbe ali se tada na fazu generisanja koda nadovezuje faza asembliranja koda. U ovom poglavlju bavićemo se tim pristupom realizaciji kompilatora. Ciljni kod

Upload: others

Post on 05-Jan-2020

3 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

Analizator međukod Optimizator Generatorkoda

međukod

Tabela simbola

Izvorni kod

12. Generisanje kodaFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi informacije sačuvane u Tabeli simbola, Sl. 12.1. Kod nekih kompilatora se nakon generisanja koda vrši njegova optimizacija mada se veoma često optimizacija koda vrši i na nivou međukoda, o čemu će biti reči u narednom poglavlju.

Osnovni zadatak generatora koda je da generiše ispravan kod pri čemu je bitno da taj kod bude i što je moguće efikasniji.

Slika 12.1 Pozicija generatora koda u procesu prevođenja

Generator koda može da bude realizovan na tako da generiše direktno mašinski kod sa apsolutnim adresama, mašinski kod sa relativnim adresama ili asemblerski kod koji zatim prolazi kroz proces asembliranja.

Kada se generiše mašinski kod sa apsolutnim adresama on se direktno smešta u memoriske lokacije i neposredno posle toga izvršava. Ovo je pristup koji se obično primenjuje kod manjih kompilatora koji se realizuju kao studentski projekti.

U slučaju kada se generiše kod sa relativnim adresama delovi programa, kao što su potprogrami mogu da se prevode nezavisno pa da se naknadno povezuju pomoću linkera i ubacuju u memoriju pomoću loadrea.

Kada generator koda generiše asemblerski jezik sam generator se lakše realizuje, koriste se simboličke naredbe asemblerskog jezika kao i raspoložive makro naredbe ali se tada na fazu generisanja koda nadovezuje faza asembliranja koda. U ovom poglavlju bavićemo se tim pristupom realizaciji kompilatora.

12.1 Ciljni jezikProces generisanja jezika direktno zavisi od ciljnog jezika i nemoguće je u opštem slučaju sagledati sve probleme koji mogu da nastanu U ovom odeljku biće opisan jedan jednostavan asembleski jezik koji će se koristiti u opisu generatora.

Uzećemo kao primer procesor u kome se za adresiranje reči koristi po jedan bajt, a same reči su dužine 4 bajta. Na raspolaganju nam je n registarau samom procesoru: R1,R2, ... Rn-1. Asemblerski jezik ovog procesora ima dvoadresne naredbe oblika

KO surce, destination

Gde je KO kod operacije naredbe, a surce, destination određuju podatak nad kojim će se operacija izvršiti. Osnovne naredbe ovog jezika su:

MOV (source se šalje u destination) ADD (source se dodaje na destination)

Ciljni kod

Page 2: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

SUB (source se oduzima od destination)Kasnije će mo kako se bude ukazivala potreba uvoditi i druge naredbe.

Načini adresiranja

Polja soure i destination nisu dovoljna da specificiraju ceo podatak ili adresu podatka već samo kodiraju način adresiranja koji je primenjen odnosno da li se u reči koja sledi iza naredbe nalazi podatak ili adresa. U Tabeli 12.1 su navedeni načini adresiranja koji se koriste kod ovog asemblerskog jezika kao i dodatna cena koju način adresiranja pridodaje ceni naredbe u kojoj je primenjen. Tabela 12.1 Pregled zastupljenih načina adresiranja

Način adresiranja Format simboličkogZapisa naredbe

Adresa Dodatna cena

Apsolutno adr. M M 1

registarsko R R 0

indeksiranje c(R) c+(R) 1

Indirekno registarsko *R (R) 0

Indirekno sa indeksiranjem

*c(R) (c+(R)) 1

Neposredno #c 1

Apsolutno adresiranje

U ovom slučaju memorijska lokacija čije je simboličko ime navedeno u naredbi je izvorište ili destinacija. Na primer, u naredbi:

MOV R0,M

Sadržaj registra R0 se prosleđuje u memorijsku lokaciju M: (R0)→M.

U ovom slučaju adresa memorijske lokacije sledi neposredno iza same naredbe, pa je zato uzeto da samo adresiranje povećava cenu za jedan.

Registarsko adresiranje

Kod registarskog adresiranja navedeni registar je izvorište ili odredište podatka na koji se odnosi naredba. U prethodnom primeru MOV naredbe sadržaj registra R0 se prebacuje u mamorijsku lokaciju M.

Kako se registri nalaze u procesoru i adresiranju se implicitno, nije potrebno da se zauzima memorijski prostor za pamćenje njihovih adresa, ovaj način adresiranja ne povećava cenu naredbe u kojoj se koristi.

Indeksiranje

U ovom slučaju adresa izvorišta ili odredišta se formira tako što se sadržaju registra koji je naveden u zapisu naredbe dodaje vrednost konstante koja je navedena u naredbi. U ovom slučaju

Page 3: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

vrednost konstante u binarnom odliku sledi iza same naredbe ovo adresiranje povećava cenu naredbe za 1.

Primer:

MOV 4,(R0), M

Efekat je da se sadržaj registra R0 povećava za 4, čime se formira adresa memorijske lokacije čiji se sadržaj šalje u memorijsku lokaciju M: (4+(R))→M.

Indirektno registarsko adresiranje

Indirektno adresiranje je označeno sa *, i sastoji se u tome da se sadržaj navedenog registra koristi kao adresa lokacije u kojoj ili iz koje se preuzima sadržaj nad kojim se izvršava navedena operacija.

Na primer, u naredbi:MOV *R0,M efekat je ((R0))→M. Sardžaj memorijske lokacije čija je adresa jednaka sadržaju registra R0 se prosleđije u memorijsku lokaciju M. Ovo adresiranje kao i registarsko ne povećava cenu naredbe zato što ne zahteva dodatan memorijski prostor za pamćenje podataka o adresi.

Indirekno indeksirano adresiranje

Kada se indirektno adresiranje kombinuje sa indeksiranjem najpre se indeksiranjem formira adresa memorijske lokacije čiji se sadržaj koristi kao adresa lokacije čiji se sadržaj koristi u operaciji.

Na primer u naredbi *4(R0), M efekat je ((c+(R0)))→M.

U ovom slučaju, kao i kod indeksiranja, konstanta koja se koristi u indeksiranju se memoriše odmah iza same naredbe tako da ovo adresiranje povećava cenu naredbe za 1.

Neposredno adresiranje

U slučaju neposrednog adresiranja podatak nad kojim se izvršava naredba je konstanta koja se daje uz samu naredbu. Ova konstanta se memoriše neposredno iza naredbe tako da takav način adresiranja povećava cenu naredbe za 1.

Primer:

Naredba MOV #5, R0 ima efekat 5→R0, vrednost konstante 5 se upisuje u registar R0.

Cena naredbi

U mnogim slučajevima prilikom generisanja koda postoji više mogućnosti. Nekada se isti efekat može postići izborom različitih instrukcija. Generator koda zbog toga prilikom generisanja koda koristi i neku procenu cene generisanog koda koju formira na osnovu cene pojedinačnih naredbi koje mu stoje na raspolaganju. Cena naredbe u suštini zavisi od memorijskog prostora koji zauzima sama naredba kao i do načina adresiranja koji je u njoj primenjen, o čemu je bilo već reči. Kao što smo videli, korišćenje procesorskih registara ne povećava cenu naredbe dok korišćenje memorijskih lokacija je povećava. Sa druge strane korišćenje registara procesora utiče i na efikasnost samog koda zato što se operacije mnogo brže izvršavaju ututar samog procesora, odnosno nad sadržajima koji se nalaze u registrima u odnosu na slučaj kada se sadržaj preuzima iz memorije. Zbog svega toga zadatak samog generatora koda je i efikasno korišćenje registara procesora.

Razmotrićemo ukupnu cenu nekih naredbi iz jezika koji koristimo kao primer:

Page 4: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

Naredba MOV R0,R1 kojom se sadržaj registra R0 kopira u registar R!, imaće ukupnu cenu 1, zato što sama naredba zauzima jednu memorijsku lokaciju i ne zahteva dodatni memorijski prostor za pamćenje adresa.

Naredba MOV R0, M , kojom se sadržaj registra R0 prebacuje u memorijsku lokaciju M, ima ukupnu cenu 2, zato što sama naredba zauzima jednu memorijsku lokaciju, a neposredno iza nje sledi adresa memorijske lokacije koja se koristi kao odredište sadržaja.

Naredba #5,R0, kojom se u registar R0 upisuje vrednost konstante 5, ima ukupnu cenu 2, zato što sama naredba zauzima jednu memorijsku lokaciju, a neposredno iza nje se memoriše konstanta 5.

Naredba MOV 4(R0), *12(R1) čiji je efekat (4+R0)→(12+(R1)). Odnosno, sadržaj memorijske lokacije čija je adresa određena zbirok indeksa 4 i sadržajem registra R0 se upisuje u memorijsku lokaciju čija je adresa određena sadržajem memorijske lokacije čija je adresa zbir konstante 12 i sadržaja registra R1. Ova naredba ima ukupnu cenu 3, zato što se jedna memorijska lokacija koristi za samu naredbu i po jedna za memorisanje konstanti 4 i 12.

Na primeru jednostavne troadresne naredbe a := b + c pokazaćemo šta sve može i treba da bude uzeto u razmatranje u okviru generatora koda. Ova naredba može da bude realizovana na mnogo različitih načina od kojih su neki:

1. MOV b,R=

ADD c, R=

MOV RO, a ukupna cena 6, zato što svaka od naredbi ima cenu 2.

2. MOV b,a

ADD c,a ukupna cena 6, zato što svaka naredba ima cenu 3.

Ako se adrese 1, b i c nalaze u registrima R1, R2 i R3 sekvenca naredbi bi bila:

3. MOV *R1, *R0

ADD *R“, R0 ukupna cena 2, zato što je cena svake naredbe 1.

Ako pretpostavimo da se vrednosti a i b nalaze u registrima R0 i R1 i da nam vrednost b ne treba posle operacije onda je moguća i sledeća sekvenca naredbi:

4. ADD R2, R1

MOV R1, a sa ukupnom cenom 3, gde je cena prve naredbe 1, a druge 2.

Iz ovog trivijalnog primera se vidi da generator koda ima dosta komplikovan zadatak ako se kao cilj postavi genrisanje optimalnog koda. Zbog toga se obično ovom problemu pristupa tako što se kao primarni cilj generatora postavlja generisanje funkcionalno ispravnog koda, a optimizacija koda se vrši naknadno.

12.2 Realizacija generatora kodaPre nego definišemo sam generator koda uvešćemo ograničenje da se rezultat izvršavanja neke operacije zadržava u registru sve dok je potreban. Iz registra ćemo ga prebacivati u memorijsku lokaciju samo u slučaju kad je taj registar potreban za neku drugu operaciju kao i neposredno pre poziva potprograma, pre naredbe skoka kao i pre naredbe sa labelom.

Algoritam generatora koda

Page 5: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

Generator koda preuzima naredbe iz ulazne sekvence koja predstavlja troadresni međukod. U okviru ovih sekvenci se obično identifikuju delovi (blokovi) koji sami za sebe predstavljaju celine, tako da se može učitavati blok po blok. Takođe za svaki od raspoloživih registara koristimo Descriptor registra koji ukazuje na to vrednost koje promenljive je memorisana u registru. Takođe za svaku od promenljivih imamo Deskriptor adrese koji ukazuje na to gde je memorisana vrednost te promenljive.

Za svaku troadresnu naredbu oblika x := y op z izvršavaju se sledeći koraci:

1. Korak: Određivanje lokacije L u kojoj će biti zapamćen rezultat

U ove svrhe koristi se funkcija getreg, je data neposredno iza ovog algoritma. Nastoji se da odredište bude neki od registara u procesoru, ali isto tako to može da bude i neka od memorijskih lokacija.

2. Korak: Određivanje podatka nad kojim se izvršava operacija

Određuje se gde se nalazi podatak y nad kojim se izvršava operacija. On može da bude u memoriji ili u nekom od registara procesora. Ukoliko se nalazi na oba mesta prednost se daje registrima. Ako podatak već nije u L, generiše se naredba MOV y’, L, kojom se podatak y prebacuje u lokaciju L. (sa y’ je označena adresa lokacije u kojoj se nalazi podatak y).

3. Korak: Generisanje naredbe

Generiše se naredba oblika OP z’, L, gde je sa z’ označena lokacija u kojoj se nalazi podatak simbolički označen sa z. Descriptor adrese za x se koriguje tako da pokazuje na lokaciju L. Ako je L registar treba korigovati njegov deskriptor tako da pokazuje da on sadrži podatak x, i izbrisati x iz sadržaja svih drugih deskriptora registara.

4. Korak: Oslobađanje registara

Ako se podaci y i z ne koriste neposredno iza razmatrane naredbe, nisu živi po izlasku iz bloka onda, ako se nalaze u registrima treba osloboditi registre ili naznačiti da se posle bloka ti sadržaji ne koriste.

Uočimo da za svaki od registara procesora imamo deskriptor registra koji pamti koji se podatak nalazi u registru, dok za svaki podatak koji je u memoriji pamtimo adresu memorijske lokacije u kojoj je memorisan.

Funkcija getregFunkciju getreg koristimo da odredimo lokaciju gde će biti smešten rezultat generisane naredbe. Ako je cilj generisanje optimalnog koda ovaj zadatak može da bude jako složen. Ovde će biti razmatrano jedno jednostavno rešenje koje daje prednost registrima procesora u odnosu na memorijske lokacije ako ta mogućnost postoji.

1. Ako descriptor nekog registra pokazuje da je y u tom registru i ako se y više ne koristi posle naredbe x := y op z, onda se taj registar vraća kao L. Kako će posle izvršenja naredbe u ovom registu biti rezultat operacije, a ne više y treba korigovati descriptor adrese za y da y više nije u tom registru.

2. Ako prva solucija nije moguća za L uzimamo prazan registar ako takav postoji.

3. Ako ni druga solucija nije moguća i ako se x koristi dalje u istom bloku, ili je op operator koji zahteva upotrebu registara, onda biramo neki od zauzetih registara R. Vrednost koja je trenutno zapisana u registru prebacujemo u memoriju (generišemo naredbu MOV R,M) ako ta vrednost već nije zapamćena u memoriji, korigujemo descriptor adrese za M i

Page 6: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

vraćamo R kao L. Ako je u registru R zapisana vrednost većeg broja promenljivih (što može da bude posledica copy naredbi) treba generisati odgovarajuću MOV naredbu za svaku od tih promenljivih.

4. Ako se x ne koristi dalje u bloku ili ne može da se nađe odgovarajući prazan registar onda se za L uzima memorijska lokacija u kojoj je zapamćena vrednost za x.

Primer. 12.1 Razmotrimo kao primer naredbu dodeljivanja d := (a - b) + (a - c) + (a –c) na osnovu koje je generisan sledeći međukod:

t1 := a – b

t2 := a – c

t3 := t1 – t2

d := t3 + t2

Genarator koda opisan gore datom procedurom generisaće sekvencu asemblerskih naredbi prikazanu u Tabeli 12.2.

Table 12. 2 Generisani kod za blok naredbi iz Primera 12.1

Naredba međukoda Generisani kod Deskriptor registra Deskriptor adrese

Registri su prazni

t1 := a - b MOV a, R=SUB b,R0

R0 sadrži t1 t1 je u R0

t2 := a - c MOV a,R1SUB c,R1

R0 sadrži t1R1 sadrži t2

t1 je u R0t2 je u R1

t3 := t1 – t2 ADD R1,R0 R0 sadrži t3R1 sadrži t2

t3 je u R0t2 je u R1

d := t3 + t2 ADD R1,R0MOV R0, d

R0 sadrži d d u R0d u memoriji

Generisanje koda za neke specijalne naredbeSloženije naredbe troadresnog koda, kao što su naredbe u kojima se javljaju indeksirane promenljive i pointeri, se transformišu u asemblerski kod na sličan način kao i naredbe sa binarnim operatorom.

Kod koji se generiše za slučaj naredbi dodeljivanja u kojima se javljaju promenljive sa indeksima prikazan je u Tabeli 12.3.

Tabela 12.3 Generisani kod za naredbe sa indeksima

Naredba međukoda

Indeks i je u registru Ri

Indeks i je u memoriji Mi

Indeks i je u steku

Gen. kod Cena Gen. kod Cena Gen. kod Cena

a := b[i] MOV b(Ri),R 2 MOV Mi, R 4 MOV Si(A),R 4

Page 7: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

MOV b(R),R MOV b(R),R

a[i] := b MOV b, a(Ri) 3 MOV Mi, RMOV b, a(R)

5 MOV Si(A),RMOV b, a(R)

5

U Tabeli 12.3 su razmatrani slučajevi naredbi: a := b[i] i a[i] := b, a uzeta su obzir tri slučaja: kada je indeks zapamćen u registru procesora, u memorijskoj lokaciji ili se čuva na steku.

Kod koji se generiše u slučaju naredbi u kojima se koriste pokazivači prikazan je u Tabeli 12.4. I ovde su uzeta u obzir dva oblika međunaredbi: a := *p i *p := a. Takođe su razmatrane slučajevi kada se vrednost pokazivača nalazi u registru procesora, u memorijskoj lokaciji ili na steku.

Tabela 12.4 Generisani kod za naredbe sa pokazivačima

Naredba međukoda

Pokazivač p je u registru Rp

Pokazivač p je u memoriji Mp

Pokazivač p je u steku

Gen. kod Cena Gen. kod Cena Gen. kod Cena

a := *p MOV *Rp,a 2 MOV Mp, RMOV *Mp, a

3 MOV Sp(A),RMOV *R,a

3

*p := a MOV a, *Rp 2 MOV Mp, RMOV a, *Rp

4 MOV a,RMOV R, *Sp(A)

4

Uslovne naredbeUslovne naredbe troadresnog koda oblika if x relop y go to z mogu da budu transformisane u asemblerski u principu na dva načina.

Jedan način je da se najpre x oduzme od y i da se rezultat zapamti u registru R, nakon čega se generiše naredba skoka na z ako je vrednost registra R negativna.

Drugi način se primenjuje kod asemblerskih jezika koji koriste skup bitova (conditional code) kojima se registruje kakva je vrednost koja je upisana u registar bilo da je ona dobijena kao rezultat izvršavanja neke operacije ili prilikom upisa vrednosti u registar. Ovi jezici obično sadrže naredbe skoka koje se vezuju za te bitove i omogućavaju prenos upravljanja na neku naredbu ako je neki od uslova ispunje. U ovom slučaju naredba međukoda oblika if x < y go to z će biti preslikana u sledeću sekvencu naredbi:

CMP x, y

CJ< z

Najpre se poredi vrednost podataka x i y, nakon čega se postavljaju vrednosti bitova kojima se registruje sadržaj rezultata. Druga naredba je skok na labelu z ako je u bitu kojim se registruje uslov< upisana vrednost 1.

12.3 Organizacija memorijeAko zamislimo da operativni sitem dodeljuje neki deo memorije kompilatoru za smeštaj programa koji se prevodi onda kompilator obično pravi raspodelu memorije tako da jedan segment koristi za smeštaj koda programa, u drugi smešta statičke podatke, jedan deo memorije se organizuje u vidu steka i služi za smeštaj aktivacionih slogova potprograma (o čemu će biti reči kasnije) a deo memorije (Heap) se koristi za smeštaj dinamičkih podataka, Slika 12.2:

Page 8: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

Kod programa

Statički podaci

Stek

Heap-Dinamički podaci

Slika 12. Organizacija memorije

Veličina generisanog koda je poznata u toku prevođenja programa, a takođe može da se izračuna i memorijski proctor potreban za smeštaj statičkih podataka. Ove informacije kompilator može da iskoristi i da kod i podatke smesti u memorijske lokacije određene apsolutnim ili relativnim adresama.

Kod nekih jezika, kao šro je na primer FORTRAN, svi podaci se smeštaju statički. Međutim postoje jezici kod kojih se koriste dinamički podaci za koje se vrši alokacija memorije u toku izvršavanja programa. Ovim podavima namenjen je dinamički deo memorije. Takođe kod programskih jezika kod kojih su dozvoljeni rekurzivni pozivi potprograma za smeštaj aktivacionih slogova potprograma koristi se stek.

Veličina steka i dinamičkog dela memorije može da se menja u toku izvršavanja programa. Prilikom implementacije nekih jezika (Pascal, C) dozvoljava se da se ovi delovi menjaju jedan na račun drugog.

Obično se u posebnom registru procesora čuva adresa vrha steka, to je takozvani pokazivač vrha steka.

Alokacioni slogovi

Za svaki poziv potprograma kompilator obično generiše jedan aktivacioni slog u kome čuva sve informacije potrebne tom pozivu potprograma. U opštem slučaju aktivacioni slog ima strukturu prikazanu na Slici 12.3. Međutim, struktura aktivacionog sloga nije ista kod svih jezika niti kod svih kompilatora za jedan jezik. Ona se obično prilagođava potrebama kompilatora.

Namena polja u aktivacionom slogu je sledeća:

1. Na vrhu sloga, smešta se vrednost koju potprogram vraća glavnom programu. Ova vrednost se zbog efikasnosti vraća u neki od registra procesora.

2. Polje namenjeno stvarnim parametrima se koristi od strane glavnog programa da prenese parametre potprogramu koji odgovaraju konkretnom pozivu potprograma.

3. Opciono polje sa upravljačkim linkovima se koristi da se obezbedi veza sa aktivacionim slogom modula iz kojeg je pozvan potprogram.

Page 9: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

Vrednost koja se vraća glavnom programu

Stvarni parametri

Opconaalni upravljački linkovi

Linkovi za pristup podacima

Podaci o statusu procesora

Lokalni podaci

Privremene promenljive

4. Opciono polje sa linkovima za pristup podacima postoji kod jezika koji dozvoljavaju da se koriste nelokalni podaci, podaci iz aktivacionih slogova drugih potprograma. Ovo polje kod Fortrana nije potrebno zato što se svi nelokalni podaci čuvaju na jednom mestu.

5. Deo aktivacionog sloga namenjen čuvanju statusa procesora služi da se u njemu memorišu vrednosti registara pocesora koje su zatečene u trenutku poziva potprograma. Ovde se obično smešta vrednost Brojača neredbi i registara procesora opšte namene.

6. Polje namenjenu lokalnim podacima služi za smeštaj podataka koji pripadaju samo potprogram, definisani su u potprogramu.

7. Polje namenjeno privremenim podacima služi za memorisanje podataka koje generiše kompilator kao pomoćne lokacije u koje smešta međurezultate.

Veličina svih polja u aktivacionom slogu može da se odredi u fazi prevođenja programa. Izuzetak su samo jezici kod kojih je dozvoljeno da se dimenzije polja definišu u fazi izvršavanja tako što se ti podaci učitavaju.

Slika 12.4 Struktura aktivacionog sloga

12.4 Strategije za alokaciju memorijeNa osnovu toga kako i kada se generišu i memorišu aktivacioni slogovi zastupljene su tri strategije alokacije memorije kod realizacije kompilatora:

Statička alokacija svih objekata u vreme kompilacije.

Alokacija pomoću steka

Dinamička alokacija pomoću Heap-a

Page 10: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

Kod statičke alokacije aktivacioni slog se generiše u fazi kompiliranja i smešta u statički deo memorije. Kod alokacije memorije pomoću steka aktivacioni slogovi se generišu u fazi izvršavanja i smeštaju na stek, dok se kod dinamičke alokacije smeštaju u dinamički deo memorije. Jednostavniji slučaj ovih alokacija je kada se svi podaci o strukturi sloga znaju u fazi kompiliranja, a složeniji kada se struktura kompletira u fazi izvršavanja.

Statička alokacijaU toku kompiliranja programa generiše se po jedan aktivacioni slog za svaku od procedura tako da se isti aktivacioni slog koristi kod svakog poziva potprograma. Ovaj aktivacioni slog se smešta u statički deo memorije. U ovom slučaju nema mogućnosti za rekurzivne pozive procedura zato što bi svaki naredni poziv procedure prebrisao sadržaj aktivacionog sloga koji odgovara prethodnom pozivu koji još nije završen. Takođe nije dozvoljen rad sa dinamičkim podacima za koje se alocira memorija u fazi izvršavanja. Ova tehnika se primenjuje kod realizacije kompilatora za programski jezik FORTRAN.

Primer 12.3Uzmimo kao primer kod program CONSUME i potprograma PRODUCE, napisanih u programskom jeziku FORTRAN

PROGRAM CONSUMECHARACTER * 50 BAFINTEGER NEXTCHARACTER C, PRODUCEDATA NEXT /1/, BUF /’ ‘/

6 C = PRODUCE ( )BUF(NEXT:NEXT) = CNEXT = NEXT + 1IF (C .NE. ‘ ‘) GO TO 6WRITE (*, ‘(A)’) BUFEND

CHACTER FUNCTION PRODUCE ( )CHARACTER * 80 BUFFERINTEGER NEXTSAVE BUFFER, NEXTDATA NEXT /81/IF (NEXT .GT. 80 ) THENREAD (*, ‘(A)’) BUFFERNEXT = 1END IFPRODUCE = BUFFER(NEXT:NEXT)NEXT = NEXT + 1END

Kako su veličina memorijskog prostora potrebnog za smeštaj koda programa i potprograma, kao i aktivacionih slogova za ova dva modula poznati u fazi kompiliranja programa raspodela memorije u ovom slučaju će biti kako je to prikazano na Slici 12.5.

Page 11: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

Kod za CONSUME

Kod za PRODUCE

Aktivacioni slog za CONSUME

CHARACTER * 50 BUFINTEGER NEXTCHARACTER C

Aktivacioni slog za PRODUCE

CHARACTER * 80 BUFFERINTEGER NEXT

Slika 12.4 Statička alokacija memorije

Alokacija memorije pomoću stekaAko programski jezik dozvoljava rekurzivne pozive potprograma onda nije moguće koristiti statičku alokaciju memorije. Naime u ovom slučaju u jednom trenutku može da postoji više aktiviranih instanci potprograma i za svaki takav poziv potreban je poseban aktivacioni slog.

Jedna od tehnika koju je u ovom slučaju moguće koristiti je alokacija memorije pomoću steka, u okviru koje se prilikom svakog poziva potprograma kreira novi aktivacioni slog i smešta na stek. Kada se izvršavanje određene istance potprograma zavši odgovarajči aktivacioni slog se skida sa steka. U jednom trenutku u steku može da se nalazi više istanci aktivacionog sloga jednog potprograma, kao i više tazličitih aktivacionih slogova.

U vreme kompiliranja programa zna se samo veličina aktivacionog sloga ali ne i dubina rekurzije (koliko će aktivacionih slogova jednog potprograma u nekom trenutku biti u steku).

Primer 12.3Uzmimo kao primer rekurzivnu proceduru quiksort kojom se uređuje vektor brojeva, čiji je kod dat u nastavku:

procedure quiksort (m,n: integer); var i: integer; begin

if (n>m) then begin

i := partition (m,n);quiksort(m, i-1);

Page 12: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

quiksort(i+1, n);end

end; begin a[0] := -9999; a[10] := 9999; readarray; quiksort(1,9);end.

Uočimo da se u datoj proceduri poziva potprogram partition kao i sam potprogram quiksort rekurzivno i to dvostrukom rekurzijom. U glavnom programu pre poziva potprograma quiksort poziva se i potprogram readaray. Redosled poziva potprograma najbolje se može prikazati aktivacionim stablom koje je za dati primer prikazano na Slici 12.5.

Slika 12.5 Aktivaciono stablo za program iz Primera 12.5.

Svaki čvor u aktivacionom stablu sa Slike 12.5 prestavlja jedan poziv potprograma. Pozivi potprograma koji se izvrše iz jedne instance potprograma predstavljeni su čvorovima do kojih vode potezi iz čvora koji odgovara toj istanci. Pri tome redosled poziva odgovara redosledu čvorova poslatrano sleva u desno. Na Slici 12.6 je prikazan redosled ubacivanja aktivacionih slogova u stek koji odgovara delu aktivacionog stabla prikazanog na Slici 12.5

Page 13: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

AKTIVACIONO STABLO Aktivacioni slogovi u steku Komentar

SAktivacioni slpg glavnog programa

Aktivacioni slog potprograma r je bio ubačen u stek, a izbačen iz steka kada se ovaj potprogram završio. Nakon toga u stek je ubačen aktivacioni slog potprograma q(1,9), a posle toga aktivacioni slog poziva p(1,9).

Kada je završen potprogram p(1,9) njegov slog se izbacuje iz steka. Nakon toga sledi poziv q(1,3) tako da se u stek ubacuje još jedna istanca aktivacionag sloga potprograma q.

s

r

s

r q(1,9)

p(1,9)s

r q(1,9)

p(1,9) q(1,3)

S

A : array

S

A : array

readarray

i : integer

S

A : array

q(1,9)

i : integer

S

A : array

q(1,9)

i : integer

q(1,3)

i : integer

Page 14: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

Potprogram q(1,3) poziva potprogram p(1,3), tako da se u stek ubacuje nova istanca aktivacionog sloga potprograma p, itd.

Slika 12.6 Dinamika ubacivana aktivacionih slogova u stek za program iz Primera 12.3.

Dinamička alokacija Aktivacioni slogovi se smeštaju u dinamičku memoriju i ne izbacuju se kao kod stek alokacije, Slika 12.7. Delu aktivacionog stabla prikazanog na slici odgovara struktura slogva data na istoj slici.

Slika 12.7 Dinamička alokacija memorije

Vektori u aktivacionom sloguAktivacioni slog sadrži sve podatke potrebne u okviru jednog poziva potprograma. Međutim, ako se potprogramu koriste vektori i matrice može da se desi da aktivacioni slog bude prevelik i da ograničava dubinu rekurzije. Zbog toga se obično u aktivacionom slogu čuvaju samo pokazivači na početne lokacije vektora i matrica, dok se same strukture dislociraju iz sloga, Slika 12.8.

s

r q(1,9)

p(1,9) q(1,3)

s

control link

AKTIVACIONI

SLOGOVI U HEAP-u

s

AKTIVACIONO

STABLOr r

control link

q(1,9)

q(1,9)

control link

S

A : array

q(1,9)

i : integer

q(1,3)

i : integer

p(1,3)

i : integerp(1,3)

Page 15: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

Slika 12. 8 Vektori dislocirani iz aktivacionog sloga

5. Realizacija alokacije memorijeDa bi se realizovala određena strategija alokacije memorije kompilator treba da generiše odgovarajuću sekvencu naredbi mašinskog ili asemblerskog koda. Ovde ćemo dati po jedan primer statičke alokacije i alokacije pomoću steka.

Realizacija statičke alokacije

U slučaju statičke alokacije u tački poziva potprograma kompilator treba da zapamti adresu povratka iz potprograma i skok na sekvencu naredbi potprograma. U te svrhe generiše sledeću sekvencu:

MOV #here + 20, pp.aktivacioni_slog

GOTO pp.kod

Praktično, naredbom MOV #here + 20, pp.aktivacioni_slog, u prvu lokaciju aktivacionog sloga pozvanog potprograma smešta se adresa povratka u glavni program. U ovom primeru ta adresa je #here + 20, gde je #here adresa tekuće naredbe, vrednost brojača naredbi (PC registra). Iza ove naredbe generiše se naredba GOTO pp.kod kojom se upravljanje prenosi na prvu naredbu potprograma. .

U samom potprogramu generiše se naredba za povratak u glavni program:

GO TO * pp.aktivacioni_slog

Za primer programa predstavljenog kodom na Slici 12.9, koji se satoji od glavnog programa i poprograma, struktura aktivacionih slogova data je na istoj slici. Na Slici 12.10 prikazan je kod koji će biti generisan od strne kompilatora za strategiju statičke alokacije.

Upravljački linkovi

pointer na Apointer na Bpointer na C array A array B array C

Upravljački linkovi

AKTIVACIONI SLOG

POLJE

VEKTORAAKTIVACIONI SLOG

Page 16: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

Slika 12.9 Primer programa C i potprograma P

/* Kod programa c */100: ACTION1

120 : MOV #140, 364 /* 140 je adresa povratka*/

132: GO TO 200 /* Skok na poptprogram */

140 : ACTION2

160: HALT/* Kod poptprograma p */200: ACTION3220: GO TO *364 /* Povratak u program c */300: /* 300-363 aktivacioni slog za c */304: /* adresa povratka */

/* Lokalni podaci za c */364: /* 364-451 aktivacioni slog za p *368: /* adresa povratka *

/* Lokalni podaci za p */

Slika 12.10 Generisani kod za statičku alokaciju

Realizacija alokacije pomoću stekaU slučaju alokacije pomoću steka zadatak kompilatora je nešto složeniji:

1. Najpre se vrši inicijalizacija steka. U te svrhe kompilator generiše sledeću sekvencu naredbi:

/* Inicijalizacija steka */

/* kod za c */action1call p action2halt

/* kod za p */action3return

TROADRESNI MEĐUKOD

return address

arr

ij

0:

56:60:

8:

AKTIVACIONI SLOG ZA C

return address

buf

n

0:

84:

4:

AKTIVACIONI SLOG ZA P

Page 17: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

MOV #stackstart, SP

Kod prve procedure

HALT

2. U tački poziva potprograma generiše se sekvenca naredbi kojom se najpre menja vrednost stek pointera koji ukazuje na početnu lokaciju steka. Kako je pre poziva potprograma stek pointer ukazivao na početak aktivacionog sloga glavnog programa, treba ga korigovati za duzinu tog aktivacionog sloga tako da pokazuje na prvu lokaciju aktivacionog sloga pozvanog potprogram. Iza toga pamti se adresa povratka i upravljanje prenosi na pozvani potprogram. Adresa povratka se pamti u steku, odnosno na početak aktivacionognog sloga potprograma, lokaciji na koju ukazuje stek pointer.

/* Dodavanje ak. sloga u stek */

ADD #glpr.recordsize, SP

MOV # here +16, *SP

GOTO pp.kod

3. U potprograma se kao poslednja naredba generiše naredba za povratak u glavni program, pri čemu se generiše skok na naredbu čija je adresa zapamćena u prvom slogu aktivacionog sloga na koji ukazuje stek pointer.

/* povratak u gl. program */

GO TO *0 ( SP )

4. Po povratku u glavni program treba izvršiti korekciju stek pointera tako da ukazuje na početak aktivacionog sloga glavnog programa, što odgovara izbacivanju aktivacionog sloga potprograma iz steka:

/* izbacivanje sloga iz steka */

SUB #glpr.recordsize, SP

Za troadresni kod quicksort programa dat na Slici 12.11. biće generisana sekvenca naredbi data na Slici 12.12.

Page 18: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

Slika 12.11 Troadresni kod quicksort programa

/* Kod za proceduru s */100: MOV #600, SP /* inicijalizacija steka */

108 : ACTION1

128: ADD #ssize, SP /* poziv potprograma */136: MOV #152, *SP /* adresa povratka ide u stek */144: GO TO 300 /* skok na pocetak pp q */152: SUB #ssize, SP /* obnavljanje SP */180 HALT

/* Kod za proceduru p*/200: ACTION3220: GO TO *0(SP)/* return */

/* Kod za proceduru q*/300: ACTION4

TROADRESNI KOD/* kod za s

*/action1call q

action2halt

/* kod za p */

action3return

/* kod za q */

action4call p

action5call q

action6call qreturn

Page 19: 1ognjen/Programski prevodioci... · Web viewFaza generisanja koda je praktično poslednja faza u procesu prevođenja jezika. Obično se nadovezuje na generisanje međukoda i koristi

320 : ADD #qsize, SP328: MOV #344, *SP /* pamti se adresa povratka */336: GO TO 200 /* poziv pp P */344: SUB #qsize, SP352: ACTION5372: ADD #qsize, SP380: MOV #396, *SP /* pamti se adresa povratka */388: GO TO 300 /* poziv pp q */396: SUB #qsize, SP404: ACTION6424: ADD #qsize, SP432: MOV #448, *SP /* pamti se adresa povratka */440: GO TO 300 /* poziv pp q */448: SUB #qsize, SP456: GO TO *0(SP) /* return */….600: /* Stek zapocinje ovde */

Slika 12.12 Generisani kod koji odgovara programu iz Primera 12.7

5. Tehnike prenosa parametara u potprogramU ovom odeljku ćemo razmotriti kako se realizuju različite tehnike prenosa parametara u potprogram. Naime poznato je da se za prenos parametara u potprogram koriste različite tehnike prenosa među kojima su nazastupljenije:

Poziv po vrednosti (call by value)

Poziv po referenci (call by reference)

Poziv po vrednosti i rezultatu (call by values and result)

Poziv po imenu (call by name) i sl.