Sunteți pe pagina 1din 7

Universitatea din Petroșani,

IME, Calculatoare, anul III


Limbaje Formale și Translatoare

Referat
“ Flex & Bison”

Studenta:
Flex și Bison sunt instrumente pentru construirea programelor care gestionează intrările
structurate. Ele erau inițial instrumente pentru construirea compilatoarelor, dar s-au dovedit a fi
utile în multe alte domenii.

GNU Bison, cunoscut sub numele de Bison, este un generator de parser (analizor
sintactic) care face parte din Proiectul GNU. Bison citește o specificație a unui limbaj liber de
context, avertizează cu privire la orice ambiguități de parsing, și generează un parser (fie în C, C
++ sau Java), care citește secvențe de token-uri, decide dacă secvența este conformă cu sintaxa
specificată. Bison implicit generează parseri LALR, dar poate crea și parseruri GLR.

Flex (generatorul de analizoare sintactice rapide) este o alternativă software gratuită și


open-source la lex. Este un program de calculator care generează analizoare sintactice (cunoscute
și ca "scanere" sau "lexeri"). Flex este folosit frecvent ca implementare lex împreună cu
generatorul de parser Berkeley Yacc pe sistemele de operare derivate din BSD (atât lex cât și
yacc fac parte din POSIX), sau împreună cu GNU Bison (o versiune a yacc) în porturile BSD și
în distribuțiile Linux. Spre deosebire de Bison, flex nu face parte din Proiectul GNU și nu este
lansat sub licența GNU General Public .

Flex a fost scris în C de către Vern Paxson în jurul anului 1987.

Bison a fost scris inițial de Robert Corbett în 1985. Mai târziu, în 1989, Robert Corbett a
lansat un alt generator de parser numit Berkeley Yacc. Bison a fost făcut compatibil cu Yacc de
Richard Stallman.

Bison este descendent din yacc, un generator de parser scris între 1975 și 1978 de către
Stephen C. Johnson la Bell Labs. Instrumentul lui Johnson a combinat o fundație teoretică fermă
din lucrarea de analiză a lui D. E. Knuth, care a făcut parserii săi extrem de fiabili și cu o sintaxă
de intrare convenabilă. Acestea au făcut-o extrem de populară printre utilizatorii sistemelor Unix,
deși licența restrictivă în care a fost distribuit Unix la acea vreme i-a limitat utilizarea sa în afara
mediilor academice și a sistemului Bell.

Cele mai veche compilatoare din anii 1950 au folosit tehnici complet ad-hoc pentru a
analiza sintaxa a codului sursă al programelor pe care le compilau. În anii 1960, domeniul acesta
a primit o mulțime de atenție academică, iar la începutul anilor 1970, analiza sintaxei a fost un
domeniu bine înțeles.

În jurul anului 1985, Bob Corbett, student absolvent al Universității din California,
Berkeley, a reimplementat yacc folosind algoritmi interni oarecum îmbunătățiți, care au evoluat
în Berkeley yacc. Deoarece versiunea sa a fost mai rapidă decât yacc-ul lui Bell și a fost
distribuită sub licența flexibilă Berkeley, ea a devenit rapid cea mai populară versiune a yacc-
ului. Richard Stallman de la Fundația pentru Software Liber (FSF) a adaptat lucrarea lui Corbett
pentru utilizarea în proiectul GNU, unde a fost extins pentru a include un număr mare de
caracteristici noi, deoarece a evoluat în versiunea actuală a Bisonului. Bison este acum menținut
ca un proiect al FSF și este distribuit sub licența publică GNU.

În 1975, Mike Lesk și internul de vară, Eric Schmidt, au scris Lex, un generator de
analize lexicale, majoritatea programărilor fiind realizate de Schmidt. Ei au văzut-o atât ca un
instrument independent, cât și ca un companion al yacc-ului lui Johnson. Lex a devenit, de
asemenea, destul de popular, în ciuda faptului că a fost relativ lent și buggy. (Schmidt totuși a
continuat să aibă o carieră destul de reușită în industria computerelor, unde este acum CEO al
Google.)

În jurul anului 1987, Vern Paxson din laboratorul Lawrence Berkeley a luat o versiune a
Lexului scrisă în Ratfor (Rational Fortran) și a tradus-o în C, numindu-l Flex, pentru "
Fast Lexical Analyzer Generator", și mai fiabilă decât AT & T lex și, ca Berkeley yacc,
disponibilă sub licența Berkeley, a înlocuit complet Lexul original. Flex este acum un proiect
SourceForge, încă sub licența Berkeley.

Flex / Bison poate fi util pentru parsarea oricărui element care are gramatică, explicită sau
implicită. Lista neexhaustivă include:

• Compilatoare
• Derivatoare
• Limbi specifice domeniului
• Validatori / unelte pentru scame

Parserul este un switch-of-switch-uri ... de-switch-uri. Flex și Bison oferă dezvoltatorilor o


abstracție de nivel superior pentru a scrie parserii lor într-un mod declarativ, în timp ce aceste
instrumente generează mașini de parsing imperative în limbajul C sub capotă.

Notă: în contextul Flex / Bison există două semnificații ale cuvântului "parser" și ambele sunt
folosite foarte des: parser ca Bison (comparativ cu Flex ca Lexer) și parser ca Flex + Bison
împreună (care este de fapt Lexer + parser).

Scanerele funcționează în general prin căutarea tipurilor de caractere din intrare. De exemplu,
într-un program C, o constantă întreg este un șir de una sau mai multe cifre, numele variabilei
este o literă urmată de zero sau mai multe litere sau cifre, iar diferiții operatori sunt caractere
unice sau perechi de caractere. Un program flexibil constă într-o listă de RegExp cu instrucțiuni
despre ceea ce trebuie făcut atunci când intrarea se potrivește cu oricare dintre ele, cunoscut sub
numele de acțiuni. Un scanner generat prin flexiune citește prin intrare, potrivind intrarea cu
toate RegExpii și făcând acțiunea potrivită pentru fiecare meci. Flex traduce toate RegExpurile
într-o formă internă eficientă, care le permite să se potrivească cu toate modelele simultan, deci
este la fel de rapid pentru 100 de modele ca pentru unul.
Majoritatea programelor cu scanere flexibile utilizează scanerul pentru a returna un flux de
token-uri care sunt manipulate de un parser. De fiecare dată când programul are nevoie de un
simbol, acesta cheamă yylex (), care citește o mică intrare și returnează tokenul. Când are nevoie
de un alt simbol, acesta apelează din nou yylex (). Scanerul acționează ca o corutină; adică, de
fiecare dată când se întoarce, își amintește unde era, iar la următoarea chemare se preia unde sa
oprit.

În interiorul scanerului, când codul de acțiune are un token gata, acesta îl returnează doar ca
valoare din yylex (). Data viitoare când programul apelează yylex (), reia scanarea cu
următoarele caractere de intrare. În schimb, dacă un model nu produce un jeton pentru programul
de apelare și nu se întoarce, scanerul va continua să intre în același apel la yylex (), scanând
următoarele caractere de intrare.

Programele Bison au (nu prin coincidență) aceeași structură cu trei părți ca și programele
Flex, cu declarații, reguli și cod C. Declarațiile de aici includ codul C care trebuie copiat la
începutul parserului C generat, din nou închis în% {și%}. În continuare, sunt declarații cu
caractere % token , spunând lui Bison numele simbolurilor din parser care sunt token-uri. Prin
convenție, token-urile au caractere majuscule, deși Bison nu o cere. Orice simboluri care nu sunt
declarate ca token-uri trebuie să apară în partea stângă a cel puțin unei condiții din program.
(Dacă un simbol nu este nici un simbol și nici nu apare în partea stângă a unei condiții, este ca o
variabilă nereferențiată într-un program C. Nu rănește nimic, dar probabil înseamnă că
programatorul a făcut o greșeală.)

Bison face automat parsarea astfel încât codul de acțiune să mențină valorile asociate fiecărui
simbol. De asemenea, parserii Bison efectuează efecte secundare, cum ar fi crearea de structuri
de date pentru utilizare ulterioară sau imprimarea rezultatelor.

Fiecare simbol dintr-o condiție din Bison are o valoare; valoarea simbolului țintă (cea din
stânga colonului) se numește $$ în codul de acțiune, iar valorile din dreapta sunt numerotate $ 1,
$ 2 și așa mai departe. Valorile token-urilor sunt oricare ar fi fost în yylval când scanerul a
returnat tokenul; valorile altor simboluri sunt setate în condițiile din parser. În acest parser,
valorile simbolurilor factor, termen și exp sunt valoarea expresiei pe care o reprezintă.

Scanarea împarte intrarea în bucăți semnificative, numite token-uri, și parsează cifrele


referitoare la modul în care ele se raportează reciproc. De exemplu:

alpha = beta + gamma ;

Un scanner împarte acest lucru în token-uri alfa, semnul egal, beta, semnul plus, gamma
și punct și virgulă. Apoi parserul determină că beta + gamma este o expresie și că expresiei îi
este
Un exemplu de program scris folosind flex și bizon este următorul calculator de birou.
Mai întâi vom scrie un scanner și apoi vom scrie un parser și îi vom combina.

/* recunoaște token-uri de la calculator și le printează */


%%
"+" { printf("PLUS\n"); }
"-" { printf("MINUS\n"); }
"*" { printf("TIMES\n"); }
"/" { printf("DIVIDE\n"); }
"|" { printf("ABS\n"); }
[0-9]+ { printf("NUMBER %s\n", yytext); }
\n { printf("NEWLINE\n"); }
[ \t] { }
. { printf("Mystery character %s\n", yytext); }
%%

Primele cinci modele sunt operatori literali, scrise ca șiruri de caractere, iar acțiunile,
pentru moment, tipăresc doar un mesaj care spune ce se potrivește. Citatele spun flexului să
utilizeze șirurile ca atare, mai degrabă decât să le interpreteze ca expresii regulate.

Al șaselea model se potrivește cu un număr întreg. Modelul bracket [0-9] se potrivește cu


o singură cifră, iar următorul semn + înseamnă pentru a se potrivi cu unul sau mai multe dintre
elementele precedente, care înseamnă aici un șir de una sau mai multe cifre. Acțiunea imprimă
șirul care se potrivește, utilizând indicatorul yytext pe care scanerul îl stabilește după fiecare
potrivire.

Al șaptelea model se potrivește cu un caracter de linie nouă, reprezentat de secvența


obișnuită C \ n.

Al optulea model ignoră spațiul alb. Se potrivește cu orice spațiu sau filă (\ t), iar codul
de acțiune gol nu face nimic.

Modelul final este cel care se potrivește cu orice alte modele nu au făcut-o. Codul său de
acțiune imprimă o plângere adecvată.

Aceste nouă modele oferă acum reguli care să se potrivească cu tot ce poate introduce
utilizatorul. Pe măsură ce vom continua să dezvoltăm calculatorul, s-ar adăuga mai multe reguli
pentru a se potrivi cu mai multe token-uri.
Scanerul va arăta astfel:

$ flex fb1-3.l
$ cc lex.yy.c -lfl
$ ./a.out
12+34
NUMBER 12
PLUS
NUMBER 34
NEWLINE
5 6 / 7q
NUMBER 5
NUMBER 6
DIVIDE
NUMBER 7
Mystery character q
NEWLINE
^D
$

Mai întâi executăm Flex, care traduce scanerul într-un program C numit lex.yy.c, apoi compilam
programul C și în final îl executăm.

În concluzie, Flex poate fi folosit ca instrument independent, dar cel mai adesea este utilizat
împreună cu Bison: Flex împuternicește executarea "codului C specific" corespunzător unui
simbol specific lui Bison, astfel încât responsabilitatea Lexer este de a produce token-uri și
responsabilitatea lui Bison este de a decide ce de a face cu aceste token-uri.
Bibliografie:

• “flex & bison”, John Levine, O’Reilly Media. 2009


• https://en.wikipedia.org/wiki/Flex_(lexical_analyser_generator)
• https://en.wikipedia.org/wiki/GNU_bison
• www.safaribooksonline.com
• stanislaw.github.io

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