34
FLEX + BISON 1. Structura unui analizor lexical si sintatctic r ealizat cu ajutorul utilitarelor flex si bison Instrumentele flex şi bison pot fi folosite împreună pentru a realiza analiza lexicală şi sintactică a unui text şi chiar pentru a obţine un interpretor sau un compilator prin mecanismul acţiunilor semantice. Schema de utilizare împreună a celor două generatoare este dată în figura u rmatoare. Realizarea unui compilator folosind generatoarele automate flex si bison Dacă fişierul a1.l descrie unităţile lexicale ale limbajului pe care dorim să-l implementăm, iar a1.y descrie sintaxa limbajului, atunci comenzile (linux) pentru a obţine fişierul a1.exe din a1.l şi a1.y sunt următoarele: bi son -d a l . y Produce (genereaza) fişierul .tab.c care conţine funcţia de parsare yyparse() Opţiunea -d  produce fişierul header .tab.h care conţine directivele care atribuie un ităţilor lexicale coduri numerice (va conţine declaraţiile pentru terminale). Acestea vor fi folosite de analizorul lexical produs de flex. flex -o al .yy.c al .l Produce fişierul a1.yy.c care conţine definiţia funcţiei yylex() care este invocată de yyparse() pentru obţinerea, pe rând, a unităţilor lexicale din textul sursă. Fişierul a1.l trebuie să conţină directiva #include a1.tab.h. gcc -o al.exe al.y y.c al.tab.c -lm -lf l Compilarea si linkeditarea fis-lor sursa .c, generate de catre flex, respectiv bison. EXEMPLE:  Exemplul 1: Analizor lexical si sintactic pentru limbajul natural. Aplicatia rezultata analizeaza lexical si sintactic doar prop. simple, insa poate fi dezvoltata (ca in exemplul 3 din referatul anterior, cel cu bison-ul). 1 FLEX + BISON

FLEX BISON 2010pp.unlocked

Embed Size (px)

Citation preview

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 1/34

FLEX + BISON

1. Structura unui analizor lexical si sintatctic realizat cu ajutorul utilitarelor flex si

bison

Instrumentele flex şi bison pot fi folosite împreună pentru a realiza analiza lexicală şi sintactică

a unui text şi chiar pentru a obţine un interpretor sau un compilator prin mecanismul acţiunilor 

semantice. Schema de utilizare împreună a celor două generatoare este dată în figura urmatoare.

Realizarea unui compilator folosind generatoarele automate flex si bison

Dacă fişierul a1.l descrie unităţile lexicale ale limbajului pe care dorim să-l implementăm, iar a1.y descrie sintaxa limbajului, atunci comenzile (linux) pentru a obţine fişierul a1.exe din a1.l şia1.y sunt următoarele: bison -d a l . y

Produce (genereaza) fişierul .tab.c care conţine funcţia de parsare yyparse() Opţiunea -d

 produce fişierul header .tab.h care conţine directivele care atribuie unităţilor lexicalecoduri numerice (va conţine declaraţiile pentru terminale). Acestea vor fi folosite deanalizorul lexical produs de flex.

flex -o al .y y. c al .lProduce fişierul a1.yy.c care conţine definiţia funcţiei yylex() care este invocată deyyparse() pentru obţinerea, pe rând, a unităţilor lexicale din textul sursă. Fişierul a1.ltrebuie să conţină directiva #include a1.tab.h.

gcc -o a l .e xe a l .y y .c a l . t ab . c - lm - l f lCompilarea si linkeditarea fis-lor sursa .c, generate de catre flex, respectiv bison.

EXEMPLE:

 Exemplul 1: Analizor lexical si sintactic pentru limbajul natural. Aplicatia rezultata analizeazalexical si sintactic doar prop. simple, insa poate fi dezvoltata (ca in exemplul 3 din referatul

anterior, cel cu bison-ul).

1

FLEX + BISON

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 2/34

 Fisier de intrare (yyin )

Citire din fisierul de intrare

 

 Fisier de iesire ( yyout) - poate coincide cu fis. intrare REZOLVARE:

1. Creati fisierul de specificatii pentru bison (analiz_prop.y):%{/*analiza propozitie simpla*/ #include <stdio.h>

o}

/*sectiunea definitii bison */ %union{char *strval; }%token <strval> SUBST %token <strval> VERB

%type <strval> prop simpla %type <strval> subiect%type <strval> predicat%%prop simpla: subiect predicat {

_ printf("PROP. SIMPLA!!!! subiect %s, predicat %s\n", $1,

$2);};

subiect: SUBST {$$=$1} ;

predicat: VERB {$$=$1} ;%%extern FILE * yyin; #include <stdio.h>

S t u d e n t u l i n v a t a

Analizor lexicalgenerat de flex

Analizorsintactic generatde bison

1/Valoare atomlexical =yylva (ex.

Studentul)

Tip (categorie)atom lexical(ex. SUBST)

Cereredeatomlexical A

2

FLEX + BISON

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 3/34

main(){yyin=stdin;while (!feof(yyin)){ yyparse(); } }

yyerror(char *s){ fprintf(stderr, "%s\n", s); }

Tipurile de atomi sunt definite in cadrul fisierului sursa pentru bison cu directiva %token . Exemplu : %token SUBST

Transferul valorii atomului lexical spre analizorul sintactic se realizeaza cu ajutorul

variabilei yylval. Aceasta variabila are implicit tipul int .

Cu ajutorul directivei %union putem defini o variabila yylval de tip structura de date . Exemplu: %union

{ char *strval; intival; }

Cu ajutorul acestei directive bisonul genereaza in cadrul fisierului y.tab.h o declaratie deforma:

typedef union

{ char* strval;int ival; }YYSTYPE;extern YYSTYPE yylval;

Daca dorim ca in momentul in care analizorul sintactic primeste un identificator(SUBST)sa primeasca si o valoare de tip sir de caractere, putem specifica acest lucru prin :

%token <strval> SUBST%token <ival> NUMAR 

Pentru a specifica ca un neterminal utilizeaza o anumita parte a valorii yylval utilizam odeclaratie de forma : %type <ival> expr;

2. Apelati bison pentru generarea fisierului analiz_prop.tab.c (care contine functia yyparse()), cuoptiunea -d (pentru generarea fişierului header analiz_prop.tab.h, care conţine directivele careatribuie unităţilor lexicale coduri numerice (va conţine declaraţiile pentru terminale); directivelevor fi folosite de analizorul lexical produs de flex). bison —d an a l i z prop.y

3.Creati fis. de specificatii ptr. flex (analiz_prop.l).%{/* analiza unor propozitii! */#include "analiz prop.tab.h" %}

%%[ ] ; /*consumare spatiu */\. {return 0; }Studentul { yylval.strval=yytext;

return

3

FLEX + BISON

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 4/34

(SUBST); }invata { yylval.strval=yytext;

return (VERB);}

%%

4.Apel flex:flex -o analiz_prop.yy.c analiz_prop.l (sau flex -o

aanaliz_prop.yy.c analiz_prop.l )

5.Compilarea si linkeditarea fisierelor generate de flex si bison:gcc —o analiz_prop.exe analiz_prop.yy.c analiz_prop.tab.c -lm -lfl

Sa consideram ca avem pe banda de intrare propozitia : "Studentul învata ."

Analizorul sintactic "cere" analizorului lexical un atom lexical. Acesta citeste caractere de laintrare pana ajunge la un sir de caractere care se potriveste cu una din expresiile regulate date înfisierul sursa flex.

Dupa citirea sirului de caractere Studentul, analizorul lexical determina faptul ca acesta se

 potriveste cu o expresie regulata data în fisierul sursa flex. In acest moment analizorul executaactiunea asociata expresiei regulate studentul .

In cadrul actiunii asociate expresiei regulate Studentul, analizorul lexical intoarce catre analizorulsintactic o valoare intreaga (corespunzatoare constantei SUBST) care specifica faptul ca atomullexical detectat este substantiv. De asemenea intoarce si sirul de caractere asociat substantivului prin intermediul variabilei yylval.strval .

Valorile intoarse de analizorul lexical spre analizorul sintactic sunt pe rand: SUBST , VERB, 0 .Valoarea 0 specifica analizorului sintactic ca s-a terminat preluarea datelor .

Functionarea analizorului sintacticVom urmări stiva asociata acestuia. Valorile primite de la analizorul lexical sunt puse in varfulunei stive. Daca partea de sus a stivei corespunde partii drepte a unei productii din analizorulsintactic, este realizata actiunea corespunzatoare acelei productii, sunt scoase din stiva elementelece corespund partii drepte a productiei si apoi este pusa in stiva partea stanga a productieirespective. Aceasta actiune poarta numele de reducere.

De oricate ori analizorul sintactic nu poate efectua o reducere, acesta cheama un atom lexical dela analizorul lexical. Aceasta operatie se numeste deplasare .

Pentru propozitia data obtinem in stiva :

SUBST -aplicam reducere cu regula 2subiect -intrucat nu e posibila o noua reducere apelam la an. lexical ptr un nou atomsubiect VERB -aplicam reducere cu regula 3

4

FLEX + BISON

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 5/34

subiect predicat -aplicam reducere cu regula 1 se afiseaza date conform actiunii asociate regulii 1 .

 prop_simpla -intrucat nu mai putem realiza nici o reducere apelam analizorul lexical.Analizorul lexical intoarce valoarea 0 corespunzatoare sfarsitului datelor de la intrare. Intrucat instiva avem simbolul de start -> propozitia este corecta conform gramaticii date in analizorulsintactic .

 Arborele sintactic corespunzator analizei precedente este următorul:

In primul pas avem nodul :SUBSTDupa aplicarea reducerii avem :

subiect

SUBST

Dupa realizarea deplasarii avem un arbore de forma :subiect

SUBST VERB

Dupa realizarea reducerii cu productia predicat->VERB obtinem :subiect predicat

SUBST VER BDupa ultima reducere, arborele e de forma :

 prop_simpla / \ subiect predicat

SUBST VER.BDupa cum se observa, arborele este construit plecand de la frunze spre radacina deci avem oconstructie bottom - up (de la frunze spre radacina).

Observaţie: Structura unui program asemanator unui utilitar flex poate contine :-Generarea unui AFN pe baza expresiilor regulate introduse in fisierul sursa

-Transformarea AFN -> AFD-Pe baza AFD obtinut se genereaza cod C pentru analizorul lexical (acceptor ).

Implementarea unei tabele de simboli in cadrul analizorului lexical

0tabela de simboli simpla se poate implementa sub forma unei liste . Exemplu:

#define NIMIC 0struct simbol{

char * nume_simbol;int tip_simbol;

struct simbol * urmatorul;};struct simbol * lista_simboli = NULL; intadauga_simbol( int tip, char * simbol )

1_____________________________________________________________________________ 5

struct simbol * sp;if( cauta_simbol ( simbol ) != NIMIC ){

 printf("!!! Atentie : simbol %s deja definit\n",simbol); return 0;

FLEX + BISON

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 6/34

}sp = (struct simbol *) malloc ( sizeof( struct simbol)); sp-> urmatorul = lista_simboli;sp ->nume_simbol = ( char * ) malloc ( strlen(simbol) + 1 );strcpy(sp -> nume_simbol, simbol);sp -> tip_simbol = tip;

lista_simboli = sp;return 1;}

int cauta_simbol( char * simbol ){

struct simbol * sp = lista_simboli;for( ; sp; sp = sp -> urmatorul){

if( strcmp(sp -> nume_simbol, simbol) == 0 ) return sp -> tip_simbol;}return NIMIC;

}

 Exemplul 2:

 Sa se construiasca cu ajutorul generatoarelor flex si bison un program care sa realizeze

translatarea expresiilor aritmetice din forma normala in forma postfixata.

Definiţie: Notatia postfixata (poloneza).1.daca E e o variabila sau o constanta atunci notatia postfixata pentru E este tot E

2.daca E este o expresie de forma E1 op E2 , unde op este o operatie binara , atunci notatia postfixata pentru E este E1' E2' op unde E1' si E2' sunt notatiile postfixate pentru E1 si E23.Daca E este o expresie de forma ( E1 ) atunci notatia postfixata pentru E este notatia postfixata pentru E1.

 Exemple :

( 9 - 5 ) + 2 in forma postfixata este : 9 5 - 2 + 9 -

( 5 + 2 ) in forma postfixata este : 9 5 2 + -

REZOLVARE:Fisierul de specificatii ptr bison (polish.y)

#include <stdio.h>#include <stdlib.h> %}

%union{ double ct; char id; int ri; }

6

FLEX + BISON

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 7/34

itoken <ct> CTitoken <id> ID•itype <ri> exp•itype <id>

iden iright '='ileft '-' '+'left '*' '/'iright 'A'

taonassoc '('')

 

linie| input linie

linie: '\n'| exp '\n'{printf("\n");}

 

extern FILE*yyin;

main( ) {yy

in 

=

 st

din;

 wh

p:

en:

put:

CT { printf("%g ",$1); }exp '+' exp { printf

("+

exp '-' exp { printf(

"-

exp '*' exp { printf(

"*

exp '/' exp { printf(

"/

exp 'A' exp { printf(

'"A

(' exp ')' { $$=$2; }

iden '= exp { printf(

"=

ID { printf("%c ",$1); }

FLEX + BISON

7

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 8/34

ile 

(!fe

of(

yyin

))

{

yyparse();

}

yyerror (char* s){ printf("%s\n",s); return 0; }

OBS: apelati

bison SI cu

opţiunea -v

(pentru generareafis-lui polish.output) sianalizaţicontinutul fis-lui polish.output!(bison -dv

p o l i s h . y )

Fisierul despecificatii ptr. flex(polish.l):%{#include"polish.tab.h"//extern intyywrapp(); %}

%option noyywrapo a%%[ \t] + [0-9]+{

yylval.ct=a

toi(yytext);retu

FLEX + BISON

8

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 9/34

rn CT; }

[a-z] {

yylval.id=yytext[0];

FLEX + BISON

9

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 10/34

return I

D; }

. {return yyte

xt[0]; }

\n {return 

yytext[0]; }

FLEX + BISON

10

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 11/34

 Exemplul 3:

FLEX + BISON

11

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 12/34

 A

 p

c

a

 ţ 

e

 

 p

e

n

u

 

e

v

a

u

a

FLEX + BISON

12

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 13/34

e

a

 

u

n

o

 

e

 x 

 p

e

 s

 

R

E

Z

O

L

V

A

FLEX + BISON

13

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 14/34

R

E

:

Fisierul sursa pentru bison (expresie.y)%{#

i

n

c

l

u

d

e

 

<

s

td

i

o

.

h

>

 

#

d

e

f

i

ne

 

Y

Y

E

R

R

O

R

_

V

E

RB

O

S

E

 

1

0ext

FLEX + BISON

14

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 15/34

ern int n

owrapp(); %}

%token NUMAR/* Sirul%token arata

definireaterminalelor */

%left '-' '+'

/* %leftarata caoperatiile deadunaresi descadere

suntasociativestanga,sianume:x+y+z=(x+y)+z .Pentruasociativitate

dreaptasefoloseste%right.Dacaoperatiile nu

FLEX + BISON

15

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 16/34

 prezintaasociativitate ,sefoloseste

%nonassoc=(nonassociative)*/

%l

eft 

'

*' 

'/'

 Ono

nass

oc 

UMIN

US

/*UMINUSreprezintaminusulunar.nonassocexprimafaptul ca

FLEX + BISON

16

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 17/34

operator ul nuesteasociativ.Ordinea

dedeclarar e aasociativitatiieste unmecanism ce permitestabilirea

 precedenteioperatiilor .Ultimaoperatiecareia i-a fostdeclarataasociativitateaeste ceamai prioritar a (incazulnostruUMINUS) ,iar  operatiile din prima

declaratie suntcele mai putin prioritar e . Inexemplunostru ,

FLEX + BISON

17

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 18/34

cea mai prioritar aoperatieesteUMINU

S ,urmatade '*' si'/' siapoi de'+' si'-'*/

%%expresie:expresie '+' expresie{$$=$1+$3;

printf("Efectueaza %i +%i,rezultat=%i\n",$1, $3,$$);}

/*r ândulanter ior se

r ef er ala

FLEX + BISON

18

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 19/34

 pr oduc

tia:ex pr esi

e+ex pr esie.Du padetectar 

eaaceste

FLEX + BISON

19

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 20/34

i pr odu

ctiiseexecu

taactiunea:$$=$1+$3,iar 

a poiseex

FLEX + BISON

20

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 21/34

ecuta p

r intf .$$=va

loar eastanga pr oductie.$

1=valoar 

FLEX + BISON

21

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 22/34

ea pr im

eiex pr esiid

in  par teadr ea pta.$3=val

oar eacel

FLEX + BISON

22

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 23/34

eide-a

douaex pr esi

idin  par teadr ea pta*/

|expresie

'-'

expresie{$$=$1-$3;

printf("E

fectueaza %i-

FLEX + BISON

23

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 24/34

%i,rezultat=

%i\n",$1,$3,

$$);}|

expresie'*'expr

esie{$$=$1*$3;

print

f("Efectueaza %i*

%i,rezultat=

%i\n",$1,

$3,$

$);}|

expresie'/'

expresie{ if($3=

=0)y

yerror("impartire cu 0");

else{$$

=$1/

$3

FLEX + BISON

24

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 25/34

;pri

ntf(

"Ef

ectu

eaz 

$1

 / $3

, re

zul

ta

t=

%i\

n", 

$1, 

$3,

 $$)

;

FLEX + BISON

25

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 26/34

}}

expresie %prec UMINUS {$$=-$2;}

/* %prec UMINUS realizeaza legatura cu UMINUS din sectiunea dedefinitii*/

|NUMAR {$$=$1;}

;%%int main( ) {

yyparse( ); }yyerror (char *s){fprintf(stderr,"%s\n",s); }

Fisierul sursa pentru flex (expresie.l)%{#include "expresie.tab.h"

/*fisierul y.tab.h este generat automat de bison (parametru -d). El contine definitii determinale .

Exemplu definitie terminal NUMAR: #define NUMAR 257*/extern int yylval;

/* variabila yylval este definita in fisierul C generat de bison . Ea contine valoareaatomului lexical detectat . De exemplu, pentru un intreg, ea contine valoarea intregului

detectat.*/%r 

%option noyywrap

%%[0-9]+ {yylval=atoi(yytext);

printf("numar=%d\n", atoi(yytext));return NUMAR;} [\t] ; \n return 0;

. return yytext[0];%%

 Exemplul 4: Implementarea unui calculator de buzunar.

Vom construi fişierele pentru flex şi bison care descriu sintaxa expresiilor aritmetice ce se

 pot forma cu constante întregi (CINT), variabile (VAR), operaţiile aritmetice uzuale şi paranteze. Desigur, orice variabilă ce poate apărea într-o expresii trebuie să fie iniţializată cuvaloarea unei expresii . Astfel, un program în accepţiunea de aici este o succesiune deexpresii aritmetice şi/sau asignări. Gramatica ce descrie un astfel de limbaj este următoarea:

program ^ program statement | X

statement ^ expression | VAR '=' expression

expression ^ CINT | VAR

| expression '+' expression

| expression '-' expression

| expression '*' expression

| expression '/' expression

| '(' expression ')' Fişierul  pentru bison, calc.y : acţiunilesemantice au ca efect obţinereavalorii numerice a unei expresiiatunci când ea este transmisă laintrare programului calc.exe ce seobţine. Tabloul

9 !

FLEX + BISON

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 27/34

sym[26] este folosit pentru a păstra valorile variabilelor ce apar în programe; o variabilă este aicio literă (va fi descrisă în fişierul pentru flex).

Fisier specificatii ptr bison (calc.y):%{/* fisierul calc.y */ #include <stdio.h> void yyerror(char *); int yylex(void);

int sym[26]; %}%token CINT VAR %left '+' '-' %left '*' '/'

program:program statement | /* NULL */

statement:expression {printf("%d\n", $1);}| VAR '=' expression { sym[$1] = $3; } ;

expression: CINT| VAR { $$ = sym[$1]; }| expression '+' expression { $$ = $1 +$3; } | expression '-' expression { $$ = $1 -

$3; } | expression '*' expression { $$ = $1 *$3; } | expression '/' expression { $$ = $1 /$3; } | '(' expression ')' { $$ = $2; }

void yyerror(char *s) {fprintf(stderr, "%s\n", s); }int main(void) {yyparse(); }

Fisier specificatii ptr flex (calc.l):%{/* fis. calc.l */ #include <stdlib.h> #include "calc.tab.h"

void yyerror(char *); %}o o %%[a-z] {yylval = *yytext - 'a';return VAR; }[0-9]+ {yylval = atoi(yytext);return CINT; }

[-+()=/*\n] { return *yytext; } /*Variabila yytext este pointer la unitatea lexicala

tocmai depistata, de aceea pentru operatori (token-uri semn) definiţia în fisierul flex*/

1

\n'

27

FLEX + BISON

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 28/34

[ \t] ; /* ignora spatiile */. yyerror("Caracter necunoscut");%%int yywrap(void) {return 1; }

Aplicaţia rezultata (calc.exe) poate "funcţiona" astfel:x = 30 (intrare)

a = 5*6 (intr.)x + a (intr.)60 (rezultat afisat!!!!!)

 Exemplul 5: Sa se realizeze un parser care recunoaşte toate şirurile limbajului: L = {w | w =

anbn , n>0}

REZOLVARE:Gramatica care genereaza acest limbaj este: A ^ aAb | ab (terminalii - tokenii - a si b).

Fisierul de specificatii pentru bison (ab.y):

%{/* ab.y */ #include <stdio.h>#include "ab.tab.h" %}

%token TOKEN_A%token TOKEN_B

%%S : S T '\n' {printf("Sir recunoscut: n= %d\n", $2); }

| S '\n' { /* linie goala tastata */ } |S '.' {return; }| /* lambda, regula implicita */

T : TOKEN_A T TOKEN_B { $$ = $2 + 1;} | TOKEN_A TOKEN_B { $$ = 1; } ;%%

int main(){ yyparse(); return 0;}

int yyerror(char *s) {printf("%s \n", s);}

Regulile gramaticii - in fisierul al.y. Parser-ul are o procesare pe linii. Am "imbunatatit" putingramatica. Prima secţiune defineste cei doi atomi. A doua secţiune descrie gramatica, cu 6 productii (4 pentru S si 2 pentru T).Secţiunea de subrutine contine functiile main() si yyparse() (pentru tratarea erorilor de

sintaxa).Sa analizam sectiunea care descrie gramatica.Deoarece prntru simbolul de start, S, exista o X-productie, acesta este redus implicit (fara a citinimic de pe banda de intrare), parser-ul plaseaza S in vf. stivei.Pentru prima productie a lui S, se detecteaza o linie completa care contine un cuvant din limbajulspecificat; sa va afisa n. Observatie ca $2 reprezinta valoarea celui de-al doilea neterminal din parteadreapta a regulii (T), adica un cuv. al limbajului.A doua productie a lui S precizeaza actiunea cand se gaseste o linie vida (daca se introduce newlinesi pe stiva nu era decat S, atunci acest neterminal se pastreaza). A treia productie a lui S va executa

FLEX + BISON

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 29/34

return din analizorul sintactic atunci cand utilizatorul introduce punct (se incheie procesarea).

Productiile pentru T sunt relativ familiare, insa sa analizam actiunile de realizat.Pentru a doua productie a lui T se detecteaza un n ucleu ab, ir valoarea asociata neterminaluluirezultat al reducerii acestui sir este 1 (s-a recunoscut un sir al limbajului cu n=1).Prima productie pentru T recunoaste recursiv siruri de dimensiuni din ce in ce mai mari, iar valoarea neterminalului in care se reduce contex recunoscut se calculeaza prin incrementareavalorii n eterminalului incadrat intre un a si un b care constituie capatul.

Fiserul de specificatii pentru flex (ab.l):%{/* ab.l

limbaj anbn, n>0 */#include "ab.tab.h"%}

%%a {return TOKEN_A;}

b {return TOKEN_B;}\. {return yytext[0]; }. {printf("atomul %s nu este recunoscut\n", yytext); }\n {return yytext[0]; }

%%

Prima regula: fiecare aparitie a lui a in textul sursa reprezinta TOKEN_A.Regula a doua: fiecare aparitie a lui b - TOKEN_B.Regula a treia: recunoaste punctul. La intalnirea lui, scanner-ul il recunoaste si il paseaza parser-uluica atare, fara a-i asocia vreun cod.Regula a patra: se potriveste tuturor celorlalte caractere nerecunoscute la intrare si afiseaza un mesajde eroare (nu se termina cu return, astfel ca scaner-ul pastreaza mai departe controlul, adica tokenulrecunoscut de aceasta regula este ignorat de parser). Regula a cincea: recunoaste car. newline si iltransmite ca atare parser-ului.

Sectiunea de subrutine - nimic. Exemplul 6: Vom descrie în acest paragraf modul cum se poate proiecta un interpreter folosind

instrumentele flex şi bison. Dorim să interpretăm programe de forma:a = 3 6;b = 42;while (a != b) if(a >b) a = a - b;else b = b - a;print a;

REZOLVARE:

Pentru aceasta vom descrie fişierele de intrare pentru flex respectiv bison. Fişierul pentru flex

descrie unităţile lexicale care vor fi transmise analizorului sintactic construit de bison. Fisierulflex este următorul: /* Fisierul glang.l intrare pentru flex. Se foloseste comandaflex glang.l dupa comanda bison -d glang.y */%{#include <stdlib.h>

#include "glang.h"#include "glang.tab.h"void yyerror(char *); %}o o.%%[a-z] { yylval.sIndex = *yytext - 'a'; return VAR; }

29

FLEX + BISON

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 30/34

[0-9]+ { yylval.iVal = atoi(yytext); return INT; }[-()<>=+*/;{}.] { return *yytext;}">=" { return GE; }"<=" { return LE; }"==" { return EQ; }"!=" { return NE; }"while" { return WHILE; }"if" { return IF; }

"else" { return ELSE; }"print" { return PRINT; }[ \t\n]+ ; /* Spatiile sunt ignorate */. yyerror(" Caracter ilegal!\n");o o.%%int yywrap(void) {return 1; }Fişierul glang.h descrie structurile de date folosite pentru reprezentarea constantelor, aidentificatorilor precum şi a tipurilor de noduri din arborele abstract care va fi costruit deanlizorul sintactic. Identificatorii sunt definiţi aici ca fiind litere şi de aceea am folosit extern intsym[26] ca tabelă a identificatorilor. O să indicăm mai târziu cum se poate aborda cazul general./* Fisierul glang.h */typedef enum { typeCon, typeId, typeOper } nodeEnum; /* constante */

typedef struct {int val; /* valoarea constantei */ } conNodeType; /* identificatori */typedef struct {int i; /* indice in tabela de simboluri */} idNodeType;/* operatori */typedef struct {int oper; /* operator */

int nops; /* nr. operanzi */struct nodeTypeTag *op[1]; /* operanzi */} oprNodeType;typedef struct nodeTypeTag {

nodeEnum type; /* tipul nodului */ union {conNodeType con; /* constante */ idNodeType id; /* identificatori */oprNodeType opr; /* operatori */ };} nodeType; extern int sym[26];

Fişierul glang.tab.h este obţinut de către yacc (bison) atunci când se foloseşte opţiunea - d. Acestfişier defineşte codurile numerice pentru unităţile lexicale: /* Fisierul glang.tab.h creat de bison cuoptiunea -d */#ifndef BISON_GLANG_TAB_H#define BISON_GLANG_TAB_H #ifndef YYSTYPEtypedef union {int iVal; /* valoare intreaga */char sIndex; /* index in tabela de simboluri */ nodeType *nodPtr; /*

pointer la un nod in arbore */

FLEX + BISON

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 31/34

Fişierul de intrare pentru bison descrie sintaxa limbajului de programare împreună cu acţiunile

semantice ce trebuiesc aplicate în cazul reducerilor. Aici este vorba de apelul funcţiei deconstruire a arborelui abstract corespunzător. Iată mai jos fişierul de intrare pentru bison:/* Fisierul glang.y intrare pentru bison. Se foloseste comanda :bison -d glang.y */ %{#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include "glang.h"/* prototipurile functiilor */nodeType *nodOper(int oper, int nops, ...);/* nod operator in arbore */nodeType *nodId(int i);/* nod frunza identificator */ nodeType *nodCon(int value); /* nodfrunza constanta */ void freeNode(nodeType *p); /* eliberare memorie */int interpret(nodeType *p); /* functia de interpretare */ intyylex(void); /* functia creata de flex */ void yyerror(char *s);int sym[26]; /* tabela de simboluri */ %}%union {int iVal; /* valoare intreaga */char sIndex; /* index in tabela de simboluri */nodeType *nodPtr; /* pointer la un nod in arbore */ };%token <iVal> INT %token <sIndex> VAR %token WHILE IF PRINT%nonassoc IFX /* rezolvarea ambiguitatii if-then-else */%nonassoc ELSE%left GE LE EQ NE '>' '<'

%left '+' '-'%left '*' '/'%nonassoc UMINUS%type <nodPtr> stmt expr stmt listo o.%%program: function { exit(0); } ;

function: function stmt { interpret($2); freeNode($2); }| /* NULL */ ;

stmt: ';' { $$ = nodOper(';', 2, NULL, NULL); } | expr ';' { $$ = $1; }| PRINT expr ';' { $$ = nodOper(PRINT, 1, $2); } | VAR '=' expr';'

} yystype

;

# define YYSTYPE yystype# define YYSTYPE IS TRIVIAL 1#endif

# define INT 257# define VAR 25 8# define WHILE 259# define IF 260# define PRINT 261# define IFX 262# define ELSE 263# define GE 264# define LE 2 65

# define EQ 266

# define NE 2 67# define UMINUS 2 68

extern YYSTYPE yylval;#endif /* not BISON_GLANG_TAB_H */

31

FLEX + BISON

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 32/34

{$$ = nodOper('=', 2, nodId($1), $3);} | WHILE '('expr ')' stmt

{ $$ = nodOper(WHILE, 2, $3, $5); } | IF '(' expr')' stmt %prec IFX

{ $$ = nodOper(IF, 2, $3, $5); } | IF '(' expr')' stmt ELSE stmt

{ $$ = nodOper(IF, 3, $3, $5, $7); } | '{'stmt_list '}' { $$ = $2; }

stmt list:"stmt { $$ = $1; }

| stmt_list stmt { $$ = nodOper(';', 2, $1, $2); } ;expr:

INT { $$ = nodCon($1); } | VAR { $$ =nodId($1); } | '-' expr %prec UMINUS

o o oo

{ $$ = nodOper UMINUS,

1, $2); }

expr '+'

expr

{ $$ = nodOper '+'

,2,

$1,

$3);

expr '-

'

expr

{ $$ = nodOper '-'

,2,

$1,

$3);

expr expr{ $$ = nodOper ,

2,$1,

$3);

expr '/'

expr

{ $$ = nodOper ,2,

$1,

$3);

expr '<'

expr

{ $$ = nodOper '<'

,2,

$1,

$3);

expr '>'

expr

{ $$ = nodOper '>'

,2,

$1,

$3);

expr GE expr{ $$ = nodOper GE

,2, $1, $3); }

expr LE expr{ $$ = nodOper LE

,2, $1, $3); }

expr NE expr

{ $$ = nodOper NE, 2, $1, $3); }

expr EQ expr{ $$ = nodOper EQ

,2, $1, $3); }

'(' expr ')'$$ = $2

;}

FLEX + BISON

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 33/34

#define SIZEOF_NODETYPE ((char *)&p->con - (char *)p) nodeType*nodCon(int value) { nodeType *p; size t nodeSize;

/* alocare memorie pentru noul nod */ nodeSize =SIZEOF_NODETYPE + sizeof(conNodeType); if ((p = malloc(nodeSize))== NULL) yyerror("out of memory"); /* copiere valoare constanta */ p->type= typeCon; p->con.val = value; return p;

}

nodeType *nodId(int i) { nodeType *p; size t nodeSize;

/* alocare memorie pentru noul nod */nodeSize = SIZEOF_NODETYPE + sizeof(idNodeType);if ((p = malloc(nodeSize)) == NULL)

yyerror("out of memory"); /* copierevaloare indice */ p->type = typeId; p->id.i =i; return p;

}

nodeType *nodOper(int oper, intnops, ...) { va list ap;nodeType *p;size t nodeSize; int i;

/* allocare memorie pentru noul nod */ nodeSize =SIZEOF_NODETYPE + sizeof(oprNodeType) + (nops - 1) *sizeof(nodeType*); if ((p = malloc(nodeSize)) == NULL)

yyerror("out ofmemory"); /* copiereinformatii functie denops */ p->type =typeOper; p->opr.oper =oper; p->opr.nops =nops; va start(ap,nops); for (i = 0; i <nops; i++)

p->opr.op[i] = va arg(ap, nodeType*); vaend(ap); return p;

}

void freeNode(nodeType *p) { int i;if (!p) return;if (p->type == typeOper) {for (i = 0; i < p->opr.nops; i++)freeNode(p->opr.op[i]); }free (p);

}

void yyerror(char *s) {fprintf(stdout, "%s\n", s);

}

int main(void){ yyparse();return 0;}

Conform regulilor următoare (din fişierul tocmai prezentat):function: function stmt { interpret($2);freeNode($2); }| /* NULL */ ;

un program în limbajul sursă descris este un şir de instrucţiuni (stmt). Fiecare din acesteinstrucţiuni este interpretată: apelul funcţiei interpret pentru argumentul $2 care este valoarea33

FLEX + BISON

8/3/2019 FLEX BISON 2010pp.unlocked

http://slidepdf.com/reader/full/flex-bison-2010ppunlocked 34/34

atributului lui stm, adică arborele construit pentru stmt, face ca această instrucţiune să fieexecutată. Prin freeNode($2) se eliberează memoria alocată la construirea arborelui amintit.Funcţia interpret() este prezentată mai jos : /* Functia interpret(nodeType *p) */#include <stdio.h> #include "glang.h" #include "glang.tab.h" int

interpret(nodeType *p) { if (!p) return 0; switch(p->type) {case typeCon: return p->con.val;case typeId: return sym[p->id.i];case typeOper:

switch(p->opr.oper) {case WHILE: while(interpret(p->opr.op[0]))interpret(p->opr.op[1]); return 0; case IF: if (interpret(p-

>opr.op[0])) interpret(p->opr.op[1]); else if (p->opr.nops > 2)interpret(p->opr.op[2]); return 0;case PRINT: printf("%d\n", interpret(p->opr.op[0]));

return 0; case ';':interpret(p->opr.op[0]);

return interpret(p->opr.op[1]); case '=': return sym[p->opr.op[0]->id.i] =

interpret(p->opr.op[1]); case UMINUS:return -interpret(p->opr.op[0]); case '+':return interpret(p->opr.op[0]) +

interpret(p->opr.op[1]); case '-': return interpret(p->opr.op[0])-

interpret(p->opr.op[1]); case '*': return interpret(p->opr.op[0])*

interpret(p->opr.op[1]); case '/': return interpret(p->opr.op[0]) /

interpret(p->opr.op[1]); case '<': return interpret(p->opr.op[0])<

interpret(p->opr.op[1]); case '>': return interpret(p->opr.op[0])>

interpret(p->opr.op[1]); case GE: return interpret(p->opr.op[0])>=

interpret(p->opr.op[1]); case LE: return interpret(p->opr.op[0])<=

interpret(p->opr.op[1]); case NE: return interpret(p->opr.op[0]) !=

interpret(p->opr.op[1]); case EQ: return interpret(p->opr.op[0])== interpret(p->opr.op[1]);

}}return 0;

}

În urma lansării comenzilor bison -dv glang.y şi flex -oglang.yy.c glang.l se obţin fişierele

glang.tab.c (analizorul sintactic), glang.output, glang.tab.h, respectiv glang.yy.c (analizorullexical). Fisierele glang.tab.c si glang.yy.c, impreună cu interpretorul din fişierul interpret.c, vor fi compilate cu un compilator de limbaj C şi se obţine astfel un interpreter pentru limbajul sursădescris.(gcc -o glang.exe glang.tab.c glang.yy.c interpret.c -lm -lfl)

Dacă lansăm acest interpreter pentru programul prezentat la începutul exemplului, se obţinerezultatul 6.

FLEX + BISON