Documente Academic
Documente Profesional
Documente Cultură
Dragan Mircea
April 19, 2006
PREFAT
A
Materialul prezentat constituie notele de curs tinute studentilor din primii
doi ani la Sectia Informatica a Facultatii de Matematica si Informatica de la
Universitatea de Vest Timisoara.
In primul capitol, Introducere se trec n revista notiunile fundamentale din
teoria limbajelor formale si se prezinta problema generala a compilarii.
Capitolul al doilea, Limbaje regulate si analiza lexical
a, prezinta chestiunile
teoretice fundamentale privind teoria automatelor si echivalenta cu limbajele de
tipul trei, proprietati speciale si mecanisme echivalente cu automatele finite. Sunt
prezentate de asemenea si principiile analizei lexicale, finalizate cu realizarea unui
analizor lexical.
Capitolul al treilea, Limbaje independente de context este dedicat studiului
teoretic al mecanismelor de generare si de recunoastere a limbajelor de tipul
doi. Sunt prezentate formele normale ale gramaticilor independente de context
si cateva proprietati speciale.
Capitolul patru, Analiza sintactica este dedicat prezentarii principiilor generale de analiza sintactica si a algoritmilor specializati de analiza. Pentru fiecare
tip de algoritm analizat s-au considerat exemple practice de aplicare.
Capitolul al cincilea, Sinteza programelor trateaza formele intermediare uzuale
pentru traducerea programelor si generarea codului obiect pornind de la formatul intermediar. Pentru cazul expresiilor aritmetice sunt prezentati si algoritmi
directi de generarea a formatului intermediar, mpreuna cu proceduri standard
de optimizare a codului generat.
Ultimul capitol, Masina Turing prezinta succint mecanismul formal ce defineste modelul de calculabilitate.
La sfarsitul fiecarui capitol sunt date cateva exercitii (nerezolvate), aplicatii
directe la chestiunile teoretice prezentate. Acestea pot fi parcurse n cadrul orelor
de seminar si laborator.
In expunerea algoritmilor s-a folosit un limbaj mai putin rigid, fara prea multe
reguli stricte. In general s-a urmarit descrierea cat mai simpla a structurilor care
apar n text.
Cuprins
1 Introducere
1.1 Limbaje formale . . . . . . . . . . . .
1.2 Gramatici generative de tip Chomsky
1.3 Ierarhia Chomsky . . . . . . . . . . .
1.4 Traducerea programelor . . . . . . .
1.5 Probleme propuse . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
5
8
12
17
20
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
23
23
29
34
37
48
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
51
51
54
56
62
65
73
76
.
.
.
.
.
.
.
.
79
80
80
81
84
90
90
92
93
4 Analiza Sintactic
a
4.1 Algoritmi TOP-DOWN . . . . . . . . . . . . . . . . . . . .
4.1.1 Algoritmul general de analiza top-down . . . . . . .
4.1.2 Analiza top-down fara reveniri . . . . . . . . . . . .
4.1.3 Programarea unui analizor sintactic. Studiu de caz
4.2 Algoritmi BOTTOM-UP . . . . . . . . . . . . . . . . . . .
4.2.1 Gramatici cu precedenta simpla . . . . . . . . . . .
4.2.2 Relatii de precedenta . . . . . . . . . . . . . . . . .
4.2.3 Proprietati ale gramaticilor cu precedenta simpla .
3
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
CUPRINS
4.2.4
4.2.5
4.2.6
4.2.7
4.2.8
4.2.9
5 Sinteza Programelor
5.1 Forme interne ale programelor . . . . . . . . . . . . . . . .
5.1.1 Tabelele compilatorului . . . . . . . . . . . . . . . .
5.1.2 Cvadruple si triplete . . . . . . . . . . . . . . . . .
5.2 Generarea formatului intermediar . . . . . . . . . . . . . .
5.2.1 Generarea cvadruplelor . . . . . . . . . . . . . . . .
5.2.2 Generarea tripletelor . . . . . . . . . . . . . . . . .
5.2.3 Generarea sirului polonez . . . . . . . . . . . . . .
5.3 Generarea formatului intermediar pentru instructii clasice .
5.3.1 Instructiunea de atribuire . . . . . . . . . . . . . .
5.3.2 Instructiunea If . . . . . . . . . . . . . . . . . . . .
5.3.3 Variabile indexate . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
107
107
107
109
114
115
117
118
121
121
121
121
6 Masina Turing
123
6.1 Limbaje de tipul zero . . . . . . . . . . . . . . . . . . . . . . . . . 123
6.2 Masina Turing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
Capitolul 1
Introducere
1.1
Limbaje formale
Notiunea general
a de limbaj. Se numeste alfabet sau vocabular orice multime
finita si nevida. Elementele unui alfabet V le vom numi simboluri (sau litere,
caractere, variabile).
Definitie 1.1 Un cuv
ant peste un alfabet V este o secvent
a p = a1 a2 . . . an , ai
V, i = 1, . . . , n.
Numarul n, deci numarul simbolurilor cuvantului p, se numeste lungimea cuvantului
si va fi notat cu |p| sau l(p). Vom considera si cuvantul vid sau e, care nu contine
nici un simbol; evident || = 0.
Notiunea de cuv
ant este fundamentala n teoria limbajelor formale sau n alte
domenii ale informaticii; termeni sinonimi utilizati n literatura sunt propozitie,
fraz
a sau sir. Sa observam ca nu exista o similitudine foarte buna ntre notiunile
de alfabet, cuvant, etc. din teoria limbajelor formale si notiunile corespunzatoare din lingvistica.
Multimea tuturor cuvintelor peste un alfabet V o notam cu V + . Aceasta
multime mpreuna cu cuvantul vid va fi notata cu V . In general, vom utiliza
litere mari de la sfarsitul alfabetului pentru notarea diverselor alfabete, U, V, W,
etc.; litere de la nceputul alfabetului (mari sau mici) pentru notarea simbolurilor,
A, B, C, . . . , a, b, c, . . . , i, j, . . . (uneori cifre 0,1,2,...); pentru notarea cuvintelor
vom utiliza litere mici de la sfarsitul alfabetului, p, q, r, s, t, u, v, w, x, y, z, etc.
(aceasta conventie de notare nu va fi absoluta).
Fie p = a1 . . . an , q = b1 . . . bm . Definim pe multimea V operatia de concatenare sau juxtapunere prin pq = a1 . . . an b1 . . . bm .
Se poate verifica usor ca aceasta operatie este asociativa. Prin urmare,
multimea V + nzestrata cu aceasta operatie este un semigrup (semigrupul liber
peste V ). Multimea V cu aceiasi operatie este un semigrup cu unitate, deci un
monoid, unitatea fiind cuvantul vid (monoidul liber peste V ). Structura are si
5
CAPITOLUL 1. INTRODUCERE
(fat
a de V ). Exista si operatii specifice limbajelor.
In general, o operatie de n-aritate oarecare (cel mai adesea binara sau unara)
pe multimea V defineste o operatie corespunzatoare pe multimea limbajelor.
Astfel, daca
: V P(V ) si : V V P(V )
sunt doua operatii pe V (unara si respectiv binara) si L1 , L2 sunt doua limbaje
peste V , putem defini limbajele (L1 ) respectiv (L1 , L2 ) prin
(L1 ) =
[
xL1
Exemple:
(x), (L1 , L2 ) =
[
xL1 ,yL2
(x, y).
2. Inchiderea
(Kleene) a unui limbaj L este
L =
Lk .
k=0
Sub(L) =
{Sub(x)}.
xL
M i(L) =
{M i(x)}.
xL
s(x).
xL
CAPITOLUL 1. INTRODUCERE
1.2
Un limbaj peste un alfabet poate sa fie o multime finita sau infinita. Daca este o
multime finita, el poate fi definit prin scrierea efectiva a cuvintelor limbajului. In
cazul n care este o multime infinita, el poate fi definit n anumite cazuri punand
n evidenta structura cuvintelor lui. De exemplu
L2 = {01, 0011, 000111, . . .} = {0n 1n |n 1}.
Exista doua procedee mai generale pentru definirea limbajelor:
1. Procedee generative, care permit generarea tuturor cuvintelor limbajului.
Exista mai multe tipuri de mecanisme de generare a limbajelor, ntre care
gramaticile Chomsky, sisteme Lindenmayer,etc.
2. Procedee analitice, care determina daca un cuvant dat apartine sau nu
limbajului. Sunt asa-numitele automate, automate finite, automate pushdown, etc.
Un rol deosebit n teoria limbajelor formale l au gramaticile Chomsky.
Notiunea de gramatic
a Fie VN si VT doua alfabete disjuncte,VN VT =
numite respectiv alfabetul simbolurilor neterminale (VN ) si alfabetul simbolurilor
terminale (VT ). Notam VG = VN VT alfabetul general si P VG VN VG VG
alfabetul regulilor.
Multimea P va fi deci formata din perechi de forma (u, v), unde u = u0 Au00 ,
0
u , u00 VG , A VN iar v VG , deci u si v sunt cuvinte peste VG , cu observatia
ca u trebuie sa contina cel putin un simbol neterminal. Vom spune ca o astfel
de pereche este o regul
a (productie, regula de generare, regula de rescriere) si o
vom nota u v (vom spune: u se transforma n v). Apartenenta unei reguli la
P o vom nota n mod obisnuit (u v) P , sau mai simplu, u v P (nu va
exista confuzia cu faptul ca v este un element al lui P ).
Definitie 1.3 O gramatic
a este un sistem G = (VN , VT , X0 , P ), unde VN este
alfabetul simbolurilor neterminale, VT este alfabetul simbolurilor terminale, X0
VN si se numeste simbol de start al gramaticii, iar P este multimea de reguli.
Observatie. Simbolurile alfabetului VN le vom nota n general cu litere mari
A, B, C, . . . , X, Y, Z (mai putin U, V, W ) iar cele ale alfabetului VT cu litere mici
de la nceput a, b, c, . . . sau cu cifre 0, 1, 2, . . ..
a direct n q
Fie G o gramatica si p, q VG . Vom spune ca p se deriveaz
si vom scrie p q (sau mai simplu pq) daca exista cuvintele r, s, u, v VG
G
Vom scrie p0 p00 (sau p0 p00 cand nu exista nici o confuzie) daca n > 1
G
0
00
numarul de derivari directe din sir l vom numi lungimea derivarii; se mai spune
ca p0 deriv
a n p00 .
+
Este clar ca relatia este nchiderea tranzitiva a relatiei , iar relatia este
nchiderea tranzitiva si reflexiva a relatiei de transformare directa .
Definitie 1.4 . Limbajul generat de gramatica G este prin definitie multimea
L(G) = {p VT , X0 p}.
G
n gramatica G.
Exemple:
1. Fie G = (VN , VT , X0 , P ), unde VN = {A}, VT = {0, 1}, X0 = A (evident)
si P = {A 0A1, A 01}. O derivare n aceasta gramatica este, de
exemplu
A0A100A11000111 = 03 13 .
Este evident ca L(G) = {0n 1n |n 1}.
Observatie. In cazul n care mai multe reguli au aceeasi parte stanga, le
vom scrie compact astfel u v1 |v2 | . . . |vn , simbolul | avand sensul de sau;
n cazul nostru, A 0A1|01.
2. G = (VN , VT , X0 , P ), unde
VN = {<propozitie>, <subiect>, <atribut>, <predicat>, <complement>,
<substantiv>, <adjectiv>, <verb>, <articol>},
VT = {o, orice, matrice, functie, derivabila, continua, este },
X0 =<propozitie>,
P = {<propozitie><subiect><atribut><predicat><complement>,
<subiect><articol><substantiv>,
<atribut><adjectiv>,
<predicat><verb>,
<complement><adjectiv>,
<articol>o|orice,
<substantiv>matrice|functie,
<adjectiv>derivabila|continua,
<verb>este.
Observatie. In acest exemplu, <propozitie>, <subiect>, etc., reprezinta
fiecare cate un simbol neterminal; de asemenea, o, orice, matrice,
10
CAPITOLUL 1. INTRODUCERE
etc., reprezinta simboluri terminale. Se poate usor observa ca aceasta
gramatica genereaza propozitii simple de forma subiect-atribut-predicatcomplement care exprima judecati asupra conceptelor de matrice si functie.
De exemplu, se poate forma propozitia: orice functie derivabila este continua, care este din punct de vedere semantic corecta, precum si propozitia
orice functie continua este derivabila, care, dupa cum se stie, este falsa.
Evident, se pot genera si numeroase propozitii care nu au sens. Ceea ce ne
intereseaza n acest moment este aspectul formal, deci din punct de vedere
sintactic toate aceste propozitii sunt corecte; semantic, unele propozitii pot
sa fie incorecte sau chiar sa nu aibe sens.
Sa mai observam ca o gramatica Chomsky este n masura sa constituie
un model matematic pentru sintaxa unei limbi, fara sa intereseze aspectele
semantice. Este ceea ce a ncercat sa faca Naom Chomsky pentru limba
engleza n lucrarile sale din anii 050.
3. G = (VN , VT , X0 , P ), unde
VN = {<program>, <instructie>, <atribuire>, <if>, <expresie>, <termen>,
<factor>, <variabila>, <index>},
VT = {begin, end, if, then, stop, t, i, +, *, (, ), =, ,, ; },
X0 =<program>
P = {<program>begin <linie> end
<linie><linie>;<instructie> | <instructie>
<instructie><atribuire> | <if> | stop
<atribuire><variabila>=<expresie>
<if>if( <expresie>) then <atribuire>
<expresie><expresie> + <termen> | <termen>
<termen><termen> <factor> | <factor>
<factor>(<expresie>)| <variabila>
<variabila>t(<index>)|i
<index><index>, <expresie> | <expresie>
Gramatica din acest exemplu defineste un limbaj de programare simplu cu
trei tipuri de instructii: atribuiri, if-then, stop. Expresiile aritmetice au numai operatorii + si *; variabilele pot fi simple sau indexate (tablouri), iar i
tine loc de identificator sau constanta. Mentionam ca definirea n acest mod
a unui limbaj, inclusiv utilizarea crosetelor pentru desemnarea simbolurilor
neterminale, poarta adesea denumirea de notatie Backus Naur; n acest
mod s-a definit limbajul ALGOL60.
11
uAv upv, u, p, v VG , p 6= , A VN
sau A si n acest caz A nu apare n dreapta vreunei reguli.
Observatie. Evident, regulile de forma a doua au sens numai daca A este
simbolul de start.
Gramaticile de tipul 2 (independente de context); sunt gramatici care au
reguli de forma
A p, A VN , p VG .
Gramaticile de tipul 3 (regulate); sunt gramatici care au reguli de forma
(
A Bp
sau
Cq
A pB
Cq
cu A, B, C VN si p, q VT .
Vom nota cu Lj , j = 0, 1, 2, 3 familiile de limbaje generate de gramaticile
de tipurile j = 0, 1, 2, 3; vom avea astfel limbaje de tipul 0, limbaje de tipul 1
(sau dependente de context) , limbaje de tipul 2 (sau independente de context)
si limbaje de tipul 3 (sau regulate). Sa observam ca este importanta structura
cuvintelor unui limbaj si nu modul n care sunt notate simbolurile terminale. De
exemplu , limbajele
L02 = {0n 1n |n 1}, L002 = {an bn |n 1}
sunt n mod practic identice. Putem utiliza o unica notatie pentru afabetul
simbolurilor terminale , de exemplu , VT = {i1 , . . . , in }. Clasificarea de mai
sus este fundamentala n teoria limbajelor formale, ea a fost introdusa de Naom
Chomsky in 1958 si prin traditie noile clase de limbaje sunt raportate la aceasta
clasificare. O alta clasificare este urmatoarea
Gramatici de tipul 0; fara restrictii;
Gramatici monotone (de tipul 1):
u v, |u| |v|, u, v VG ;
Gramatici dependente de context:
uAv upv, u, p, v VG , p 6= , A VN ;
Gramatici independente de context (de tipul 2):
A p, A VN , p VG ;
12
CAPITOLUL 1. INTRODUCERE
Gramatici liniare:
A uBv, A VN , B VN {} u, v VT ;
Gramatici (stang) drept liniare:
A uB (A Bv), A VN , B VN {} u, v VT ;
Gramatici regulate (de tipul 3); gramatici stang liniare sau gramatici drept
liniare.
1.3
Ierarhia Chomsky
x1 . . . xm p, unde xj VG , j = 1, m , p VG .
at
Atunci exista p1 , p2 , . . . , pm VG astfel nc
p = p1 . . . pm si xj pj , j = 1, m.
Demonstratie. Procedam prin inductie asupra lungimii derivarii l.
Daca l = 0 atunci p = x1 . . . xm si luam pj = xj .
Presupunem ca proprietatea este adevarata pentru derivari de lungime l si
13
pj =
qj
0
qk uqk00
,j =
6 k
,j = k
14
CAPITOLUL 1. INTRODUCERE
XX1 X2 Y1 Y2 Y3 Z1 Z2 .
Definim acum urmatoarea gramatica independenta de context fara reguli de
stergere G0 = (VN , VT , X0 , P 0 ) unde VN , VT , X0 sunt ca n gramatica data, iar P 0
se construieste pornind de la P astfel. Fie X p P, p 6= . Includem atunci
n P 0 aceasta regula precum si toate regulile de forma X pj , unde pj se obtine
din p lasand la o parte, n toate modurile posibile, simbolurile din Uf (se excepta
cazul pj = ). De exemplu daca X ABC P si A, B Uf , vom induce n P 0
regulile
X ABC, X BC, X AC, X C.
15
G0
adica X p.
G0
X X1 . . . Xm p
G
Unele din cuvintele pj pot sa fie vide; pentru precizarea ideilor sa presupunem ca
X X1 X4 X6 . . . Xm p1 p4 p6 . . . pm = p.
G0
G0
X0 u v p.
G0
G0
G0
16
CAPITOLUL 1. INTRODUCERE
Daca n derivarea directa u v se aplica o regula care exista si n G, atunci
G0
A , avem
G
Teorema 1.1 L2 L1 .
Demonstratie. Fie L L2 un limbaj independent de context si G o gramatica de
tipul 2 care l genereaza, adica L = L(G).
Presupunem ca L. Construim gramatica G0 ca n lema precedenta; orice
cuvant p 6= din L(G) se poate obtine n G0 si invers , deci L(G0 ) = L(G) {}.
Consideram atunci o gramatica G00 = (VN {X000 }, VT , X000 , P 0 {X000 , X000
X0 }). Evident L(G00 ) = L(G). Toate regulile lui G00 respecta tipul 1 (cu u =
v = ) si contine o singura regula de stergere X000 iar X000 nu apare n partea
dreapta a vreunei reguli. Deci G00 este de tipul 1 si orice limbaj independent de
context este inclus n L1 , adica L2 L1 .2
Fiind data o operatie binara notata cu pe o familie de limbaje L, vom
spuna ca familia L este nchisa la operatia daca L1 , L2 L implica L1 L2
L. Definitia notiunii de nchidere pentru operatii unare sau cu aritate oarecare
este analoaga. Relativ la proprietatile de nchidere a familiilor din clasificarea
Chomsky mentionam urmatorul rezultat.
Teorema 1.2 Familiile Lj , j = 0, 1, 2, 3 sunt nchise la operatiile regulate.
Demonstratie. Fie Gk = (VNk , VTk , Sk , Pk ), k = 1, 2 doua gramatici de acelasi
tip j, j = 0, 1, 2, 3. Putem presupune ca VN1 VN2 = . Trebuie sa aratam ca
limbajele L(G1 ) L(G2 ), L(G1 )L(G2 ), L(G1 ) , sunt de acelasi tip j. In acest
scop vom construi gramatici de tipul j care sa genereze le genereze. Vom indica
fara demonstrtie modul de constructie al gramaticilor (pentru detalii vezi [?]):
Reuniune
17
j = 0, 1, 2, 3:
G = VN1 VN2 {S}, VT1 VT2 , P1 P2 {S S1 |S2 }).
Produs
j = 0, 1, 2:
G = VN1 VN2 {S}, VT1 VT2 , P1 P2 {S S1 S2 }).
j = 3:
G = VN1 VN2 {S}, VT1 VT2 , S1 , P10 P2 ),
unde P10 se obtine din P1 prin nlocuirea regulilor de forma A p cu A pS2 .
Inchidere
Kleene
j = 0, 1:
G = (VN {S , X}, VT , S , P {S |S|XS, Xi Si|XSi, i VT })
j = 2:
G = (VN {S }, VT , S , P P prime {S S S|})
j = 3:
G = (VN {S }, VT , S , P P prime {S S|})
1.4
Traducerea programelor
Un limbaj de programare este un limbaj care are drept scop descrierea unor
procese de prelucrare a anumitor date si a structurii acestora (n unele cazuri
descrierea structurii datelor este preponderenta), prelucrare care se realizeaza n
general cu ajutorul unui sistem de calcul.
Exista n prezent un numar mare de limbaje de programare de nivel nalt sau
evoluate care se caracterizeaza printr-o anumita naturalete, n sensul ca descrierea
procesului de prelucrare cu ajutorul limbajului este apropiata de descrierea naturala a procesului respectiv precum si prin independenta unor astfel de limbaje
fata de sistemul de calcul. Dintre limbajele de acest tip cu o anumita raspandire
n momentul de fata mentionam limbajele PASCAL, FORTRAN, C, JAVA, etc.
O alta clasa importanta de limbaje, sunt limbajele de asamblare, sau de nivel
inferior, ale caror caracteristici depind de sistemul de calcul considerat. In general, fiecare sistem de calcul (sau tip de sistem de calcul), are propriul sau limbaj de asamblare; de exemplu, limbajul de asamblare ale sistemelor de calcul
echipate cu procesoare de tip Intel Z-80 este denumit n mod curent ASSEMBLER. Instructiile unui limbaj de asamblare corespund cu operatiile simple ale
18
CAPITOLUL 1. INTRODUCERE
sistemului de calcul iar stocarea datelor n memorie este realizata direct de utilizator la nivelul locatiilor elementare ale memoriei. Exista de asemenea anumite
pseudo-instructii sau directive referitoare la alocarea memoriei, generarea datelor,
segmentarea programelor, etc., precum si macroinstructii care permit generarea
unor secvente tipice de program sau accesul la bibliotecile de subprograme.
In afara de limbajele evoluate si de limbajele de asamblare, exista numeroase
limbaje specializate, numite uneori si de comand
a, care se refera la o anumita clasa
de aplicatii. Mentionam de exemplu limbajul pentru prelucrarea listelor LISP,
limbajele utilizate n cadrul softwarelui matematic (Mathematica, Maple, MATCAD, etc.) si multe altele. In general nsa astfel de limbaje nu sunt considerate
limbaje de programare propriuzise.
Un program redactat ntr-un limbaj de programare poarta denumirea de program surs
a. Fiecare sistem de calcul, n functie de particularitatile sale, poseda
un anumit limbaj propriu, numit cod masina, acesta fiind singurul limbaj nteles
de procesorul sistemului. Un astfel de limbaj depinde de structura instructiilor
procesorului, de setul de instructii, de posibilitatile de adresare, etc. Un program redactat n limbajul cod masina al sistemului de calcul l numim program
obiect.
Procesul de transformare al unui program sursa n program obiect se numeste
compilare sau translatare, uneori chiar traducere. De obicei termenul de compilare este utilizat numai n cazul limbajelor evoluate, n cazul limbajelor de
asamblare fiind utilizat termenul de asamblare.
Compilarea (asamblarea) este efectuata de un program al sistemului numit
compilator (asamblor). De multe ori compilatoarele nu produc direct program
obiect, ci un text intermediar apropiat de programul obiect, care n urma unor
prelucrari ulterioare devine program obiect. De exemplu, compilatoarele sistemelor de operare DOS produc un text numit obiect (fisiere cu extensia obj)
care n urma unui proces numit editare de legaturi si a ncarcarii n memorie
devine program obiect propriuzis, numit program executabil (fisiere cu extensia
exe). Exista mai multe ratiuni pentru o astfel de tratare, ntre care posibilitatea
cuplarii mai multor module de program realizate separat sau provenite din limbaje sursa diferite, posibilitatea crearii unor biblioteci de programe n formatul
intermediar si utilizarea lor n alte programe, etc.
Un program sursa poate de asemenea sa fie executat de catre sistemul de
calcul direct, fara transformarea lui prealabila n program obiect. In acest caz,
programul sursa este prelucrat de un program al sistemului numit interpretor;
acesta ncarca succesiv instructiile programului sursa, le analizeaza din punct
de vedere sintactic si semantic si dupa caz, le executa sau efectueaza anumite
operatii auxiliare.
Procesul de compilare este un proces relativ complex si comporta operatii care
au un anumit caracter de autonomie. Din aceste motive procesul de compilare
este de obicei descompus n mai multe subprocese sau faze, fiecare faza fiind o
operatie coerenta, cu caracteristici bine definite. In principiu aceste faze sunt
19
Program Sursa
Analiza Lexicala
Analiza sintactica
Tratarea
erorilor
Generarea formatului
intermediar
Prelucrarea
tabelelor
Generarea codului
Optimizarea codului
Program Obiect
20
CAPITOLUL 1. INTRODUCERE
1.5
Probleme propuse
21
22
CAPITOLUL 1. INTRODUCERE
(n) L = {ai bj ai bj };
(o) L = {awbbw0 |w, w0 {0, 1} };
(p) L = {w {0, 1} |w contine maxim 2 de 0 };
(q) L = {waw|w
{0, 1} };
(r) L = {w|w octet ce reprezinta un numar par };
(s) L = {A, B, C, . . . , Z};
4. Construiti o gramatica ce contine reguli de stergere, dar genereaza un limbaj
-liber.
5. Folosind teorema sa se construiasca o gramatica independenta de context,
fara reguli de stergere care genereaza limbajul de la punctul precedent.
Capitolul 2
Limbaje Regulate si Analiza
Lexical
a
2.1
Automate finite. Automatele finite sunt mecanisme pentru recunoasterea limbajelor de tipul 3 (regulate). Un automat finit (AF ) se compune dintr-o band
a
de intrare si un dispozitiv de comand
a.
Pe banda de intrare sunt nregistrate simboluri ale unui alfabet de intrare, constituind pe banda un cuvant p. La fiecare pas de functionare banda se deplaseaza
cu o pozitie spre stanga.
Dispozitivul de comanda poseda un dispozitiv de citire de pe banda; dispozitivul se afla permanent ntr-o anumita stare interna, element al unei multimi
finite de stari. Schema unui automat finit este redata n figura 2.1.
Automatul finit functioneaza n pasi discreti. Un pas de functionare consta
din: dispozitivul de comanda citeste de pe banda de intrare simbolul aflat n
dreptul dispozitivului de citire; n functie de starea interna si de simbolul citit,
automatul trece ntr-o noua stare si muta banda cu o pozitie spre stanga. Automatul si nceteaza functionarea dupa ce s-a citit ultimul simbol nregistrat pe
banda; n acest moment el se va afla ntr-o anumita stare, care, dupa cum vom
vedea, va juca un rol important n recunoasterea cuvintelor.
Din punct de vedere matematic, un automat finit este un sistem
AF = (, I, f, s0 , f ),
unde
este alfabetul (multimea) de stari;
I este alfabetul de intrare;
f : I P() este functia de evolutie;
s0 este starea initiala;
f este multimea de stari finale.
23
CAPITOLUL 2. LIMBAJE REGULATE SI ANALIZA LEXICALA
24
i1
i2
i3
...
ik
...
i n-1
in
...
Banda de intrare
Dispozitiv de citire
s S
Dispozitiv de comanda
s0
{s1 }
s1
{s2 }
{s0 , s1 }
s2
{s0 }
{s0 , s1 }
25
i2
i1
i2
s1
i1
s0
i2
i2
s2
f(
Zk , i) =
f (Zk , i)
f (Zk , i) =
[ [
sZk
f (s, i)) =
[
sZk
f (s, i) = f (
Zk , i).2
CAPITOLUL 2. LIMBAJE REGULATE SI ANALIZA LEXICALA
26
27
1
2
1
s0 s
1 s0 s1 ;
i1
i2
i1
s0 s
1 s1 s2 ;
A iB,
unde A, B, C VN , i, j VT
C j,
28
f =
{X, S} , pentru E
{X}
, pentru 6 E
(3) :
A1 f (S, i1 ),
A2 f (A1 , i2 ),
...
X f (An1 , in )
1
2
3
n
(4) S
A1 A
2 . . . X f
29
Deci p L(AF ).
Daca p = , atunci S si S P . Dar atunci L(AF ), caci
automatul este n starea S si ramne n aceasta stare dupa citirea lui ; cum
nsa n acest caz S f rezulta ca si n acest caz p L(AF ). In consecinta
L(G) L(AF ).
Fie acum p = i1 . . . in L(AF ); atunci avem traiectoria (4), relatiile (3),
regulile de generare (2) si putem scrie derivarea (1), adica p L(G) si L(AF )
L(G).2
Partea II E R E L3 .
Vom indica numai modul de constructie a gramaticii. Fie AF = (, I, f, s0 , f )
automatul finit care recunoaste limbajul E, pe care l presupunem determinist.
Construim gramatica G = (, I, s0 , P ) unde multimea P este definita astfel
f (A, i) = B genereaza regula A iB P ,
n plus daca B f se genereaza si regula A i P .
Putem arata ca L(G) = L(AF ).2
2.2
Propriet
ati speciale ale limbajelor regulate
Caracterizarea algebric
a a limbajelor regulate. Limbajele regulate, fiind
parti din I , se pot caracteriza algebric, independent de mecanismele de generare
(gramaticile de tipul 3) sau de cele de recunoastere (automatele finite).
Teorema 2.3 Fie E I un limbaj. Urmatoarele afirmatii sunt echivalente.
(a) E R;
(b) E este o reuniune de clase de echivalente a unei congruente de rang finit;
(c) Urmatoarea congruent
a
= {(p, q)|E (r1 pr2 ) = E (r1 qr2 ), r1 , r2 I },
unde E este functia caracteristic
a a lui E, este de rang finit.
Demonstratie: Vom arata urmatoarele implicatii: (a) (b), (b) (c), (c) (a).
(a) (b).
Fie AF = (, I, f, s0 , f ) automatul finit care recunoaste limbajul E. Definim
pe I relatia
= {(p, q)|f (s, p) = f (s, q), s }.
Se poate vedea cu usurinta ca este o relatie de echivalenta (reflexiva , simetrica
, tranzitiva). In plus , daca r I si (p, q) , atunci (pr, qr) si (rp, rq) .
De exemplu, prima apartenenta se deduce astfel
f (s, pr) = f (f (s, p), r) = f (f (s, q), r) = f (s, qr), etc.
30
31
e q)
e E
Ee(rf1 perf2 ) = Ee(rf1 qerf2 ) (p,
32
ij
sj = s
ik+1
s j-1
i1
s1
s k-1
s k+1
s j+1
s n-1
s0
in
sn
33
Consecint
a 2.3 Incluziunea L3 L2 este stricta.
In adevar, fie limbajul L2 = {0n 1n |n 1}. Stim ca acest limbaj este de tipul 2 si
ca poate fi generat de gramatica G = ({A}, {0, 1}, A, {A 0A1|01}). Sa aratam
ca L2 nu este de tipul 3.
Sa presupunem ca L2 este de tipul 3 si fie AF = (, I, f, s0 , f ) automatul
finit care l recunoaste. Cum L2 contine cuvinte oricat de lungi, fie p L2
astfel ncat p card(). Conform lemei de pompare, p se descompune n forma
p = uvw, v 6= si uv m w E. Putem avea una din situatiile:
(1) p = 0| .{z
. . 0} 0| .{z
. . 0} 0| . . . 01
{z . . . 1},
u
(2) p = 0| . . . 01
. . 1} 1| .{z
. . 1},
{z . . . 1} 1
| .{z
u
(3) p = 0| .{z
. . 0} 0| .{z
. . 1} 1| .{z
. . 1} .
u
CAPITOLUL 2. LIMBAJE REGULATE SI ANALIZA LEXICALA
34
2.3
35
In cazul n care nu exista pericol de confuzie, vom nota cu L (fara indice) limbajul
reprezentat de o anumita expresie regulata.
Exemple.
S
j
2
1. R = a ; L =
j=0 {a } = {, a, a , . . .}.
2. R = aa ; L = a {, a, a2 , . . .} = {a, a2 , a3 . . .}.
3. R = (a|b) ; L = (La Lb ) = ({a} {b}) = {a, b} ;
{a, b} = {}{a, b}1 {a, b}2 . . . = {, a, b, aa, ab, ba, bb, . . .}, adica
(a|b) reprezinta multimea tuturor cuvintelor peste alfabetul {a, b}.
4. R = a|ba ; L = {a} {b} {, a, a2 , . . .} = {a, b, ba, ba2 , . . .}.
Limbajele reprezentate de expresii regulate constituie o anumita familie de limbaje; o vom nota cu Llr . Apare urmatoarea problema: care este pozitia acestei
familii n ierarhia Chomsky? Vom arata ca Llr coincide cu familia limbajelor
regulate.
Sisteme tranzitionale
Definitie 2.3 Un sistem tranzitional este un sistem de forma
ST = (, I, f, 0 , f , )
unde:
este o multime (finita) de stari;
I este alfabetul de intrare;
f : I P() este functia de tranzitie;
0 este multimea de stari initiale;
f este multimea de stari finale;
este relatia de tranzitie .
Exemplu. = {s0 , s1 , s2 }, I = {0, 1}, 0 = {s0 , s1 }, f = {s2 } iar functia si
relatia de tranzitie sunt date de:
f
0
1
s0
s1
s2
{s1 }
{s2 }
{s0 }
{s0 , s1 } {s0 , s2 }
= {(s0 , s1 ), (s2 , s1 )}.
36
0
1
s1
s0
0,1
s2
s0 O . . . s1 s2 O . . . s00 .
i
i2
in
s0 = s0 ` s1 ` . . . ` sn = s00 .
p
L(ST ) = {p|p I , s0 0 , s0 ` s, s f }.
Vom nota cu LST familia limbajelor recunoscute de sisteme tranzitionale. Este evident ca orice automat finit este un sistem tranzitional particular n care card(0 ) =
1 iar = (nu exista arce punctate). Prin urmare R LST .
Teorema 2.6 R = LST .
Demonstratie. Evident, trebuie sa aratam incluziunea LST R. Fie ST =
(, I, f, 0 , f , ) un sistem tranzitional. Construim automatul finit AF = (P(), I, f 0 , 0 , 0f )
unde
i
f 0 (Z, i) = {s|s0 Z, s0 ` s},
0f = {Z|Z f 6= }.
2.4. ANALIZA LEXICALA
s0
37
s0
s1
s1
s0
s1
i2
in
s0 ` s1 ` . . . ` sn f .
Putem construi o traiectorie a lui AF de forma
i
1
2
n
0
Z1
. . .
Zn ,
2.4
Analiza lexical
a
Procesul de analiza lexicala este o faza a procesului de compilare n care se determina unitatile lexicale (cuvintele, atomii) ale unui program sursa, se furnizeaza
38
ST R
ST S
ST R
ST L
ST R
2.4. ANALIZA LEXICALA
39
40
Unitate lexicala
if
else
identificator
constanta ntreaga
constanta reala
+
/
<
>
<=
>=
(
)
{
}
COD
if = 1
else = 2
ID = 3
NUM = 4
FLOAT = 5
op = 6
op = 6
op = 6
op = 6
opr = 7
opr = 7
opr = 7
opr = 7
LPAR = 8
RPAR = 9
LBRACE = 10
RBRACE = 11
ATRIBUT
Exemplu
referinta
referinta
referinta
1
2
3
4
1
2
3
4
-
if, If, IF
else ElSe
Nelu v tabel
4 -3 233
4.32 -3.233
2.4. ANALIZA LEXICALA
41
/* text */
directive de preprocesare
#include<stdio.h>
#define MAX 5.6
G:
< ul >< id > | < num > | < cc > | < op > | < opr >
< id > l < id1 > |l, < id1 > l < id1 > |c < id1 > |l|c
< op > +| | |/
42
2.4. ANALIZA LEXICALA
43
if
if8
Etapa II. Corespunzator expresiilor avem urmatoarele automate finite deterministe echivalente, prezentate n figura 2.9 (starile au fost notate prin numere
ntregi):
Etapa III. Se construieste sistemul tranzitional (vezi figura 2.10) ce recunoaste limbajul reuniune, adaugand o noua stare initiala (notata cu 1), pe
care o conectam prin arce punctate (ce corespund -tranzitiilor). Constructia
provine din legarea sistemelor tranzitionale n paralel. S-au renumerotat starile
sistemului tranzitional, asignand nume simbolice starilor finale.
Etapa III. Constructia automatului finit determinist general ce recunoaste
reuniunea limbajelor. Pentru aceasta sistemul tranzitional se transforma cu teorema de echivalenta n automat finit determinist (practic se trece de la stari ale
sistemului tranzitional la submultimi de stari, ce devin starile automatului finit).
44
a-z
0-9
a-z
2
ID
0-9
0-9
NUM
\n\t\b
\n\t\b
WS
a-z,\b
/
/
2
orice
1
\n
3
COM
ERR
2.4. ANALIZA LEXICALA
45
IF
a-z
0-9
a-z
6
ID
0-9
0-9
NUM
\n\t\b
\n\t\b
/
12
11
orice
15
WS
a-z ,\b
10
16
\n
13
14
COM
ERR
46
ID
IF
f
3,6,16
4,6
a-e
g-z
i
a-h
-jz
a-z
0-9
0-9
a-z
ID
a-z
0-9
6,16
0-9
ID
0-9
NUM
0-9
8,16
\n\t\b
WS
\n\t\b
10,16
ERR
12,16
ERR
orice
altceva
COM
/
\n
14
13
a-z,\b
16
2.4. ANALIZA LEXICALA
Last
Final
0
2
3
0
7
0
2
3
5
0
11
0
0
0
...
Current
State
1
2
3
0
1
7
0
1
2
3
5
0
1
11
0
1
8
9
...
Current Input
|>
i f i f 8 % / / h a \n
| i>
f i f 8 % / / h a \n
| i f> i f 8 % / / h a \n
| i f > i f 8 % / / h a \n
i f |>
i f 8 % / / h a \n
i f| >
i f 8 % / / h a \n
i f | > i f 8 % / / h a \n
i f |>
i f 8 % / / h a \n
i f | i>
f 8 % / / h a \n
i f | i f> 8 % / / h a \n
i f | i f 8>
% / / h a \n
i f | i f 8> % / / h a \n
i f i f 8|>
% / / h a \n
i f i f 8| %>
/ / h a \n
i f i f 8| %> / / h a \n
i f i f 8 %|>
/ / h a \n
i f i f 8 %|> / / h a \n
i f i f 8 %|> / / h a \n
...
47
Accept Action
resume
CAPITOLUL 2. LIMBAJE REGULATE SI ANALIZA LEXICALA
48
int edges[][] = {
/* ...
0 1 2 ...
e f g h i j ...
*/
/* state 0 */
/* state 1 */
/* state 2 */
etc
}
Figura 2.13: Reprezentarea functiei de evolutie a automatului finit
functia de evolutie asociata automatului finit determinist se memoreaza sub forma
unui tablou bidimensional de ntregi, ca n figura 2.13. Starea 0 este asociata cu
blocarea automatului. Ajungerea n aceasta stare echivaleaza cu gasirea ultimei
unitati lexicale, ntre pointerii | si >. Se executa actiunea asociata starii finale
si se reia cautarea (resume) urmatoarei unitati lexicale ncepand cu caracterul
imediat urmator pointerului >.
Observatie: Cele mai costisitoare operatiuni (ca timp) din analiza lexicala
sunt ignorarea comentariilor si tratarea erorilor lexicale. Primele generatoare
automate de analizoare lexicale si sintactice au aparut n anii 0 70 si au fost incluse
n sistemul de operare Unix.
2.5
Probleme propuse
49
50
Capitolul 3
Limbaje Independente de
Context
3.1
Arbori de derivare
v0
{v1 , v2 }
v1
51
v2
{v3 , v2 }
v3
v4
52
Nivel 0
v0
Nivel 1
v2
v1
v3
v4
Nivel 2
53
Varianta 2
Varianta 1
A
a
A
A
B
A
B
B
i1
i2
...
in
54
X1
p1
X2
...
p2
...
Xm
pm
XX1 . . . Xn p
si X p, etc. 2
3.2
55
G1
G2
(1) S S1 p, deci S1 p;
G
(2) S S1 p, deci S1 p,
G
i1 . . . in A0n
i1 . . . in A00n
p.
56
3.3
Forma normal
a Chomsky.
a n forma normala Chomsky este o gramatic
a cu reguli
Definitie 3.5 O gramatic
de forma
A BC,
D i,
unde A, B, C, D VN si i VT . Se accept
a si regula de completare S cu
conditia ca S sa nu apar
a n dreapta vreunei reguli.
Lema 3.1 (lema substitutiei). Fie G o gramatic
a de tipul 2 si X uY v precum
si Y p1 . . . pn toate regulile din G care au Y n stanga . Atunci G este echivalenta cu o gramatic
a G0 n care am facut substitutiile; adica facem urmatoarea
nlocuire
X uY v se nlocuieste cu X up1 v| . . . |upn v
(Regulile Y p1 | . . . |pn le vom pastra neschimbate).
G : S rstp.
Daca n rs se utilizeaza regula X uY v atunci n mod necesar n pasul
urmator se utilizeaza una din regulile Y p1 | . . . |pn , sa presupunem Y pj
(evident, este posibil ca aceasta regula sa nu se aplice n pasul imediat urmator,
dar ea poate fi adusa n aceasta pozitie). Prin urmare
(A) G : r = r0 Xr00 r0 uY vr00 r0 upj vr00 = t.
Acesti doi pasi se pot obtine si n G0 (ntr-un singur pas):
(B) G0 : r = r0 Xr00 r0 upj r00 = t.
57
G : u = u0 Xu00 u0 X1 . . . Xn u = v.
Aceasta derivare se poate obtine si n G0 n mai multi pasi si anume
00
58
00
G0
G0
G0
G0
L(G ) L(G).2
Forma normal
a Greibach.
59
e1:
e2:
j := 1;
begin
Se elimina recursiile stangi; neterminalele
noi le notam cu Y1 , Y2 , . . .
end
if j = n then STOP;
j := j + 1;
l := 1;
begin
Fie Xj Xl p, p VN si Xl p1 . . . pm
toate regulile care au Xl n stanga; se efectueaza toate substitutiile.
end
l := l + 1;
if l < j 1 then goto e2
goto e1
60
(1) Xj i;
(2) Xj Xk p, j < k, p VN ;
(3) Y iq, q VN , i = 1, . . . , m.
Aranjam toate neterminalele ntr-un sir unic, la nceput Y1 , . . . , Ym apoi X1 , . . . , Xn
si le redenumim, de exemplu cu X1 , . . . , Xm+n :
Y1 , Y2 , . . ., Ym , X1 ,
X2 ,
. . ., Xn
X1 , X2 , . . ., Xm , Xm+1 , Xm+2 , . . ., Xm+n
Vom nota n + m = N . In felul acesta regulile gramaticii vor avea numai
formele (1) si (2).
Etapa III. Toate regulile care au XN n stanga vor avea forma (1). Fie Xn1
XN p1 | . . . |XN pn toate regulile care au XN 1 n stanga si care nu sunt de forma
(1). Efecuam substitutiile lui XN ; n acest fel regulile care au XN si XN 1 n
stanga satisfac cerintele din forma normala Greibach. In continuare, consideram
toate regulile care au XN 2 n stanga si efectuam substitutiile, etc.2
Forma normal
a operator
Una din formele importante pentru gramatici independente de context, utilizata n analiza sintactica prin metoda precedentei, este forma operator a acestor
gramatici.
Definitie 3.8 O gramatic
a independent
a de context G = (VN , VT , S, P ) se spune
ca este n forma normala operator dac
a oricare ar fi productia A P , n
nu apar doua neterminale (variabile) consecutive, adic
a
P VN [(VN VT ) \ (VN VT ) V 2 (VN VT ) ].
Teorema 3.8 Orice gramatic
a independent
a de context este echivalent
a cu o gramatica n forma normala operator.
Demonstratie. Fie G = (VN , VT , S, P ) o gramatica de tipul 2 si L(G) limbajul
generat. Fara a restrange generalitatea presupunem ca 6 L(G) si G este
n forma 2canonica (regulile sunt de forma A BC, A B, A a vezi
teorema ??). Definim o gramatica echivalenta G0 = (VN0 , VT , S, P 0 ) astfel: VN0 =
{S} (VN VT ), iar P 0 = P1 P2 P3 P4 unde
i)
ii)
iii)
iv)
P1
P2
P3
P4
= {S (S, a)a| a VT };
= {(A, a) | A VN , a VT , A a P };
= {(A, a) (B, a)| A, B VN , a VT , A B P };
= {(A, a) (B, b)b(C, a)| A, B, C VN , a, b VT , A BC P }.
61
A B wa
G
A BC wa.
G
G0
G0
(B, b) u, (C, a) v.
Cum A BC P vom avea n P 0 productia (A, a) (B, b)b(C, a) si n G0
putem scrie derivarea extrem dreapta
G0
G0
62
S wa
G
(S, a) w, w VT , a VT .
G0
3.4
Lema BarHillel
XY Z p.
Observatie. Daca X p si |p| > 2m1 atunci exista n arborele AX,p cel putin
o ramura cu m + 1 noduri.
63
v 1 =A
v 2 =A
u
ABC vwx,
64
65
Totusi, nu orice limbaj care nu este de tipul 2 poate fi respins de lema lui
BarHillel. De exemplu, aceasta lema nu poate respinge limbajul
m
3.5
66
Banda de intrare
i1
i2
i3
...
ik
i n-1
in
...
Dispoz itiv
de comanda
...
zm
s S
Memoria pushdown
z1
z0
67
68
Prin urmare, este necesar ca dupa citirea lui p, eventual dupa nca cativa pasi,
APD sa ajunga ntr-o stare finala. Vom vedea ca cele doua definitii sunt echivalente.
Limbaje recunoscute de automate push-down cu golirea memoriei. Vom
arata ca familia limbajelor recunoscute de APD cu stari finale coincide cu familia
limbajelor independente de context. In felul acesta, APD constituie mecanisme
analitice de definire a limbajelor de tipul 2.
Teorema 3.11 Un limbaj este independent de context daca si numai daca este
recunoscut de un automat pushdown cu golirea memoriei pushdown.
Demonstratie. Partea I E L2 E = L(AP D).
Fie G = (VN , VT , S, P ) o gramatica de tipul 2 n forma normala Greibach care
genereaza limbajul E. Construim un automat pushdown astfel:
AP D = ({s}, VT , VN , f, s, S), functia de evolutie fiind definita de:
A ip P (s, p) f (s, i, A),
altfel .
(extrem stanga):
(A) Si1 X1 u1 i1 i2 X2 u2 u1 i1 i2 i3 X3 u3 u2 u1 . . . i1 . . . in ,
unde u1 , u2 , u3 , . . . VN = Z .
Observatie. Aparent, partea us us1 . . . u1 se mareste cu fiecare derivare directa. In realitate, unele din cuvintele uj sunt vide, si anume atunci cand se
aplica o regula de forma X i; n particular, n ultimele derivari directe se
aplica numai reguli de aceasta forma.
Avem
S i1 X1 u1 (s, X1 u1 ) f (s, i1 , S),
X1 i2 X2 u2 (s, X2 u2 ) f (s, i2 , X1 ),
X2 i3 X3 u3 (s, X3 u3 ) f (s, i3 , X2 ),
... .
Prin urmare automatul poate sa aiba urmatoarea evolutie:
(s, i1 i2 i3 i4 . . . in , S)7(s, i2 i3 i4 . . . in , X1 u1 )7
7(s, i3 i4 . . . in , X2 u2 u1 )7(s, i4 . . . in , X3 u3 u2 u1 )7 . . . .
Daca comparam aceasta evolutie cu derivarea (A) putem observa ca pe banda
de intrare avem la fiecare pas partea complementara a cuvantului (fata de derivare)
iar n memoria push-down se reproduce partea de neterminale din formele propozitionale
69
Vom arata o implicatie ceva mai generala, si anume, pentru orice u VN , avem
(s, p, u)7(s, , ) u p.
G
Presupunem ca implicatia este adevarata pentru un cuvant |p| = l si consideram un p astfel ncat |p| = l + 1. Fie i si X primele simboluri din p si u,
70
unde s0 .
Sa observam ca gramatica astfel construita este independenta de context, si
anume n forma normala Greibach.
adica p L(G).
Procedam prin inductie asupra lungimii evolutiei l.
Daca l = 1 atunci (s, p, z)7(s0 , , ), deci p = i si (s0 , ) f (s, i, z) si
(s, z, s0 ) i este o regula, adica putem scrie (s, z, s0 )i = p.
Presupunem ca implicatia este adevarata pentru evolutii de lungime oarecare
l si consideram o evolutie de lungime l + 1; punem n evidenta prima evolutie
directa
7 (s2 , , ),
7 (s3 , , ),
...
(sm , pm , zm ) 7 (s0 , , ).
(c)
La primul pas (situatia a) automatul este n starea s1 , pe banda este i1 iar n
memoria push-down este z1 . Dupa efectuarea unui pas, automatul trece n starea
s01 , muta banda cu o pozitie spre stanga, extrage pe z1 si scrie n memoria pushdown un cuvant q (situatia b). Se poate observa ca z2 a coborat; cum stim ca
memoria push-down se goleste (p L(AP D)), trebuie ca la un moment dat z2 sa
ajunga n varful stivei (situatia c). In acest moment partea din p citita va fi p1
iar starea n care a ajuns automatul o notam cu s2 . Este clar ca daca pe banda
am avea scris numai p1 am avea evolutia (s1 , p1 , z1 )7(s2 , , ).
71
Analog p2 , . . . , pm .
Din definitia derivarii directe (s, i1 p0 , z)7(s1 , p0 , z1 . . . zm ) avem
(s1 , z1 . . . zm ) f (s, i1 , z) iar n P va exista regula
(s, z, s0 ) i1 (s1 , z1 , s2 )(s2 , z2 , s3 ) . . . (sm , zm , s0 )
unde luam starile s2 , . . . , sm cele rezultate la descompunerea lui p0 . Pe de alta
parte, din ipoteza inductiva, avem
(s1 , z1 , s2 )p1 ,
(s2 , z2 , s3 )p2 ,
...
(sm , zm , s0 )pm .
Putem scrie derivarea
0
(s, z, s0 )p0 (s0j1 , zj1
, s0j )(sj , zj , sj+1 ) . . . (sm , zm , s0 )
0
p i(s1 , z1 , s2 ) . . . (sj1 , zj1 , sj )(sj , zj , sj+1 ) . . . (sm , zm , s0 ),
unde s0j = sj ; la ultimul pas s-a aplicat regula
0
(s0j1 , zj1
, sj ) i(s1 , z1 , s2 ) . . . (sj1 , zj1 , sj ).
0
)
Rezulta (s1 , z1 . . . zj1 ) f (s0j1 , i, zj1
0
0
(sj1 , i, zj1 )7(s1 , , z1 . . . zj1 ).
0
(s, p0 , z)7(s0j1 , , zj1
zj . . . z m )
Prin urmare
0
(s, p, z) = (s, p0 i, z)7(s0j1 , i, zj1
zj . . . zm )7(s1 , , z1 . . . zm )
72
n aceasta derivare se va aplica prima data o regula de forma (1), apoi regula de
forma (2) iar la sfarsit reguli de forma (3). La aplicarea regulilor (2) putem rescrie
la fiecare pas simbolul neterminal cel mai din stanga, deci sa obtinem o derivare
extrem stanga. Sa observam ca n acest caz structura formelor propozitionale
intermediare este cea mentionata, p(s1 , z1 , s2 )(s2 , z2 , s3 ) . . . (sm , zm , s0 ).
Prin urmare, derivarea va avea forma
73
3.6
Functionarea unui APD este n general nedeterminista, card f (s, i, z) 1. Pentru ca un APD sa aiba o functionare determinista nu ete suficient sa impunem
conditia card f (s, i, z) = 1, deoarece daca pentru un anumit s si z Z avem
f (s, , z) 6= si f (s, i, z) 6= , putem face un pas citind sau citind i.
Definitie 3.10 Un automat pushdown este determinist daca
(1) card f (s, i, z) 1, s , i I {}, z Z;
(2) daca f (s, , z) 6= , atunci f (s, i, z) = , i I.
74
p I exist
a o evolutie de forma (s0 , p, z0 )7(s, , q).
Intr-un APD determinist neblocabil orice cuvant peste I poate fi citit. Evident, de aici nu rezulta ca orice cuvant este recunoscut de APD.
Lema 3.6 Un APD determinist cu stari finale este echivalent cu un APD determinist cu stari finale neblocabil (relativ la prima situatie de blocare).
Demonstratie.Fie AP Df = (, I, Z, f, s0 , z0 , f ). Construim AP Df0 = (
{s00 , s0 }, I, Z {z00 }, f 0 , s00 , z00 , f ) unde:
(1) f 0 (s, i, z) = f (s, i, z) daca f (s, i, z) 6= , s , i I {}, z Z;
(2) f 0 (s, i, z) = (s0 , z) daca f (s, i, z) = f (s, , z) = , s , i I, z Z;
(3) f 0 (s0 , i, z) = (s0 , z), i I, z Z;
(4) f 0 (s0 , , z00 ) = (s0 , z0 z00 ).
Avem
p L(AP Df ) (s0 , p, z0 )
(s00 , p, z00 )
AP Df0
|=
(s0 , p, z0 z00 )
AP Df
|= (s, , q), s f
AP Df0
AP Df0
AP Df0
75
Demonstratie. Fiind dat un APD determinist vom construi un APD determinist neblocabil echivalent. Conform lemei anterioare putem presupune ca nu
are loc prima situatie de blocare.
Daca are loc a doua situatie de blocare, putem avea doua cazuri:
1. continutul memoriei pushdown se mareste nelimitat;
2. lungimea cuvintelor scrise n memoria pushdown nu depaseste un anumit
numar.
Fie card() = n, card(Z) = k, l = max{|q|, q Z | (s0 , q) f (s, i, z)}.
Cazul 1. Exista n total un numar nk de perechi de forma (s, z). Daca n
evolutia lui APD s-ar succede numai configuratii cu perechi de forma (s, z) distincte atunci lungimea cuvantului din memoria pushdown ar creste la maximum
s00
(s0 , 1 ) pentru s0 f ,
(s0 , 2 ) pentru s0 6 f ,
multimea de stari finale este 0f = {(s, 3 )|s } iar functia de evolutie este
definita de
76
3.7
Probleme propuse
77
78
Capitolul 4
Analiza Sintactic
a
Analiza sintactica este o faza a procesului de compilare care are urmatoarele doua
obiective principale:
Stabileste daca un cuvant dat apartine sau nu limbajului, deci daca cuvantul
este corect din punct de vedere sintactic. In particular limbajul poate
fi definit de o gramatica generativa de tip Chomsky si deci termenul de
analiza sintactica trebuie nteles n sensul teoriei limbajelor formale. Mai
mentionam ca prin cuv
ant ntelegem orice structura constituita cu simbolurile acceptate de limbaj, n particular un ntreg program, dar de obicei
ne vom margini la anumite entitati, de exemplu, o linie sau un rand.
Determina derivarea (arborele de derivare) corespunzator cuvantului. Odata
cu aceasta operatie sunt degajate anumite structuri pentru care se poate
genera cod intermediar, structuri pe care le vom numi unitati sintactice.
Pe langa aceste obiective principale se mai efectuaza si alte operatii, de exemplu, analiza si tratarea erorilor, prelucrarea tabelelor, etc. Rezultatul analizei sintactice va fi un fisier care contine derivarile (arborii de derivare) corespunzatoare unitatilor sintactice n care este descompus programul: expresii aritmetice, declaratii, etc. Acest fisier este utilizat n faza de generare a formatului
intermediar. In mod curent nsa, generatoarele de format intermediar sunt niste
rutine, apelate de analizorul sintactic, astfel ncat formatul intermediar se obtine
succesiv.
Teoretic, problema analizei sintactice este rezolvata de automatele corespunzatoare
diverselor tipuri de limbaje; aceasta cale conduce nsa la algoritmi cu complexitate mare (numar mare de stari, functie de tranzitie conmplexa, etc.). Exista
algoritmi speciali de analiza sintactica cu eficienta supe- rioara. In continuare ne
vom ocupa cu doua clase de astfel de algoritmi:
Algoritmi top-down (de sus n jos);
Algoritmi bottom-up (de jos n sus).
79
CAPITOLUL 4. ANALIZA SINTACTICA
80
4.1
4.1.1
Algoritmi TOP-DOWN
Algoritmul general de analiz
a top-down
x12 si i cere sa gaseasca derivarea x12 p2 , etc. Daca toate simbolurile activate de
x0 transmit succes, constructia este terminata. Sa presupunem ca x1j transmite
esec; atunci x0 l dezactiveaza pe x1j , l reactiveaza pe x1j1 caruia i transmite:
Mi-ai dat o derivare, dar aceasta nu este buna, ncearc
a alta. Daca x1j1 reuseste,
procesul se continua spre dreapta; daca nu, atunci x0 l dezactiveaza pe x1j1 ,
l reactiveaza pe x1j2 caruia i cere o alta derivare. Procesul se continua n
acest mod fie spre dreapta, fie spre stanga. Daca se ajunge la x11 si acesta nu
reuseste sa gasasca o alta derivare, x0 decide ca prima regula aleasa nu este buna
si ncearca cu urmatoarea regula, adica x0 x21 . . . x2n2 , s. a. m. d.
Observatii
Fiecare simbol devenit activ, procedeaza exact ca si parintele sau, alege
prima regula, activeaza primul simbol, etc.
Nu se cunoaste anticipat descompunerea p = p1 p2 . . . pn1 . Deci x1j trans
mite succes daca reuseste sa gaseasca o derivare x1j pj , unde pj este un
subcuvant oarecare al lui p, cu singura conditie ca p1j sa nceapa din punctul
unde s-a terminat p1j1 . De exemplu, daca p = i1 i2 . . . i8 . . . si p1 = i1 i2 i3 i4 ,
81
E T + E|T
T F T |F
F (E)|a
Procesul de analiza sintactica top-down pentru cuvantul p = aa este prezentat n figura 4.1.
In aceasta figura, revenirile n sus au fost marcate prin ncadrarea ntr-un
dreptunghi a subarborelui care a condus la un esec. Dreptunghiurile interioare
au semnificatia unor esecuri realizate mai devreme (este vorba de timpul de
desfasurare al procesului). Arborele corespunzator cuvantului este cel nencadrat
n vreun dreptunghi (n figura acesta este situat n partea dreapta).
4.1.2
Analiza top-down f
ar
a reveniri
In cazul unor gramatici cu o forma speciala se poate face o analiza de tip top-down
fara reveniri. Principala conditie este ca n cazul mai multor alternative (reguli cu
acelasi simbol n stanga), sa se poata decide cu precizie ramura corecta. In general
o astfel de decizie se poate realiza prin analiza unor simboluri care urmeaza n
cuvantul de analizat.
Exemplu Consideram urmatoarea gramatica G care genereaza secvente de
declaratii si instructiuni cuprinse intre cuvintele cheie Program si EndProgram. Declaratiile sunt notate simbolic cu d,iar instructiunile cu i. Fiecare
instructie sau declaratie se ncheie cu ;, exceptand cazul celei ce precede EndProgram.
D d; X
X d; X|
I iY
Y ; iY |
CAPITOLUL 4. ANALIZA SINTACTICA
82
E
7
5
1
(
*
3
F
2
(
F
8
(
10
E
F
9
(
i
F
4
(
F
E
11
(
i
i
F
6
(
83
Program
d;
d;
i;
i;
i;
EndProgram
O derivare extrem stanga pentru acest cuvant este
< program > P rogram D I EndP rogram P rogram d; X I EndP rogram
P rogram d; d; X I EndP rogram P rogram d; d; I EndP rogram
P rogram d; d; iY EndP rogram P rogram d; d; i; iY EndP rogram
P rogram d; d; i; i; iY EndP rogram P rogram d; d; i; i; i EndP rogram
Pentru constructia derivarii extrem stangi se procedeaza astfel: initial se considera simbolul de start < program > pentru care se alege singura regula disponibila (daca primul simbol din sirul de analizat nu coincide cu primul terminal al
regulii se poate decide imediat eroare sintactica).Urmatorul simbol neterminal
pentru care trebuie aleasa o regula este D iar sirul ramas de analizat (de generat)
ncepe cu d, astfel ca regula aleasa va fi D d; X. Din cuvantul initial trebuie
generata n continuare secventa d; i; i; i; EndP rogram ce ncepe cu d iar neterminalul cel mai din stanga este X, astfel ca se alege regula ce ncepe cu d. In
continuare, din cuvantul initial ramane de generat secventa i; i; i; EndP rogram
ce ncepe cu i iar neterminalul cel mai din stanga este X, astfel ca se alege regula
ce X , s.a.m.d.
Daca se considera gramatica ce genereaza expresii aritmetice simple, n forma
considerata la algoritmul general top-down (4.2.9), atunci la primul pas al unei
derivari extrem stangi pentru cuvantul (a + a a) + a nu se poate decide regula
de ales prin citirea primului terminal ( deoarece ar fi necesar sa consultam sirul
rezultat pana la ntalnirea operatorului + aflat dupa paranteza nchisa.
O gramatica pentru care alegerea regulii de aplicat este unic determinat
a
de urmatorul simbol terminal din sirul de analizat se numeste gramatica LL(1)
(Left to right parsing, Leftmost derivation, 1 symbol lookahead). In multe cazuri
exista posibilitatea de a transforma gramatica ntr-una echivalenta de tip LL(1).
Pentru cazul particular al gramaticii pentru generarea expresiilor aritmetice, o
gramatica echivalenta este urmatoarea:
E T E0
0
0
0
E +T E | T E |
T FT0
T 0 F T 0 |/F T 0 |
F (E)|id|num
CAPITOLUL 4. ANALIZA SINTACTICA
84
{
a = 2;
b = b + 1;
if ( b-a ) then { x = x-1;
a = 3 };
c = b*72
}
Figura 4.3: Program sursa de analizat sintactic
4.1.3
Programarea unui analizor sintactic top-down fara reveniri se poate face relativ
usor asociind cate o functie la fiecare neterminal. Analiza unui cuvant revine
la un sir de apeluri corespunzatoare tratarii simbolurilor ce apar pe parcursul
constructiei derivarii extrem stangi. Fiecare functie asociata contine o singura
instructiune switch cu clauze ce corepund regulilor gramaticii. Alegerea regulii
se face dupa urmatoarea unitate lexicala din textul de analizat.
Sa consideram urmatoarea gramatica (vezi figura 4.2) ce genereaza un bloc
de instructiuni de atribuire, conditionale de tip if (expresie aritmetica) then
instructiune sau repetitive de tip while. Instructiune poate fi o instructie simpla
sau bloc de instructiuni separate prin delimitatorul ;(SEMICOLON).
Un text sursa ce poate fi analizat de aceasta gramatica este cel din figura 4.3.
Lista de unitati lexicale furnizate de analizorul lexical este pentru acest caz
LBRACE id LET num SEMI id LET id PLUS num SEMI if LPAR id MINUS id
RPAR then LBRACE id LET id LET id minus num SEMI id LET num RBRACE
SEMI id LET id ORI num RBRACE.
85
S uXv uv u
P rim() = {a VT |a, VG }
N U LL(G) = {X VN |X }
Daca un terminal a P rim() atunci a poate aparea pe prima pozitie ntr-un
sir derivat din . Multimea SD(X, ) poarta denumirea de multimea simbolurilor
directoare asociate regulii X , iar N U LL(G) contine neterminalele ce se pot
sterge (n unul sau mai multi pasi) cu reguli din G.
Teorem
a.
G LL(k) SD(X, ) SD(X, ) = , X , X P, 6=
CAPITOLUL 4. ANALIZA SINTACTICA
86
bloc()
eat(LBRACE);
lista()
instr()
eat(id);
eat(LET);
E()
T()
F()
eat(num);
return_F;
Tprime()
return_Tprime;
return_T;
Eprime()
return_Eprime;
return_E;
return_instr;
L()
eat(SEMI)
instr()
.... aici se recunoaste ; b = b + 1
return_instr;
L()
eat(SEMI);
instr()
.... aici se recunoaste ; if ( ... }
return_instr;
L()
.... aici se recunoaste ; c = b * 72
return_L();
return_L;
return_L;
return_lista;
eat(RBRACE);
return_bloc;
Figura 4.5: Executia analizei lexicale pentru textul sursa
87
CAPITOLUL 4. ANALIZA SINTACTICA
88
P rim(X) =
P rim(X)
dac0 a X
/ N U LL(G)
P rim(X) P rim() dac0 aX N U LL(G)
N U LL P rim
U rm
(, i
)
DA
+,
)
,
(, i +, , )
DA
, / +, , )
(, i
, /, )
89
CAPITOLUL 4. ANALIZA SINTACTICA
90
Se opreste analiza sintactica n punctul unde s-a depistat o eroare, cu transmiterea unui mesaj prietenos catre utilizator, de exemplu: Eroare sintactic
a: asteptam sa urmeze delimitator de instructiune. Mai nvat
a sintaxa
limbajului! BYE!.
Se ncearca repararea greselii de sintaxa inserand n textul sursa un simbol
din multimea de simboluri directoare asociate regulii ce s-a aplicat. Desigur
ca este suficient sa presupunem ca am inserat n text, astfel ncat analiza
poate continua (desigur nu vom uita sa anuntam utilizatorul ca nu cunoaste
regulile de sintaxa si l-am corectat noi!). Inserarea poate conduce la cicluri
infinite, astfel ca nu este recomandabila totdeauna.
Se ncearca gasirea unui simbol ce se potriveste ignorand toate terminalele
textului sursa pana se ntalneste un simbol din multimea simbolurilor directoare. Se transmite acelasi mesaj prietenos catre autorul textului sursa,
apoi se continua analiza.
4.2
4.2.1
Algoritmi BOTTOM-UP
Gramatici cu precedent
a simpl
a
adica un cuvant peste alfabetul general VG astfel ncat x0 p. Vom nota cu Ax0 ,p
arborele de derivare care are radacina x0 si frontiera p.
Definitia 1. Vom spune ca f este o fraza simpla a lui p daca f este un
subcuvant al lui p si n plus:
x VN , cu x f P;
Ax,f Ax0 ,p .
Exemplu. Consideram gramatica GE 4.2.9 si forma propozitionala p = T F +
a (E + T ). Arborele de derivare este prezentat n figura 4.6. Se poate observa
ca frazele simple sunt T F, a, E + T .
Observatie. Subcuvantul F respecta prima conditie dar nu este fraza simpla,
ntrucat nu este satisfacuta conditia a doua din definitie.
Definitia 2. Fraza simpla cea mai din stanga poarta denumirea de fraz
a
simpla stang
a.
Vom nota fraza simpla stanga corespunzatoare lui p cu fp n exemplul nostru,
fp = T F . Dupa cum vom vedea n continuare, fraza simpla stanga are un
rol important n algoritmii de analiza sintactica bottom-up. In principiu, acesti
algoritmi prevad urmatorii pasi (descrisi de figura 4.7):
Regulile determinate la pasul (3), aplicate n ordine inversa, ne vor da derivarea
corespunzatoare lui p. Sa mai observam ca n acest mod arborele de derivare se
91
T
F
F
+
(1) Initializare p;
(2) Se determina fp , fraza simpla stanga a lui p;
(3) Se determina regula x fp ;
(4) Se reduce fraza simpla stanga, adica daca p = rfp s, se pune p = rxs;
GOTO(2).
Figura 4.7: Algoritmul bottom-up
CAPITOLUL 4. ANALIZA SINTACTICA
92
construieste de jos n sus (bottom-up). Problema cea mai dificila este desigur
determinarea frazei simple stangi de la pasul (2). In principiu ar trebui cunoscut
anticipat arborele de derivare corespunzator lui p, dar tocmai acesta este scopul
analizei sintactice. Dupa cum vom vedea, aceasta dificultate se poate elimina,
deci putem determina fraza simpla stanga fara a cunoaste acest arbore. De fapt,
fraza simpla stanga este legata de anumite proprietati ale gramaticii pe care le
tratam n continuare.
4.2.2
Relatii de precedent
a
daca xi xj
daca xi xj
Exemplu. Consideram urmatoarea gramatica
93
Matricea de precedenta va fi
A B
A
B
0
1
4.2.3
0 1
Propriet
ati ale gramaticilor cu precedent
a simpl
a
a1 a2 a3 a4
ceea ce contrazice relatia (*), conform careia a3 a4 iar gramatica are precedenta
simpla.
Observatie La delimitarea frazei simple stangi se procedeaza astfel: parcurgem
sirul de simboluri de la stanga la dreapta pana se gaseste relatia (sau marginea
dreapta a formei propozitionale) pentru determinarea ultimului simbol din fp ,
apoi se parcurge sirul spre stanga, trecand peste relatii , pana la gasirea unei
CAPITOLUL 4. ANALIZA SINTACTICA
94
a1 a2 a3
a4
a5
a6
a7
a1 a2 a3
a4
a4
a6
a7
a6
a7
(b)
(a)
a1 a2 a3
a5
a5
a6
a1 a2 a3
a7
a4
a5
(d)
(c)
x0
a1
a2
...
an
95
obtine arborii A0x0 ,q si Ax0 ,q unde q = rXs iar cei doi arbori trebuie sa fie diferiti.
Dar numarul de noduri interne este ni, n contrazicere cu ipoteza.
4.2.4
Asa cum s-a precizat deja, relatiile de precedenta sunt proprietati intrinseci ale
gramaticii, nu depind de contextul n care se afla cele doua simboluri. Prin urmare, cunoasterea anticipata a acestor relatii mpreuna cu proprietatea 1, rezolva
complet problema pasului 2 de la algoritmul de analiza bottom-up, adica determinarea frazei simple stangi. In acest subparagraf vom prezenta o teorema de
caracterizare pe baza careia se pot determina relatiile de precedenta simple si
implicit faptul daca gramatica este sau nu cu precedenta simpla.
Vom defini doua relatii specifice gramaticilor si care vor fi utilizate n continuare, numite, respectiv, F (First) si L (Last). Fie x VN si y VG doua
simboluri ale gramaticii. Vom spune ca
xF y daca x yu P, u VG
xLy daca x uy P, u VG
Inchiderile tranzitive, respectiv, tranzitive si reflexive ale acestor relatii le vom
nota cu F + , L+ si respectiv, F , L . Exista numerosi algoritmi directi care
permit calcularea acestei nchideri,cu complexitate redusa.
Teorema 2. Avem
(1) x y u . . . xv . . . P, vF + y;
(2) x y u . . . xy . . . P;
(3) x y u . . . vw . . . P, vL+ x, wF y;
Schita de demonstratie. Se analizeaza posibilitatile de arbori de derivare care
raspund cerintelor teoremei. De exemplu, pentru cazul (1), trebuie sa existe
structura de arbore ca n figura 4.10.
Este clar ca daca x y, atunci conform definitei frazei simple stangi, trebuie sa existe p astfel ncat p = rxys, x
/ fp , y fp , adica sa existe structura din 4.10. Invers, daca exista o astfel de structura, atunci fie o forma
propozitionala care contine u. Efectuam reduceri succesive pana cand vom obtine
o forma propozitionala pentru care u apartine frazei simple stangi; la arborele
astfel obtinut, adaugam subarborele de mai sus. Vom avea n mod evident
x
/ fp , y fp .
4.2.5
Studiu de caz
CAPITOLUL 4. ANALIZA SINTACTICA
96
u
v
Ramificatii
spre dreapta
... x
...
E
T
F
+
(
)
a
F +
) a
E E + T |T
T T F |F
F (E)|a
E L+ {T, F, a, )}
T L+ {F, a, )}
F L+ {a, )}
E F {E, T, F, a, )}
T F {T, F, a, )}
F F {F, a, )}
G:
A A0 | B1
B1
97
S
S
a
b
a b
F orma propozitionala
a a a b aababbbabb
S ab
a a S a a b abbbabb
S ab
a a S a S a b bbabb
S ab
a a S a S S b babb
S aSSb a a S S b abb
S aSSb a S a b b
S ab
aSSb
S aSSb S
Figura 4.13: Reconstructia derivarii cuvantului p = aaabaababbbabb
Deci gramatica GE nu are proprietatea de precedenta simpla, astfel ca nu
poate fi aplicat direct algoritmul de analiza sintactica bottom up.
Vom exemplifica algoritmul de analiza pentru gramatica din figura 4.12, matricea de precedenta asociata este cea alaturata.
Reconstituirea derivarii cuvantului p = aaabaababbbabb este prezentata n
tabelul 4.13, unde fiecare linie corespunde formei propozitionale, n care fraza
simpla stanga este subliniata, precedata de regula identificata.
4.2.6
Gramatici operatoriale
CAPITOLUL 4. ANALIZA SINTACTICA
98
p(/), ceea ce nseamna ca mai ntai se fac adunarile si scaderile, apoi nmultirile
si mpartirile, etc. Efectuarea unei operatii depinde de contextul n care se afla
operatorul respectiv, si anume, daca ponderea operatorului precedent este mai
mare sau egala cu ponderea operatorului curent, atunci se poate efectua operatia
definita de operatorul precedent. Din acest motiv, acest tip de gramatici se
numesc cu operator de precedent
a (operator precedence grammars).
Putem realiza un algoritm simplu de evaluare utilizand doua stive
P- stiva operatorilor;
S- stiva operanzilor.
Vom utiliza indicii i si k pentru a indica nivelele celor doua stive. Prin urmare,
notatia pi , respectiv sk au sensul de operatorul, respectiv operandul din stiva aflat
pe nivelul i, respectiv k. Pentru simplificare, vom utiliza aceiasi notatie pi atat
pentru operator cat si pentru ponderea operatorului respectiv.
Algoritmul de evaluare:
PAS 1: Initializ
ari: Se introduce primul operator si primul operand n stivele P
si S si se initializeaza nivelele celor doua stive, i = k = 2;
PAS 2: Se introduce urmatorul operator n stiva P si se actualizeaza nivelul,
i = i + 1;
PAS 3: Daca pi1 < pi atunci se introduce urmatorul operand n lista S, se
actualizeaza nivelul stivei, k = k + 1, si se revine la pasul 2;
PAS 4: Daca pi1 pi atunci:
n stiva P : pi1 se nlocuieste cu pi ;
n stiva S: sk1 se nlocuieste cu sk1 pi1 sk ;
se actualizeaza nivelele celor doua stive, i = i 1; k = k 1 si se revine la
pasul 3.
Observatie. Pentru uniformitatea algoritmului se introduce operatorul marcaj, notat cu # , cu ponderea cea mai mica; orice expresie se ncadreaza ntre doua
marcaje iar oprirea algoritmului are loc la pasul 4 n cazul n care p1 = p2 = #.
Schematic, acest algoritm este prezentat n figura 4.14.
Exemplu. Tabelul 4.15 contine starea dinamica a celor doua stive pentru
expresia #a + b c/d f #. Mentionam ca n cadrul pasilor 2 si 4 s-a completat
cate un rand nou n tabel.
Observatie. Ponderile operatorilor sunt legate de ierarhia lor n gramatica, cu
cat un operator este mai jos cu atat ponderea lui este mai mare. Acest fapt este
ilustat n figura 4.16.
Pentru cazul expresiilor aritmetice cu paranteze algoritmul se pastreaza, dar
este aplicat dupa preprocesarea expresiei prin modificarea dinamica a ponderilor operatorilor si renuntarea la paranteze. Se parcurge expresia de la stanga la
dreapta alocand ponderi operatorilor; la ntalnirea unei paranteze deschise ponderile se incrementeaza cu 10, iar la ntalnirea unei paranteze nchise se decrementeaza ponderile operatorilor cu 10. In continuare parantezele sunt ignorate.
99
p1
1.
s1
i=2, k=2
pi
2.
p i-1
i=i+1
sk
s k-1
3.
p i-1 < p i
k=k+1
p i-1 p i
4.
p i-1
pi
s k-1
inainte de
prelucrare
sk
dupa
prelucrare
s k-1 p i-1 s k
pi
i=i+1, k=k+1
1
2
3
4
5
6
7
8
9
10
1
#0
#0
#0
#0
#0
#0
#0
#0
#0
#0
2
+1
+1
1
1
1
1
1
1
#0
1
2
2 /2
/2
/2 #0
#0
1
a
a
a
a+b
a+b
a+b
a+b
a+b
a+b
a + b c d/f
2
b
b
c
c
c
cd
cd
c d/f
3 4
d
d
f
f
CAPITOLUL 4. ANALIZA SINTACTICA
100
E +T
E + T
T
T * F
p(+)<p(*)
T * F
p(*)>p(+)
4.2.7
Gramatici operatoriale
101
Ni
N i+1
Tj
N' j+1
N j+1
0
0
(1) x Ni0 Ti Ni+1
Ti+1 . . . Tj Nj+1
P, si Nk0 Nk k = i, . . . , j.
(2) Ax,f Ax0 ,p .
Structura de arbore corespunzatoare unei fraze simple este prezentata n figura
4.17.
Ca si n cazul gramaticilor cu precedenta simpla, fraza simpla cea mai din
stanga poarta denumirea de fraz
a simpla stang
a. Principiul de analiza sintactica
este identic cu cel de la gramatici cu precedenta simpla. Problema principala
este si aici determinarea frazei simple stangi. Aceasta operatie poate fi facuta
utilizand relatiile de precedenta dintre simbolurile gramaticii care pentru gramatici operatoriale au o definitie putin modificata.
Definitia 3. Fie x, y VT . Vom spune ca:
CAPITOLUL 4. ANALIZA SINTACTICA
102
Ramificatii
spre dreapta
N 1 T 1 N 2 T 2 N' 3 T 3 N' 4 T 4
N3
N' 5 T 5
N5
N4
Ramificatii
spre dreapta
N 1 T 1 N 2 T 2 N' 3
T 3 N' 4 T 4 N' 5 T 5
N3
N4
N5
(b)
(a)
<
<
rezulta T2 <T3 =T4 =T5 >T6 . Mai trebuie sa aratam ca T1 <T2 sau T1 =T2 . In acest
scop analizam structurile posibile de arbori (figura 4.18).
pentru cazul (a) si T1 =T2 pentru cazul (b). Pentru implicatia inversa presupunem
ca fp = Nk Tk Nk+1 Tk+1 . . . Tl Nl+1 , l 6= j, k 6= i si consideram toate cazurile de
pozitionare a indicilor k, l n raport cu i, j. De exemplu, daca l < j atunci, n
ipoteza, avem Tl <Tl+1 sau Tl =Tl+1 ceea ce contrazice ipoteza initiala conform
careia gramatica este cu precedenta simpla.
Proprietatea 2. O gramatica operatoriala cu precedenta simpla este neambigua.
Schita de demonstratie. Fie p o forma propozitionala si Ax0 ,p arborele de
derivare corespunzator. Vom arata ca acest arbore este unicul arbore de derivare
care are radacina x0 si frontiera p. Procedam prin inductie asupra numarului de
noduri interne ni. Daca ni = 1 atunci arborele de derivare va avea forma din
figura 4.19 si unicitatea acestuia este evidenta. Presupunem acum ca proprietatea
103
x0
N1 T1
...
Tn
Nn
4.2.8
+
y;
(1) x<y u . . . xv . . . P, vF1,2
(2) x=y u . . . xN y . . . P;
CAPITOLUL 4. ANALIZA SINTACTICA
104
v
N' i
Ni
N' j+1
N j+1
4.2.9
Studiu de caz
E E + T |T
T T F |F
F (E)|a
{E, T, F, +, , (, a}
{E, T, F, +, , (, a} E F1,2
E F1,2 {E, T, +} E F1,2
+
T F1,2 {T, F, , (, a}
T F1,2 {T, F, } T F1,2 {T, F, , (, a}
+
{F, (, a}
{(, a}
F F1,2
F F1,2 {(, a}
F F1,2
E L1,2 {T, +}
T L1,2 {F, }
F L1,2 {a, )}
E L+
1,2 {T, +, F, , a, )}
T L+
1,2 {F, , a, )}
F L+
1,2 {a, )}
{E, T, +, F, , a, )}
E F1,2
T F1,2 {T, F, , a, )}
{F, a, )}
F F1,2
+ >
>
( <
) >
a >
105
( ) a
>
>
>
>
F orma propozitionala
a> + <(a + a) a a
F a
F + <(<a> + a) a a
F a
F + <(<F + <a>) a a
F a
F + <(<F + F >) a a
T T F ,T F
F + <(T =)> a a
F (E) , E T
F + <F <a> a
F a
F + <F F > a
T T F ,T F
F + <T < <a
F a
F + <T F
T T F
F +T
E E T ,E T ,T F E
Figura 4.22: Reconstructia derivarii cuvantului p = a + (a + a) a a
Conform teoremei de calcul a relatiilor de precedenta vom obtine matricea de
precedenta (vezi figura 4.21) asociata simbolurilor gramaticii GE .
Deci gramatica GE are proprietatea de precedenta operatoriala simpla, astfel
ca se poate aplica direct algoritmul de analiza sintactica bottom up.
Reconstituirea derivarii cuvantului p = a + (a + a) a a este prezentata
n tabelul 4.22, unde fiecare linie corespunde formei propozitionale, n care fraza
simpla stanga este subliniata, precedata de regula identificata.
106
Capitolul 5
Sinteza Programelor
5.1
5.1.1
Compilatoarele prelucreaza un numar important de informatii, variabile de diverse tipuri, date organizate n anumite structuri standard sau definite de utilizator, etc. De cele mai multe ori aceste informatii sunt stocate n tabele si memorate
pe suporturile de informatii ale sistemului. Organizarea si prelucrarea tabelelor
constituie o problema distincta, cu infuenta importanta asupra performantelor
unui compilator, mai ales daca acestea sunt memorate pe un suport extern. In
cele ce urmeaza vom prezenta pe scurt principalele tabele utilizate n mod obisnuit
n cadrul unui compilator si modul de organizare a informatiilor stocate n aceste
tabele. Mentionam ca structura acestor tabele este definita de proiectantul de
compilator si ca prin urmare exista un anumit grad de subiectivitate n modul de
organizare al acestora.
Tabelul de variabile. Contine variabilele utilizate ntr-un program si informatii asupra lor. Mentionam ca variabilele contin datele prelucrate de
program, n conformitate cu tipul acestora, continut care se modifica n
mod dinamic pe parcursul evolutiei programului. Informatiile din fiecare
linie a tabelului pot fi:
numele variabilei; asa cum s-a precizat la analiza lexicala, numele unei
variabile este de obicei un sir de caractere, litere sau cifre, primul
caracter trebuind sa fi o litera.
tipul variabilei; relativ la tipurile de variabile utilizate n programare
trebuie sa facem mentiunea ca acestea depind n mod esential de domeniul de aplicabilitate al limbajului. De exemplu, pentru un limbaj de
tip matematic (Pascal), tipul unei variabile este caracterizat n general
de trei atribute: structura (scalar, tablou), calitatea (intreg, flotant,
107
108
109
unde adr0 este adresa de nceput a zonei, c este lungimea elementelor iar i
numarul de ordine al variabilei temporare. Se poate adopta un sistem de
alocare dinamica a variabilelor temporare n scopul economisirii memoriei.
Tabelul de constante. Contine constantele de diverse tipuri utilizate ntr-un
program. In general este un tabel de mai mici dimensiuni, de aceea nu
comporta probleme deosebite de organizare si prelucrare.
5.1.2
Cvadruple si triplete
, a, b, t1
+, c, d, t2
/, t2 , e, t3
+, t1 , t3 , t4
110
Text Sursa
Cvadruple
a+b
+,a,b,t, idem -,*,/
a=b
=,a,b,
goto i
BR, i, ,
if (a==b) then BE, a,b, n
Figura 5.1: Exemplu de codificare prin cvadruple
Expresie logica
rezultatul in t
Expresie
fals
r,a,b, n
adevarat
Instructie
Bloc
Instructie
Bloc
if,_,_,_
(b) Cvadruple
111
Semantica acestei instructii este prezentata n figura 5.2. Mentionam ca expresie logica va avea forma particulara E1 rE2 , unde r este un operator relational.
In figura (a) prezinta schema logica a instructiei iar (b) cvadruplele corespunzatoare. Partea de cod corespunzatoare expresiei logice va stoca valoarea
(logica ) a expresiei ntr-o variabila temporara t; aceasta valoare va fi utilizata n
instructia de salt, n conformitate cu tipul de salt prevazut n programul sursa (<,
=, etc.). In consecinta, cvadrupul de salt r va trebui sa prevada aceasta variabila
temporara, plus numarul de ordine n al primului cvadruplu care urmeaza dupa
cvadruplele corespunzatoare instructiei sau blocului. De exemplu, acest cvadruplu poate avea urmatoarea forma r, a, b, n unde n este numarul cvadruplului la
care trebuie sa se faca saltul.
Triplete
Este o alta posibilitate de format intermediar, asemanator cu cvadruplele, singura deosebire fiind accea ca nu se prevede explicit o variabila temporara pentru
stocarea rezultatului. Prin urmare, tripletul corespunzator unei operatii binare
de forma A op B va fi op, A, B. In cazul n care ca operand al unui triplet
trebuie specificat rezultatul unui triplet anterior, se va scrie numarul de ordine
al tripletului respectiv.
Exemplu. Pentru secventa de program xx = a b + (c + d)/e sirul de triplete
generat va fi
(1)
(2)
(3)
(4)
(5)
, a, b
+, c, d
/, (2), e
+, (1), (3)
=, xx, (4)
Notatia polonez
a
Notatia poloneza a fost introdusa initial pentru a se putea evalua expresii aritmetice printr-o singura parcurgere secventiala. Din punctul de vedere al proiectarii
compilatoarelor, aceasta notatie poate fi utilizata ca un format intermediar al
programelor, n mod special pentru limbajele de programare algoritmice, Fortran, Pascal. In continuare vom ilustra ideea de evaluare secventiala a expresiilor
aritmetice printr-un exemplu.
Consideram expresia aritmetica ab+(cde)f . Ideea sirului polonez consta
n scrierea operanzilor si a operatorilor acestei expresii (fara a utiliza paranteze)
ntr-un sir cu urmatoarea proprietate: se parcurge sirul secvential de la stanga la
dreapta si fiecare operator ntalnit provoaca efectuarea operatiei respective ntre
cei doi operanzi din fata, n ordinea aparitiei lor. Pentru exemplul considerat, un
112
a a*b
b
c
d
e
a*b a*b
c
c-d*e
d*e
f
a*b
(c-d*e)*f
a*b+(c-d*e)*f
E E + T |T
T T F |F
F a
113
Acelasi limbaj al expresiilor aritmetice fara paranteze poate fi generat cu o gramatica cu un singur neterminal, fie acesta A, si avand regulile
A A + A|A A|a
Dar n acest caz trebuie introduse alte conventii pentru a preciza ordinea operatiilor;
de exemplu, pentru expresia a+bc, n acest ultim caz, nimic nu arata ca operatia
trebuie facuta nainte de +. Trebuie sa precizam ca prin considerarea a numai
doi operanzi nu se impune o constrangere asupra notiunii de expresie aritmetica,
foarte usor putem generaliza aceasta gramatica la un numar oarecare de operatori
binari, de exemplu
A1 A1 op1 A2 |A2
A2 A2 op2 A3 |A3
etc.
De asemenea, putem considera operatori de n-aritate oarecare precum si reguli
de rescriere n concordanta cu sintaxa pe care dorim sa o satisfaca acestia. Utilizarea unor paranteze pentru a indica o anumita ordine de efectuare a operatiilor,
iarasi nu difera esential de cazul expresiilor fara paranteze. Putem folosi algoritmul de modificare dinamica a ponderilor descris la gramatici operatoriale: parcurgem expresia de la stanga la dreapta si atasam fiecarui operator ponderea sa;
n momentul n care ntalnim o paranteza deschisa, marim toate ponderile cu o
constanta mai mare decat cea mai mare pondere iar la ntalnirea unei paranteze
nchise, scadem aceasta constanta. Apoi eliminam toate parantezele. Este evident ca n acest fel operatiile din interiorul parantezelor vor avea prioritatae mai
mare, mergandu-se spre parantezele din interior.
Definitia 3. Fie Gp = (VN , VT , x0 , P), unde VN = {A}, VT = {a, +, },
x0 = A iar regulile sunt
A AA + |AA |a
Orice cuvant p L(Gp ) va fi numit sir polonez. Este natural ca aceste
siruri poloneze sa fie puse n legatura cu expresiile aritmetice fara paranteze
prezentate mai sus. Gramatica Gp nu stabileste o ordine intrinseca de efectuare
a operatiilor, ntocmai ca si gramatica cu un singur neterminal de generare a
expresiilor. Convenim nsa ca aceasta ordine sa fie cea secvential
a.
Daca p L(Gp ) atunci convenim sa notam cu aes(p) cuvantul obtinut din p
cu ajutorul algoritmului de evaluare secventiala.
Urmatoarea teorema stabileste legatura ntre cele doua entitati.
Teorem
a. Pentru orice cuvant e L(Gexp ) exista un pe L(Gp ) astfel ncat
aes(pe ) = e.
Demonstratie. Procedam prin inductie asupra numarului n de operatori din
e. Daca n = 1 atunci e = a + b sau e = a b si sirul polonez care satisface conditia
din teorema va fi pe = ab+ sau pe = ab. Sa presupunem ca proprietatea este
114
E
E
T
E
T
T
e1
e2
(a)
e1
(b)
5.2
115
5.2.1
Generarea cvadruplelor
E E + T |E T |T
T T F |T /F |F
F (E)|a
116
Regula
(1) E1 E2 + T
(2) E1 E2 T
(3) E T
(4) T1 T2 F
(5) T1 T2 /F
(6) T F
(7) F (E)
(8) F a
Cvadruplu
Sens
+, S(E2 ), S(T ), ti S(E1 ) = ti
, S(E2 ), S(T ), ti S(E1 ) = ti
S(E) = S(T )
, S(T2 ), S(F ), ti S(T1 ) = ti
/, S(T2 ), S(F ), ti S(T1 ) = ti
S(T ) = S(F )
S(F ) = S(E)
S(F ) = Adr(a)
E,t
T,t
T,t
T,d
T,t
F,t
F,t
E,t
E,e
F,c
F,d
c
(
E,a
E,t
T,e
T,b
T,f
F,f
F,e
T,a
F,b
f
e
F,a
b
a
Regula
(1) E1 E2 + T
(2) E1 E2 T
(3) E T
(4) T1 T2 F
(5) T1 T2 /F
(6) T F
(7) F (E)
(8) F a
117
Cvadruplu
Sens
+, S(E2 ), S(T ) S(E1 ) = (n)
, S(E2 ), S(T ) S(E1 ) = (n)
S(E) = S(T )
, S(T2 ), S(F ) S(T1 ) = (n)
/, S(T2 ), S(F ) S(T1 ) = (n)
S(T ) = S(F )
S(F ) = S(E)
S(F ) = Adr(a)
5.2.2
Generarea tripletelor
(1)
(2)
(3)
(4)
(5)
+, a, b
*, (1), c
-, e, f
*, d, (3)
-, (2), (4)
118
(1)
(2)
(3)
(4)
(5)
(6)
(7)
(8)
Regula
E E+T
E ET
ET
T T F
T T /F
T F
F (E)
F a
Notatia poloneza
pi = +
pi =
pi =
pi = /
pi = Adr(a)
5.2.3
Textul sursa
Regula aplicata
a * b + (c - d * e) * f F a
F * b + (c - d * e) * f F b
F * F + (c - d * e) * f T T F, T F
T + (c - d * e) * f
F c
T + (F - d * e) * f
F d
T + (F - F * e) * f
F e
T T F, T F
T + (F - F * F) * f
T + (F - T) * f
E E T, E T, T F
T + (E) * f
F (E)
F f
T+F*f
T+F*F
T T F, T F
T+T
E E + T, E T
E
119
Notatia poloneza
a
ab
ab*
ab*c
ab*cd
ab*cde
ab*cde*
ab*cde*ab*cde*ab*cde*-f
ab*cde*-f*
ab*cde*-f*+
ab*cde*-f*+
120
+ b
11
* c
3
/ d
14
- e
22
- f
12
Intrare
(Expresie aritmetica )
Iesire
(Sir polonez )
Varful stivei
Stiva
5.3
5.3.1
to fill
5.3.2
Instructiunea If
to fill
5.3.3
to fill
Variabile indexate
122
ab*cde*-f*+
a*b+( c-d*e)*f
2 *
4
3
2
*
(
Capitolul 6
Masina Turing
6.1
124
G : S uv p.
125
u = u1 X1 u2 X2 u3 X2 u4 u1 Y1 Z1 u2 Y2 Z2 u2 Y2 Z3 u4 = v,
unde u1 , u2 , u3 , u4 VN . In G0 putem scrie
S 0 S 0 X2 S 0 X2 X2 S 0 X1 X2 X2 S X1 X2 X2
uX1 X2 X2 = u1 X1 u2 X2 u3 X2 u4 X1 X2 X2 u1 X1 X1 u2 X2 X2 u3 X2 X2 u4
u1 Y1 Z1 u2 Y2 Z2 u3 Y2 Z2 u4 = v p
G0
G0
Invers, fie p L(G0 ), deci S 0 p. Daca n derivarea S 0 p apar simbolurile X1 , X2 ele nu pot aparea dacat n urma aplicarii regulilor S 0 S 0 X1
si S 0 S 0 X2 , deci la nceputul derivarii, apoi singura posibilitate de continuare
este S 0 S; de asemenea, aceste simboluri nu pot fi eliminate decat cu regulile
X1 X1 Y1 Z1 si X2 X2 Y2 Z2 , etc. Astfel derivarea noastra trebuie sa aiba
126
p=i 1i 2i 3i 4i 5, n=4
i1
i2
i3
i4
i5
s S
Dispozitiv de comanda
6.2
Masina Turing
Conceptul de masin
a Turing. Masina Turing este un mecanism de recunoastere
a limbajelor de tipul zero. In felul acesta, familiilor de limbaje din clasificarea
Chomsky le corespund automate specifice de recunoastere.
Familia L3 - automate finite,
Familia L2 - automate pushdown,
Familia L1 - automate liniar marginite,
Familia L0 - masina Turing.
O masina Turing (prescurtat MT) se compune dintrun dispozitiv de comanda
care poseda un dispozitiv de scrierecitire si o banda de intrare. Banda de intrare
se considera marginita la stanga si nemarginita la dreapta; ea contine simboluri
ale unui alfabet de intrare, ncepand din prima pozitie. Alfabetul are un simbol special numit blanc si notat [ (sau spatiu), care se considera nregistrat n
toata partea neocupata a benzii. Indicele simbolului din dreptul dispozitivului de
scrierecitire l notam cu n si el va constitui un element al starii masinii Turing.
Dispozitivul de comanda se afla ntr-o anumita stare interna, element al unei
multimi finite de stari.
Schema unei masini Turing este data n figura 6.1. O masina Turing functioneaza
n pasi discreti. Un pas de functionare consta din:
Dispozitivul de comanda citeste simbolul aflat n dreptul dispozitivului de
scrierecitire; n functie de simbolul citit, masina Turing trece ntr-o noua stare
interna, scrie pe banda un nou simbol (ntotdeauna diferit de blanc) n locul
simbolului citit si muta banda cu o pozitie (spre stanga sau dreapta) sau o lasa
127
128
s0
s1
(s2 , 1, 1)
(s1 , 0, 1)
(s0 , 1, 1) (s0 , 0, 1)
s2
(s0 , 0, 1)
129
2)s0 (i1 , i1 ) . . . (in , in )(, [)m (i1 , i01 ) . . . (ik1 , i0k1 )sf (ik , i0k ) . . . (in+m , i0n+m ),
unde
130
i"1
i"3
i"2
...
i"g
i"1
i"3
i"2
...
i"g
s
h=g
h= g+1
s0 (i1 , i1 ) . . . (in , in )(, [)m (i1 , i001 ) . . . (ij1 , i00j1 )s(ij , i00j ) . . . (in+m , i00n+m ).
In conformitate cu definitia evolutiei directe avem
f (s, i00j ) = (sf , i0j , 1), k = j + 1, s(ij , i00j ) (ij , i00j )sf ;
f (s, i00j ) = (sf , i0j , 1), k = j 1, (ij1 , i00j1 )s(ij , i00j ) sf (ij , i00j1 )(ij , i0j ).
In ambele cazuri
s0 (i1 , i1 ) . . . (in , in )(, [)m (i1 , i01 ) . . . (ik1 , i0k1 )sf (ik , i0k ) . . . (in+m , i0n+m ).
Acum, deoarece sf f , putem scrie
sf i1 sf i2 sf . . . sf in sf i1 . . . in = p.
Prin urmare p L(G) si L(M T ) L(G). Analog se arata si incluziunea inversa
si deci L(M T ) = L(G).2
Bibliografie
1. Octavian C. Dogaru, Bazele informaticii. Limbaje formale, Tipografia Universitatii din Timisoara, 1989.
131