Documente Academic
Documente Profesional
Documente Cultură
bloca
Capatul reprezinta cel mai din stanga subarbore complet, format dintr-un nod si toti fiii sai. Parintele (in cazul
nostru A) este nodul cel mai de jos si cel mai din stanga avand toti fiii prezenti in arbore sub forma de frunze. Reducerea
unui capat la partea stanga a productiei respective se numeste fasonarea capatului si consta din indepartarea fiilor lui
A din arborele sintactic.
Exemplu: fie gramatica ambigua
E -> E + E
E -> E * E
E -> (E)
E -> id
iar sirul de cautare : id+ id * id
(1) E =d> E + E =d> E + E * E =d> E + E * id3 =d> E + id2 * id3 =d> id1 + id2 * id3
Se observa din Exemplu ca sirurile situate in dreapta unui capat contin exclusiv simboluri terminale. Gramatica
data fiind ambigua exista si urmatoara derivare dreapta distincta de prima:
(2) E =d> E * E =d> E * id3 =d> E + E * id3 =d> E + id2 * id3 =d> id1 + id2 * id3
In forma propozitionala E + E* id3 exista 2 capete: id3, E+E, corespunzatoare primei si respectiv celei de-a
doua derivari dreapta prezentate. La fel ca si in prezentarea acestui Exemplu la discutarea gramaticii ambigue, existenta
celor 2 dericari dreapta semnifica prioritati relative diferite ale operatorilor * si +. La primul model de derivare este
mai prioritar *.
4.5.2. Fasonarea capetelor
Fasonarea capetelor se poate considera si ca procesul de parcurgere in sens invers a unei derivari dreapta. Se
porneste de la un sir de analizat. Daca apartine limbajului descris de gramatica data, atunci el se poate obtine dintr-un
pas oarecare n al unei derivari dreapta inca necunsocute, dar care are urmatoarea forma:
S =d> 0 =d> 1 =d> =d> n =d>
Reconstituirea in sens invers a acestei derivari consta in localizarea in forma propozitionala n a unui capat n si
inlocuirea lui cu partea stanga a productiei. An -> n, obtinandu-se astfel forma propozitionala n-1. Apoi se continua
procedeul cu n-1 etc. Daca in final s-a ajuns la simbolul de start al gramaticii inseamna ca procesul de analiza s-a incheiat
cu succes.
Exemplu: se considera gramatica din Exemplul anterior
E -> E + E | E -> E * E | E -> (E) | E -> id
avand sirul din intrare: id1 + id2 * id3
Secventa de reduceri care apare in continuare reprezinta inversul secventei din prima derivare (unde * este mai
prioritara)
forma propozitionala dreapta
id1 + id2 * id3
E + id2 * id3
E + E * id3
E+E*E
E+E
capat
id1
id2
id3
E*E
E+E
intrare
id1 + id2 * id3 $
+ id2 * id3 $
actiune
deplasare
reducere E->id
$E
$E+
$ E + id2
$E+E
$E+E*
$ E + E * id3
$E+E*E
$E+E
$E
1.
2.
3.
4.
+ id2 * id3 $
id2 * id3 $
* id3 $
* id3 $
id3 $
$
$
$
$
deplasare
deplasare
reducere E -> id
deplasare
deplasare
reducere E -> id
reducere E -> E * E
reducere E -> E + E
succes
intrare
else $
Pentru configuratia data nu se poate decide daca varful stivei este un capat sau nu. Avem deci un conflict
deplasare-reducere, intrucat in functie de ce urmeaza in intare, poate fi corect sa se reduca if <expr> then <instr> la
<instr> sau ar putea fi corect sa se deplaseze else din intrare in stiva , urmat de cautarea unei alte <instr>, pentru ramura
de else.
Deoarece nu se poate lua decizia pe baza unui singur simbol de anticipare, se spune ca gramatica nu este LR1.
In general nici o gramatica ambigua (ca cea de sus) nu poate sa fie LRk, oricare ar fi k N*. Analizorul sintactic cu
deplasare-reducere poate fi usor adoptat pentru a analiza si gramatici ambigue ca cea de mai sus prin decizia ca orice
conflict de tipul deplasare-reducere sa se rezolve in favoarea deplasarii. Se observa ca luand aceasta decizie in situatia
de mai sus, analiza decurge corect. O alta situatie pentru gramaticile non LR este atunci cand se localizeaza cu
certitudine un capat, dar continutul stivei si simbolul curent din intrare nu sunt suficiente pentru a determina ce productie
trebuie utilizata pentru reducere (conflict reducere-reducere). Exemplu: dispunem de un analizor lexical care furnizeaza
atomul lexical id pentru orice identificator, indiferent de utilizarea acestuia (cazul normal). Presupunem ca in limbajul
ales apelurile de proceduri pe de o parte si refeirea elementelor de tablou pe de alta parte, au aceeasi forma sintactica,
adica un nume si argumentele intre paranteze. Deoarece din punct de vedere semantic traducerea indicilor in referinte de
tablou difera substantial de traducerea argumentelor la apelurile de proceduri si functii, trebuie sa utilizam productii
diferite pentru a genera listele de indici si respectiv listele de argumente, ca in gramatica urmatoare:
(1)
<instr> -> id (<lista_param>)
(2)
<instr> -> <expresie> :=<expresie>
(3)
<lista_param> -> <lista_param>,<parametru>
(4)
<lista_param> -> <parametru>
(5)
<parametru> -> id
(6)
<expresie> -> id (<lista_expr>)
(7)
<expresie> -> id
(8)
<lista_expr> -> <lista_expr>,<expresie>
(9)
<lista_expr> -> <expresie>
Consideram o instructiune care incepe cu a(i,j) si presupunem ca am ajuns in situatia in care primii trei atomi
au fost transferati in stiva.
stiva
intrare
( id
, id ) $
Este evident ca id din varful stivei trebuie redus, dar nu se stie care dintre productii trebuie utilizate. Daca a
este procedura, ar trebui aleasa pentru reducere productia (5), iar daca a este element de tablou, trebuie aplicata
productia (7). Pentru a lua decizia, ar trebui consultata tabela de simboluri (daca acolo informatiile sunt completate). O
solutie pur sintactica la aceasta situatie consta in modificarea analizorului lexical astfel incat sa furnizeze un atom
distinct (procid) cand a este un nume de procedura.
Cu modificarea propusa, pentru cazul cand in situatia de mai sus este un apel de procedura, continutul
stivei si al intrarii este urmatorul:
stiva
intrare
procid ( id
, id ) $
Este clar ca reducerea lui id se face prin (5).
Observatie:
- decizia privind reducerea este luata pe baza simbolului al treilea de sub varful stivei (procid) care nici
macar nu participa la reducere
- rezolvarea conflictelor reducere-reducere pe baza modificarilor de gramatica este metoda generala de
rezolvare a acestei situatii
(1)
<instr> -> procid ( <lista_param>)
4.6. Analiza sintactica bazata pe precedenta operatorilor
Se poate aplica doar la o clasa redusa de gramatici dar este imortanta datorita raspandirii ei. Are avantajul ca
analizorul se poate construi usor manual. Printre alte cerinte esentiale, gramatica la care se aplica acest tip de analiza,
trebuie sa aiba urmatoarele doua proprietati:
1. sa nu aiba productii vide
2. in nici o productie sa nu existe parte dreapta continand doua neterminale adiacente
Gramaticile care respecta conditia 2 se numesc gramatici de operatori
semnificatia
a cedeaza precedenta lui b
a are aceeasi precedenta cu b
a are precedenta fata de b
2. se baleiaza sirul inapoi omitand eventualele simboluri = pana se intalneste primul marcaj <, acesta va fi marginea
3.
4.
stanga a capatului.
se considera ca fiind capat sirul de simboluri gramaticale dintre cele 2 marcaje, inclusiv neterminalele care apar ca
incluse sau inconjurand terminalele dintre marcaje. Considerarea neterminalelor inconjuratoare este necesara pentru
a asigura ca nu vor apare doua neterminale adiacente in forma propozitionala urmatoare.
Exemplu: se considera sirul de intrare $ id + id * id $ si matricea de relatii de precedenta redusa de mai jos:
id
id
+
*
$
+
*
$
>
>
>
<
>
<
>
<
>
>
>
<
<
<
In tabela, operatorul de adunare este asociativ la stanga, in timp ce operatorul de inmultire asociativ la dreapta
Sirul initial, avand introduse relatiile de precedenta este urmatorul:
$ < d > + < id > * < id > $
capat
$ E + id * id $
$ < + < id > * < id > $
$ E + E * id $
$ < + < * < id > $
$E+E*E$
$<+<*>$
E -> E * E
$E+E$
$<+>$
$ E $ => sfarsit
Observatie: deoarece neterminalele nu influenteaza analiza, nu trebuie facuta distinctie intre ele.
In stiva analizorului este suficient sa se tina un singur marcaj reprezentativ pentru orice fel de terminal pentru a
marca doar locul din stiva corespunzator acelui neterminal, util pentru inregistrarea atributelor semantice
corespunzatoare neterminalului respectiv. Aparent din Exemplul de mai sus s-ar putea deduce ca pentru determinarea
capatului ar fi necesara baleierea intregii forme propozitionale sau in orice caz a unei mari portiuni din ea. Acest lucru
nu este necesar intrucat implementarea concreta se face tot pe baza mecanismului de analiza sintactica cu deplasare si
reducere iar relatiile de precedenta sunt utile doar pentru a dirija actiunile analizorului (deplasare sau reducere).
Actiunile analizorului sunt cele cunoscute :
1. deplasare : cat timp nu s-a gasit extremitatea dreapta a capatului, adica intre simboulu terminal cel mai apropiat de
varful stivei si simbolul curent din intrare este valabila una din realatiile < sau =.
2. reducere : cand s-a gasit extremitatea dreapta a capatului adica intre terminalul cel mai propiat din varful stivei si
simbolul de intrare este relatia >, se baleiaza in sens invers stiva pana la intalnirea primului marcaj < dupa care se
face reducere.
3. acceptare : cand ambele simboluri care se compara ( adica varful stivei si simbolul curent din intrare) sunt $
4. eroare : daca se compara 2 simboluri intre care nu exista relatie de precedent
Aceste idei privind mecanismul de analiza sintactica bazata pe precedenta operatorilor sunt cuprinse in urmatorul
algoritm.
Algoritmul primeste la intrare sirul w de analizat si matricea relatiilor de precedenta. Daca w este corect, se va
obtine la iesire un schelet al arborelui sau sintactic, in caz contrar un mesaj de eroare, datorita substituirii
intermediare a neterminalului, motiv pentru care nodurile interioare vor fi uniforme.
stiva
intrare
$
w$
(1) * se pozitioneaza pointerul de intrare pe primul simbol din w
(2) repeat forever
if *atat simbolul din varful stivei cat si simb. curent de intrare sunt $ then return
else
begin
*fie a simbolul terminale cel mai apropiat de varful stivei,
b simbolul curent din intrare
if (a < b) or ( a=b) then
begin {deplasare}
* introdu b in stiva
* avanseaza cu o pozitie pointerul de intrare
end
else if (a >b) then {reducere}
repeat
* extrage din stiva
until *terminalul din varful stivei este in relatie < cu terminalul cel mai recent extras
else *eroare
end;
4.6.3. Deducerea intuitiva a relatiei de precedenta din asociativitatea si prioritatea algebrica a operatorilor
Singura cerinta care trebuie avuta in vedere este aceea ca ele sa conduca la analiza corecta a limbajului defninit
de gramatica. Tinand cont de faptul ca analiza sintactica bazata pe precedenta operatorilor se aplica la gramatici pentru
expresii sau similare cu acestea iar intre operatorii din expresii exista reguli de priorotate si asociativitate riguroase care
rezolva eventualele ambiguitati, aceste reguli pot reprezenta baza pentru stabilirea relatiei de precedenta. Pentru cazul
operatorilor binari, notati cu , 1, 2 relatiile de precedenta pot fi deduse astfel:
1. daca 1 este mai prioritar algebric decat 2, se introduc in tabela relatiile
1 > 2 si 2 < 1.
2. daca 1 si 2 au prioritate algebrica egala (inclusiv cand reprezinta acelasi operator) apar urmatoarele 2 situatii:
a. 1 si 2 sunt asociativi la stanga
1 > 2 si 2 > 1
b. 1 si 2 sunt asociativi la dreapta
1 < 2 si 2 < 1
3. pentru orice operator exista urmatoarele relatii de precedenta cu celelalte terminale
id
< id
id >
<(
(<
( si )
>)
)>
>$
$>$
Pentru a asigura reducerea la E a lui id si a lui (E), intre terminalele care nu sunt operatori se introduc
urmatoarele relatii:
(=)
(<(
( < id
$<(
id > $
id > )
$ id
)<$
)>)
Exemplu:
Se considera gramatica:
E -> E + E | E E | E * E | E / E | E ^ E | ( E ) | id
Operatorii au urmatoarele proprietati:
^
*,/
+.-
+
>
>
*
<
/
<
^
<
id
<
(
<
)
>
$
>
*
/
^
id
(
)
$
>
>
>
>
>
<
>
<
>
>
>
>
>
<
>
<
id * ( id ^ id ) id / id
$ < id > * < ( < id > ^ < id > ) > - < id > / < id > $
$ < * < ( < id > ^ < id > / < id > ) > -.
$ < * < ( < ^ < id > ) .
$ < * < ( < ^ > ) > - < id > / < id > $
$ < * < ( = ) > - < id > / < id > $
$ < * > - < .
$ < - < id > / < id > $
$ < - < / < id > $
$<-</>$
$<->$
<
>
>
>
>
<
>
<
<
>
>
>
>
<
>
<
<
<
<
<
>
<
>
<
<
<
<
<
<
<
<
<
<
<
<
<
>
>
>
>
>
=
>
>
>
>
>
>
>