Generator programm leksicheskogo analiza lex
Proizvodstvenno-vnedrencheskij kooperativ
"I N T E R F E J S"
Dialogovaya Edinaya Mobil'naya
Operacionnaya Sistema
Demos/P 2.1
Generator programm leksicheskogo analiza lex
Moskva
1988
Annotaciya
V dokumente opisan yazyk programmirovaniya lex, prednaz-
nachennyj dlya razrabotki programm leksicheskogo analiza. Pri-
vodyatsya pravila raboty s kompilyatorom yazyka lex OS DEMOS.
1. Vvedenie
lex - generator programm leksicheskogo analiza. Leksi-
cheskij analiz - eto raspoznavanie leksem vo vhodnom potoke
simvolov. Predpolozhim, chto zadano nekotoroe konechnoe mno-
zhestvo slov (leksem) v nekotorom yazyke i nekotoroe vhodnoe
slovo. Neobhodimo ustanovit', kakoj element mnozhestva (esli
on sushchestvuet) sovpadaet s dannym vhodnym slovom.
Obychno leksicheskij analiz vypolnyaetsya tak nazyvaemym
leksicheskim analizatorom. Leksicheskij analizator - eto
programma.
Leksicheskij analiz primenyaetsya vo mnogih sluchayah, nap-
rimer, dlya postroeniya paketnogo redaktora ili v kachestve
raspoznavatelya direktiv v dialogovoj programme i t.d.
Odnako, naibolee vazhnoe primenenie leksicheskogo analizatora
- eto ispol'zovanie ego v kompilyatore. Zdes' leksicheskij
analizator vypolnyaet funkciyu programmy vvoda dannyh.
Leksicheskij analizator vypolnyaet pervuyu stadiyu kompilya-
cii - chitaet stroki kompiliruemoj programmy, vydelyaet lek-
semy i peredaet ih na dal'nejshie stadii kompilyacii (gramma-
ticheskij razbor, kodogeneraciyu i t.d.).
Leksicheskij analizator raspoznaet tip kazhdoj leksemy i
sootvetstvuyushchim obrazom pomechaet ee. Naprimer, pri kompilya-
cii Si-programmy mogut byt' vydeleny sleduyushchie tipy leksem:
chislo, identifikator, operator, ogranichitel' i t.d.
Leksicheskij analizator dolzhen ne tol'ko vydelit' lek-
semu, no i vypolnit' nekotorye preobrazovaniya. Naprimer,
esli leksema - chislo, to ego neobhodimo perevesti vo vnut-
rennyuyu (dvoichnuyu) formu zapisi kak chislo s plavayushchej ili
fiksirovannoj tochkoj. A esli leksema - identifikator, to
ego neobhodimo razmestit' v tablice, chtoby v dal'nejshem
obrashchat'sya k nemu ne po imeni, a po adresu v tablice.
Hotya leksicheskij analiz po svoej idee prost, tem ne
menee eta faza raboty kompilyatora chasto zanimaet bol'she vre-
meni, chem lyubaya drugaya. CHastichno eto proishodit iz-za neob-
hodimosti prosmatrivat' i analizirovat' ishodnyj tekst sim-
vol za simvolom. Inogda dazhe byvaet neobhodimo vernut' pro-
chitannyj simvol vo vhodnoj potok s tem, chtoby povtorit'
prosmotr i analiz.
Proishodit eto potomu, chto chasto byvaet trudno oprede-
lit', gde prohodyat granicy leksemy.
Dopustim, imeyutsya dve leksemy:
make
makefile
3
Pust' iz vhodnogo potoka postupaet nabor simvolov:
...makefile...
Pri analize vhodnogo potoka simvolov budet vydelena leksema
make, hotya pravil'no bylo by vydelit' leksemu makefile.
Edinstvennyj sposob preodolet' eto zatrudnenie - pros-
motr poluchennoj cepochki simvolov nazad i vpered. V nashem
primere pri vydelenii leksemy make my dolzhny prosmotret'
sleduyushchij postupayushchij simvol i, esli on budet simvolom "f",
to vpolne vozmozhno, chto postupaet leksema makefile.
Process prosmotra vhodnogo potoka mozhno rassmatrivat'
kak dvizhenie vlevo i vpravo ramki nad cepochkoj simvolov. Pri
etom analiziruetsya tol'ko tot simvol, kotoryj ohvachen ram-
koj.
...
. .
source make.f.ile file compiler
. .
...
<=== ===>
Analiz zaklyuchaetsya v opredelenii sootvetstviya rassmatrivae-
moj posledovatel'nosti simvolov nekotoromu tak nazyvaemomu
regulyarnomu vyrazheniyu.
Naprimer, regulyarnoe vyrazhenie
(+?[0-9])+|(-?[0-9])+
pozvolyaet vydelit' v cepochke vse leksemy tipa celoe, pered
kotorymi libo ukazan znak (+ ili -), libo ne ukazan. Dlya
chisel s tochkoj eto vyrazhenie imelo by vid:
(+?[0-9.])+|(-?[0-9.])+
V teh sluchayah, kogda vydelenie leksemy zatrudneno libo po
prichine togo, chto odno regulyarnoe vyrazhenie ne pozvolyaet ee
odnoznachno opredelit', libo iz-za togo, chto leksema yavlyaetsya
chast'yu drugoj, prihoditsya pribegat' k kontekstno-zavisimym
algoritmam analiza s ispol'zovaniem levogo i pravogo naprav-
lenij prosmotra vhodnoj cepochki simvolov.
lex chastichno ili polnost'yu avtomatiziruet process
napisaniya programmy leksicheskogo analiza. lex - eto program-
miruyushchaya programma ili generator programm. lex stroit prog-
rammu - leksicheskij analizator na tak nazyvaemom host-yazyke
(ili "glavnom" yazyke). |to znachit, chto Lex-programma pishetsya
na "yazyke" lex, a Lex-generator, v svoyu ochered', generiruet
programmu leksicheskogo analiza na kakom-libo drugom yazyke.
4
Dannaya versiya lex generiruet leksicheskie analizatory na yazy-
kah Si i Ratfor (racional'nyj dialekt Fortrana). V kachestve
host-yazyka my budem ispol'zovat' yazyk Si. Svedeniya ob
ispol'zovanii v kachestve host-yazyka Ratfor vydeleny v
otdel'nyj paragraf.
V kataloge /usr/lib/lex imeetsya fajl-zagotovka ncform,
kotoryj ispol'zuetsya Lex-generatorom dlya postroeniya leksi-
cheskogo analizatora. |tot fajl yavlyaetsya uzhe gotovoj prog-
rammoj leksicheskogo analiza, no v nem ne opredeleny dejst-
viya, kotorye neobhodimo vypolnit' pri raspoznavanii leksemy,
otstutstvuyut i sami leksemy, ne sformirovany rabochie massivy
i t.d.
lex na osnove Lex-programmy dostraivaet fajl ncform. V
rezul'tate my poluchaem fajl so standartnym imenem lex.yy.c,
kotoryj yavlyaetsya tekstom Si-programmy, osushchestvlyayushchej leksi-
cheskij analiz.
Lex-programma imeet sleduyushchij format:
opredeleniya
%%
pravila
%%
podprogrammy, sostavlennye
pol'zovatelem
Lyuboj iz etih razdelov mozhet byt' pustym. Prostejshaya Lex-
programma imeet vid:
%%
Zdes' net nikakih opredelenij i nikakih pravil.
Vse razdely Lex-programmy my podrobno rassmotrim nizhe.
Sejchas celesoobrazno rassmotret', chto predstavlyayut soboj
pravila.
Pravilo sostoit iz dvuh chastej:
REGULYARNOE_VYRAZHENIE DEJSTVIE
Po regulyarnym vyrazheniyam, soderzhashchimsya v levoj chasti pravil,
lex stroit determinirovannyj konechnyj avtomat. |tot avtomat
osushchestvlyaet interpretaciyu, a ne kompilyaciyu. Kolichestvo pra-
vil i ih slozhnost' ne vliyayut na skorost' leksicheskogo ana-
liza, esli tol'ko pravila ne trebuyut slishkom bol'shogo ob®ema
povtornyh prosmotrov vhodnoj posledovatel'nosti simvolov.
Odnako, s rostom chisla pravil i ih slozhnosti rastet razmer
konechnogo avtomata, interpretiruyushchego ih i, sledovatel'no,
rastet razmer Si-programmy, realizuyushchej etot konechnyj avto-
mat.
5
Rassmotrim v kachestve primera sleduyushchuyu Lex-programmu:
%%
[jJ][aA][nN][uU][aA][rR][yY] {
printf("YAnvar'"); }
[fF][eE][bB][rR][uU][aA][rR][yY] {
printf("Fevral'"); }
[mM][aA][rR][cC][hH] {
printf("Mart"); }
[aA][pP][rR][iI][lL] {
printf("Aprel'"); }
[mM][aA][yY] {
printf("Maj"); }
[jJ][uU][nN][eE] {
printf("Iyun'"); }
[jJ][uU][lL][yY] {
printf("Iyul'"); }
[aA][uU][gG][uU][sS][tT] {
printf("Avgust"); }
[sS][eE][pP][tT][eE][mM][bB][eE][rR] {
printf("Sentyabr'"); }
[oO][cC][tT][oO][bB][eE][rR] {
printf("Oktyabr'"); }
[nN][oO][vV][eE][mM][bB][eE][rR] {
printf("Noyabr'"); }
[dD][eE][cC][eE][mM][bB][eE][rR] {
printf("Dekabr'"); }
[mM][oO][nN][dD][aA][yY] {
printf("Ponedel'nik");}
[tT][uU][eE][sS][dD][aA][yY] {
printf("Vtornik"); }
[wW][eE][dD][nN][eE][sS][dD][aA][yY] {
printf("Sreda"); }
[tT][hH][uU][rR][sS][dD][aA][yY] {
printf("CHetverg"); }
[fF][rR][iI][dD][aA][yY] {
printf("Pyatnica"); }
[sS][aA][tT][uU][rR][dD][aA][yY] {
printf("Subbota"); }
[sS][uU][nN][dD][aA][yY] {
printf("Voskresen'e");}
Programma stroit konechnyj avtomat, kotoryj raspoznaet ang-
lijskie naimenovaniya mesyacev i dnej nedeli. Kazhdoe pravilo
zdes' opredeleyaet dejstvie (kotoroe vzyato v figurnye
skobki). Obratite vnimanie na to, chto otkryvayushchaya figurnaya
skobka stoit v toj zhe stroke, chto i pravilo - eto trebovanie
lex.
Dejstvie v kazhdom pravile dannoj Lex-programmy - eto
vyvod russkogo znacheniya najdennogo anglijskogo slova. V
kachestve operatora, vypolnyayushchego dejstvie, ispol'zuetsya bib-
liotechnaya funkciya yazyka Si.
6
Para figurnyh skobok opredelyaet blok (v smysle yazyka
Si), kotoryj mozhet soderzhat' lyuboe kolichestvo strok. Esli
dejstvie soderzhit vsego odnu stroku Si, to mozhno ee ukazat'
bez figurnyh skobok, kak obychno. Edinstvennoe uslovie - ona
dolzhna nachinat'sya v toj zhe stroke, gde ukazano regulyarnoe
vyrazhenie.
V programme soderzhitsya tol'ko razdel pravil, ih vsego
19. Regulyarnoe vyrazhenie kazhdogo pravila opredelyaet anglijs-
koe slovo, napisannoe malen'kimi ili bol'shimi latinskimi
simvolami. Naprimer "May" (Maj) opredelen kak
"[mM][aA][yY]". Po etomu regulyarnomu vyrazheniyu budet vyde-
lena vo vhodnom potoke simvolov leksema "May", a po dejstviyu
etogo pravila budet vyvedeno "Maj". Nalichie bol'shoj i maloj
bukvy v kvadratnyh skobkah obespechivaet raspoznavanie slova
"May", napisannogo lyubymi latinskimi simvolami.
Takim obrazom, dannaya Lex-programma stroit Si-
programmu, kotoraya perevodit na russkij yazyk imena mesyacev i
dnej nedeli.
Dopustim, Lex-programma razmeshchena v fajle source.l,
togda, chtoby poluchit' leksicheskij analizator na Si, neobho-
dimo vypolnit' sleduyushchij nabor komand:
% lex source.l
% cc -O lex.yy.c -ll -o program
%
lex vsegda, esli ne ukazano drugoe, stroit vyhodnoj fajl s
imenem lex.yy.c - Si-programmu - leksicheskij analizator. Vo
vtoroj stroke etoj posledovatel'nosti komand zapuskaetsya
Si-kompilyator, kotoryj vyvodit rezul'tat v fajl program.
Program mozhet rabotat' kak fil'tr v konvejere komand,
kak samostoyatel'naya komanda i v interaktivnom rezhime. Napri-
mer:
% program
May
Maj
MONDAY
Ponedel'nik
MoNdaY
Ponedel'nik
CNTRL/C
%
Flag -ll trebuet podklyucheniya biblioteki /usr/lib/libl.a -
biblioteki lex. Esli neobhodimo poluchit' samostoyatel'nuyu
programmu, kak v dannom sluchae, podklyuchenie biblioteki
7
obyazatel'no, poskol'ku togda iz nee podklyuchaetsya golovnoj
razdel main. V protivnom sluchae, esli imeetsya neobhodimost'
vklyuchit' analizator v kachestve funkcii v druguyu programmu
(naprimer, v programmu grammaticheskogo razbora), etu biblio-
teku neobhodimo vyzvat' uzhe pri sborke i togda, esli main
opredelen v vyzyvayushchej leksicheskij analizator programme,
redaktor svyazej ne budet podklyuchat' razdel main iz biblio-
teki lex.
Esli neobhodimo poluchit' fajl s imenem, otlichnym ot
lex.yy.c, mozhno vospol'zovat'sya flagom -t :
% lex -t source.l >> file
Po etomu flagu rezul'tat postupaet v fajl file.
2. Regulyarnye vyrazheniya v Lex-pravilah
Regulyarnye vyrazheniya opredelyayut leksemu. Regulyarnoe
vyrazhenie mozhet soderzhat' simvoly latinskogo i russkogo
alfavitov v verhnem i nizhnem registrah, drugie simvoly
(cifry, znaki prepinaniya i t.d.) i simvoly-operatory.
Operatory pozvolyayut osushchestvlyat' razlichnye dejstviya nad
vydelennoj cepochkoj simvolov. Operatory takzhe oboznachayutsya
simvolami.
2.1. Oboznacheniya simvolov v vyrazheniyah
V vyrazhenii mozhno ispol'zovat' lyuboj simvol. Simvol
mozhno ukazyvat' v dvojnyh kavychkah. V etom sluchae eto vsegda
prosto simvol - ego special'noe znachenie otmenyaetsya. Napri-
mer:
"abc"
abc
eti posledovatel'nosti simvolov identichny.
. tochka oznachaet lyuboj simvol, krome simvola novoj stroki
"\n";
\vos'merichnyj_kod_simvola
ukazanie simvola ego vos'merichnym kodom (kak v Si);
\n simvol novoj stroki;
\t simvol tabulyacii;
\b vozvrat kursora na odin shag nazad;
8
probel
lyuboj simvol probela v vyrazhenii, esli on ne nahoditsya
vnutri kvadratnyh skobok, neobhodimo zaklyuchat' v dvoj-
nye kavychki. |to neobhodimo, tak kak probel i tabulyaciya
ispol'zuyutsya lex v kachestve razdelitelya mezhdu opredele-
niem i dejstviem v pravile.
2.2. Operatory regulyarnyh vyrazhenij
Operatory oboznachayutsya simvolami-operatorami, k nim
otnosyatsya:
\ ^ ? * + | $ / %
[] {} () <<>>
Kazhdyj iz etih simvolov ili par skobok v regulyarnom vyrazhe-
nii igraet rol' operatora. Esli neobhodimo otmenit' speci-
al'noe znachenie simvola, oboznachayushchego operator, pered nim
nuzhno postavit' simvol \ ili ukazat' ego v dvojnyh kavychkah.
Naprimer:
abc+ - simvol "+" - operator;
abc\+ - simvol "+";
abc"+" - simvol "+".
2.3. Operator vydeleniya klassov simvolov
Kvadratnye skobki zadayut klassy simvolov, kotorye v nih
zaklyucheny.
[abc]
oznachaet libo simvol "a", libo "b", libo simvol "c";
Znak - ispol'zuetsya dlya ukazaniya lyubogo simvola iz lek-
sikograficheski uporyadochennoj posledovatel'nosti:
[A-z]
oznachaet lyuboj latinskij simvol;
[A-YA]
lyubaya propisnaya russkaya bukva;
[+-0-9]
vse cifry i znaki "+" i "-".
2.4. Povtoriteli
Kogda neobhodimo ukazat' povtoryaemost' vhozhdeniya sim-
vola v regulyarnom vyrazhenii, ispol'zuyut operatory-
povtoriteli * i +.
9
Operator * oznachaet lyuboe (v tom chisle i 0) chislo vhozh-
denij simvola ili klassa simvolov. Naprimer:
x* lyuboe chislo vhozhdenij simvola "x";
abc* lyuboe chislo vhozhdenij cepochki "abc";
[A-z]*
lyuboe chislo vhozhdenij lyuboj latinskoj bukvy;
[A-ZA-YAa-za-ya_0-9]*
lyuboe vhozhdenie russkih i latinskih bukv, znaka podcher-
kivaniya i cifr.
Operator + oznachaet odno i bolee vhozhdenij. Naprimer:
x+ odno ili bolee vhozhdenij "x";
[0-9]+
odno ili bolee vhozhdenij cifr;
abc+ odno ili bolee vhozhdenij cepochki abc;
[A-z]+
odno ili bolee vhozhdenij lyuboj latinskoj bukvy.
2.5. Operatory vybora
Operatory:
/ | ? $ ^
upravlyayut processom vybora simvolov.
Operator /:
ab/cd
"ab" uchityvaetsya tol'ko togda, kogda za nim sleduet
"cd".
Operator |:
ab|cd
ili "ab", ili "cd".
Operator ?:
x? oznachaet neobyazatel'nyj simvol "x".
_?[A-Za-z]*
oznachaet, chto pered cepochkoj lyubogo kolichestva latins-
kih bukv mozhet byt' neobyazatel'nyj znak podcherkivaniya.
10
-?[0-9]+
vydelit lyuboe celoe chislo s neobyazatel'nym minusom vpe-
redi.
Operator $:
x$ oznachaet vybrat' simvol "x", esli on yavlyaetsya poslednim
v stroke. Stoit pered simvolom "\n"!
abc$ oznachaet vybrat' cepochku "abc", esli ona zavershaet
stroku.
Operator ^:
^x oznachaet vybrat' simvol "x", esli on yavlyaetsya pervym
simvolom stroki;
^abc oznachaet vybrat' cepochku simvolov "abc", esli ona nachi-
naet stroku.
[^A-Z]*
oznachaet vse simvoly, krome propisnyh latinskih bukv.
Kogda simvol ^ stoit pered vyrazheniem ili vnutri [], on
vypolnyaet operaciyu dopolnenie. Vnutri kvadratnyh skobok
simvol ^ dolzhen obyazatel'no stoyat' pervym u otkryvayushchej
skobki!
2.6. Operator {}
Operator {} imeet dva razlichnyh primeneniya:
x{n,m} zdes' n i m natural'nye, m > n. Oznachaet ot n do m
vhozhdenij x, naprimer, x{2,7} - ot 2 do 7 vhozhdenij
x.
{imya} vmesto {imya} v dannoe mesto vyrazheniya budet podstav-
leno opredelenie imeni iz oblasti opredelenij Lex-
programmy.
Primer:
BUKVA [A-ZA-YAa-za-ya_]
CIFRA [0-9]
IDENTIFIKATOR {BUKVA}({BUKVA}|{CIFRA})*
%%
{IDENTIFIKATOR} printf("\n%s",yytext);
lex postroit leksicheskij analizator, kotoryj budet oprede-
lyat' i vyvodit' vse "slova" iz vhodnogo fajla. Pod slovom v
dannom sluchae podrazumevaetsya identifikator Si-programmy. V
etom primere {IDENTIFIKATOR} budet zamenen na
{BUKVA}({BUKVA}|{CIFRA})*, zatem na [A-ZA-YAa-za-ya_]([A-ZA-
YAa-za-ya_]|[0-9])*.
11
yytext - eto vneshnij massiv simvolov programmy
lex.yy.c, kotoruyu stroit lex. yytext formiruetsya v processe
chteniya vhodnogo fajla i soderzhit tekst, dlya kotorogo usta-
novleno sootvetstvie kakomu-libo vyrazheniyu. |tot massiv dos-
tupen pol'zovatel'skim razdelam Lex-programmy.
Operator printf vyvodit kazhdyj identifikator na novoj
stroke.
Pravilo ".|\n ;" ispol'zuetsya dlya togo, chtoby
propustit' (ne vyvodit') vse cepochki simvolov, kotorye ne
sootvetstvuyut regulyarnomu vyrazheniyu {IDENTIFIKATOR}.
2.7. Operator <<>>. Sluzhebnye slova START i BEGIN
Razdel pravil Lex-programmy mozhet soderzhat' aktivnye i
neaktivnye pravila. Aktivnye pravila vypolnyayutsya vsegda.
Neaktivnye vypolnyayutsya tol'ko v teh sluchayah, kogda vypolnya-
etsya nekotoroe nachal'noe uslovie.
Nachal'nye usloviya Lex-programmy pomeshchayutsya v razdel
opredelenij, a neaktivnye pravila pomechayutsya sootvetstvuyu-
shchimi usloviyami. Operator START pozvolyaet ukazat' spisok
nachal'nyh uslovij Lex-programmy, a operator BEGIN pozvolyaet
aktivirovat' pravila, pomechennye nachal'nymi usloviyami.
Aktivnye pravila imeyut sleduyushchij sintaksis:
REGULYARNOE_VYRAZHENIE DEJSTVIE
Neaktivnye pravila imeyut sleduyushchij sintaksis:
<<METKA_USLOVIYA>>REG_VYRAZHENIE DEJSTVIE
VAZHNO: lyuboe pravilo dolzhno nachinat'sya s pervoj pozicii
stroki, probely i tabulyacii nedopustimy - oni ispol'zuyutsya
kak razdeliteli mezhdu regulyarnym vyrazheniem i dejstviem v
pravile!
Rassmotrim primer:
12
%START COMMENT
KOMM_NACHALO "/*"
KOMM_KONEC "*/"
%%
{KOMM_NACHALO} { ECHO;
BEGIN COMMENT;};
[\t\n]* ;
<COMMENT>[^*]* ECHO;
<COMMENT>[^/] ECHO;
<COMMENT>{KOMM_KONEC} {
ECHO;
printf("0);
BEGIN 0;};
lex postroit leksicheskij analizator, kotoryj vydelyaet kom-
mentarii v Si-programme i zapisyvaet ih v standartnyj fajl
vyvoda. Programma nachinaetsya s klyuchevogo slova START, koto-
roe ukazano posle simvola %. Klyuchevoe slovo START mozhno
ukazat' i tak: Start, ili S, ili s . Za klyuchevym slovom
START ukazana metka nachal'nogo usloviya COMMENT.
Operator "<COMMENT>x" oznachaet - x, esli analizator
nahoditsya v nachal'nom uslovii COMMENT.
Operator "BEGIN COMMENT;" perevodit analizator v
nachal'noe uslovie COMMENT (smotrite pervoe pravilo razdela
pravil etoj Lex-programmy). Posle etogo analizator uzhe naho-
ditsya v novom sostoyanii i teper' razbor vhodnogo potoka sim-
volov budet osushchestvlyaetsya i temi pravilami, kotorye nachina-
yutsya operatorom "<COMMENT>". Naprimer, pravilo
<COMMENT>[^*]* ECHO;
vypolnyaetsya tol'ko togda, kogda vo vhodnom potoke simvolov
budet obnaruzheno nachalo kommentariev ("/*"). V etom sluchae
analizator zapisyvaet v standartnyj fajl vyvoda lyuboe chislo
(v tom chisle i nol') simvolov, otlichnyh ot simvola "*". Ope-
rator "BEGIN 0;" perevodit analizator v ishodnoe sostoyanie.
Lex-programma mozhet soderzhat' neskol'ko pomechennyh
nachal'nyh uslovij. Naprimer, esli Lex-programma nachinaetsya
strokoj
%START AA BB CC DD
to eto oznachaet, chto ona upravlyaet chetyr'mya nachal'nymi sos-
toyaniyami analizatora. V kazhdoe iz etih nachal'nyh sostoyanij
analizator mozhno perevesti, ispol'zuya operator BEGIN.
13
Kazhdoe pravilo, pered kotorym ukazan operator tipa
"<<METKA>>", my budem nazyvat' pomechennym pravilom. Metka for-
miruetsya tak zhe, kak i metka v Si.
Kolichestvo pomechennyh pravil ne ogranichivaetsya. Krome
togo, razreshaetsya odno pravilo pomechat' neskol'kimi metkami,
naprimer:
<<METKA1,METKA2,METKA3>>x DEJSTVIE
Zapyataya - obyazatel'nyj razdelitel' spiska metok!
Rassmotrim primer s neskol'kimi nachal'nymi usloviyami:
%START AA BB CC
BUKVA [A-ZA-YAa-za-ya_]
CIFRA [0-9]
IDENTIFIKATOR {BUKVA}({BUKVA}|{CIFRA})*
%%
^# BEGIN AA;
^[ \t]*main BEGIN BB;
^[ \t]*{IDENTIFIKATOR} BEGIN CC;
\t ;
\n BEGIN 0;
<AA>define printf("Opredelenie.\n");
<AA>include printf("Vklyuchenie.\n");
<AA>ifdef {
printf("Uslovnaya kompilyaciya.\n"); }
<BB>[^\,]*","[^\,]*")" {
printf("main s argumentamii.\n"); }
<BB>[^\,]*")" {
printf("main bez argumentov.\n"); }
<CC>":"/[ \t] printf("Metka.\n");
Programma soderzhit aktivnye i neaktivnye pravila. Vse neak-
tivnye pravila pomecheny, pered nimi ukazana metka nachal'nogo
usloviya. Lex-programma upravlyaet tremya nachal'nymi usloviyami,
v sootvetstvii s kotorymi aktiviruyutsya pomechennye pravila.
V rezul'tate raboty lex my poluchim leksicheskij analiza-
tor, kotoryj budet raspoznavat' v Si-programme stroki prep-
rocessora Si-kompilyatora, vydelyat' funkciyu main, raspozna-
vaya, s argumentami ona ili bez nih, raspoznavat' metki.
Leksicheskij analizator ne vyvodit nichego, krome soobshchenij o
vydelennyh leksemah.
14
3. Struktura Lex-programmy
Lex-programma vklyuchaet razdely opredelenij, pravil i
pol'zovatel'skih programm. Rassmotrim podrobnee sposoby
oformleniya etih razdelov.
Vse stroki, v kotoryh zanyata pervaya poziciya, otnosyatsya
k Lex-programme. Lyubaya stroka, ne yavlyayushchayasya chast'yu pravila
ili dejstviya, kotoraya nachinaetsya s probela ili tabulyacii,
kopiruetsya v sgenerirovannuyu programmu lex.yy.c - rezul'tat
raboty lex.
3.1. Razdel opredelenij Lex-programmy
Opredeleniya, prednaznachennye dlya lex, pomeshchayutsya pered
pervym %%. Lyubaya stroka etogo razdela, ne soderzhashchayasya mezhdu
%{ i %} i nachinayushchayasya v pervoj kolonke, yavlyaetsya opredele-
niem stroki podstanovki lex. Razdel opredelenij Lex-
programmy mozhet vklyuchat':
nachal'nye usloviya,
opredeleniya,
fragmenty programmy pol'zovatelya,
tablicy naborov simvolov,
ukazateli host-yazyka,
izmeneniya razmerov vnutrennih massivov,
kommentarii v formate host-yazyka.
NACHALXNYE USLOVIYA zadayutsya v forme:
%START imya1 imya2 ...
Esli nachal'nye usloviya opredeleny, to eta stroka dolzhna byt'
pervoj v Lex-programme.
OPREDELENIYA zadayutsya v forme:
imya translyaciya
V kachestve razdelitelya ispol'zuetsya odin ili bolee probelov
ili tabulyacij. Primer:
BUKVA [A-ZA-YAa-za-ya_]
DIGIT [0-9]
IDENTIFIKATOR {BUKVA}({BUKVA}|{DIGIT})*
Imya - kak obychno, lyubaya posledovatel'nost' bukv i cifr,
nachinayushchayasya s bukvy. Translyaciya - eto regulyarnoe vyrazhenie
(ili ego chast'), kotoroe budet podstavleno vsyudu tam, gde
ukazano imya (smotrite tret'yu stroku etogo primera).
15
FRAGMENTY PROGRAMMY POLXZOVATELYA ukazyvayutsya dvumya spo-
sobami:
- v vide "probel fragment";
- v vide:
%{
stroki
fragmenta
programmy
pol'zovatelya
%}
Takaya forma vklyucheniya pol'zovatel'skogo fragmenta
neobhodima dlya vvoda, naprimer, makroopredelenij Si,
kotorye dolzhny nachinat'sya v pervoj kolonke stroki.
Vse stroki fragmenta pol'zovatel'skoj programmy, raz-
meshchennye v razdele opredelenij, budut yavlyat'sya vnesh-
nimi dlya lyuboj funkcii programmy lex.yy.c
TABLICA NABOROV SIMVOLOV zadaetsya v vide:
%T
celoe_chislo stroka_simvolov
.........
celoe_chislo stroka_simvolov
%T
Sgenerirovannaya programma lex.yy.c osushchestvlyaet vvod-vyvod
simvolov posredstvom bibliotechnyh funkcij lex s imenami
input, output, unput. Takim obrazom, lex pomeshchaet v yytext
simvoly v predstavlenii, ispol'zuemom v etih bibliotechnyh
funkciyah. Dlya vnutrennego ispol'zovaniya simvol predstavlya-
etsya celym chislom, znachenie kotorogo obrazovano naborom
bitov, predstavlyayushchih simvol v konkretnoj |VM. Pol'zovatelyu
predostavlyaetsya vozmozhnost' menyat' predstavlenie simvolov
(celyh konstant) s pomoshch'yu tablicy naborov simvolov. Esli
tablica simvolov prisutstvuet v razdele opredelenij, to
lyuboj simvol, poyavlyayushchijsya libo vo vhodnom potoke, libo v
pravilah, dolzhen byt' opredelen v tablice simvolov. Simvolam
nel'zya naznachat' chislo 0 i chislo, bol'shee chisla, vydelennogo
dlya vnutrennego predstavleniya simvolov konkretnoj |VM.
Primer:
16
%T
1 Aa
2 Bb
3 Cc
.
.
.
26 Zz
27
28 +
29 -
30 0
31 1
.
.
.
39 9
%T
V etom primere simvoly verhnego i nizhnego registrov perevo-
dyatsya v chisla 1-26, simvol novoj stroki v 27, "+" i "-"
perevodyatsya v chisla 28 i 29, a cifry - v chisla 30-39.
IZMENENIYA RAZMERA VNUTRENNIH MASSIVOV zadayutsya v forme:
%x chislo
chislo - novyj razmer massiva;
x - odna iz bukv:
p - pozicii;
n - sostoyaniya;
e - uzly dereva;
a - upakovannye perehody;
k - upakovannye klassy simvolov;
o - massiv vyhodnyh elementov.
lex imeet vnutrennie tablicy, razmery kotoryh ogranicheny.
Pri postroenii programmy leksicheskogo analiza mozhet proi-
zojti perepolnenie lyuboj iz etih tablic, o chem lex soobshchaet
pri postroenii leksicheskogo analizatora. Pol'zovatelyu pre-
dostavlyaetsya vozmozhnost' izmenit' razmery tablic (sokrashchaya
razmery odnih i uvelichivaya razmery drugih) takim obrazom,
chtoby oni ne perepolnyalis'. Estestvenno, eti izmeneniya voz-
mozhny lish' v predelah toj pamyati, kotoraya vydelyaetsya pod
process.
Nizhe perechisleny razmery tablic, kotorye ustanavliva-
yutsya po umolchaniyu:
17
p - pozicij 1500
n - sostoyanij 300
e - uzlov 600
a - upakovannyh perehodov 1500
k - upakovannyh klassov simvolov 1000
o - vyhodnyh elementov 1500
Dlya togo chtoby opredelit', kakovy razmery tablic i naskol'ko
oni zanyaty, mozhno ispol'zovat' flag -v, naprimer:
% lex -v source.l
33/600 uzlov(%e)
97/1500 pozicij(%p)
17/300 sostoyanij(%n)
2551 perehodov
18/1000 upakovannyh klassov simvolov(%k)
41/1500 upakovannyh perehodov(%a)
68/1500 vyhodnyh elementov(%o)
%
Zdes' pokazano soobshchenie, kotoroe vyvodit lex po flagu -v.
CHislo pered simvolom "/" ukazyvaet skol'ko elementov massiva
zanyato, a chislo za simvolom "/" ukazyvaet ustanovlennyj raz-
mer massiva.
KOMMENTARII v razdele opredelenij zadayutsya v forme
host-yazyka i dolzhny nachinat'sya ne s pervoj kolonki stroki.
3.2. Razdel pravil
Vse, chto ukazano posle pervoj pary %% i do konca Lex-
programmy ili do vtoroj pary %%, esli ona ukazana, otnositsya
k razdelu pravil. Razdel pravil mozhet soderzhat' pravila i
fragmenty programm. Fragmenty programm, soderzhashchiesya v raz-
dele pravil, stanovyatsya chast'yu funkcii yylex fajla lex.yy.c,
v kotoroj osushchestvlyaetsya vypolnenie dejstvij aktivnyh pra-
vil. Fragment programmy ukazyvaetsya sleduyushchim obrazom:
%{
stroki
fragmenta
programmy
%}
Naprimer:
%%
%{
#include file.h
%}
.
.
.
18
Zdes' stroka "#include file.h" stanet strokoj funkcii
yylex().
Razdel pravil mozhet vklyuchat' spisok aktivnyh i neaktiv-
nyh (pomechennyh) pravil. Aktivnye i neaktivnye pravila
mogut byt' ukazany v lyubom poryadke, v tom chisle byt' "pere-
meshannymi" v spiske. Aktivnye pravila vypolnyayutsya vsegda,
neaktivnye tol'ko po ssylke na nih operatorom BEGIN.
Aktivnoe pravilo imeet vid:
VYRAZHENIE DEJSTVIE
Neaktivnoe pravilo imeet vid:
<METKA>VYRAZHENIE DEJSTVIE
ili
<SPISOK_METOK>VYRAZHENIE DEJSTVIE
gde SPISOK_METOK imeet vid:
metka1,metka2,...
V kachestve pervogo pravila razdela pravil mozhet byt' pravilo
vida:
BEGIN METKA;
V etom pravile otsutstvuet VYRAZHENIE, i pervym dejstviem v
razdele pravil budet aktivizaciya pomechennyh pravil. Dlya
vozvrashcheniya avtomata v ishodnoe sostoyanie mozhno ispol'zovat'
dejstvie:
BEGIN 0;
Vazhno otmetit' sleduyushchee. Esli Lex-programma soderzhit aktiv-
nye i neaktivnye pravila, to aktivnye pravila rabotayut
vsegda. Operator "BEGIN METKA;" prosto rasshiryaet spisok
aktivnyh pravil, aktiviruya pomechennye metkoj METKA. A opera-
tor "BEGIN 0;" udalyaet iz spiska aktivnyh pravil vse pome-
chennye pravila, kotorye do etogo byli aktivirovany. Krome
togo, esli iz pomechennogo i aktivnogo v dannyj moment vre-
meni pravila osushchestvlyaetsya dejstvie BEGIN METKA, to iz
pomechennyh pravil aktivnymi ostanutsya tol'ko te, kotorye
pomecheny metkoj METKA.
3.2.1. Dejstviya v pravilah Lex-programmy
Dejstvie mozhno predstavlyat' libo kak operator lex, nap-
rimer, "BEGIN METKA;", libo kak operator Si. Esli imeetsya
neobhodimost' vypolnit' dostatochno bol'shoj nabor preobrazo-
vanij, to dejstvie oformlyayut kak blok Si-programmy (on
19
nachinaetsya otkryvayushchej figurnoj skobkoj i zavershaetsya zakry-
vayushchej figurnoj skobkoj), soderzhashchij neobhodimye fragmenty.
Dejstvie v pravile ukazyvaetsya cherez ne menee, chem odin
probel ili tabulyaciyu posle vyrazheniya (obyazatel'no v toj zhe
stroke, gde i vyrazhenie), a ego prodolzhenie mozhet byt' uka-
zano v sleduyushchih strokah tol'ko v tom sluchae, esli dejstvie
oformleno kak blok Si-programmy.
Oblast' dejstviya peremennyh, ob®yavlennyh vnutri bloka,
rasprostranyaetsya tol'ko na etot blok. Vneshnimi peremennymi
dlya vseh dejstvij budut yavlyat'sya tol'ko te peremennye, koto-
rye ob®yavleny v razdele opredelenij Lex-programmy.
Dejstviya v pravilah Lex-programmy vypolnyayutsya, esli
pravilo aktivno, i esli avtomat raspoznaet cepochku simvolov
iz vhodnogo potoka kak sootvetstvuyushchuyu regulyarnomu vyrazheniyu
dannogo pravila. Odnako, odno dejstvie vypolnyaetsya vsegda -
ono zaklyuchaetsya v kopirovanii vhodnogo potoka simvolov v
vyhodnoj. |to kopirovanie osushchestvlyaetsya dlya vseh vhodnyh
strok, kotorye ne sootvetstvuyut pravilam, preobrazuyushchim eti
stroki. Kombinaciya simvolov, ne uchtennaya v pravilah i poya-
vivshayasya na vhode, budet napechatana na vyhode. Mozhno ska-
zat', chto dejstvie - eto to, chto delaetsya vmesto kopirovaniya
vhodnogo potoka simvolov na vyhod. CHasto byvaet neobhodimo
ne kopirovat' na vyhod nekotoruyu cepochku simvolov, kotoraya
udovletvoryaet nekotoromu regulyarnomu vyrazheniyu. Dlya etoj
celi ispol'zuetsya pustoj operator Si, naprimer:
[ 0 ;
|to pravilo ignoriruet (zapreshchaet) vyvod probelov, tabulyacij
i simvola novaya stroka. Zapret vyrazhaetsya v tom, chto na
ukazannye simvoly vo vhodnom potoke osushchestvlyaetsya dejstvie
";" - pustoj operator Si, i eti simvoly ne kopiruyutsya v
vyvodnoj potok simvolov.
Sushchestvuet vozmozhnost' dlya neskol'kih regulyarnyh vyra-
zhenij ukazyvat' odno dejstvie. Dlya etogo ispol'zuetsya simvol
"|", kotoryj ukazyvaet, chto dejstvie dannogo pravila sovpa-
daet s dejstviem dlya sleduyushchego, naprimer:
" " |
|
;
Rezul'tat budet tot zhe, chto i v primere, ukazannom vyshe.
Kogda neobhodimo vyvesti ili preobrazovat' tekst, soot-
vetstvuyushchij nekotoromu regulyarnomu vyrazheniyu, ispol'zuetsya
vneshnij massiv simvolov, kotoryj formiruet lex. Nazyvaetsya
on yytext i dostupen v dejstviyah pravil. Naprimer:
20
[A-Z]+ printf("%s",yytext);
Po etomu pravilu raspoznaetsya slovo, soderzhashchee propisnye
latinskie bukvy i vyvoditsya s pomoshch'yu printf, esli ono vyde-
leno. Operaciya vyvoda raspoznannogo vyrazheniya ispol'zuetsya
ochen' chasto, poetomu imeetsya sokrashchennaya forma zapisi etogo
dejstviya:
[A-Z]+ ECHO;
Rezul'tat dejstviya etogo pravila budet analogichen rezul'tatu
predydushchego primera. V vyhodnom fajle lex.yy.c ECHO oprede-
leno kak makropodstanovka:
#define ECHO fprintf(yyout, "%s",yytext);
Kogda neobhodimo znat' dlinu obnaruzhennoj posledovatel'nosti
simvolov, ispol'zuetsya schetchik najdennyh simvolov yyleng,
kotoryj takzhe dostupen v dejstviyah. Naprimer:
[A-Z]+ printf("%c",yytext[yyleng-1]);
V etom primere budet vyvoditsya poslednij simvol slova, soot-
vetstvuyushchego regulyarnomu vyrazheniyu [A-Z]+. Rassmotrim eshche
odin primer:
[A-Z]+ {chislo_slov++;chislo_bukv += yyleng;}
Zdes' vedetsya podschet chisla raspoznannyh slov i kolichestva
simvolov vo vseh slovah.
3.2.2. Poryadok dejstviya aktivnyh pravil
Spisok pravil Lex-programmy mozhet soderzhat' aktivnye i
neaktivnye pravila, razmeshchennye v lyubom poryadke v razdele
pravil. V processe raboty leksicheskogo analizatora spisok
aktivnyh pravil mozhet vidoizmenyat'sya za schet dejstvij opera-
tora BEGIN. V processe raspoznavaniya simvolov vhodnogo
potoka mozhet okazat'sya tak, chto odna cepochka simvolov budet
udovletvoryat' neskol'kim pravilam i, sledovatel'no, vozni-
kaet problema: dejstvie kakogo pravila dolzhno vypolnyat'sya?
Dlya razresheniya etogo protivorechiya mozhno ispol'zovat'
kvantovanie (razbienie) regulyarnyh vyrazhenij etih pravil
Lex-programmy na takie novye regulyarnye vyrazheniya, kotorye
dadut, po vozmozhnosti, odnoznachnoe raspoznavanie leksemy.
Odnako, kogda eto ne sdelano, lex ispol'zuet opredelennyj
determinirovannyj mehanizm razresheniya takogo protivorechiya:
- vybiraetsya dejstvie togo pravila, kotoroe raspoznaet
naibolee dlinnuyu posledovatel'nost' simvolov iz vhod-
nogo potoka;
21
- esli neskol'ko pravil raspoznayut posledovatel'nosti
simvolov odnoj dliny, to vypolnyaetsya dejstvie togo
pravila, kotoroe zapisano pervym v spiske razdela
pravil Lex-programmy.
Rassmotrim primer:
.
.
.
[Mm][Aa][Jj] ECHO;
[A-YAa-ya]+ ECHO;
.
.
.
Slovo "Maj" raspoznayut oba pravila, odnako, vypolnitsya per-
voe iz nih, tak kak i pervoe, i vtoroe pravilo raspoznali
leksemu odinakovogo razmera (3 simvola). Esli vo vhodnom
potoke budet, dopustim, slovo "majskij", to pervye 3 simvola
udovletvoryayut pervomu pravilu, a vse 7 simvolov udovletvo-
ryayut vtoromu pravilu, sledovatel'no, vypolnitsya vtoroe pra-
vilo, tak kak emu udovletvoryaet bolee dlinnaya posledovatel'-
nost' simvolov.
3.3. Razdel programm pol'zovatelya
Vse, chto razmeshcheno za vtorym naborom %%, otnositsya k
razdelu programm pol'zovatelya. Soderzhimoe etogo razdela
kopiruetsya v vyhodnoj fajl lex.yy.c bez kakih-libo izmene-
nij. V fajle lex.yy.c stroki etogo razdela rassmatrivayutsya
kak funkcii v smysle Si. |ti funkcii mogut vyzyvat'sya v
dejstviyah pravil i, kak obychno, peredavat' i vozvrashchat' zna-
cheniya argumentov.
3.4. Kommentarii Lex-programmy
Kommentarii mozhno ukazyvat' vo vseh razdelah Lex-
programmy. Format kommentariev dolzhen sootvetstvovat' for-
matu kommentariev host-yazyka. Odnako, v kazhdom razdele Lex-
programmy kommentarii ukazyvayutsya po raznomu. V razdele
opredelenij kommentarii dolzhny nachinat'sya ne s pervoj pozi-
cii stroki. V razdele pravil kommentarii mozhno ukazyvat'
tol'ko vnutri blokov, prinadlezhashchih dejstviyam. V razdele
programm pol'zovatelya kommentarii ukazyvayutsya kak i v host-
yazyke.
3.5. Primery Lex-programm
Primer1.
22
%Start KOMMENT
/*
* Programma zapisyvaet v
* standartnyj fajl vyvoda
* kommentarii Si-programmy.
* Obratite vnimanie na to, chto
* zdes' stroki kommentariev ukazany
* ne s pervoj pozicii stroki!
*/
KOMM_NACHALO "/*"
KOMM_KONEC "*/"
%%
{KOMM_NACHALO} { ECHO;
BEGIN KOMMENT;}
[0* ;
<KOMMENT>[^*]* ECHO;
<KOMMENT>[^/] ECHO;
<KOMMENT>{KOMM_KONEC} {
ECHO;
printf("0);
/*
* Zdes' priveden primer
* ispol'zovaniya kommentariev v
* razdele pravil Lex-programmy.
* Obratite vnimanie na to, chto
* kommentrij ukazan vnutri bloka,
* opredelyayushchego dejstvie pravila.
*/
BEGIN 0;}
%%
/*
* Zdes' priveden primer kommentariev
* v razdele programm pol'zovatelya.
*/
Primer 2.
23
%Start IC1 IC2 Normal
/*
* Otladochnyj fragment
* Lex-programmy, kotoraya stroit
* leksicheskij analizator dlya
* kompilyatora yazyka Paskal'.
* Dejstvie return(...)
* vozvrashchaet tip leksemy v
* v vyzyvayushchuyu analizator
* programmu.
* Obratite vnimanie na to, chto v
* etoj Lex-programme otsutstvuyut
* aktivnye pravila. |to sdelano
* v svyazi s tem, chto net
* neobhodimosti imet' pravila,
* kotorye vsegda aktivny.
* Vse cepochki simvolov vhodnogo
* potoka, ne raspoznannye v
* pravilah, kopiruyutsya v vyhodnoj
* potok simvolov.
*/
LETTER [A-ZA-YAa-za-ya_]
DIGIT [0-9]
IDENT {LETTER}({LETTER}|{DIGIT})*
INT {DIGIT}+
FIXED {INT}?.{INT}
WHISP [ 0*
%%
BEGIN Normal;
<Normal>"{" BEGIN IC1;
<IC1>[^}] ;
<IC1>"}" BEGIN Normal;
<Normal>"(*" BEGIN IC2;
<IC2>[^*]|[^)] ;
<IC2>>"*)" BEGIN Normal;
<Normal>'([^']|'')*' return( stroka );
<Normal>"<>" return( ne_ravno );
<Normal>"=" return( ravno );
<Normal>"<" return( men'she );
<Normal>">" return( bol'she );
<Normal>">=" return(bol'she_ili_ravno);
<Normal>"<=" return(men'she_ili_ravno);
<Normal>".." return( tochka_tochka );
<Normal>"+" return( plyus );
<Normal>"-" return( minus );
<Normal>":=" return( prisvoit' );
<Normal>"*" return( umnozhit' );
<Normal>"/" return( razdelit' );
<Normal>mod return( t_mod );
24
<Normal>div return( t_div );
<Normal>and return( t_and );
<Normal>or return( t_or );
<Normal>not return( t_not );
<Normal>"(" return( lpar );
<Normal>")" return( rpar );
<Normal>"[" return( lbracket );
<Normal>"]" return( rbracket );
<Normal>"," return( comma );
<Normal>":" return( colon );
<Normal>"^" return( circumflex );
<Normal>";" return( semicolon );
<Normal>write return( Write );
<Normal>writeln return( Writeln );
<Normal>label return( t_label );
<Normal>program return( );
<Normal>const x( "konstanty" ) ;
<Normal>type x( "tipy" ) ;
<Normal>var x( "perem" ) ;
<Normal>procedure x( "procedura" ) ;
<Normal>function x( "funkciya" ) ;
<Normal>begin x( "nachalo" ) ;
<Normal>end{WHISP}. x( "konec progr" ) ;
<Normal>end x( "konec" ) ;
<Normal>array x( "massiv" ) ;
<Normal>of x( "iz" ) ;
<Normal>record x( "zapis'" ) ;
<Normal>case x( "vybor" ) ;
<Normal>in x( "v" ) ;
<Normal>file x( "fajl" ) ;
<Normal>for x( "dlya" ) ;
<Normal>to x( "k" ) ;
<Normal>downto x( "vniz k" ) ;
<Normal>do x( "vypoln" ) ;
<Normal>while x( "poka" ) ;
<Normal>repeat x( "povt" ) ;
<Normal>until x( "do" ) ;
<Normal>set x( "mnozhestvo" ) ;
<Normal>with x( "s" );
<Normal>nil x( "nil" ) ;
<Normal>if x( "esli" ) ;
<Normal>then x( "to" ) ;
<Normal>else x( "inache" ) ;
<Normal>{FIXED} x( "float" ) ;
<Normal>{INT} x( "c.b.z" ) ;
<Normal>{IDENT} x( "ident" ) ;
<Normal>[ 0] ;
%%
x( s )
char *s ;
{
25
printf("%-15.15s 177> %s <1770,
s, yytext ) ;
}
4. Struktura fajla lex.yy.c
lex stroit programmu - leksicheskij analizator na yazyke
Si, kotoraya razmeshchaetsya v fajle so standartnym imenem
lex.yy.c. |ta programma soderzhit dve osnovnyh funkcii i nes-
kol'ko vspomogatel'nyh. Osnovnye - eto:
funkciya yylex()
Ona soderzhit razdely dejstvij vseh pravil, kotorye
opredeleny pol'zovatelem;
funkciya yylook()
Ona realizuet determinirovannyj konechnyj avtomat, koto-
ryj osushchestvlyaet razbor vhodnogo potoka simvolov v
sootvetstvii s regulyarnymi vyrazheniyami pravil Lex-
programmy.
Vspomogatel'nye funkcii, kotorye yavlyayutsya podprogram-
mami vvoda-vyvoda. K nim otnosyatsya:
input()
chitaet i vozvrashchaet simvol iz vhodnogo potoka simvolov;
unput(c)
vozvrashchaet simvol obratno vo vhodnoj potok dlya povtor-
nogo chteniya;
output(c)
vyvodit v vyhodnoj potok simvol c.
|ti funkcii opredeleny kak makropodstanovki sleduyushchim
obrazom:
input -
fprintf( fout, "%s%d%s0,
"#define input() (((yytchar=yysptr>yysbuf
ctable['0],
"?(yylineno++,yytchar):yytchar)==EOF?0:yyt
unput -
26
#define unput(c){
yytchar = (c);
if( yytchar == '\n' ) yylineno--;
*yysptr++ = yytchar;
}
output -
#define output(c) putc(c,yyout)
|ti funkcii mozhno izmenit', ukazav im te zhe imena i
razmestiv v razdele programm pol'zovatelya.
Pri sborke programmy leksicheskogo analiza redaktor
svyazi ld po flagu -ll podklyuchaet golovnuyu funkciyu main, esli
ona ne opredelena. Nizhe priveden tekst etoj funkcii iz bib-
lioteki /usr/lib/libl.a
# include "stdio.h"
main(){
yylex();
exit(0);
}
5. Funkciya yywrap()
Funkciya yywrap ispol'zuetsya dlya opredeleniya konca
fajla, iz kotorogo leksicheskij analizator chitaet potok sim-
volov. Esli yywrap vozvrashchaet 1, leksicheskij analizator
prekrashchaet rabotu. Odnako, inogda imeetsya neobhodimost'
nachat' vvod dannyh iz drugogo istochnika i prodolzhit' rabotu.
V etom sluchae pol'zovatel' dolzhen napisat' svoyu podprogrammu
yywrap, kotoraya organizuet novyj vhodnoj potok i vozvrashchaet
0, chto sluzhit signalom k prodolzheniyu raboty analizatora. Po
umolchaniyu yywrap vsegda vozvrashchaet 1 pri zavershenii vhodnogo
potoka simvolov.
V Lex-programme nevozmozhno zapisat' pravilo, kotoroe
budet obnaruzhivat' konec fajla. Edinstvennyj sposob eto sde-
lat' - ispol'zovat' funciyu yywrap. |ta funkciya takzhe udobna,
kogda neobhodimo vypolnit' kakie-libo dejstviya po zaversheniyu
vhodnogo potoka simvolov, opredeliv v razdele programm pol'-
zovatelya novyj variant funkcii yywrap. Primer:
27
%START AA BB CC
/*
* Stroitsya leksicheskij analizator,
* kotoryj raspoznaet nalichie
* vklyuchenij fajlov v Si-programme,
* uslovnyh kompilyacij,
* makroopredelenij,
* metok i golovnoj funkcii main.
* Analizator nichego ne vyvodit, poka
* osushchestvlyaetsya chtenie vhodnogo
* potoka, a po ego zavershenii
* vyvodit statistiku.
*/
BUKVA = [A-ZA-YAa-za-ya_]
CIFRA [0-9]
IDENTIFIKATOR {BUKVA}({BUKVA}|{CIFRA})*
int a1,a2,a3,b1,b2,c;
%%
{a1 = a2 = a3 = b1 = b2 = c = 0;}
^# BEGIN AA;
^[ \t]*main BEGIN BB;
^[ \t]*{IDENTIFIKATOR} BEGIN CC;
\t ;
\n BEGIN 0;
<AA>define { a1++; }
<AA>include { a2++; }
<AA>ifdef { a3++; }
<BB>[^\,]*","[^\,]*")" { b1++; }
<BB>[^\,]*")" { b2++; }
<CC>":"/[ \t] { c++; }
%%
yywrap(){
if( b1 == 0 && b2 == 0 )
printf("V programme\
otsutstvuet funkciya main.\n");
if( b1 >= 1 && b2 >= 1 ){
printf("Mnogokratnoe\
opredelenie funkcii main.\n");
} else {
if(b1 == 1 )
printf("Funkciya main\
28
s argumentami.\n");
if( b2 == 1 )
printf("Funkciya main\
bez argumentov.\n");
}
printf("Vklyuchenij fajlov: %d.\n",a2);
printf("Uslovnyh kompilyacij: %d.\n",a3);
printf("Opredelenij: %d.\n",a1);
printf("Metok: %d.\n",c);
return(1);
}
Operator return(1) v funkcii yywrap ukazyvaet, chto lek-
sicheskij analizator dolzhen zavershit' rabotu. Esli neobhodimo
prodolzhit' rabotu analizatora dlya chteniya dannyh iz novogo
fajla, nuzhno ukazat' return(0), predvaritel'no osushchestviv
operacii zakrytiya i otkrytiya fajlov i, v etom sluchae, anali-
zator prodolzhit chtenie i obrabotku vhodnogo potoka. Odnako,
esli yywrap ne vozvrashchaet 1, to eto privodit k beskonechnomu
ciklu.
6. Funkciya REJECT
Obychno lex razdelyaet vhodnoj potok, ne osushchestvlyaya
poisk vseh vozmozhnyh sootvetstvij kazhdomu vyrazheniyu. |to
oznachaet, chto kazhdyj simvol rassmatrivaetsya odin i tol'ko
odin raz. Predpolozhim, chto my hotim podschitat' vse vhozhdeniya
cepochek she i he vo vhodnom tekste. Dlya etogo my mogli by
zapisat' sleduyushchie pravila:
she s++;
he h++;
. |
\n ;
Tak kak she vklyuchaet v sebya he, analizator ne raspoznaet te
vhozhdeniya he, kotorye vklyucheny v she, tak kak, prochitav odin
raz she, eti simvoly on ne vernet vo vhodnoj potok.
Inogda zhelatel'no pereopredelit' etot vybor. Dejstvie
funkcii REJECT oznachaet "vybrat' sleduyushchuyu al'ternativu".
|to privodit k tomu, chto kakim by ni bylo pravilo, posle
nego neobhodimo vypolnit' vtoroj vybor. Sootvetstvenno izme-
nitsya i polozhenie ukazatelya vo vhodnom potoke:
29
she { s++; REJECT; }
he { h++; REJECT; }
. |
\n ;
Zdes' posle vypolneniya odnogo pravila simvoly vozvrashchayutsya
nazad vo vhodnoj potok, i vypolnyaetsya drugoe pravilo.
Funkciya REJECT polezna v tom sluchae, kogda ona primenya-
etsya dlya opredeleniya vseh vhozhdenij kakogo-libo ob®ekta,
prichem vhozhdeniya mogut perekryvat'sya ili vklyuchat' drug
druga. Predpolozhim, neobhodimo poluchit' iz odnogo potoka
tablicu vseh dvuhbukvennyh sochetanij, kotorye obychno perek-
ryvayutsya, naprimer, slovo the soderzhit kak th, tak i he.
Dopustim, imeetsya dvumernyj massiv digram, togda:
%%
[a-z][a-z] {
digram[yytext[0]][yytext[1]]++;
REJECT;
}
\n ;
Zdes' REJECT ispol'zuetsya dlya vydeleniya bukvennyh par, nachi-
nayushchihsya na kazhdoj bukve, a ne na kazhdoj sleduyushchej.
7. Funkcii yyless i yymore
V obychnoj situacii soderzhimoe yytext obnovlyaetsya vsyakij
raz, kogda na vhode poyavlyaetsya sleduyushchaya stroka. Napomnim,
chto v yytext vsegda nahodyatsya simvoly raspoznannoj posledo-
vatel'nosti. Inogda voznikaet neobhodimost' dobavit' k teku-
shchemu soderzhimomu yytext sleduyushchuyu raspoznannuyu cepochku sim-
volov. Dlya etoj celi ispol'zuetsya funkciya yymore. Format
vyzova etoj funkcii:
yymore()
V nekotoryh sluchayah voznikaet neobhodimost' ispol'zovat' ne
vse simvoly raspoznannoj posledovatel'nosti v yytext, a
tol'ko neobhodimoe ih chislo. Dlya etoj celi ispol'zuetsya
funkciya yyless. Format ee vyzova:
yyless(n)
gde n ukazyvaet, chto v dannyj moment neobhodimy tol'ko n
simvolov stroki v yytext. Ostal'nye najdennye simvoly budut
vozvrashcheny vo vhodnoj potok.
Primer ispol'zovaniya funckii yymore:
30
.
.
.
\"[^"]* {
if( yytext[yyleng - 1] == '\\'){
yymore();
}else{
/*
* zdes' dolzhna byt' chast'
* programmy, obrabatyvayushchaya
* zakryvayushchuyu kavychku.
*/
}
}
.
.
.
V etom primere raspoznayutsya stroki simvolov, vzyatye v dvoj-
nye kavychki, prichem simvol dvojnaya kavychka vnutri etoj
stroki mozhet izobrazhat'sya s predshestvuyushchej kosoj chertoj.
Analizator dolzhen raspoznavat' kavychku, ogranichivayushchuyu
stroku, i kavychku, yavlyayushchuyusya chast'yu stroki, kogda ona izob-
razhena kak \".
Dopustim, na vhod postupaet stroka "abv\"gde". Snachala
budet raspoznana cepochka "abv\ i, tak kak poslednim simvolom
v etoj cepochke budet simvol "\", vypolnitsya vyzov yymore().
V rezul'tate k cepochke "abv\ budet dobavleno "gde, i v
yytext my poluchim: "abv\"gde, chto i trebovalos'.
Primer ispol'zovaniya funcii yyless:
.
.
.
=-[A-ZA-YAa-za-ya] {
printf("Operator (=-) dvusmyslennyj.\n");
yyless(yyleng - 2);
/*
* zdes' neobhodimo ukazat'
* dejstviya dlya sluchaya "=-"
*/
}
.
.
.
V etom primere razreshaetsya dvusmyslennost' vyrazheniya "=-
31
bukva" v yazyke Si. |to vyrazhenie mozhno rassmatrivat' kak
"=- bukva" (ravnosil'no "-=" )
ili
"= -bukva"
Predpolozhim, chto zhelatel'no etu situaciyu rassmatrivat' kak
"= -bukva" i vyvodit' perduprezhdenie. Ukazannoe v primere
pravilo raspoznaet etu situaciyu i vyvodit preduprezhdenie.
Zatem, v rezul'tate vyzova "yyless(yyleng - 2);" dva sim-
vola "-bukva" budut vozvrashcheny vo vhodnoj potok, a znak "="
ostanetsya v yytext dlya obrabotki, kak v normal'noj situacii.
Takim obrazom, pri prodolzhenii chteniya vhodnogo potoka uzhe
budet obrabatyvat'sya cepochka "-bukva", chto i trebovalos'.
8. Sovmestnoe ispol'zovanie lex i yacc
yacc trebuet ukazanie leksicheskomu analizatoru imeni
yylex(). Imenno poetomu eta funkciya tak nazyvaetsya v lex.
Izvestno, chto yacc stroit vyhodnoj fajl y.tab.c .
Osnovnoj v fajle y.tab.c yavlyaetsya funkciya yyparse, realizuyu-
shchaya algoritm grammaticheskogo razbora. Funkciya yyparse soder-
zhit mnogokratnoe obrashchenie k funkcii leksicheskogo analiza
yylex.
Dlya obespecheniya korrektnoj raboty grammaticheskogo ana-
lizatora funkciya yylex dolzhna byt' soglasovana s konkretnoj
specifikaciej grammatiki i udovletvoryat' opredelennym trebo-
vaniyam.
Pol'zovatel' pri opisanii grammatiki reshaet, kakie
konstrukcii celesoobraznee neposredstvenno vydelyat' iz vhod-
nogo teksta na etape leksicheskogo analiza.
Slozhnost' leksicheskogo analizatora zavisit ot togo,
kakie strukturnye edinicy vzyaty za osnovu pri opisanii gram-
maticheskih pravil. Detalizovav grammatiku do otdel'nyh sim-
volov, mozhno obojtis' prostejshim leksicheskim analizatorom.
Odnako, v etom sluchae chislo pravil rastet, a grammaticheskij
razbor okazyvaetsya menee effektivnym. Poetomu pol'zovatel'
obychno dolzhen najti nekotoryj kompromiss pri vybore nabora
leksem.
Zametim, chto klyuchevye slova opisyvaemogo vhodnogo yazyka
chasto byvaet udobno schitat' leksemami. Imena leksem mogut
sovpadat' s etimi klyuchevymi slovami, nedopustimym yavlyaetsya
lish' sovpadenie imen leksem s zarezervirovannymi slovami
yazyka Si.
Osnovnaya zadacha funkcii yylex sostoit vo vvode iz vhod-
nogo potoka ryada ocherednyh simvolov do vyyavleniya konstruk-
cii, sootvetstvuyushchej odnoj iz leksem, i vozvrashchenii nomera
32
tipa etoj leksemy i, kogda eto neobhodimo, znacheniya etoj
leksemy.
Vse vidy leksem, krome literalov, oboznachayutsya nekoto-
rymi imenami i pod etimi imenami figuriruyut v Yacc-
programme, gde ob®yavlenie imen leksem osushchestvlyaetsya direk-
tivoj token:
%token <spisok imen leksem>
Blagodarya ob®yavleniyu imen leksem v direktive token, yacc
otlichaet imena leksem ot imen neterminal'nyh simvolov.
Primer ob®yavleniya imen leksem v Yacc-programme:
%token IDENT CONST ZNAK IF THEN GOTO
Pri pervom poyavlenii leksemy ili literala v sekcii ob®yavle-
nij Yacc-programmy za kazhdym iz nih mozhet sledovat' neotri-
catel'noe celoe chislo, rassmatrivaemoe kak nomer_tipa lek-
semy.
Po umolchaniyu nomera tipov vseh leksem opredelyayutsya yacc
sleduyushchim obrazom:
- dlya literala nomerom tipa leksemy schitaetsya chislovoe
znachenie dannogo literal'nogo simvola, rassmatrivae-
mogo kak odnobajtovoe celoe chislo;
- leksemy, oboznachennye imenami, v sootvetstvii s oche-
rednost'yu ih ob®yavleniya poluchayut posledovatel'nye
nomera, nachinaya s 257.
Dlya kazhdogo imeni leksemy nezavisimo ot togo, pereopre-
delen li ee nomer pol'zovatelem, yacc generiruet v vyhodnom
fajle y.tab.c operator preprocessora:
#define <imya_leksemy> <nomer_tipa>
Znachenie, vozvrashchaemoe funkciej yylex, yavlyaetsya nomerom tipa
leksemy. Takim obrazom, spisok leksem i nomera ih tipov uka-
zyvayutsya v Yacc-programme, a opredeleniya etih leksem v Lex-
programme. Voznikaet problema sootvetstviya nomerov tipov
leksem v fajlah y.tab.c i lex.yy.c, kotoroya razreshaetsya sle-
duyushchim obrazom:
- pri vyzove yacc s flagom -d posledovatel'nost' opera-
torov #define pomeshchaetsya v fajl y.tab.h.;
- etot fajl posredstvom operatora #include vklyuchaetsya v
Lex-programmu.
33
V procedure leksicheskogo analiza krome vydeleniya leksem
mozhno predusmotret' nekotoruyu obrabotku leksem opredelennyh
tipov, v chastnosti, zapominanie konkretnyh znachenij leksem.
Primerom znacheniya leksemy mogut sluzhit' chislovoe znache-
nie simvola - cifry, vychislennoe znachenie konstanty, adres
identifikatora v tablice imen (postroenie tablicy imen osu-
shchestvlyaet lex). Krome togo, eti znacheniya obychno trebuetsya
peredat' grammaticheskomu analizatoru. S etoj cel'yu nuzhnoe
znachenie dolzhno byt' prisvoeno vneshnej peremennoj celogo
tipa s imenem yylval. Esli funkciya yylex nahoditsya v otdel'-
nom fajle, to eta peremennaya dolzhna byt' ob®yavlena:
extern int yylval;
Utochnim, chto znacheniem_leksemy budem nazyvat' znachenie,
prisvoennoe pri ee raspoznavanii peremennoj yylval. Zametim,
chto v yylval vsegda dolzhno nahoditsya znachenie poslednej
vydelennoj leksemy.
Dopustim, my raspolagaem Yacc-programmoj v fajle
source.y i Lex-programmoj v fajle source.l, kotorye neobho-
dimo sobrat' v rabotayushchuyu programmu. Sushchestvuet dva sposoba
sborki:
- sborka Lex- i Yacc-programmy s sozdaniem fajla
y.tab.h;
- sborka Lex- i Yacc-programmy bez sozdaniya fajla
y.tab.h.
Rassmotrim pervyj sposob sborki.
Nizhe priveden primer makefile dlya programmy make, koto-
raya osushchestvlyaet posledovatel'nuyu obrabotku i sborku eih
programm i razmeshchaet rezul'tat v fajle program:
34
program: y.tab.o lex.yy.o
cc y.tab.o lex.yy.o -ly -ll -o program
y.tab.o: y.tab.c
cc -c -O y.tab.c
lex.yy.o: lex.yy.c y.tab.h
cc -c -O lex.yy.c
y.tab.h:
y.tab.c: source.y
yacc -d source.y
lex.yy.c: source.l
lex -v source.l
clear:
rm -f yy.tab.? lex.yy.? program
V fajle source.l razmeshchena Yacc-programma, realizuyushchaya
nebol'shoj nastol'nyj kal'kulyator. Kal'kulyator imeet 52
registra, pomechennyh bukvami ot A do z, i razreshaet ispol'-
zovat' arifmeticheskie vyrazheniya, soderzhashchie operacii +, -,
*, /, % (ostatok ot deleniya), & (pobitovoe i), | (pobitovoe
ili) i prisvaivanie. Kak i v Si, celye chisla, nachinayushchiesya s
0, schitayutsya vos'merichnymi, vse ostal'nye - desyatichnymi.
Rezul'tat vsegda vyvoditsya desyatichnymi chislami.
Kal'kulyator rabotaet v interaktivnom rezhime s postroch-
nym formirovaniem vyhoda, mozhet chitat' zadanie iz fajla i
vyvodit' rezul'tat v fajl.
Znak "=" ispol'zuetsya dlya prisvaivaniya, a dlya vyvedeniya
rezul'tata dostatochno nazhat' klavishu <VK>. Raspoznayutsya sko-
bochnye struktury, izmenyayushchie poryadok prioritetov pri vychis-
leniyah. Kal'kulyator rabotaet tol'ko s celymi tipa integer.
35
%token DIGIT LETTER
%left '|'
%left '&'
%left '+' '-'
%left '*' '/' '%'
%left UMINUS
%{
int base, regs[26];
%}
%%
list:
|
list stat '\n'
|list stat error '\n' { yyerrok; }
stat:
expr { printf( "%d\n",$1 ); }
|LETTER '=' expr { regs[$1]=$3; }
expr:
'(' expr ')' { $$=$2; }
|expr '+' expr { $$=$1+$3; }
|expr '-' expr { $$=$1-$3; }
|expr '*' expr { $$=$1*$3; }
|expr '/' expr { $$=$1/$3; }
|expr '%' expr { $$=$1%$3; }
|expr '&' expr { $$=$1&$3; }
|expr '|' expr { $$=$1|$3; }
|'-' expr %prec UMINUS { $$= -$2; }
| LETTER { $$=regs[$1]; }
| number;
number:
DIGIT { $$=$1;
base=10;
if($1==0) base=8; }
|number DIGIT { $$=base*$1+$2; }
V fajle source.l razmeshchena Lex-programma leksichskogo
analizatora dlya etogo kal'kulyatora:
36
%{
#include "y.tab.h"
extern int yylval;
%}
%%
^\n ;
[ \t]* ;
[A-Za-z] {
yylval = yytext[yyleng-1] - 'a';
return(LETTER);}
[0-9] {
yylval = yytext[yyleng-1] - '0';
return(DIGIT);}
Rassmotrim vtoroj sposob sborki. Makefile teper'
sushchestvenno proshche:
program: y.tab.c lex.yy.c
cc -O y.tab.c -ly -ll -o program
y.tab.c: source.y
yacc source.y
lex.yy.c: source.l
lex -v source.l
clear:
rm -f y.tab.? lex.yy.? program
No v fajlah source.y i source.l proizojdut sleduyushchie izmene-
niya. V razdele vhodnoj informacii dlya Yacc-programmy neobho-
dimo ukazat' stroku #include lex.yy.c, a iz Lex-programmy
neobhodimo ubrat' stroku #include "y.tab.h". Teper' fajl
source.y vyglyadit sleduyushchim obrazom:
37
%token DIGIT LETTER
%left '|'
%left '&'
%left '+' '-'
%left '*' '/' '%'
%left UMINUS
%{
#include "lex.yy.c"
int base, regs[26];
%}
%%
list:
|
list stat '\n'
|list stat error '\n' { yyerrok; }
stat:
expr { printf( "%d\n",$1 ); }
|LETTER '=' expr { regs[$1]=$3; }
expr:
'(' expr ')' { $$=$2; }
|expr '+' expr { $$=$1+$3; }
|expr '-' expr { $$=$1-$3; }
|expr '*' expr { $$=$1*$3; }
|expr '/' expr { $$=$1/$3; }
|expr '%' expr { $$=$1%$3; }
|expr '&' expr { $$=$1&$3; }
|expr '|' expr { $$=$1|$3; }
|'-' expr %prec UMINUS { $$= -$2; }
| LETTER { $$=regs[$1]; }
| number;
number:
DIGIT { $$=$1;
base=10;
if($1==0) base=8; }
|number DIGIT { $$=base*$1+$2; }
A fajl source.l vyglyadit sleduyushchim obrazom:
38
%{
extern int yylval;
%}
%%
^\n ;
[ \t]* ;
[A-Za-z] {
yylval = yytext[yyleng-1] - 'a';
return(LETTER);}
[0-9] {
yylval = yytext[yyleng-1] - '0';
return(DIGIT);}
9. Ispol'zovanie Ratfora
lex mozhno ispol'zovat' dlya generacii programm leksiches-
kogo analiza na Ratfore. Dlya etogo v pervoj stroke razdela
opredelenij neobhodimo ukazat' %R. Vse skazannoe vyshe ob
ispol'zovanii Si v kachestve host-yazyka otnositsya i k Rat-
foru. Neobhodimo uchest', chto Ratfor imeet svoyu biblioteku
vvoda-vyvoda. Odnako, sostav funkcij lex dlya Ratfora tot zhe,
chto i dlya Si. Est' i funkciya, vydelennaya tol'ko dlya Ratfora
- lexshf. Funkciya lexshf perevodit vnutrennee predstavlenie
simvola (mladshij bajt) iz Si vo vnutrennee predstavlenie
simvola v Fortrane (starshij bajt).
Destviya pravil Lex-programmy dlya Ratfora oformlyayutsya v
vide vychislyaemyh goto v vyhodnom fajle, kotoryj nazyvaetsya
lex.yy.r.
Dopustim, imeetsya ishodnyj fajl source.l s Ratforom v
kachestve host-yazyka, togda dlya polucheniya leksicheskogo anali-
zatora neobhodimy sleduyushchie dejstviya:
% lex source.l
% rc lex.yy.r -llr
Napomnim, chto v Ratfore indeksy massivov nachinayutsya s 1,
poetomu, naprimer, yytex[yyleng] - eto poslednij poluchennyj
iz vhodnogo potoka simvol.
10. Flagi Lex
-t pomestit' rezul'tat v standartnyj fajl vyvoda, a ne v
fajl lex.yy.c;
-v vyvesti razmery vnutrennih tablic;
-f uskorit' rabotu, ne upakovyvaya tablicy (tol'ko dlya
nebol'shih programm);
39
-n ne vyvodit' razmery tablic (ustanavlivaetsya po umolcha-
niyu);
-d ispol'zuetsya pri otladke lex.
Imeetsya vozmozhnost' sobrat' analizator dlya diagnostiki.
Dlya etogo neobhodimo kompilyaciyu fajla lex.yy.c osushchestvlyat'
s podklyucheniem razdelov diagnostiki:
cc -d -DLEXDEBUG lex.yy.c
Pri rabote poluchennogo takim obrazom analizatora budet vyvo-
dit'sya diagnostika dejstvij. Flag -d, krome togo, pozvolyaet
proverit' tekst programmy lex.yy.c s pomoshch'yu tekstovogo
otladchika cdeb.
40
SODERZHANIE
. Annotaciya ......................................... 2
1. Vvedenie .......................................... 3
2. Regulyarnye vyrazheniya v Lex-pravilah ............... 8
2.1. Oboznacheniya simvolov v vyrazheniyah ............... 8
2.2. Operatory regulyarnyh vyrazhenij .................. 9
2.3. Operator vydeleniya klassov simvolov ............. 9
2.4. Povtoriteli ..................................... 9
2.5. Operatory vybora ................................ 10
2.6. Operator {} ..................................... 11
2.7. Operator <>. Sluzhebnye slova START i BEGIN ...... 12
3. Struktura Lex-programmy ........................... 15
3.1. Razdel opredelenij Lex-programmy ................ 15
3.2. Razdel pravil ................................... 18
3.2.1. Dejstviya v pravilah Lex-programmy ............. 19
3.2.2. Poryadok dejstviya aktivnyh pravil .............. 21
3.3. Razdel programm pol'zovatelya .................... 22
3.4. Kommentarii Lex-programmy ....................... 22
3.5. Primery Lex-programm ............................ 22
4. Struktura fajla lex.yy.c .......................... 26
5. Funkciya yywrap() .................................. 27
6. Funkciya REJECT .................................... 29
7. Funkcii yyless i yymore ........................... 30
8. Sovmestnoe ispol'zovanie lex i yacc ............... 32
9. Ispol'zovanie Ratfora ............................. 39
10. Flagi Lex ......................................... 39
41
Last-modified: Mon, 29 Jun 1998 14:01:55 GMT