Flex Bison
Flex Bison
Flex Bison
Sadraj
Predgovor 1 Uvod
1.1 1.2 Istorijat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Leksika analiza i sintaksna analiza 1.2.1 1.2.2 Skeniranje i regularni izrazi Parsiranje i gramatike 1.2.2.1
iv 1
1 2 3 3 4
. . . . . . . . . . . . . . . . . .
BNF gramatike . . . . . . . . . . . . . . . . .
Flex
2.1 Format 2.1.1 2.1.2
ex
specikacije
. . . . . . . . . . . . . . . . . . . . .
8 8 9 10 10 11 11 11 13 14 16
Denicije
. . . . . . . . . . . . . . . . . . . . . . . . .
Pravila . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.1.2.1
ex
regularni izrazi
. . . . . . . . . . . . . .
Korisniki kod
. . . . . . . . . . . . . . . . . . . . . .
Komentari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
ex
skeneri
2.3
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19 19 20 21 22 24 25 26 27
2.4
Vebe
Bison
3.1 LR parseri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.1 3.2 Format 3.2.1 3.2.2 3.2.3 3.3 Generatori LR parsera . . . . . . . . . . . . . . . . . .
29
29 30 31 31 31 33 33 37 38 40 41 41 43 45 45 47 50 52
bison
specikacije
. . . . . . . . . . . . . . . . . . . .
Denicije
. . . . . . . . . . . . . . . . . . . . . . . . .
Shift-reduce
3.4 3.5
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Broj rei i reenica u ulaznom tekstu . . . . . . . . . . Rei iz ulaznog teksta 3.5.2.1 3.5.2.2 . . . . . . . . . . . . . . . . . . . . .
Tekst u zagradama . . . . . . . . . . . . . . .
55
55 56
59
59 60
61 62 63 67
iii
iv
Predgovor
Ova zbirka zadataka je napisana za potrebe kursa Programski prevodioci na Fakultetu tehnikih nauka, Univerziteta u Novom Sadu. Namera zbirke je da prenese konkretne tehnike i alate koji se koriste za implementaciju kompajlera.
Flex
bison
su korisni i za mnoge aplikacije koje e zanimati i one koji se ne bave kompajlerima. Svaka aplikacija koja trai obrasce ( ima ulazni ili komandni jezik je dobar kandidat za tavno odravanje programa.
primeri, pokretanja programa i gramatika mC jezika. Svako poglavlje, na kraju, sadri vebe, koje nude dodatni rad za one koji to ele.
Pregled
Uvod, prua istorijski pregled alata lex i yacc, kao i njihovih potomaka ex i bison, i daje pregled kako i u kojim situacijama se koriste ex i bison.
Poglavlje 1, Poglavlje2, Poglavlje3, Poglavlje 4,
Flex, detaljno opisuje nain upotrebe ex-a kroz nekoliko primera. Bison, daje potpune primere koji koriste i ex i bison.
Konikti i njihovo razreavanje, objanjava dvosmislenosti i konikte u bison-u, i probleme u gramatici koji onemoguuju bison da napravi
v
Poglavlje 5,
prepoznavanje i prijavljivanje greaka u ulaznoj datoteci. Renik sadri tehnike pojmove iz teorije kompajlera. Pretpostavlja se da je italac familijaran sa programskim jezikom C, jer su svi primeri na C-u,
ex-u i bison-u.
lex i yacc.
GNU Project od strane Free Software Foundation zajednice distribuira i on je ukljuen u sve uobiajene distribucije Linux (poslednju) verziju, moete je nai na
web
stranici:
http://www.gnu.org/software/bison/
ator ), u uobiajenim distribucijama Linux-a, ali ako elite poslednju verziju, moete je nai na web stranici:
http://flex.sourceforge.net/
Zahvalnica
Autori ele da se zahvale studentima koji su imali u rukama
draft
verziju
zbirke zadataka na kursu Programski prevodioci i koji su nali brojne slovne i druge greke u prvim verzijama materijala, i uinili ovaj materijal itljivijim i zanimljivijim. Autori
vi
Poglavlje 1
Uvod
Flex
ulaz. i
bison
veoma korisni i u mnogim drugim oblastima. Evo nekoliko primera za ta se mogu koristiti
ex i bison
desktop
kalkulator
domenske jezike za odreenu aplikaciju alate za preprocesiranje raznih dokumenata programske kompajlere, npr. C kompajler sam
ex
U ovom poglavlju emo se upoznati sa istorijatom ovih alata i sa osnovnim teorijskim postavkama koje stoje iza ovih alata.
1.1 Istorijat
Bison
je potomak programa
yacc
Stiven C. Johnson iz Bell Labs, u periodu izmeu 1975 i 1978. samo ime
yacc
kae (skraeno od
kompajler kompajlera), u to vreme su mnogi ljudi pisali generatore parsera. Johnson je svoj alat zasnovao na vrstoj teorijskoj osnovi i na radu D. E. Knuth-a, koja je proizvela izuzetno pouzdane parsere. Ova pouzdanost je poveala
bison-ovu
restriktivna licenca, pod kojom je Unix distribuiran u to vreme, ograniavala njegovo korienje izvan univerziteta i Bell laboratorija. 1
POGLAVLJE 1.
UVOD
yacc koristei donekle naprednije algoritme i razvio Berkli yacc (Byacc, Berkeley yacc )[2]. Poto je njegova verzija bila bra od Bell-ovog yacc -a, a i deljen je pod eksibilnijom Berkli licencom, brzo je postao najpopularnija verzija yacc -a. Richard Stalman, iz FSF (Free
Berkliju, je reimplementirao Software Foundation), je adaptirao Corbett-ov rad za korienje u GNU projektu. Alat je proiren mnogobrojnim novim karakteristikama i evoluirao je u trenutnu verziju pod GNU javnom licencom (
bison -a. Bison je sada projekat FSF-a i distribuira se GNU Public Licence ) [7]. 1975 godine, Majk Lesk i pripravnik Eric Schmidt su napisali lex, generator
leksikih analizatora [4].
spor i bagovit. Oko 1987, Vern Paxson iz Lawrence Berkeley Lab je uzeo verziju na C i nazvao ga
lex -a
fast lexical analyzer generator ) [6]. Poto lex -a i dostupan pod Berkli licencom, potpuno je zamenio originalni lex. Flex je sada SourceForge projekat,
(skraeno od je bio bri i pouzdaniji od AT&T verzije jo uvek pod Berkli licencom.
ex
ad hoc
a = b + c;
skener deli u tokene:
a, znak jednakosti, b, znak plus, c i znak taka-zarez. Zatim parser utvruje da je b + c izraz, a da se izraz dodeljuje promenljivoj a.
1.2.
regex ex
ili
regexp.
regular expressions ),
koji se esto
Flex
program (
Uz svaki regualrni izraz stoji uputstvo o tome ta skener treba da radi kada ulazni string odgovara tom regularnom izrazu. Ova uputstva se zovu akcije. Skener koji se izgenerie iz varajuu akciju. formu
ex-a
Flex
sve regularne izraze prevodi u ekasnu unutranju jednako brz za 100 obrazaca kao i za jedan.
obrascima. Zato je
ex
+ 5
1 * 2 + 3 * 4
parse tree ).
Na
1*2+3*4+5
nite automation,
DFA)
POGLAVLJE 1.
UVOD
Mnoenje ima vei prioritet od sabiranja, pa su prva dva izraza 1 * 2 i 3 * 4 listovi tog stabla. Onda se ta dva izraza sabiraju, pa se na tu sumu dodaje 5. Svaka grana stabla pokazuje odnos izmeu tokena ili podstabla ispod nje. Struktura ovog konkretnog stabla je vrlo jednostavna.
Bison
pravi
stablo parsiranja dok parsira ulazni tekst. Ovo stablo je samo implicitno, u sekvenci operacija koje parser vri, ali sam korisnik moe eksplicitno kreirati stablo, kao strukturu podataka u memoriji.
grammar,
context-free
Simbole
jeziku. Gramatika opisuje sintaksu jezika, ali ne i semantiku. Gramatika se sastoji od pravila, simbola (
terminals )
i pojmova (
nonterminals ).
prepoznaje skener, dok pojmove i ispravnost redosleda pojmova prepoznaje parser. Standardna forma u kojoj se piu CFG gramatike je Bakus-Naurova forma (
::=
::=) je pojam.
BNF pravilo moe biti rekurzivno, to znai da se ime sa leve strane pravila denie pomou samog sebe (pa se isto ime pojavljuje i na desnoj strani pravila). U primeru su oba pravila, i
exp i factor,
denisana rekurzivno.
ex je veoma
Za kompleksnije
1.2.
ex
Flex
ex
olakava pronalaenje greaka. Uopteno, ako se pravila za podelu ulaznog teksta u tokene moe opisati regularnim izrazima, Takoe,
ex
je pravi izbor.
bison
bison
radi verikaciju
POGLAVLJE 1.
UVOD
Poglavlje 2
Flex
Leksiki analizator (skener) je program namenjen za leksiku analizu (skeniranje) teksta. Skener radi tako to ita tekst, karakter po karakter, i pokuava da prepozna neku od zadatih rei. Kada prepozna re (sekvencu karaktera) izvri zadatu akciju. Skener se moe napraviti (isprogramirati) runo ili korienjem alata za generisanje skenera. era je program
ex . Flex
Jedan od esto korienih alata za generisanje skengenerie skener na osnovu pravila zadatih u
ex
specikaciji. Specikaciju kreira korisnik u posebnoj datoteci koja po konvenciji ima ekstenziju
.l.
koje skener treba da prepozna. Pravila se zadaju u obliku regularnih izraza. Svakom regularnom izrazu mogue je pridruiti akciju (u obliku
C koda) koja
e se izvriti kada skener prepozna dati regularni izraz. Uobiajena akcija je vraanje oznake simbola, odnosno tokena za taj simbol. Token je numerika oznaka grupe (vrste) simbola. Na primer: token broj (i
2 i 359),
dok token
IF
NUMBER
if.
.l
datoteka se prosleuje
yylex() u datoteci lex.yy.c. Akcije, pridruene regularnim .l datoteci, su delovi C koda koji se direktno prenose (kopilex.yy.c. Ovako generisan C kod moe da se prevede i C i C++ yylex(), lanici klase yyFlexLexer ili lanici
ex -u,
kompajlerom (tj. moe da se ukljui u C ili u C++ program). Ako se za generisanje skenera, umesto programa biva generisan u C++ funkciji
ex
pozove program
ex++ 1 , skener
1
`+`.
U pitanju je isti program, samo se drugaije ponaa kada mu se ime zavrava znakom
POGLAVLJE 2.
FLEX
yyFlexLexer.
Ovako gener-
isan skener moe da se ukljui samo u C++ program. Ovakav program predstavlja leksiki analizator koji transformie ulazni tekst u niz tokena (u skladu sa pravilima zadatim u specikaciji). Korienje programa
ex
ex -a
Prilikom izvravanja, skener e traiti pojavu stringa u ulaznom tekstu koji odgovara nekom regularnom izrazu. Ako ga pronae, izvrie akciju (kod) koju je korisnik pridruio tom regularnom izrazu. U suprotnom, podrazumevana akcija za tekst koji ne odgovara ni jednom regularnom izrazu je kopiranje teksta na standardni izlaz.
%%:
ex
2.1.1 Denicije
Prvi deo se obino koristi za ukljuivanje zaglavlja i denicije promenljivih (pri emu ovakav kod mora biti okruen specijalnim zagradama ovom delu se navode jo i regularne denicije, obavezan.
ex
%{ i %}).
ex
specikacije nije
ex
nudi razne opcije za pravljenje skenera. Veina se moe navesti u oliku u prvom delu specikacije, ili kao
%option name
2.1.
--name
ex -a.
Da bi se neka opcija iskljuila, pre imena opcije treba dodati string no, kao na primer:
ili
%option noyywrap
yywrap().
ex -u
da ne
opie ponaanje skenera posle itanja datoteke (npr. da nastavi itanje neke druge datoteke). Ako funkcija
yywrap()
nije den-
isana, podrazumeva se da e skener preuzeti i itati samo jednu ulaznu datoteku i da e nakon itanja kraja datoteke vratiti pozivaocu vrednost
0.
Zgodno je znati broj skenirane linije u
ex
denie promenljivu
ije i automatski je aurira svaki put kada proita karakter mora dodeliti vrednost datoteke.
2.1.2 Pravila
Drugi deo specikacije sadri niz pravila koja opisuju ponaanje skenera. Na osnovu ovih pravila obliku:
ex
obrazac
[ akcija ]
Obrasci se zadaju korienjem proirenog skupa regularnih izraza (datog u nastavku), a akcije blokom C (ili C++) koda koji e se izvriti kada skener prepozna obrazac. Obrazac mora da pone u prvoj koloni, a akcija ne mora da postoji. Ako akcija postoji, njena denicija mora da pone u istom redu u kojem je denisan obrazac. Ovaj deo
ex
specikacije je obavezan.
10
POGLAVLJE 2.
FLEX
2.1.2.1
ex -u.
znaenje, ispred njega treba staviti kosu crtu (\) ili ga navesti pod navodTako, na primer, regularni izraz osim
a iza kojeg sledi bilo koji karakter b (taka se tretira kao operator).
newline
a.b
regularni izraz
x "x" \x x? x* x+ x|y [xy] [x-z] [^x] . ^x x$ (x) x/y {xx} x{m,n} x, x,
znaenje
karakter ak i ako je ak i ako je
opciono
x x
x
operator operator
(0 ili 1 instanca)
y ili y karakteri x, y
ili
x x
x x z
ili
x x
x newline
na poetku linije
na kraju linije
x n x
pravilo za
xx m
ex -u
main(),
koji e biti
bez izmena prekopiran na kraj generisanog skenera. Ovaj deo datoteke omoguava da se ceo program smesti u samo jednu (.l) datoteku. Kompleksni programi se svakako (zbog itljivosti) rasporeuju u
2.2.
FLEX SKENERI
11
2.1.4 Komentari
U
// /*...*/
Komentari se u
ex
kroz nekoliko
ex
zero.l)
je prikazana u
zero.l
%%
Ova datoteka sadri samo oznaku
%%.
(koja ne sadri nijedno pravilo) prihvata karaktere sa standardnog ulaza i kopira ih na standardni izlaz (karakter po karakter). Iz ovog jednostavnog primera se vidi da e svi karakteri iz ulaznog teksta, koji ne budu prepoznati (koji se ne uklapaju ni u jedan od zadatih obrazaca), biti ispisani na standardnom izlazu. Skener se generie, kompajlira i pokree naredbama:
12
POGLAVLJE 2.
FLEX
ex
lex.yy.c.
zero.l
--noyywrap, prosleen ex -u, kae da korisnik ne eli da denie funkciju yywrap().
U drugoj liniji pozivamo
gcc
kompajler i prosleujemo mu
yylex().
lex.yy.c
da-
--o
prosleen
gcc-u
grama koji e biti izgenerisan. Ukoliko se ne upotrebi ovaj svi, kompajler e napraviti izvrnu datoteku sa imenom Uz program funkcija
a.out.
U ovoj biblioteci je denisana
main(),
ex
dolazi i biblioteka
libl.a.
yylex():
main() koristi se ona iz biblioteke. -l govori linkeru da pogleda u biblioteku ije ime je navedeno iza svia. Tom prilikom se iz imena biblioteke izostavljaju prva tri slova: `lib` (jer se 2 ona podrazumevaju ) i ekstenzija. Otuda, -l l u pozivu gcc-a. ./zero
se izgenerisani skener pokree u interak-
tivnom reimu, to znai da se ulaz oekuje preko tastature, a da se program zavrava kada se na ulazu pavi kombinacija
^D.
Ukoliko elimo skeneru da prosledimo datoteku (test.txt) na skeniranje, upotrebiemo redirekciju standardnog ulaza:
2.2.
FLEX SKENERI
13
2.2.2 Obrasci
Obrasci opisuju sekvence (nizove) karaktera koje skener treba da prepozna. Kada je potrebno prepoznati samo jednu sekvencu karaktera (kao na primer kljunu re
if
njam),
tu sekvencu je mogue
ex
datoteka
prikazan na listingu 2.2. Kada se prepozna, ova re e biti ignorisana. Listing 2.2:
njam.l
%% njam
Ako se zatim, ponovo izgenerie, kompajlira i pokrene, program ponaa sliano programu
zero
njam
se
prosledi na izlaz. Ako se na ulazu pojavi niz karaktera interaktivna sesija programa
njam
njam
izgleda ovako:
$ ./ njam Ovo prolazi bez izmena . Ovo prolazi bez izmena . njam Cunjam ovuda . Cu ovuda .
Kada je potrebno prepoznati sve sekvence karaktera iz neke klase (kao na primer: broj, kao niz od jedne ili vie cifara), tada se za specikaciju obrasca koriste sloeniji izrazi, iz proirenog skupa regularnih izraza. Sledi primer (listing 2.3) specikacije skenera koji prepoznaje prirodne brojeve. Listing 2.3:
num.l
%% [0 -9]+
Uglaste zagrade opisuju klasu karaktera bilo koji karakter u rasponu od ASCII karaktera 0 do ASCII karaktera 9 (tj. postojati). Izlaz ovog programa moe da izgleda ovako: bilo koja cifra), a operator + kae da se cifra moe ponavljati jednom ili vie puta (bar jedna mora
14
POGLAVLJE 2.
FLEX
2.2.3 Akcije
Akcija je
C (ili C++) kod koji skener izvrava kada prepozna string koji odgo-
varaju obrascu. Na listingu 2.4 je prikazan skener sa samo jednim pravilom koji prepoznaje beline (proizvoljno dugake sekvence praznih mesta i tabova) i zamenjuje ih samo jednim praznim mestom. Listing 2.4:
ws.l
Obrazac je regularni izraz koji opisuje: ili razmak ili tab jednom ili vie puta. Akcija je poziv C funkcije koja ispisuje jedan karakter - jedno prazno mesto na standardni izlaz. praznim mestom. Upotreba ovog programa: Kako se ova akcija izvrava svaki put kada skener prepozna niz razmaka i/ili tabova, dobija se efekat zamene belina jednim
$ ./ ws Neko pise reci odvojene jednim razmakom a neko Neko pise reci odvojene jednim razmakom a neko ne . ^D $
ne .
Na listingu 2.5 je prikazan skener sa samo jednim pravilom, koji prepoznaje karaktere za novi red (newline) i broji ih. Listing 2.5:
lines.l
%{ %} %%
int lines = 0;
2.2.
FLEX SKENERI
15
\n %%
{ lines ++; }
0.
Promenljiva
inkrementira unutar akcije, tj. svaki put kada se prepozna karakter za novi
main()), ve nakon toga jo i ispie broj redova u proitanom tekstu. test.txt, sa sadrajem: test.txt
words.l
[a - zA - Z ]+ .
Obrazac za re opisuje stringove ili malo ili veliko slovo jednom ili vie puta. Svaki put kada se prepozna re, izvrava se akcija koja je vezana za taj obrazac. globalnoj Provera da li je prvo slovo prosleenog stringa veliko se vri rei se nalazi u je tipa pomou funkcije
char*
ex -ovoj
i u svakom
16
POGLAVLJE 2.
FLEX
U prethodnim primerima smo videli da se svi neprepoznati karakteri sa ulaza prosleuju na izlaz. Ukoliko ne elimo da se, pored rei sa prvim velikim slovom, ispisuju i ostali (neprepoznati) simboli, potrebno je dodati pravilo koje prepoznaje bilo koji karakter (operator
.)
Ukoliko se ovakav program pokrene sa ulaznom datotekom prethodnog primera, dobie se izlaz:
test.txt
iz
ex -a,
sledei nain: kada parser aktivira leksiku analizu, skener poinje sa itanjem preostalog ulaznog teksta, jedan po jedan karakter, dok ne nae najdui niz karaktera koji odgovara nekom obrascu. pridruena prepoznatom obrascu. ukoliko se u njoj izvri naredba vraanje kontrole parseru. Tada, izvrava akciju koja je Akcija moe da vrati kontrolu parseru
return.
analizator nastavlja da ita ostatak ulaznog teksta, dok akcija ne izazove Ponavljanje traenja stringova dok se kontrola eksplicitno ne vrati parseru, olakava skeneru obradu praznina i komentara. Skener parseru ne prosleuje npr. string prepoznatog simbola, ve token za taj simbol (slika 2.2). Token je numerika oznaka kategorije (vrste) simbola (npr. token
IF
opisuje kljunu re
if,
token
NUM
ID
Slika 2.2: Komunikacija izmeu skenera i parsera Na listingu 2.8 sledi primer prepoznavanja kljune rei
ex
specikacije.
return.l
%{
2.2.
FLEX SKENERI
17
%} %% if [0 -9]+ [a - zA - Z ]+ %% int main () { int tok ; while ( tok = yylex () ) { switch ( tok ) { case IF : printf ( " IF " ) ; break ; case NUM : printf ( " NUM " ) ; break ; case WORD : printf ( " WORD " ) ; break ; } } }
Svaka od akcija vraa odgovarajui token prepoznatog simbola. U praksi, funkciju skenera najee poziva parser, dok u ovom primeru to radi funkcija
main().
if IF, za string 123 vraa NUM, za string abc token WORD). Za string 5abc, vidimo da skener vraa 2 tokena: prvo za string 5 vraa token NUM, a zatim za string abc vraa token WORD. Skener je, krenuvi od karaktera 5, pokuao da pronae najdui string koji se poklapa sa nekim obrascem. Naao je samo jedan obrazac koji zapoinje brojem ([0-9]+). Preuzeo je sledei karakter a, ali je zakljuio da se on ne uklapa u obrazac za broj, pa
Za svaki pojedinani string skener vraa odgovarajui token (za string vraa token ga je vratio nazad na standardni ulaz - odakle ga je i preuzeo (da bi se taj karakter obradio u okviru sledeeg simbola). Skener je uspeo da prepozna
NUM. Dalje nastavlja skeniranje tamo gde je stao i preuzima ponovo karakter a, zatim b i onda c, prepoznaje to kao re i vraa token WORD. Svi neprepoznati karakteri (npr: !) se samo prosleuju na standardni izlaz.
broj koji se sastoji samo od 1 cifre i za njega vraa token Skener parseru, osim tokena, moe da vrati i neku vrednost koja preciznije
18
POGLAVLJE 2.
FLEX
opisuje svojstva tokena. U sluajevima kada skener prepozna jednostavne rei, kao to su kljune rei (npr.
(vratiti) token te kljune rei. U sluaju kada skener prepozna identikator ili broj, parseru je, osim tokena, potrebno proslediti i konkretan string imena odnosno vrednost konkretnog broja. Ova vrednost se prosleuje preko globalne promenljive a uobiajeno je da se ova promenljiva denie kao unija (union), jer se za razliite simbole vezuje razliita vrednost (drugaijeg tipa). Unija je promenljiva koja moe uvati objekte razliitih tipova i veliina, odnosno to je jedna promenljiva koja moe sadrati vrednost jednog od nekoliko tipova (a programer je duan da vodi rauna o tome koji tip vrednosti se trenutno uva u uniji). Za prethodni primer, potrebno je u prvom delu specikacije, denisati uniju. Listing 2.9:
yylval.
int,
union.l
- unija
if
IF
Uz token
NUM
int.
int).
Listing 2.10:
union.l
- pravila
if [0 -9]+ [a - zA - Z ]+
Uz token
{ return IF ; } { yylval . n = atoi ( yytext ) ; return NUM ; } { yylval . s = yytext ; return WORD ; }
se prosleuje konkretni string rei, jer se rei mogu razliito
WORD
napisati. Ovaj string se smea u polje Izmena funkcije 2.11). Listing 2.11:
promenljive
yylval.
union.l - main()
case IF : printf ( " IF " ) ; break ; case NUM : printf ( " NUM : % d " , yylval . n ) ; break ; case WORD : printf ( " WORD : % s " , yylval . s ) ; break ;
2.3.
PRIMERI
19
2.3 Primeri
2.3.1 Broj rei, karaktera i redova u tekstu
Napraviti skener koji preuzme sve karaktere sa ulaza i ispie:
koliko je bilo rei koliko je bilo karaktera koliko je bilo redova. Listing 2.12:
wclc.l
%} %%
[a - zA - Z ]+ \n . %%
{ words ++; chars += strlen ( yytext ) ; } { chars ++; lines ++; } { chars ++; }
main () { yylex () ; printf ( " chars : %d , words : %d , lines : % d .\ n " , chars , words , lines ) ; }
Prvi deo specikacije sadri opciju za iskljuivanje funkcije efekat smo u ranijim primerima postizali navoenjem svia komandnoj liniji prilikom poziva
ex -a.
U prvom delu specikacije se nalaze i denicije 3 promenljive koje e uvati broj karaktera, rei i linija. Prvi obrazac
[a-zA-Z]+
ceo obrazac opisuje niz slova, tj. re. Akcija inkrementira broj vienih rei
prepoznat na osnovu tog obrasca. U ovom sluaju, ne zanima nas koji je to string, ve koliko karaktera ima u njemu.
20
POGLAVLJE 2.
FLEX
Drugi obrazac
\n
mentira broj karaktera i broj redova. Trei obrazac je regularni izraz koji opisuje bilo koji karakter osim karaktera za novi red. Akcija inkrementira broj karaktera.
main
funkciju
yylex()
i ispisuje vrednosti 3
brojaa.
sa tastature:
$ flex wclc . l $ gcc lex . yy . c $ ./ a . out Eci peci pec ti si mali zec ^D chars : 28 , words : 7 , lines : 2. $
Prvo kaemo
(C program koji je izgenerisan), pokrenemo program i otkucamo mali ulaz za skener. Izgleda da radi.
ex -u
da prevede skener na
C,
zatim kompajliramo
lex.yy.c
Neki ozbiljniji program, koji broji rei i karaktere, bi imao malo drugaiju deniciju rei: niz karaktera koji nisu belina, pa bi izgleda ovako:
ex
pravilo moglo da
[^ \ t \ n \ r \ f \ v ]+
Operator
jednostavno napravite izmene u obrascu, a zatim pustite izmenama u izgenerisanom kodu skenera.
ex
ex -a:
da brine o
wsdot.l
2.3.
PRIMERI
21
Ovaj skener treba da reaguje na beline pre i posle take, a sve ostale karaktere da proputa na izlaz. Zato pravimo dva pravila. Prvo pravilo opisuje prepoznavanje 0 ili vie belina pre take, iza kojih sledi taka, iza koje sledi niz od 0 ili vie belina. Akcija koja se izvrava u sluaju da se pronae taka okruena belinama je da se ceo string zameni stringom . , ime zadovoljavamo zahtev zadatka da posle take treba da stoji samo jedno prazno mesto. Drugo pravilo kae da svi karakteri, koji ne odgovaraju prvom pravilu, treba da prou na izlaz neizmenjeni. To se dobije akcijom koja radi eho ulaznog stringa na izlaz (ECHO). Ovaj program bi se ponaao isto i da smo izostavili drugo pravilo, jer
ex
$ ./ wsdot Prva recenica . Druga recenica . Treca recenica . Cetvrta Prva recenica . Druga recenica . Treca recenica . Cetvrta . ^D $
comments.l
% x COMMENT %% " /* " /* Blok komentari */ { BEGIN COMMENT ; /* predji u stanje COMMENT */ } { /* preskoci tekst komentara */ } { BEGIN INITIAL ; /* vrati se u normalno stanje */ }
%x COMMENT.
To
22
POGLAVLJE 2.
FLEX
Prva tri pravila slue za prepoznavanje blok komentara. Prvo pravilo ulazi u
COMMENT kada prepozna /*, a tree pravilo se vraa nazad u normalno INITIAL stanje kada prepozna */. Drugo pravilo prepoznaje sve to se nalazi
stanje izmeu, odnosno tekst komentara. Ako bismo dodali jo i pravilo
< COMMENT > < < EOF > > { printf ( " line % d : Unterminated comment \ n " , yylineno ) ; return 0; }
mogli bismo da detektujemo i prijavimo nezavrene komentare. Poslednje pravilo opisuje jednolinijske komentare (dva kojih moe da sledi proizvoljan broj karaktera). Za ulaznu datoteku
slash
karaktera iza
test-comment.c,
Listing 2.15:
test-comment.c
/* vraca vrednost 1 ako se vrednost prvog parametra nalazi u navedenim granicama . Inace vraca 0. */ int interval ( int x , int lower , int upper ) { if ( x >= lower && x <= upper ) return 1; // vrati bool vrednost true else return 0; // vrati bool vrednost false }
program daje izlaz: Listing 2.16:
out.c
int interval ( int x , int lower , int upper ) { if ( x >= lower && x <= upper ) return 1; else return 0; }
0B0110.
2.3.
PRIMERI
23
Listing 2.17:
2to10.l
%{ %} %%
0[ bB ][01]{1 ,32}
} {
for ( i = yytext +2; * i !=0; ++ i ) { val < <= 1; val += * i - '0 '; } printf ( " % d " , val ) ; val = 0; ECHO ; }
celobrojnu neoz-
koja
val, koja e sluiti za konverziju vrednosti, i pokazivaku promenljivu e sluiti kao iterator for petlje. b, '0'
zatim malo ili a zatim minimalno jedna, a maksimalno 32 binarne cifre.
Prvo pravilo prepoznaje binarne brojeve kao karakter veliko slovo ator
Akcija koja prati ovo pravilo radi konverziju binarnog u dekadni broj. Iter-
for
preskae
0b.
Promenljiva
za ispravnu konverziju sledeeg broja. Drugo pravilo preusmerava sve ostale karaktere na izlaz (poziva makro Primer pokretanja bi mogao da izgleda:
123
24
POGLAVLJE 2.
FLEX
%{ %} %%
re sum - vraa pozivaocu sumu unetih vrednosti re mean - vraa pozivaocu srednju vrednost unetih vrednost re quit - dovodi do zavretka programa. Listing 2.18:
cmd.l
{ sum += atof ( yytext ) ; count ++; } { printf ( " Sum : % f " , sum ) ; sum = 0; count = 0; } { printf ( " Mean : % f " , sum / count ) ; sum = 0; count = 0; } { return 0; } { }
float brojeve kao jednu ili vie cifara, iza ega sledi
To znai da su taka i cifra
taka, iza ega opciono sledi 0 ili vie cifara. sabira vrednost broja u promenljivoj
ispred take obavezni, a cifre iza take nisu. Akcija, dodeljena ovom pravilu,
sum.
Drugo i tree pravilo opisuju prepoznavanje stringa komande i izvravaju akciju: ispisuju rezultat komande i resetuju promenljive. etvrto pravilo vraa vredost izuje komandu
quit.
0,
Poslednje pravilo sve ostale karaktere prosleuje na izlaz. Primer pokretanja programa:
$ ./ cmd
2.3.
PRIMERI
25
1.1 2.2 sum Sum : 3.300000 5.5 3.5 6. mean Mean : 5.000000 quit
dd-mmm-yyyy.
Listing 2.19:
dd/mm/yyyy,
date.l
% option noyywrap yylineno %{ %} %% char * months [] = { " " , " jan " , " feb " , " mar " , " apr " , " maj " , " jun " , " jul " , " avg " , " sep " , " okt " , " nov " , " dec " };
[0 -9]{2}\/[0 -9]{2}\/[0 -9]{4} { printf ( " %d -% s -% d " , atoi ( yytext ) , months [ atoi ( yytext +3) ] , atoi ( yytext +6) ) ; }
slash
karakter jedan of
ex
slash
karakterom
\/.
/.
Kada
se prepozna datum u prvobitnom obliku, ispisuje se datum u novom obliku, sa crticama. Promenljiva indeksu 6. Funkcija
yytext
atoi()
$ ./ date Danas je utorak 06/11/2012 godine . Danas je utorak 6 - nov -2012 godine . ^D $
26
POGLAVLJE 2.
FLEX
rei koje poinju velikim slovom: prvo jedno veliko slovo, a zatim 0 ili vie malih slova:
[A-Z][a-z]*
[a-z]+
text.l
% option noyywrap yylineno %{ char * yylval ; # define _DOT # define _CAPITAL_WORD # define _WORD
1 2 3
%} %%
static char * tokens [] = { " " , " _DOT ", " _CAPITAL_WORD " , " _WORD " };
[ \ t \ n ]+ "." [A - Z ][ a - z ]* [a - z ]+ . %%
{ /* skip */ } { return _DOT ; } { yylval = yytext ; return _CAPITAL_WORD ; } { yylval = yytext ; return _WORD ; } { printf ( " \ nline % d : LEXICAL ERROR on char % c " , yylineno , yytext [0]) ; }
main () { int token = -1; while (( token = yylex () ) != 0) { printf ( " \ n %16 s TOKEN : %s " , yytext , tokens [ token ]) ; if ( token == _CAPITAL_WORD || token == _WORD ) { printf ( " value : % s " , yylval ) ; } }
2.4.
VEBE
27
}
Prvi deo specikacije sadri opcije za iskljuivanje funkcije ukljuivanje brojanja linija
yylineno.
yywrap
i za
vrednostima 1, 2 i 3. Dalje su denisani stringovi koji odgovaraju imenima tokena, i slue za tampanje izlaza programa. Vrednosti tokena odgovaraju indeksima njihovih stringova. Prvo pravilo preskae beline. Drugo pravilo prepoznaje taku i vraa samo token. Tree i etvrto pravilo prepoznaju rei i vraaju i token i string simbola kroz promenljivu denisana
je promenljiva
yylval
Poslednje pravilo slui za prijavljivanje leksike greke: ako je neki karakter dospeo u ovo pravilo, znai da nije odgovarao nijednom prethodnom pravilu, a to znai da njegova pojava nije ni predviena. Funkcija
main
$ ./ a . out Ovo je tekst . Za skeniranje . Ovo je tekst . Za skeniranje . TOKEN : TOKEN : TOKEN : TOKEN : TOKEN : TOKEN : TOKEN : _CAPITAL_WORD _WORD _WORD _DOT _CAPITAL_WORD _WORD _DOT value : Ovo value : je value : tekst value : Za value : skeniranje
^D $
2.4 Vebe
1. Proiriti prvi primer (sa listinga 2.7), tako da posebno ispie broj rei koje poinju velikim slovom i broj rei koje poinju malim slovom. 2. Napraviti skener (slian primeru 2) koji prepravi ulazni tekst tako da se iza take uvek nalazi veliko slovo. Ispravka treba da se primeni samo u sluaju da reenica poinje reju, a ne, recimo, brojem. Na primer, ulaz:
28
POGLAVLJE 2.
FLEX
dd/mm/yyyy
Na primer, ulaz
31/12/2012
treba da se izmeni u
HH:MM (gde su sati predstavljeni brojevima 0-24) u oblik HH:MM AM ili HH:MM PM (gde su sati predstavljeni brojevima 0-12). Na primer,
ulazni tekst se izmeni u
da se izmeni u
4:55 PM,
dok ulaz
2:55
treba da
5. Napraviti skener, koji prima tekst napisan na amerikom engleskom jeziku, i menja neke rei na britanski engleski jezik. Rei koje treba zameniti su: am color fall cookie fries freeway br colour autumn biscuit chips motorway
Poglavlje 3
Bison
Sintaksa jezika opisuje pravila po kojima se kombinuju simboli jezika (npr. u
while iskazu se prvo navede kljuna re while, zatim se u malim zagradama navodi logiki izraz, a iza zagrada slede naredbe koje ine telo while iskaza).
Sintaksa se opisuje gramatikom, obino pomou BNF notacije. Svako pravilo se sastoji od leve i desne strane. Sintaksna analiza ima zadatak da proveri da li je ulazni tekst sintaksno ispravan. Ona to ini tako to preuzima niz tokena od skenera i proverava da li su tokeni navedeni u ispravnom redosledu. Ako jesu, to znai da je ulazni tekst napisan u skladu sa pravilima gramatike korienog jezika, tj. da je sintaksno ispravan. U suprotnom, sintaksna analiza treba da prijavi sintaksnu greku i da nastavi analizu. Opisani proces se vri u delu kompajlera koji se zove parser i naziva se parsiranje. U toku parsiranja gradi se stablo parsiranja.
3.1 LR parseri
LR parseri spadaju u grupu
bottom-up
parsiranja od listova ka korenu stabla. U toku parsiranja se prvo preuzimaju simboli (tokeni) sa ulaza i parser pokuava da prepozna desnu stranu nekog pravila i da ga zameni levom stranom pravila. Cilj je da se stigne do korena stabla, tj. do polaznog pojma gramatike. To je trenutak kada je parsiranje uspeno zavreno. L (left) oznaava da se ulaz ita s eva na desno, a R (right) oznaava da se koristi
29
30
POGLAVLJE 3.
BISON
LR parseri koriste dve vrste akcija koje se odnose na ulazni tekst i njihov stek:
shift : reduce :
simbol se proita iz ulaznog teksta i stavi se na stek gornjih N elemenata steka uvaju simbole identine sa N simbola koji se nalaze sa desne strane odreenog pravila. Reduce akcijom se ovih N simbola zamenjuje pojmom koji se nalazi sa leve strane tog pravila.
shift-reduce
accept : error :
ova akcija se izvrava kada je proitan ceo ulazni tekst, a na steku se nalazi samo jedan, i to poetni, pojam gramatike ako ulazni tekst nije u skladu sa gramatikom, parser nee moi da primeni ni greku.
shift
ni
reduce
bison .
Ko-
bison -a
Speci-
.y
ila se zadaju u BNF obliku. Svakom pravilu je mogue pridruiti akciju (u obliku
.y datoteka se prosleuje bison -u, koji kao izlaz, generie C program y.tab.c.
Kod koji je izgenerisao
y.tab.c se
3.2.
31
prosleuje
a.out.
Ovaj pro-
gram predstavlja parser koji proverava sintaksnu ispravnost ulaznog teksta (na osnovu pravila gramatike). Prilikom izvravanja, parser e od skenera traiti naredni token iz ulaznog teksta i proveriti da li je njegova pojava na datom mestu dozvoljena (da li je u skladu sa gramatikom). Ako jeste nastavie parsiranje, a ukoliko nije, prijavie greku, pokuae da se oporavi od greke i da nastavi parsiranje. U momentu kada parser prepozna celo pravilo, parser e izvriti akciju koja je pridruena tom pravilu.
Bison
3.2.1 Denicije
Prvi deo se obino koristi za ukljuivanje zaglavlja i denicije promenljivih (pri emu ovakav kod mora biti okruen specijalnim zagradama rei
%{
%}).
U ovom delu se deniu i tokeni tako to se ime tokena navede iza kljune
%token.
3.2.2 Pravila
Drugi deo specikacije sadri gramatiku, odnosno pravila koja opisuju sintaksu jezika. Gramatika svakog jezika obuhvata: simbole, pojmove, pravila i polazni pojam. Na osnovu ovih pravila pravilo se zadaje u obliku:
bison
pravilo
[ akcija ]
Pravila se piu na formalan nain u BNF obliku, a akcije blokom C (ili C++) koda koji e se izvriti kada skener prepozna pravilo. Obrazac mora da pone u prvoj koloni, a akcija ne mora da postoji. Ako akcija postoji,
32
POGLAVLJE 3.
BISON
njena denicija mora da pone u istom redu u kojem je denisan obrazac. Ovaj deo opisa Pravila ( simbola:
bison
programa je obavezan.
::=)
sekvencom pojmova i/ili simbola koje sadri desna strana pravila (iza znaka
::=).
To znai da se leva strana pravila moe zameniti desnom stranom Jedan od pojmova predstavlja polazni pojam i on se
pravila, i obrnuto.
IF-ELSE
expr,
zatvorene zagrade
stmt.
),
iskaza
stmt,
IF,
otvorene zagrade
kljune rei
ELSE,
(,
i na kraju,
IF-ELSE
Bison
::=
ili strelice
->
3.3.
PARSIRANJE
33
bison
specikaciji.
main(),
koji e, bez
3.3 Parsiranje
Bison
preuzima gramatiku iz specikacije i pravi parser koji prepoznaje reenice, odnosno iskaze te gramatike. Programi mogu biti sintaksno ispravni, ali semantiki neispravni (na primer, C program koji
string
dodeljuje
int
promenljivoj).
Bison
rukuje samo
sintaksnom, a sve ostale validacije su ostavljene korisniku. Postupak parsiranja e biti opisan na primeru gramatike za jednostavni kalkulator:
e opisuje izraz (expression ). NUMBER, PLUS i MINUS su simboli. NUMBER odgovara broj (niz cifara), simbolu PLUS karakter +, a simbolu MINUS karakter -. Vertikalna crta (|) znai da za isti pojam postoje dve
razliite mogunosti i opisuje se reju ILI. U ovom sluaju, izraz moe biti ili sabiranje ili oduzimanje. Svi pojmovi koji se koriste u gramatici moraju biti denisani, odnosno mora postojati bar jedno pravilo u kom se taj pojam nalazi na levoj strani. Na levoj strani pravila se ne sme nai token (to je greka). Uobiajeni nain da se predstavi isparsiran tekst je stablo. Na primer, ako se parsira ulaz:
2+3
34
POGLAVLJE 3.
BISON
2+3
Parser ne kreira automatski ovakvo stablo kao strukturu podataka, iako je relativno jednostavno da korisnik to uradi. Pravila mogu da pozivaju, direktno ili indirektno, sama sebe, pa se zovu rekurzivna pravila. Time je omogueno parsiranje proizvoljno dugakih ulaznih nizova. Ako prethodnu gramatiku malo izmenimo, dobiemo:
gde
lines
\n.
e i lines su pojmovi.
NUMBER, NEWLINE, PLUS i MINUS su NEWLINE odgovara karakter za novi parsira ulaz 2+3\n, stablo izgleda kao na
slici 3.3.
2+3\n
3.3.
PARSIRANJE
35
U ovom primeru,
Svaka gramatika U
ima poetni pojam, onaj koji mora da bude koren stabla parsiranja. ovoj gramatici poetni pojam je poetnim, treba da bude naveden kao prvo pravilo u se ime poetnog pojma navede iza kljune rei specikacije, na primer:
%start,
bison
specikaciji ili da
u prvom delu
bison
% start lines
U naem primeru pravilo
To znai da se ime pravila nalazi na poetku (na levom kraju) desne strane pravila. Zbog ove osobine, mogue je parsirati izraz primenom pravila prikazano je na slici 3.4).
2+3-4+5 ponovljenom e (deo stabla parsiranja koji se odnosi na ovaj ulazni izraz
Slika 3.4: Deo stabla parsiranja za izraz Listing 3.1 sadri vanje iskaza. Listing 3.1:
2+3-4+5
ex,
a listing 3.2
bison
calc1.l
%{ %} %%
[ \ t ]+ [0 -9]+
36
POGLAVLJE 3.
BISON
{ { { {
return PLUS ; } return MINUS ; } return NEWLINE ; } printf ( " Unknown char % c \ n " , * yytext ) ; }
bison,
calc1.tab.h koju
U pravilima se prepoznaje broj kao niz cifara i uz token se prosleuje konkretna vrednost broja (podrazumevanti tip promenljive
yylval je int).
Za simbole
Listing 3.2:
calc1.y
%{
%}
# include < ctype .h > # include < stdio .h > int yyparse ( void ) ; int yylex ( void ) ; NUMBER PLUS MINUS NEWLINE
lines : | lines NEWLINE | lines e NEWLINE ; e : | | ; e PLUS NUMBER e MINUS NUMBER NUMBER
3.3.
PARSIRANJE
37
lines
opisuje prazan red ili red u kojem se nalazi izraz iza kog sledi karakter za novi red. Izraz je rekurzivno denisan kao jedan broj, ili sabiranje ili oduzimanje dva broja.
main()
pozvae se funkcija
yyerror()
$ bison -d calc1 . y $ flex -- noyywrap calc1 . l $ gcc -o calc1 calc1 . tab . c lex . yy . c $ ./ calc1 2+3 5 -2 ^D $
Prvo se pokrene
ex
koji napravi
izvrni program
vata izraze, ali ne izvrava sabiranje i oduzimanje, jer pravilima jo nismo pridruili akcije, tj. nismo mu rekli ta da radi kada prepozna izraz i liniju.
3.3.1 Akcije
Hajde da pravilima u prethodnoj 3.3): Listing 3.3:
bison
calc2.y
{ $$ = $1 + $3 ; }
38
POGLAVLJE 3.
BISON
| | ;
{ $$ = $1 - $3 ; } { $$ = $1 ; }
U akcijama se koriste meta-promenljive, ija imena poinju karakterom a iza nje sledi broj. desnoj strani pravila. Tako se meta-promenljiva simbola je u parser stigla preko promenljive Meta-promenljiva
'$',
$1
yylval,
$$
sadri njegovu vrednost. To znai da, kada elimo da deniemo vrednost nekog pojma, u njegovom pravilu emo imati akciju Krenuemo od poslednjeg pravila za izraz akciju
{ $$ = ...
; }.
e dobija istu onu NUMBER, a to je konkretna vrednost prepoznatog broja, jer smo u skeneru, uz token NUMBER preko yylval, prosledili i vrednost
Ova akcija kae da vrednost pojma vrednost koju ima simbol broja (slika 3.5).
{ $$ = $1; }.
e : NUMBER
Slika 3.5: Prenoenje vrednosti simbola iz skenera u parser U pravilu za oduzimanje dodali smo akciju oduzeti 2 broja. a
$3
$1
{ $$ = $1 - $3; },
gde emo
e),
sadri vrednost drugog broja (koji se nalazi na treoj poziciji desne Vrednosti pojma
$3).
$$)
se
prepoznavanja jedne linije sa izrazom, ispisuje vrednost izraza. Ovu akciju ne treba dodati u ostala dva pravila za navanje praznih linija, bez izraza, pa nema ni izraunavanja ni ispisivanja.
bison
pravi parser,
3.3.
PARSIRANJE
39
on kreira skup stanja, od kojih svako odraava poziciju u pravilu koje se parsira. Dok parser ita tokene, svaki put kada proita token kojim se jo nije kompletiralo pravilo, on ga stavi na interni stek i pree u novo stanje. Ova akcija se zove
shift .
stranu pravila, on ih sve ukloni sa steka i umesto njih na stek stavi pojam sa leve strane pravila, a zatim pree u novo stanje. Znai, zamenio je desnu stranu pravila na steku levom. Ova akcija se zove elemenata na steku. Kad god
bison
prepozna
akciju koja je pridruena tom pravilu. Da vidimo kako e parser parsirati ulaz
1+2\n.
kroz izmene na steku stanja i steku vrednosti (vrhovi oba steka su gore). Na poetku parsiranja, oba steka su prazna (slika 3.6.a). Pre preuzimanja prvog karaktera, deava se redukcija po prvom pravilu, koja prazan red pretvara u
lines
1.
NUMBER
NUMBER,
e, pa izvrava redukciju. Sa steka stanja uklanja NUMBER i menja ga pojmom e, a sa steka vrednosti uklanja vrednost 1 i stavlja vrednost pojma e. Vrednost
strani nekog pravila. Konstatuje da ini desnu stranu pravila za pojma se rauna u akciji koja je pridruena tom pravilu i koja se izvrava u toku redukcije. U toj akciji pie da vrednost pojma simbola
NUMBER
NUMBER ($1),
a to je vrednost
e ($$)
dobija vrednost
(vidi 3.6.d).
1+2\n
Poto ne moe da izvri vie nijednu redukciju, parser se ponovo obraa skeneru za token. Dobija token 3.6.e). Uz token
PLUS
40
POGLAVLJE 3.
BISON
i dobija token
NUMBER
i vrednost
(vidi 3.6.f ).
Sada poslednja 3 elementa na vrhu steka ine desnu stranu pravila da uklanja 3 elementa sa steka stanja i stavlja pojam uklanja 3 elementa i stavlja novu vrednost
za
3.
e, a sa steka vrednosti
e dobija kao zbir prvog operanda ($1 - u naem sluaju vrednost 1) i drugog operanda ($3 - u naem sluaju vrednost 2). Vrednosti simbola NUMBER se pristupa preko meta-promenljive $3, jer se simbol nalazi na treem
pojma mestu na desnoj strani pravila, a istovremeno je trei element koji je skinut sa steka (vidi 3.6.g). Parser dalje iftuje simbol uradi redukciju po pravilu (vidi 3.6.i). Nakon toga, iftuje da uradi
NEWLINE (vidi 3.6.h) i sada je u mogunosti da lines : lines e NEWLINE. U procesu redukcije uklanja po 3 elementa sa svakog steka i stavlja pojam lines na steku stanja EOF karakter, jer je stigao do kraja datoteke i u prilici je EOF
karakter (3.6.j, 3.6.k). U ovom
accept
Bison
rukuje
To je zato to na svom
steku uva sve simbole koji su dotad vieni za sva delimino isparsirana pravila. Ako se koristi desno rekurzivna verzija pravila
exp_list
i na ulazu
se pojavi lista od 10 izraza, kad se bude proitao 10-ti izraz, na steku e biti ve 20 elemenata: izraz i zarez za svih 10 izraza. Kada se lista zavri, svi ugnjedeni
exp_list
exp_list
exp,
exp_list,
pravilo
3.5.
PRIMERI
41
3.5 Primeri
3.5.1 Broj rei i reenica u ulaznom tekstu
Data je gramatika teksta: Tekst se sastoji od 0 ili vie reenica. Reenica zapoinje reju na ijem poetku je veliko slovo. Zatim mogu da slede rei koje zapoinju bilo velikim bilo malim slovom. Na kraju stoji taka. Napraviti parser koji e izbrojati rei i reenice koje se pojave u ulaznom tekstu. Tekst gramatika u
text : | ;
sentence : _CAPITAL_WORD words _DOT ; words : /* empty */ | words _WORD | words _CAPITAL_WORD ;
Skener, koji predstavlja deo reenja ovog primera, je ve dat na listingu 2.20 (glava 2.3.7). Razlika je u tome, to je prethodni skener napravljen kao samostalni program, pa sadri svoju je listingu 3.5. Listing 3.5:
main()
count1.l
% option noyywrap yylineno %{ # define YYSTYPE char * # include " count1 . tab . h " %} %% [ \ t \ n ]+ { /* skip */ }
42
POGLAVLJE 3.
BISON
[a - z ]+ .
{ yylval = yytext ; return _WORD ; } { printf ( " \ nline % d : LEXICAL ERROR on % c " , yylineno , * yytext ) ; }
Broja reenica
se inkrementira svaki put kada se prepozna cela reenica, a to se deava u akciji koja sledi iza pravila re reenice (pravilo Broja rei se inkrementira svaki kada dobije prvu put kada parser dobije od skenera token za neku re: dini reenice (pravilo
_CAPITAL_WORD (pravilo sentence), kada dobije _WORD u sreword) i kada dobije _CAPITAL_WORD u sredini reenice word).
Listing 3.6:
count1.y
%{
# include < stdio .h > # define YYSTYPE char * int yylex ( void ) ; int yyparse ( void ) ; int word_counter = 0; int sentence_counter = 0; extern int yylineno ;
%}
% token _DOT % token _CAPITAL_WORD % token _WORD %% text : | ; /* empty text */ text sentence
sentence : _CAPITAL_WORD words _DOT { word_counter ++; sentence_counter ++; } ; words : /* empty */ | words _WORD { word_counter ++; }
3.5.
PRIMERI
43
| ; %%
main () { yyparse () ; printf ( " Total words : % d .\ n " , word_counter ) ; printf ( " Total sentences : % d .\ n " , sentence_counter ) ; } yyerror ( char * s ) { fprintf ( stderr , " line %d : SYNTAX ERROR % s \ n " , yylineno , s ) ; }
Kada se ovaj program pokrene, njegov izlaz e izgledati ovako:
yylval.
bison
promenljive
memorije i kopiranje.
count2.l
- modikacija
[A - Z ][ a - z ]* { yylval = strdup ( yytext ) ; return _CAPITAL_WORD ;} [a - z ]+ { yylval = strdup ( yytext ) ; return _WORD ; }
Ispis rei se vri svaki put kada u parser stigne neka re. Nakon svakog ispisa rei sledi oslobaanje memorije koju je u skeneru zauzela funkcija
strdup().
44
POGLAVLJE 3.
BISON
Listing 3.8:
count2.y
- pravila
text : | ;
sentence : _CAPITAL_WORD words _DOT { word_counter ++; sentence_counter ++; printf ( " % s \ n " , $1 ) ; free ( $1 ) ; } ; words : /* empty */ | words _WORD { word_counter ++; printf ( " % s \ n " , $2 ) ; free ( $2 ) ; } | words _CAPITAL_WORD { word_counter ++; printf ( " % s \ n " , $2 ) ; free ( $2 ) ; }
$ ./ count2 Danas je predivan dan . je predivan dan Danas ^D Total words : 4. Total sentences : 1. $
Osim prve rei, sve rei su ispisane u redosledu u kom su se pojavile u ulaznom tekstu. Prva re je ispisana na kraju. Ovo se deava zato to se kod, koji vri ispis prve rei u reenici, nalazi u akciji koja se izvrava tek kada se zavri parsiranje cele reenice (pa se i ispis prve rei vri kada je prepoznata cela reenica). U tekstu zadatka se ne trai da se rei ispiu u redosledu u kom su se pojavile u ulaznom tekstu, pa se ovo reenje moe smatrati zadovoljavajuim. Sledei primer reava pitanje redosleda ispisivanja rei.
3.5.
PRIMERI
45
sentence.
_CAPITAL_WORD.
ovom sluaju, prva re u reenici e biti ispisana im dospe u parser, a ne, kao u prethodnom primeru, kada se prepozna cela reenica. Listing 3.9:
count3.y
- pravilo
sentence
sentence : _CAPITAL_WORD { word_counter ++; printf ( " % s \ n " , $1 ) ; free ( $1 ) ; } words _DOT { sentence_counter ++; ;
$ ./ count3 Danas je lep dan . Danas je lep dan ^D Total words : 4. Total sentences : 1. $
count4.l
- male zagrade
"(" ")"
46
POGLAVLJE 3.
BISON
Moemo preuzeti i parser iz prethodnog primera pa mu dodati denicije tokena (listing 3.11). Listing 3.11:
count4.y
- tokeni
% token % token
_LPAREN _RPAREN
i proiriti pravilo
words
Listing 3.12:
count4.y
- pravilo
words
words : /* empty */ | words _WORD { word_counter ++; printf ( " % s \ n " , $2 ) ; free ( $2 ) ; } | words _CAPITAL_WORD { word_counter ++; printf ( " % s \ n " , $2 ) ; free ( $2 ) ; } words _LPAREN words _RPAREN
| ;
Novo rekurzivno pravilo opisuje da se par zagrada moe nai oko bilo koje grupe rei. prazne. Poto
words moe biti samo jedna re, pa je mogue da se izmeu zagrada words se moe sastojati od vie rei, pa smo words
ne opisuje prvu re u reenici, obezbedili smo da se u pravilu
words
time omoguili da se izmeu zagrada nae i vie od jedne rei. Kako pojam token
zagrade ne mogu nai ispred prve rei u reenici (prvu re u reenici opisuje
_CAPITAL_WORD
sentence). words,
omoguena je pojava
$ ./ count4 Danas ( utorak ) je lep dan ( nije hladno ( i vedro je ) ) () . Danas utorak je lep dan
3.5.
PRIMERI
47
nije hladno i vedro je Nezavrsene ( zagrade u tekstu . Nezavrsene zagrade u tekstu line 2: SYNTAX ERROR syntax error Total words : 14. Total sentences : 1. $
Prva reenica je sintaksno ispravna. Testirali smo varijante: jedna re u
zagradama, vie rei u zagradama, ugnjedene zagrade i prazne zagrade. Druga reenica je sintaksno neispravna, jer ne sadri zatvorenu zagradu. Parser je preuzimao simbole sa ulaza dok nije stigao do kraja datoteke, a zatim je ispisao poruku da je detektovao sintaksnu greku (jer nije pronaao zatvorenu zagradu), i zavrio svoju aktivnost.
dd/mm/yyyy. Napraviti parser koji procesira ulazni tekst i dd-mmm-yyyy. Ostatak teksta se ne menja (ispisuje
Listing 3.13:
date.l
% option noyywrap yylineno %{ # include " date . tab . h " %} %% [ \ t \ n ]+ "/" [0 -9]{2} [0 -9]{4} "." [A - Z ][ a - z ]* { /* skip */ } { return _SEPARATOR ; } { yylval . i = atoi ( yytext ) ; return _2D ;} { yylval . i = atoi ( yytext ) ; return _4D ; } { return _DOT ; } { yylval . s = yytext ; return _CAPITAL_WORD ; }
48
POGLAVLJE 3.
BISON
[a - z ]+
U skeneru se kao deo datuma prepoznaju simboli od 2 i od 4 cifre. Za njih su vezani tokeni
_2D i _4D,
i unije yylval. Kao separator ovih simbola / i za njega je vezan token _SEPARATOR. Ostali simboli s
unije
su, kao u prethodnim primerima, simboli tekst gramatike (jedina razlika je to se ovde stringovi rei prenose preko polja Unija u ovom parseru treba da ima jedan i
yylval).
(jer se uz tokene
_4D
integer
kene
_CAPITAL_WORD i _WORD
string
_2D
(jer se uz to-
yylval
a uz
denie kao unija, za svaki token koji ima vrednosti, se mora rei kog tipa je ta vrednost. Zato uz deniciju tokena deniciju tokena
_CAPITAL_WORD i _WORD
Listing 3.14:
_2D
_4D
stoji oznaka
stoji oznaka
<s>.
<i>,
date.y
%}
int yylex ( void ) ; int yyparse ( void ) ; extern int yylineno ; char * months [] = { " " , " jan " , " feb " , " mar " , " apr " , " maj " , " jun " , " jul " , " avg " , " sep " , " okt " , " nov " , " dec " };
% union { int i; char * s ; } % token % token % token % token % token % token %% text : | ; /* empty text */ text sentence _SEPARATOR <i > _2D <i > _4D _DOT <s > _CAPITAL_WORD <s > _WORD
3.5.
PRIMERI
49
words : /* empty */ | | | ; date : words _WORD { printf ( " % s " , $2 ) ; } words _CAPITAL_WORD { printf ( " % s " , $2 ) ; } words date
_2D
; %%
{ printf ( " %d - " , $1 ) ; } _SEPARATOR _2D { printf ( " %s - " , months [ $4 ]) ; } _SEPARATOR _4D { printf ( " % d " , $7 ) ; }
int main () { yyparse () ; printf ( " \ n " ) ; } int yyerror ( char * s ) { fprintf ( stderr , " line %d : % s \ n " , yylineno , s ) ; }
Parser je proiren u pravilu dini reenice.
words,
se akcija koja ispisuje taj broj na ekran (vrednost meta-promenljive a iza njega novi separator. koje oznaavaju mesec, pomou niza stringova
$1),
months,
denisanog u pr-
vom delu specikacije, se ispisuje tekstualna forma meseca i novi separator. Nakon to se prepoznaju 4 cifre za godinu, one se ispiu na ekran (vrednost meta-promenljive
$7).
neizmenjene ispiu na izlaz. Primer pokretanja ovog programa je prikazan na sledeem listingu:
$ ./ date
50
POGLAVLJE 3.
BISON
Danas je 06/11/2012 godine , a za dva meseca ce biti 06/01/2013. Danas je 6 - nov -2012 godine , a za dva meseca ce biti 6 - jan -2013. ^D $
13 1004.9 E 3 67
Listing 3.15 sadri skener a listing 3.16 parser ovog primera. Listing 3.15:
meteo.l
% option noyywrap yylineno %{ # include " meteo . tab . h " %} %% [ \ t \ n ]+ { /* skip */ } { { { { { { { { { return _TEMPERATURA ; } return _PRITISAK ; } return _PRAVAC_VETRA ; } return _BRZINA_VETRA ; } return _VLAGA ; } return _DVOTACKA ; } yylval . i = atoi ( yytext ) ; return _INT ;} yylval .f = atoi ( yytext ) ; return _FLOAT ; } return _VETAR ; }
" temperatura " " pritisak " " pravac vetra " " brzina vetra " " vlaznost " ":" [0 -9]+ [0 -9]+\.[0 -9]* E | NE | SE | W | NW | SW
Skener prepoznaje sve kljune rei iz sloga, kao i dvotaku, i za njih alje samo token. Prilikom prepoznavanja celog i razlomljenog broja, on alje odgovarajui token (_INT ili i
int
_FLOAT) i vrednost broja. Unija sadri tipove float, da bi mogle da se prenesu konkretne vrednosti ovih brojeva. Tokenu _INT je dodeljen tip <i>, a tokenu _FLOAT tip <f>. Token _VETAR se NE, SE, W, NW, SW).
alje kada skener prepozna neku kombinaciju karaktera, koja oznaava smer vetra (E,
3.5.
PRIMERI
51
Primenjena gramatika opisuje da se jedan fajl sastoji od jednog ili vie slogova, a da jedan slog redom sadri: opis temperature, pritiska, pravca vetra, brzine vetra i vlanosti. Deo sloga koji opisuje temperaturu se sastoji prvo od kljune rei temperatura, zatim sledi dvotaka, pa zatim ceo broj koji sadri vrednost temperature (listing 3.16). Listing 3.16:
meteo.y
%{
%}
# include < stdio .h > int yylex ( void ) ; int yyparse ( void ) ; extern int yylineno ; int temp = 0;
% union { int i; float f ; } % token % token % token % token % token % token % token % token % token %% fajl : | ; slog : ; slog fajl slog _TEMPERATURA _PRITISAK _PRAVAC_VETRA _BRZINA_VETRA _VLAGA _DVOTACKA <i > _INT <f > _FLOAT _VETAR
52
POGLAVLJE 3.
BISON
: ;
pravac_vetra : _PRAVAC_VETRA _DVOTACKA _VETAR ; brzina_vetra : _BRZINA_VETRA _DVOTACKA _INT ; vlaga : _VLAGA _DVOTACKA _INT ; %% int main () { yyparse () ; printf ( " U ovom mesecu bilo je % d dana sa t > 12 C .\ n " , temp ) ; } int yyerror ( char * s ) { fprintf ( stderr , " line % d: % s \ n " , yylineno , s ) ; }
Da bi izraunali koliko je dana bilo sa temperaturom preko 12 stepeni, treba
temp). Nakon _INT (to je ujedno i kraj pravila temperatura), smetamo akciju koja inkremetira promenljivu temp, ako je vrednost temperature > 12. Vrednosti broja pristupamo preko meta-promenljive $3 (jer elimo da proitamo vrednost uz token _INT koji se nalazi na 3-oj poziciji na desnoj strani pravila). Ispis broja dana se vri iz main funkcije, nakon parsiranja
nam promenljiva u kojoj emo brojati takve dane (promenljiva prepoznavanja tokena svih slogova.
3.6 Vebe
1. Proiriti kalkulator tako da prihvata i linijske komentare. 2. Proiriti kalkulator tako da prihvata i heksa i decimalne brojeve. Uputstvo: u skeneru dodati obrazac koji se prenosi preko funkcije cifara, a u akciji koristiti funkciju
printf
yylval,
0x[a-f0-9]+ za prepoznavanje heksa strtol za konverziju stringa u broj vratiti token NUMBER. Prilagoditi poziv
heksa broj.
3.6.
VEBE
53
3. Proiriti kalkulator operatorima na nivou bita, kao to su 5. Napisati gramatike za svaki od ovih jezika:
AND i OR.
4. Proiriti primer 3 tako da izrauna prosenu temperaturu. (a) Svi nizovi rei da i ne koji sadre isti broj rei da i rei ne (u bilo kom redosledu). (b) Svi nizovi rei da i ne koji sadre duplo vie rei da od ne.
54
POGLAVLJE 3.
BISON
Poglavlje 4
isati prepravljanjem gramatike ili deklarisanjem prednosti operatora. ini gramatiku i parser manjim i jednostavnijim za odravanje.
Bison
Veina generatora moe pruiti informacije pomou kojih se moe locirati mesto u gramatici na kom se nalazi problem. Pokretanjem jom (sviem)
sadi spisak konikata, kao i opis u kom stanju parsera se desio konikt.
e : | | | | | ;
dobiemo dvosmislenu gramatiku. Na primer, ulaz 2+3*4 moe znaiti (2+3)*4 ili 2+(3*4), a ulaz 3-4-5-6 moe znaiti 3-(4-(5-6)) ili (3-4)-(5-6) 55
56
POGLAVLJE 4.
i jo mnogo slinih mogunosti. Slika 4.1 pokazuje dva mogua stabla parsiranja za primer
2+3*4.
2+3*4
2+3*4
on
2+3*4
4.2.
RAZREENJE KONFLIKTA
57
(2+3)
po pravilu
oekujui da e
* i moe da uradi redukciju poslednja 3 elementa e : e '+' e, a moe da uradi i iftovanje operatora *, moi kasnije da uradi redukciju po pravilu e : e '*' e.
bison -u
a
asocijativnosti operatora. Prioritet upravlja redosledom izvravanja izraza. Mnoenje i deljenje imaju prednost nad sabiranjem i oduzimanjem, tako da izraz
a+b*c
ima znaenje
a+(b*c),
d/e-f
znai
(d/e)-f.
U bilo kojoj
gramatici izraza, operatori su grupisani u nivoe prioriteta od najnieg ka najviem. Postoje dva nana da se deniu prioritet i asocijativnost u gramatici: implicitno i eksplicitno. Implicitna denicija prioriteta podrazumeva deniciju zasebnih pojmova za svaki nivo prioriteta. Naa gramatika bi u ovom sluaju izgledala:
mul_exp : num_exp "* " num_exp | num_exp " / " num_exp ; num_exp : exp " + " exp | exp " -" exp ; exp
Meutim, eratora.
: NUMBER ;
bison
bison
specikacije,
calc4.y
- prioritet operatora
%left, %right,
%nonassoc
jnieg ka najviem. da je
One kau
bison -u
/
da su
levo asocijativni i sa
Bison
strani pravila. Ako taj token nema pridruen prioritet, ni pravilo nema svoj prioritet. Kada
bison
naie na
shift/reduce
oriteta i, ako sva pravila koja uestvuju u koniku imaju dodeljen prioritet, koristi taj prioritet za razreavanje konikta.
58
POGLAVLJE 4.
exp,
exp OP
svih konikata. Parser koji koristi eksplicitne denicije prioritera operatora je malo manji i bri od onog koji sadri dodatna pravila sa implicitnom denicijom prioriteta, jer ima manje pravila za redukciju. Listing 4.2:
calc4.y
{ { { { { { $$ $$ $$ $$ $$ $$
- prioritet pravila
: | | | | | ;
= = = = = =
$1 + $3 ; $1 - $3 ; $1 * $3 ; $1 / $3 ; - $2 ; } $1 ; }
} } } }
- (minus),
%prec UMINUS.
Jedini operator u
timo kao unarni minus, elimo da ima vii prioritet od mnoenja i deljenja.
%prec
kae
Prioritet operatora treba koristiti u gramatikama koje opisuju izraze. Inae, treba popraviti gramatiku tako da konikt nestane. znai da lena.
bison
Postojanje konikta
Poglavlje 5
leksike (pogreno napisano ime, kljuna re ili operator) sintaksne (logiki izraz sa nepotpunim parom zagrada) semantike (operator primenjen na nekompatibilni operand) logike (beskonaan rekurzivni poziv).
da saopti prisustvo greaka jasno i ispravno da se oporavi od greke dovoljno brzo da bi mogao da detektuje naredne greke da ne usporava bitno obradu ispravnih programa.
U svakoj fazi kompajliranja se moe pojaviti greka, pa zato svaka faza mora postupiti sa grekom tako, da se proces kompajliranja moe nastaviti, sa ciljem detekcije jo novih greaka. Najveim brojem greaka (koje kompajler moe da otkrije) rukuju sintaksna i semantika analiza. 59
60
POGLAVLJE 5.
bison -ov parser detektuje greku, ispie string syntax error i zavri bison nudi
error. error
oznaava mesto oporavka od greke. Kada
parser detektuje greku, on poinje da odbacuje simbole sa steka sve dok ne dostigne mesto gde e
error
token biti validan. Parser odbacuje ulazne Ako parsiranje ponovo detektuje Da bi se
tokene sve dok ne pronae jedan koji moe iftovati u trenutnom stanju i tada nastavlja parsiranje od te take. greku, odbacuje se jo simbola sa steka i jo ulaznih tokena, sve dok ne postane mogu nastavak parsiranja ili dok se stek ne isprazni. izbeglo puno suvinih (neadekvatnih) poruka o grekama, parser, posle prve greke, prestane da prijavljuje poruke sve dok ne uspe da iftuje tri tokena jedan za drugim. U nastavku je dat primer kalkulatora koji detektuje greku unutar izraza, oporavlja se od greke i nastavlja parsiranje (listing 5.1). Ovaj primer nastao je proirenjem prethodnog primera novim pravilom za pojam Listing 5.1:
lines.
calc3.y
{ printf ( " % d \ n " , $2 ) ; } { yyerror ( " reenter last line :\ n " ) ; yyerrok ; }
error.
pojavu bilo kakve sintaksne greke unutar linije, pre karaktera za novi red. Ukoliko se na ulazu pojavi greka, parser e uraditi redukciju po ovom pravilu, i u naem sluaju, ispisati poruku korisniku da ponovo unese izraz. Nakon novog unosa, parser nastavlja sa parsiranjem. Za ispis greke koristi se funkcija Makro
yerror().
poruke o grekama mogu prijavljivati. U cilju detekcije to vie greaka mogue je dodati puno pravila koja opisuju greke, ali u praksi retko postoji vie od nakoliko pravila sa grekama.
Listinzi
2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 2.10 2.11 2.12 2.13 2.14 2.15 2.16 2.17 2.18 2.19 2.20 3.1
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11 13 13 14 14 15 15 16 18 18 18 19 20 21 22 22 23 24 25 26 35
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
- unija . . . . . . . . . . . . . . . . . . . . . . . . . . - pravila . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
test-comment.c 2to10.l
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
calc1.l
62
LISTINZI
3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 4.1 4.2 5.1
calc1.y calc2.y count1.l count1.y count2.l count2.y count3.y count4.l count4.y count4.y date.l date.y
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
36 37 41 41 42 43 44 45 45 46 46 47 48 50 51 57 58 60
. . . . . . . . . . . . . . . . . . . . . . . .
sentence
. . . . . . . . . . . . . . . . . .
words
. . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - prioritet operatora . . . . . . . . . . . . . . . . . .
- prioritet pravila . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Slike
1.1 Stablo parisiranja za izraz
1*2+3*4+5
. . . . . . . . . . . . . .
2.1 2.2
Korienje
ex -a
. . . . . . . . . . . . . . . . . . . . . . . . .
8 16
Korienje
bison -a
. . . . . . . . . . . . . . . . . . . . . . . .
30 34 34 35 38 39
2+3
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2+3\n
2+3-4+5
1+2\n
. . . . . . . . . . . . . . .
4.1 4.2
2+3*4
. . . . . . . .
56 56
2+3*4
. . . . . . . . . . . . . . . . .
63
Indeks
.l, 7 .output, 55 funkcije noyywrap, 12 yywrap(), 9 opcije, 8 noyywrap, 9, 12 yylineno, 9 promenljive yylineno, 9 yylval, 18 yytext, 15 specikacija, 8, 11 gramatika, 29, 33, 37 dvosmislena, 55 greka leksika greka, 9, 27, 36 sintaksna greka, 29 iskaz, 35 izraz, 3335 konikt razreenje, 55 leksika analiza, 7 leksika greka, 9, 27, 36 leksiki analizator, 7
.y,
30
bison, 30
$$, 38 $1, 38 .y, 30 asocijativnost operatora, 57 opcije -d, 37 -v, 55 oporavak od greke, 60 pravila, 31 prioritet operatora, 57 prioritet operatora, 57
ex
48
yyerrok, 60 yyerror(), 37
BNF notacija, 29 deterministiki konani automat, 3 DFA, 3
lex.yy.c,
LR parser
7, 12, 37
ex, 7
.l, 7 64
INDEKS
65
reduce, 39 shift, 39
parsiranje, 29 pojam, 33
poetni, 35 rekurzivno pravilo, 34, 35, 40 rukovanje grekama, 59 simbol, 37 sintaksa, 29 sintaksna analiza, 29 sintaksna greka, 29 skener, 7 skeniranje, 7 stablo parsiranja, 29, 3335 token, 16, 17 token
error,
60
66
INDEKS
Dodatak A
Renik
akcija
C ili C++ kod pridruen obrascu u kaciji. kod pridruene akcije.
ex
bison
speci-
ASCII
bison
Program koji prevodi gramatiku, napisanu u posebnom obliku BNF notacije, u LALR(1) parsere. Vidi LALR(1).
BNF
Backus-Naur Form ;
Ulazna sintaksa za
bison
dvosmislenost
Dvosmislena gramatika je ona koja sadri vie od jednog pravila ili skupa pravila kojima se moe prepoznati isti ulazni string. U dvosmilsena pravila dovode do pojave ikta. Mehanizam parsiranja, koji
razrei dvosmislene gramatike. Programer moe da denie prioritet operatora i prioritet pravila da bi razreio konikte, ili da preformulie gramatiku. 67
68
DODATAK A.
RENIK
epsilon
Specijalan sluaj ulaznog stringa sa nula simbola, tj. prazan string.
ex
Program koji generie leksike analizatore (skenere), koji prepoznaju obrasce (denisane regularnim izrazima) u ulaznom tekstu.
gramatika
Skup pravila koji zajedno deniu jezik.
interpreter
Program koji ita program napisan na jeziku visokog nivoa i izvrava ga. Uporedi sa kompajlerom.
jezik
Formalno: denisan skup stringova iz nekog alfabeta, a neformalno: skup instrukcija za opis zadataka koji se mogu izvriti na raunaru.
kompajler
Program koji prevodi program, napisan na jeziku visokog nivoa, na ekvivalentan program na jeziku niskog nivoa. interpreterom. Obino, izlaz iz kompajlera je na mainskom jeziku koji se moe direktno izvravati na raunaru. Uporedi sa
konani automat
Finite automaton ; apstraktna maina koja se sastoji od konanog broja instrukcija (prelaza). Konani automati su korisni za modelovanje uobiajenih raunarskih procesa a imaju i korisna matematika svojstva. prave skenere i parsere na osnovu konanih automata.
Flex
bison
konikt
Greka u
bison
gramatici koja se pojavljuje u situaciji kada se, za isti ulazni Postoji dve vrste
niz tokena, mogu izvriti dve ili vie akcija parsiranja. konikata:
shift/reduce i reduce/reduce. Vidi dvosmislenost. kontekstno nezavisna gramatika Context-free grammar ; gramatika u kojoj svako pravilo ima samo jedan pojam sa leve strane pravila.
LALR(1)
Look Ahead Left to Right ; tehnika parsiranja koju bison obino oznaava da je lookahead limitiran na 1 token. Vidi lookahead.
koristi. (1)
69
leksiki analizator
Program koji konvertuje niz karaktera u niz tokena. Zove se jo i skener ili lekser.
lex
Program koji generie leksike analizatore (skenere). mu je
ex.
Savremeni naslednik
lookahead
Ulaz koji je proitan od strane parsera ili skenera, ali jo nije prepoznat kao deo obrasca ili pravila.
ex-ovi
U
Bison-ovi
lookahead
token, dok
obrazac
ex-ovom
pretrauje ulazni tekst da pronae string koji odgovara datom regularnom izrazu, odnosno obrascu.
parsiranje
Proces preuzimanja niza tokena i provere ispravnosti njihovog redosleda.
pojam
Pojmovi (
poetni pojam
Jedan pojam koji predstavlja cilj parsiranja ulaznog teksta. Pravilo koje na levoj strani ima poetni pojam se zove poetno pravilo.
pravilo
U
bison-u,
stranu, razdvojenu znakom :, dok na kraju pravila stoji znak ;. Na levoj strani se nalazi samo jedan pojam (koji se denie) a na desnoj strani niz simbola i pojmova (koji ga deniu).
prioritet
Redosled u kom se neke odreene operacije vre. Na primer, kada se interpretiraju matematike naredbe, mnoenje i deljenje imaju vii prioritet od sabiranja i oduzimanja. Tako izraz
2+3*4
rezultira vrednou
14
a ne
20.
program
70
DODATAK A.
RENIK
reduce
Kada se u ulaznom tekstu prepozna niz simbola koji ini desnu stranu nekog pravila, pravila.
bison-ov
parser vri
reduce
reduce/reduce konikt
Situacija u kojoj istom nizu tokena odgovaraju dva ili vie pravila. razreava konikt tako to vri deno u gramatici.
reduce
Bison
regularni izraz
Jezik za opisivanje obrazaca koji slue za prepoznavanje niza karaktera.
shift
Akcija u toku parsiranja u kojoj stavlja ga na stek.
bison-ov
shift/reduce konikt
Situacija u kojoj
Shift/reduce
simbol
bison-ov
shift
reduce
akciju.
lookahead
terminals ) se prepoznaju u skeneru i alju se parseru. Vidi pojam nonterminal ). specikacija Flex specikacija je skup obrazaca po kojima se pretrauje ulazni tekst. Ovakvu specikaciju ex pretvara u skener. stek parsera U bison-ovom parseru, simboli i pojmovi delimino prepoznatog pravila se
Simboli ( (
shift akciju i uklanjaju sa njega kada parser vri reduce tabela simbola
vri
smetaju na interni stek. Simboli i pojmovi se dodaju na stek kada parser akciju.
Struktura podataka koja sadri informacije o imenima koja se pojavljuju u programu (ulaznom tekstu) tako da sve reference na isto ime mogu biti vezane za isti objekat.
71
tokenizacija
Proces konvertovanja niza karaktera u niz tokena. Skener tokenizuje ulazni tekst.
ulaz
Podaci koje ita program. Na primer, ulaz za dok je ulaz za
bison-ov
ex-ov
vrednost
Skener parseru alje token i, opciono, neku semantiku vrednost simbola.
yacc
Yet Another Compiler Compiler ;
predak
bison-a,
72
DODATAK A.
RENIK
Bibliograja
[1] A.V. Aho, R. Sethi, and J.D. Ullman.
and tools.
Pub. Co., 1986. [2] Robert Corbett. Byacc. Technical report, 1990. [3] Stephen C. Johnson. report, 1979. [4] M. E. Lesk and E. Schmidt. Unix vol. ii. chapter Lex - a lexical analyzer generator, pages 375387. W. B. Saunders Company, Philadelphia, PA, USA, 1990. [5] J. Levine. Yacc: Yet another compiler-compiler. Technical
[6] Vern Paxson. Flex, http://ex.sourceforge.net/. Technical report, 1987. [7] Richard Stallman. Technical report. Gnu bison, http://www.gnu.org/software/bison/.
73