Documente Academic
Documente Profesional
Documente Cultură
TEORIA COMPILATOARELOR
Compilator: este un program care analizeaza codul sursa si ne arata erorile existente.
TABELUL DE SIMBOLURI
TRATAREA ERORILOR
Analiza lexicala: descopera in textul sursa, siruri de caractere cu reguli precise de formare numite
atomi lexicali (identificatori, constante, operatori).
exemplu:
val_fin=val_p+TVA*20 (id=identificator)
↑ = ↑ + ↑ *20
id1 = id2 + id3*20
Analiza sintactica: descopera in sirul atomilor lexicali structuri sintactice ca proceduri, expresii etc. pe
care le aseaza in arborele sintactic pentru a reflecta relatiile dintre ele.
:=
/ \
id1 +
/ \
id2 *
/ \
id3 20
Analiza semantica: completeaza arborele sintactic facand alte verificari ce nu au putut fi efectuate
anterior. Una dintre verificari se refera la conversia tipului de date.
1
TEORIA COMPILATOARELOR
:=
/ \
id1 +
/ \
id2 *
/ \
id3 int→real
\
20
Generarea codului intermediar: este o secventa de instructiuni de format fix, asemanatoare cu cele ale
calculatorului. Operanzii sunt variabile din program, utilizate la calculele intermediare.
t1:=int – real(20)
t2:=id3 * t1
t3:= id2 * t2
id1:=t3
Tabela de simboluri: colecteaza informatii despre numele simbolurilor intalnite in program. Aceste
informatii se refera la numele identificatorilor si la atribute.
Tratarea erorilor: se refera la eventuala apelare a unui set de proceduri care incearca sa repare o parte
dintre erori. Trebuie sa indice tipul de eroare intalnita si locul unde se afla ea. Compilatorul poate fi definit ca
o functie: - ∑*, traducere de intrare;
f: ∑* → Δ* , unde
Δ*, traducere de iesire
-
O traducere se noteaza cu T: T∑** Δ* (x,y)T, iar y=(x)
2
TEORIA COMPILATOARELOR
exemplu:
Fie arborele: S supus urmatoarei reguli:
/ | \ S→oAS, SAo
o A S
arborele va deriva in:
S
/ | \
S A o
Alte dispozitive de traducere sunt traducatoarele finite, care sunt automate finite. Un traducator finit se
defineste astfel:
F=(Q, ∑, Δ, , qo, F), unde F este multimea starilor finale.
O configuratie de forma: (q, x, y), unde
- q: starea
- x: ce a mai ramas de citit
data prin: (q, ax, y)├ (p, x, yz), daca (q, a) (p, z), atunci
(F)={(x, y) / (qo, x, ) ├* (q, , y), qF, x∑*, y Δ*}
traducatoarele finite se utilizeaza in analiza lexicala.
Traducatoarea Pushdown
Fie T = (Q, ∑, P, Δ, , qo, zo, F), unde zo: este simbolul initial si
=Q × (∑{}× P→Pf(Q, P* × Q*), atunci configuratia va fi de forma:
(q, x, , y), unde y este continutul benzii de iesire. Trecerea se realizeaza astfel:
(q, ax, z, y) ├ (p, x, , yz), daca: (q, a, z) (p, , z)
si
(P) = {(x, y) / (qo, x, zo, ) ├* (q, , , y), q F}
(P) = {(x, y) / (qo, x, zo, ) ├* (q, , , y), q F}
Traducatoarele Pushdown se utilizeaza in analiza sintactica. O schema de traducere orientata pe
sintaxa se numeste simpla, daca este in acceaasi ordine.
S→AdA bAdA
TEOREMA:
O traducere este realizata de o schema simpla, daca si numai daca este realizata de un traducator
Pushdown.
Analiza lexicala
3
TEORIA COMPILATOARELOR
exemplu:
IDENTIFICATOR
r a
lite
bla
t n k
cifra blank
INTREG t
INCEPUT
SFARSIT
pun
ct nk
bla
t
REAL
“
“
punct
t
TEXT
ceva”
In cazul unor gramatici complexe se recomanda stratificarea acestora, stratificare care consta in
impartirea gamaticii in mai multe subgramatici care vor fi analizate separat, isirea unui traducator fiind
intrarea altuia.
G1 <atom>:=<id> / <constanta> / <op> / <comentariu>
G3 <litera>:=A / B / ….. / Z / a / b / … / z /
<cifra>:=0 / 1 / … / 9
G3 G2 G1
4
TEORIA COMPILATOARELOR
O parte dintre productii se vor transforma din gramatici de nivel inferior in gramatici de nivel
superior, pentru a usura munca. Se vor stratifica mai intai neterminalele.
G1: <atom>
G2: <id>, <const>, <op>, <del>, <comentariu>
In gramaticile de nivel superior se vor considera ca terminale, neterminalele din gramaticile de pe nivel
inferior. In felul acesta, gramaticile putand deveni regulate.
ANALIZA SINTACTICA
Gramaticile LL(k) realizeaza analiza sintactica la stanga, decizia de extindere a arborelui de derivare
fiind luata privind k simboluri spre dreapta din cuvantul de analizat.
G = (N, ∑, P, S), wL(G) si Sw, arborele asociat acestei derivari
Teorema: Gramatica G=LL(k), daca si numai daca AN, astfel incat exista derivarea SwA si
pentru orice A→ si A→, productii distincte, rezulta ca PRIMk()PRIMk() = .
Definitie: Fie G si ( N∑ )*, atunci putem defini URMk() = {w / S si wPRIMk()}.
Definitie: Fie L1 si L2 limbaje peste un alfabet ∑. Definim L1 L2 = {w / xL1 si yL2 astfel incat:
a) w=xy, daca |xy| k
b) w este format din primele k simboluri
exemplu:
L1={, abb} si L2={b, bab}, atunci L1 L2 = {b, ba, ab}
Cu definitia anterioara PRIMk()=PRIMk() PRIMk(). Si conform acestei relatii si relatiei din
teorema va rezulta:
(PRIMk() k L) (PRIMk() k L) = , unde L = PRIMk()
5
TEORIA COMPILATOARELOR
Algoritmul PRIM
La intrare: G, k, α=x1, x2, …., xn
La iesire : PRIMk(α)
Metoda : PRIMk(α) = PRIMk(x1, x2, …., xn) = PRIMk(x1) PRIMk(x2) … PRIMk(xn)
PRIMk(a) = {a} pentru a∑u{}
P1: F1(a) = a, a∑u{}, i=0,1,…
P2: Fo(A) = {x∑* | (A→x α) P si |x| = k sau |x|<k si α=
P3: Fo, F1, …. Fi-1 ; Fi(A) = {x | x Fi-1(y1) k… k Fi-1(yn), daca (A→y1, y2, …, yn) P}
P4: daca Fi-1(A) = Fi(A), pentru orice A neterminal atunci iau PRIM k(A) = Fi(A), in caz contrar se
revine la P3
Algoritmul
La intrare: G, k
La iesire : (A), AN
Metoda : pentru A, BN se calculeaza (A, B) = {L∑* | AwBα si L=PRIMk(α)}
i(A, B), i=0,1,…
P1: o(A, B) = {L∑* | (AwBα)P si L=PRIMk(α)}
P2: o, 1, …, i-1 calculate pentru orice A, B si calculez i(A,B) astfel
a) ………………. Nu se vede …..
b) Daca (A→x1, x2, …, xn) P si oricare ar fi x astfel incat L’i-1(xj, B), atunci
L = L’ k PRIMk(xj+1…xn) i(A,B)
P3: daca i-1(A,B) = i(A,B) A, B x, atunci (A,B) = i(A,B)
P4: (A) = (S, A)
exemplu:
S→aAaB / bAbB
A→a / ab
B→aB / a
Sa aratam ca aceasta gramatica este LL(B).
Fi(x)={x} pentru x{a, b, ∑} i=0,1,…
Fo(x)= , Fo(A)={a, ab}, Fo(B)={a}
F1(S)= Fo(S) { Fo(a) 3 Fo(A) 3 Fo(a) 3 Fo(a)} Fo(B) 3 Fo(A) 3 Fo(b) 3 Fo(B)} = {a 3 {a, ab}
3 a 3 {a}} {b 3 {a, ab} 3 b 3 {a}} = {aaa, aab, bab}
.
.
.
PRIM3(S) = {aaa, aab, bab}
PRIM3(A) ={a, ab}
PRIM3(B) = {a, aa, aaa}
6
TEORIA COMPILATOARELOR
exemplu:
1. S→aAbc
2. A→BA
3. A→
4. B→dcCe
5. B→fa
6. C→cC
7. C→
PRIM1(aAbc) = {a}
PRIM1(BA) = {d,f}
PRIM1(∑) = {∑}
PRIM1(dcCe) = {d}
PRIM1(fa) = {f}
PRIM1(cC) = {c}
URM1(A) = {b}
URM1(B) = {b, ∑ }
URM1(C) = {c, ∑ }
Pentru B : PRIM1(dcCe) PRIM1(fa) = {d}{f} =
Pentru A : PRIM1(BA) URM1(A) = {d, f}{b} =
Pentru C : PRIM1(cC) URM1(C) = {c}{c, ∑} =
Analiza sintactica se face astfel:
a b c d e f ∑
S aAbc, 1
A , 3 BA, 2 B,A, 2
B dcCe, 4 fa, 5
a R
b R
c R
d R
e R
f R
$ A
C cC, b , f
Codul intermediar
Este format din instructiuni simple: operatii aritmetice, atribuiri, teste, salturi, care se executa in
ordinea in care se intalnesc. Din program lipsesc declaratiile, ele gasindu-se in tabela de simboluri.
Codul intermediar se prezinta sub urmatoarele forme:
- forma poloneza
7
TEORIA COMPILATOARELOR
- arbori sintactici
- cod cu 3 adrese
Forma poloneza este recomandata pentru limbajele care au multe expresii aritmetice si structuri de
control rudimentare. Se foloseste forma postfixata in care operatorii apar dupa operanzi. Are avantajul ca
evolueaza parcurgand expresiile o singura data de la stanga la dreapta si tinand seama de aritatea
operatorilor.
a*(b+c) abc + *
Operanzii se trec intr-o stiva si la intalnirea unui operator se extrag din stiva atatia operanzi cat indica
aritatea operatorului. Se efectueaza operatia si se trece rezultatul in varful stivei.
O forma poloneaza se defineste astfel:
1) orice operand este o expresie in forma poloneza
2) daca e1, e2, …, en este o forma poloneza si * este o expresie in forma poloneza
Pentru a putea lucra cu forma poloneza trebuie ca si alte structuri sa fie transpuse similar.
Arborii sintactici se utilizeaza frecvent deoarece sunt utili in faza de optimizare.
exemplu:
id1*( id2+ id3[id4])
*
/ \
id1 +
/ \
id2 ()
/ \
id3 id4
daca luam instructiunea if id1 > id2
then id2:= id1**2
else goto et.1
if else
go to
e
diti
con
the
n
> et 1
:=
id1 id2
id2 **
id1 2
8
TEORIA COMPILATOARELOR
Codul cu 3 adrese
Are forma A:= B op C
(op, B, C) – triplet. Componentele unui triplet sunt pointerii catre tabela de simboluri.
A:=(B+C)*O
(0) + B C T1
(1) * T D
T2
(2) := A T2
A:=B op C (op, B, C, A)
A:=op B (op, B, └┘, A) unde └┘ este “spatiu” (blank)
A:=B (:=, B, └┘, A)
goto Q (goto, └┘, └┘, Q)
if A op rel B goto Q
(op rel, A, B, Q)
exemplu:
A<B or C
if A < B goto (3)
(1) T1:=0
(2) goto (4)
(3) T1:=1
(4) T2:= T1 or C
Optimizarea codului
Are ca scop rearanjarea codului intermediar astfel incat sa se obtina unul mai bun din punct de vedere
al timpului de executie si al memoriei ocupate.
9
TEORIA COMPILATOARELOR
(1) (3)
BL1 (5)
(2)
(6)
BL2
(4)
(8)
(7)
(14)
In fig.1 numarul cvadruplelor executate este 2+12*20=242, iar pe fig.2 se executa 4+10*20=204
cvadruple.
Al doilea tip de optimizare se refera la eliminarea variabilelor induse (variabile care iau valori in
progresie aritmetica. Se elimina variabila indusa care face ca alte variabile sa fie induse (“i”). Se elimina “i”,
iar variabilele T1 si T4 vor primi valorile initiale si apoi se vor modifica cu ratia 4. Se vor elimina cvadruplele
(12) si (13) care vor fi “i”. Va rezulta:
10
TEORIA COMPILATOARELOR
P=0
T1: = 0
T4: = 0
T1: = T1+4
T4: = T4+4
T6: = T5[T4]
T7: = T3*T4
T8: = p+T7
p: = T8
Optimizari locale au rolul de a elimina instructiunile inutile date de existenta a mai multor subexpresii
comune.
exemplu:
(1) T1:=(1+20)
(2) T2:=-x
11
TEORIA COMPILATOARELOR
=[ ] T3
=[ ] T6
po [1]
* T1, T4
- T2
- T5
+ T9
adr(A) 4
adr(B) io 20
1
Daca in lista variabilele asociate unui nod sunt numai temporale, se retine una la intamplare, celelalte
eliminandu-se. Daca se afla si variabile din program (A, B1, …, Bk).
12
TEORIA COMPILATOARELOR
exemplu:
D:=(A-B)+(A-C)+(A-C)
T1: A-B MOV A, RO
SUB B, RO
T1: A-C MOV A, R1
SUB C, R1
T3: T1+T2 ADD R1, RO
T4: T3+T2 ADD R1, RO
MOV RO, D
13
TEORIA COMPILATOARELOR
*
2 3
+ 4 -
* 1
5
*
6 -
D
E
+
C
A B
Etichetarea nodurilor. Fiind dat un GOFC. Acest algoritm stabileste numarul de registri, pentru a genera
codul corespunzator.
Algoritmul de etichetare:
La intrare: GOFC
La iesire: numarul de registri
Metoda: fie “n” nodul ce urmeaza a fi etichetat
14
TEORIA COMPILATOARELOR
Tabela de simboluri
Stocheaza informatia culeasa in timpul compilarii. Aceasta informatie este cuprinsa din doua parti:
- numele (identificatorul)
- atributele (tip, locatia de memorie unde se afla valoarea, modul de utilizare)
Divizarea aceasta se realizeaza pentru a economisi memorie cand se iese din domeniul de divizibilitate
al unei variabile numele numai este necesar si zona de memorie poate fi eliberata.
Tabela de simboluri este utilizata in toate etapele compilarii:
- in analiza lexicala si sintactica cand se verifica daca un ******** este in
tabela;
- in faza de analiza semantica pentru a verifica daca identificatorii sunt
folositi in concordanta cu declaratiile;
- in generarea de cod pentru alocarea optima a zonelor de memorie;
- in tratarea erorilor pentru a evita mesajele redundante
Exista 2 tipuri de tabele de simboluri: ordonate si neordonate.
In tabelele neordonate informatia se stocheaza in ordinea in care se intalneste,
Nume Atribute
f functii, real
Are dezavantajul ca pentru a cauta un identificator, tabela trebuie parcursa de la inceput de fiecare
data.
Tabelele ordonate sunt de urmatoarele tipuri:
- ordonate alfabetic, care folosesc cautarea binara;
- arborescente, in care fiecare nod, pe langa nume si atribute contin o
legatura pe stanga si alta pe dreapta, catre numele mai mici, respectiv mai mari.
15
TEORIA COMPILATOARELOR
Azi
este
duminica
- dispersate: acestea folosesc o functie numita dispersie, care asociata numelui, intoarce un numar
intreg numit index.
Multimea identificatorilor este impartita in clase. Avantajul este ca la cautare se determina mai intai
indexul si apoi se face cautarea secventiala.
Exemplu de functie index: h(nume) = prima litera
h(nume) = clasa mod
Cea mai utilizata metoda de tip dispersie este inlatuirea separata in care se memoreza informatia
intalnita pentru prima data.
Exemplu:
Nume Atribute Legatura
Nod
Memorie
ad 1
.
.
B 3
16