Sunteți pe pagina 1din 32

Lucrarea de laborator Nr.

6 la Modelarea Sistemelor

Tema: Analiza i simularea construirii programului prin recunoasterea gramaticei dupa


anumita sintaxa si reguli de transformare a grafului in program.
Obiective:
1. de studiat i nsuit materialul teoretic pentru evidenierea esenialului n elaborarea modelelor;
2. s se elaboreze scenarii de modelare i analiza simulrii elementelor caracteristice produselor soft i
modulelor (funciilor) n baza diferitor modele de reprezentare pentru propria variant (Exemplu);
3. de analizat tehnicile i metodele de analiz sintactic ca parte component a analizei lexicale de
recunoastere a corectitudinei.
4. n baza celor studiate de elaborat modelul experimental n forma unui program de simulare a analizei
semantice ca faz a compilrii n care au fost stabilite gramaticile de baz a limbajului C i au fost
implementate n program. De asemenea se execut i se efectuiaz analiza sintactic a codului surs,
adic se face verificarea punctuaiei i a utilizrii parantezelor n textul programului.
Consideraii teoretice
1. Noiuni generale i definiii.
Domeniul care se preocup de acest aspect ar fi prelucrarea limbajului natural, situat undeva la
grania ntre lingvistic i tiinele cognitive.
Principalul scop const n ceea ce privete limbajul natural este permiterea comunicrii ntre calculator
i om fr a fi necesar memorarea unor comenzi sau proceduri complexe, comunicarea urmnd a se face
prin comenzi simple, formulate n limbajul de zi cu zi.
Un alt scop important ar fi traducerea automat, aceasta urmnd s permit oamenilor de tiin,
oamenilor de afaceri sau populaiei de rnd s comunice liber intre ei indiferent de naionalitate i limb
vorbit.
Toate acestea reprezint doar o parte din aria vast a inteligentei artificiale i a limbajului natural, ce
include i tiinele cognitive n ncercarea de a explica modul n care oamenii neleg de fapt limbajul
(nelegerea limbajului uman).
Printele prelucrrii limbajului natural este considerat omul de tiin Naom Chomsky, studiile sale
ncepnd cu 1950, influennd dezvoltarea ulterioar a limbajelor de programare prin intermediul limbajelor
formale. Este memorabil teza acestuia potrivit creia ne cunoatem cunoscnd limbajul. Plecnd de la
aceast tez, Alan Turing, tot n 1950, propune ca una dintre cerinele pe care un calculator trebuie s le
ndeplineasc pentru a fi considerat inteligent, s fie aceea de a fi capabil s neleag si s rspund ntr-un
limbaj natural.
Limbajul natural este o modalitate de comunicare om-main care prezint cteva avantaje majore de
partea utilizatorului:
- Nu necesit instruire pentru folosirea lui;
- Scutete utilizatorul de familiarizarea cu limbajele formale;
- Este un mijloc direct de accesare a informaiei, independent de structura i codificarea acestuia.
O aplicaie de prelucrare a limbajului natural poate prezenta urmtoarele trei componente:
1. scanner-ul

36
Care realizeaz descompunerea unei propoziii/fraze ntr-o list a cuvintelor sale componente
2. parser-ul care realizeaz analiza propoziiilor/frazelor conform regulilor specificate de gramatica
adoptat precum i obinerea semanticii aferente acestora. Pentru aceasta, se
apeleaz la analiza sintactic i morfologic, la analiza semantic i la analiza pragmatic;
3. executivul care preia semantica obinut n pasul anterior, transformndu-o n comenzi sau
cunotine. Noi nelegem texte mari combinnd fora noastr de nelegere pentru textele mai mici.
Principalul scop al teoriei lingvistice este acela de a arta cum prtile mari de text sunt formate din mai
multe prti mici. Acestea sunt modelate de gramatic. Lingvistica computaional ncearc s implementeze
acest proces de recunoatere ntr-un mod ct mai eficient. Este tradiional s subdivizm acest task n
sintactic i semantic, unde sintactica descrie cum diferite elemente formale a unui text, de cele mai multe ori
propoziii, pot fi combinate, iar semantica descrie cum este calculat interpretarea.
Analiza sintactic ne ajut s nelegem modalitatea prin care cuvintele se grupeaz n vederea
construirii unei propoziii sau fraze. n acest sens, o propoziie este format din constitueni sintactici, unii
dintre ei fiind, la rndul lor, compui din constitueni. Constituenii care la rndul lor sunt formai din
constitueni se numesc non-lexicali n timp ce toi ceilali se numesc lexicali. Constituenii lexicali (cuvintele
vocabularului) mpreun cu caracteristicile lor morfologice (numr, timp, caz etc.) formeaz lexiconul.

1. Schema general a unui compilator. Compilatorul este un program complex, a crui realizare
presupune abordarea sistemic a procesului de traducere. In procesul de compilare, PS sufer un ir de
transformri n cascad, din ce n ce mai apropiate de CO. Conceptual, un compilator realizeaz dou mari
clase de operaii:
- analiza textului surs;
- sinteza codului obiect.
La rndul lor, aceste operaii se descompun n suboperaii specializate, nlnuite ntre ele i caracterizate
prin funcii bine precizate. Din punctul de vedere al structurii sale, un compilator poate fi reprezentat
schematic ca n fg. 3.5. Se observ nlnuirea etapelor analizei i sintezei, precum i ordinea natural a
acestora. Facem aici observaia c aceast reprezentare se dorete a fi general, i c n practic anumite
etape pot fi considerate mpreun.

36
Analiza lexical realizeaz o prim parcurgere a PS (considerai ca sar de caractere), grupnd aceste
caractere in subsiruri. numite atomi lexicali: cuvinte cheie sau rezervate, operatori, constante, identificatori,
separatori.
Analiza sintactica depisteaz in irul atomilor lexicali structuri sintactice, expresii, liste, instruciuni,
procedri s a , genernd arborele sintactic (arborele de derivare), care descrie relaiile dintre aceste structuri
(de incluziune, de separare etc).
Analiza semantic folosete arborele sintactic pentru extragerea de informaii privind apariiile obiectelor
purttoare de date din PS (tipuri de date, variabile, proceduri, funcii) i pentru verificarea consistenei
utilizrii lor Pe msura parcurgerii arborelui sintactic, se genereaz codul intermediar. Acesta este un ir de
instruciuni simple, cu format fix, n care: codurile operaiilor sunt asemntoare cu codurile main
corespunztoare, ordinea operaiilor respect ordinea execuiei (dictat de apariia acestora n PS), iar
operanzii sunt reprezentai sub forma variabilelor din PS, i nu sub form de regitri sau adrese de memorie.
Optimizarea codului intermediar are ca obiectiv eliminarea redundanelor, a calculelor inutile, n scopul
realizrii unei execuii eficiente a codului obiect Pentru atingerea acestui obiectiv se ncearc:
realizarea tuturor calculelor posibile nc din faza de compilare (de exem-plu
n expresii cu operanzi constante);
eliminarea subexpresiilor comune (prin evaluarea lor o singur dat);
factorizarea invarianilor din cicluri.
Generarea programului (codului) obiect const in alocarea de locaii de memorie i regitri ai unitii
centrale pentru variabilele programului i n nlocuirea codurilor de operaii din codul intermediar cu cele
main. Codul obiect rezultat poate fi:
absolut (direct executabil);
relocabil (care va face obiectul editrii de legturi, unde va fi legat de alte
module obiect, rezultate din compilri anterioare sau din biblioteci);
n limbaj de asamblare, lucru ce asigur un efort mai mic de implementare a
generatorului de cod
sau
n alt limbaj de programare n cazul preprocesoarelor.
n alt ordine de idei, generarea de cod difer in funcie de arhitectura mainii (main cu acumulator i
cu registre de baz i index sau main cu registre generale).

Cele 5 module de baza ale procesului de compilare sunt asistate de alte dou componente ale compilatorului,
ale cror servicii sunt utilizate pe tot parcursul compilarii: modulul de tratare a erorilor i gestionarul tabelei
de simboluri:
Modulul de tratare a erorilor este constituit dintr-o colecie de proceduri care sunt activate ori de cte ori este
detectat o eroare n timpul operaiilor de analiza. Ele emit mesaje de diagnostic relative ia eroarea
respectiv i iau decizii privind modul de continuare a traducerii:
- traducerea se continu cu ignorarea elementului ce conine eroarea;
- se ncearc corectarea erorii
sau
- se abandoneaz procesul de traducere.
Dup momentul de analiz n care apar, erorile pot fi lexicale, sintactice sau semantice. Un alt criteriu de
clasificare a erorilor este "gravitatea" lor; distingem avertismente (de obicei omisiuni de programare),
erori care se pot "corecta" de ctre un compilator mai inteligent i erori "fatale", care provoac
abandonarea

Gestionarul tabelelor este tot o colecie de proceduri care realizenz crearea si actualizarea bazei de date a
compilatorului, carc conine dou categorii de informaii:

37
- proprii compilatorului (generate la implementare i constituite din mecanismele de descriere a
analizei lexicale, sintactice i semantice)
si
- caracteristice PS (identificatori, constante, cuvinte cheie), care de obicei se memoreaz ntr-o tabel
de simboluri.
Exist diverse modaliti de gestionare a tabelei de simboluri, n funcie de reprezentarea acesteia (tabel
neordonat, tabel ordonat alfabetic sau dispersat -memorarea i regsirea fcnd apel ntr-un astfel de caz
la aa numitele funcii de dispersie hashing functions de tipul limbajului supus traducerii (cu sau fr
structur de bloc), de conveniile alese pentru reprezentarea atributelor n tabel, de caracterul general
(acoperitor) al tabelei (existena unei singure tabele de simboluri sau prezena unor tabele specializate
pentru variabile, proceduri, constante, etichete) etc.
In faza de analiz lexicali (de obicei), la ntlnirea unui nume nou, acesta este introdus n tabela de
simboluri, reinndu-se adresa intrrii. Ori de cte ori numele este referit, informaia prezenta n tabel
este actualizat cu informaii sau atribute noi ale numelui respectiv, verificndu-se totodat consistena
utilizrii acestuia (n analiza semantica). La generarea de cod, atributele numelui determina lungimea
zonei de memorie alocata acestuia. In sfirsit, atributele
numelui pot servi si in faza de tratare a erorilor.

1.1 Analiza Faza de analiz cuprinde trei etape: analiza lexical, sintactica si semantica. Aceste trei etape
se pot implementa separat, aa cum este ilustrat in figura 3.5, sau global.
1.2 Analiza lexical. Analiza lexical (engl. scanning, analizor lexical = scanner), transforma PS
(considerat ir de caractere) ntr-un ir de uniti lexicale, numite atomi lexicali sau particule lexicale (engl.
tokens). Clasele de atomi lexicali, considerate ca mulimi finite, corespund identificatorilor, constantelor
ntregi, constantelor reale i operatorilor. Pe scurt, analizorul lexical realizeaz operaii de detectare,
clasificare i traducere:
- detectarea n PS a subirurilor ce respecta regulile de formare a atomilor lexicali;

- clasificarea acestor subiruri (identificarea clasei acestora);

- traducerea subirurilor n atomi lexicali;

- memorarea n tabela de simboluri a identificatorilor i constantelor.

De obicei, analiza lexical este considerat ca o etap a analizei sintactice. Intre argumentele n favoarea
separrii acestor operaii menionm:
- o proiectare mai simpl a analizorului sintactic i a celui lexical, datorat principiului separrii
funciilor;
- posibilitatea scrierii analizorului lexical n limbaj de asamblare (el ne cesitnd n general operaii apropiate de
main), i n limbaje de nivel nalt a celorlalte componente ale compilatorului;
- deoarece sintaxa atomilor lexicali se poale exprima cu ajutorul unei gramatici regulate, modelul
analizorului lexical poate fi un automat finit care este mai simplu de implementat dect automatele push-
down utilizate n celelalte etape ale analizei;
- aportul analizorului lexical la "igienizarea" PS, deoarece:

numrul atomilor lexicali este mai mic dect numrul de caractere din PS;
se elimini blank-urile sau comentariile;
se poate prelua n analiza lexical evaluarea unor construcii dificil de implementat n analizorul
sintactic, rezultatul fiind reducerea complexitii analizei sintactice;

36
- creterea portabilitii algoritmului de compilare (de exemplu la dialecte diferite ale aceluiai limbaj, ce
diferi prin cuvinte cheie, realizarea unui compilator nseamn doar (scrierea analizorului lexical).

Din punctul de vedere al relaiei cu analizorul sintactic, se deosebesc dou moduri de abordare:

- analizor lexical independent de analizorul sintactic;

- analizor lexical comandat de analizorul sintactic, caz n care primul este o rutin a celui de al doilea.

Din punct de vedere structural, analizorul lexical poate fi monobloc (analiza lexical este abordat i
rezolvat global) sau structurat, cnd gramatica atomilor lexicali este stratificat, rezultnd de obicei trei
subfaze: transliterare (clasificarea caracterelor PS), explorare (depistarea i clasificarea subirurilor de atomi
lexicali) i selectare (definitivarea clasificrii, eliminarea caracterelor inutile i codificarea atomilor lexicali).

Etapele ce trebuie parcurse n proiectarea unui analizor lexical sunt:

tratarea gramaticii atomilor lexicali, prin rafinri succesive, obtinndu-se o mulime de gramatici
regulate;

stabilirea diagramei de tranziie a automatului de recunoatere echiva-lent gramaticilor regulate;

completarea diagramei de tranziie cu proceduri semantice asociate tranziiilor (pentru semnalarea


erorilor sau pentru emiterea unor ieiri).

1.3 Analiza sintactic. Analiza sintactic (engl. parsing) este una dintre etapele principale ale
procesului de traducere. Prin ea se realizeaz transformarea irului de intrare (format din atomi lexicali) n:

- descrierea structural a acestuia, semantic echivalent (n cazul cnd irul de intrare este corect
sintactic)
respectiv
- mesaj de eroare (n caz contrar).

Descrierea structural este echivalent arborelui de derivare.

Construirea arborelui de derivare se face pe baza irului atomilor lexicali i poate fi:

- ascendent (de la frunze spre rdcin)


sau
- descendent (de la rdcin spre frunze).

Analizoarele sintactice se pot clasifica dup modul de construire a arborelui de derivare (analizoare
ascendente, respectiv descendente) sau dup existena revenirilor n procesul de construire a acestui arbore
(cu reveniri sau fr reveniri).
Modelul sintaxei limbajelor de programare este gramatica independent de context, prin urmare,
conform rezultatelor teoretice expuse n seciunea precedent, modelul analizorului sintactic va fi
automatul push-down nedeter-minist. n simularea funcionrii acestuia, este important problema tratrii
revenirilor. Dac la un moment dat se pot lua n considerare mai multe alternative de continuare a derivrii,
trebuie s se prevad posibilitatea revenirii la o alt alternativ posibil cnd alternativa aleas nu conduce
la un rezultat favorabil. Acest lucru mrete timpul de realizare a analizei, motiv pentru care este de dorit ca
la orice moment s fie asigurat o singur posibilitate de continuare a acesteia.

Analiza sintactic descendent are ca model APDN i se bazeaz pe derivarea stnga a irului

37
acceptat Operaiile acestui automat sunt:

- expandarea (nlocuirea unui neterminal A din vrful stivei cu partea dreapt a unei A-producii din
gramatic) i

- avansul (tergerea unui terminal din vrful stivei atunci cnd el coincide cu terminalul curent din
irul de intrare, urmat de avansul intrrii).

Criteriul de acceptare este criteriul stivei vide. Revenirile sunt modelate cu ajutorul unei stive auxiliare, n
care se memoreaz configuraia APDN la fiecare punct de ramificare a analizei, cnd sunt posibile mai
multe alternative de derivare. In cazul analizoarelor sintactice descendente fr reveniri, modelul sintaxei
este gramatica LL(k).

Analiza sintactic ascendent are ca model APDN extins i se bazeaz pe derivarea dreapta a irului
acceptat, parcurs n ordine invers. Operaiile acestui automat sunt:

- deplasarea (cutarea n irul de intrare, trecut succesiv n stiv, a prilor drepte ale regulilor de
producie ale gramaticii) i

- reducerea (o parte dreapt a unei reguli de producie este nlocuit cu neterminalul din partea stng
a regulii respective).

Criteriul de acceptare este epuizarea ntregului ir de intrare, iar n stiv trebuie si rmn numai simbolul
de start al gramaticii. In cazul general, cnd modelul sintactic al limbajului de tradus este o gramatic
independent de intext, analiza sintactic ascendent este cu reveniri. Analiza sintactic acendent fr
reveniri utilizeaz ca model de sintax gramaticile LR(k).

1.4 Analiza semantic. Structura sintactic poate fi folosit pentru specificarea semanticii unui limbaj.
n general, semantica (nelesul) unei construcii poate fi exprimat prin orice cantitate sau mulime de
cantiti asociate acelei construcii. O astfel de cantitate asociat se numete atribut. Ca exemple de
atribute putem meniona: o mulime de iruri de caractere, o valoare, un tip, o configuraie specific de
memorie etc. Aceast modalitate de abordare a semanticii se numete orientat de sintax (syntax
directed). Regulile care definesc atributele unei construcii se numesc reguli semantice. O specificare de
sintax mpreun cu regulile semantice asociate realizeaz o definiie orientat de sintax.
De exemplu, dac dezvoltm un evaluator de expresii, semantica expresiei 2+3 poate fi exprimat prin
valoarea 5. Dac dezvoltm un translator din form infixat n form postfxat semantica expresiei 2+3 ar
putea fi exprimat sub forma tripletului (+ 2 3).
Conceput ca o finalizare a etapei de analiz a textului surs (prin generarea codului intermediar), analiza
semantic completeaz structurile sintactice cu valorile atributelor asociate fiecrei componente de structur.
Cunoscndu-se valorile atributelor, se realizeaz:
- validare semantic a PS;
- generarea codul intermediar echivalent
Aciunile realizate n aceast ultim faz a analizei sunt urmtoarele:
- atributarea arborelui de derivare (evaluarea atributelor asociate nodurilor acestuia);
- generarea de cod intermediar.
Aceste dou obiective se realizeaz de obicei prin parcurgerea de mai multe ori a arborelui de sintax. In
practic, analiza semantic se desfoar n paralel cu analiza sintactic, prin completarea aciunilor
analizorului sintactic cu aciuni referitoare la anumite structuri de date ce reprezint atribute ale
componentelor sintactice.
Exist diverse formalismc pentru analiza semantic, ntre care amintim:
- schemele generalizate de traducere orientate pe sintax (Aho);

36
- gramaticile de atribute extinse cu aciuni de traducere (Marcotty),
Nu exist ns un model unanim acceptat Formalismele existente depind de strategia aleas n analiza
sintactic (ascendent sau descendenta)

1.5 Uniti de program. Structura general a unui program scris ntr-un limbaj de
programare convenional (imperativ, dirijat de control) presupune existenta unui program principal
i eventual a unuia sau mai multor subprograme (proceduri, funcii si subrutine) care comunic ntre
ele i/sau cu programul principal prin intermediul parametrilor i/sau a unor variabile globale.
Orice program sau subprogram surs, indiferent de limbajul n care este scris i indiferent de sintaxa
concret a acestuia este divizat n dou pri (nu neaparat distincte din punct de vedere fizic): partea de
declaraii i partea imperativa Declaraiile, denumite uneori i instruciuni neexecutabile sunt informaii
descriptive adresate compilatorului care descriu in principal atribute ale zonelor de date cum ar fi tipul,
dimensiunea de reprezentare, eventual valori initiale etc. Partea imperativ conine instruciunile ce se vor
executa n cursul rulrii (sub)programului.
Ideea reutilizrii codului precum i cea a reducerii dificultilor de proiectare i ntreinere a programelor
mari au condus n mod natural la modularizarea dezvoltrii programelor. Corespunztor, ca rezultat al
procesului de abstractizare i factorizare, apar astfel la nivelul programelor, unitati de program distincte,
numite module, cu rol bine precizat i care aduc odat ru apariia lor numeroase avantaje. Unul dintre cele
mai importante n acest sens este compilarea separat.
In
majoritatea cazurilor activitile pe care subprogramele le efectueaz sunt independente. Astfel, unul
sau mai multe subprograme pot fi grupate n module, care, fiind la rndul lor independente pot fi compilate
separat unul de cellalt, adic la momente diferite n timp i combinate mai trziu de ctre editorul de
legturi ntr-un unic program executabil. Ca urmare, dac un modul necesit modificri i celelalte nu, va fi
recompilat doar modulul modificat, editorul de legturi realiznd apoi combinarea codului obiect rezultat cu
versiunile deja compilate ale celorlalte module. Se economisete in acest fel un timp semnificativ de lucru,
ideea compilrii separate fiind extrem de util la ntreinerea bibliotecilor mari de programe.

1.6 Rolul analizorului sintactic. Un analizor sintactic primete la


intrare un ir de uniti lexicale i produce arborele de derivare al acestui ir n
gramatica ce descrie structura sintactic (mai degrab o anume reprezentare a
acestui arbore). n practic, odat cu verificarea corectitudinii sintactice, se produc
i alte aciuni n timpul analizei sintactice: trecerea n tabela de simboluri a unor
informaii legate de unitile sintactice, controlul tipurilor sau producerea codului
intermediar i alte chestiuni legate de analiza semantic (unele din acestea le vom
discuta n capitolul ce trateaz semantica). S ne referim n cteva cuvinte la natura
erorilor sintactice i la strategiile generale de tratare a acestora.
Dac un compilator ar trebui s trateze doar programele corecte, atunci
proiectarea i implementarea sa s-ar simplifica considerabil. Cum ns programatorii
scriu adesea programe incorecte, un compilator bun trebuie s asiste programatorul
n identificarea i localizarea erorilor. Cea mai mare parte a specificrilor limbajelor
de programare nu descriu modul n care implementarea (compilatorul) trebuie s
reacioneze la erori; acest lucru este lsat pe seama celor care concep
compilatoarele. Erorile ntr-un program pot fi:
lexicale: scrierea eronat a unui identificator, a unui cuvnt cheie, a unui
operator etc. ;
sintactice: omiterea unor paranteze ntr-o expresie aritmetic, scrierea
incorect a unei instruciuni, etc. ;
semantice: aplicarea unui operator aritmetic unor operanzi logici, nepotrivirea
tipului la atribuiri etc. ;
logice: un apel recursiv infinit.

37
1.7 Problema recunoaterii. Problema recunoaterii n gramatici
independente de context este urmtoarea: Dat o gramatic G = (V, T, S, P) i un
cuvnt w T*, care este rspunsul la ntrebarea w L(G)? Se tie c problema este
decidabil; mai mult, exist algoritmi care n timp O(|w| ) dau rspunsul la ntrebare
(Cooke-Younger-Kasami, Earley). Problema parsrii (analizei sintactice) este
problema recunoaterii la care se adaug: dac rspunsul la ntrebarea w e L(G) este
afirmativ, se cere arborele sintactic (o reprezentare a sa) pentru w.
Fie G = (V, T, S, P) o gramatic i w L(G). S notm prin
p q
()
st dr
relaia de
derivare extrem stng (dreapt) n care, pentru rescriere s-a aplicat producia p e P
(q P).
Atunci, pentru w L(G) exist o derivare extrem stng:
p1 p2 pn
S 0 1 ... n n w
st st st

i o derivare extrem dreapt:


q1 q2 qm
S 0 1 ... m m w
dr dr dr

Atunci, arborele sintactic corespunztor se poate reprezenta prin secvena de


producii p1p2pn P+ (respectiv q1q2qm P+ ) care s-au aplicat, n aceast
ordine, n derivarea extrem stng (dreapt) pentru obinerea lui w.


Definiia 1.2.1 Secvena de producii = p1p2pn P+ pentru care S
st
w se
numete analizare stng (parsare stng) pentru cuvntul w L(G).


Secvena de producii = q1q2qn P+ pentru care S
dr
w se numete
analizare dreapta (parsare dreapta) pentru cuvntul w.
Exemplul 1.2.4 Fie gramatica
1. E E+T 2. E T 3. TT*F
4. TF 5. F (E) 6. Fid
Unde: 1, 2,,6 identific cele 6 producii ale acesteia.
Pentru cuvntul w = id+id*id, arborele sintactic este dat n figura 1.1.

Figura 1.1
Analizarea stng pentru acest cuvnt este: 1=12463466 iar analizarea
dreapt este 2=64264631. Aici am identificat fiecare producie prin numrul su.

1.8 Analiza sintactic descendent

36
Analiza sintactic descendent (parsarea descendent) poate fi considerat ca o
tentativ de determinare a unei derivri extrem stngi pentru un cuvnt de intrare.
In termenii arborilor sintactici, acest lucru nseamn tentativa de construire a unui
arbore sintactic pentru cuvntul de intrare, pornind de la rdcin i construind
nodurile n manier descendent, n preordine (construirea rdacinii, a subarborelui
stng apoi a celui drept). Pentru realizarea acestui fapt avem nevoie de urmtoarea
structur (figura 1.2):
o band de intrare n care se introduce cuvntul de analizat, care se parcurge
de la stnga la dreapta, simbol cu simbol;
o memorie de tip stiv (pushdown) n care se obin formele propoziionale
stngi (ncepnd cu S). Prefixul formei propoziionale format din terminali se
compar cu simbolurile curente din banda de intrare obinndu-se astfel
criteriul de naintare n aceast band;
o band de ieire n care se nregistreaz pe rnd produciile care s-au aplicat
n derivarea extrem stng care se construiete.

Figura 1.2
Criteriul de oprire cu succes este acela n care s-a parcurs ntreaga band de
intrare, iar memoria pushdown s-a golit. n acest caz n banda de ieire s-a obinut
parsarea stng a cuvntului respectiv. Iat un exemplu de cum funcioneaz acest
mecanism (considerm gramatica din exemplul precedent i cuvntul w = id+id*id).
Vom considera caracterul # pentru marcarea sfritului benzii de intrare (marca de
sfrit a cuvntului) precum i pentru a marca baza stivei.
Tabelul 1: Analiza sintactic descendent pentru w = id+id*id
Pasul Banda de Stiva de Banda de
intrare lucru ieire
1 id+id*id# E#
2 id+id*id# E+T# 1
3 id+id*id# T+T# 12
4 id+id*id# F+T# 124
5 id+id*id# id+T# 1246
6 id*id# T# 1246
7 id*id# T*F# 12463
8 id*id# F*F# 124634
9 id*id# id*F# 1246346

37
10 id# F# 1246346
11 id# id# 12463466
12 # # 12463466

Se obine la ieire = 12463466.

1.8.1 Parser descendent general. Fie G = (V, T, S, P) o gramatic care


descrie sintaxa unui limbaj de programare. S considerm mulimea C = T*# x *# x
P* numit mulimea configuraiilor (unui parser). Interpretarea pe care o dm unei
configuraii este urmtoarea: dac c = (u#, y#, ), atunci u# este cuvntul rmas de
analizat (coninutul benzii de intrare la un moment dat), Y# este coninutul stivei, cu
primul simbol din y n top-ul stivei (y= X1,X2,...,Xn ca n figura 1.2), iar # la baza
acesteia, iar n este coninutul benzii de ieire: dac = p1,p2,,pk, pn n acest
moment s-au aplicat produciile din n n aceast ordine.
Definiia 1.3.1 Parserul (analizorul sintactic) descendent ataat gramaticii G =
(V, T, S, P) este perechea (Co, ) unde Co = {(w#, S#, s) | w T* } C} este
mulimea configuraiilor iniiale, iar C x C este relaia de tranziie ntre
configuraii dat de urmtoarea schem:
1. (u#, Ay#, ) (u#, Py#, r), unde r = A P P.
2. (uv#, uy#, ) (v#, Y#, ).
3. ( #, #, ) este configuraie de acceptare dac s.
4. O configuraie c pentru care nu exist c' astfel ca c c' (n sensul 1, 2)
spunem c produce eroare.
S considerm relaia + ( ) nchiderea tranzitiv (i reflexiv) a relaiei d
definit mai sus. Este clar c, dac vom considera parserul ca un sistem de
rescriere, acesta este nedeterminist aa cum este definit tranziia de tip 1: dac n
P exist produciile A 1 i A 2 cu 12, atunci au loc, n acelai timp: (u#,
Ay#, ) d (u#, P1Y#, ), (u#, Ay#, r1) d (u#, P2Y#, r2) unde r1 = A 1, r2 = A
2. Pentru a fi corect, parserul definit mai sus va trebui s transforme (n mod
nedeterminist, n general) configuraia (w#, S#, s) n configuraia (#, #, ) pentru
cuvintele w e L(G) i numai pentru acestea! Vom demonstra n continuare
corectitudinea n acest sens.
Lema 1.3.1 Dac n parserul descendent ataat gramaticii G = (V, T, S, P) are loc

calculul (uv#, Y#, ) * (v#, #, ), atunci n gramatica G are loc derivarea
st
u ,
oricare ar fi u, v T*, y, *, P*.
Demonstraie. S demonstrm afirmaia din lem prin inducie asupra lungimii
lui (notat ||):
Dac | | = 0 nseamn c n calculul considerat s-au folosit doar tranziii de
tip

2. Atunci Y = u i are loc
st
u cu = ;
Dac | | > 0 fie = 1r, unde r=A>P este ultima producie care se
folosete n calculul considerat i presupunem afirmaia adevrat pentru calcule ce
produc la ieire n1. Aadar, putem scrie:
(uv#,Y#,)=(u1u2v#,Y#,)*(u2v#,AY1#,1)(u2v#,Y1#,1r)=
(u2v#,u2#,1r)*(v#,#, 1r)
Atunci din (u1u2v#,Y#,)*(u2v#,AY1#,1), conform ipotezei inductive, are loc
u1Ay1. Cum n u1Ay1, u1 T*, iar A V este cea mai din stnga variabil,

st

aplicnd acesteia producia A > , obinem:

36

u1 A 1 u1 1 u1u 2 u Y == u1Ay1 i demonstraia este ncheiat.
st st

Corolarul 1.3.1 Dac n parserul descendent are loc (w#, S#, )+(#,#, ) atunci

n gramatica G are loc S w
st
Demonstraie Se aplic lema precedent pentru u = w, v = , Y = S, = .

Lema 1.3.2 Dac n gramatica G are loc derivarea u i 1: V, (vezi
st
definiia 1.3.2), atunci n parserul descendent are loc calculul:
(uv#, Y#, )*(v#,#,), v T*.
Teorema 1.3.1 (Corectitudinea panerului descendent general). Se consider
gramatica redus G = (V, T, S, P) i w G T*. Atunci, n parserul descendent general
ataat acestei gramatici are loc (w#, S#, s) d* (#, #, n) (acceptare) dac i numai
dac w e L(G) i n este o analizare sintactic stng a frazei w.
Demonstraie Teorema sintetizeaz rezultatele din lemele 1.3.1 i 1.3.2.
1.8.2 Gramatici LL(k). Parserul general introdus n paragraful precedent este
un model nedeterminist iar implementarea sa pentru gramatici oarecare este
ineficient. Cea mai cunoscut clas de gramatici pentru care acest model
funcioneaz determinist este aceea a gramaticilor LL(k): Parsing from Left to right
using Leftmost derivation and k symbols lookahead. Intuitiv, o gramatic este LL(k)
dac tranziia de tip 1 din Definiia 1.3.1 se face cu o unic regul A P
determinat prin inspectarea a k simboluri care urmeaz a fi analizate n banda de
intrare. Dar s definim n mod riguros aceast clas de gramatici.
Defininiia 1.3.2 Fie G = (V, T, S, P) o gramatic, a 2* i k > 1 un numr
natural. Atunci definim:
k:a = if | a | < k then a else a1, unde a = a1P, | a1| = k,
a:k = if | a | < k then a else a2, unde a = ya2, | a2| = k.
Defininiia 1.3.3 O gramatic independent de context redus este gramatic
LL(k), k > 1, dac pentru orice dou derivri de forma:
* *
S uA u 1 ux
st st st
* *
S uA u 2 uy
st st st

unde u, x, y T*, pentru care k: x = k: y, are loc 1 = 2:


Definiia prezentat exprim faptul c, dac n procesul analizei cuvntului
w=ux a fost obinut(analizat) deja prefixul u i trebuie s aplicm o producie
neterminalului A (avnd de ales pentru acesta mcar din dou variante), aceast
producie este determinat n mod unic de urmtoarele k simboluri din cuvntul care
a rmas de analizat (cuvntul x).

1.8.3 O caracterizare a gramaticilor LL(1). Pentru ca un parser SLL(k) s


poat fi implementat, trebuie s indicm o procedur pentru calculul mulimilor
FIRSTk i FOLLOWk. Pentru c n practic se folosete destul de rar (dac nu chiar
deloc) cazul k > 2, vom restrnge discuia pentru cazul k = 1. Vom nota n acest caz
FIRST1 i FOLLOW1 prin FIRST respectiv FOLLOW. Aadar, dac a +, A V :

Mai nti s artm c gramaticile SLL(1) coincid cu gramaticile LL(1).

37
Teorema 1.3.10 O gramatic G = (V, T, S, P) este gramatic LL(1) dac i numai
dac
pentru orice A V i pentru orice producii A P1 | P2 are loc:
FIRST (P1FOLLOW (A)) 3 FIRST (P2FOLLOW (A)) = 0 Demonstraie S
presupunem c G este LL(1). Acest lucru este echivalent cu(dup Definiia 1.3.3):

S presupunem c G nu este SLL(1): exist produciile A a1, A a2 i a


FIRST (a1FOLLOW (A)) 3 FIRST (a2FOLLOW (A)) Distingem urmtoarele cazuri:

a FIRST (a1) 3 FIRST (a2), adic


Atunci, putem scrie derivrile ( G este redus):

ceea ce contrazice faptul c G este LL(1).


Atunci: , i putem scrie:

ceea ce contrazice de asemenea ipoteza.

, caz ce se trateaz analog cu


precedentul.

.
n acest caz avem:

Deci din nou se contrazice proprietatea LL(1) pentru gramatica G.


Invers, s presupunem c pentru orice dou producii A P13 A P2 distincte are
loc FIRST (P1FOLLOW (A)) 3 FIRST (P2FOLLOW (A)) = 0 i, prin reducere la absurd,
G nu este LL(1). Asta nseamn c exist dou derivri:

36
cu 1:v = 1:v' dar 1 2.
Analiznd cele dou derivri, se constat uor c:

ceea ce contrazice ipoteza.

1.8.4 Tabela de analiz sintactic LL(1). Pentru a implementa un analizor


sintactic pentru gramatici LL(1), s considerm o tabel de analiz, sau tabel de
parsare LL(1):
M : V x (T U{ # }) {(P, p) |p = A P P }U {eroare} construit dup
algoritmul urmtor:
Algoritmul 1.3.6 (Tabela de analiz sintactic) Intrare:Gramatica G = (V, T, S, P);
Mulimile FIRST(P), FOLLOW(A), A P P.
Ieire:Tabela de parsare M.
Metoda: Se parcurg regulile gramaticii i se pun n tabel for(A V )
for(aTU{#})M(A,a)=0; for(p =APP){
for(aFIRST(P)-{s})
M(A, a) = M(A, a) U {( P, p)} ;
if(s FIRST(B)){ for(b FOLLOW(A)){
if(b == s)M(A, #) = M(A, #) U {( P, p)};
10. else M(A, b) = M(A, b) U {( P, p)};
}//endfor
}//endif
}//endfor
11. for(A V)
12. for( a T U { # })
13. if(M(A,a)=0) M(A,a)={eroare};
Lema 1.3.6 (caracterizarea gramaticilor LL(1)) Gramatica redus G este LL(1)
dac i numai dac pentru orice A V i orice a T U { # } M(A, a), dac nu este
eroare, conine cel mult o pereche (P, p).
Demonstraie Dac G este LL(1), atunci VA V, oricare ar fi dou producii cu
partea stng A, AP1, AP2, are loc, conform teoremei 1.3.10,
FIRST(P1FOLLOW(A)) 3 FIRST(P2FOLLOW(A))= O. Dac ar exista n tabela
construit A V i a V U { # } astfel nct M(A, a) 3 {(P, p), (P', q)}, atunci, dac a
T rezult
a FIRST(PFOLLOW(A)) 3 FIRST(P'FOLLOW(A))
ceea ce contrazice ipoteza. Dac a = #, atunci s ar fi comun n
FIRST(PFOLLOW(A)) i FIRST(P'FOLLOW(A)), din nou absurd. Deci M ndeplinete
condiia enunat. In mod analog se dovedete implicaia invers.

1.3.5 Analizorul sintactic LL(1). Parserul (analizorul sintactic) LL(1) este un


parser top-down n care tranziiile sunt dictate de tabela de parsare. Aadar, un astfel
de parser are ca i configuraie iniial tripleta (w#, S#, s) unde w este cuvntul de
analizat, iar tranziiile se descriu astfel:
1. (u#, Ay#, n) d (u#, Py#, nr) dac M(A, 1:u#) = (P, r). (operaia expandare)
2. (uv#, uy#, n) d (v#, y#, n). (operaia potrivire)
3. (#, #, n) d acceptare dac n g s.
4. (au#, by#, n) d eroare dac a g b.
5. (u#, Ay#, n) d eroare dac M(A, 1:u#) = eroare.
Teorema de corectitudine a parserului descendent general mpreun cu teorema
de caracterizare LL(1), a modului n care s-a definit tabela M, dovedesc
corectitudinea parserului LL(1). Suntem acum n msur s indicm modul de

37
implementare al unui analizor sintactic LL(1). Presupunem c dispunem de o band
de intrare (fiier de intrare) din care, cu o funcie getnext(), se obine caracterul
(tokenul) urmtor. De asemenea dispunem de o stiv cu funciiile specifice pop() i
push() . Produciile care se aplic pe parcursul analizei le scriem ntr-o band
(fiier) de ieire cu funcia write(). Atunci algoritmul de analiz sintactic se descrie
astfel: Algoritmul 1.3.6 (Parser LL(1) )
Gramatica G = (V, T, S, P). Tabela de analiz LL(1) notat M. Cuvntul de intrare
w#.
Analiza sintactic stng n a lui w dac w L(G), eroare n caz contrar.
Sunt implementate tranziiile 1 5 folosind o stiv St.
St.push(#),St.push(S)// St = S# a = getnext(), n = s;
do {
X = St.pop();
if(X == a)
if(X != '#') getnext(); else{
if (n != s){write("acceptare"); exit(0);} else {write("eroare");
exit(1);} } //endelse else{
if(XT){write("eroare"); exit(1);} else{
if(M(X,a)
{write( else {
// M(X,a) = (P,r), r=X P, P=Y1Y2...Yn //P inlocueste pe X in stiva
for(k = n; k>0; --k) push(Yk)
write(r); //se adauga r la n
} //endelse
} //endelse } //endelse
} while(1);
Exemplul 1.3.4 S relum gramatica din exemplele precedente:
1. S E
2. S B
3. E s
4. B a
5. B begin SC end
6. C s
7. C ;SC
Mulimile FIRST i FOLLOW sunt date n tabelul urmtor:
X FIRST(X) FOLLOW(X)
S a begin s end ; s
E s end ; s
B a begin end ; s
C ; s end

Tabela de analiz LL(1) pentru aceast gramatic este dat mai jos:
M a begin end ;
S
E eroar eroare (s, 3) (s, 3) (s, 3)
e
B (begin SC eroar eroare eroar
end, 5) e e
C eroar eroare (;SC, eroar
e 7) e

36
Se vede din tabel c aceast gramatic este LL(1) (conform teoremei 1.3.13).
Iat i dou exemple de analiz, unul pentru cuvntul begin a;;a end care este din
limbajul generat de gramatica dat, iar altul pentru begin aa end care nu este
corect.
PAS INTRARE STIVA OPERAIE IEIRE
1 begin a S# expandare
a; end#
2 begin a B# expandare 2
a; end#
3 begin a begin SC potrivire 5
a; end# end#
4 a; a SC end# expandare
end#
5 a; a BC end# expandare 2
end#
6 a; a aC end# potrivire 4
end#
7 a C end# expandare
end#
8 a ;SC end# potrivire 7
end#
9 a SC end# expandare
end#
10 a EC end# expandare 1
end#
11 a C end# expandare 3
end#
12 a ;SC end# potrivire 7
end#
13 a end# SC end# expandare
14 a end# BC end# expandare 2
15 a end# aC end# potrivire 4
16 end# C end# expandare
17 end# end# potrivire 6
18 # # acceptare
1 begin aa end# S# expandare
2 begin aa end# B# expandare 2
3 begin aa end# begin SC potrivire 5
end#
4 aa end# SC end# expandare
5 aa end# BC end# expandare 2
6 aa end# aC end# potrivire 4
7 a end# C end# eroare

1.8.7 Eliminarea recursiei stngi. O gramatic stng recursiv nu este


LL(k) pentru nici un numr k. Este cazul, spre exemplu, al gramaticii care genereaz
expresiile aritmetice:
E E+T |E - T|-T |T T T*F |T/ F| F
F (E) | a
Prin eliminarea recursiei stngi, exist posibilitatea obinerii unei gramatici din
clasa LL. Acesta este un procedeu utilizat frecvent n proiectarea analizoarelor
sintactice. S reamintim c o gramatic G este stng recursiv dac exist un

37
neterminal A pentru care A = Aa. Spunem c un neterminal A este stng recursiv
imediat dac exist o producie A Aa n P. S indicm mai nti un procedeu de
eliminare a recursiei stngi imediate.
Lema 1.3.7 Fie G = (V, T, S, P) o gramatic pentru care A este stng recursiv
imediat. S considerm toate A produciile gramaticii, fie ele A Aa1 | Aa2 | ... |
Aan cele cu recursie i A P1 | P2 | ... | Pm cele fr recursie imediat (prile
drepte nu ncep cu A). Exist o gramatic G' = (V', T, S, P') echivalent cu G, n care
A nu este stng recursiv imediat.
Demonstraie S considerm un nou neterminal A' 2 V i fie V' = V U{A} iar P'
se obine din P astfel:
Se elimin din P toate A -produciile;
Se adaug la P urmtoarele producii:
A PiA' 1 < i < m. A' ajA' | s 1 < j < n.
Notm cu P' mulimea de producii obinut.
S observm c A nu mai este stng recursiv n G'. Noul simbol neterminal
introdus, notat cu A', este de data aceasta drept recursiv. Acest lucru ns nu este un
inconvenient pentru analiza sintactic descendent.
S observm c, pentru orice derivare extrem stnga n gramatica G, de forma:
exist n gramatica G' o derivare extrem dreapta de forma:
A = PhA' = Phak1 A' = ... = fta^. -a^ A' = fta^.. .a^.
De asemenea, afirmaia reciproc este valabil.
Aceste observaii conduc la concluzia c cele dou gramatici sunt echivalente.
Exemplul 1.3.5 n gramatica expresiilor aritmetice:
E E+T |E-T |-T |T
T T*F | T/F | F
F (E) | a se fac transformrile urmtoare:
Produciile E E+T |E-T |-T |T se nlocuiesc cu:
E TE' | -TE', E' +T E'|-TE' | s
Produciile T T*F | T/ F | F se nlocuiesc cu:
T FT', T' *FT' | /FT' | s
Se obine astfel gramatica echivalent:
E TE' | -TE'
E' +T E'|-TE' | s
T FT'
T' *FT' | /FT' | s
F (E) | a
Aplicnd algoritmii pentru determinarea mulimilor FIRST i FOLLOW se obine:
X FIRST(X) FOLLOW(X)
E (a- s)
E' + -s s)
T (a +-s)
T' * /s + - s)
F (a */+-s)
Tabela de parsare pentru aceast gramatic este dat mai jos.
M a + - * / ( ) #
E (TE', eroare (-TE', eroare eroare (TE', 1) eroare eroare
1) 2)
E' eroare (+TE',3) (-TE', eroare eroare eroare (s, 5) (s, 5)
4)
T (FT', eroare eroare eroare eroare (FT', 6) eroare eroare
6)
T' eroare (s, 9) (s, 9) (*FT',7) (/FT',8 eroare (s, 9) (s, 9)

36
)
F eroare eroare eroare eroare ((E) 10) eroare eroare
Se observ de aici c gramatica este LL(1). S urmrim analiza sintactic pentru
expresia -(a+a)*a.
PASU INTRARE STIVA OPERAI IEIRE
L E
1. - E# expandar
(a+a)*a# e
2. - -TE'# potrivire 4
(a+a)*a#
3. (a+a)*a# TE'# expandar
e
4. (a+a)*a# FT'E'# expandar 6
e
5. (a+a)*a# (E)T'E'# potrivire 10
6. a+a)*a# E)T'E'# expandar
e
7. a+a)*a# TE')T'E'# expandar 1
e
8. a+a)*a# FT'E')T'E expandar 6
'# e
9. a+a)*a# aT'E')T'E potrivire 11
'#
10. +a)*a# T'E')T'E' expandar
# e
11. +a)*a# E')T'E'# expandar 9
e
12. +a)*a# +TE')T'E' potrivire 3
#
13. a)*a# TE')T'E'# expandar
e
14. a)*a# FT'E')T'E expandar 6
'# e
15. a)*a# aT'E')T'E potrivire 11
'#
16. )*a# T'E')T'E' expandar
# e
17. )*a# E')T'E'# expandar 9
e
18. )*a# )T'E'# potrivire 5
19. *a# T'E'# expandar
e
20. *a# *FT'E'# potrivire 7
21. a# FT'E'# expandar
e
22. a# aT'E'# potrivire 11
23. # T'E'# expandar
e
24. # E'# expandar 9
e
25. # # acceptare 5

37
S artm cum eliminm n general recursia stng ntr-o gramatic. Vom face
ipoteza c + gramatica G nu are s - producii i nu are cicluri de forma A == A.
Aceasta nu este de fapt o restricie: este tiut faptul c, pentru orice gramatic G
exist G' fr s -producii i fr cicluri astfel nct L(G') = L(G) - { s }. (vezi [Gri86],
[Juc99]). Aadar are loc urmtoarea teorem:
Teorema 1.3.13 Pentru orice gramatic G fr s - producii i fr cicluri, exist
o gramatic echivalent G' care nu este stng recursiv.
Demonstraie S considerm urmtorul algoritm:
Intrare: Gramatica G = (V, T, S, P) fr s-producii, fr cicluri.
Ieire:Gramatica G' fr recursie stng astfel ca L(G)=L(G').
Metoda: Dup ordonarea neterminalilor se fac transformri ce nu schimb
limbajul gramaticii, inclusiv prin eliminarea recursiei imediate
Se consider V = [Ai, A2, -,An|
for (i=1; i < n;)
for (j=1; j < i 1;){
for (Ai AjY e P) {
P = P - { Ai AjY };
for (Aj p e P ) P = P U { Ai Py};
} //endfor
8. Se elimina recursia imediata pentru Ai;
//endfor
} //endfor
8. V'= V; P'=P; // V s-a modificat la 7 iar P la 4-6

S observm c transformrile din 4 - 7 nu modific limbajul generat de


gramatic nct L(G')=L(G). S artm acum c G' nu are recursie stng. Acest
lucru rezult din faptul c, dup iteraia i - 1 a buclei 2, fiecare producie de forma
Ak Ala pentru k < i are proprietatea c l > k. Aceasta datorit transformrilor 4 - 6
i eliminrii recursiei stngi imediate n linia 7: dup execuia buclei 3 se obin
producii A Ama cu m > i, iar dac m = i, producia Ai Aia se elimin n linia 7.
Aadar, gramatica obinut este fr recursie stng.

1.8.6 Funcii de numrare i formula multinomului. In cele ce urmeaz se va lucra cu mulimi finite.
Numrul de elemente din mulimea finit X va fi notat cu |X|. Unei funcii / de la X in Y, unde X si Y sunt mulimi
finite, astfel nct X = [ x \ , . . . , x n } si Y = [ y i , . . . , y m } , i se pune in corespondenta o aranjare a mulimii X de
obiecte in mulimea Y de csue, astfel nct in csua s intre obiectele din mulimea [x|x E X , / (x) = y }. Aceasta
corespondent este o bijecie. De asemenea, se poate stabili o bijecie intre mulimea funciilor / : X Y si mulimea
n-uplelor formate cu elemente din Y sau a cuvintelor de lungime n formate cu litere din mulimea Y astfel: unei
funcii / i se pune in corespondenta cuvntul / ( x i ) / ( x 2 ) . . . /(xn) in care ordinea literelor este esenial.
PROPOZIIA 1. Numrul funciilor / : X Y este egal cu mn, daca |X| = n si |Y| = m.
Prin definiie se noteaz [x]n = x(x 1). . . (x n + 1) si [x]n = x(x + 1). . . (x + n 1), ambele produse
coninnd cte n factori consecutivi.
PROPOZIIA 2. Numrul funciilor injective / : X Y, unde |X| = n si | Y| = m este egal cu [m ]n.
Aranjamente de m luate cate n se numesc cuvintele de lungime n formate cu litere diferite din mulimea Y, iar
numrul lor este [m]n. Dac m = n, aceste cuvinte de lungime n formate cu toate literele din Y se numesc permutri
ale mulimii Y si numrul lor este egal cu [n]n, care se noteaz cu n! = 1 2 n si se numete n factorial. Prin
definiie 0! = 1.

Daca mulimea Y este o mulime ordonat astfel nct y1 < y2 < . . . < yn, un cuvnt de lungime n format cu litere
din Y, yil . . . yin se numete cresctor dac yil < yi2 < . . . < yin si strict cresctor daca yil < yi2 . . . < yin. Cuvintele strict
cresctoare de lungime n formate cu m simboluri se mai numesc combinri de m luate cte n, iar cele cresctoare se
numesc combinri cu repetiie de m luate cte n.

36
PROPOZIIA 3. Numrul cuvintelor strict cresctoare de lungime n formate cu m simboluri este egal cu
[m]n/n!. Acest numr este egal si cu numrul submulimilor cu n elemente ale unei mulimi cu m elemente. Numerele
[m]n se mai noteaz prin si se numesc numere binomiale cu parametrii m si n.
PROPOZIIA 4. Numrul cuvintelor cresctoare de lungime n formate cu m simboluri este egal cu [m] n/n!.
Demonstraie. S observam mai nti ca [m] n/n! = (m+n_^. Putem presupune ca Y = {1,. . . ,m} si vom stabili o
bijecie de la mulimea cuvintelor cresctoare de lungime n formate cu litere din Y (cu ordinea naturala) pe mulimea
cuvintelor strict cresctoare de lungime n formate cu litere din alfabetul extins {1,. . . , m + n 1} in felul urmtor:
^(yil yj2 . . . yin) = yil |yi2 + 1|. . . |yin + n 1. Se verific imediat ca ^ este o bijecie, de unde rezult propoziia,
deoarece numrul cuvintelor strict cresctoare de lungime n formate cu litere dintr-un alfabet cu m + n 1 simboluri
este egal cu

Numerele binomiale apar drept coeficieni in formula binomului:

, (1)

care este valabil pentru orice a , b dintr-un inel comutativ. Demonstraia formulei (1) se poate face innd
seama ca (a + b)n = (a + b)(a + b ) . . . (a + b), unde in produs sunt n factori. Pentru a obine monomul an-kbk trebuie sa l
alegem pe b din k paranteze si pe a din parantezele ramase, in numr de n k. Dnd cate un numr de ordine celor n
paranteze, trebuie sa selectam k numere de ordine ale parantezelor din care l alegem pe b din mulimea de numere
{1,. . . , n}, ceea ce se poate face in (jkj moduri, deci coeficientul
monomului an-kbk este egal cu nk .
PROPOZIIA 5. Numrul de aranjri ale unei mulimi de n obiecte X = . . . ,xn} intr-o mulime de p csue Y =
{y1,... ,yp}, astfel nct csua yj s conin n obiecte pentru orice 1 < i < p (n1 + . . . + np = n) este egal cu

Demonstraie. Obiectele din csua y1 pot fi alese in(n/n1) moduri, obiectele din csua y2 pot fi alese din cele
n n1 obiecte rmase in (n-n1/n2) moduri etc. Rezulta in total un numr de posibiliti egal cu

Acest raport de factoriale se mai noteaz si se numete numr multinomial, care generalizeaz
numerele binomiale (cazul p = 2) si apar in formula multinomului care extinde relaia (1):

(2)

Demonstrata formulei (2) a multinomului se poate face astfel: Este clar c dezvoltarea ( a \ + . . . + ap)n va
conine o suma de monoame de forma an , unde numerele naturale n \ , . . . n p verific ni+ . . .+np = n. Trebuie gsit
coeficientul acestui monom, deci de cate ori apare el in puterea a na a expresiei a1 + . . . + ap. Pentru aceasta se
procedeaz ca la formula binomului, dndu-se numerele de ordine 1 , . . . , n parantezelor din dezvoltarea (a1 + . . . +
ap)n = (a1 + . . . + a p ) . . . (a1 + . . . + ap) si observnd c pentru a obine monomul a*,11 trebuie s-l alegem pe a1
din n1 paranteze,... ,pe ap din np paranteze. Ori aceasta este echivalent cu plasarea numerelor de ordine 1 , . . . , n ale
parantezelor in p cutii, astfel nct cutia 1 sa conin n 1 numere,...,cutia p sa conin np numere, ceea ce se poate realiza
in (ni n n ) moduri, conform propoziiei 5.
PRINCIPIUL INCLUDERII I AL EXCLUDERII I APLICAII Principiul includerii si al excluderii constituie
o generalizare a identitii:
(3)
unde A, B C X.
TEOREMA 1 (Principiul includerii si al excluderii). Dac Aj (1 < i < q) sunt submulimi ale unei mulimi X,
are loc relaia:

37
(4)

r
Demonstra e. Vom face demonstraia prin inducie dup q. Pentru q = 2 se obine relaia (3). Fie q > 3, sa
presupunem formula (4) adevrata pentru q 1 mulimi si s o demonstrm pentru q mulimi. Avem:
. Aplicnd

distributivitatea se obine , deci aplicnd ipoteza de inducie se deduce


=

de unde, regrupnd termenii se obine (4). Aplicaii


1) Determinarea funciei lui Euler </?(n).
Fiind dat un numr natural n, <^(n) reprezint numrul numerelor naturale mai mici ca n si relativ prime cu n.
Dac descompunerea lui n in factori primi distinci este n = p l1 p22 p^9 si se noteaz cu Ai mulimea numerelor
naturale mai mici sau egale cu n care sunt multipli de p i, se obine |Ai| = n/pi, |Ai n A j | = n/(pipj-) etc. Deci

(5)

2) Determinarea numrului D(n) al permutrilor a n elemente fr puncte fixe.


Fie p o permutare a mulimii X = {1,. . . , n}, adic o bijecie p : X X. Permutarea p are un punct fix in i dac
p(i) = i. Daca notam cu Ai mulimea permutrilor care au un punct fix in i, rezulta ca D(n) = n! |A1 U . . . U An| =
n! E n=1 |Aj| + E 1<i<j<n |Aj n Aj | + . . . + ( 1)n| fl n=1 Aj|. Se obine | Ail n Ai2 n . . . Aik | = (n k)!, deoarece o
permutare din mulimea Ail n . . . Aik are puncte fixe in poziiile . . . , ik, celelalte imagini putnd fi alese in (n k)!
moduri. Deoarece k poziii i 1 , . . . , ik pot fi alese din mulimea celor n poziii in moduri, rezulta:
sau

. (6)

3) Determinarea numrului xn>TO al funciilor surjective.


Fie mulimile X = . . . , xn} si Y = { y 1 , . . . , ym}. Pentru fiecare i, 1 < i < m, s notm prin Ai mulimea
funciilor de la X in Y pentru care yi nu este imaginea nici unui element din X, adic Ai = { / : X Y| y i < / / (X)} . Se
obine xn,m = mn |A1 U . . . U Am| = mn 1 |Aj| + 1<l<j<m |Aj n A j | . . . + ( 1)m | fi"= 1 Ai | . Ai este
mulimea funciilor definite pe X cu valori in Y\{yi}, deci |Ai| = (m 1)n si in general |Ail n . . . n Ai;| = (m 1)n.
Deoarece fiecare sum 1 <l<...<l<m |Ail n . . . n Ai; | conine ("") termeni egali cu (m 1)n, deducem:

(7)

Daca m = n se obine snn = n!, iar daca m > n nu exist surjectii de la X pe Y, deci xn>m = 0 (identitile lui
Euler).

NUMERELE LUI STIRLING, BELL, FIBONACCI I CATALAN Alturi de numerele binomiale si


multinomiale, numerele lui Stirling, Bell si Fibonacci joac un rol deosebit in probleme de numrare.
Pentru a defini numerele lui Stirling de prima spea, pe care le notam s(n, k), vom dezvolta polinomul [x] n in
ordinea cresctoare a puterilor lui x. Coeficienii acestei dezvoltri sunt prin definiie numerele lui Stirling de prima
spet, adic

(8)

Numerele s(n, k) se pot calcula prin recurenta, utiliznd relaiile s(n, 0) = 0, s(n, n) = 1 si s(n + 1, k) = s(n, k
1) ns(n, k), ultima relaie obinndu-se prin egalarea coeficienilor lui xk in cei doi membri ai egalitii [x]n+1 =
[x]n(x n). Se obine tabelul urmtor, unde s(n, k) = 0 pentru n < k.
s(n, k) k=0 1 2 3 4 5 ...
n=1 0 1 0 0 0 0

36
2 0 -1 1 0 0 0
3 0 2 -3 1 0 0
4 0 -6 11 -6 1 0
5 0 24 -50 35 -10 1
Numrul lui Stirling de spea a doua, notat S ( n , m), este numrul partiiilor unei mulimi cu n elemente in
m clase. S observm c att ordinea claselor, cat si ordinea elementelor intr-o clas a unei partiii sunt indiferente. De
exemplu, dac avem X = [ a , b , c , d}, partiiile cu trei clase ale acestei mulimi sunt: {(a), (b), (c, d)}, {(a), (c), (b,
d)}, {(a), (d), (b,c)}, {(b), (c), (a, d)}, {(b), (d), (a, c)}, {(c), (d), (a, b)}, deci S(4, 3) = 6.
Numerele lui Stirling de spea a doua pot fi calculate prin recurent astfel: Considernd mulimea celor S(n, k
1) partiii ale unei mulimi cu n elemente in k 1 clase, putem obine S(n, k 1) partiii a n + 1 elemente in k clase,
adugnd la fiecare partiie o noua clasa formata dintr-un singur element si anume al ( n + 1)-lea. S considerm acum
o partiie a n elemente in k clase. Deoarece putem aduga al (n + 1)-lea element la clasele deja existente in k moduri
diferite si toate partiiile a n + 1 elemente cu k clase se obin fr repetiii printr-unul din cele dou procedee expuse,
rezult c

pentru 1 < k < n si S(n, 1) = S(n, n) = 1. Aceste relaii permit calculul prin recurenta al numerelor S(n, m),
obinndu-se tabelul urmtor:
S(n, m) m =1 2 3 4 5 ...
n=1 1 0 0 0 0
2 1 1 0 0 0
3 1 3 1 0 0
4 1 7 6 1 0
5 1 15 25 10 1
Pentru calculul direct al numerelor lui Stirling de spea a doua, vom arta ca S(n,m) = xn>m/m!. Intr-
adevr, oricrei surjectii / a mulimii X = . . . , xn} pe mulimea Y = { y 1 , . . . , yn} ii corespunde o partiie a mulimii X
cu m clase si anume /-1(y1), /- 1 ( y 2 ) , . . . , /-1(ym). Deoarece intr-o partiie nu conteaz ordinea claselor, rezult c n!
funcii surjective de la X pe Y vor genera o aceeai partiie a mulimii X. innd seama de (7) rezult:

(9)

2. Analiza sintactic ascendent


2.1 Analiza sintactice "deplaseaz-reduce". Fie gramatica:

i cuvntul baacde din limbajul generat de gramatic. Vom ncerca s refacem drumul parcurs de un
analizor cu strategie ascendent care pleac de la irul baacde i gsete n final neterminalul S. Pe parcurs
vom evidenia problemele mai deosebite ale acestui tip de analiz.
Prototipul analizei sintactice ascendente este automatul "push-down" extins. Dup cum se tie, el poate
simula n funcionarea sa derivarea dreapt ntr-o gramatic independent de context, derivare parcurs ns
n ordine invers. Automatul "push-down" extins identific pentru acesta n vrful stivei pri drepte ale
produciilor pe care le "reduce" la neterminalul prii stngi corespunztoare. n vederea completrii prii
drepte, automatul i aduce pe rnd n stiv simbolurile de la intrare. irul este acceptat dac au rmas doar
simbolul de nceput.
n cazul exemplului considerat, un analizor sintactic ascendent va cuta pri dreapta ale produciilor n
irul de intrare. Le gsete sub forma: a i d. Desigur, analiznd n mod natural, de la stnga la dreapta, dup
depirea lui b, va prefera nlocuirea primului a cu A, rezultnd irul bAacde. n termenii arborilor de
derivare subirul analizat se prezint ca n figura .2.1.
Dup cum vom vedea n continuare, un analizor ascendent creeaz o "pdure" de arbori pe care
ncearc s-i reuneasc n final ntr-un unic arbore. n cazul nostru, el a creat un arbore format dintr-un nod
etichetat b i un arbore ca n figura 2.1.

37
Figura 2.1

Figura 2.2.

ncercnd n continuare s gseasc pri dreapta (de aceast dat n bAacde) analizorul va
gsi, n ordine : Aa, a i d. Ordinea de analiz de la stnga la dreapta a intrrii impune de data
aceasta dou posibiliti: Aa i a. Ambele se reduc la A, dar nu sunt totui la fel de bune. ntr-
adevr, reducerea lui a la A conduce la irul bAAcde care apoi prin reducerea lui d la B conduce
la bAAcBe n care analizorul nu mai poate recunoate nici o parte dreapt i analiza pe aceast
cale euat, fiind necesar revenirea la decizia reducerii lui a. Dac se alege reducerea lui Aa la A
se obine irul bAcde i corespunztor "pdurea" din figura 2.3
Concluzia este, desigur, acceptarea irului.
S observm c analiza a refcut n ordine invers derivarea dreapt:
Dup adugarea lui e i d la pdure, singurul ir de redus este d. Dup reducerea lui
obinem bAcBe i pdurea din figura 2.4.
n fine, adugnd i ultimul simbol la pdurea de arbori, se observ c noul ir, ca i
rdcinile arborilor pdurii, alctuiesc partea dreapt a primei producii, deci putem reduce la S,
adic ajungem la arborele de derivare din figura 2.5.

Figura 2.3

Figura 2.4

36
Figura 2.5

prin reduceri:
n aceste transformri, subirul redus joac un rol esenial. El trebuie mai nti identificat i
apoi nlocuit cu un neterminal. Acest subir este ntotdeauna cel mai din stnga subir dintr-o
form propoziional dreapt care poate fi redus astfel nct s se refac n sens invers un pas
ntr-o derivare dreapt. El poart numele de capt (n engl.: handle).
Definiia 2.5. Captul unei forme propoziionale dreapta este irul a dac n
gramatica respectiv exist derivarea:

n cazurile concrete captul este dat printr-o producie A a i poziia lui a n /3aa>
(adic limitele lui din stnga i din dreapta).
n arborele de derivare asociat unei forme propoziionale captul apare ca cel mai din
stnga subarbore complet (format deci dintr-un nod-rdcin i toi descendenii si).
Utiliznd noiunea de capt, analiza ascendent apare ca un proces de formare i
identificare a capetelor formelor propoziionale dreapta obinute i de reducere a lor la
neterminale.
Exemplul 2.5. Fie gramatica:

i irul de intrare id1,id2 (id3,id4) n care am evideniat diferenele apariiei ale


terminalului id.
Reducerea irului la neterminalul L are loc n urmtoarele etape:
Form propoziional dreapta Capt Producie folosit n reducere
id1, id 2 (id 3, id 4) id1 E id
E, id 2 (id 3, id 4) E L E E id
L, id2 (id3 , id4 ) id3 L-E
L, id 2 (E, id 4) L, id 2 (L, id 4) L, id 2 E id4 L, E E id L L, E E id(L) L L, E
(L, E) L, id2 (L) id2(L) L, E
L, E
L

Se observ c secvena reducerilor este invers secvenei derivrilor dreapta.


Din prezentarea de mai sus remarcm faptul c un analizor sintactic ascendent este
confruntat cu dou probleme : identificarea captului n forma propoziional dreapta i alegerea
produciei cu care s fac reducerea.

37
n ceea ce privete identificarea captului, se poate arta c ntr-o parcurgere de la stnga la
dreapta a irului de intrare nsoit de reduceri succesive ale captului fiecrui forme
propoziionale dreapta, la un moment dat, analizorul sintactic nu trebuie s se ntoarc oricnd n
pdurea de arbori deja format pentru a cuta captul, ci acesta apare n mod natural n
vecintatea imediat a punctului de analiz.
Mai precis, s considerm cele dou posibiliti de apariie a captului. Fie mai nti
derivarea:

n care s-au folosit produciile i . Se observ c irul s-a evideniat


neterminalul cel mai din dreapta.
Pornind n sens invers, de la irul de terminale, analizorul sintactic-ascendent a prelucrat parial
irul de intrare aducndu-l la forma : , i rmnndu-i de parcurs irul yu. Este momentul n care el
trebuie s depisteze captul y i s-l reduc la B, irul prelucrat devenind , iar cel neanalizat
rmnnd yu. Se vede c n irul , deci la stnga lui B, captul nu poate apare, B fiind cel mai din
dreapta neterminal. Singura posibilitate este ca noul capt s se completeze prin adunarea de terminale
din yu. Aceast operaie de adugare de ctre analizor din irul de intrare a noi terminale la poriunea deja
prelucrat a formei propoziionale se numete deplasare. Adugnd y obinem By n care moment se
identific un capt By, ce se reduce la A. (z poate fi chiar irul vid; atunci fr a se face vreo deplasare,
dup reducerea lui y la B se face reducerea lui B la A).
O alt posibilitate de derivare dreapt o constituie secvena:

n care s-au folosit produciile A y i B y.


Lucrnd n sens invers, analizorul construiete irul ay n care momentul gsete c y este
capt i l reduce la B. Din nou, captul nu are ce cuta n stnga lui B, deci se vor aduga de la
intrare noi simboluri pn la formarea irului aBxy n care momentul se delimiteaz captul y i
se reduce la A.
Din observarea celor dou cazuri posibile de localizare a captului, constatm c orice
capt este format din cele mai recente simboluri prelucrate, reduse sau deplasate.
Deci irul deja analizat alctuiete o list LIFO a crei implementare se poate face o
memorie stiv.
n afara stivei, algoritmul de analiz va avea acces la irul de intrare pentru a-i deplasa
terminale n stiv. De asemenea, va trebui s depun la ieire informaii privind analiza efectuat.
Algoritmul, pe baza informaiei de la intrare i a coninutului stivei, va decide asupra urmtoarei
aciuni ce poate fi: reducerea, deplasare, eroare, acceptare.
Un asemenea algoritm de analiz poart numele ,,deplaseaz-reduce"

Maina ,,deplaseaz-reduce" . Analizorul ,,deplaseaza-reduce" are, dup cum uor se


poate observa, ca model matematic, automatul "push-down" extins. Ca i analiza descendent
vom ncerca s definim un model fizic al analizei ascendente ce lucreaz prin deplasri i
reduceri : maina ,,deplaseaza-reduce", pe scurt MDR.
Din punct de vedere al structurii, MDR este similar mainii de analiz predictiv, MAP,
prezentat n 2.1.2. Operaiile primitive sunt aceleai cu cele ale MAP cu excepia operaiei de
comparaie a subirurilor din stiv, necesar n identificarea capetelor din vrful stivei. n
termenii acestor operaii, efectele aciunilor MDR sunt urmtoarele:
1)reducere cu (, A, i):
- se terg din vrful stivei || simboluri,
- se depune n vrful stivei simbolul A T ,
- se depune pe banda de ieire numrul i.
2)Deplasare:
- se depune simbolul curent de la intrare n vrful stivei,
- se avanseaz banda de intrare.
3)Eroare:

36
- se semnalizeaz eroarea prin modificarea strii procesorului.
4) Acceptare (are loc la ntlnirea marcajului $ pe banda de intrare i a irului $Z0 n stiv,
Z0 T):
- se semnalizeaz acceptarea prin modificarea strii procesorului.
Starea mainii este sintetizat ctre configuraia sa ($aX,x$, ), unde $aXeste coninutul
stivei cu vrful X reprezentat spre dreapta, x$ este irul de intrare cu marcajul de sfrit al irului
$ i n este irul numerelor de producii cu care s-au fcut reducerile.
Configuraia iniial este ($,x$, ),unde x este irul de analizat, iar configuraiile finale sunt
de forma ($Z0,$, i).
Reducerea cu (,A,i) determin o micare a mainii de forma :

Deplasarea determina micarea:

Eroarea ntrerupe irul micrilor ceea ce notm astfel:


eroare.
Acceptarea de asemenea ntrerupe evoluia mainii:
eroare.
Relaia de micare se poate extinde la nchiderea ei tranzitiv i reflexiv . MDR
poate fi privit i ea ca un translator ce definete o traducere astfel:

Definiia 2.6. O MDR este valabil pentru o gramatic G dac:


a)
b) pentru orice , dac , atunci .
Exemplul 2.6. Fie gramatica GL de mai sus i irul de intrare id, id. Considerm
i . Atunci exist urmtoarea secven de micri ale MDR (pentru a nu se confunda cu
virgula folosit n descrierea configuraiei, terminalul ',' a fost prins" ntre apostrofuri).

Principala problem n proiectarea uni MDR valabile pentru o anumit gramatic o


reprezint algoritmul de conducere al mainii. El trebuie s decid cnd maina face o reducere,
o deplasare, cnd semnalizeaz eroare sau acceptare, care este captul, cu ce producie se face
reducerea. Pentru toate aceste decizii este de dorit ca algoritmului s-i fie suficient un context al
analizei ct mai limitat, alctuit, de exemplu, din simbolul curent de la intrare (n cazuri mai
complicate i din alte cteva care i urmeaz) precum i simbolul din vrful stivei (eventual i
alte cteva de sub acesta). La baza unui asemenea algoritm vor exista tabele care, pentru toate
combinaiile de simboluri ce pot aprea n vrful stivei i la intrare, s indice o unic aciune.
Modul concret n care se construiesc asemenea tabele reprezint subiectul urmtoarelor
paragrafe. Astfel, vom prezenta proiectarea analizoarelor sintactice bazate pe relaii de
preceden ntre simbolurile gramaticii, precum i cele bazate pe gramatici LR(1), cea mai larg
clas de gramatici ce permit analiza determinist, ascendent a limbajelor generate de ele. n
toate cazurile vom urmri modul n care se stabilesc regulile referitoare la:
- delimitarea produciei captului prin precizarea limitei dreapta i apoi a celei stnga
ale acestuia,
- stabilirea produciei cu care se face reducerea.

2.2. Gramatici de preceden. Ideea analizei bazat pe relaii de preceden const n


posibilitatea depistrii limitei dreapta i a celei stnga ale captului folosind relaii ntre

37
simbolurile ce alctuiesc forma propoziional. Relaiile, trei la numr, sunt notate de obicei cu
<,=,>. n cazul precedenei simple, ntr-o derivare de forma:

captul XK+1XK ...X 2 X1 este delimitat prin cele trei relaii astfel :
- la dreapta: X1>a,
- la stnga: XK+1<Xk,
- n interiorul captului: Xi+1=Xi, pentru i=1,.........,k-1. De asemenea, ntre simbolurile
consecutive din aXK+1 avem relaii < sau =.
Presupunnd c ntre dou simboluri oarecare din gramatic exist cel mult o relaie,
depistarea captului de ctre MDR este unic determinat. Problema care rmne este cea a
alegerii produciei cu care se face reducerea . Pentru a nltura aceast nedeterminare vom
presupune c gramatica folosit este unic invertibil, adic n cadrul produciilor ei nu exist
dou pri drepte identice. Cele de mai sus sunt formal introduse prin urmtoarele definiii:
Definiia 2.7. Se numesc relaii de preceden Wirth - Weber relaiile :

definite astfel pentru i :


a) X < Y dac exist ,
b) X = Y dac exist ,
c) X > Y dac exist a.. . La acestea se adaug relaiile ce
implic marcajul '$':
d) $ < X dac exist o derivare
e) X > $ dac exist o derivare .

n ciuda asemnrii lor ca notaie cu relaiile <,=,> din algebr, relaiile Wirth -Weber nu au
proprietile acestora. Reprezentarea cea mai folosit pentru relaiile Wirth -Weber este cea tabelar

Definiia 2.8. O gramatic independent de context G=<N, E ,P,S> este proprie dac nu are
simboluri inutile, dac nu exist derivri de forma pentru A e N i dac nu are X - producii n
afar, eventual, a produciei S X n care caz S nu apare n nici o parte dreapt a vreunei producii. O
gramatic independent de context, proprie, fr X -producii, n care ntre orice dou simboluri exist cel
mult o relaie de preceden Wirth-Weber, se numete gramatic de preceden simpl.

Exemplul 2.7. Fie gramatica :

Mulimea perechilor R. este uor de construit : se caut n prile dreapta ale produciilor
toate perechile de simboluri consecutive:

Pentru calculul mulimii R se pornete cu ea vid i cu o mulime M iniializat < cu R. Se


caut n M perechi de forma (X,B); n exemplul nostru ele sunt: (b,A) i (A,A).Pentru fiecare B
din aceste perechi cutam n prile dreapta ale B- produciilor primului simbol. Fie el Y. Se
adaug (X,Y) la mulimea R i dac Y N se adaug i < la M. n exemplu, din (b,A)
obinem : (b,a) i (b,S). Ambele se adaug la R, dar (b,*S)< se adaug i la M. Calculul lui R se
ncheie cnd nu mai exist n M nici o pereche <
(X,B) netratat. Se adaug, n fine, perechile ($,Y), unde . n cazul nostru , ($,b). n final,
relaia R devine:

<

36
Pentru calculul perechilor din mulimea R o vom considera iniial vid. Fie o mulime M
iniializat cu R. n M vom cuta perechile de forma (B,Y). n exemplul nostru ele sunt: (A,A),(A,a),(S,a).
Se calculeaz PRIM(Y). Apoi, pentru fiecare B-producie, se ia ultimul simbol al prii dreapt, fie el X.
Se adaug la toate perechile (X,a) cu a e PRIM(Y), iar la mulimea M perechile (X,a) cu X e N. n
exemplul nostru, pentru (A,A) avem : PRIM(A)={a,b}, iar ultimul simbol al prii dreapta este a. Deci
perechile adugate la R sunt (a,a) i (a,b). Mulimea R rezultat este:

Tabelul relaiilor de preceden este cel din figura III.2.16

S A a b c $
S
A < = < < =
a > > >
b < < <
c > >
$ <

Deoarece n fiecare intrare a tabelului exist cel mult o relaie de preceden, gramatica
este de precedent simpl.
La baza analizei limbajelor generate de gramatici de precedent st urtoarea teorem:
Teorema 2.5. Fie G=<N, S ,P,S> o gramatic proprie fr - producii i fie o derivare
dreapta n aceast gramatic a irului $S$:

Atunci:
a) pentru k < i < p, Xi+1 = Xi;
b) Xk +1 < Xk ;
a) pentru 1 < i < k -1, Xt+1 = Xt;
c) X1 > a1.
Demonstraie: Folosind metoda induciei pentru numrul de pai n derivare. Dac derivarea este

ntr-un pas: , unde k>1, atunci din definiia 2.7. avem: $ < Xk, Xi = Xi+1
pentru 1 < i < k - 1 i Xi > $. Deci cerinele teoremei sunt ndeplinite.
S considerm afirmaiile teoremei adevrate pentru n pai n derivare, n>0 , i fie
derivarea dreapta n n+1 pai:

Se poate arta uor c: Atunci avem : Xj+1 <Yq


(conditia b).
n care, n ultimul pas, Xj (1 < j < p) a fost nlocuit cu Xj-1X1 sunt terminale (dac j=1,
avem Xj-1,...., X1 = ).
Din ipoteza inductiv avem: Xj-1 < Xj sau X j-1 = Xj, precum i:
Xi+1 < Xt sau Xi+1 = Xi pentru p < i < j (condiia a).

Deoarece : avem:

Y1 > Xj-1 sau , pentru j=1, Y1 > a (condiia c).


Corolarul 2.1. Dac G este gramatic de preceden atunci concluziile a)-d) ale teoremei
2.5. devine:
a) pentru k < i < p, fie Xi+1 < Xi, fie Xi+1 = Xi;
b) Xk+1 < Xk;

37
c) pentru 1 < i < k -1, Xi+1 = Xt;
d) X1 > a1 ;
e) ntre orice dou simboluri din irul X p ...X1a1 nu mai exist nici o alt relaie n afara celor
precizate n a)..d).
Demonstraie. Eviden, datorit definiiei 2.8.

2.3 Tabele de analiza LR pentru gramatici ambigue.


Un caz interesant pentru analiza LR l prezint gramaticile ambigue. Se tie c ntr-o
asemenea gramatic avea forme propoziionale pentru care exist cel puin doi arbori de derivare
distinci.
De multe ori se refer pentru definirea limbajelor de programare asemenea gramatici
datorit faptului c ele sunt mai compacte i uneori chiar mai sugestive dect gramaticile
neambigue echivalente.
Se poate demonstra c o gramatic ambigu nu este LR(1), construirea tabelelor
conducnd la intrri cu mai multe valori n TA, deci la conflicte. Exist totui posibilitatea
prelucrrii acestor tabele prin eliminarea conflictelor ntr-un mod convenabil proiectantului.
Unele ambiguiti apar din nespecificarea prin gramatic a regulilor de preceden i
asociativitate a operatorilor din limbaj. Exemplul 2.22. Fie gramatica ambigu:

Ea nu specific prin producii intermediare o ordine a reducerilor care s stabileasc


ordinea operaiilor. Pentru urmtoarele dou derivri distincte ale aceleiai propoziii:

n prima derivare secvena reducerilor reflect prioritatea obinuit : * este prioritar fa


de +, n timp cea de-a doua derivare reduce nti E + E la E i apoi pe E *E la E ceea ce
inverseaz prioritatea cunoscut a operatorilor.
Ambiguitatea se reflect n tabelele LR. Astfel, n tabela de aciuni SLR(1) pentru
gramatica ambigu de mai sus(fig. III.2.29 a) se constat conflicte deplasare-reducere n TA(s
7,+), TA(s 7 ,*), TA(s 8,+), TA(s 8 ,*).

a + * ( ) $
D, E E D, E E
s3 s2
s E D, S4 D, s5 E E A
1
S D, E E D, E E
2 s3 s2
S E R, 4 R, 4 E R, 4 R,
3 4
S D, E E D, E E
4 s3 s2
S D, E E E E
5 S3
S E D, S4 D, s5 E D, E
6 S9
S E D, S4 R, D, s5 R, E R1 R,
7 1 1 1
S E D, S4 R, D, S5 R, E R, 2 R,
8 2 2 2
S E R, 3 R, 3 E R, 3 R,
9 3

36
Se consider conflictul din TA(s7 ,*) ntre (D,s5) i (R,1). Analizorul are de ales ntre a
deplasa ,,* ''(conform lui (D, s5)) i a reduce cu producia E E +E i a deplasa ,+' vom prefera
reducerea ceea ce reflect opiunea pentru asociativitatea la stnga, cea mai folosit de obicei. n
al doilea caz, din acelai motiv aplicat ns operatorului *, vom prefera tot reducerea.
Cu aceste modificri, tabela de aciuni devine cea din fig.2.8.
a
+ * ( ) $
S D, E E D, E E
0 S3 s2
s E D, D, E E A
1 S4 S5
S D, E E D, E E
2 S3 s2
S E R, 4 R, 4 E R, 4 E,
3 4
S D, E E D, E E
4 S3 s2
S D, E E D, E E
5 S3 s2
S E D, D, E D, E
6 S4 S5 S9
S E R, 1 D, E R, 1 R,
7 S5 1
S E R, 2 R, 2 E R, 2 R,
8 2
S E R, 3 R, 3 E R, 3 R,
9 3
Observaie : Analizorul care folosete aceast tabel va recunoate acelai limbaj cu
limbajul recunoscut de analizorul ce folosete tabela din figura III.2.24 (Exemplul 2.10) dar va
evita reducerile prin producii singulare i va beneficia astfel de o tabel mai mic. n mod
asemntor se pot obine pentru gramatici ambigue i tabelele LR(1) i LALR(1).
Bibliografie

Popa Ioan "Limbaje formale", vol.1 si 2, Colectia Bursa, Bucuresti, 1997


2. Lascu Ciliana Corina " Locul compilatorului n programare ", Ed. Teora, 1996
3. Negoescu Gh., Bontas C.A. " Structura compilatoarelor ", Galati, 1999
5. Andrei t., Grigora Gh. : Tehnici de compilare. Lucrri de laborator. Editura
Universitii Al.I.Cuza, Iai, 1995
6. Appel, A., Modern Compiler Implementation in C, Cambridge University Press,
1997
7. Aho, A.V., Sethi, R., Ullman, J.D.: Compilers: Principles, Techniques, and Tools.
Addison-Wesley Publishing Company, U.S.A., 1986
8. Grigora, Gh.: Limbaje formale i tehnici de compilare. Editura Universitii
9. Al.I.Cuza, Iai, 1986
10. Grigora, Gh.: Constructia compilatoarelor - Algoritmi fundamentali, Editura
Universitatii "Al. I. Cuza" Iasi, ISBN 973-703-084-2, 274 pg., 2005.
11. Jucan, T, Andrei, t.: Limbaje formale i teoria automatelor. Culegere de
probleme. Editura Universitii Al.I.Cuza, Iai, 1997
12. Jucan, T., Limbaje formale i automate, Editura MatrixRom, 1999.
13. erbnai, L.D., Limbaje de programare i compilatoare, Editura Academiei,
Bucureti,1987.
Anexa C. Exemplu. Modelul experimental. Listingul programului
#include <conio.h>

37
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include<string.h>
int disparte(char S[], char *ss,char c, int a)
{ int k=0;
if (S[a]==c)
{a++;
for(;a<strlen(S);a++)
if(S[a]!=' '&&S[a]!=')'&&S[a]!=';'&&S[a]!='\0') {ss[k]=S[a]; k++;}
else {ss[k]='\0'; break;}
}
else
{for(;a<strlen(S);a++)
if(S[a]==c) break;
a++;
for(;a<strlen(S);a++)
if(S[a]!=' '&&S[a]!=')'&&S[a]!=';'&&S[a]!=';') {ss[k]=S[a]; k++;}
else {ss[k]='\0'; break;}
}
return a;
}
void simulare_switch()
{
char ch,s1[256],s2[256],s3[300],s4[300],s5[300];
int i=0,j=0;
FILE *f;
clrscr();
f = fopen("switch.txt", "r");
window(1,1,80,50);
textbackground(1);
textcolor(15);
clrscr();

int k=0,l=0;
i=0;
puts("\tOperatorul 'Switch' analizat este:\n");
do
{
do
{
ch=fgetc(f);
s1[i]=ch; i++; printf("%c",ch);
} while(ch!='\n'&&ch!=EOF&&ch!=' ');
s1[i-1]='\0';
//puts(s1);
i=0;
if(strcmp(s1,"switch")==0) {l=1;}
if(!strcmp(s1,"case")||!strcmp(s1,"default:")) k++;
if(!strcmp(s1,"break;")) j++;
} while (ch!=EOF );
puts("\n\tAnaliza sintactica a operatorului 'Switch'...\n");
if(l)

36
{if (j>k) printf("\nIn exprsia data lipseshte un 'case' sau instructiunea optionala 'default'");
else if(j<k) printf("\nExpresia switch este incorecta deoarece lipseste intreruperea 'break' a
instructiunii");
else printf("\nDin punct de vedere sintatic operatorul SWITCH a fost oganizat corect");
}
else printf("\nIn instructiunea data lipseshte cuvintul chee 'switch'");
fclose(f);
getch();
}
void main()
{ char s[100],s1[10],s2[10],s3[10],s4[10];
char *semn[5]={"!=","<=",">=","<",">"},*oper[6]={"++","--","+=","-=","*=","/="};
int i,j,k,l,d;
window(1,1,80,50);
textbackground(1);
textcolor(15);
clrscr();
simulare_switch();

et1:

window(1,1,80,50);
textbackground(1);
textcolor(15);
clrscr();
clrscr();
puts("Introdu expresia for: ");
//gets(s);
strcpy(s,"for (i=0;i<=n;i+=2)");
puts(s);
for(i=0;i<strlen(s);i++)
if(s[i]!=' '&&s[i]!='(') {s1[j]=s[i]; j++;}
else {s1[j]='\0'; break;}
i=disparte(s,s2,'(',i);
i=disparte(s,s3,';',i);
i=disparte(s,s4,';',i);
int v=0;
puts("Verificarea sintaxei a operatorului 'for'");
if(!strchr(s,'(')) {puts("In exprsia data lipseste '('"); v++;}
if(!strchr(s,')')) {puts("In exprsia data lipseste ')'"); v++;}
k=0;
for(l=0;l<strlen(s);l++)
if(s[l]==';') k++;
if(k!=2) {puts("In expresia data lipseste ';'"); v++;}
if(strlen(s1)==3&&s1[1]!='=') {puts("Inexpresia data lipseste '='"); v++;}
if (v) {puts("In expresia introdusa sunt erori doritzi sa o reintroducetzi? da-'y',nu-'n'");
et3: char ch=getch();
if (ch!='y'&&ch!='n') goto et3;
if(ch=='y') goto et1;
else exit(0);
}
else puts("\n\tVerificarea sintaxe a expresiei a trecut cu succes\n");

37
for(i=0;i<5;i++)
if(strstr(s3,semn[i])) {printf("\nSemnul conditional utilizat este: %s",(semn[i])); break;}
for(j=0;j<6;j++)
if(strstr(s4,oper[j])) {printf("\nSemnul operational utilizat este: %s",oper[j]); break;}
l=s2[2]-48;
k=0; int ll=1;
for (i=strlen(s4)-1;i>0;i--)
if(s4[i]>47&&s4[i]<59) {k+=(s4[i]-48)*ll; ll*=10;}
else break;
int n;
printf("Valoarea de modificare a parametrului ciclului este=%d\n\n",k);
puts("Introdu vloarea lui n");
scanf("%d",&n);
for(i=0;i<5;i++)
if(strstr(s3,semn[i])) {puts(semn[i]); break;}
/////////////// Simularea lui for
int t;
t=l; l=0;
while (1)
{ switch(i)
{ case 0: if (t==n) goto et; break;
case 1: if (t>n) goto et; break;
case 2: if (t<n) goto et; break;
case 3: if (t==n) goto et; break;
case 4: if (t==n) goto et; break;
}
switch(j)
{ case 0: t++; break;
case 1: t--; break;
case 2: t+=k; break;
case 3: t-=k; break;
case 4: t*=k; break;
case 5: t/=k; break;
}
l++;
}
et: printf("\nnumarul de pashi de executzie este=%d\n",l);
/////////////// sf Simularii

getch();

36

S-ar putea să vă placă și