Sunteți pe pagina 1din 16

BISON Generator de analizoare sintactice (parsere)

LUCRARE DE LABORATOR

1. Studiul generatoarelor automate de analizoare sintactice:
a. Se va citi materialul Despre bison
b. Se va citi materialul prezentat in referat
2. Se vor studia si implementa exemplele prezentate in referat

Bison - generator automat de analizoare sintactice
(parsere)
1. Prezentare generala
Bison este un generator de analizoare sintactice pentru gramatici LALR(1) si constituie unul
dintre utilitarele standard ale sistemelor de operare Unix.
Programul Bison poate genera un translator in modul urmator: primeste la intrare un fisier
continand o specificatie (specificatiile sintactice si unele semantice) a gramaticii pe care
urmeaza sa o recunoasca si genereaza un program C ce contine codul de analiza sintactica,
cod care implementeaza metoda de analiza sintactica LALR(1):
- Sintaxa de specificare a gramaticii din fis. de intrare - este o varianta a formei BNF
(Backus-Naur Form). Fisierul ce contine specificatia gramaticii este un fisier text care poate
avea orice nume acceptat de sistemul de operare. Din considerente istorice se recomanda ca
fisierul de specificatie sa aiba extensia .y (bison este succesorul utilitarului yacc).
- Functia de analiza din programul C generat se numeste yyparse( ). Programul C rezultat
este memorat intr-un fisier care are implicit acelasi nume cu fisierul de specificare (mai
putin extensia .y) la care se adauga sufixul .tab.c (utilizatorul poate solicita explicit un alt
nume).
o In afara de codul generat automat, utilizatorul mai trebuie sa prevada cel putin
trei functii C:
functia main( ) din care se va apela yyparse( );
functia yylex( ) care va furniza atomii lexicali (este apelata de yyparse);
functia yyerror( char *s ) pentru afisarea mesajelor de eroare (este apelata de
yyparse).
In continuare se compileaza programul obtinut, rezultand astfel analizorul sintactic
executabil.
Intrare Bison: Gramatica
Iesire Bison: Fisier sursa C, care compilat, constituie parser LALR ptr. gramatica data.
Bison folosit si in verificarea erorilor (prin producerea tuturor starilor unui automat
finit, se pot depista erorile deplaseaza/reduce sau reduce/reduce).
Permite completarea cu actiunile posibile in vederea depanarii.
Permite definirea actiunilor semantice si atribuirea de valori simbolurilor gramaticii.

Lansarea in executie a programului Bison
Lansarea in executie a programului Bison se realizeaza cu comanda
bison [optiuni] [nume_fisier_specificatii]

Cateva dintre optiunile liniei de comanda mai des utilizate sunt:
-d sau --defines = se genereaza un fisier de iesire suplimentar ce contine
macrodefinitii pentru:
o codurile atomilor lexicali definiti in gramatica

1
BISON Generator de analizoare sintactice (parsere)
o tipul asociat atributelor atomilor lexicali YYSTYPE
o declaratiile variabilelor externe
Fisierul astfel obtinut are acelasi nume ca si fisierul cu cod C generat, dar cu extensia
.h si poate fi inclus in specificatia pentru Flex;
-h sau --help = afiseaza la stdout un rezumat al optiunilor din linia de comanda;
-t sau --debug = se genereaza cod pentru macroul YYDEBUG. Activarea regimului
"debug" se realizeaza atribuind variabilei globale yydebug o valoare nenula (implicit
variabila are valoarea 0);
-v sau --verbose = se genereaza un fisier de iesire suplimentar ce contine o descriere
detaliata a starilor analizorului si a actiunilor preconizate pentru fiecare atom din sirul
de intrare. Tot aici sunt descrise si conflictele (rezolvate si nerezolvate) depistate la
generarea analizorului. Numele fisierului este acelasi ca nume fisierului cu cod C
generat, dar cu extensia .output in loc de .tab.c;
-o nume_fisier_iesire= aceasta optiune se foloseste daca se doreste ca fisierul de iesire
al generatorului sa aiba alt nume decat cel implicit;
-V sau --version = la stdout se afiseaza versiunea programului Bison;

2. Structura unui fiier sursa bison (yacc):
Programul de specificatie, de obicei cu extensia .y, (fisierul sablon pe baza caruia bison-ul
genereaza programul C care reprezinta parser-ul) este format din patru mari sectiuni:
%{
declaratii C: declaratii globale si definitii
%}
definiii Bison
%%
reguli (specificarea gramaticii)
%%
cod C utilizator

Sectiunea de declaratii C este opional i poate cuprinde dou seciuni. Sectiunea de
definitii bison este asemntoare cu cea din flex. Astfel este permis introducerea de cod C
ntre %{ si %}. Tot n seciunea de definiii trebuie specificate terminalele pe care analizorul
sintactic se asteapta s le primeasca de la analizorul lexical .
1. O prim seciune cuprinde ntre delimitatorii %{ i %} declaraii n limbajul C pentru
variabilele care se utilizeaz n regulile de traducere sau n procedurile din cea de-a treia
parte a fiierului. Aadar, textul cuprins ntre %{ i %} se copie nealterat n fiierul C
produs de bison. Daca nu este nevoie de declaratii C, atunci intreaga sectiune poate lipsi
(inclusiv delimitatorii "%{" si "%}").
2. A doua seciune a acestei prime pri conine declaraii ale unitilor lexicale ale
gramaticii, declaraii de asociativitate i preceden a operatorilor, declaraii ale tipurilor
de date si declaratii de functii si variabile care sunt folosite in actiunile semantice din
regulile gramaticii. Aceste declaratii sunt copiate la inceputul codului generat, inainte de
definitia functiei yyparse. Aici se declara atomii lexicali (simbolurile terminale), tipurile
asociate atributelor simbolurilor terminale si neterminale, precedenta si asociativitetea
operatorilor, etc.


2
BISON Generator de analizoare sintactice (parsere)
Principalele declaratii Bison din aceasta a doua sectiune sunt:
%token pentru declararea simbolurilor terminale ale gramaticii
%union {....} pentru declararea unei multimi de valori posibile
utilizate in actiunile semantice.
%left pentru asociativitate stnga a operatorilor
%right pentru asociativitate dreapta a operatorilor
%nonassoc pentru declaraiile de neasociativitate
%prec pentru precizarea precedenei operatorilor
%type pentru definirea tipului simb-lor neterminale
Tot n aceast seciune se poate introduce simbolul de start al gramaticii, n cazul n care
acesta nu este partea stng a primei reguli sintactice:
start <nume _simbol _de _start>
%token
Simbolurile terminale ale gramaticii unitile lexicale cu excepia celor formate dintr-
un singur caracter (precum +, * etc.), trebuiesc declarate. Aceste simboluri sunt
reprezentate n bison prin nite coduri numerice; funcia yylex transmite codul unitii
respective funciei yyparse. Programatorul nu trebuie s tie aceste coduri numerice, ele
sunt generate automat folosind opiunea d la lansarea lui bison i sunt trecute ntr-un
fiier nume.tab.h (sau yytab.h sub DOS).
Unitile lexicale se definesc prin linii de forma:
% token <nume _unitate _lexical>
i pot fi utilizate n celelalte dou pri ale fiierului de intrare. Numele de terminale nu au
nici o semnificatie pentru bison, ele fiind doar niste denumiri de constante. Totui, prin
conventie, numele alese pentru terminale conin numai majuscule, iar toate celelalte nume
sunt formate cu minuscule.
Se pot utiliza trei tipuri de declaratii bison:
%token [VAL] <nume_atom>: declararea unui atom sau simbol terminal, cu
specificarea unei valori (optional).
%token <<VAL>> <SYMBOL>: declararea unui simbol al gramaticii care are
valoarea semantica VAL. OBS: <VAL> trebuie inclusa intre < si >.

Simbolurile gramaticii pot avea valori semantice
1
, atribute. n mod implicit, aceste
valori sunt ntregi si sunt specificate n YYSTYPE. Pentru a specifica alt tip, n partea de
declaraii C se adaug o directiv define pentru YYSTYPE:
#define YYSTYPE <nume tip>
declar tipul valorilor semantice (atributelor) pentru simbolurile gramaticii ca fiind <nume
tip>.

Utilizarea de tipuri diferite pentru simboluri diferite se realizeaz prin specificarea
acestor tipuri ntr-o declaraie union (specific bison), iar declararea tipului simbolurilor
cu type.
Exemplul 1:
%uni on {
i nt i nt val ;
doubl e doubl eval ;
symr ec *t pt r ;
}

1
Vezi si paragrafele Descrierea regulilor semantice in bison si Valorile simbolurilor si
actiuni ale regulilor.

3
BISON Generator de analizoare sintactice (parsere)
%t ype <i nt val > I NT
%t ype <doubl eval > REAL
%t ype <t pt r > I D
Prin aceste declaraii se specific tipul valorilor pentru token-urile INT, REAL, ID ca
fiind respectiv int, double, pointer la symrec (pointer n tabela de simboluri).

%{
/*sectiunea de declaratii dintr-un fis. De specificatii bison ptr. generarea unui analizor
de expresii aritmetice */
#i ncl ude <st di o. h>
#i ncl ude <st r i ng. h>
#def i ne MAX_SI ZE 100
char *_f i nal st r ;
%}

%t oken SEMI COLON
%t oken MULT
%t oken DI V
%t oken PLUS
%t oken MI NUS
%t oken RPAREN
%t oken LPAREN
%t oken <num> NUMBER
%uni on{
doubl e num;
char *st r ;
}

%t ype <st r > expr l i st
%t ype <num> expr
%t ype <num> addexpr
%t ype <num> mul t expr
%t ype <num> unar yexpr
%t ype <num> si mpl eexpr

Exemplul 1-1:
%right '='
%left '-' '+'
%left '*' '/'
%right '^'
%nonassoc '(' ')'

Declaratia %left arata ca operatorii declarati prezinta asociativitate stanga. De
exemplu pentru operatia de adunare: x+y+z=(x+y)+z . Pentru asociativitate dreapta se
foloseste %right . Termenul nonassoc exprima faptul ca operatorul nu este asociativ.
Ordinea de declarare a operatorilor, permite stabilirea precedentei operatiilor.
Operatiile declarate la inceput sunt cele mai putin prioritare, iar cele declarate la sfarsit
sunt cele mai prioritare .

Sectiunea de reguli gramaticale este obligatorie si contine regulile gramaticale care descriu
sintaxa pe care trebuie sa o verifice analizorul lexical generat cu bison. In aceasta sectiune se
specifica productiile gramaticii si actiunile de realizat sunt specificate.
Fiecare regul conine:

4
BISON Generator de analizoare sintactice (parsere)
- partea stng (un neterminal al gramaticii GIC);
- partea dreapt (irul format din terminali i neterminali, corespunztor unei reguli din GIC);
o Cele dou pri sunt desprite prin : (dou puncte).
- partea de aciune, cuprins ntre{ i }, conine cod C care va fi inclus n analizor i
reprezint operaiile care se execut atunci cnd analizorul realizeaz o reducere cu regula
specificat. Analizorul sintactic executa aciunea de la sfaritul unei producii imediat ce
aceasta se potriveste pe datele de la intrare.
O regul se termin prin ; (punct virgul). Dac sunt mai multe reguli care au aceeai parte
stng, acestea se scriu o singur dat i prile drepte se despart prin |.

Sintaxa de scriere a regulilor gramaticale este urmatoarea:
rezultat: alternativa1
| alternativa2
...
;
unde
rezultat este o un simbol neterminal pentru care se descriu regulile de derivare;
alternativele sunt secvente de simboluri terminale si nerminale grupate conform
productiilor gramaticii.
Fiecare producie conine de la stanga la dreapta, un simbol neterminal, caracterul : i o lista
de simboluri i aciuni. Cu ajutorul caracterului ; se marcheaz sfaritul produciei .

Exemplul 2: Regulile gramaticii care descrie expresiile aritmetice:
expr : NUMAR
| expr + expr
| expr - expr
| expr * expr
| expr / expr
| ( expr )
;
Aici, expr este numele neterminalului care definete expresia aritmetic, terminalii +, -
,
*, /, (, ) se pun ntre apostrof, iar NUMAR reprezint token-ul (unitatea lexical)
numr (ce
trebuie declarat n seciunea declaraii).

Dac dorim ca analizorul pe care-l construim s realizeze i aciuni semantice
2
, de
pild s evalueze expresiile (pentru irul 25+15, pe lng faptul c verific sintaxa,
raporteaz i rezultatul adunrii, valoarea 40), se adaug la reguli partea de aciune.
Pentru fiecare productie se ataseaza intre acolade actiunea de urmat. In cadrul acesteia,
$1, $2, $3, .... identifica tokenii din dreapta productiei (capatul recunoscut pe vf. stivei
cu valorile respective), iar $$ identifica valoarea pe care o primeste neterminalul care
este introdus in stiva in locul celor redusi.

expr : NUMAR {$$ = $1; }
| expr + expr {$$ = $1+$3; }
| expr - expr {$$ = $1- $3; }
| expr * expr {$$ = $1*$3; }
| expr / expr {$$ = $1/ $3; }

2
Vezi si paragraful Descrierea regulilor semantice in bison si Modul de functionare a
analizorului sintactic

5
BISON Generator de analizoare sintactice (parsere)
| ( expr ) {$$ = $2; }
;
n partea de aciune se scriu instruciuni n limbajul C. Aici, $$ reprezint valoarea
unui atribut al neterminalului expr din stnga regulii sintactice, iar $i reprezint
valoarea atributului celui de-al i-lea simbol din partea stng a regulii.

Implicit, prima regula din sectiune este cea care descrie derivarile posibile pentru simbolul de
start al gramaticii (prima producie se considera cea de nivel cel mai nalt).

Expresia din partea dreapta a unei producii conine 0 sau mai multe simboluri . Un exemplu
de producie foarte simpla este cea care conine n partea dreapta un singur simbol. Dupa ce
apare n stanga unei producii, un simbol poate fi folosit n producii ulterioare n partea
dreapta . Caracterul | citit ca "sau" introduce o regula avnd aceeai parte stanga ca regula
anterioara .

Exemplul 3 (specificarea regulilor pentru un parser al unui text in limbaj natural:
propoziie : prop_simpla {printf("\n Propoziie simpla");}
| prop_compusa {printf("\n Propoziie compusa");}
;
prop_simpla:subiect verb complement
;
prop_compusa:prop_simpla CONJ prop_simpla
|prop_compus CONJ prop_simpla
;
subiect : SUBST
| PRON
| ADJ subiect
;
verb :VERB
|ADV VERB
|verb VERB
;
complement:SUBST
|ADJ complement
;

Dac datele de intrare nu corespund nici unei reguli (Exemplu subiect, subiect) atunci
se apeleaz funcia yyerror( ) definita n seciunea de rutine, i apoi se aplica productia
speciala error. Se poate introduce facilitatea de revenire din eroare, modificnd codul pentru
yyerror( ).

Exemplul 4 (specificarea regulilor pentru parser-ul de expresii aritmetice din exemplul 1):
expr l i st : expr l i st expr
| expr
;
expr : addexpr SEMI COLON
| SEMI COLON
;
addexpr : addexpr PLUS mul t expr
| addexpr MI NUS mul t expr
| mul t expr

6
BISON Generator de analizoare sintactice (parsere)
;
mul t expr : mul t expr MULT unar yexpr
| mul t expr DI V unar yexpr
| unar yexpr
;
unar yexpr : MI NUS unar yexpr
| si mpl eexpr
;
Si mpl eexpr : LPAREN expr RPAREN
| NUMBER
;



Seciunea de cod utilizator conine cod C definit de utilizator, cod care este copiat ca atare n
analizorul sintactic generat (la sfarsitul fisierului in care se afla codul generat automat);
conine rutine scrise n limbaj C care se includ nealterate n analizorul generat cu bison. n
aceast sectiune trebuie furnizat un analizor lexical, adic o funcie yylex() precum i apelul
(n programul principal) la funcia yyparse() pe care o creeaz bison-ul.Aici este locul potrivit
pentru definirea functiilor main, yyerror si eventual yylex.
Cea mai importanta funcie din aceasta seciune este funcia main(), care cheama n mod
repetat funcia yyparse() pn cnd datele de la intrare se termina. Funcia yyparse()
reprezinta analizorul sintactic generat de bison, deci programul ncearca n mod repetat s
analizeze propoziii pn cnd se termina datele de la intrare. Terminarea datelor de la intrare
este semnalata de analizorul lexical prin ntoarcerea valorii 0.

Exemplu de seciune cod utilizator:
extern yyin; /* variabila yyin este o variabila globala generata de flex n codul
analizorului lexical , fiind implicit iniializata la intrarea standard*/
main ( )
{
while( !feof(yyin))
{yyparse( );}
}
yyerror(char *s)
{
fprintf(stderr,"%s\n",s);
}

Modul de funcionare al analizorului sintactic
(analiza sintactica LR sau de tip deplasare - reducere )
Un analizor sintactic generat cu bison lucreaz detectnd reglile de producie care s-ar putea
aplica utiliznd terminalele citite deja. Pentru a realiza acest lucru el creaz o mulime de
stri, fiecare reprezentnd o poziie posibila n una sau mai multe reguli de producie partial
analizate. La citirea unui terminal de la intrare, analizorul poate aciona n doua feluri:
Dac prin citirea terminalului nu se ajunge la sfaritul nici unei reguli de producie partial
analizate, terminalul este introdus ntr-o stiva interna iar analizorul trece ntr-o stare care
s reflecte noua poziie n regulile partial analizate. Aceasta operatie se numeste
deplasare.
Cnd analizorul a detectat toate simbolurile, terminale sau neterminale, care formeaz
partea dreapta a unei reguli, el extrage simbolii ce formeaz partea dreapta de pe stiva

7
BISON Generator de analizoare sintactice (parsere)
interna, introduce simbolul aflat n stanga produciei i intra ntr-o noua stare care s
corespunda noului simbol introdus. Aceasta operatie se numeste reducere .

Fie gramatica expresiilor aritmetice i irul de intrare a * (a + a).
(1) E E + T
(2) E T
(3) T T * F
(4) T F
(5) F (E)
(6) F a
Pentru acelai ir se obine secventa de miscri:
(q, a * (a + a), $, l) |- (q, * (a + a), $a, l)
|- (q, * (a + a), $F, 6)
|- (q, * (a + a), $T, 64)
|- (q, (a + a), $T *, 64)
|- (q, a + a), $T * (, 64)
|- (q, + a), $T * (a, 64)
|- (q, + a), $T * (F, 646)
|- (q, + a), $T * (T, 6464)
|- (q, + a), $T * (E, 64642)
|- (q, a), $T * (E +, 64642)
|- (q, ), $T * (E + a, 64642)
|- (q, ), $T * (E + F, 646426)
|- (q, ), $T * (E + T, 6464264)
|- (q, ), $T * (E, 64642641)
|- (q, l, $T * (E), 64642641)
|- (q, l, $T * F, 646426415)
|- (q, l, $T, 6464264153)
|- (q, l, $, 64642641532)
|- (q, l, l, 64642641532)

Sa consideram urmatorul exemplu: gramatica (simplificata) a expresiilor aritmetice:
(r1) E E + E
(r2) E E * E
(r3) E id
O succesiune de derivari (dreapta) pentru a obtine propozitia x+y*z este:
E E * E E * z E + E * z E + y * z x + y * z
2

Pentru a analiza sintactic propozitia (programul sursa) trebuie construita derivarea in sens
invers (de la frunze catre simbolul de start: vom reduce propozitia x + y * z la simbolul de
start (E)). Acest tip de analiza sintactica este este numit bottom-up sau shift-reduce parsing
si foloseste o stiva pentru stocarea formelor propozitionale intermediare. Iata aceeasi derivare,
dar in ordine inversa:
(1) . x + y * z shift
(2) x . + y * z reduce (r3)
(3) E . + y * z shift
(4) E + . E * z shift
(5) E + y . * z reduce (r3)
(6) E + E . * z shift
(7) E + E * . z shift

8
BISON Generator de analizoare sintactice (parsere)
(8) E + E * z . reduce (r3)
(9) E + E * E . reduce (r2) efectueaza inmultirea
(10) E + E . reduce (r1) efectueaza adunarea
(11) E . acceptare
Termenii din stanga punctului sunt introdusi in stiva, cei din dreapta punctului urmand sa
fie cititi de pe banda de intrare. Cand vf. stivei coincide cu partea dreapta a unei productii,
atunci atomii din vf. acesteia se inlocuiesc cu partea stanga a productiei recunoscute.
Intuitiv, atomii recunoscuti sunt scosi din stiva (pop) a avut loc recunoasterea unui capat -
iar partea stanga a productiei este introdusa (push) - reducerea. Grupul de atomi recunoscutti
este numit capat (handle), iar operatia consta in reducerea capatului recunoscut cu partea
stanga a productiei. Procesul continua pana cand toti atomii (tokenii) de la intrare sunt
shiftati pe stiva, iar stiva nu contine decat simbolul de start.
La pasul 1 se shfteaza x pe stiva. La pasul 2 se aplica o reducere pentru regula r3 (se schimba
x in E), etc, pana cand in stiva ramane doar simbolul de start. La pasii 9 si 10, cand se reduc
r2, respectiv r1, se emit instructiunile de inmultire, respectiv adunare. Inmultirea are prioritate
mai mare fata de adunare. Totusi, sa analizam ce se intampla la pasul 6: operatia de deplasare
(shiftare): aici, in loc sa realizam o deplasare, am fi putut reduce vf. stivei (E + E) cu r1.
Aceasta ar fi fost corecta daca adunarea avea prioritate mai mare ca inmultirea. In mod
normal, bison nu stie ce operatie (deplasare sau reducere) dorim sa aplicam: este o situatie in
care apare un conflict deplasare-reducere.Astfel de situatie se rezolva fie rescriind gramatica
(eliminam ambiguitatea), fie semnaland bison-ului care este prioritatea operatorilor implicati.

Valorile simbolurilor i aciuni ale regulilor.
Orice simbol ntr-un analizor generat de yacc are o valoare, care furnizeaza informaii
suplimentare despre o anumita apariie a simbolului. Dac simbolul reprezinta un numr,
atunci valoarea va fi numrul respectiv, dac este un ir, valoarea va fi un pointer catre zona
n care este memorat irul, iar dac este un identificator, valoarea este un pointer catre o
intrare n tabela de simboluri. Unele terminale nu au nici o valoare utila . De exemplu, pentru
paranteze nu avem nevoie de valoare, pentru ca doua apariii ale acestui simbol nu difera prin
nimic. Simbolurile neterminale pot avea orice valoare, stabilita n codul specificat n
programul bison(yacc).
n specificaiile mai complicate, simboluri diferite folosesc tipuri de date diferite. De
exemplu, int i double pentru numere, char* pentru iruri i pointeri catre structuri pentru
simboluri de nivel mai nalt. Dac se folosesc mai multe tipuri de valori, ele trebuie listate
astfel nct yacc s poata genera un tip union, cu numele YYSTYPE, care s le conina. n
mod implicit, yacc considera ca toate valorile sunt de tip int. De fiecare data cnd analizorul
reduce o regula, executa codul asociat cu acea regula, cod denumit aciune. Aciunea apare
ntre acolade, la sfaritul regulii nainte de | sau ; . Codul din aciune se poate referi la valorile
simbolurilor (yylval corespunztor) din partea dreapta a regulii prin $1,$2, i poate seta
valoarea simbolului din stanga , folosind $$.

Exemplu:
expresie : expresie '+' numr
{$$=$1+$3}
| expresie '-' numr
{$$=$1-$3}
| numr {$$=$1}
;


9
BISON Generator de analizoare sintactice (parsere)
Tratarea erorilor in bison
Analizorul sintactic generat de Bison sesizeaza, implicit, o eroare sintactica, atunci cand
atomul lexical care urmeaza nu poate fi prelucrat conform regulilor sintactice si in contextul
creat (continutul stivei analizorului). Utilizatorul poate genera o situatie de eroare sintactica si
in mod explicit, in cadrul unei actiuni, prin invocarea macroului YYERROR. Semnalarea
erorii se realizeaza prin apelarea functiei yyerror() cu un argument reprezentand mesajul de
eroare. Apelul functiei yyerror() se face fie automat, din functia yyparse(), fie imediat inainte
de invocarea lui YYERROR. Mesajul implicit, in cazul erorilor sintactice depistate automat,
este parse error, dar utilizatorul poate obtine si mesaje mult mai sugestive daca defineste
simbolul YYERROR_VERBOSE in sectiunea de declaratii (nu conteaza valoarea asociata
acestuia).
Revenirea din erori
Dupa revenirea din functia yyerror(), in functia yyparse(), analizorul sintactic va incerca
revenirea din eroare. Revenirea din eroare si continuarea compilarii este posibila doar
daca in sectiunea de reguli sunt prevazute si productii de eroare corespunzatoare. In absenta
acestor productii de eroare, analizorul sintactic isi termina executia si genereaza un cod de
retur diferit de zero.

Productii de eroare
In tentativa de revenire din eroare, analizorul sintactic introduce, in mod fortat, in sirul de
intrare un simbol special cu numele error. Simbolul error este predefinit in limbajul
recunoscut de Bison si este considerat simbol terminal (token, atom) cu destinatie speciala
pentru tratarea erorilor. Utilizatorul poate prevedea cateva reguli speciale, numite productii
de eroare, in sectiunea de reguli, care sa contina pseudo-atomul error. Daca una din aceste
reguli speciale se potriveste cu situatia nou creata (prin introducerea fortata a lui error in
sirul de intrare), procesul de analza (functia yyparse) poate continua. Potrivirea regulilor,
care reprezinta productii de eroare, este interpretata de catre Bison intr-o maniera foarte
larga, in sensul ca daca potrivirea stricta nu este aplicabila, atunci se fac noi tentative de
aranjara a unei potriviri dupa cum urmeaza. Mai intai se deruleaza inapoi contextele, prin
scoaterea succesiva a starilor din stiva analizorului, pana cand se ajunge intr-o stare care sa
permita deplasarea simbolului error. In continuare se incearca deplasarea, conform regulii
date de productia de eroare, a atomului aflat in sirul de intrare la momentul sesizarii erorii
(atomul care a declansat eroarea). Daca acest lucru nu este posibil, se abandoneaza atomul si
se citesc noi atomi pana cand se va realiza potrivirea cu regula. Atomii care nu s-au potrivit
regulii sunt si ei abandonati.
Modul de construire a productiilor de eroare determina, in final, strategia de revenire din
erori. O strategie simpla si eficienta este ca simbolul error sa apara la sfarsitul productiilor
de eroare, intercalat intre doua simboluri terminale. Astfel se incerca reducerea intregii
constructii sintactice, in care apare eroarea, fara a mai semnala alte erori in lant. Binenteles,
aceasta schema functioneaza doar daca atomul care incheie constructia apare corect in textul
sursa. In caz contrar revenirea din eroare va trebui sa se faca cu o alta productie de eroare, la
un nivel mai sus in ierarhia regulilor sintactice (mai aproape de simbolui de start al
gramaticii). Totusi, pentru a preveni semnalarea erorilor sintactice in lant, cauzate de o
singura gresala in textul sursa, analizorul generat de Bison emite un mesaj de eroare dupa care
suspenda emiterea celorlalte mesaje. Reluarea semnalarii mesajelor de eroare se realizeaza fie
prin apelul macroului yyerrok (in cadrul unei actiuni semantice asociate unei reguli), fie in
mod automat dupa prelucrarea cu succes a trei atomi consecutivi.

10
BISON Generator de analizoare sintactice (parsere)

Descrierea regulilor semantice in Bison
Semantica limbajului este data de actiunile pe care le executa compilatorul in momentul in
care recunoaste anumite constructii sintactice. Rezultatul actiunilor semantice depinde in
mare masura de valorile care intra in calcul si care, de regula, reprezinta atributele asociate
simbolurilor (terminale sau neterminale). Pentru aceasta, programul Bison permite atasarea la
oricare simbol al gramaticii a unei valori semantice, pe post de atribut. Tipul implicit pentru
atribute este int. Pentru a preciza alt tip pentru atributele tuturor simbolurilor se introduce
definitia:
#define YYSTYPE tip_explicit
in sectiunea de declaratii. Pentru a preciza tipuri distincte pentru atributele diferitelor
simboluri sunt necesare doua etape:
- descrierea tuturor tipurilor preconizate pentru atribute in declaratia %union.
- precizarea explicita a tipului atributului pentru fiecare simbol (terminal sau neterminal) a
carui valoare semantica se utilizeaza. Pentru simbolurile terminale precizarea tipului se
realizeaza in cadrul declaratiei %token, iar pentru simbolurile neterminale in cadrul
declaratiei %type.
Actiunile semantice se pot intercala printre simbolurile productiilor din sectiunea de reguli si
au forma:
{ instructiuni C}
De regula, productiile au o singura actiune semantica plasata la sfarsitul productiei. Actiunea
tipica este cea care calculeaza valoarea atributului pentru simbolul rezultat (din partea stanga
a productiei) in functie de atributele simbolurilor care compun alternativa regulii sintactice
(din partea dreapta a productiei). Codul C din cadrul actiunii semantice poate referi atributul
pentru simbolul rezultat prin constructia $$ iar atributele simbolurilor care compun alternativa
prin constructii de forma $n, unde n este numarul de ordine al simbolului din cadrul
alternativei (eventualele actiuni semantice intercalate printre simboluri intra si ele la numar).

Exemplul 4:
/* Exemplu de fisier intrare bison, exemplul4.y */
%{
i nt yyl ex( voi d) ;
voi d yyer r or ( char * s) ;
%}
%t oken I D
%t oken WHI LE
%t oken BEGI N
%t oken END
%t oken DO
%t oken I F
%t oken THEN
%t oken ELSE
%t oken SEMI
%t oken ASSI GN
%st ar t pr og
%%
pr og: st ml i st
;
st m: I D ASSI GN I D
| WHI LE I D DO st m
| BEGI N st ml i st END
| I F I D THEN st m
| I F I D THEN st mELSE st m

11
BISON Generator de analizoare sintactice (parsere)
;
st ml i st : st m
| st ml i st SEMI st m
;
%%

Dac se compileaz acest fiier cu bison, acesta construiete automatul LALR(1) pentru
gramatica descris n seciunea Reguli. Aceast gramatic are 3 neterminali: prog
(simbolul de start al gramaticii), stm i stmlist. Terminalii sunt declarai prin directiva
%token. Bison raporteaz conflictele de deplasare reducere i cele de reducere-reducere
dac exist. Aceste conflicte sunt rezolvate de ctre bison astfel:
conflictul de deplasare-reducere este rezolvat n favoarea deplasrii;
conflictul de reducere-reducere este rezolvat n favoarea reducerii cu regula care apare prima
n lista de reguli

Pentru descrierea precedent este raportat un singur conflict de deplasare reducere (este
obinut datorit celor dou forme ale instruciunii IF). Automatul LALR(1) obinut este
vizibil dac se lanseaza bison ul cu opiunea v (pentru a afla ce opiuni pot fi folosite
lansai bison h). Iat cum se descrie automatul n exemplul dat (exemplul4.output, generat
datorita optiunii -v) - LALR PARSI NG TABLE:

St at e 20 conf l i ct s: 1 shi f t / r educe

Gr ammar
0 $accept : pr og $end
1 pr og: st ml i st
2 st m: I D ASSI GN I D
3 | WHI LE I D DO st m
4 | BEGI N st ml i st END
5 | I F I D THEN st m
6 | I F I D THEN st mELSE st m
7 st ml i st : st m
8 | st ml i st SEMI st m

Ter mi nal s, wi t h r ul es wher e t hey appear
$end ( 0) 0
er r or ( 256)
I D ( 258) 2 3 5 6
WHI LE ( 259) 3
BEGI N ( 260) 4
END ( 261) 4
DO ( 262) 3
I F ( 263) 5 6
THEN ( 264) 5 6
ELSE ( 265) 6
SEMI ( 266) 8
ASSI GN ( 267) 2

Nont er mi nal s, wi t h r ul es wher e t hey appear
$accept ( 13)
on l ef t : 0
pr og ( 14)
on l ef t : 1, on r i ght : 0
st m( 15)
on l ef t : 2 3 4 5 6, on r i ght : 3 5 6 7 8
st ml i st ( 16)
on l ef t : 7 8, on r i ght : 1 4 8


12
BISON Generator de analizoare sintactice (parsere)
st at e 0
0 $accept : . pr og $end
I D shi f t , and go t o st at e 1
WHI LE shi f t , and go t o st at e 2
BEGI N shi f t , and go t o st at e 3
I F shi f t , and go t o st at e 4
pr og go t o st at e 5
st m go t o st at e 6
st ml i st go t o st at e 7

st at e 1
2 st m: I D . ASSI GN I D
ASSI GN shi f t , and go t o st at e 8

st at e 2
3 st m: WHI LE . I D DO st m
I D shi f t , and go t o st at e 9

st at e 3
4 st m: BEGI N . st ml i st END
I D shi f t , and go t o st at e 1
WHI LE shi f t , and go t o st at e 2
BEGI N shi f t , and go t o st at e 3
I F shi f t , and go t o st at e 4
st m go t o st at e 6
st ml i st go t o st at e 10

st at e 4
5 st m: I F . I D THEN st m
6 | I F . I D THEN st mELSE st m
I D shi f t , and go t o st at e 11

st at e 5
0 $accept : pr og . $end
$end shi f t , and go t o st at e 12

st at e 6
7 st ml i st : st m.
$def aul t r educe usi ng r ul e 7 ( st ml i st )

st at e 7
1 pr og: st ml i st .
8 st ml i st : st ml i st . SEMI st m
SEMI shi f t , and go t o st at e 13
$def aul t r educe usi ng r ul e 1 ( pr og)

st at e 8
2 st m: I D ASSI GN . I D
I D shi f t , and go t o st at e 14

st at e 9
3 st m: WHI LE I D . DO st m
DO shi f t , and go t o st at e 15

st at e 10
4 st m: BEGI N st ml i st . END
8 st ml i st : st ml i st . SEMI st m
END shi f t , and go t o st at e 16
SEMI shi f t , and go t o st at e 13

st at e 11

13
BISON Generator de analizoare sintactice (parsere)
5 st m: I F I D . THEN st m
6 | I F I D . THEN st mELSE st m
THEN shi f t , and go t o st at e 17

st at e 12
0 $accept : pr og $end .
$def aul t accept

st at e 13
8 st ml i st : st ml i st SEMI . st m
I D shi f t , and go t o st at e 1
WHI LE shi f t , and go t o st at e 2
BEGI N shi f t , and go t o st at e 3
I F shi f t , and go t o st at e 4
st m go t o st at e 18

st at e 14
2 st m: I D ASSI GN I D .
$def aul t r educe usi ng r ul e 2 ( st m)

st at e 15
3 st m: WHI LE I D DO . st m
I D shi f t , and go t o st at e 1
WHI LE shi f t , and go t o st at e 2
BEGI N shi f t , and go t o st at e 3
I F shi f t , and go t o st at e 4
st m go t o st at e 19

st at e 16
4 st m: BEGI N st ml i st END .
$def aul t r educe usi ng r ul e 4 ( st m)

st at e 17
5 st m: I F I D THEN . st m
6 | I F I D THEN . st mELSE st m
I D shi f t , and go t o st at e 1
WHI LE shi f t , and go t o st at e 2
BEGI N shi f t , and go t o st at e 3
I F shi f t , and go t o st at e 4
st m go t o st at e 20

st at e 18
8 st ml i st : st ml i st SEMI st m.
$def aul t r educe usi ng r ul e 8 ( st ml i st )

st at e 19
3 st m: WHI LE I D DO st m.
$def aul t r educe usi ng r ul e 3 ( st m)

st at e 20
5 st m: I F I D THEN st m.
6 | I F I D THEN st m. ELSE st m
ELSE shi f t , and go t o st at e 21
ELSE [ r educe usi ng r ul e 5 ( st m) ]
$def aul t r educe usi ng r ul e 5 ( st m)

st at e 21
6 st m: I F I D THEN st mELSE . st m
I D shi f t , and go t o st at e 1
WHI LE shi f t , and go t o st at e 2
BEGI N shi f t , and go t o st at e 3

14
BISON Generator de analizoare sintactice (parsere)
I F shi f t , and go t o st at e 4
st m go t o st at e 22

st at e 22
6 st m: I F I D THEN st mELSE st m.
$def aul t r educe usi ng r ul e 6 ( st m)


Exemplul 5:
/* Intrare bison pentru expresii aritmetice de forma a*(a+a) */
%{
#def i ne QUI T ( ( doubl e) 101010)
voi d pr ompt ( voi d ) {
pr i nt f ( " READY> " ) ;
}

%}
%st ar t S
%%
S: { pr ompt ( ) ; }
| S ' \ n' { pr ompt ( ) ; }
| S E ' \ n' {
i f ( $2 == QUI T) {
r et ur n( 0) ; }
el se {
pr i nt f ( " Expr esi a est e cor ect a. \ n" ) ;
pr ompt ( ) ; }
}
;

E : E ' +' T {pr i nt f ( " E- >E+T\ n" ) ; }
| E ' - ' T {pr i nt f ( " E- >E- T\ n" ) ; }
| T {pr i nt f ( " E- >T\ n" ) ; }
;

T : T ' *' F {pr i nt f ( " T- >T*F\ n" ) ; }
| T ' / ' F {pr i nt f ( " T- >T/ F\ n" ) ; }
| F {pr i nt f ( " T- >F\ n" ) ; }
;

F : ' ( ' E ' ) ' {pr i nt f ( " F- >( E) \ n" ) ; }
| ' a' {pr i nt f ( " F- >a\ n" ) ; }
;
%%

#i ncl ude <st di o. h>
#i ncl ude <ct ype. h>
i nt mai n( ) {
pr i nt f ( " \ n**********************************************\ n" ) ;
pr i nt f ( " ** **\ n" ) ;
pr i nt f ( " ** Par ser pent r u expr esi i ar i t met i ce **\ n" ) ;
pr i nt f ( " ** cu oper anzi a si oper at or i +, - , *, / , ( ) **\ n" ) ;
pr i nt f ( " ** La pr omt er ul READY> **\ n" ) ;
pr i nt f ( " ** I nt r oducet i o expr esi e. Ex. a*( a+a) - a **\ n" ) ;
pr i nt f ( " ** Pent r u i esi r e t ast at i qui t **\ n" ) ;
pr i nt f ( " ** **\ n" ) ;

15
BISON Generator de analizoare sintactice (parsere)
pr i nt f ( " \ n**********************************************\ n" ) ;
yypar se( ) ;
}
yyer r or ( s) {
pr i nt f ( " Expr esi a est e i ncor ect a\ n" ) ;
}
yyl ex( ) {
i nt c;
whi l e ( ( c=get char ( ) ) == ' ' | | c == ' \ t ' ) ;
i f ( c==EOF)
r et ur n 0;
i f ( c == ' Q' | | c == ' q' )
i f ( ( c=get char ( ) ) == ' U' | | c == ' u' )
i f ( ( c=get char ( ) ) == ' I ' | | c == ' i ' )
i f ( ( c=get char ( ) ) == ' T' | | c == ' t ' ) {
yyl val = QUI T;
r et ur n( EOF ) ;
}
el se r et ur n ' ?' ;
r et ur n c;
}

OBSERVATII FINALE
BISON poate fi folosit pentru proiectarea de aplicaii diverse. Dezvoltarea unui proiect
cu ajutorul BISON - ului presupune parcurgerea urmtoarelor etape:
1. Identificarea problemei. Acest lucru presupune o viziune de ansamblu asupra proiectului
stabilindu-se arhitectura sistemului ce urmeaz a fi proiectat, descompunerea sistemului n
funciile componente, etc;
2. Definirea limbajului surs. Obiectul acestui pas este specificarea limbajului care urmeaz
a fi tradus. Cel mai adecvat mecanism pentru aceast specificare este gramatica independent
de context pentru c se poate descrie aceast gramatic direct n limbajul BISON;
3. Scrierea programului de descriere a gramaticii n fiierul de intrare pentru BISON;
4. Scrierea codului auxiliar. n acest pas se stabilesc i se scriu aciunile ataate regulilor
sintactice, funciile necesare lansrii aplicaiei (main(), yylex(), yyerror()) precum i alte
instruciuni C care urmeaz a fi ncorporate n programul generat de BISON;
5. Obinerea funciei yyparse(). Odat creat fiierul de intrare, se lanseaz BISON pentru
acesta i se obine programul surs C. Dac sunt necesare i alte funcii C, acestea se pot
incorpora n programul obinut de BISON;
6. Compilarea textului obinut i obinerea programului executabil.



16

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