Sunteți pe pagina 1din 67

Construc]ia compilatoarelor folosind

Flex [i Bison
Anthony A. Aaby
Walla Walla College
cs.wwc.edu
aabyan@wwc.edu
Popa Dan
Universitatea Bac\u
www.ub.ro
popavdan@yahoo.com, dpopa@ub.ro
Versiunea din 26 iunie 2005
1
Copyright 2003 Anthony A. Aaby
Walla Walla College
204 S. College Ave.
College Place, WA 99324
E-mail aabyan!""c.e#$
%a&e' (o$rce( available by re)$e(t.
&hi( material may be #i(trib$te# only ($b*ect to the term( an# con#ition(
(et +orth in the ,pen P$blication %icen(e, v-.0 or later .the late(t ver(ion i(
pre(ently available at http//""".opencontent.org/openp$b
&hi( boo0 i( #i(trib$te# in the hope it "ill be $(e+$l, b$t "itho$t any "arranty1
"itho$t even the implie# "arranty o+ merchantability or +itne(( +or a
partic$lar p$rpo(e.
&he a$thor enco$rage( "i#e #i(trib$tion o+ thi( boo0 +or per(onal an# commercial
$(e, provi#e# the above copyright notice remain( intact an# the metho#
a#here( to the provi(ion( o+ the ,pen P$blication %i(cen(e locate# at
http//""".opencontent.org/openp$b
2n ($mmary, yo$ may copy an# #i(trib$te thi( boo0 +ree o+ charge or +or a
pro+it. 3o e4plicit permi((ion i( re)$ire# +rom the a$thor +or repro#$ction o+
thi( boo0 in any me#i$m, phy(ical or electronic.
3ote, #erivative "or0( an# tran(lation( o+ thi( #oc$ment m$(t incl$#e the
original copyright notice m$(t remain intact.
Versiunea `n limba rom=na este tradus [i adaptat de !an "opa #
popav#an!yahoo.com, #popa!$b.ro. $m fcut de asemenea o serie de
rectificri [i corecturi% $m unificat nota]iile pentru codul &enerat [i instruc]i'
unile ma[inii (irtuale% )oate fi[ierele surs au fost rescrise la calculator [i
toate pro&ramele au fost testate% !atorit adaptrii# o serie de por]iuni din
text au fost rescrise iar para&rafe `ntre&i cu explica]ii au fost adu&ate%
*arcarea lor folosind caractere italice ar fi `ncrcat inutil textul dar cititorul
interesat poate compara cele dou edi]ii# en&le+ [i rom=n pentru a (edea
ce modificri [i adu&iri s'au fcut cu oca+ia traducerii [i adaptrii% , parte
din anexele (ersiunii `n limba en&le+ nu au fost incluse `n aceast
(ersiune%
Cop-ri&.t'ul pentru edi]ia `n limba rom=n/ !an "opa 02001'20052
2
C$prin(
0 3n loc de moti(a]ie 5
1 4ntroducere 5
2 $nali+orul sintactic 0"arser'ul2 16
6 7caner'ul 0$nali+orul lexical2 18
1 Contextul 25
5 ,ptimi+area 65
6 *a[ini Virtuale 65
5 9enerarea Codului 15
: ,ptimi+area de cod dup &enerare 56
8 ;ecturi suplimentare 51
10 <xerci]ii 56
$nexa $/ ;imba=ul 7imple ' 4mplementarea complet %%5:
$%1 "arserul/ 7imple%- % % % % % % % % % % % % % % % % % % % % % % % % % 5:
$%2 4ndica]ii de lucru % % % % % % % % % % % % % % % % % % % % % % % % % % % 61
$%6 7canerul/ 7imple%lex % % % % % % % % % % % % % % % % % % % % % % % %62
$%1 )abela de simboluri/ 7)%. % % % % % % % % % % % % % % % % % % % 66
$%5 9eneratorul de cod/ C9%. % % % % % % % % % % % % % % % % % % % %61
$%6 *a[ina cu sti(/ 7*%. % % % % % % % % % % % % % % % % % % % % % % %65
$%5 >n exemplu de pro&ram/ test?simple % % % % % % % % % % %65
$nexele edi]iei de limb en&le+ neincluse `n aceast edi]ie electronic /
B ;ex@Flex
B%1 ;ex@Flex <xamples % % % % % % % % % % % % % % % % % % % % % % % % % %
B%2 ).e ;ex@Flex 4nput File % % % % % % % % % % % % % % % % % % % % % % %
B%6 ).e 9enerated 7canner % % % % % % % % % % % % % % % % % % % % % %
B%1 4nterfacin& Ait. Bacc@Bison % % % % % % % % % % % % % % % % % % % %
C Bacc@Bison
C%1 $n ,(er(ieA % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
C%2 $ Bacc@Bison <xample % % % % % % % % % % % % % % % % % % % % % %
C%6 ).e Bacc@Bison 4nput File % % % % % % % % % % % % % % % % % % % %
C%1 Bacc@Bison ,utput/ t.e "arser File % % % % % % % % % % % % %
C%5 "arser C';an&ua&e 4nterface % % % % % % % % % % % % % % % % % %
C%6 !ebu&&in& Bour "arser % % % % % % % % % % % % % % % % % % % % % %
C%5 7ta&es in >sin& Bacc@Bison % % % % % % % % % % % % % % % % % % %
6
1
Capitolul 0
3n loc de moti(a]ie
!e ce s scriu o carte despre compilatoare# interpretoare #Flex [i Bison# `n limba
rom=n# `n anii primului cincinal al mileniului al doilea C 7unt de actualitate C Folosesc
ele cui(a C 7au rm=n un simplu exerci]iu academic ori te.nic# destinat profesorilor de
teoria compilatoarelor [i .acDerilor 0ade(ra]ilor .acDeri# acei exper]i autentici `n
compilatoare care sunt `n stare s']i in(ente+e un limba= de pe a+i pe m=ine sau s']i
ascund un (irus `ntr'un compilator astfel ca el s &enere+e pro&rame de lo&in EsparteF#
c.iar dac le compile+i din nou2 C !e ce o asemenea carte este necesar oportun [i
cui ar folosi C Ce moti(e sunt pentru scrierea ei C
4at'le# `ntr'o ordine oarecare# a[a cum mi'au (enit Gla prima stri&areF/
12 ;inux'ul se rsp=ndeste rapid# numrul de utili+atori cresc=nd (erti&inos cu cifre `ntre
6H [i 66H pe an 0numrul depinde de cate&oria de utili+atori# utili+atori casnici sau
mana&eri de ser(ere2% "entru acei utili+atori de ;inux care# uneori `n ciuda (=rstei# mai
au dorin]a de a `n(]a# de a se bucura ca ni[te copii care descoper 9oo&le'ul# pentru
ei# cei care uneori .abar n'au ce ser(icii le pot aduce Flex'ul [i Bisonul# merit s
traduc# s scriu# s complete+ aceast carte% $u o [ans `n plus s afle ce mai con]ine
distribu]ia lor fa(orit de ;inux% Iu scriu care distribu]ie# deoarece ma=oritatea distribu]i'
ilor de ;inux pe care le'am consultat 0JedKat 1%2# 5%2# 6%0# 6%1# 6%2# 5%0# 5%2 # Corel
;inux # *andraDe ;inux :%0# :%1# :%2# 8# 10 [i altele2 includ pac.etele Flex [i Bison%
22 Flex [i Bison nu sunt numai instrumente de scriere a compilatoarelor% Flex'ul e un
&enerator de anali+oare lexicale deci o unealt pentru `mpr]it texte `n Ecu(inteE 0sau
litere sau alte &rupri de simboluri cu structur specific2 [i de executat ac]iuni la
`nt=lnirea lor% Bisonul este c.iar mai puternic/ poate prelucra date imbricate# a(=nd
structuri [i substructuri# specificate printr'o &ramatic% <ste un &enerator de parsere
0anali+oare sintactice2 care pot fi dotate [i cu re&uli semantice# ceea ce `l face un
(eritabil &enerator de compilatoare%
62 Flex'ul [i `n mai mic msur Bison'ul pot fi de folos [i altor cate&orii de personal%
3ntr'un numr din re(ista "C Jeport# un alt &enerator de anali+oare lexicale era
pre+entat printr'un exemplu care re+ol(a o problem spinoas te.noredactorilor/
con(ersia textelor de la un font la altul sau la standardul >)F% Cei care s'au lo(it de
problema diacriticelor limbii rom=ne# problem pentru care exist c=te EbordeieE at=tea
Eobiceie de scriereE ' a se citi fonturi sau standarde# [i au primit nu o dat mail'ul unui
[ef suprat c textul nu se (ede cu diacritice pe computerul su# (or `n]ele&e
actualitatea problemei%
12 $]i putea fi de asemenea cititori ai unei asemenea cr]i dac dori]i s manipula]i date
structurate ori (re]i s ob]ine]i (ite+ la prelucrri ale unor anumite ba+e de date
5
reali+ate cu L*; # fr a mai `n(]a L*; [i `n condi]iile `n care aplica]ia (a fi reali+at cu
un compilator de limba= C%
52 $lte probleme banale pe fond dar relati( dificil de abordat cu mi=loace clasice [i
totodat adesea `nt=lnite la concursurile pentru posturi de pro&ramatori se re+ol( u[or
cu Flex [i Bison% !intre ele amintim crearea unui calculator e(aluator de expresii
numerice cu parante+e # 0un asemenea modul softAare ar ferici orice utili+ator de
produs de contabilitate# dar admit c poate fi reali+at [i altfel dect cu un &enerator de
compilatoare2 sau clasica problem de traducere care const `n a &enera pentru un
numr `n cifre transcrierea lui `n litere% $ceste probleme au [i alte solu]ii dar dac
reali+a]i o aplica]ie contabil cu ba+e de date *-7M; pe platform ;inux poate ('ar
interesa [i problemele de mai sus# mai ales dac pro&rama]i `n C sau CNN%
62 <xist o mul]ime de &eneratoare de compilatoare mai sofisticate dect perec.ea
Flex# Bison# unele folosite la $cademie sau `n medii uni(ersitare% <xist [i metode de
specificare mai e(oluate 0de exemplu Viena !efinition *et.od2% !in nefericire ori softul
este inaccesibil ma=orit]ii cititorilor# ori are licen] proprietar# ori rulea+ pe cine [tie ce
computer 7un 7parc 7tation pe care nu'l a(em la dispo+i]ie noi# utili+atoriui de "C'uri%
,ri pur [i simplu nu putem &si `n Jom=nia softAare'ul ori documenta]ia% Combina]ia
;inux plus Flex plus Bison plus 9CC 0compilatorul 9I># fost 9I> C Compiler2 rm=ne
deocamdat &eneratorul de compilatoare cu rsp=ndirea cea mai lar& [i de[i exist
(oci care afirm c re+ol( doar :0H din problem# este totu[i `ndr&it de
pro&ramatorii care ador s se afirme scriind ei c=t mai mult cod%
52 !ac sunte]i student la un curs de compilatoare sau doctorand la un `ndrumtor care
se ocup de construc]ia limba=elor# dac sunte]i frustrat c la finalul cursului n'a]i fcut
`nc un compilator# fie [i unul c=t de mic# pentru un limba= oric=t de simplu [i [ti]i s da]i
c=te(a comen+i unui ;inux atunci aceast carte e pentru dumnea(oastr cu si&uran]%
Iu pot s ( descriu emo]ia scrierii primului pro&rmel care (a rula pe interpretorul
dumnea(oastr sau (a fi compilat cu compilatorul dumnea(oastr% Oi mai ales satisfac]i'
a care o (e]i sim]i (+=nd c rulea+ sau se compilea+ [i se execut fr erori% V'o
spune un fost absol(ent al primei serii de la o facultate de 4nformatic# serie nscut
prin transformarea uneia din cele de la sec]iile Faculta]ii de *atematic% Ca student re'
u[isem performan]a de a termina facultatea de 4nformatic fr s fac practic nici un
compilator PPP *oti( pentru care dedic aceast carte [i fo[tilor cole&i de an [i fo[tilor mei
profesori# `nceptorii de alt dat 0preparatori# asisten]i etc2# speciali[tii de ast+i%
6
Capitolul 1
4ntroducere
>n compilator este `n esen] un pro&ram traductor ce transform pro&rame scrise `ntr'
un limba= surs `n ec.i(alentele lor scrise `ntr'un limba= obiect% ;imba=ul surs este de
obicei un limba= de pro&ramare de ni(el `nalt iar limba=ul obiect este de obicei limba=ul
ma[in al computerului% !in punct de (edere pra&matic putem afirma c prin translator
0compilator2 se define[te o anume semantic a limba=ului de pro&ramare% )ranslatorul
transform opera]iile date `n mod sintactic `n opera]ii ale modelului de calcul al unei ma
[ini (irtuale sau reale% $cest capitol arat cum sunt folosite &ramaticile independente de
context la construc]ia translatoarelor 0compilatoarelor2% !eoarece traducerea este
&.idat de sintaxa limba=ului surs# traducerea aceasta este numit Es-ntax'directed
translationE adic Etraducere ba+at pe sintaxE sau# mai bine +is Etraducere diri=at de
sintaxE%
!e ce este ne(oie de tot acest ansamblu de te.nici C V'a]i `ntrebat (reodat de fac
compilatoarele anali+ sintactic pe ba+a unei &ramatici C !oar de dra&ul (erificrii
sintaxei C Iicidecum P >n limba= de pro&ramare este ec.i(alent cu o mul]ime poten]ial
infinit de pro&rame% 7unt pro&ramele care se scriu `n el% !ac am `ncerca s definim
direct cum s'ar traduce ele# lu`ndu'le r=nd pe r=nd# nu ne'ar a=un&e (e[nicia% !eci
trebuie &site alte te.nici% )otu[i asemenea mul]imi infinite pot fi definite inducti( [i
stp=nite cu te.nici similare banalei induc]ii matematice de la liceu%
Ce este o defini]ie inducti( C !au un exemplu ar.icunoscut/ numerele naturale nenule
se pot defini cu doar dou elemente/ 1 [i functia succesor s0x2 care ni'l d pe
succesorul lui x adic pe x plus 1% $tunci numerele naturale nenule sunt/ 1# s012# s0s0122#
[amd% V'a]i prins C 7e `ncepe cu ceea ce matematicienii numesc ba+a induc]iei [i se
continu dup o re&ul inducti( care define[te ceea ce urmea+ func]ie de ceea ce
a(eam definit mai `nainte% $stfel putem stp=ni numerele naturale# `n infinitatea lor#
lucrnd cu doar dou elemente # 0 [i func]ia s0x2# cea care `n fapt descrie cum se ob]ine
un numr mai complicat din precedentul%
!orim s transcriem aceste numere ca sume de unit]i C !at fiind c numerele naturale
nenule sunt definite doar cu a=utorul a dou elemente# acum este simplu% )rebuie s
definim cum se transcriu ca sume de unit]i cele dou elemente / 1 [i s0ceva2 unde
ceva la r=ndul su s'ar putea scrie tot ca o sum de unit]i% 4at cele dou re&uli/
1 se transcrie prin 1# EsumaE cu un termen
s0x2 se transcrie prin/ 1 plus transcrierea lui x
$dic )012 este 1
iar )0s0x22 este 1 plus )0x2
C=t este# de exemplu# )0s0s0122 C
5
<ste 1 plus )0s0122 adic 1plus 1 plus )012 adic 1 plus 1 plus 1%
Conclu+ia/ "utem defini o traducere pe o mul]ime infinit de elemente definite structural
inducti( dac [tim cum se traduc/ elementele cele mai simple 0la un limba= de
pro&ramare structurat printre ele sunt instruc]iunile2 [i cum se traduc structurile
compuse% "entru structuri sunt date ni[te re&uli care ne spun de obicei c traducerea
structurii compuse se ob]ine imediat din traducerile structurilor componente% $cesta
este de altfel celebrul principiu compo+i]ional din semantic%
!eci de ce a(em ne(oie de sintaxa limba=ului# de structura lui sintactic sau sc.ema#
arborele sintactic al acestuia C 0Care nu'i mai complicat dect ceea ce se fcea la
[coala &eneral# la &ramatic ' acele desene arborescenteP2 !eoarece nu'l putem
traduce altfel# fiind infinit mul]imea pro&ramelor posibile% >n mod de a stp=ni
infinitatea aceasta este induc]ia matematic# definirea inducti( iar pentru induc]ie a(em
ne(oie de ba+a induc]iei 0elemente de limba= despre care [tim direct cum se traduc2 [i
re&ulile inducti(e 0structurale2 care spun cum se traduce o structur compus#
traducndu'i `nt=i componentele% $(=nd traducerea definit astfel# inducti(# pe structuri
[i substructuri# e clar c primul pas al compilrii e s &sesc# aceste structuri% <xact a[a
ce(a face anali+a sintactic P 4ar proiectantul unui limba= [i al unui compilator (a `ncepe
prin a scrie &ramatica limba=ului# acea descriere inducti(# structurat a sintaxei
limba=ului `nsu[i% <i `i (a asocia pe urm re&ulile semantice destinate a conduce
traducerea%
!efini]ie/ >n compilator este un translator al crui limba= surs este un limba= de ni(el
`nalt 0apropiat omului# cu cu(inte din limbile umane2 [i al crui limba= obiect este
apropiat de limba=ul ma[in al computerului concret disponibil% Compilatorul tipic
parcur&e urmtoarele fa+e [i fiecare fa+ prelucrea+ Eoutput'ulE# ie[irea care se ob]ine
din fa+a precedent/
Fa+a de analiz\ lexical\ 0EscanareaE textului `n cutarea cu(intelor [i altor entit]i2
&rupea+ caracterele `n unit]i lexicale# numite atomi lexicali 0`n en&le+
EtoDensE2% ;a intrarea anali+orului lexical se prime[te pro&ramul ca un [ir amorf
de caractere# litere spa]ii [i simboluri% ;a ie[ire re+ult un [ir de atomi lexicali%
)radi]ional# a[a+isele "expresiile regulate" sunt folosite pentru a defini [abloane
de recunoa[tere a atomilor de ctre scaner 0anali+or lexical2% $cesta este
implementat ca un automat finit determinist# o ma[in cu un numr de stri finit
care'[i sc.imb starea la primirea c=te unui caracter% 0Iot/ 7unt posibile [i alte
te.nici# de exemplu s'a in(entat anali+orul lexical adapti( care recuno[te [i `n(a'
] sin&ur diferitele cate&orii de atomi lexicali [i ne scute[te s mai scriem noi
specifica]iile% )ot ce ne rm=ne e s spunem care dintre clasele de atomi
descoperite (or fi identificatori# care numere etc% Iu (a fi `ns subiect al acestei
cr]i%2
;ex'ul [i Flex'ul sunt instrumentele cele mai populare de &enerare a anali+oarelor
lexicale # acele pro&rame care recunosc sin&ure [abloane lexicale `n text% Flex este o
:
(ariant mai rapid a ;ex'ului# compatibil cu acesta la ni(el de specifica]ii% 3n acest
capitol# prin ;ex @ Flex (om numi simultan ambele &eneratoare% 3n anexa despre ;ex @
Flex 0din (ersiunea en&le+ a cr]ii2 sunt preluate condensat elemente din manualul
EflexdocE scris de Vern "axon%
Analizorul sintactic 0parser'ul2 &rupea+ atomii lexicali 0toDens2 `n unit]i
0structuri2 sintactice% Ca re+ultat ob]ine o repre+entare arborescent/ $rborele
sintactic al pro&ramului# abre(iat ca 7) ' syntax tree# `n literatura de limb
en&le+% , &ramatic independent de context furni+at parserului 0&ramatica
limba=ului2 `i spune acestuia ce structuri sintactice s recunoasc% "arserul este
cel mai adesea implementat ca un automat pus.'doAn% 0$dic o ma[in cu
numr finit de stri `n+estrat [i cu o sti(% 4ntui]i probabil de=a c sti(a `i este
necesar pentru a urmri imbricarea structurilor sintactice# `nc.iderea
parante+elor desc.ise `n expresii [amd%2
Bacc [i Bison sunt instrumente pentru &enerarea de anali+oare sintactice 0parsere '
pro&rame care recunosc structura sintactic a unui pro&ram2% Bison este o (ersiune mai
rapid de Bacc% 3n acest capitol# prin Bacc @ Bison ne (om referi la ambele instrumente%
7ec]iunea pri(ind Bacc @ Bison este o condensare [i apoi extindere a documentului
EB47,I t.e Bacc'compatible "arser 9eneratorE scris de C.arles !onell- `mpreun cu
celebrul Jic.ard 7tallman%
Fa+a de analiz\ semantic\ prelucrea+ arborele sintactic `n cutarea acelor
informa]ii dependente de context numite `n en&le+ Estatic semanticsE 0s'ar
traduce prin Esemantic staticE2% ;a terminarea ei se ob]ine un arbore sintactic
0$7)2 adnotat% 0!e exemplu stabilirea tipurilor (ariabilelor din expresii# pe ba+a
declara]iilor precedente se face `n aceast fa+%2 Gramaticile cu atribute sunt
suportul teoretic al acestei etape% Cu a=utorul lor se descrie semantica static a
unui pro&ram%
$ceast fa+ se reali+ea+ de obicei concomitent cu anali+a sintactic% 4nforma]iile
colectate `n aceast fa+ pri(ind (ariabilele [i alte entit]i 0definite de pro&ramator `n
pro&ram2 sunt culese [i stocate `n tabela de simboluri 0 `n en&le+ ' symbol table).
$ceste informa]ii sunt folosite la (erificrile dependente de context# acele (erificri `n
care se confirm c o entitate a fost folosit conform cu specifica]iile existente despre
ea%
Optimizatorul 0arborelui2 supune arborele sintactic adnotat 0$7)2 unor
transformri care pstrea+ sensul de ansamblu al pro&ramului dar simplific
structura arborelui [i facilitea+ &enerarea unui cod mai eficient%
Generatorul de cod transform arborele adnotat [i simplificat `n cod obiect#
folosind re&uli care denot semantica limba=ului de pro&ramare% 0Vede]i [i
materiale despre denotational semantics%2 9eneratorul de cod poate fi inte&rat
8
anali+orului sintactic# astfel ca el s &enere+e cod imediat ce recunoa[te o
structur sintactic%
,ptimi+atorul de cod &enerat 0`n en&le+ Epeep'.ole optimi+er2 examinea+
codul obiect &enerat [i# constat=nd uneori c un &rup de instruc]iuni ale
procesorului se poate `nlocui cu una sin&ura sau cu un &rup mai mic# mai
eficient# ori mai rapid# reali+ea+ `mbunt]iri ale codului dependente de ma[in%
3n contrast cu compilatorul# interpretorul este un pro&ram care simulea+ execu]ia
pro&ramului scris `n limba=ul surs% 4nterpretoarele pot E`n]ele&eE [i executa fie direct
instruc]iuni ale unui limba= de pro&ramare de ni(el `nalt# fie pot compila pro&ramul [i
executa iterpretati( codul re+ultat# acest cod fiind de obicei &enerat ca pentru o ma[in
(irtual# adic un procesor de care nu dispunem `n form .ardAare% 3n aceast situa]ie#
compilatorul inclus &enerea+ un cod pentru acea ma[in (irtual# cod care
corespunde pro&ramului ini]ial din limba=ul surs%
<xist o lar& palet de translatoare care se folosesc `mpreun cu compilatoarele `n
procesul de reali+are a pro&ramelor% >n asamblor este acel translator 0compilator dac
(re]i2 al unui limbaj de asamblare. 4nstruc]iunile acestui limba= corespund una c=te una
unei instruc]iuni din codul obiect# adic din limba=ul procesorului% 0Cu alte cu(inte
limba=ul de asamblare nu este un limba= structurat# `n care s pute]i scrie instruc]iuni
compuse# imbricate# ci doar cel mult expresii # iar acestea sunt prelucrate doar de
unele asambloare mai sofisticate2% <xist compilatoare care &enerea+ codul `n limba=
de asamblare iar acesta (a fi transformat `n limba= ma[in de ctre un asamblor% >n
`ncrctor 0`n en&le+ loader2 e un translator pentru care at=t limba=ul de la intrare ct [i
cel de la ie[ire sunt limba= obiect% ;a intrare prime[te [i o tabel care spune unde
trebuie modificat pro&ramul `n limba= ma[in pentru a fi corect executat c=nd este plasat
`n memorie la o adres anume% >n link-editor e tot un fel de translator care prime[te o
colec]ie de module de pro&ram executabile [i le lea& `mpreun form=nd un sin&ur
pro&ram executabil destinat apoi execu]iei% >n preprocesor este un translator al crui
limba= surs este un fel de limba= de ni(el superior extins cu alte construc]ii# iar al crui
limba= obiect este acel limba= de ni(el superior# neextins%
Ca exemplu# `n cele ce urmea+ (om construi un compilator pentru un limba= de
pro&ramare imperati( ' de=a clasic `n cursurile de compilatoare ' numit Simple%
9ramatica limba=ului Simple, a[a cum ne'o propune domnul $nt.on- $% $ab-# este /
program ::= LET [ declarations ] N [command sequence] END
declarations ::= NTEGER [ id seq ] DENTFER .
id seq ::= [id seq ...] DENTFER ,
command sequence ::= command... command
10
command ::= SKP ;
| DENTFER := expression ;
| F exp THEN [command sequence] ELSE [command sequence] F ;
| WHLE exp DO [command sequence] END ;
| READ DENTFER ;
| WRTE expression ;
expression ::= NUMBER | DENTFER | '(' expression ' )'
| expression + expression | expression - expression
| expression * expression | expression / expression
| expression ^ expression
| expression = expression
| expression < expression
| expression > expression
Ieterminalii sunt scri[i cu minuscule# terminalii 0cu(intele limba=ului2 s'au scris cu
ma=uscule sau cu simboluri [i acolo unde ar fi fost pricin de confu+ie cu metasimboluri
din <BIF# s'au folosit [i &.ilimele simple% 7imbolul de start este program, neterminalul
corespun+tor cate&oriei &ramaticale a pro&ramelor complet scrise% !e[i am folosit
ma=uscule la scrierea cu(intelor limba=ului 0simbolurilor terminale2# la implementare (om
lucra cu minuscule%
;imba=ul (a a(ea dou re&uli# restric]ii# dependente de context% 7e cere ca (ariabilele s
fie declarate `nainte de a fi folosite [i ca (ariabilele s fie declarate exact o dat%
"entru necunosctorii nota]iei folosite 0de inspira]ie <BIF2# comentm sintaxa de mai
sus# re&ul cu re&ul/
program ::= LET [ declarations ] N [command sequence] END
"ro&ramul e format din cu(=ntul obli&atoriu ;<)# ni[te declara]ii care pot lipsi 0atunci
c=nd nu folosim (ariabile2# cu(ntul obli&atoriu 4I # sec(en]a de instruc]iuni de executat#
care poate fi [i ea (id# [i# `n cele din urm se termin cu <I!%
declarations ::= NTEGER [ id seq ] DENTFER .
!eclara]iile `ncep cu cu(=ntul 4I)<9<J [i se termin cu un identificator 0oarecare2 [i un
punct% "oate fi dup 4I)<9<J o sec(en] mai lun& de al]i identificatori declara]i `n
aceea[i declara]ie%
id seq ::= [ id seq ...] DENTFER ,
$ceast sec(en] se termin totdeauna cu (ir&ul pus dup ultimul identificator [i
`ncepe cu o sec(en] 0care notm noi poate fi [i (id% "ractic sec(en]a# a[a cum (a
apare `n declara]ie# este format din identificatori urma]i de (ir&ul# cu excep]ia ultimului
0din declara]ie2 despre care am (+ut din re&ula anterioar c era urmat de punct%
command sequence ::= command... command
11
7ec(en]a de comen+i este format din comen+i puse una dup alta# pur [i simplu% Vom
(edea din re&ula urmtoare c fiecare comand include un simbol Epunct [i (ir&ulE%
$m scris peste tot [command sequence] cu parante+e drepte deoarece ea putea fi [i (id#
adic putea lipsi% 3n nota]ia de specialitate parante+a ptrat marc.ea+ un element op'
]ional al construc]iei sintactice respecti(e%
command ::= SKP ;
| DENTFER := expression ;
| F exp THEN [command sequence] ELSE [command sequence] F ;
| WHLE exp DO [command sequence] END ;
| READ DENTFER ;
| WRTE expression ;
4nstruc]iunile posibile sunt instruc]iunea (id 7Q4"# atribuirea# 4F')K<I'<;7< terminat
cu F4# RK4;<'!, terminat cu <I! precum [i dou instruc]iuni de intrare ie[ire# absolut
necesare ca s comunicm cu calculatorul `n 7imple/ citirea (alorii unui identificator [i
scrierea (alorii unei expresii%
Iota]i c 4!<I)4F4C$),J este scris cu ma=uscule ca un terminal 0iar el (a fi furni+at ca
atare dup anali+a lexical# ca un sin&ur atom lexical oricum s'ar numi el iar numele `i
(a de(eni un simplu atribut2% 3n timp ce EexpressionE # expresia# este scris cu
minuscule# ca un neterminal deoarece e numele unei cate&orii &ramaticale din pro&ram%
<xpresiile au structur# nu's simboli terminali# [i (or trebui anali+ate sintactic mai
departe% Felul cum sunt structurate expresiile e descris de re&ula urmtoare/
expression ::= NUMBER | DENTFER | '(' expression ' )'
| expression + expression | expression - expression
| expression * expression | expression / expression
| expression ^ expression
| expression = expression
| expression < expression
| expression > expression
<xpresia poate fi un simplu numr# un simplu identificator sau o expresie pus `n
parante+ 0ce se comport ca (aloarea ei2% *ai poate fi o sum# o diferen]# un produs
sau un c=t de expresii precum [i un Gade(ratF 012 sau GfalsF 002 re+ultat `n urma unei
compara]ii# a unei (erificri dac alte dou expresii sunt `ntr'o rela]ie de e&alitate #
ine&alitate ori compara]ie de un fel sau altul 0 S # T 2%
,bser(a]ie/ acele cate&orii &ramaticale care corespund unor neterminali din care poate
deri(a un [ir (id 0deci acelea care pot lipsi2 au fost# nu uita]i# puse `n parante+% Vom
(edea `n capitolul urmtor o alt nota]ie pentru &ramatica limba=ului 7imple# e(iden]iind
ni[te re&uli 0sau mai corect alternati(e ale unor re&uli2 cu partea dreapt (id% !ar
aceasta la momentul potri(it% !eocamdat# `n acest capitol# am (rut doar s (a
familiari+m cu limba=ul ce urmea+ a fi implementat%
12
Capitolul 2
$nali+orul sintactic 0"arser'ul2
>n parser este un pro&ram care determin dac textul primit de el este sintactic corect
[i `n plus# `i determin c.iar structura% $ltfel spus nu spune doar ECorect PE sau E4ncorect
PE% "arserele pot fi scrise de m=n sau pot fi automat &enerate de un &enerator de
anali+oare sintactice# pornind de la descrierea unor structuri sintactice corecte 0ce (or fi
recunoscute# (alidate# de (iitorul parser2% $ceste descrierei de sintax iau forma unor
&ramatici independente de context% 9eneratoarele de anali+oare sintactice pot fi
folosite la de+(oltarea de parsere pentru o &am lar& de limba=e# de la limba=ul
expresiilor cu parante+e pe care `l folose[te un calculator de birou p=n la cele mai
complexe limba=e de pro&ramare%
Bacc @ Bison este un asemenea &enerator care primind la intrare o descriere a unei
&ramatici independente de context 094C2 construie[te un pro&ram `n C 0iar (ersiunile
noi de Bison pot produce [i pro&rame `n CNN PP2 care (a anali+a sintactic un text
conform cu re&ulile &ramaticii date% Bacc a fost de+(oltat de 7% C% Uo.nson [i de cole&ii
si de la $)V) Bell ;aboratories% $t=t Bacc c=t [i Bison permit s manipula]i `mpreun
cu sti(a anali+orului sintactic o a doua sti( 0`n care se operea+ sincron cu prima la
fiecare `ncepere@terminare de structur sintactic2# aceast a doua sti( fiind destinat
manipulrilor fcute de rutinele semantice% 0Iu uita]i c (om face traducere Es-ntax'
dri(enE# deci condus de sintax2%
Fi[ierul de intrare pentru Bacc@Bison are urmtoarea structur/
declara]ii C [i declara]ii parser
%%
Je&ulile &ramaticii [i ac]iunile semantice ata[ate 0care (or opera cu a doua sti(2
%%
Func]ii C 0adesea aici se include [i func]ia *ain# care nu e &enerat automat2
"e scurt/
declara]ii C [i parser
%%
Je&uli
%%
Func]ii C
"rima sec]iune con]ine [i lista atomilor lexicali 0diferi]i de simple caractere2 care sunt a
[tepta]i de ctre parser deoarece fac parte din limba=% )ot aici se include [i declara]ia
simbolului ini]ial din &ramatic# acel neterminal care corespunde no]iunii de pro&ram
complet% $ceast sec]iune poate con]ine [i specifica]ii pri(ind ordinea opera]iilor [i
asociativitatea operatorilor. Ca efect# utili+atorul are o mai mare libertate `n proiectarea
limba=ului# `n al&erea &ramaticii sale% $dunarea [i scderea (or fi declarate asociati(e la
st=n&a [i cu cea mai mic preceden] `n timp ce ridicarea la putere este declarat ca
16
fiind asociati( la dreapta [i a(=nd cea mai mare preceden]# cea mai mare prioritate%
%start program
%token LET NTEGER N
%token SKP F THEN ELSE END WHLE DO READ WRTE F
%token NUMBER
%token DENTFER ASSGNOP
%left '-' '+'
%left '*' '/'
%right '^'
%%
Reguli ale gramaticii cu ac]iuni
%%
Subrutine C
$ doua sec]iune a fi[ierului cuprinde &ramatica independent de context a limba=ului de
anali+at% Je&ulile 0numite produc]ii2 sunt aici separate prin EWE 0punct [i (ir&ul2# simbolul
X ::= X este `nlocuit de X/X # o e(entual parte dreapt (id este scris ca atare #
neterminalii sunt scri[i cu minuscule iar terminalii din mai multe simboluri 0cum este
semnul atribuirii2 cu ma=uscule% Jemarca]i o anumit simplificare a &ramaticii datorit
separrii informa]iilor despre prioritatea operatorilor de restul &ramaticii% 0Constructorii
de compilatoare cu experien] [tiu c lu=nd `n considerare prioritatea operatorilor#
&ramatica expresiilor aritmetice se scrie cu mai multe re&uli dec=t `n exemplul nostru%2
Declaratiile anterioare
%%
program : LET declarations N commands END ;
declarations : /* empty */
| NTEGER id seq DENTFER '.'
;
id seq : /* empty */
| id seq DENTFER ','
;
commands : /* empty */
| commands command ';'
;
command : SKP
| READ DENTFER
| WRTE exp
| DENTFER ASSGNOP exp
| F exp THEN commands ELSE commands F
| WHLE exp DO commands END
;
exp : NUMBER
| DENTFER
| exp '<' exp
| exp '=' exp
| exp '>' exp
| exp '+' exp
| exp '-' exp
| exp '*' exp
| exp '/' exp
11
| exp '^' exp
| '(' exp ')'
;
%%
Subrutine C
$ treia sec]iune din fi[ierul cu specifica]ii Bacc const `ntr'o colec]ie de func]ii scrise `n
limba=ul C% "rintre ele se recomand s existe func]ia main() care (a apela func]ia
yyparse(). Func]ia yyparse() este de fapt subrutina produs de &enerator 0pe ba+a
specifica]iilor de mai `nainte2 [i este cea care (a conduce anali+a sintactic% 3n ca+ de
eroare ea (a `ncerca s apele+e func]ia yyerror() pentru a semnala [i prelucra
eroarea% $ceast func]ie --parse02 e lsat s fie scris de pro&ramator# ceea ce
confer flexibilitate% 4at ni[te exemple simple cum ar putea arta func]iile main02 [i
--parse02/
declara]ii C [i declara]ii parser
%%
Je&ulile &ramaticii
%%
main( int argc, char *argv[] )
{ extern FLE *yyin;
++argv; --argc;
yyin = fopen( argv[0], 'r' );
yydebug = 1;
/* errors = 0; */
yyparse ();
}
yyerror (char *s) /* Called by yyparse on error */
{ /* errors ++; */
printf ("%s\n", s);
}
Iot/ Variabila errors (a numra erorile din timpul anali+ei sintactice% "ute]i renun]a la
ea dac nu dori]i acest lucru% !ac totu[i dori]i s'o folosi]i# elimina]i comentariile de pe
r=ndurile unde se fac referin]e la ea [i nu uita]i s'o declara]i ca (ariabil &lobal a
pro&ramului `n sec]iunea declara]iilor C% 0 int errors; 2
!ar pentru a nu complica acest exemplu minimal ('a[ recomanda ca `n prima fa+ s
renun]a]i la ea%
"arserul# a[a cum este &enerat pe ba+a specifica]iilor de p=n acum# nu &enerea+
nimic la ie[ire# nici mcar arborele sintactic% $cesta este `ns implicit construit `n timpul
anali+ei% "e msur ce anali+a pro&resea+# parserul crea+ ni[te structuri interne care
corespund sintaxei pro&ramului anali+at% Jepre+entarea aceasta intern se ba+ea+ pe
pr]ile drepte ale re&ulilor &ramaticii% C=nd o parte dreapt a unei produc]ii 0re&uli2 este
recunoscut ea e `nlocuit cu partea st=n& corespun+toare% ,pera]ia se nume[te
reducere. Vom spune c partea dreapt a re&ulii a fost redus\ la neterminalul din
15
st=n&a re&ulii% $cesta la r=ndul su este candidat la a fi&ura `n partea dreapt a unei
alte re&uli [i a[a mai departe p=n c=nd `ntre&ul pro&ram este redus la simbolul de start
al &ramaticii# semn c anali+a a reu[it cu succes%
Compilarea fi[ierului surs de mai sus# simple.y se face cu Bacc# tast=nd comanda/
-acc '(d simple%-
sau pe un sistem ;inux pe care este instalat Bison# cu comanda/
bison '(d simple%-
sau
bison 'd( simple%-
%%%unde pute]i `nlocui pe simple%- cu numele fi[ierului dumnea(oastr%
3n urma prelucrrii se ob]ine un fi[ier cu extensia dubl %tab%c [i acela[i nume `naintea
extensiei ca fi[ierul ini]ial% 3n exemplul nostru se (a numi simple%tab%c deoarece
specifica]iile se numeau simple%- % <xtensia tradi]ional a fi[ierelor cu specifica]ii
Bacc@Bison este %- %
Fi[ierul %tab%c astfel ob]inut poate fi compilat cu compilatorul de C de pe sistemul
dumnea(oastr >nix @ ;inux% <l con]ine [i func]iile scrise de dumnea(oastr [i func]ia
&enerat --parse02 care face anali+a% 7istemul de ,perare ;inux (ine cu compilatorul
9CC# iar linia de comand necesar pentru a compila sursa %c (a fi/
&cc 'c simple%tab%c
%%% ceea ce duce la ob]inerea modulului obiect cu numele simple%tab%o %
Iota]i [i faptul c `n urma folosirii Bacc @ Bison se mai &enerea+ un fi[ier# cu extensia %
tab%. % $cesta con]ine defini]ii de constante care asi&ur transferul corect al informa]iilor
`ntre anali+orul sintactic 0parserul2 &enerat de Bacc @Bison [i anali+orul lexical &enerat
de Flex @ ;ex % 4deea este c fiecare tip de atom lexical (a a(ea un numr# iar aceste
numere definite [i a[teptate de parserul produs de Bacc @ Bison trebui s'i (in de la
anali+orul lexical% $cesta trebuie deci [i el s le cunoasc# ceea ce (a face inclu+=nd `n
sursa sa fi[ierul cu extensia %tab%. &enerat de Bacc @ Bison%
Iu cuta]i Bacc pe sistemele ;inux% Bacc este distribuit `mpreun cu sistemele >nix%
7istemele ;inux# oferite sub licen]a 9I> 9"; de ctre Free 7oftAare Foundation 4nc%#
au `n distribu]ie Bison `n loc de Bacc% Bison este un produs al Free 7oftAare
Foundation%
"entru mai multe informa]ii despre folosirea Bacc @ Bison ( ru&m fie s cuta]i `n
anexele cr]ii de fa]# fie s consulta]i pa&ina de manual pentru bison folosind
comanda/
man bison
16
*ai pute]i citi 0dac le &si]i P2 lucrrile/ E"ro&rammin& >tilities and ;ibraries ;J "arsin&E
de $%V%$.o [i 7%C%Uo.nson publicat `n Computin& 7ur(e-s `n iunie 1851 [i documentul
EB47,I t.e Bacc'compatible "arser 9eneratorE# de C.arles !onnell- [i Jic.ard
7tallman%
3n urma completrii tuturor celor trei sec]iuni ale fi[ierului Bacc# acesta (a arta ca mai
=os/
/* Declaratii */
%start program
%token LET NTEGER N
%token SKP F THEN ELSE END WHLE DO READ WRTE F
%token NUMBER
%token DENTFER ASSGNOP
%left '-' '+'
%left '*' '/'
%right '^'
%%
program : LET declarations N commands END ;
declarations : /* empty */
| NTEGER id_seq DENTFER '.'
;
id_seq : /* empty */
| id_seq DENTFER ','
commands : /* empty */
| commands command ';'
;
command : SKP
| READ DENTFER
| WRTE exp
| DENTFER ASSGNOP exp
| F exp THEN commands ELSE commands F
| WHLE exp DO commands END
;
exp : NUMBER
| DENTFER
| exp '<' exp
| exp '=' exp
| exp '>' exp
| exp '+' exp
| exp '-' exp
| exp '*' exp
| exp '/' exp
| exp '^' exp
| '(' exp ')'
;
%%
/* Subrutine */
int main (int argc, char * argv[] )
{extern FLE *yyin;
++argv; --argc;
15
yyin = fopen( argv[0], "r" );
yydebug = 1 ;
yyparse();
}
yyerror (char *s) /* Called by yyparse on error */
{
print("%s\n", s);
}

"entru a'l procesa urma]i indica]iile din pa&inile precedente sau exemplul de sesiune
de lucru la terminal dat `n anex%
1:
Capitolul 6
7caner'ul 0$nali+orul lexical2
>n anali+or lexical 0en&l% scanner2 este un pro&ram capabil s descopere [i s clasifice
por]iuni de text 0Ecu(inteE2 conforme cu ni[te [abloane date% $nali+oarele lexicale pot fi
ori scrise de m=n# ori &enerate automat de un &enerator de anali+oare lexicale# pe
ba+a listei de [abloane pe care le au de recunoscut% !escrierea acestor [abloane se
face sub form de expresii regulate%
;ex este un &enerator de anali+oare lexicale de+(oltat de *%<%;esD [i <%7c.midt de la
$)V) Bell ;aboratories% ;ex prime[te la intrare un fi[ier con]in=nd descrierile atomilor
de recunoscut# fiecare clas de asemenea atomi 0ex% numere# identificatori etc2 fiind
caracteri+at# descris# de o expresie re&ulat% ;ex produce la ie[ire un `ntre& modul de
pro&ram# scris `n C# care poate fi compilat [i linD'editat `mpreun cu alte module%
0"rintre aceste module este adesea [i cel &enerat de Bacc @Bison ' anali+orul sintactic '
precum [i alte componente ale unui compilator# sau interpretor%2 Fi[ierul de intrare
pentru ;ex @Flex este or&ani+at similar cu cel pentru Bacc @Bison # tot `n trei sec]iuni
separate prin HH% "rima con]ine declara]ii pentru scanner [i alte declara]ii C # a doua
con]ine `n loc de &ramatic descrierile atomilor lexicali 0toDens2 sub form de expresii
re&ulate [i ac]iunile pe care le (a face anali+orul `nt=lnindu'le 0de obicei returnea+
parser'ului codul atomului respecti(# e(entual [i alte informa]ii2 iar a treia con]ine restul
de subrutine 0func]ii2 scrise `n C%
Ca urmare a prelucrrii intrrii# ;ex produce un fi[ier cu extensia %c# `n care e definit
func]ia yylex(), func]ie ce (a returna un `ntre& corespun+tor fiecrui atom &sit%
$ceast func]ie (a fi apelat de func]ia main() scris de pro&ramator `n ultima sec]iune#
dac facem doar recunoa[terea [i prelucrarea atomilor lexicali sau de func]ia din
modulul de anali+ sintactic# dac construim un compilator sau un interpretor% 3ntr'o
asemenea situa]ie func]ia --lex02 ofer ser(icii 0(alori2 func]iei --parse02 din modulul
&enerat de Bacc@Bison%
Codurile di(ersilor atomi lexicali sunt la fel `n]elese de ambele func]ii --lex02 [i --parse02
deoarece fi[ierul &enerat de ;ex (a cuprinde [i directi(a de includere a fi[ierului .eader
&enerat de Bacc# cu extensia %tab%.% 4ncluderea pic `n sarcina pro&ramatorului%
$[a arat fi[ierul de intrare pentru ;ex/
declara]ii C [i declara]ii pentru scanner
%%
!escrieri de atomi lexicali sub forma expresilor re&ulate [i ac]iuni
%%
Func]ii C # subrutine
18
3n exemplul nostru# cea dint=i declara]ie care se (a scrie `n prima sec]iune a fi[ierului
pentru ;ex este cea de includere a fi[ierului simple%tab%.% # &enerat anterior de Bacc @
Bison% <l con]ine defin]ii pri(ind atomii multi'caracter% !e asemenea# prima sec]iune
cuprinde o serie de defini]ii a=uttoare pentru scrierea expresiilor re&ulate din sec]iunea
a doua% 3n exemplul nostru (om defini aici pe !494) ca o sec(en] de una sau mai
multe cifre de la 0 la 8 iar pe 4! 0de la identificator2 ca fiind o liter urmat de una sau
mai multe litere [i@sau cifre%
%{
#include "simple.tab.h" /* The tokens */
%}
DGT [0-9]
D [a-z][a-z0-9]*
%%
!escrieri de atomi lexicali sub forma expresilor re&ulate [i ac]iuni
%%
Func]ii C # subrutine
"or]iunea dintre %{ [i %} (a fi transcris fr modificri `n textul &enerat% ,bser(a]i c
am folosit directi(a #include pentru a include fi[ierul simple%tab%. % 0'8 semnific o cifr
din mul]imea de cifre de la 0 la 8% a'+ `nseamn o liter din mul]imea de litere de la a la
+ iar a'+0'8 un simbol din reuniunea celor dou mul]imi% ,bser(a]i c se scriu cu
parante+ ptrat nu cu acolad% 7telu]a de dup parante+a ptrat `nseamn c pot fi
oric=te elemente din acea mul]ime `n succesiune imediat# inclusi( nici unul% 3n cele din
urm facem obser(a]ia c !494) repre+int orice cifr iar 4! orice identificator%
$ doua sec]iune din fi[ierul ;ex 0acestea au extensia %lex2 este seria de pereci [ablon
0dat de expresia re&ulat2 - ac]iune 0dat ca un corp de func]ie C# cuprins `n acolade2%
Fiecrui fel de atom lexical 0toDen2 descoperit `i corespunde o ac]iune bine preci+at%
Oirurile de unu sau mai mul]i di&i]i sunt recunoascute ca numere `ntre&i [i ca urmare#
(aloarea constantei I>*B<J (a fi returnat parserului% Cu(intele re+er(ate ale
limba=ului sunt sec(en]e de litere minuscule% 07e poate lucra [i cu ma=uscule dar ele (a
fi necesar s fie tratate altfel PP2 7pa]iile albe# blanc'uri# tab'uri (or fi i&norate# nu (or
produce nici o ac]iune% 3n dreptul lor `n loc de ac]iune este un comentariu% )oate
celelalte caractere 0ceea ce `n ;ex se notea+ cu simbolul punct G.F2 (or fi pur [i simplu
returnate a[a cum sunt% 7canerul plasea+ textul de parcurs `n (ariabila strin& yytext [i
`ntotdeauna yytext[0] este caracterul curent de prelucrat%
declara]ii C [i declara]ii pentru scanner
%%
":=" { return(ASSGNOP); }
{DGT}+ { return(NUMBER); }
do { return(DO); }
else { return(ELSE); }
end { return(END); }
fi { return(F); }
if { return(F); }
in { return(N); }
20
integer { return(NTEGER); }
let { return(LET); }
read { return(READ); }
skip { return(SKP); }
then { return(THEN); }
while { return(WHLE); }
write { return(WRTE); }
{D} { return(DENTFER); }
[ \t\n]+ /* blank, tab, new line: eat up whitespace */
. { return(yytext[0]); }
%%
Subrutine C
,bser(a]i c fiecrui tip de atom lexical i se asocia+ de re&ul ac]iunea de a `ntoarce o
(aloare `ntrea& 0constant2 care semnific felul de atom lexical descoperit%
;ista urmtoare cuprinde forma c=tor(a feluri u+uale de expresii re&ulate care ( pot fi
de folos la a specifica atomii lexicali de recunoscut% Iota]i [i faptul c exist o (ariabil
&lobal yylval , accesibil at=t scanerului &enerat de ;ex c=t [i parserului &enerat de
Bacc @Bison% <a poate fi folosit pentru a transmite alte informa]ii le&ate de atomul al
crui cod tocmai a fost returnat%
. orice caracter cu excep]ia returului de car# <I)<J
x [ablonul care se potri(e[te cu caracterul XxX
rs concatenarea 0succesiunea2 a ce(a care se potri(e[te cu r [i ce(a ce se potri(e[te cu s
r|s reuniunea sau alternati(aW se potri(esc cu ea at`t sec(en]ele de cractere corespun+toare
expresiei r c`t [i cele corespun+toare expresiei s
(r) la fel ca r ; parentezele se folosesc la grupare
r* +ero sau mai multe sec(en]e de caractere ce se potri(ese cu r#
unde r poate fi orice expresie re&ulat
r+ una sau mai multe sec(en]e de caractere ce se potri(ese cu r#
unde r poate fi orice expresie re&ulat
[xyz] o clas 0mul]ime2 de caractere# `n acest exemplu se (or potri(i cu [ablonul doar caracterele
XxX # X-X# X+X
[abj-oZ] o clas 0mul]ime2 de caractere# `n acest exemplu se (or potri(i cu [ablonul doar
caracterele XaX sau XbX #orice de la X=X la XoX inclusi(# sau XYX
{NAME} expandarea unei 0macro2defini]ii anterioare# cu numele I$*<
\X dac L este un ul dintre caracterele XaX# XbX# XfX# XnX# XrX# XtX sau X(X # atunci \X se interpretea+
conform standardului ANS-C
"[+xyz]+\"+foo" stringul: [xyz]"foo
21
$ treia sec]iune a fi[ierului (a fi lsat necompletat `n acest exemplu% !ar `n ca+ul `n
care ac]iunile anali+orului lexical presupuneau opera]ii complexe [i apeluri de func]ii
utili+ator# aceste func]ii puteau fi adu&ate aici# `n a treia sec]iune% $stfel scrierea ac]i'
unilor de(ine mai clar iar unele detalii nesemnificati(e sunt ascunse `n func]iile
0subrutinele2 din a treia sec]iune%
Compilarea fi[ierului ;ex se face cu una din comen+ile/
lex !i"ier.lex
respecti(
flex !i"ier.lex
[i se (a ob]ine un fi[ier cu denumirea lex%--%c `n care e &enerat func]ia yylex(). ;a
fiecare apel al func]iei --lex02# intrarea (a fi scanat 0parcurs2 `n cutarea urmtorului
atom lexical [i se (a executa ac]iunea pro&ramat care'i corespunde% 3n ca+ul din
exemplul nostru se (a returna codul atomului respecti(%
Ve]i lucra cu ;ex dac a(e]i un sistem >nix de firm# deoarece ;ex este distribuit
`mpreun cu sistemele >nix sau cu EclonaE acestuia# Flex# dac folosi]i un sistem ;inux%
Flex este un produs al Free 7oftAare Foundation# 4nc%# distribuit sub licen] &neral
public 9I> 9";%
, sesiune tipic de lucru cu o ma[in ;inux# folosind Flex# Bison [i compilatorul 9CC
pentru a ob]ine pro&ramul binar# executabil# 0in sursele C nerate de Flex [i Bison2 se
desf[oar dnd comen+ile din lista de mai =os% $m presupus c cele dou fi[iere cu
specifica]ii se numesc simple.y [i simple.lex% "romptul sistemului este notat cu EZE de
obicei [i nu face parte din comand/
Z bison 'd( simple.y
Z &cc 'c simple.tab.c
Z flex simple.lex
Z &cc 'c lex%--%c
Z &cc 'o simple simple.tab.o lex%--%o 'lm 'lfl
"rima comand in(oc Bison pentru a &enera din sursa simple.y fi[ierul simple.tab.c [i
fi[ierul simple.tab. care fi&urea+ ca inclus `n sursa ce V$ F4 &enerat de Flex @;ex%
$ doua in(oc compilatorul &cc pentru a compila simple.tab.c [i a ob]ine modulul obiect
simple.tab.o.
$ treia &enerea+ din specifica]ia ;ex simple.lex sursa C cu nume standard lex%--%c%
$ patra este comanda de compilare a acestei surse [i re+ult modulul obiect lex%--%o%
3n sf=r[it# cu ultima comand se lea& modulele obiect simple.tab.o [i lex%--%o `mpreun
cu o serie de func]ii de bibliotec `n executabilul binar simple% $ten]ie la op]iunile din
finalul liniei de comand% "e sistemul Jed Kat ;inux 5%2 cu care am rulat prima oar
aceste exemple trebuie scrise neaparat op]iunile ';* ';F; dar cu minuscule PPP "e alte
(ersiuni de sisteme ;inux este suficient doar prima op]iune ';* scris tot cu
minusculeP
22
"entru mai multe informa]ii despre comen+ile [i op]iunile ;ex @ Flex consulta]i pa&inile
de manual lex # flex de pe sistemul dumnea(oastr >nix @ ;inux# documenta]ia flexdoc
[i citi]i lucrarea E;ex ' ;exical $nal-+er 9enerator de *% <% ;esD [i <% 7c.midt# `n ca+ul
c=nd o pute]i &si%
3n final# `ntre&ul fi[ier simple%lex# pentru limba=ul 7imple# arat a[a/
%{
#include "simple.tab.h" /* The tokens */
%}
DGT [0-9]
D [a-z][a-z0-9]*
%%
":=" { return(ASSGNOP); }
{DGT}+ { return(NUMBER); }
do { return(DO); }
else { return(ELSE); }
end { return(END); }
fi { return(F); }
if { return(F); }
in { return(N); }
integer { return(NTEGER); }
let { return(LET); }
read { return(READ); }
skip { return(SKP); }
then { return(THEN); }
while { return(WHLE); }
write { return(WRTE); }
{D} { return(DENTFER); }
[ \n\t]+ /* blank, tab, new line: eat up whitespace */
. { return(yytext[0]); }
%%
Comentariile le pute]i scrie# bine`n]eles [i `n limba rom=n% "rimul ! "#e to$ens ! s'ar
putea traduce prin !%tomii lexicali! de[i textual toDens `nseamn G=etoaneleF%
$l doilea @[ blanD# tab# neA line/ eat up A.itespace [@ s'ar traduce mai bine prin
! succesiunile formate cu spa]iu, tab sau enter & toate sunt consumate !.
26
21
Capitolul 1
Contextul
7pecifica]iile din fi[ierele ;ex [i Bacc potr fi extinse pentru a manipula informa]ii
dependente de context% !e exemplu# s presupunem c `n limba=ul 7imple impunem ca
(ariabilele s fie declarate `nainte de a fi folosite% !in acest moti( parserul 0anali+orul
sintactic2 trebuie s fie capabil s compare referin]ele la (ariabile cu declara]iile
acestea# care sunt memorate `n (ederea (erificrilor%
>n mod de a re+ol(a aceast problem este de a construi `nc din timpul parcur&erii
sec]iunii de declara]ii a pro&ramului un fel de list de (ariabile [i de a (erifica apoi
fiecare (ariabil `nt=lnit# compar=nd'o cu datele de pe list% , asemenea list este
numit tabel\ de simboluri% )abelele de simboluri pot fi implementate folosind liste#
arbori# 0arbori de cutare2 sau tabele'.as.%
Vom modifica fi[ierul ;ex pentru a atribui (ariabilei &lobale yylval un strin& cu informa]ii
de identificare de fiecare dat c=nd `nt=lnim o entitate 0atom2 a crei set de
caracteristici se (or pstra `n context% $semenea informa]ii (or fi# `n teorie# atribute
prelucrate de gramatica cu atributre%
*odulul )abel de 7imboluri 07)%.2
"entru a pstra informa]iile cerute de prelucrrile ce le (a face &ramatica cu atribute#
(om construi o tabel de simboluri% )abela de simboluri cuprinde informa]ii de context
pri(ind atributele di(erselor construc]ii 0sintactice2 scrise `n limba=ul de pro&ramare%3n
particular# pentru (ariabile# cuprinde informa]ii despre tipul 0en&% type 2 [i domeniul de
(i+ibilitate 0en&% scope 2 al (ariabilei%
)abela de simboluri pe care o (om de+(olta (a fi un modul surs C care se (a include
de ctre sursa &enerat 0de ctre Bacc @ Bison 2# cu oca+ia compilrii%
Cititorul ambi]ios este in(itat ca# dup parcur&erea inte&ral a acestui (olum# s
in(ente+e un limba= de specificare a tabelelor de simboluri [i un &enerator de surse C
0similar Bacc'ului [i Bison'ului2 pentru a &enera module asemntoare celui de mai =os
pornind de la specifica]ii% 4nstrumentele cu care (a lucra (or fi e(ident Bacc @ Bison
pentru anali+a sintactic [i &enerarea outputului prin ac]iuni semantice [i ;ex @Flex
pentru anali+a lexical2%
)abela de simboluri pentru limba=ul 7imple const `ntr'o list simplu `nln]uit de
identificatori# ini]ial (id% 4at declara]ia unui nod 0element2 al listei
struct symrec
{char *name; /* name of symbol - numele simbolului*/
25
struct symrec *next; /* link field - pointerul la alt element*/
};
apoi definirea tipului symrec [i ini]iali+area listei (ide cu un pointer nul
typedef struct symrec symrec;
symrec *sym_table = (symrec *)0;
symrec *putsym ();
symrec *getsym ();
[i cele dou opera]ii% "rima# putsym e cea care pune un identificator `n tabel
symrec *
putsym ( char *sym_name )
{symrec *ptr;
ptr = (symrec *) malloc (sizeof(symrec));
ptr -> name = (char *) malloc (strlen(sym_name)+1);
strcpy (ptr -> name, sym_name);
ptr -> next = (struct symrec *)sym_table;
sym_table = ptr;
return ptr;
}
Comente+ pu]in codul func]iei putsym pentru e(entualii cititori mai pu]in familiari+a]i cu
limba=ul C% !ac stp=ni]i bine C'ul# trece]i direct la pa&ina urmtoare# la func]ia getsym%
"rimul r=nd declar tipul re+ultatului dat de func]ie# care e pointer la un record 0element
de list2 symrec# deci e [i pointer la o list de asemenea elemente%
symrec *
>rmea+ numele func]iei [i parante+a cu parametrul formal unic de tip pointer la
caracter 0sinonim `n C cu strin&2# cu numele sym#name/
putsym ( char *sym_name )
Corpul func]iei `ncepe cu declararea (ariabilei locale ptr# pointer la tipul symrec/
{symrec *ptr;
7e aloc spa]iu pentru structura 0record'ul2 propriu'+is [i pentru numele sym#name ce e
destinat a fi stocat `n acea intrare din tabel%
ptr = (symrec *) malloc (sizeof(symrec));
ptr -> name = (char *) malloc (strlen(sym_name)+1);
7e copie apoi numele dat ca parametru `n spa]iul alocat de=a# indicat de pointerul
ptr-$name# stoc=nd astfel copia numelui `n tabel% 0Func]ia C strcp-02 este o (eritabil
atribuire pentru strin&uri# capabil s copie al doilea strin& de la adresa sa# la adresa
primului strin&# dat ca prim parametru%2
26
strcpy (ptr -> name, sym_name);
<lementul nou creat# aflat la adresa ptr de(ine primul element din list iar capul de list
sym#table (a arata acum spre el% )ot aceast adres a elementului nou [i simultan a
listei este returnat de func]ia al crei corp se `nc.eie cu obi[nuita acolad%
ptr -> next = (struct symrec *)sym_table;
sym_table = ptr;
return ptr;
}
4ar getsym returnea+ un pointer ctre intrarea din tabela de simboluri corespun+=nd
unui identificator dat sau pointerul nul# +ero# dac nu l'a &sit%
symrec *
getsym ( char *sym_name )
{symrec *ptr;
for (ptr = sym_table ; ptr != (symrec *) 0 ; ptr = (symrec *)ptr- >next)
if (strcmp (ptr ->name,sym name) == 0)
return ptr;
return 0 ; /* sau eventual return (symrec *) 0; */
}
3n final# modulul 7)%. ar putea arta a[a/
/* ST.h the symbol table module */
/* De Dan Popa, dupa Anthony A Aaby , "Compiler Construction using Flex and Bison" */
/* Cap 4 pg 14 */
struct symrec
{
char *name; /* name of symbol - numele variabilei*/
struct symrec *next; /* link field - legatura la elementul urmator */
};
typedef struct symrec symrec;
symrec *sym_table = (symrec *)0;
symrec *putsym ();
symrec *getsym ();
/* Doua operatii: punerea unui identificator in tabela ...*/
symrec *
putsym ( char *sym_name )
{
symrec *ptr;
ptr = (symrec *) malloc (sizeof(symrec));
25
ptr->name = (char *) malloc (strlen(sym_name)+1);
strcpy(ptr->name, sym_name);
ptr->next = (struct symrec *) sym_table;
sym_table = ptr;
return ptr;
}
/* si a doua operatie: aflarea pointerul intrarii din tabel corespunzator unui identificator. */
symrec*
getsym (char *sym_name)
{
symrec *ptr;
for (ptr = sym_table; ptr != (symrec *)0; ptr = (symrec *) ptr->next)
if (strcmp (ptr->name, sym_name) == 0 )
return ptr;
return 0;
}
,bser(a]iu c func]ia caut `n lista sym#table parcur&=nd'o cu pointerul 0local2 ptr c=t
(reme mai sunt elemente `n list deci pointerul e nenul% !ac strin&ul dat sym#name
coincide cu strin&'ul din elementul de list curent# adresa acestuia este returnat% $ltfel
se returnea+ un 0 0care e practic un pointer nul2% Func]ia strcmp%& compar strin&urile
de la cele dou adrese%

*odificrile anali+orului sintactic 0parserului2
<ste necesar s modificm specifica]iile oferite Bacc'ului @ Bison'ului# astfel `nc=t s
includem tabela de simboluri [i rutinele necesare introducerii [i cutrii unui identificator
`n (ederea (erificrii folosirii sale corecte# conforme contextului% $m adu&at [i (ariabila
pentru numrarea erorilor# errors# nedeclarat `n capitolul anterior% $du&irile se fac `n
sec]iunea de specifica]ii pe care Bacc @ Bison le (a copia direct `n sursa C &enerat#
adic (or fi scrise la `nceput# `ntre %{ [i %}.
%{
#include <stdlib.h> /* nclude malloc, necesar pt. symbol table */
#include <string.h> /* nclude strcmp, necesar pt. symbol table */
#include <stdio.h> /* Functii pentru afisarea de mesaje de eroare */
#include "ST.h" /* Modulul "Symbol Table" */
#define YYDEBUG 1 /* Pentru debugging setez variabila Yacc la valoarea 1*/
int errors; /* Contor de erori */
install ( char *sym_name )
{ symrec *s;
s = getsym (sym_name);
if (s == 0)
s = putsym (sym_name);
else { errors++;
printf( "%s is already defined\n", sym_name );
2:
}
}
context check( char *sym_name )
{ if ( getsym( sym_name ) == 0 )
printf( "%s is an undeclared identifier\n", sym_name );
}
%}
Declaratii pentru Parser
%%
Gramatica: reguli plus actiuni
%%
Subrutine C
!eoarece anali+orul lexical 0scanerul &enerat de ;ex @ Flex2 (a returna doar (alorile
unor identificatori 0constante `ntre&i2 [i doar at=t# o structur de record semantic
0semantic static2 este necesar pentru a transmite denumirea fiecrui identificator de
(ariabil% $[a putem deosebi (ariabilele `nt=lnite deoarece altfel anali+orul lexical
returnea+ doar o aceea[i (aloare a constantei 4!<I)4F4<J pentru orice (ariabil%
7imple%lex (a fi modificat astfel/
Declaratii C
%union { /* RECORD SEMANTC */
char *id; /* Pentru transferul numelor identificatorilor*/
}
%start program
%token NT SKP F THEN ELSE F WHLE DO END
%token <id> DENTFER /* Simple identifier */
%left '-' '+'
%left '*' '/'
%right '^'
%%
Gramatica: reguli plus actiuni
%%
Subrutine C
3n continuare# &ramatica independent de context [i ac]iunile ei semantice sunt
modificate pentru a include apeluri la func]iile install%& [i context#ceck%& . Iota]i c
fiecare Zn este o (ariabil Bacc care face referire la al n'lea record semantic# cel
corespun+tor celui de'al n'lea element din partea dreapt a unei produc]ii 0re&uli a
&ramaticii2% $stfel (om putea prelucra# stoca# testa# denumirile di(er[ilor identificatori de
(ariabile care apar `n re&ulile &ramaticii# `n di(erse po+i]ii 0date de ordinea sintactic2%
*etoda se aplic la orice fel de element sintactic 0nu numai identificator de (ariabil2 a
crui propriet]i# atribute# urmea+ s le prelucrm% Jemarca]i c po+i]ia cu(=ntului
4!<I)4F4<J `n re&ula &ramaticii corespunde ca numr cu (ariabila Zn implicat `n ac]i'
unea semantic# 0unde n este acela[i numr P 2%
Declaratiii pt. C si parser
%%
...
28
declarations : /* empty */
| NTEGER id_seq DENTFER '.' { install( $3 ); }
;
id_seq : /* empty */
| id_seq DENTFER ',' { install( $2 ); }
;
command : SKP
| READ DENTFER { context_check( $2 ); }
| DENTFER ASSGNOP exp { context_check( $1 ); }
...
exp : NT
| DENTFER { context_check( $2 ); } ...
%%
Subrutine C
!up modificare [i sal(area fi[ierului cu numele simple.y# Bison 0pe un sistem ;inux2 (a
fi in(ocat cu una din comen+ile/
bison '(d simple.y
bison 'd simple.y
3n aceast implementare arborele sintactic este creat implicit [i adnotat implicit cu
informa]ii pri(ind situa]ia unei (ariabile/ dac ea este sau nu declarat 0deci poate sau
nu furni+a o (aloare2 `n momentul c=nd ea este referit dintr'o expresie% 4nforma]iile
care ar trebui s adnote+e arborele sintactic sunt `ns pstrate direct `n tabela de
simboluri%
Cititorii interesa]i de o implementare care crea+ efecti( un arbore sintactic adnotat pot
consulta lucrarea E$ Compact 9uide )o ;ex V BaccE de ).omas Iiemann# disponibil
&ratuit pe 4nternet# pe site'ul epapers%com% Iotm totu[i c exemplele de acolo nu pot fi
folosite pe un sistem ;inux fr unele modificri% Vom `ncerca s publicm `n anexa
acestui (olum sau `n partea a doua [i unele surse corectate pentru Flex @ Bison 0deci
destinate platformei ;inux2 pe care le'am rescris document=ndu'ne din lucrarea citat%
*odificrile 7canner'ului 0anali+orului lexical2
Oi scanerul 0anali+orul lexical2 trebuie modificat pentru a returna denumirea 0sub form
de strin& a %%%2 fiecrui identificator# ea fiind practic (aloarea semantic 0d%p%d%(% al
semanticii statice2 asociat fiecrui identificator% $ceast (aloare semantic (a fi
returnat printr'o (ariabil &lobal numit yylval. )ipul acestei (ariabile este un tip
reuniune 0union ca `n C2 creat cu directi(a 'union plasat `n fi[ierul cu descrierea
parserului% !up ca+ [i tipul (alorii semantice de comunicat de la scaner la parser#
aceasta (a fi plasat `ntr'un membru corespun+tor ca tip al reuniunii% !ac declara]ia
EunionE'ului (a fi
%union { char *id;
}
60
(aloarea semantic (a trebui copiat din (ariabila &lobal yytext 0 care con]ine
`ntotdeauna textul utimului atom lexical2 `n yylval.id % !eoarece exemplul de mai =os
folose[te func]ia strdup din biblioteca strin&%.# aceast bibliotec trebuie s fie [i ea
inclus% Fi[ierul cu descrierea scanerului# care (a fi prelucrat de ;ex @ Flex # (a con]ine/
%{
#include <string.h> /* fiind necesar strdup */
#include "simple.tab.h" /* cu definitiile atomilor si cu yylval */
%}
DGT [0-9]
D [a-z][a-z0-9]*
%%
":=" { return(ASSGNOP); }
{DGT}+ { return(NUMBER); }
do { return(DO); }
else { return(ELSE); }
end { return(END); }
fi { return(F); }
if { return(F); }
in { return(N); }
integer { return(NTEGER); }
let { return(LET); }
read { return(READ); }
skip { return(SKP); }
then { return(THEN); }
while { return(WHLE); }
write { return(WRTE); }
{D} { yylval.! # ($%ar *) s&r!'((yy&)x&)*
return(DENTFER);}
[ \t\n]+ /* eat up whitespace - pentru a consuma albitura, blancurile, tab-urile */
. { return(yytext[0]);}
%%
Jepre+entarea intermediar
*ulte compilatoare con(ertesc codul surs `ntr'o repre+entare intermediar `n cursul
acestei fa+e de traducere [i (erificare a restric]iilor contextuale% "e aceast
repre+entare intermediar operea+ &ramatica cu atribute [i optimi+atorul arborelui 0sau
al repre+entrii intermediare2% 3n exemplul nostru repre+entarea intermediar implicit
este c.iar arborele sintactic% "ractic el este construit ramur cu ramur pe sti(# pe
msura parcur&erii% !e[i deocamdat el este doar implicit# cu mici modificri de pro&ram
el poate fi construit explicit# apel=nd pentru fiecare structur sintactic func]ii care
creea+ nodul respecti( sau modific repre+entarea%
$lte solu]ii rsp=ndite pentru reali+area repre+entrii intermediare includ arborii de
sintax abstract# cod cu trei adrese# cunoscutele \uadruple [i scrierea postfix
0operatorii se scriu dup operan+i2% 7unt folosite `n di(erse etape intermediare ale
compilrii%
61
3n acest exemplu de implementare a limba=ului simple (om sri peste etapa &enerrii
repre+entrii intermediare a pro&ramului 0deci [i peste optimi+area ei2 [i (om trece
direct la &enerarea de cod% !e altfel principiile ilustrate mai departe la &enerarea de cod
se pot aplica foarte bine [i la &enerarea de repre+entri intermediare 0de exemplu la
&enerarea de \uadruple2%
3n urma modificrilor indicate `n acest capitol# fi[ierele dumnea(oastr ar putea arta a
[a/
7imple%lex
%{
#include <string.h> /* Aici este functia "strdup" */
#include "simple.tab.h" /* Definitiile atomilor si yylval */
%}
DGT [0-9]
D [a-z][a-z0-9]*
%%
":=" { return(ASSGNOP); }
{DGT}+ { return(NUMBER); }
do { return(DO); }
else { return(ELSE); }
end { return(END); }
fi { return(F); }
if { return(F); }
in { return(N); }
integer { return(NTEGER); }
let { return(LET); }
read { return(READ); }
skip { return(SKP); }
then { return(THEN); }
while { return(WHLE); }
write { return(WRTE); }
{D} { yylval.id = (char *) strdup (yytext);
return (DENTFER); }
[ \n\t]+ /* eat up whitespace - pentru a consuma albitura, blancurile, tab-urile */
. { return(yytext[0]); }
%%
7imple%-
/* Yacc/bison file for Simple */
/* Dan Popa, dupa Anthony A Aabey, Comp. Constr with Flex and Bison, cap 4 pg 14 */
/* C and parser declarations */
%{
#include <stdlib.h> /*Contine malloc folosit de tab. de simboluri ST.h*/
#include <string.h> /*Contine strcmp folosit de tab. de simboluri ST.h*/
#include <stdio.h> /* Pentru mesajele de eroare ? */
#include "ST.h" /* Modulul cu Tabela de simboluri */
#define YYDEBUG 1 /* For debugging */
62
int errors;
install (char *sym_name )
{ symrec *s;
s = getsym (sym_name);
if (s == 0)
s = putsym (sym_name);
else
{ errors++;
printf( "%s is already defined \n", sym_name );
}
}
context_check(char * sym_name )
{ if ( getsym(sym_name) == 0 )
printf ("%s is an undeclared identifier \n", sym_name);
}
/* Sectiunea continua cu: Parser declarations */
/* Deoarece scanerul generat de Lex va returna identificatori, */
/* iar noi vom utiliza o semantica statica, o inregistrare */
/* numita "semantic record" e necesara pentru a stoca valoarea */
/* iar DENT este asociat cu acest "semantic record". */
%}
%start program
%union { /* SEMANTC RECORD */
char *id; /*for returning identifiers */
}
%token LET NTEGER N
%token SKP F THEN ELSE END WHLE DO READ WRTE F
%token ASSGNOP NUMBER
%token <id> DENTFER /* Simple identifier */
%left '-' '+'
%left '*' '/'
%right '^'
%%
program : LET declarations N commands END ;
declarations : /* empty */
| NTEGER id_seq DENTFER '.' { install($3); }
;
id_seq : /* empty */
| id_seq DENTFER ',' {install($2); }
;
commands : /* empty */
| commands command ';'
;
command : SKP
| READ DENTFER { context_check ($2); }
| WRTE exp
| DENTFER ASSGNOP exp { context_check ($1); }
| F exp THEN commands ELSE commands F
| WHLE exp DO commands END
;
exp : NUMBER
| DENTFER { context_check ($1); }
| exp '<' exp
66
| exp '=' exp
| exp '>' exp
| exp '+' exp
| exp '-' exp
| exp '*' exp
| exp '/' exp
| exp '^' exp
| '(' exp ')'
;
%%
/* C subroutines */
int main (int argc, char * argv[] )
{extern FLE *yyin;
++argv; --argc;
yyin = fopen( argv[0], "r" );
yydebug = 1 ;
/* errors = 0 ; */
yyparse();
}
yyerror (char *s) /* Called by yyparse on error */
{
print("%s\n", s);
}

61
Capitolul 5
,ptimi+area
<ste teoretic posibil s transformm arborele de deri(are pentru a'i reduce dimensiunile
sau pentru a oferi &eneratorului de cod oportunitatea de a produce un cod mai eficient%
3ntruc=t compilatorul din exemplul nostru nu produce 0dec=t implicit2 arborele# nu (om
ilustra aceste transformri de arbore% 3n sc.imb (om pre+enta asemenea transformri
sub forma codului surs corespun+tor instruc]iunilor neoptimi+ate [i respecti(
optimi+ate% $ceast pre+entare i&nor deliberat faptul c unele compilatoare fac dou
feluri de optimi+ri# unele asupra arboreluli altele asupra codului &enerat% $ceste dou
feluri de optimi+ri# nu se pot substitui una pe alta%
'valuarea constantelor din timpul compilrii `[i propune s precalcule+e tot ce se
poate pe ba+a (alorilor constante cunoscute la momentul compilrii# care apar `n
expresii% 4at cum s'ar transforma ele/
j := 5 + K + 6 ; --> j := 11 + K;
m := 4 ; n := m + 3; --> m := 4; n := 7;
'liminarea calculelor repetate din bucle# scoaterea lor `nafara buclei# repre+int o
alt optimi+are% Jemarca]i parante+a din ciclu ce (a trebui e(aluat inutil [i repetat%
while ( index < maxim ) do
input sales;
value := salex * ( +ar,-'( + &ax );
output := value;
index := index + 1;
end;
(odul ar putea fi optimi)at *n felul urm\tor+
temp := ( mark_up + tax );
while ( index < maxim ) do
input sales;
value := salex * &)+(;
output := value;
index := index + 1;
end;
'liminarea variabilei contor+ Cea mai mare parte din timpul de calcul al pro&ramelor
este ocupat cu execu]ia calculelor din bucle% ,ptimi+area buclelor este deci o `mbunt'
]ire semnificati(% >+ual# (ariabila contor a buclei este folosit doar `n interiorul buclei%
3n acest ca+ este mai bine ca ea s poat fi stocat `ntr'un re&istru `n loc s fie stocat
`n memorie% 3n plus# dac ea este folosit doar ca indice pentru un (ector 0ceea ce
implic o `nmul]ire [i o adunare la fiecare rotire a buclei2 optimi+area const `n a ini]ia'
li+a (ariabila cu adresa de `nceput a (ectorului [i a o EincrementaE cu lun&imea unui
element de (ector% , bucl/
65
For := 1 to 10 do
A[] := A[] + E
,evine +
For := adresa primului element din A
&o adresa ultimului element din A
by dimensiunea unui element din A !o
A[] := A[] + E
'liminarea subexpresiilor comune dintr'un [ir de expresii prin calcularea (alorii lor
doar o sin&ur dat/
A := 6 * (B+C);
D := 3 + 7 * (B+C);
E := A * (B+C);
,evine+
TEMP := B + C;
A := 6 * TEMP;
D := 3 * 7 * TEMP;
E := A * TEMP;
-nlocuirea unor *nmul]iri cu opera]ii mia rapide+
2*x --> x + x
2*x --> shift left x
.tili)area identit\]ilor matematice+
a*b + a*c --> a*(b+c)
a - b --> a + ( - b )
Iu (om `n+estra implementarea noastr de 7imple cu un optimi+ator de cod%
66
Capitolul 6
*a[ini Virtuale
>n calculator construit efecti( din componente electronice este considerat o ma[in de
calcul real% <l exist fi+ic% !in punct de (edere al pro&ramatorul# setul de instruc]iuni
ale acelui .ardAare define[te clar ma[ina de calcul% >n sistem de operare este un
pro&ram construit peste resursele oferite de ma[ina real# pentru a fi &estionarul
acestora [i pentru a oferi o serie de alte ser(icii# de exemplu apelurile de sistem%
7er(iciile oferite de sistemul de operare# practic instruc]iuni aparte ce pot fi&ura `ntr'un
pro&ram sau altul# definesc de data aceasta o ma[in (irtual% <a nu exist fi+ic% Iu
exist circuite electronice speciali+ate care s ofere acele ser(icii%
>n limba= de pro&ramare pune la dispo+i]ie un set de date [i un set de instruc]iuni
exprimabile printr'o anume sintax% >n .ardAare capabil s execute direct acele
instruc]iuni asupra datelor ar fi un computer real% 3n teorie este posibil s (orbim de o
ma[n "ascal# o ma[in 7c.eme sau una Fort.% Cea din urm e c.iar implementat
`ntr'un cip speciali+at% "ractic# pentru pro&armator nu contea+ dac ma[ina este real
sau (irtual% Cei care au trecut de la C la Ua(a au constatat c trecerea de la
pro&ramarea unei ma[ini reale la pro&ramarea uneia (irtuale nu'i deran=a cu nimic% 4ar
pentru pro&ramator ma[ina e sinonim cu limba=ul computerului% ;imba=ul de
pro&ramare define[te practic un computer ima&inar# (irtual sau araeori real# cu care
interac]ione+i pro&ram=ndu'l% ,rice ma[in (irtual# pro&ramabil# capabil s
manipule+e date# trebuie s aib o modalitate de a stoca at=t datele c=t [i pro&ramul%
!ac o implemente+i `n alt limba= trebuie s specifici `n acest alt limba= cum se execut
instruc]iunile ma[ini (irtuale asupra datelor ei%
!e obicei 0obicei care a fost preluat de limba=e interpretate ca Basic# Ua(a2 `ntre
pro&ramator# care dialo&.ea+ cu o ma[in (irtual ba+at pe un limba= de ni(el `nalt [i
ma[ina (irtual care e sistemul de operare se interpune o alt ma[in (irtual%
Compilatorul limba=ului poate &enera altfel de cod 0b-tecode2 [i pe acesta trebuie s'l
rule+e cine(a% $ceast ma[in (irtual este a[a'+isul Erun'time en&ineE al limba=ului%
Complexitatea acesteia poate (aria de la nimic 0ca+ul Fortranului [i al acelor
compilatoare care &enerea+ cod direct pentru procesor sau pentru ma[ina (irtual
care este sistemul de operare2 la acele sisteme extrem de sofisticate# a(=nd mana&er
de memorie [i mecanisme de intercomunicare `ntre procese cum e ca+ul unor limba=e
de pro&ramare concurente# de exemplu 7J%
Jun'time s-stem'ul pentru limba=ul 7imple (a include o component de procesare
capabil s execute cod# implementat ca un mic interpretor interior [i o +on de date `n
care (alorile atribuite (ariabilelor sunt accesate printr'un deplasament raportat la
`nceputul +onei% < practic un (ector%
Iot/ unele pro&rame utili+ator pot fi considerate de asemenea ca o clas aparte de
ma[ini (irtuale%
65
).e 70tacD2 *ac.ine ' , ma[in (irtual cu sti(
0adaptare dup IiDlaus Rirt.# Algorithms + Data Structure = Programs
"rentice'Kall# <n&leAood Clifs# I%U%# 1856%2
7'ma[ina este o ma[in cu sti( proiectat pentru a simplifica implementarea limba=elor
cu structur de bloc% <a ofer o alcare dinamic sub forma unei sti(e de `nre&istrri de
acti(are% 0Care corespund# nota bene# blocurilor%2 $ceste `nre&istrri de acti(are sunt
le&ate `ntre ele pentru a permite tipi+area static [i con]in [i informa]iile de context
necesare procedurilor%
/rgani)area ma[inii+ 7'ma[ina const `n dou +one de stocare# una dedicat
pro&ramului [i numit ( 0or&ani+at ca un (ector read'onl-2 [i o +on de date S
0or&ani+at ca o sti(2% <xist patru re&i[triW un re&istru de instruc]iuni 01 care con]ine
instruc]iunea ce trebuie interpretat# un re&istru EstacD'pointerE " care con]ine adresa
ultimului element al sti(ei# 2(, acel Epro&ram'counterE care con]ine adresa urmtoarei
instruc]iuni de adus `n (ederea interpretrii [i re&istrul `nre&istrrii de acti(are curente#
%1, cel care con]ine adresa ba+ei `nre&istrrii de acti(are aferente procedurii care e `n
curs de interpretare% Fiecare loca]ie din ( este capabil s stoc.e+e o instruc]iune%
Fiecare loca]ie din S este capabil s stoc.e+e o adres sau un `ntre&% Fiecare instruc'
]iune const `n trei informa]ii# trei c=mpuri/ un cod al opera]iei [i doi parametri%
Setul de instruc]iuni+ (-codurile formea+ limba=ul ma[in al 7'ma[inii% 7'codurile
ocup fiecare c=te patru b-tes% "rimul b-te este codul opera]iei 0op'code2% <xist nou
astfel de instruc]iuni 07'coduri2 de ba+# fiecare cu un cod de opera]ie diferit% $l doilea
b-te al 7'codului con]ine ori un +ero# ori un fel de offset lexical# ori un cod de condi]ie
pentru instruc]iunile de salt condi]ionat% >ltimii doi b-tes lua]i `mpreun formea+ un
`ntre& pe 16 bi]i cu rolul de operand% <l poate fi o constant 0Eliteral (alueE2# un offset al
po+i]iei unei (ariabile pe sti( pornind de la ba+a# adresa loca]iei altui 7'cod# un numr
de opera]ie 0PCP2# ori un alt numr special al crui sens e (alabil doar pentru un 7'cod cu
anumit cod de opera]ie%
(omentarii+ < normal ca di(ersele feluri de instruc]iuni 07'coduri2 s se distin& prin
codul opera]iei% , adunare e ce(a diferit de un salt# de exemplu% ;a r=ndul lor salturile
condi]ionate pot fi condi]ionate de faptul c o (aloare este +ero# sau nu este +ero deci
oricum a(em mai multe cate&orii de instruc]iuni de salt% $l doilea octet diferen]ia+
tocmai instruc]iunile din aceea[i familie# cu acela[i cod de opera]ie% 4nstruc]iunile pot s
manipule+e [i adrese sau numere de 16 bi]i ori de 2 b-tes deci mai poate fi ne(oie de
`nc doi b-tes suplimentari pentru corpul instruc]iunii% "ractica arat c la un asemenea
limba= simplu nu e ne(oie de mai mul]i b-tes pentru un 7'code% )oate instruc]iunile#
indiferent de codul de opera]ie din primul octet n'au ne(oie de mai mult de 6 octe]i
pentru a a(ea `n continuarea op'code'ului informa]iile necesare%
7emantica# ac]iunea fiecreia dintre instruc]iuni este descris mai =os# folosind un
6:
amestec de limba= natural [i nota]ie formal% $ceast nota]ie inspirat din limba=ele de
pro&ramare de ni(el `nalt este folosit pentru a preci+a sc.imbrile care au loc `n
memoria de date [i `n re&istrele ma[inii cu sti(% ,bser(a]i c instruc]iunile de acces la
date 0practic la (ariabilele locale ale procedurilor2 au ne(oie de un deplasament
raportat la `nre&istrarea de acti(are curent 0arat a c=ta (ariabil local= e implicat2 [i
de diferen]a de ni(el dintre ni(elul referin]ei [i ni(elul declara]iei 0era posibil de exemplu
ca (ariabila s fi fost declarat `ntr'o procedur exterioar# dar contea+ exact `n a c=ta
deoarece aceasta determin po+i]ia ei pe sti( `n `nre&istrarea de acti(are
corespun+toare2% $pelurile de procedur au ne(oie de adresa codului apelat [i de
asemenea de diferen]a dintre ni(elul referin]ei [i cel al declara]iei%
./s&r'$&o/ 0()ra/!s 1o++)/&s
/O operations
READ 0,N nput integer in to location N: S(N) := nput
WRTE Output top of stack: Output := S(T); T:= T-1
OPR Arithmetic and logical operations
0,0 process and function, return operation
T:= AR-1; AR:= S(T+2); P:= S(T+3)
ADD ADD: S(T-1) := S(T-1) + S(T); T := T-1
SUB SUBTRACT: S(T-1) := S(T-1) - S(T); T := T-1
MULT MULTPLY: S(T-1) := S(T-1) * S(T); T := T-1
DV DVDE: S(T-1) := S(T-1) / S(T); T := T-1
MOD MOD: S(T-1) := S(T-1) mod S(T); T := T-1
EQ TEST EQUAL:
S(T-1) := if S(T-1) = S(T) then 1 else 0; T:= T-1
LT TEST LESS THAN:
S(T-1) := if S(T-1) < S(T) then 1 else 0; T:= T-1
GT TEST GREATER THAN:
S(T-1) := if S(T-1) > S(T) then 1 else 0; T:= T-1
LD_NT 0,N LOAD literal value onto stack: T:= T+1; S(T):= N
LD_VAR L,N LOAD value of variable at level offset L, base
offset N in stack onto top of stack
T:= T + 1; S(T):= S(f(L,AR)+N)+3
STORE L,N store value on top of stack into variable location
at level offset L, base offset N in stack
S(f(ld,AR)+os+3):= S(T); T:= T - 1
CAL L,N call PROC or FUNC at S-code location N declared
at level offset L
S(T+1):= f(ld,AR); { Static Link }
S(T+2):= AR; { Dynamic Link }
S(T+3):= P; { Return Address }
AR:= T+1; { Activation Record }
P:= cos; { Program Counter }
T:= T+3 { Stack Top }
CAL 255,0 call procedure address in memory: POP address, PUSH return
address, JUMP to address
DATA 0,NN ADD NN to stack pointer T := T+NN
GOTO 0,N JUMP: P := N
JMP_FALSE C,N JUMP: if S(T) = C then P:= N; T:= T-1
$ici diferen]a de ni(el static `ntre procedura curent [i cea apelat este notat cu ld%
68
Cu os este notat offsetul 0deplasamentu2 `n cadrul `nre&istrrii de acti(are curente [i tot ld este diferen]a
de ni(el static `ntre `nre&istrarea de acti(are curent [i `nre&istrarea de acti(are `n care (a fi stocat
(aloarea% Func]ia f0ld#a2 este implementarea urmtoarei expresii condi]ionale% , pute]i scrie ca o func]ie cu
acolad daca dori]i%
f(i,a) = if i=0 then a else f(i-1,S(a))
4ma&ina]i'( c fiecare `nre&istrare de acti(are are la `nceputul ei# la adresa a# un
pointer ctre precedenta `nre&istrare de acti(are% "ractic 70a2 (a fi adresa `nre&istrrii
de acti(are precedente%
7e mer&e pe acest [ir de `nre&istrri de acti(are `napoi# pas cu pas# p`n a=un&em la
prima% $dresa ei este la ba+a sti(ei%
3unc]ionarea+ Je&istrii ma[inii cu sti( sunt `ni]iali+a]i dup cum urmea+/
P = 0. { Program Counter - ndica instructiunea curenta}
AR = 0; { Activation Record ndica inregistrarea de activare curenta}
T = 2; { Stack Top Virful stivei}
S[0] := 0; { Static Link Legatura statica}
S[1] := 0; { Static Dynamic Link Legatura dinamica}
S[2] := 0; { Return Address Adresa de reintoarcere }
*a[ina aduce periodic `n re&istrul 4J instruc]iunea indicat de re&istrul "C#
incrementea+ re&istrul "C [i execut instruc]iunea% )otul se repet p`n c=nd "C'ul
a=un&e s con]in +ero sau este `nt=lnit [i executat o instruc]iune K$;)% 3ntr'un
pseudocod inspirat de "ascal#0parte a unei masini (irtuale2 ciclul s'ar scrie/
REPEAT
R:= C(P); (* Fetch *)
PC:= PC+1;
interpret(R); (* Execute*)
UNTL R = "Halt" or PC = 0
$ceast bucl numit [i Efetc.'execute loopE are de fcut deci dou lucruri `nainte de a
executa 0interpreta2 o instruc]iune/ s aduc op'codul ei `n re&istrul de instruc]iuni [i s
po+i]ione+e contorul de pro&ram "C astfel ca el s indice octetul urmtor% $ici (a &si
subrutina EinterpretE b-te'ul al doilea% Jecuperarea acestor al doilea [i la ne(oie# al
treilea [i al patrulea b-te din 7'codul instruc]iunii curente rm=n `n sarcina subrutinei
EinterpretE% <a poate dup ca+ s aduc spre utili+are unu# doi sau trei dintre ace[ti
b-tes sau c.iar pe niciunul# dar oricum (a face (a trebui s incremente+e re&istrul "C
astfel `nc=t el s indice op'cod'ul urmtor% "ractic dup terminarea subrutinei EinterpretE
"C'ul (a arta o adres cu 6 b-tes mai departe# ea fiind adresa urmtoarei instruc]iuni%
,p'codul de aici (a fi `ncrcat `n 4J la urmtorul Efetc.E atunci c=nd se reia bucla% Oi tot
a[a mai departe%
*odulul E*a[ina Virtual cu 7ti(E# 7*%.
4mplementarea ma[inii cu sti( de care a(em ne(oie e dat `n continuare% 7etul de
instruc]iuni implementate [i structura unei instruc]iuni sunt definite dup cum urmea+/
10
/* OPERATONS: nternal Representation */
enum code_ops { HALT, STORE, JMP_FALSE, GOTO,
DATA, LD_NT, LD_VAR,
READ_NT, WRTE_NT,
LT, EQ, GT, ADD, SUB, MULT, DV, PWR };
/* OPERATONS: External Representation */
char *op_name[] = {"halt", "store", "jmp_false", "goto",
"data", "ld_int", "ld_var",
"in_int", "out_int",
"lt", "eq", "gt", "add", "sub", "mult", "div", "pwr" };
struct instruction
{
enum code_ops op;
int arg;
};
*emoria este separat `n dou se&mente# un se&ment destinat codului [i altul destinat
deopotri( sti(ei [i (ariabilelor locale create dinamic `n cursul execu]iei%
struct instruction code[999];
int stack[999];
>rmea+ defini]iile re&i[trilorW contorul de instruc]iuni 0en&% Epro&ram counterE2 pc#
re&istrul de instruc]iuni ir, re&istrul indicator al `nre&istrrii de acti(are 0 en&% Eacti(ation
recordE2 curente numit ar [i re&istrul care arat spre (=rful sti(ei# numit top% 3n pa&inile
anterioare fusese numit ) dar este (orba de acela[i re&istru% <ste uneori numit [i stacD
pointer ' indicator de sti(# din aceast cau+ fiind notat 7" la unele procesoare%
Je&istrul ar indic `nceputul por]iunii din sti( care (a corespunde ultimei proceduri
acti(e% !e (ariabila c. (om a(ea ne(oie mai t=r+iu dar o declarm de=a aici%
int pc = 0 ;
struct instruction ir ;
int ar = 0 ;
int top = 0 ;
char ch ;
Ciclul Efetc.'executeE se repet p=n la `nt=lnirea unei instruc]iuni speciale# numit
K$;)# instruc]iune care exist [i la procesoarele reale%
void fetch_execute_cycle()
{
do { /* Fetch */
ir = code[pc++];
/* Execute */
switch (ir.op) {
11
case HALT : printf( "halt\n" ); break;
case READ_NT : printf( "nput: " );
scanf( "%ld", &stack[ar+ir.arg] ); break;
case WRTE_NT : printf( "Output: %d\n", stack[top--] ); break;
case STORE : stack[ir.arg] = stack[top--]; break;
case JMP_FALSE : if ( stack[top--] == 0 )
pc = ir.arg; break;
case GOTO : pc = ir.arg; break;
case DATA : top = top + ir.arg; break;
case LD_NT : stack[++top] = ir.arg; break;
case LD_VAR : stack[++top] = stack[ar+ir.arg]; break;
case LT : if ( stack[top-1] < stack[top] )
stack[--top] = 1;
else stack[--top] = 0; break;
case EQ : if ( stack[top-1] == stack[top] )
stack[--top] = 1;
else stack[--top] = 0; break;
case GT : if ( stack[top-1] > stack[top] )
stack[--top] = 1;
else stack[--top] = 0;
top--; break;
case ADD : stack[top-1] = stack[top-1] + stack[top];
top--;
break;
case SUB : stack[top-1] = stack[top-1] - stack[top];
top--;
break;
case MULT : stack[top-1] = stack[top-1] * stack[top];
top--;
break;
case DV : stack[top-1] = stack[top-1] / stack[top];
top--;
break;
case PWR : s&a$,[&o(-2] # s&a$,[&o(-2] * s&a$,[&o(]* 3* 4)& $or)$&a a$5 *3
top--;
break;
default : printf( "%snternal Error: Memory Dump\n" );
break;
}
}
while (ir.op != HALT);
}
*a[ina (irtual de mai sus are ne(oie de o corectur deoarece tentati(a ei de a
executa instruc]iunea "RJ duce la calculul unui produs nu la cel al unei ridicri la
putere% Jeali+area acestei corecturi este lsat pe seama cititorului# ca exerci]iu%
"entru depanarea buclei Efetc.'executeE pute]i scrie [i urmtoarele linii de pro&ram `n
locul comentariului @[ Fetc. [@ sau imediat dup acesta%
printf ( "PC = %23d R.arg =%8d AR = %23d Top = %3d , %8d \n",
pc, ir.arg, ar, top , stack[top] );
12
*odificri ale parserului
7unt necesare modificri `n fi[ierul anterior cu specifica]ii Bacc@Bison astfel ca
pro&ramul principal s apele+e ma[ina (irtual pentru a rula pro&ramul care a fost
anali+at 0EparsatE2 cu succes% $du&a]i `n sec]iunea *$4I a parserului 7imple%- linile/
printf ( "Parse Completed\n" );
if ( errors == 0 )
{ print_code ();
fetch_execute_cycle();
}
3ntrea&a func]ie main din fi[ierul 7imple%- (a arta a[a/
/*=========================================================================
MAN
=========================================================================*/
main( int argc, char *argv[] )
{ extern FLE *yyin;
++argv; --argc;
yyin = fopen( argv[0], "r" );
/*yydebug = 1;*/
errors = 0;
yyparse ();
printf ( "Parse Completed\n" );
if ( errors == 0 )
{ print_code ();
fetch_execute_cycle();
}
}
$ceste modificri (or permite s fie executat pe ma[ina (irtual codul &enerat% !e
&enerarea codului se ocup capitolul urmtor%
16
>n exemplu de cod produs `n urma compilrii/
0: data 1
1: in_int 0
2: ld_var 0
3: ld_int 10
4: lt 0
5: jmp_false 9
6: ld_int 1
7: store 1
8: goto 9
9: ld_var 0
10: ld_int 10
11: lt 0
12: jmp_false 22
13: ld_int 5
14: ld_var 1
15: mult 0
16: store 1
17: ld_var 0
18: ld_int 1
19: add 0
20: store 0
21: goto 9
22: ld_var 0
23: out_int 0
24: ld_var 1
25: out_int 0
26: halt 0
Figura 7.2: Cod generat
11
Capitolul 5
9enerarea codului
"e msur ce pro&ramul surs este parcurs 0de ctre parser2 el este tradus `ntr'o form
intern% Frec(ent folosit este forma de arbore% $cesta poate fi creat explicit sau
parcurs implict# ca o sec(en] de apeluri de subpro&rame% 3n exemplul nostru arborele
(a fi implicit% "ot exista [i alte forme interne% ;a unele compilatoare# `nainte de codul
obiect &enerat# exist o (ariant a lui `ntr'un limba= care seamn cu limba=ul de
asamblare% Codul `n form intern este `n final transformat `n cod obiect de ctre
&eneratorul de cod% )ipic# codul obiect este un pro&ram pentru o minuscul ma[in
(irtual% $lteori el este c.iar cod pentru procesorul .ardAare al sistemului% "entru
execu]ia pro&ramelor scrise `n 7imple (om folosi ma[ina (irtual descris anterior#
format din trei se&mente 0de memorie2W un segment de date# un segment de cod [i o
stiv\# aceasta fiindu'ne util pentru e(aluarea expresiilor% ;a implementri de limba=e
care folosesc subpro&rame sti(a ser(e[te [i pentru controlul execu]iei acestora [i
stocarea (alorilor locale%
7e&mentul de date este cel care stoc.ea+ (alorile (ariabilelor%Fiecare (ariabil are
asociat o loca]ie `n care se (a stoca (aloarea ei% !eci o parte din acti(itatea
&eneratorului de cod (a consta `n atribuirea de adrese pentru fiecare (ariabil%
7e&mentul de cod con]ine sec(en]a tuturor instruc]iunilor pro&ramului% Constantele din
pro&ram sunt stocate tot `n se&mentul de cod# lucru posibil deoarece (alorile lor nu se
sc.imb iar se&mentul de cod este din punct de (edere al ma[inii (irtuale Eread'onl-E%
7ti(a expresiilor este o sti( folosit `n special pentru a pstra (alorile intermediare care
apar `n timpul e(alurii expresiilor% !atorit pre+en]ei ei# ma[ina (irtual a limba=ului
7imple este numit o ma[in cu sti( sau 7'ma[in 0en&% 7tacD'mac.ine2%
)raducerea declara]iilor
!eclara]iile definesc contextul e(alurii expresiilor% "entru a re+er(a spa]iul pe sti(
necesar (ariabilelor (om folosi instruc]iunea !$)$ a ma[inii (irtuale# creat c.iar `n
acest scop% Jolul ei este s E`mpin&E capul sti(ei mai departe ls=nd loc pe sti(
pentru numrul de (ariabile cerut% 3n 7imple toate (ariabilele fiind de acela[i tip# spa]iul
ocupat pe sti( este propor]ional cu numrul lor [i e suficient s dm acest numr ca
parametru al instruc]iunii !$)$% <l (a fi pstrat `n se&mentul de cod ca ar&ument al
instruc]iunii !$)$%
!ar (ariabilele (or fi stocate `n se&mentul de date% $cesta fiind practic un (ector
declarat `n C# numrtoarea (ariabilelor (a `ncepe cu 0# prima (ariabil ocup=nd po+i]ia
0# a doua po+i]ia 1# a treia po+i]ia 2 [%a%m%d% !eci se (a compila/
integer x,y,z. ---> DATA 2 iar integer n,x. ---> DATA 1
15
)raducerea instruc]iunilor
4nstruc]iunile de atribuire# if# A.ile# read [i Arite sunt traduse dup re&ulile de mai =os/
x := expr cod pentru expr
STORE X
if cond then cod pentru cond
S1 JMP_FALSE L1
else cod pentru S1
S2 BR L2
end L1: cod pentru S2
L2:
while cond do L1: cod pentru cond
S JMP_FALSE L2
end cod pentru S
GOTO L1
L2:
read X N_NT X
write expr cod pentru expr
OUT_NT
,bser(a]i c anumite adrese cum sunt ;1 [i ;2 pentru if sau ;2 pentru A.ile nu sunt
imediat disponibile# (aloarea lor fiind determinat de lun&imea unor se&(en]e de cod
care n'au fost `nc &enerate% <le (or fi completate atunci c=nd (aloarea lor exact
de(ine cunoscut% ,pera]ia se nume[te EbacD'patc.in&E [i (a fi executat de o
subrutin care se apelea+ `n finalul compilrii structurii respecti(e% 3n exemplul nostru
aceast subrutin se (a numi c.iar back#patc%
)raducerea expresiilor
<xpresiile (or fi e(aluate folosind sti(a% ;a traducerea lor se (or &enera instruc]iuni ale
ma[inii (irtuale cum sunt ;! [i ;!?4I)% Codul pentru un operator (a fi &enerat dup
codurile pentru operan+i% "ractic traducerea transform expresia obi[nuit `n forma ei
polone+ postfixat 0cu operatorul dup operan+i2 iar e(aluarea se (a face de ctre ma'
[ina (irtual care implementea+ re&ulile/ 12 constanta sau (ariabila se pune pe sti( [i
22 operatorul scoate din sti( c=]i operan+i are ne(oie# face calculul [i pune re+ultatul
tot `n sti(% Cu aceste re&uli simpla parcur&ere a unei expresii duce la plasarea (alorii ei
pe sti(% Ca o consecin]# pentru ma[ina (irtual# simpla execu]ie a codului asociat
expresiei (a duce la punerea re+ultatului `n sti(% )raducerea se fece dup re&ulile/
constanta LD_NT constanta
variabila LD_VAR variabila
e1 op e2 cod pentru e1
cod pentru e2
cod pentru op
16
*odulul &enerator de cod / C9%.
7e&mentul de date `ncepe cu loca]ia 0 % Je+er(area spa]iului `n se&mentul de date se
(a face apel=nd func]ia data#location care (a returna adresa loca]iei nou re+er(ate%
Variabila data#o!!set arat totdeauna urmtoarea loca]ie liber `n se&mentul de date%
3ntruc=t datele ocup exact o loca]ie `n se&ment# tot ce are de fcut data#location este
s returne+e adresa loca]iei curente libere [i apoi s incremente+e (ariabila data#o!!set.
int data_offset = 0;
int data_location() { return data_offset++; }
7e&emntul de cod are [i el loca]iile numerotate `ncep=nd cu +ero% $ici `ns alocarea de
spa]iu se (a face apel=nd subrutina reserve#loc care (a returna adresa loca]iei &site%
0"rima loca]ie liber%2 !ac nu mai (rem s alocm dar ne interesea+ la ce adres (a
`ncepe sec(en]a de cod urmtoare 0ca `n ca+ul `n care acolo ar fi o etic.et ;22 (om
apela func]ia gen#label care nu face dect s returne+e (aloarea adresei urmtoarei
loca]ii libere#dar fr s aloce spa]iul%
int code_offset = 0;
int reserve_loc()
{
return code_offset++;
}
int gen_label()
{
return code_offset;
}
Func]iile reserve#loc [i gen#label ne (or ser(i la bacD'patc.in&'ul codului%
Func]iile gen#code [i back#patc sunt folosite `n procesul &enerrii codului% gen#code
&enerea+ codul unei instruc]iuni `n po+i]ia curent 0code?offset2 `n se&mentul de cod%
3n sc.imb back#patc este folosit la a &enera completri ale codului la c=te'o adres
re+er(at dinainte# adresa fiindu'i dat ca prim parametru%
void gen_code( enum code_ops operation, int arg )
{ code[code_offset].op = operation;
code[code_offset++].arg = arg;
}
void back_patch( int addr, enum code_ops operation, int arg )
{
code[addr].op = operation;
code[addr].arg = arg;
}
15
*odificri ale modulului )abela de 7imboluri/ 7)%.
Formatul articolelor din tabela de simboluri trebuie extins% <l (a con]ine pentru fiecare
(ariabil din tabel [i offset'ul 0po+i]ia2 acesteia `n se&mentul de date% $ceasta e adresa
+onei `n care (ariabila `[i pstrea+ (aloarea% 4ar func]ia putsym de adu&are a
simbolului `n tabel (a fi [i ea extins pentru a `ndeplini sarcina de plasare a offset'ului
`n articolul din tabel corespun+tor (ariabilei%
struct symrec
{
char *name; /* numele simbolului - identificatorul variabilei */
int offset; /* offset in segmentul de date */
struct symrec *next; /* legatura cu urmatorul din lista */
};
...
symrec * putsym (char *sym_name)
{
symrec *ptr;
ptr = (symrec *) malloc (sizeof(symrec));
ptr->name = (char *) malloc (strlen(sym_name)+1);
strcpy (ptr->name,sym_name);
ptr->offset = data_location();
ptr->next = (struct symrec *)sym_table;
sym_table = ptr;
return ptr;
}
...
*odificrile parserului 0anali+orului sintactic2/ 7imple%-
Completm exemplul nostru anterior cu &enerarea de cod% Vom extinde defini]iile din fi'
[ierele ;ex [i Bacc ale limba=ului 7imple astfel ca s &enerm cod pentru 7'ma[in%
"entru `nceput (om modifica fi]ierele Bacc [i ;ex astfel ca (alorile constantelor s fie
transmise de la scanner 0anali+orul lexical2 la parser 0anali+orul sintactic2% <l e acel
care# prin re&uli semantice ata[ate re&ulilor sintactice# &enerea+ cod%
Vom modifica defini]ia acelui Esemantic'recordE din fi[ierul Bacc astfel ca (aloarea
constantelor s fie returnat ca parte a acestui Esemantic'recordE% Corespun+toare
celor dou etic.ete care apar `n codurile instruc]iunilor if [i A.ile (a exista o structur cu
dou c=mpuri%
7e (a defini [i un tip special de atomi 0EtoDenE2 numit SlblsT corespun+tor lui 4F [i
RK4;<% <l ofer [i spa]iu de stocare pentru adresele etic.etelor ce's adu&ate `n
procesul de bacDpatc.in&% ne)lblrec e func]ia care aloc spa]iul necesar pentru a
stoca (alorile etic.etelor necesare la bacDpatc.in&%
Func]ia context#ceck (a prelua &enerarea de cod aferent opera]iei efectuate asupra
unei (ariabile 0dar (a a(ea ne(oie [i de codul opera]iei de implementat P2% Codul e
&enerat doar dac identificatorul exist `n tabel%
1:
%{#include <stdio.h> /* Pentru /O */
#include <stdlib.h> /* Pentru malloc folosit aici si in ST.h */
#include <string.h> /* Pentru strcmp folosuit in tabela de simboluri St.h */
#include "ST.h" /* Tabela de Simboluri */
#include "SM.h" /* S-Masina */
#include "CG.h" /* Generator de cod */
#define YYDEBUG 1 /* Pentru depanare */
int errors; /* Contor de erori incrementat de CG.h */
struct lbs /* Pentru etichetele de la if si while */
{
int for_goto;
int for_jmp_false;
};
struct lbs * newlblrec() /* Alloca spatiu pentru etichete */
{
return (struct lbs *) malloc(sizeof(struct lbs));
}
install ( char *sym_name )
{
symrec *s;
s = getsym (sym_name);
if (s == 0)
s = putsym (sym_name);
else { errors++;
printf( "%s is already defined\n", sym_name );
}
}
context_check( enum code_ops operation, char *sym_name )
{ symrec *identifier;
identifier = getsym( sym_name );
if ( identifier == 0 )
{ errors++;
printf( "%s", sym_name );
printf( "%s\n", " is an undeclared identifier" );
}
else gen_code( operation, identifier->offset );
}
%}
%union semrec /* Record-ul semantic */
{
int intval; /* Valoarea cinstantei intregi */
char *id; /* dentificatorul */
struct lbs *lbls /* Adrese etichetate pentru backpatching*/
}
%start program /* Neterminalul de la care incepe analiza e "program" */
%token <intval> NUMBER /* Constante intregi */
%token <id> DENTFER /* dentificatori */
%token <lbls> F WHLE /* Etichete pentru backpatching */
%token SKP THEN ELSE F DO END
%token NTEGER READ WRTE LET N
%token ASSGNOP
%left '-' '+' /* Operatorii asociaza la stinga si au prioritate minima */
%left '*' '/' /* Operatorii asociaza la stinga */
%right '^' /* Operatorii asociaza la dreapta si au prioritatea maxima*/
18
%%
/* Regulile gramaticii si Actiunile semantice */
%%
/* Subrutine scrise in C*/
$nali+orul sintactic# parserul# este acum extins cu re&uli de &enerare [i `mbinare a por]
iunilor de cod% 3n final# codul &enerat pentru instruc]iunile if [i A.ile trebuie s con]in
adresele corecte pentru salturi% $cetsea sunt marcate cu etic.ete# `n re&ulile de
traducere% !eoarece destina]iile exacte ale salturilor nu sunt cunoscute dec=t dup
&enerarea codului `ntre&ii structuri# e ne(oie de aceast adu&are a lor# numit back-
patcing 0ceea ce s'ar putea traduce prin Epeticire `napoiE2% Valoarea exact a adresei
destina]ie pentru salturi (a fi adu&at 0ca un petec2 `n cod# dup ce# prin compilarea
`ntre&ii instruc]iuni structurate se (a [ti precis ce adres e `n punctul (i+at#
corespun+tor etic.etei 0fie ea ;1 sau ;22%
Bacc permite pentru fiecare re&ul sintactic s adu&m ac]iuni semantice care (or
&enera cod% *ai mult dect at=t# pentru fiecare element 0terminal sau neterminal din
re&ul2 Bacc asocia+ o (ariabil special al crui nume `ncepe cu Z [i continu cu
numrul elementului din re&ul% Capul re&ulii beneficia+ [i el de o asemenea (ariabil#
ZZ# fr numr% Consulta]i documenta]ia Bacc@Bison de pe sistemul dumnea(oastr#
pentru a afla amnunte% "ute]i folosi aceste (ariabile locale procedurilor de anali+
sintactic pentru a stoca informa]ii semantice 0atribute2 despre elementul sintactic
respecti(% !ac a(e]i de stocat mai multe informa]ii pute]i s folosi]i (ariabila ca pe
adresa unei structuri de date ce (a con]ine informa]iile necesare% 7tructura de date o
(e]i creea `ns dumnea(oastr prin alocare dinamic%
C.iar [i declara]iile de (ariabile 0statice2 (or &enera cod/ codul &enerat de o declara]ie
nu face dec=t s re+er(e loc `n se&mentul de date pentru (ariabila respecti(%
/* Declaratiile pentru C si Parser */
%%
program : LET
declarations
N { gen_code( DATA, data_location()-1 ); }
commands
END { gen_code( HALT, 0 ); YYACCEPT; }
;
declarations : /* empty */
| NTEGER id_seq DENTFER '.' { install( $3 ); }
;
id_seq : /* empty */
| id_seq DENTFER ',' { install( $2 ); }
;
4nstruc]iunile 4F [i RK4;< (or recur&e la bacDpatc.in&%
commands : /* empty */
| commands command ';'
;
command : SKP
| READ DENTFER { context_check( READ_NT, $2 ); }
| WRTE exp { gen_code( WRTE_NT, 0 ); }
50
| DENTFER ASSGNOP exp { context_check( STORE, $1 ); }
| F exp { $1 = (struct lbs *) newlblrec();
$1->for_jmp_false = reserve_loc(); }
THEN commands { $1->for_goto = reserve_loc(); }
ELSE { back_patch( $1->for_jmp_false,
JMP_FALSE,
gen_label() ); }
commands
F { back_patch( $1->for_goto, GOTO, gen_label() ); }
| WHLE { $1 = (struct lbs *) newlblrec();
$1->for_goto = gen_label(); }
exp { $1->for_jmp_false = reserve_loc(); }
DO
commands
END { gen_code( GOTO, $1->for_goto );
back_patch( $1->for_jmp_false,
JMP_FALSE,
gen_label() ); }
;
Codul corespun+tor expresiilor e &enerat de re&ulile de mai =os/
exp : NUMBER { gen_code( LD_NT, $1 ); }
| DENTFER { context_check( LD_VAR, $1 ); }
| exp '<' exp { gen_code( LT, 0 ); }
| exp '=' exp { gen_code( EQ, 0 ); }
| exp '>' exp { gen_code( GT, 0 ); }
| exp '+' exp { gen_code( ADD, 0 ); }
| exp '-' exp { gen_code( SUB, 0 ); }
| exp '*' exp { gen_code( MULT, 0 ); }
| exp '/' exp { gen_code( DV, 0 ); }
| exp '^' exp { gen_code( PWR, 0 ); }
| '(' exp ')'
;
%%
/* Subprograme C */
*odificrile $nali+orului ;exical# 07canerului2
, `ntrebare pe care ('o pune]i citind re&ulile de compilare a expresiilor [i semnturile
func]iilor implicate este de ce pentru I>*B<J (aloarea (ariabilei Bacc Z1 este c.iar
(aloarea numeric a constantei iar `n ca+ul unui identificator 04!<I)4F4<J2 este c.iar
strin&ul format de literele identificatorului% ;a urma urmei de ce n'ar fi [i la numr la fel
ca la identificator C 7 se transmit [irul cifrelor# de ce nu C Ceea ce nu am specificat
este c acest comportament (a trebui preci+at express `n specifica]iile scanerului%
Valoarea respecti( (a fi stocat `n record'ul semantic%
%{
#include <string.h> /* for strdup */
#include "simple.tab.h" /* for token definitions and yylval */
%}
DGT [0-9]
51
D [a-z][a-z0-9]*
%%
{DGT}+ { yylval.intval = atoi( yytext );
return(NT); }
...
{D} { yylval.id = (char *) strdup(yytext);
return(DENT); }
[ \t\n]+ /* eat up whitespace */
. { return(yytext[0]);}
%%
, func]ie pentru afi[area codului
"entru a afi[a codul &enerat pute]i adu&a la finalul modulului C9%. urmtoarea func]ie%
$pela]i'o dup &enerarea de cod# `nainte de a'l executa# pentru a (erifica codul
&enerat%
, serie de exemple de mici pro&rame `n 7imple [i codul &enerat la compilarea lor inten'
]ionm s le anexm acestui material%
void _print_code();
{
int i = 0;
while (i < code_offset) {
printf("%3ld: %-10s%4ld\n",i,op_name[(int) code[i].op], code[i].arg );
i++
}
}
>n exemplu
"entru a ilustra felul cum func]ionea+ &eneratorul de cod al compilatorului nostru
pre+entm un pro&ram `n 7imple [i codul &enerat 0Codul a fost pre+entat `n fi&ura 5%2#
la `nceputul capitolului2%
let
integer n,x.
in
read n;
if n < 10 then x := 1; else skip; fi;
while n < 10 do x := 5*x; n := n+1; end;
skip;
write n;
write x;
end
Figura 7.1: Program Simple
52
Capitolul :
,ptimi+area de cod dup &enerare
C.iar [i dup &enerarea codului exist optimi+ri care se mai pot face% Iu uita]i c por]i'
unile de cod &enerat s'au alturat a[a cum impunea sursa pro&ramul de compilat dar
nimic nu &arantea+ c `mbinarea lor este optim% !e asemenea anumite constante
care apar `n instruc]iunile &enerate pot su&erea `nlocuirea `ntre&ii instruc]iuni cu alta
mai scurt sau mai rapid% >nele `nmul]iri sau `mpr]iri# de exemplu cele cu 2 pot fi
`nlocuite cu alte opera]ii# cum sunt cele de deplasare a bi]ilor% 4nstruc]iuni de adunare
cu +ero # cele de `nmul]ire cu 1 [i alte opera]ii de(enite inutile din cau+a anumitor (alori
ale constantelor pot fi `nlocuite ori cu I," 0no operation2 sau c.iar eliminate% $dunarea
sau scderea cu 1 beneficia+ [i ele de instruc]iuni speciale mai rapide# pe care
ma=oritatea procesoarelor .ardAare le ofer% 4ar anumite opera]ii cu (ariabile pot fi
`nlocuite cu opera]ii reali+ate cu a=utorul re&i[trilor procesorului# mrindu'se astfel (ite+a
codului &enerat%
"entru a'l optimi+a# `ntre&ul cod &enerat (a fi parcurs a(=nd la fiecare moment `n (i+or
c=te(a instruc]iuni (ecine 0ca [i cum a]i (edea o camer pri(ind pe &aura c.eii2% !ac
ele se potri(esc cu anumite [abloane cunoscute de optimi+ator 0 procesul e numit c.iar
Epeep.ole optimi+ationE ' Eoptimi+are tip &aura c.eiiE2 atunci acesta le (a `nlocui cu alte
sec(en]e de cod mai rapide 0sau mai eficiente din alt punct de (edere# de exemplu mai
scurte2% >n exemplu tipic este eliminarea unor sec(en]e ">7K ] "," care nu fac dec=t
s pun [i s scoat aceea[i (aloare din sti( sau inlocuirea acestora cu opera]ii de
transfer `ntre re&istri 0dac sunt mai mul]i cu func]ii asemntoare2 sau `ntre re&i[tri [i
memorie%
Iu (om ilustra `n exemplul nostru de compilare a limba=ului 7imple asemenea te.nici
de optimi+are% !e altfel limba=ul ma[in extrem de simplu al 7'ma[inii noastre nu ofer
prea multe posibilita]i de a face asemenea optimi+ri# fiind un limba= minimalist% Cu totul
alta este situa]ia atunci c=nd se &enerea+ cod pentru un procesor .ardAare real# care
este oferit de fabricant cu un set mult mai (ast de instruc]iuni# dintre care unele pot
`nlocui uneori cu suces pe altele# oferind [i a(anta=e%
56
Capitolul 8
;ecturi suplimentare
3n ultimele (ersiuni 015 sept% 2006 [i 25 feb% 20012 ale documentului care a stat la ba+a
acestui (olum# document oferit de prof% $nt.on- $% $ab- prin 4nternet capitolul 8 nu
cuprindea dec=t dou r=nduri care recomand alte materiale ' nenumite ' pri(ind ;ex [i
Bacc precum [i lucrrile ' tot necitate ' scrise de un autor pe nume "ratt# pri(itoare la
ma[inile (irtuale% Vom suplini aceast omisiune indic=nd alte materiale accesibile `n
Jom=nia sau pe 4nternet pe care le'am selectat `n procesul elaborrii acestui (olum
deri(at din lucrarea domnului $nt.on- $% $ab-%
!espre 7%,% >I4L [i componentele sale# inclu+=nd Bacc [i ;ex pute]i consulta capitolul
11 al (olumui de mai =os# scris de Valentin Cristea [i colecti(ul su de coautori% <xplica'
]ii suplimentare despre folosirea (ariabilelor ZZ [i Z1#Z2 `n re&ulile semantice se &sesc
la pa&ina 251%
4) 5alentin (ristea, %lexandru 2\noiu, 'ugenia 6alis), 0rina %t#anasiu, 7orina
8egreanu, Silviu (\linoiu, 3lorin 9aboescu - UNIX, 9ucure[ti 4::;, 'd."eora ,
0S98 :<;-=>4-4>?-@
, carte accesibil# disponibil [i prin 4nternet dup ce `n prealabil fusese publicat de
4nternational ).omson `n 1886 apar]ine profesorului "%!%)err- de la J.odes >ni(ersit-%
3n anex este un `ntre& compilator pentru limba=ul Clan&# scris `n C% <xtrem de
instructi(% ,fer un bun suport teoretic dar recomand alt &enerator de compilatoare#
Coco@J% 7e poate &si cut=nd numele profesorului )err- cu un motor de cutare% 3n
prefa]a cr]ii sunt indicate site'urile/ .ttp/@@AAA%scifac%ru%ac%+a@compilers@ [i
.ttp/@@cs%ru%ac%+a@.ome@cspt@compbooD%.tm%
A) 2.,."erry, Compilers and Compiler Generators, 1#odes .niversity, 4::=,
2ublis#ed by 0nternational "#omson
>rmea+ un concis dar frumos manual de folosire pentru ;ex [i Bacc# utili+abil cu pu]in
effort [i pentru clonele lor de pe platforma ;inux# Flex'ul [i Bison'ul% <ra disponibil `n
format pdf pe site'ul epapers%com% Compilatorul pre+entat acolo foloseste un arbore
creat explicit nu implicit ca `n exemplul din acest (olum% $cest arbore poate fi exploatat
de un e(aluator# interpretor'ul de arbori# ob]in`ndu'se un interpretor pentru limba=ul
propus% $lt (ariant este &enerarea de cod pe ba+a arborelui% >n exerci]iu interesant
este implementarea unui compilator ca cel din lucrarea amintit 0mai =os2 folosind o
distribu]ie ;inux care include pro&ramele Flex [i Bison%
;) "#omas 8iemann, A Compact Guide to Lex & Yacc, epapers.com
"entru cunosctorii de "ascal interesa]i s scrie fr &enerator un mic compilator putem
51
recomanda un (olum practic# de tipul Elearn'b-'doin&E scris de un specialist `n fi+ic dar
pasionat de compilatoare# domnul UacD R%Crens.aA% <xist di(erse (ersiuni pe 4nternet
ale serialului su despre scrieirea practic a unui compilator# fie ca ar.i(e +ip cu plain'
text sau ca fi[ier pdf% $m a(ut la dispo+i]ie (ersiunea 1%: `n format pdf% < un mod
interesant de a face cuno[tin] cu un compilator [i cu problemele reali+rii acestuia%
"unctul de (edere este cel al practicianului care nu'[i pierde mult timp cu teoria% Ceea
ce face ca lectura unui (olum de teorie `npreun cu acesta s fie cu at=t mai
interesant%
@) Bac$ C. (rens#aD, Compiler Building Tutorial, ver. 4.E, %prill 44,A>>4.
3n cele din urm# dar poate cel mai citat# celebrul (olum scris de $lfred $.o# Ja(i 7et.i
[i Ueffre- >llmann `n 18:6 [i republicat apoi `n 18::% 7e poate &si la unele biblioteci
din Jom=nia%
?) %lfred %#o, 1avi Set#i [i Beffrey .llmann, (ompilers, 2rinciples, "ec#niFues
and "ools, 4:E=, %ddison-Cesley, 1eading, Gassac#usetts.

55
Capitolul 10
<xerci]ii
<xerci]iile care urmea+ sunt (ariate ca dificultate% "entru fiecare se cere s determina]i
ce modificri trebuie fcute &ramaticii# tabelei de simboluri [i ma[inii cu sti(% 7unt
c=te(a dintre exerci]iile oferite de prof% $%$%$ab- ele(ilor si%
1% Je'implementa]i tabela de simboluri sub form de arbore binar de cutare%
2% Je'implementa]i tabela de simboluri ca tabel .as.%
6% Je'implementa]i tabela de simboluri# &eneratorul de cod [i ma[ina cu sti( sub form
de clase C++.0Ioile (ersiuni de Flex [i Bison pot produce [i ele cod sub form de clase
C++.2
1% <xtinde]i compilatorul cu extensiile date mai =os% <xtensiile cer modificarea scanerului
pentru a manipula noii atomi [i modificarea parserului pentru a &estiona &ramatica
extins%
0a2 !eclara]ii/ 7c.imba]i procesarea semanticii identificatorilor astfel `nc=t ace[tia
s 0nu2 necesite declarare anterioar%
0b2 Constante [i (ariabile reale/ <xtinde]i tabela de simboluri astfel `nc=t
subrutinele care'o actuali+ea+ s stoc.e+e [i atributul de tip pentru fiecare
identificator% <xtinde]i rutinele semantice ale &eneratorului de cod astfel ca acesta s
&enere+e codul corespun+tor tipului de constante [i (ariabile pe care le `nt=lne[te#
(ariabile pe care aceste rutine le primesc ca parametri%
0c2 3nmul]ire# `mpr]ire 0[i ridicare la putere P2% Face]i sc.imbrile necesare `n
rutinele semantice pentru a se ocupa corect de &enerarea de cod%
0d2 4nstruc]iunile if [i D#ile+ Jutinele semantice trebuie s &enere+e propriile
teste [i salturi%
0e2 "roceduri fr parametri/ )abela de simboluri trebuie extins pentru a
manipula declara]ii imbricate iar rutinele semantice trebuie extinse pentru a &enera cod
pentru asi&urarea transferului controlului la fiecare punct de apel [i de asemenea la
`nceputul [i sf=r[itul corpului procedurii% 4ndica]ie/ 7e (a folosi re&istrul $J al ma[inii
(irtuale [i instruc]iunile care operea+ cu el%
,p]ional pute]i adu&a/
0a2 >n interpretor pentru codul produs de compilator%
0b2 3nlocui]i parserul &.idat de tabele# cu un parser descendent recursi(%
5% <xtinde]i compilatorul% , descriere este 0sau a fost2 inclus `n dosarul cs660@compiler
tools de pe site'ul cs%AAc%edu% "e scurt# sunt cerute urmtoarele extensii/
56
0a2 <xtinderea scanerului pentru a manipula noii atomi% Folosi]i un &enerator
pentru a produce noile tabele%
0b2 !eclara]ii pentru (ariabile `ntre&i [i reale%
0c2 Constante `ntre&i# expresii cu `ntre&i# opera]ii de 4@, pentru `ntre&i [i de ie[ire
pentru strin&uri%
0d2 4nstruc]iunea loop cu exit [i adu&area lui else [i elsif la instruc]iunea if.
0e2 "roceduri recursi(e cu parametri%
0f2 !eclararea recordurilor [i utili+area c=mpurilor%
0&2 !eclararea (ectorilor [i utili+area elementelor din (ectori%
0.2 >tili+area modulelor [i folosirea identificatorilor cu calificare%
6% Compilatorul urmtor trebuie s'l scrie]i complet# de la +ero% ;ista de mai =os enumer
caracteristicile limba=ului# pre+ent=nd `nt=i un subset de ba+ absolut necesar% Celelalte
caracteristici care urmea+ sunt op]ionale%
7etul de ba+/
0a2 )ipurile `ntre&# real# boolean%
0b2 <xpresii simple cu `ntre&i reali [i (alori booleene folosind operatorii/ +6- 6*6 36
/o&6 a/!6 or6 abs6 +o!6 **6 767#6868#6#6 3#
0c2 ,pera]ii de intrare pentru (alori `ntre&i# reale [i booleene
0d2 ,pera]ii de ie[ire pentru strin&uri [i expresii `ntre&i# reali# (alori booleene%
Fr formatare%
0e2 7tructuri de bloc# inclu+=nd declara]ii de (ariabile locale [i de constante
0f2 $tribuirea
0&2 4nstruc]iunile if# loop [i exit
0.2 "roceduri [i func]ii fr ar&umente# cu re+ultat scalar# inclusi( imbricate [i cu
(ariabile non'locale%
7etul op]ional/
Iu este tradus aici% 3l pute]i &si `n lucrarea ori&inal a prof% $%$%$ab-%
Jeamintim c un compilator scris de la +ero dar care &enerea+ cod pentru un procesor
real *otorola &si]i `n (olumul lui Bac$ C. (rens#aD, Compiler Building Tutorial,
ver. 4.E, %prill 44,A>>4, disponibil pe 4nternet%
55
$nexa $
;imba=ul 7imple ' 4mplementarea complet
$1% "arserul 7imple%-
!ac a]i reali+at fi[ierul cu specifica]ii Bacc@Bison# conform cu indica]iile din capitolele
precedente# ar trebui s ob]ine]i un text similar cu cel de mai =os# cu excep]ia
comentariilor% !ecoment=nd r=ndul /*yydebug = 1;*/ din func]ia main (e]i ob]ine la
execu]ie mult mai multe detali despre func]ionarea parserului%
%{/*************************************************************************
Compiler for the Simple language
***************************************************************************/
/*=========================================================================
C Libraries, Symbol Table, Code enerator ! other C "ode
=========================================================================*/
#in"lude $stdio%h& /* 'or (/) */
#in"lude $stdlib%h& /* 'or mallo" here and in symbol table */
#in"lude $string%h& /* 'or str"mp in symbol table */
#in"lude *ST%h* /* Symbol Table */
#in"lude *S+%h* /* Sta", +a"hine */
#in"lude *C%h* /* Code enerator */
#define --./01 1 /* 'or .ebugging */
int errors; /* /rror Count */
/*2222222222222222222222222222222222222222222222222222222222222222222222222
The follo3ing support ba",pat"hing
2222222222222222222222222222222222222222222222222222222222222222222222222*/
stru"t lbs /* Labels for data, if and 3hile */
{
int for4goto;
int for45mp4false;
6;
stru"t lbs * ne3lblre"78 /* 9llo"ate spa"e for the labels */
{
return 7stru"t lbs *8 mallo"7si:eof7stru"t lbs88;
6
/*2222222222222222222222222222222222222222222222222222222222222222222222222
(nstall identifier ! "he", if pre;iously defined%
2222222222222222222222222222222222222222222222222222222222222222222222222*/
install 7 "har *sym4name 8
{
symre" *s;
s = getsym 7sym4name8;
if 7s == <8
s = putsym 7sym4name8;
else { errors==;
printf7 *%s is already defined>n*, sym4name 8;
6
6
/*2222222222222222222222222222222222222222222222222222222222222222222222222
(f identifier is defined, generate "ode
2222222222222222222222222222222222222222222222222222222222222222222222222*/
"onte?t4"he",7 enum "ode4ops operation, "har *sym4name 8
{ symre" *identifier;
identifier = getsym7 sym4name 8;
5:
if 7 identifier == < 8
{ errors==;
printf7 *%s*, sym4name 8;
printf7 *%s>n*, * is an unde"lared identifier* 8;
6
else gen4"ode7 operation, identifier2&offset 8;
6
/*=========================================================================
S/+9@T(C A/C)A.S
=========================================================================*/
%6
%union semre" /* The Semanti" Ae"ords */
{
int int;al; /* (nteger ;alues */
"har *id; /* (dentifiers */
stru"t lbs *lbls; /* 'or ba",pat"hing */
6
/*=========================================================================
T)B/@S
=========================================================================*/
%start program
%to,en $int;al& @1+0/A /* Simple integer */
%to,en $id& (./@T('(/A /* Simple identifier */
%to,en $lbls& (' CD(L/ /* 'or ba",pat"hing labels */
%to,en SB(E TD/@ /LS/ '( .) /@.
%to,en (@T//A A/9. CA(T/ L/T (@
%to,en 9SS@)E
/*=========================================================================
)E/A9T)A EA/C/./@C/
=========================================================================*/
%left F2F F=F
%left F*F F/F
%right FGF
/*=========================================================================
A9++9A A1L/S for the Simple language
=========================================================================*/
%%
program H L/T
de"larations
(@ { gen4"ode7 .9T9, data4lo"ation78 2 1 8; 6
"ommands
/@. { gen4"ode7 D9LT, < 8; --9CC/ET; 6
;
de"larations H /* empty */
I (@T//A id4seJ (./@T('(/A K%K { install7 LM 8; 6
;
id4seJ H /* empty */
I id4seJ (./@T('(/A F,F { install7 LN 8; 6
;
"ommands H /* empty */
I "ommands "ommand F;F
;
"ommand H SB(E
I A/9. (./@T('(/A { "onte?t4"he",7 A/9.4(@T, LN 8; 6
I CA(T/ e?p { gen4"ode7 CA(T/4(@T, < 8; 6
I (./@T('(/A 9SS@)E e?p { "onte?t4"he",7 ST)A/, L1 8; 6
I (' e?p { L1 = 7stru"t lbs *8 ne3lblre"78;
L12&for45mp4false = reser;e4lo"78; 6
58
TD/@ "ommands { L12&for4goto = reser;e4lo"78; 6
/LS/ { ba",4pat"h7 L12&for45mp4false,
O+E4'9LS/,
gen4label78 8; 6
"ommands
'( { ba",4pat"h7 L12&for4goto, )T), gen4label78 8; 6
I CD(L/ { L1 = 7stru"t lbs *8 ne3lblre"78;
L12&for4goto = gen4label78; 6
e?p { L12&for45mp4false = reser;e4lo"78; 6
.)
"ommands
/@. { gen4"ode7 )T), L12&for4goto 8;
ba",4pat"h7 L12&for45mp4false,
O+E4'9LS/,
gen4label78 8; 6
;
e?p H @1+0/A { gen4"ode7 L.4(@T, L1 8; 6
I (./@T('(/A { "onte?t4"he",7 L.4P9A, L1 8; 6
I e?p F$F e?p { gen4"ode7 LT, < 8; 6
I e?p F=F e?p { gen4"ode7 /Q, < 8; 6
I e?p F&F e?p { gen4"ode7 T, < 8; 6
I e?p F=F e?p { gen4"ode7 9.., < 8; 6
I e?p F2F e?p { gen4"ode7 S10, < 8; 6
I e?p F*F e?p { gen4"ode7 +1LT, < 8; 6
I e?p F/F e?p { gen4"ode7 .(P, < 8; 6
I e?p FGF e?p { gen4"ode7 ECA, < 8; 6
I F7F e?p F8F
;
%%
/*=========================================================================
+9(@
=========================================================================*/
main7 int arg", "har *arg;RS 8
{ e?tern '(L/ *yyin;
==arg;; 22arg";
yyin = fopen7 arg;R<S, *r* 8;
/*yydebug = 1;*/
errors = <;
yyparse 78;
printf 7 *Earse Completed>n* 8;
if 7 errors == < 8
{ print4"ode 78;
fet"h4e?e"ute4"y"le78;
6
6
/*=========================================================================
--/AA)A
=========================================================================*/
yyerror 7 "har *s 8 /* Called by yyparse on error */
{
errors==;
printf 7*%s>n*, s8;
6
/**************************** /nd rammar 'ile ***************************/
60
$%2% 4ndica]ii de lucru
$m transcris mai =os comen+ile pe care (a trebui s le da]i sistemului dumnea(oastr
;inux% $m testat aceast sec(en] pe un JedKat ;inux 5%2 [i nu am &sit deosebiri fa]
de comen+ile propuse de dl% $%$%$ab-% 7in&urele deosebiri au fost c promptul
sistemului meu ;inux nu este ETE ci EZE 0de[i el se poate modifica folosind comanad
prompt2 iar (ersiunea de compilator &cc folosit mai a(ea ne(oie de o op]iune `n linia de
comand 0 'lfl2%
> bison -d Simple.y
sau
> bison -dv Simple.y
Simple.y contains 39 shift/reduce conflicts.
> gcc -c Simple.tab.c
> flex Simple.lex
> gcc -c lex.yy.c
> gcc -o Simple Simple.tab.o lex.yy.o -lm -lfl
> Simple test_simple
Parse Completed
0: data 1
1: in_int 0
2: ld_var 0
3: ld_int 10
4: lt 0
5: jmp_false 9
6: ld_int 1
7: store 1
8: goto 9
9: ld_var 0
10: ld_int 10
11: lt 0
12: jmp_false 22
13: ld_int 5
14: ld_var 1
15: mult 0
16: store 1
17: ld_var 0
18: ld_int 1
19: add 0
20: store 0
21: goto 9
22: ld_var 0
23: out_int 0
24: ld_var 1
25: out_int 0
26: halt 0
61
$%6% 7canerul/ 7imple%lex
/***************************************************************************
S"anner for the Simple language
***************************************************************************/
%{
/*=========================================================================
C2libraries and To,en definitions
=========================================================================*/
#in"lude $string%h& /* for strdup */
/*#in"lude $stdlib%h& */ /* for atoi */
#in"lude *Simple%tab%h* /* for to,en definitions and yyl;al */
%6
/*=========================================================================
T)B/@ .efinitions
=========================================================================*/
.((T R<2TS
(. Ra2:SRa2:<2TS*
/*=========================================================================
A/1L9A /UEA/SS()@S defining the to,ens for the Simple language
=========================================================================*/
%%
*H=* { return79SS@)E8; 6
{.((T6= { yyl;al%int;al = atoi7 yyte?t 8;
return7@1+0/A8; 6
do { return7.)8; 6
else { return7/LS/8; 6
end { return7/@.8; 6
fi { return7'(8; 6
if { return7('8; 6
in { return7(@8; 6
integer { return7(@T//A8; 6
let { return7L/T8; 6
read { return7A/9.8; 6
s,ip { return7SB(E8; 6
then { return7TD/@8; 6
3hile { return7CD(L/8; 6
3rite { return7CA(T/8; 6
{(.6 { yyl;al%id = 7"har *8 strdup7yyte?t8;
return7(./@T('(/A8; 6
R >t>nS= /* eat up 3hitespa"e */
% { return7yyte?tR<S8; 6
%%
int yy3rap7;oid8{6
/************************** /nd S"anner 'ile *****************************/
62
$%1 )abela de simboluri/ 7t%.
/***************************************************************************
Symbol Table +odule
***************************************************************************/
/*=========================================================================
./CL9A9T()@S
=========================================================================*/
/*2222222222222222222222222222222222222222222222222222222222222222222222222
S-+0)L T90L/ A/C)A.
2222222222222222222222222222222222222222222222222222222222222222222222222*/
stru"t symre"
{
"har *name; /* name of symbol */
int offset; /* data offset */
stru"t symre" *ne?t; /* lin, field */
6;
typedef stru"t symre" symre";
/*2222222222222222222222222222222222222222222222222222222222222222222222222
S-+0)L T90L/ /@TA-
2222222222222222222222222222222222222222222222222222222222222222222222222*/
symre" *identifier;
/*2222222222222222222222222222222222222222222222222222222222222222222222222
S-+0)L T90L/
(mplementationH a "hain of re"ords%
222222222222222222222222222222222222222222222222222222222222222222222222*/
symre" *sym4table = 7symre" *8<; /* The pointer to the Symbol Table */
/*========================================================================
)perationsH Eutsym, etsym
========================================================================*/
symre" * putsym 78;
symre" * getsym 78;
symre" * putsym 7"har *sym4name8
{
symre" *ptr;
ptr = 7symre" *8 mallo" 7si:eof7symre"88;
ptr2&name = 7"har *8 mallo" 7strlen7sym4name8=18;
str"py 7ptr2&name,sym4name8;
ptr2&offset = data4lo"ation78;
ptr2&ne?t = 7stru"t symre" *8sym4table;
sym4table = ptr;
return ptr;
6
symre" * getsym 7"har *sym4name8
{
symre" *ptr;
for 7 ptr = sym4table;
ptr V= 7symre" *8 <;
ptr = 7symre" *8ptr2&ne?t 8
if 7str"mp 7ptr2&name,sym4name8 == <8
return ptr;
return <;
6
/************************** /nd Symbol Table **************************/
66
$%5 9eneratorul de cod/ C9%.
/***************************************************************************
Code enerator
***************************************************************************/
/*2222222222222222222222222222222222222222222222222222222222222222222222222
.ata Segment
2222222222222222222222222222222222222222222222222222222222222222222222222*/
int data4offset = <; /* (nitial offset */
int data4lo"ation78 /* Aeser;es a data lo"ation */
{
return data4offset==;
6
/*2222222222222222222222222222222222222222222222222222222222222222222222222
Code Segment
2222222222222222222222222222222222222222222222222222222222222222222222222*/
int "ode4offset = <; /* (nitial offset */
int reser;e4lo"78 /* Aeser;es a "ode lo"ation */
{
return "ode4offset==;
6
int gen4label78 /* Aeturns "urrent offset */
{
return "ode4offset;
6
/* enerates "ode at "urrent lo"ation */
;oid gen4"ode7 enum "ode4ops operation, int arg 8
{
"odeR"ode4offsetS%op = operation;
"odeR"ode4offset==S%arg = arg;
6
/* enerates "ode at a reser;ed lo"ation */
;oid ba",4pat"h7 int addr, enum "ode4ops operation, int arg 8
{
"odeRaddrS%op = operation;
"odeRaddrS%arg = arg;
6
/*2222222222222222222222222222222222222222222222222222222222222222222222222
Erint Code to stdio
2222222222222222222222222222222222222222222222222222222222222222222222222*/
;oid print4"ode78
{
int i = <;
3hile 7i $ "ode4offset8 {
printf7*%MldH %21<s%Wld>n*,i,op4nameR7int8 "odeRiS%opS, "odeRiS%arg 8;
i==;
6
6
/************************** /nd Code enerator **************************/
61
$%6 *a[ina cu sti( / 7*%.
/***************************************************************************
Sta", +a"hine
***************************************************************************/
/*=========================================================================
./CL9A9T()@S
=========================================================================*/
/* )E/A9T()@SH (nternal Aepresentation */
enum "ode4ops { D9LT, ST)A/, O+E4'9LS/, )T),
.9T9, L.4(@T, L.4P9A,
A/9.4(@T, CA(T/4(@T,
LT, /Q, T, 9.., S10, +1LT, .(P, ECA 6;
/* )E/A9T()@SH /?ternal Aepresentation */
"har *op4nameRS = { *halt*, *store*, *5mp4false*, *goto*,
*data*, *ld4int*, *ld4;ar*,
*in4int*, *out4int*,
*lt*, *eJ*, *gt*, *add*, *sub*, *mult*, *di;*,
*p3r* 6;
stru"t instru"tion
{
enum "ode4ops op;
int arg;
6;
/* C)./ 9rray */
stru"t instru"tion "odeRTTTS;
/* A1@2T(+/ Sta", */
int sta",RTTTS;
/*2222222222222222222222222222222222222222222222222222222222222222222222222
Aegisters
2222222222222222222222222222222222222222222222222222222222222222222222222*/
int p" = <;
stru"t instru"tion ir;
int ar = <;
int top = <;
"har "h;
/*=========================================================================
'et"h /?e"ute Cy"le
=========================================================================*/
;oid fet"h4e?e"ute4"y"le78
{ do { /*printf7 *EC = %Md (A%arg = %Xd 9A = %Md Top = %Md,%Xd>n*,
p", ir%arg, ar, top, sta",RtopS8; */
/* 'et"h */
ir = "odeRp"==S;
/* /?e"ute */
s3it"h 7ir%op8 {
"ase D9LT H printf7 *halt>n* 8; brea,;
"ase A/9.4(@T H printf7 *(nputH * 8;
s"anf7 *%ld*, !sta",Rar=ir%argS 8; brea,;
65
"ase CA(T/4(@T H printf7 *)utputH %d>n*, sta",Rtop22S 8; brea,;
"ase ST)A/ H sta",Rir%argS = sta",Rtop22S; brea,;
"ase O+E4'9LS/ H if 7 sta",Rtop22S == < 8
p" = ir%arg;
brea,;
"ase )T) H p" = ir%arg; brea,;
"ase .9T9 H top = top = ir%arg; brea,;
"ase L.4(@T H sta",R==topS = ir%arg; brea,;
"ase L.4P9A H sta",R==topS = sta",Rar=ir%argS; brea,;
"ase LT H if 7 sta",Rtop21S $ sta",RtopS 8
sta",R22topS = 1;
else sta",R22topS = <;
brea,;
"ase /Q H if 7 sta",Rtop21S == sta",RtopS 8
sta",R22topS = 1;
else sta",R22topS = <;
brea,;
"ase T H if 7 sta",Rtop21S & sta",RtopS 8
sta",R22topS = 1;
else sta",R22topS = <;
brea,;
"ase 9.. H sta",Rtop21S = sta",Rtop21S = sta",RtopS;
top22;
brea,;
"ase S10 H sta",Rtop21S = sta",Rtop21S 2 sta",RtopS;
top22;
brea,;
"ase +1LT H sta",Rtop21S = sta",Rtop21S * sta",RtopS;
top22;
brea,;
"ase .(P H sta",Rtop21S = sta",Rtop21S / sta",RtopS;
top22;
brea,;
case PWR : stack[top-1] = stack[top-1] * stack[top];
top--;
break;
default H printf7 *%s(nternal /rrorH +emory .ump>n* 8;
brea,;
6
6
3hile 7ir%op V= D9LT8;
6
/*************************** /nd Sta", +a"hine **************************/
$[a cum am preci+at `n capitolele precedente# instruc]iunea "RJ a ma[inii (irtuale
trebuie s fac ridicare la putere nu `nmul]ire% "or]iunea din text care trebuie `nlocuit
este e(iden]iat%
66
$%5 >n exemplu de pro&ram/ test?simple
let
integer n,x.
in
read n;
if n < 10 then x := 1; else skip; fi;
while n < 10 do x := 5*x; n := n+1; end;
skip;
write n;
write x;
end
Oi codul produs# de data aceasta alturate/
0: data 1
1: in_int 0
2: ld_var 0
3: ld_int 10
4: lt 0
5: jmp_false 9
6: ld_int 1
7: store 1
8: goto 9
9: ld_var 0
10: ld_int 10
11: lt 0
12: jmp_false 22
13: ld_int 5
14: ld_var 1
15: mult 0
16: store 1
17: ld_var 0
18: ld_int 1
19: add 0
20: store 0
21: goto 9
22: ld_var 0
23: out_int 0
24: ld_var 1
25: out_int 0
26: halt 0
Figura 7.2: Codul generat
65