Provided by:
manpages-pl_20060617-3_all 
NAZWA
flex - szybki generator analizatora leksykalnego
SK/LADNIA
flex [-bcdfhilnpstvwBFILTV78+? -C[aefFmr] -ooutput -Pprefix -Sskeleton]
[--help --version] [filename ...]
WPROWADZENIE
Podrcznik ten opisuje narzdzie flex. Jest ono przeznaczone do
generowania programow, dokonywujcych dopasowywania wzorcow na tekcie.
Podrcznik zawiera zarowno sekcje przewodnikowe jak i informacyjne.
Opis
krotki przegld moliwoci narzdzia
Proste Przyklady
Format Pliku Wejciowego
Wzorce
rozszerzone wyraenia regularne uywane przez flex
Sposob Dopasowywania Wejcia
reguly okrelania, co dopasowano
Akcje
jak podawa, co robi po dopasowaniu wzorca
Generowany Skaner
szczegoly o skanerze, tworzonym przez fleksa; jak kontrolowa rodlo
wejciowe
Warunki Startowe
wprowadzanie do skanerow kontekstu i obsluga "mini-skanerow"
Wielokrotne Bufory Wejciowe
jak obslugiwa wiele rodel wejciowych; jak skanowa z lacuchow
zamiast z plikow
Reguly Koca Pliku
specjalne reguly dopasowywane do koca wejcia
Rone Makra
ogol makr dostpnych z poziomu akcji
Wartoci Dostpne Uytkownikowi
ogol wartoci dostpnych z poziomu akcji
Lczenie z Yacc
lczenie skanerow flex z analizatorami yacc
Opcje
opcje linii polece fleksa i dyrektywa "%option"
Kwestie wydajnociowe
jak przyspiesza skanery
Generowanie Skanerow C++
eksperymentalna wlaciwo generowania klas skanerow C++
Niezgodnoci z Lex i POSIX
czym flex roni si od standardow AT&T lex i POSIX lex
Diagnostyka
objanienie komunikatow o bldach, generowanych przez flex (lub
skanery)
Pliki
pliki uywane przez flex
Niedostatki / Bldy
znane problemy fleksa
Zobacz Take
pozostala dokumentacja i zwizane z fleksem narzdzia
Autor
informacja kontaktu z autorem
OPIS
flex jest narzdziem przeznaczonym do generowania skaner'ow: programow,
rozpoznajcych wzorce leksykalne tekstu. flex odczytuje podane pliki
wejciowe (lub stdin gdy nie s podane) i pobiera z nich opis
generowanego skanera. Opis sklada si z par wyrae regularnych i kodu C.
Pary te nazywane s regu/lami. flex jako wyjcie generuje plik rodlowy C
o nazwie lex.yy.c. Definiuje on funkcj yylex(). Plik ten musi
kompilowany i konsolidowany z bibliotek -lfl. Po uruchomieniu pliku
wykonywalnego, program analizuje wejcie w poszukiwaniu wyrae
regularnych. Gdy tylko takie si znajdzie, wykonywany jest odpowiedni
fragment kodu C.
PROSTE PRZYK/LADY
Przedstawmy teraz troch prostych przykladow aby oby si z uywaniem flex.
Nastpujcy plik wejciowy flex okrela skaner, ktory za kadym razem gdy
napotka lacuch "username", podmieni go nazw uytkownika:
%%
username printf( "%s", getlogin() );
Domylnie tekst, ktorego flex nie moe dopasowa jest kopiowany na wyjcie.
Skaner bdzie wic kopiowal swoj plik wejciowy na wyjcie, podmieniajc
wszelkie pojawienia "username". W tym przykladzie wejcia mamy tylko
jedn regul. Wzorcem jest "username", a akcj jest "printf". Znaki "%%"
oznaczaj pocztek regul.
Oto kolejny prosty przyklad:
int num_lines = 0, num_chars = 0;
%%
\n ++num_lines; ++num_chars;
. ++num_chars;
%%
main()
{
yylex();
printf( "# of lines = %d, # of chars = %d\n",
num_lines, num_chars );
}
Ten skaner zlicza liczb znakow i liczb linijek swojego wejcia (nie daje
adnego wyjcia, nie liczc kocowego raportu). Pierwsza linia deklaruje
dwie zmienne globalne, "num_lines" i "num_chars", ktore s dostpne
wewntrz funkcji yylex() i main(), zadeklarowanej po drugim "%%". Mamy
tu dwie reguly: pierwsza dopasowuje si do nowej linii ("\n") i
inkrementuje licznik linii oraz znakow; druga dopasowuje si do
dowolnego znaku innego ni nowa linia (wyraenie regularne ".") i zwiksza
licznik liczby znakow.
A oto troch bardziej skomplikowany przyklad:
/* skaner dla zabawkowego Pascalo-podobnego jzyka */
%{
/* potrzebujemy tego do wywolania atof() */
#include <math.h>
%}
DIGIT [0-9]
ID [a-z][a-z0-9]*
%%
{DIGIT}+ {
printf( "Liczba calkowita: %s (%d)\n", yytext,
atoi( yytext ) );
}
{DIGIT}+"."{DIGIT}* {
printf( "Liczba zmiennoprzecinkowa: %s (%g)\n", yytext,
atof( yytext ) );
}
if|then|begin|end|procedure|function {
printf( "Slowo kluczowe: %s\n", yytext );
}
{ID} printf( "Identyfikator: %s\n", yytext );
"+"|"-"|"*"|"/" printf( "Operator: %s\n", yytext );
"{"[^}\n]*"}" /* zjedz jednolinijkowe komentarze */
[ \t\n]+ /* zjedz biale spacje */
. printf( "Nierozpoznany znak: %s\n", yytext );
%%
main( argc, argv )
int argc;
char **argv;
{
++argv, --argc; /* pomi nazw programu */
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
else
yyin = stdin;
yylex();
}
S to pocztki prostego skanera dla jzyka podobnego do Pascala. Rozronia
poszczegolne rodzaje token'ow i informuje co zobaczyl.
Szczegoly tego przykladu zostan wyjanione w nastpnych sekcjach.
FORMAT PLIKU WEJCIOWEGO
Plik wejciowy fleksa sklada si z trzech sekcji, rozdzielanych liniami z
lacuchem %%:
definicje
%%
reguly
%%
kod uytkownika
Sekcja definicji zawiera definicje prostych nazw, upraszczajcych poniej
specyfikacj skanera. Zawiera te deklaracje warunk'ow pocztkowych, ktore
objaniono w dalszej sekcji.
Definicje nazw maj posta:
nazwa definicja
gdzie "nazwa" jest slowem, rozpoczynajcym si od litery lub podkrelenia
('_'). Pozostale znaki mog by literami, cyframi, podkreleniami lub
mylnikami. Definicja jest pobierana od momentu pojawienia si
pierwszego znaku, ktory nie jest spacj i ktory znajduje si za nazw.
Definicja rozciga si do koca linii. Do takiej definicji mona si
nastpnie odwolywa przy uyciu konwencji "{nazwa}", ktora jest
automatycznie rozwijana w "(definicj)". Na przyklad
DIGIT [0-9]
ID [a-z][a-z0-9]*
definiuje "DIGIT" jako wyraenie regularne, pasujce do pojedynczej
cyfry, a "ID" jako wyraenie regularne odpowiadajce literze z
doklejonymi ewentualnymi literami lub cyframi. Poniejsze odniesienie
do
{DIGIT}+"."{DIGIT}*
jest rownowane
([0-9])+"."([0-9])*
i dopasowuje jedn lub wicej cyfr, po ktorych wystpuje kropka i
ewentualnie nastpne cyfry.
Sekcja regu/l wejcia fleksa zawiera szereg regul w postaci:
wzorzec akcja
Przed wzorcem nie moe wystpi wcicie, a akcja musi rozpoczyna si w tej
samej linii.
Dla dalszego opisu akcji patrz dalej.
W kocu, sekcja kodu uytkownika jest zwyczajnie kopiowana do lex.yy.c
(bez dokonywania w niej zmian). Jest to uywane do funkcji
pomocniczych, ktore wolaj lub s wolane przez skaner. Obecno tej sekcji
jest opcjonalna; jeli nie istnieje, to ostatni %% pliku wejciowego moe
by pominity.
Jeli w sekcjach definicji lub regul znajduje si jaki wcity
(indentowany) tekst lub tekst ujty w %{ i %}, to jest on kopiowany
doslownie na wyjcie (po usuniciu %{}). Znaki %{} musz pojawi si
samodzielnie w liniach bez wci.
W sekcji regul, tekst wcity lub tekst %{}, znajdujcy si przed pierwsz
regul moe sluy deklarowaniu zmiennych lokalnych dla procedury skanujcej
oraz (po deklaracjach) kodu, ktory ma by wywolywany za kadym
uruchomieniem procedury skanujcej. Pozostale przypadki wcitego tekstu
lub tekstu %{} sekcji regul s nadal kopiowane na wyjcie, lecz ich
znaczenie nie jest dokladnie zdefiniowane i mog spowodowa bldy
kompilacji (wlaciwo ta jest obecna dla zgodnoci z POSIX; zobacz niej
inne tego typu wlaciwoci).
W sekcji definicji na wyjcie kopiowane s rownie nie-wcite bloki
komentarza, ujte midzy znaki "/*" i "*/".
WZORCE
Wzorce wejciowe s pisane z uyciem rozszerzonego zestawu wyrae
regularnych. S to:
x dopasowuje znak 'x'
. dowolny znak poza now lini
[xyz] "klasa znakow"; w tym przypadku wzorzec odpowiada
zarowno 'x', 'y' jak i 'z'
[abj-oZ] "klasa znakow" z zakresem; odpowiada ona
'a', 'b', dowolnej literze od 'j' do 'o' oraz 'Z'
[^A-Z] zanegowana "klasa znakow" tj. dowolny znak poza
wymienionymi w klasie. W tym wypadku dowolny znak oprocz
duych liter
[^A-Z\n] dowolny znak oprocz duych liter lub nowej linii
r* zero lub wicej r'ow, gdzie r jest wyraeniem regularnym
r+ jeden lub wicej r'ow
r? zero lub jeden r (tj. "opcjonalny r")
r{2,5} od dwu do piciu r
r{2,} dwa lub wicej r
r{4} dokladnie 4 r
{nazwa} rozwinicie definicji "nazwa" (patrz wyej)
"[xyz]\"foo"
lacuch literalny: [xyz]"foo
\X Jeli X to 'a', 'b', 'f', 'n', 'r', 't' lub 'v',
to nastpuje interpretacja ANSI-C \x. W przeciwnym
wypadku uywany jest literalny 'X' (uywane do cytowania
operatorow--np. '*').
\0 znak NUL (kod ASCII 0)
\123 znak o wartoci osemkowej 123
\x2a znak o wartoci szesnastkowej 2a
(r) dopasuj r; nawiasy s uywane do przeciania priorytetow
(patrz niej)
rs wyraenie regularne r, za ktorym nastpuje wyraenie
regularne s; nazywa si to "lczeniem"
r|s r lub s
r/s r, lecz tylko jeli za nim nastpuje s. Tekst dopasowywany
przez s jest zalczany do okrelania czy ta regula miala
"najdlusze dopasowanie", lecz potem jest zwracany do
wejcia przed wykonaniem akcji. Tak wic akcja widzi tylko
tekst dopasowany przez r. Ten rodzaj wzorca jest nazywany
"doklejonym kontekstem". (Istniej pewne kombinacje r/s,
ktorych flex nie potrafi wlaciwie dopasowa; zobacz uwagi
w dalszej sekcji Niedostatki / Bldy w okolicach
"niebezpiecznego kontekstu doklejonego".)
^r r, lecz tylko na pocztku linii (tj. zaraz po rozpoczciu
skanowania, lub po wyskanowaniu nowej linii).
r$ r, lecz tylko na kocu linii (tj. tu przed now lini).
Rownowane "r/\n".
Zauwa, e notacja nowej linii fleksa jest dokladnie tym,
co bylo uywane jako '\n' przez kompilator C, uyty do
kompilacji fleksa; w praktyce na niektorych systemach DOS
musisz wyfiltrowa \r lub jawnie uywa r/\r\n zamiast
"r$".
<s>r r, lecz tylko dla warunku pocztkowego s (zobacz niej
dyskusj o warunkach pocztkowych)
<s1,s2,s3>r
to samo, lecz jeli dowolny z warunkow pocztkowych s1,
s2 lub s3
<*>r r w dowolnym warunku pocztkowym, nawet wykluczajcym
<<EOF>> koniec pliku
<s1,s2><<EOF>>
koniec pliku w warunkach pocztkowych s1 lub s2
Zauwa, e w obrbie klasy znakow wszystkie operatory wyrae regularnych
trac swoje znaczenie specjalne (nie liczc cytowania '\', znakow klasy
'-', ']' oraz '^' na pocztku klasy).
Wymienione wyej wyraenia regularne s pogrupowane zgodnie z
priorytetami, liczc od najwyszego do najniszego (z gory na dol). Te,
ktore zgrupowano razem maj jednakowy priorytet. Na przyklad,
foo|bar*
jest rownowane
(foo)|(ba(r*))
poniewa operator '*' ma wyszy priorytet ni lczenie, a lczenie ma wyszy
priorytet ni alternatywa ('|'). Wzorzec ten pasuje wic albo do lacucha
"foo" albo do "ba", po ktorym moe nastpi zero lub wicej r. W celu
dopasowania "foo" lub zero lub wicej "bar"'ow, uyj:
foo|(bar)*
a eby dopasowa zero lub wicej "foo"-lub-"bar"'ow:
(foo|bar)*
Poza znakami i zakresami znakow, klasy znakow mog te zawiera specjalne
wyraenia. Wyraenia te s ujmowane w ograniczniki [: i :] (ktore musz
dodatkowo pojawia si wewntrz '[' i ']' klasy znakow; inne elementy w
klasie znakow te mog si pojawi). Prawidlowymi wyraeniami s:
[:alnum:] [:alpha:] [:blank:]
[:cntrl:] [:digit:] [:graph:]
[:lower:] [:print:] [:punct:]
[:space:] [:upper:] [:xdigit:]
Wyraenia te oznaczaj zestaw znakow, odpowiadajcy rownowanemu
standardowi funkcji isXXX jzyka C. Przykladowo [:alnum:] oznacza
wszystkie znaki, dla ktorych isalnum(3) zwraca prawd - tj. wszelkie
znaki alfabetyczne lub numeryczne. Niektore systemy nie udostpniaj
isblank(3). Flex definiuje [:blank:] jako spacj lub tabulacj.
Na przyklad nastpujce klasy s sobie rownowane:
[[:alnum:]]
[[:alpha:][:digit:]
[[:alpha:]0-9]
[a-zA-Z0-9]
Jeli twoj skaner jest niewraliwy na wielko znakow (flaga (flaga -i), to
[:upper:] i [:lower:] s rownowane [:alpha:].
Troch uwag o wzorcach:
- Zanegowana klasa znakow, taka jak wyej wymienione przykladowe
"[^A-Z]" bdzie pasowa do nowej linii, chyba e "\n" (lub
rownowana sekwencja specjalna) jest jednym z jawnie obecnych w
klasie znakow (np. "[^A-Z\n]"). Odbiega to od sposobu
traktowania zanegowanych klas znakow przez inne narzdzia
operujce na wyraeniach regularnych, lecz niestety niespojno jest
ugruntowana historycznie. Dopasowywanie nowej linii oznacza, e
wzorzec w rodzaju [^"]* moe dopasowa si do calego wejcia, chyba
e istnieje w nim drugi cudzyslow.
- Regula moe mie najwyej jedn instancj dowizanego kontekstu
(operatory '/' lub '$'). Wzorce warunku pocztkowego '^' oraz
"<<EOF>>" mog pojawi si tylko na pocztku wzorca i dodatkowo,
podobnie jak '/' i '$', nie mog by grupowane w nawiasy. Znak
'^', ktory nie pojawia si na pocztku reguly, lub '$', nie
znajdujcy si na kocu traci swoje specjalne znaczenie.
Nastpujce wzorce s niedozwolone:
foo/bar$
<sc1>foo<sc2>bar
Zauwa, e pierwszy z nich moe by zapisany jako "foo/bar\n".
Nastpujce wzorce powoduj, e '$' lub '^' s traktowane jak zwykle
znaki:
foo|(bar$)
foo|^bar
Jeli oczekiwan wartoci jest "foo" lub "bar-z-now-lini", to uy
mona nastpujcego wzorca (akcja specjalna | jest wyjaniona niej):
foo |
bar$ /* tu rozpoczyna si akcja */
Podobna sztuczka powinna zadziala dla dopasowywania foo lub bar-
na-pocztku-linii.
JAK DOPASOWYWANE JEST WEJCIE
Po uruchomieniu skanera, analizuje on swoje wejcie w poszukiwaniu
lacuchow odpowiadajcych ktoremu z jego wzorcow. Jeli znajdzie wicej ni
jeden pasujcy wzorzec, wybiera ten, ktory pasuje do najwikszej iloci
tekstu (w regulach z dowizanym kontekstem oznacza to te dlugo czci
dowizanej, mimo faktu, e zostanie ona zwrocona na wejcie. Jeli znajdzie
dwa lub wicej dopasowa o tej samej dlugoci, to wybierana jest pierwsza
regula.
Po okreleniu dopasowania, tekst dopasowania (zwany dalej tokenem) jest
udostpniany we wskanikowej zmiennej globalnej yytext, a jego dlugo w
globalnej zmiennej calkowitej yyleng. Wykonywana jest te odpowiadajca
wzorcowi akcja (szczegolowy opis akcji jest dalej), a nastpnie
pozostala cz wejcia jest dopasowywana do kolejnego wzorca.
Jeli dopasowanie nie zostanie znalezione, wykonana zostanie regu/la
domylna: nastpny znak wejcia jest uwaany za dopasowany i kopiowany na
stdout. Tak wic najprostszym poprawnym plikiem wejciowym fleksa jest:
%%
Generuje to skaner, ktory po prostu kopiuje swoje wejcie (jeden znak
naraz) na wyjcie.
Zauwa, e yytext moe by definiowane na dwa sposoby: jako wskanik do
znakow lub jako tablica znakow. Uywanie konkretnej definicji mona
kontrolowa, wlczajc do pliku wejciowego w pierwszej sekcji specjalne
dyrektywy %pointer lub %array. Domylnie uywana jest dyrektywa
%pointer, chyba e uywa si opcji -l zgodnoci z leksem i wtedy yytext
staje si tablic. Korzyci z uywania %pointer jest zwikszenie szybkoci
skanowania i zlikwidowanie przepelnie bufora przy dopasowywaniu duych
tokenow (chyba e zabraknie pamici dynamicznej). Wad jest ograniczenie
sposobu modyfikowania przez akcje zmiennej yytext (zobacz nastpn sekcj)
i to, e wywolania funkcji unput() niszcz aktualn zawarto yytext, co moe
przyprawia o bol glowy podczas portowania skanerow midzy ronymi
wersjami lex.
Zalet %array jest moliwo modyfikowania yytext i to, e wolanie unput()
nie niszczy yytext. Poza tym, istniejce programy lex czasami
zewntrznie zagldaj do yytext przy uyciu deklaracji w postaci:
extern char yytext[];
Definicja ta jest bldna przy uyciu z %pointer, lecz prawidlowa dla
%array.
%array definiuje yytext jako tablic YYLMAX znakow, co domylnie jest do
du wartoci. Moesz zmienia rozmiar przez proste #definiowanie YYLMAX na
inn warto w pierwszej sekcji wejciowego pliku fleksa. Jak wspomniano
wyej, dla %pointer yytext wzrasta dynamicznie, by przechowywa due
tokeny. Chocia oznacza to, e skaner %pointer moe zbiera due tokeny (jak
np. cale bloki komentarzy), to zakop sobie w pamici, e za kadym razem
gdy skaner zmienia rozmiar yytext to musi rownie reskanowa caly token
od pocztku, wic moe si to okaza powolne. yytext w chwili obecnej nie
zwiksza dynamicznie rozmiaru jeli wywolanie unput() powoduje wepchnicie
z powrotem zbyt duego bloku tekstu. Zamiast tego pojawia si bld
wykonania.
Zauwa te, e postaci %array nie mona uywa z klasami skanerow C++ (zobacz
opcj c++ poniej).
AKCJE
Kady wzorzec reguly ma odpowiadajc mu akcj, ktora moe by dowoln
instrukcj jzyka C. Wzorzec koczy si na pierwszym niecytowanym znaku
bialej spacji; reszta linijki jest akcj. Jeli akcja jest pusta, to
token wejciowy jest zwyczajnie odrzucany. Na przyklad oto program,
kasujcy wszystkie pojawienia lacucha "wytnij mnie":
%%
"wytnij mnie"
(Wszystkie pozostale znaki wejcia zostan skopiowane na wyjcie, gdy
dopasuj si do reguly domylnej.)
Oto program, ktory kompresuje wielokrotne spacje i tabulacje do
pojedynczej spacji. Program wycina te wszystkie biale spacje z koca
linii:
%%
[ \t]+ putchar( ' ' );
[ \t]+$ /* ignoruj ten token */
Jeli akcja zawiera znak '{', to rozciga si ona a do zamykajcego '}',
nawet na przestrzeni wielu linii. flex ma pewne wiadomoci o lacuchach
C i komentarzach, wic nie zostanie oglupione przez klamry, ktore mog si
w nich znajdowa. Poza tym dozwolone s te akcje, ktore zaczynaj si od %{
i zawieraj tekst akcji a do nastpnego %} (niezalenie od zwyczajnych
klamer wewntrz akcji).
Akcja skladajca si wylcznie z pionowej kreski ('|') oznacza "taka sama,
jak akcja nastpnej reguly". Dla zobrazowania patrz niej.
Akcje mog zawiera kod C, wlczajc w to instrukcje return, przeznaczone
do zwracania wartoci do procedury, ktora wywolala yylex(). Przy kadym
wywolaniu yylex() kontynuuje przetwarzanie tokenow od miejsca, w ktorym
ostatnio przerwal a do osignicia koca pliku lub wywolania return.
Akcje mog spokojnie modyfikowa zmienn yytext; nie mog jej jednak wydlua
(dodawanie znakow do jej koca nadpisze dalsze znaki strumienia
wejciowego). Odmiennie jest natomiast przy uywaniu %array (patrz wyej);
wtedy yytext mona spokojnie modyfikowa w dowolny sposob.
Podobnie do powyszej zmiennej, mona spokojnie modyfikowa yyleng, lecz
naley uwaa by nie robi tego jeli akcja uywa yymore() (patrz niej).
Istnieje wiele dyrektyw specjalnych, ktore mona zawrze w akcji:
- ECHO kopiuje wejcie yytext na wyjcie skanera.
- BEGIN z doklejon nazw warunku pocztkowego umieszcza skaner w
odpowiednim warunku pocztkowym (patrz niej).
- REJECT Kieruje skaner na dzialanie w "drugiej najlepszej"
regule, ktora zostala dopasowana do wzorca wejciowego (lub
prefiksu wejcia). Regula jest wybierana wedlug zasad opisanych w
"Jak dopasowywane jest wejcie", po czym nastpuje odpowiednie
ustawienie yytext oraz yyleng. Moe to by albo ta regula, ktora
dopasowala si do takiej samej iloci tekstu, jak poprzednia, lecz
wystpila poniej w pliku wejciowym fleksa, albo taka, ktora
dopasowala si do mniejszej iloci tekstu. Na przyklad, nastpujcy
przyklad bdzie liczyl slowa wejciowe i wolal funkcj special()
dla kadego "frob":
int word_count = 0;
%%
frob special(); REJECT;
[^ \t\n]+ ++word_count;
Bez dyrektywy REJECT, slowa "frob" wejcia nie bylyby zliczane
jako slowa, gdy skaner normalnie wykonuje tylko jedn akcj na
token. Dozwolonych jest wiele komend REJECT, z ktorych kada
wyszukuje najbardziej pasujcego nastpc. Na przyklad poniszy
skaner skanujc token "abcd" zapisze na wyjciu "abcdabcaba":
%%
a |
ab |
abc |
abcd ECHO; REJECT;
.|\n /* zjedz nietrafione znaki */
(Pierwsze trzy reguly maj wspoln akcj z czwart, gdy uywaj akcji
specjalnej '|'.) REJECT jest do kosztown wlaciwoci jeli chodzi
o wydajno skanera; jeli jest uywane w ktorej z akcji skanera, to
spowolni wszystkie dopasowania skanera. Co wicej, REJECT nie moe
by uywany z opcjami -Cf i -CF (zobacz niej).
Zauwa te, e, w przeciwiestwie do innych akcji specjalnych,
REJECT jest odga/lzieniem; kod akcji wystpujcy bezporednio po nim
nie zostanie wykonany.
- yymore() mowi skanerowi, e przy nastpnym dopasowaniu reguly,
odpowiadajcy token powinien by doklejony do biecej wartoci
yytext. Na przyklad, przy wejciu "mega-kludge", poniszy
przyklad na wyjciu wypisze "mega-mega-kludge":
%%
mega- ECHO; yymore();
kludge ECHO;
Pierwsze "mega-" jest dopasowane i wydrukowane na wyjcie.
Nastpnie dopasowane jest "kludge", lecz poprzednie "mega-" wci
znajduje si na pocztku yytext i komenda ECHO dla "kludge"
wydrukuje w rzeczywistoci "mega-kludge".
Dwie uwagi na temat yymore(). Po pierwsze, yymore() zaley od wartoci
yyleng, odzwierciedlajcej rozmiar biecego tokenu. Zatem jeli uywasz
yymore(), nie modyfikuj tej zmiennej. Po drugie, obecno yymore() w
akcji skanera wplywa na pewne pogorszenie wydajnoci w szybkoci
dokonywania przez skaner dopasowa.
- yyless(n) zwraca wszystkie poza pierwszymi n znakami biecego
tokenu z powrotem do strumienia wejciowego, skd zostan one
powtornie przeskanowane przy dopasowywaniu nastpnego wzorca.
yytext i yyleng s odpowiednio dostrajane (tj. yyleng bdzie
teraz rowne n). Na przyklad, przy wejciu "foobar", nastpujcy
kod wypisze "foobarbar":
%%
foobar ECHO; yyless(3);
[a-z]+ ECHO;
Podanie yyless argumentu zerowego powoduje reskanowanie calego
obecnego lacucha wejciowego. O ile nie zmienisz sposobu
kolejnego przetwarzania przez skaner wejcia (przy uyciu np.
BEGIN), spowoduje to nieskoczon ptl.
Zwro uwag, e yyless jest makrem i moe by uywane tylko z pliku
wejciowego fleksa, a nie z innych plikow rodlowych.
- unput(c) wstawia znak c z powrotem do strumienia wejciowego.
Bdzie to nastpny skanowany znak. Ponisza akcja pobierze biecy
token i spowoduje, e zostanie reskanowany po ujciu w nawiasy.
{
int i;
/* Kopiuj yytext, gdy unput() niszczy jego zawarto */
char *yycopy = strdup( yytext );
unput( ')' );
for ( i = yyleng - 1; i >= 0; --i )
unput( yycopy[i] );
unput( '(' );
free( yycopy );
}
Zwro uwag, e skoro kady unput() wstawia dany znak na pocztek
strumienia, to wstawianie znakow musi odbywa si tylem-na-przod.
Wanym potencjalnym problemem uywania unput() jest fakt, e jeli uywasz
dyrektywy %pointer (domylne), wywolanie unput() niszczy zawarto yytext,
poczynajc od znaku najbardziej z prawej, idc w lewo za kadym
wywolaniem. Jeli potrzebujesz zachowa warto yytext po uyciu tej
funkcji, (jak w powyszym przykladzie), musisz skopiowa jej zawarto
gdzie indziej lub zbudowa skaner z uyciem %array.
Na koniec, zauwa te, e nie moesz wstawia tak znakow EOF. Nie mona t
metod zaznacza koca pliku w strumieniu.
- input() odczytuje nastpny znak ze strumienia wejciowego. Na
przyklad, ponisze jest jednym ze sposobow poerania komentarzy
jzyka C:
%%
"/*" {
register int c;
for ( ; ; )
{
while ( (c = input()) != '*' &&
c != EOF )
; /* zeryj tekst komentarza */
if ( c == '*' )
{
while ( (c = input()) == '*' )
;
if ( c == '/' )
break; /* znalazlem koniec */
}
if ( c == EOF )
{
error( "EOF w komentarzu" );
break;
}
}
}
(Zauwa, e jeli skaner jest skompilowany z uyciem C++, to input()
nazywa si yyinput(). Jest tak w celu zapobieenia zderzeniu
nazwy ze strumieniem C++ poprzez nazw input.)
- YY_FLUSH_BUFFER wypronia wewntrzny bufor skanera. Przy nastpnym
razie gdy skaner bdzie dopasowywal si do tokenu, najpierw
napelni na nowo bufor z uyciem YY_INPUT (zobacz niej Generowany
Skaner). Akcja ta jest szczegolnym przypadkiem bardziej ogolnej
funkcji yy_flush_buffer(), opisanej niej w sekcji Wielokrotne
Bufory Wejciowe.
- yyterminate() moe by uywane zamiast instrukcji return akcji.
Koczy dzialanie skanera i zwraca 0 do wywolujcego skaner,
wskazujc, e "wszystko zrobione". Domylnie, yyterminate() jest
wywolywane rownie po napotkaniu koca pliku. Jest to makro i moe
by redefiniowane.
GENEROWANY SKANER
Wynikiem dzialania fleksa jest plik lex.yy.c, zawierajcy procedur
skanujc yylex() oraz zestaw tablic, uywanych przez niego do
dopasowywania tokenow i par procedur i makr. Domylnie yylex() jest
deklarowany jako
int yylex()
{
... tu rone definicje i akcje ...
}
(Jeli twoje rodowisko obsluguje prototypy funkcji, to bdzie to "int
yylex( void )".) Definicj t mona zmieni definiujc makro "YY_DECL". Na
przyklad
#define YY_DECL float lexscan( a, b ) float a, b;
informuje fleksa, by nada procedurze skanujcej nazw lexscan i e
procedura ta ma zwraca typ float i pobiera dwa argumenty (te typu
float). Zwro uwag, e jeli podajesz argumenty procedurze skanujcej,
uywajc deklaracji w niezaprototypowanym stylu K&R, musisz zakoczy
definicj rednikiem (;).
Przy kadym wywolaniu yylex(), nastpuje skanowanie tokenow z globalnego
pliku wejciowego yyin (ktory domylnie wskazuje na stdin). Wczytywanie
trwa a do osignicia koca pliku, lub a do napotkania w ktorej z akcji
instrukcji return.
Jeli skaner osiga koniec pliku, to kolejne wywolania s niezdefiniowane.
Sposobem na skorygowanie tego jest przekierowanie yyin na nowy plik
wejciowy (w tym wypadku skanowanie nastpuje z nowego pliku) lub
wywolanie yyrestart(). yyrestart() pobiera jeden argument: wskanik
FILE * (ktory moe by nil, jeli ustawile YY_INPUT na skanowanie ze rodla
innego ni yyin), i inicjalizuje yyin na pocztek tego pliku. W zasadzie
nie ma ronicy midzy zwyklym przypisaniem yyin do nowego pliku i uyciem
yyrestart(); Procedura ta jest dostpna z uwagi na kompatybilno z
poprzednimi wersjami flex, a take dlatego, e moe by uywana do
przelczania plikow wejciowych w rodku skanowania. Moe by te uywana do
porzucania biecego bufora wejciowego poprzez wywolanie z argumentem
yyin; lepszym rozwizaniem jest jednak uycie YY_FLUSH_BUFFER (patrz
wyej). Zauwa, e yyrestart() nie resetuje warunku pocztkowego na
INITIAL (zobacz niej Warunki Pocztkowe).
Jeli yylex() koczy skanowanie z powodu wywolania instrukcji return w
jednej z akcji, skaner moe by wolany ponownie i wznowi dzialanie tam,
gdzie skoczyl.
Domylnie (i dla celow wydajnoci) skaner zamiast pojedynczych getc()
wykonuje odczyty blokowe z yyin. Sposob pobierania wejcia moe by
kontrolowany przez definiowanie makra YY_INPUT. Sekwencja wywolujca
YY_INPUT to "YY_INPUT(buf,wynik,max_rozmiar)". Jej wynikiem jest
umieszczenie co najwyej max_rozmiar znakow w tablicy znakowej buf i
zwrocenie w zmiennej calkowitej wynik albo liczby wczytanych znakow
albo stalej YY_NULL (0 w systemach uniksowych), okrelajcej EOF.
Domylnie, YY_INPUT czyta z globalnego wskanika "yyin".
Przykladowa definicja YY_INPUT (w sekcji definicji pliku wejciowego):
%{
#define YY_INPUT(buf,wynik,max_rozmiar) \
{ \
int c = getchar(); \
wynik = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
}
%}
Definicja ta zmieni przetwarzanie wejcia tak, by naraz pojawial si
tylko jeden znak.
W momencie, gdy skaner uzyska od YY_INPUT warunek koca pliku, to wola
funkcj yywrap(). Jeli yywrap() zwroci zero, to zaklada, e funkcja
poszla dalej i skonfigurowala yyin do wskazywania na nowy plik, a
skanowanie trwa dalej. Jeli zwroci warto niezerow, skaner koczy
dzialanie, zwracajc 0 do funkcji wywolujcej. Zauwa, e w kadym
przypadku warunek pocztkowy pozostaje niezmieniony; nie przechodzi on w
INITIAL.
Jeli nie chcesz podawa wlasnej wersji yywrap(), to musisz albo uy opcji
%option noyywrap (wtedy skaner zachowuje si, jakby yywrap() zwracalo
1), albo konsolidowa z -lfl, uzyskujc tak domyln wersj funkcji, zawsze
zwracajcej 1.
Do skanowania z buforow pamiciowych (a nie z plikow) przeznaczone s
trzy procedury: yy_scan_string(), yy_scan_bytes() oraz
yy_scan_buffer(). Zobacz niej dyskusj w sekcji Wielokrotne Bufory
Wejciowe.
Swoje wyjcie ECHO skaner zapisuje do globalnego strumienia yyout
(domylnie stdout), ktory mona przedefiniowa dziki zwyklemu przypisaniu
tej zmiennej do innego wskanika FILE.
WARUNKI POCZTKOWE
flex daje mechanizm warunkowej aktywacji regul. Reguly rozpoczynajce si
od "<sc>" wlcz si tylko jeli skaner znajduje si w warunku pocztkowym
"sc". Na przyklad,
<STRING>[^"]* { /* zjedz cialo lacucha ... */
...
}
bdzie aktywne tylko jeli skaner jest w warunku pocztkowym "STRING", a
<INITIAL,STRING,QUOTE>\. { /* obslu cytowanie ... */
...
}
bdzie aktywne tylko jeli obecnym warunkiem pocztkowym jest albo
"INITIAL", albo "STRING" albo "QUOTE".
Warunki pocztkowe s deklarowane w sekcji definicji wejcia przy uyciu
niewcitych linii, zaczynajcych si od %s lub %x, za ktorymi nastpuje
lista nazw. Pierwsza posta deklaruje w/lczajce warunki pocztkowe, a
druga wykluczajce. Warunek pocztkowy wlcza si przy uyciu akcji BEGIN.
Reguly uywajce danego warunku pocztkowego bd aktywne a do wywolania
nastpnej akcji BEGIN. Jeli warunek pocztkowy jest w/lczajcy , to reguly
bez warunkow pocztkowych bd rownie aktywne. Jeli jest wykluczajcy, to
wykonywane bd tylko reguly odpowiadajce warunkowi pocztkowemu. Zestaw
regul opierajcych si na tym samym wykluczajcym warunku pocztkowym,
opisuje skaner, ktory jest niezaleny od wszelkich innych regul wejcia
fleksa. Z uwagi na to, warunki wykluczajce ulatwiaj tworzenie "mini-
skanerow", ktore skanuj czci wejcia, odmienne syntaktycznie od reszty
(np. komentarze).
W rozronieniu warunkow wlczajcych i wykluczajcych istnieje wci pewna
niejasno: oto przyklad, ilustrujcy ich powizanie. Zestaw regul:
%s przyklad
%%
<przyklad>foo rob_cos();
bar cos_innego();
jest rownowany
%x przyklad
%%
<przyklad>foo rob_cos();
<INITIAL,przyklad>bar cos_innego();
Bez uycia kwalifikatora <INITIAL,przyklad>, wzorzec bar w drugim
przykladzie nie bylby aktywny (tj. nie dopasowalby si) w warunku
pocztkowym przyklad. Jeli uylibymy do kwalifikowania bar tylko
<przyklad>, to byloby aktywny tylko w warunku pocztkowym przyklad, ale
nie w INITIAL, podczas gdy w pierwszym przykladzie jest aktywny w
obydwu, gdy warunek pocztkowy przyklad jest w nim w/lczajcy (%s).
Zauwa te, e specjalny specyfikator <*> pasuje do dowolnego warunku
pocztkowego. Tak wic, powysze mona zapisa rownie nastpujco:
%x przyklad
%%
<przyklad>foo rob_cos();
<*>bar cos_innego();
Regula domylna (wykonywania ECHO na kadym niedopasowanym znaku)
pozostaje aktywna w warunkach pocztkowych. Jest to w sumie rownowane:
<*>.|\n ECHO;
BEGIN(0) zwraca do stanu oryginalnego, w ktorym aktywne s tylko reguly
bez warunku pocztkowego. Stan ten jest oznaczany jako warunek pocztkowy
"INITIAL", wic mona go ustawi rownie poprzez BEGIN(INITIAL). (Nawiasy
wokol nazwy warunku pocztkowego nie s wymagane, lecz s w dobrym tonie.)
Akcje BEGIN mog by podawane jako kod wcity na pocztku sekcji regul. Na
przyklad, nastpujcy kod spowoduje, e skaner wejdzie w warunek pocztkowy
"SPECIAL" za kadym razem, gdy wywolane zostanie yylex() a zmienna
globalna enter_special bdzie ustawiona na prawd:
int enter_special;
%x SPECIAL
%%
if ( enter_special )
BEGIN(SPECIAL);
<SPECIAL>blahblahblah
...i kolejne ruguly...
Dla zilustrowania wykorzystania warunkow pocztkowych, oto skaner, ktory
daje dwie rone interpretacje lacucha "123.456". Domylnie bdzie
traktowal go jako 3 elementy, liczb calkowit 123, kropk i liczb
calkowit "456". Jeli jednak lacuch zostanie poprzedzony lini z napisem
"expect-floats", to bdzie go traktowal jako pojedynczy element
zmiennoprzecinkowy (123.456).
%{
#include <math.h>
%}
%s expect
%%
expect-floats BEGIN(expect);
<expect>[0-9]+"."[0-9]+ {
printf( "znalazlem zmiennoprzecinkow, = %f\n",
atof( yytext ) );
}
<expect>\n {
/* jest to koniec linii, wic
* potrzebujemy kolejnego "expect-number"
* przed rozpoznawaniem dalszych liczb
*/
BEGIN(INITIAL);
}
[0-9]+ {
printf( "znalazlem calkowit, = %d\n",
atoi( yytext ) );
}
"." printf( "znalazlem kropk\n" );
Oto skaner, ktory rozpoznaje komentarze C podczas zliczania linii.
%x comment
%%
int line_num = 1;
"/*" BEGIN(comment);
<comment>[^*\n]* /* zjedz wszystko, co nie jest '*' */
<comment>"*"+[^*/\n]* /* zjedz '*'-ki, po ktorych nie ma '/' */
<comment>\n ++line_num;
<comment>"*"+"/" BEGIN(INITIAL);
Skaner ten moe mie problemy z dopasowaniem maksymalnej iloci tekstu w
kadej z regul. Ogolnie, przy pisaniu szybkich skanerow, probuj
dopasowywa w kadej regule tyle, ile si da.
Zauwa, e nazwy warunkow pocztkowych s tak naprawd wartociami
calkowitymi i mog by tak przechowywane. Tak wic powysze mona rozwin w
nastpujcym stylu:
%x comment foo
%%
int line_num = 1;
int comment_caller;
"/*" {
comment_caller = INITIAL;
BEGIN(comment);
}
...
<foo>"/*" {
comment_caller = foo;
BEGIN(comment);
}
<comment>[^*\n]* /* zjedz wszystko co nie jest '*' */
<comment>"*"+[^*/\n]* /* zjedz '*', po ktorych nie ma '/' */
<comment>\n ++line_num;
<comment>"*"+"/" BEGIN(comment_caller);
Co wicej, moesz mie dostp do biecego warunku pocztkowego poprzez makro
YY_START (o wartoci calkowitej). Na przyklad, powysze przypisania do
comment_caller mona by zapisa jako
comment_caller = YY_START;
Flex jako alias do YY_START daje YYSTATE (gdy jest to nazwa, uywana
przez AT&T lex).
Zauwa, e warunki pocztkowe nie maj wlasnej przestrzeni nazw; %s i %x-y
deklaruj nazwy podobnie jak #define.
Na deser, oto przyklad dopasowywania cytowanych w stylu C napisow przy
uyciu wykluczajcych warunkow pocztkowych, wlcznie z rozwijanymi
sekwencjami specjalnymi (lecz bez sprawdzania czy lacuch nie jest za
dlugi):
%x str
%%
char string_buf[MAX_STR_CONST];
char *string_buf_ptr;
\" string_buf_ptr = string_buf; BEGIN(str);
<str>\" { /* zobaczylem zamykajcy cytat - gotowe */
BEGIN(INITIAL);
*string_buf_ptr = '\0';
/* zwro typ i warto tokenu stalej lacuchowej do
* analizatora
*/
}
<str>\n {
/* bld - niezakoczona stala lacuchowa */
/* generuj komunikat o bldzie */
}
<str>\\[0-7]{1,3} {
/* osemkowa sekwencja specjalna */
int result;
(void) sscanf( yytext + 1, "%o", &result );
if ( result > 0xff )
/* bld, stala poza zakresem */
*string_buf_ptr++ = result;
}
<str>\\[0-9]+ {
/* generuj bld - zla sekwencja specjalna; co jak
* '\48' lub '\0777777'
*/
}
<str>\\n *string_buf_ptr++ = '\n';
<str>\\t *string_buf_ptr++ = '\t';
<str>\\r *string_buf_ptr++ = '\r';
<str>\\b *string_buf_ptr++ = '\b';
<str>\\f *string_buf_ptr++ = '\f';
<str>\\(.|\n) *string_buf_ptr++ = yytext[1];
<str>[^\\\n\"]+ {
char *yptr = yytext;
while ( *yptr )
*string_buf_ptr++ = *yptr++;
}
Czsto, np. w niektorych przykladach powyej mona skoczy piszc grup
regul, rozpoczynajcych si od tych samych warunkow pocztkowych. Flex
ulatwia calo wprowadzajc pojcie zakresu warunku pocztkowego. Zakres
rozpoczyna si od:
<SCs>{
gdzie SCs jest list jednego lub wicej warunkow pocztkowych. Wewntrz
zakresu warunku pocztkowego kada regula dostaje automatycznie
przedrostek <SCs> a do napotkania '}', ktory odpowiada startowemu '{'.
W ten sposob na przyklad
<ESC>{
"\\n" return '\n';
"\\r" return '\r';
"\\f" return '\f';
"\\0" return '\0';
}
jest rownowane:
<ESC>"\\n" return '\n';
<ESC>"\\r" return '\r';
<ESC>"\\f" return '\f';
<ESC>"\\0" return '\0';
Zakresy warunkow pocztkowych mog by zagniedane.
Do obslugi stosow warunkow pocztkowych s przeznaczone trzy procedury:
void yy_push_state(int new_state)
wrzuca biecy warunek pocztkowy na stos warunkow pocztkowych i
przelcza si w stan new_state, zupelnie jak po uyciu BEGIN
new_state (pamitaj, e nazwy warunkow pocztkowych s rownie
liczbami calkowitymi).
void yy_pop_state()
zdejmuje warto ze stosu i przelcza si na ni przez BEGIN.
int yy_top_state()
zwraca wierzcholek stosu bez zmiany zawartoci stosu.
Stos warunkow pocztkowych ronie dynamicznie i nie ma adnych wbudowanych
ogranicze. Po wyczerpaniu pamici, wykonywanie programu jest przerywane.
Aby korzysta ze stosow warunkow pocztkowych, skaner musi zawiera
dyrektyw %option stack (zobacz niej rozdzial Opcje).
WIELOKROTNE BUFORY WEJCIOWE
Niektore skanery (te, obslugujce pliki dolczane "include") wymagaj
odczytu z wielu strumieni wejciowych. Poniewa skanery flex wykonuj
sporo buforowania, nie mona jednoznacznie zdecydowa skd bdzie
wykonywany nastpny odczyt przez proste napisanie YY_INPUT, ktore jest
wraliwe na kontekst skanowania. YY_INPUT wywolywane jest tylko gdy
skaner osiga koniec swojego bufora, ktory moe by daleko po wyskanowaniu
instrukcji takiej jak "include", wymagajcej przelczenia rodla wejcia.
Aby zalatwi niektore z tych problemow, flex daje mechanizm tworzenia i
przelczania midzy wielokrotnymi buforami wejciowymi. Bufor wejciowy
jest tworzony z uyciem funkcji
YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
ktora pobiera wskanik FILE i rozmiar size, a nastpnie tworzy bufor
zwizany z danym plikiem, ktorego wielko (w znakach) jest okrelona
parametrem rozmiaru. (w razie wtpliwoci uyj YY_BUF_SIZE jako
rozmiaru). Funkcja zwraca uchwyt YY_BUFFER_STATE, ktory moe by potem
przekazywany do innych procedur (zobacz niej). Typ YY_BUFFER_STATE jest
wskanikiem do struktury struct yy_buffer_state wic mona bezpiecznie
inicjalizowa zmienne YY_BUFFER_STATE na ((YY_BUFFER_STATE) 0) i odnosi
si do struktury w celu poprawnego zadeklarowania buforow wejciowych w
plikach rodlowych innych ni ten od twojego skanera. Zauwa, e wskanik
FILE w wywolaniu yy_create_buffer jest uywany tylko jako warto yyin
widzianego przez YY_INPUT; jeli redefiniujesz YY_INPUT tak, eby nie
uywalo yyin, to moesz spokojnie przekaza tu zerowy wskanik FILE.
Zadany bufor do skanowania wybiera si za pomoc:
void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
co przelcza bufor wejciowy skanera tak, e kolejne tokeny bd pochodzily
z bufora new_buffer. Zauwa, e yy_switch_to_buffer() moe by uywane
przez yywrap() do zestawiania ronych rzeczy we wznowionym skanowaniu
zamiast otwierania nowego pliku i ustawiania na nim yyin. Zauwa te, e
przelczanie rodel wejciowych przez yy_switch_to_buffer() lub yywrap()
nie zmienia warunku pocztkowego.
void yy_delete_buffer( YY_BUFFER_STATE buffer )
uywane jest do odzyskania miejsca zwizanego z buforem ( buffer moe by
wartoci nil, ale wtedy funkcja ta nic nie robi.) Mona te czyci biec
zawarto bufora, stosujc:
void yy_flush_buffer( YY_BUFFER_STATE buffer )
Funkcja ta niszczy zawarto bufora, wic przy nastpnej probie dopasowania
tokenu z bufora, skaner najpierw wypelni bufor na nowo uywajc YY_INPUT.
yy_new_buffer() jest synonimem yy_create_buffer(), udostpnionym dla
zgodnoci z C++ narzdziami new i delete, slucymi do tworzenia i
niszczenia obiektow dynamicznych.
Na koniec makro YY_CURRENT_BUFFER zwraca uchwyt YY_BUFFER_STATE do
biecego bufora.
A oto przyklad uywania tych wlaciwoci w skanerze, rozwijajcym pliki
zalczane (wlaciwo <<EOF>> jest opisywana niej):
/* stan "incl" jest uywany do wybierania nazwy zalczanego pliku
*/
%x incl
%{
#define MAX_INCLUDE_DEPTH 10
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
int include_stack_ptr = 0;
%}
%%
include BEGIN(incl);
[a-z]+ ECHO;
[^a-z\n]*\n? ECHO;
<incl>[ \t]* /* zjedz bial spacj */
<incl>[^ \t\n]+ { /* mam nazw pliku zalcznika */
if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
{
fprintf( stderr, "Zbyt zagniedone zalczniki" );
exit( 1 );
}
include_stack[include_stack_ptr++] =
YY_CURRENT_BUFFER;
yyin = fopen( yytext, "r" );
if ( ! yyin )
error( ... );
yy_switch_to_buffer(
yy_create_buffer( yyin, YY_BUF_SIZE ) );
BEGIN(INITIAL);
}
<<EOF>> {
if ( --include_stack_ptr < 0 )
{
yyterminate();
}
else
{
yy_delete_buffer( YY_CURRENT_BUFFER );
yy_switch_to_buffer(
include_stack[include_stack_ptr] );
}
}
Do zestawiania buforow wejciowych dla skanowania lacuchow z pamici
zamiast plikow istniej trzy procedury. Kada z nich tworzy nowy bufor
wejciowy do skanowania lacucha i zwraca odpowiadajcy uchwyt
YY_BUFFER_STATE (ktory powiniene skasowa stosujc yy_delete_buffer() po
zakoczeniu dzialania). Przelczaj one te przetwarzanie na nowy bufor
przy uyciu yy_switch_to_buffer(), wic nastpne wywolanie yylex()
rozpocznie skanowanie lacucha.
yy_scan_string(const char *str)
skanuje lacuch zakoczony zerem.
yy_scan_bytes(const char *bytes, int len)
skanuje len bajtow (dopuszczalne zera w rodku) poczwszy od
pozycji bytes.
Zauwa, e obydwie funkcje tworz i skanuj kopie oryginalnych danych.
(Jest to podane, gdy yylex() modyfikuje zawarto skanowanego bufora.)
Kopiowania mona unikn, stosujc:
yy_scan_buffer(char *base, yy_size_t size)
ktore skanuje bufor na miejscu, zaczynajc od base, a w dlugoci
size bajtow, z ktorych dwa bajty musz by znakami
YY_END_OF_BUFFER_CHAR (ASCII NUL). Ostatnie dwa bajty nie s
skanowane; tak wic skanowanie przebiega od base[0] do
base[size-2] wlcznie.
Jeli nie ustawisz odpowiednio base to yy_scan_buffer() zwraca
wskanik nil zamiast tworzy nowy bufor wejciowy.
Typ yy_size_t jest typem calkowitym, na ktory rzutuje si
wyraenie calkowite, okrelajce rozmiar bufora.
REGU/LY END-OF-FILE
Specjalna regula "<<EOF>>" okrela akcje, ktore naley wykona po
osigniciu koca pliku i gdy yywrap() zwraca zero (tj. wskazuje brak
dalszych plikow do przetworzenia). Akcja musi si zakoczy zrobieniem
jednej z czterech rzeczy:
- przypisaniem yyin do nowego pliku wejciowego (w poprzednich
wersjach fleksa po dokonaniu przypisania nalealo wywola specjaln
akcj YY_NEW_FILE; nie jest to ju wymagane);
- wywolaniem instrukcji return;
- wywolaniem specjalnej akcji yyterminate();
- przelczeniem na nowy bufor za pomoc yy_switch_to_buffer().
Reguly <<EOF>> nie mog by uywane z innymi wzorcami; mog one by
kwalifikowane jedynie list warunkow pocztkowych. Jeli podana jest
niekwalifikowana regula <<EOF>>, to dotyczy ona wszystkich warunkow
pocztkowych, ktore nie maj jeszcze akcji <<EOF>>. Aby poda regul
<<EOF>> tylko dla pocztkowego warunku pocztkowego uyj
<INITIAL><<EOF>>
Te reguly przydatne s do lapania rzeczy takich, jak niezamknite cytaty.
Przyklad:
%x quote
%%
...inne reguly cytatowe...
<quote><<EOF>> {
error( "nie zamknity cytat" );
yyterminate();
}
<<EOF>> {
if ( *++filelist )
yyin = fopen( *filelist, "r" );
else
yyterminate();
}
R'ONE MAKRA
Mona zdefiniowa makro YY_USER_ACTION, ktore sluy do podania akcji
wykonywanej zawsze przed akcj dopasowanej reguly. Na przyklad moe by
#definiowane do wywolywania procedury konwertujcej yytext na male
litery. Gdy wywolywane jest YY_USER_ACTION, zmienna yy_act okrela
numer dopasowanej reguly (reguly s numerowane od 1). Zalomy, e chcesz
wyprofilowa jak czsto jest uywana kada z regul. Rozwizaniem jest
nastpujcy kawalek kodu:
#define YY_USER_ACTION ++ctr[yy_act]
gdzie ctr jest tablic przechowujc zawarto ronych regul. Zauwa, e makro
YY_NUM_RULES daje ogoln liczb regul (lcznie z regul domyln, nawet jeli
uywasz -s), wic poprawn deklaracj ctr jest:
int ctr[YY_NUM_RULES];
Makro YY_USER_INIT sluy do podania akcji, ktora bdzie wykonywana zawsze
przed pierwszym skanem (i przed wewntrznymi inicjalizacjami skanera).
Na przyklad mona to wykorzysta do wolania procedury czytajcej tablice
danych lub otwierajcej plik raportowy.
Makro yy_set_interactive(is_interactive) moe by uywane do sterowania
czy biecy bufor jest uwaany za interaktywny. Bufor interaktywny jest
przetwarzany wolniej, lecz musi by uywany gdy wejcie rzeczywicie jest
interaktywne. Zapobiega to problemom zwizanym z oczekiwaniem na
wypelnienie buforow (zobacz niej dyskusj flagi -I). Warto niezerowa w
wywolaniu makra zaznacza bufor jako interaktywny, a zero to wylcza.
Zauwa, e uycie tego makra przeslania %option always-interactiv lub
%option never-interactive (zobacz niej Opcje). Przed rozpoczciem
skanowania bufora, ktory jest (lub nie jest) interaktywny, naley wywola
funkcj yy_set_interactive().
Makro yy_set_bol(at_bol) moe by wykorzystywane do sterowania czy biecy
kontekst skanujcy bufora dla nastpnego dopasowania tokena jest
dokonywany jak gdyby od pocztku linii. Niezerowa warto argumentu
powoduje, e reguly zakotwiczone w '^' staj si aktywne, a warto zerowa
je dezaktywuje.
Makro YY_AT_BOL() zwraca prawd jeli nastpny token skanowany z biecego
bufora bdzie mial aktywne reguly '^'. W przeciwnym wypadku zwraca
falsz.
W niektorych generowanych skanerach akcje s zebrane wszystkie w jedn
wielk instrukcj switch i s rozdzielone makrem YY_BREAK, ktore mona
redefiniowa. Domylnie jest to po prostu "break". Redefiniowanie
YY_BREAK umoliwia uytkownikom C++ zadeklarowanie, by makro nie robilo
niczego (uwaajc przy tym szczegolnie, by kada regula koczyla si
instrukcj "break" lub "return"!). Mona tak zapobiec cierpieniom
spowodowanym ostrzeeniami o tym, e przez zakoczenie akcji reguly
instrukcj return, YY_BREAK jest nieosigalne.
WARTOCI DOSTPNE DLA UYTKOWNIKA
Sekcja ta zestawia rone wartoci dostpne dla uytkownika w akcjach
regulowych.
- char *yytext zawiera biecy tekst tokenu. Moe by modyfikowany,
lecz nie moe by wydluany (nie mona dokleja dodatkowych znakow na
kocu).
Jeli w pierwszej sekcji opisu skanera pojawi si dyrektywa
specjalna %array to yytext zostanie zadeklarowane jako
charyytext[YYLMAX], gdzie YYLMAX jest makrodefinicj, ktor mona
przedefiniowa w pierwszej sekcji (warto domylna to ogolnie 8KB).
Uywanie %array daje wolniejsze skanery, lecz warto yytext staje
si odporna na wywolania input() i unput(), ktore potencjalnie
niszcz jego warto kiedy yytext jest wskanikiem znakowym.
Przeciwn dyrektyw do %array jest %pointer, ktora jest dyrektyw
domyln.
Dyrektywy %array nie mona uywa do generowania klas skanera C++
(flaga -+).
- int yyleng przechowuje dlugo biecego tokenu.
- FILE *yyin jest plikiem, z ktorego flex domylnie odczytuje
wejcie. Moe by redefiniowany, lecz taki zabieg ma sens tylko nim
rozpocznie si skanowanie lub po napotkaniu EOF. Zmienianie tej
wartoci w rodku skanowania moe da nieoczekiwane rezultaty
spowodowane buforowaniem wejcia. Zamiast tego uyj wtedy
yyrestart(). Po zakoczeniu skanowania przez napotkanie koca
pliku, mona przypisa warto yyin do nowego pliku wejciowego i
wywola ponownie skaner by dokoczyl skanowanie.
- void yyrestart( FILE *new_file ) moe by wolane do wskazywania
yyin na nowy plik wejciowy. Przelczenie na nowy plik jest
natychmiastowe (wszelkie poprzednio buforowane wejcie jest
tracone). Zauwa, e wolanie yyrestart() z argumentem yyin porzuca
biecy bufor wejciowy i kontynuuje skanowanie tego samego pliku
wejciowego.
- FILE *yyout jest plikiem, do ktorego kierowane jest wyjcie akcji
ECHO. Uytkownik moe mu przypisa inn warto.
- YY_CURRENT_BUFFER zwraca uchwyt YY_BUFFER_STATE do biecego
bufora.
- YY_START zwraca warto calkowit, odpowiadajc biecemu warunkowi
pocztkowemu. Wartoci tej mona uywa dalej z BEGIN do powrotu do
tego warunku.
/LCZENIE Z YACC
Jednym z podstawowych zastosowa fleksa jest wspoltowarzyszenie
generatorowi analizatorow yacc. Analizatory skladni yacc oczekuj
wywolania procedury o nazwie yylex() celem znalezienia kolejnego tokenu
wejciowego. Procedura powinna zwroci typ nastpnego tokenu oraz wstawi
zwizan z nim warto do globalnej zmiennej yylval. Aby uywa fleksa z
yaccem, naley yaccowi przekaza opcj -d, co kae mu generowa plik
y.tab.h zawierajcy definicje wszystkich %token'ow(%tokens) pojawiajcych
si w wejciu yacc. Plik ten jest nastpnie zalczany do skanera
fleksowego. Na przyklad jeli jednym z tokenow jest "TOK_NUMBER", to cz
skanera moe wyglda tak:
%{
#include "y.tab.h"
%}
%%
[0-9]+ yylval = atoi( yytext ); return TOK_NUMBER;
OPCJE
flex ma nastpujce opcje:
-b Generuje informacje zapasowe do lex.backup. Oto lista stanow
skanera, ktore wymagaj kopii zapasowych oraz znaki wejciowe dla
ktorych to zachodzi. Dodajc reguly mona usun stany zapasowe.
Jeli wyeliminowane zostan wszystkie stany zapasowe, a uyte bdzie
-Cf lub -CF, wygenerowany skaner bdzie dzialal szybciej (zobacz
flag -p). Opcj to powinni si martwi jedynie uytkownicy
wyciskajcy ostatnie poty ze swoich skanerow. (Zobacz sekcj o
Rozwaaniach nad Wydajnoci.)
-c nieuywana i niezalecana opcja dla zgodnoci z POSIX-em.
-d powoduje, e generowany skaner dziala w trybie debug. Za kadym
razem po rozpoznaniu wzorca, gdy globalna zmienna yy_flex_debug
jest niezerowa (co jest domylne), skaner zapisze na stderr lini
w postaci:
--accepting rule at line 53 ("dopasowany tekst")
Numer linii odnosi si do poloenia reguly w pliku definiujcym
skaner (tj. w pliku, potraktowanym fleksem). Komunikaty s
rownie generowane gdy skaner robi kopie zapasowe, przyjmuje
domyln regul, dochodzi do koca bufora (lub napotyka NUL; w tym
momencie obydwa [zdarzenia] wygldaj jednakowo z punktu widzenia
skanera) lub osiga koniec pliku.
-f okrela szybki skaner. Nie dokonywana jest kompresja tabel i
pomijane jest stdio. W efekcie kod jest duy, lecz szybki. Opcja
ta jest rownowana -Cfr (zobacz niej).
-h generuje zestawienie "pomocy" opcji fleksa na stdout i koczy
dzialanie. -? i --help s rownowanikami -h.
-i nakazuje fleksowi generowania skanera niewraliwego na wielko
znakow. Wielko liter we wzorcach zostanie zignorowany, a tokeny
wejcia bd dopasowywane niezalenie od wielkoci. Dopasowany tekst
znajdujcy si w yytext bdzie mial zachowan oryginaln wielko
liter.
-l wlcza maksymaln zgodno z oryginaln implementacj leksa z AT&T.
Zauwa, e nie oznacza to pelnej zgodnoci. Uycie tej opcji
kosztuje sporo wydajnoci i eliminuje z uycia opcje -+,-f,-F,-Cf
lub -CF. Dla szczegolow o zapewnianej zgodnoci, zobacz niej
sekcj o niezgodnociach midzy Leksem i POSIX-em. Opcja ta
powoduje te z#definiowanie nazwy YY_FLEX_LEX_COMPAT w
generowanym skanerze.
-n kolejna ignorowana opcja dodana dla zgodnoci z POSIX-em.
-p generuje raport o wydajnoci na stderr. Raport sklada si z
komentarzy o wlaciwociach pliku wejciowego fleksa, wic powoduje
znaczn utrat wydajnoci skanera. Jeli podasz t flag dwukrotnie,
uzyskasz te komentarze o wlaciwociach, ktore doprowadzily do
drugorzdnych utrat wydajnoci.
Zauwa, e uycie REJECT, %option yylineno, i zmiennego wiszcego
kontekstu (variable trailing context) (zobacz niej sekcj o
Niedostatkach / Bldach) powoduje znaczn utrat wydajnoci; uywanie
yymore(), operatora ^ i flagi -I powoduje pomniejsze utraty
wydajnoci.
-s powoduje, e domylna regula (powodujca echo niedopasowanego
wejcia skanera na stdout) nie jest wykonywana. Jeli skaner
napotka wejcie, ktorego nie moe dopasowa do regul, przerywa
dzialanie z bldem. Opcja ta jest przydatna do znajdowania dziur
w zbiorze regul skanera.
-t nakazuje fleksowi zapisanie wygenerowanego skanera na
standardowe wyjcie zamiast do pliku lex.yy.c.
-v nakazuje fleksowi pisanie na stderr zestawienia statystyk
dotyczcych generowanego skanera. Wikszo statystyk jest
pozbawiona znaczenia dla typowego uytkownika, lecz pierwsza z
linijek wskazuje wersj fleksa (to samo co zglasza opcja -V), a
nastpna linia flagi uyte do generowania skanera, z domylnymi
wlcznie.
-w powstrzymuje komunikaty o ostrzeeniach.
-B nakazuje fleksowi generowanie skanera wsadowego, czyli odwrotno
skanerow interaktywnych, generowanych przez -I (zobacz niej).
Ogolnie, opcji -B uywa si majc pewno, e skaner nigdy nie bdzie
uywany interaktywnie i chcc wycisn jeszcze troszeczk wicej
wydajnoci. Jeli chcesz zyska wicej wydajnoci, powiniene uy opcji
-Cf lub -CF (opisanych niej), ktore wlczaj -B i tak
automatycznie.
-F mowi, e naley uy reprezentacji tablicy szybkiego skanera (i
stdio ma by pominite). Reprezentacja ta jest mniej wicej tak
szybka jak reprezentacja pelnej tablicy (-f), i dla niektorych
zestawow wzorcow bdzie znacznie mniejsza (a dla innych wiksza).
Ogolnie, jeli wzorzec zawiera zarowno "slowa kluczowe" jak i
lapic-wszystko regul "identyfikatora", tak jak poniszy zestaw:
"case" return TOK_CASE;
"switch" return TOK_SWITCH;
...
"default" return TOK_DEFAULT;
[a-z]+ return TOK_ID;
to lepiej uy reprezentacji pelnej tablicy. Jeli obecna jest
tylko regula "identyfikatora" i uywasz potem hasza lub podobnej
rzeczy do wykrywania slow kluczowych, to lepiej uy opcji -F.
Opcja ta odpowiada -CFr (zobacz niej). Nie mona jej uywa z -+.
-I nakazuje fleksowi generowanie skanera interaktywnego. Skaner
interaktywny patrzy naprzod do wyboru dopasowania jedynie jeli
musi. Okazuje si, e patrzenie o jeden dodatkowy znak dalej,
nawet jeli skaner ma ju do do dopasowania tokenu jest troch
szybsze ni wersja minimalna. Lecz skanery patrzce naprzod daj
dziadowsk wydajno interaktywn; na przyklad gdy uytkownik wpisze
now lini, to nie jest ona rozpoznawana jako token nowej linii
dopoki nie wprowadzony zostanie nastpny token, co oznacza czsto
wpisanie calej kolejnej linii.
Skanery fleksa s domylnie interaktywne, chyba e uyjesz opcji
kompresji tablicy -Cf lub -CF (zobacz niej). Jest tak dlatego,
e jeli oczekujesz wysokiej wydajnoci, to powiniene uy jednej z
tych opcji, a jeli tego nie zrobile, flex zaklada, e jeste gotow
powici troch wydajnoci na rzecz intuicyjnego zachowania
interaktywnego. Zauwa te, e nie moesz uy -I w polczeniu z -Cf
lub -CF. Z tej przyczyny opcja ta nie jest w rzeczywistoci
wymagana; jest domylnie wlczona dla tych przypadkow, dla ktorych
jest dopuszczalna.
Opcj -B moesz wymusi by skaner nie byl interaktywny (zobacz
powyej).
-L nakazuje fleksowi nie generowa dyrektyw #line. Bez tej opcji
flex przyprawia generowany skaner dyrektywami #line, wic
komunikaty o bldach w akcjach bd poprawnie poloone wzgldem
oryginalnego pliku wejciowego fleksa (jeli bldy wynikaj z kodu w
pliku wejciowym) lub [wzgldem] lex.yy.c (jeli bldy s win fleksa
-- powiniene zglosi takie bldy pod adres e-mail podany poniej.)
-T powoduje, e flex dziala w trybie ledzenia. Bdzie generowal na
stderr wiele komunikatow o postaci wejcia i wynikajcych ze
niedeterministycznych i deterministycznych automatach
skoczonych. Opcja ta jest uywana zwykle w opiece nad fleksem.
-V drukuje numer wersji na stdout i koczy dzialanie. --version
jest synonimem -V.
-7 nakazuje fleksowi generowanie skanera 7-bitowego, tj. takiego
ktory moe rozpoznawa w swoim wejciu tylko znaki 7-bitowe. Zalet
uywania -7 jest to, e tablice skanera bd o polow mniejsze ni
wygenerowane opcj -8 (zobacz niej). Wad jest to, e skanery takie
czsto si zawieszaj lub zalamuj jeli na ich wejciu znajdzie si
znak 8-bitowy.
Zauwa jednak, e jeli generujesz skaner z uyciem opcji kompresji
tablic -Cf lub -CF, to uycie -7 zachowa jedynie niewielki
rozmiar przestrzeni tablic, a spowoduje, e skaner bdzie znaczco
mniej przenony. Domylnym zachowaniem fleksa jest generowanie
skanerow 8-bitowych, chyba e uyto opcji -Cf lub -CF, i wtedy
flex generuje domylnie skaner 7-bitowy, chyba e twoja maszyna
zawsze byla skonfigurowana na generowanie skanerow 8-bitowych
(co czsto si zdarza poza USA). To, czy flex wygenerowal skaner 7
czy 8 bitowy, mona okreli, sprawdzajc zestawienie flag w wyjciu
-v, co opisano wyej.
Zauwa, e jeli uywasz -Cfe lub -CFe, flex wci domylnie generuje
skaner 8-bitowy, gdy po kompresji pelne tablice 8-bitowe nie s
wiele wiksze od 7-bitowych.
-8 nakazuje fleksowi generowanie skanera 8-bitowego, tj. takiego,
ktory rozpoznaje znaki 8-bitowe. Flaga ta jest wymagana jedynie
dla skanerow wygenerowanych z uyciem -Cf lub -CF, gdy w innych
wypadkach jest ona przyjmowana jako domylna.
-+ okrela, e chcesz by fleks wygenerowal klas skanera w C++. Zobacz
sekcj o generowaniu skanerow C++.
-C[aefFmr]
steruje poziomem kompresji tablic, balansujc midzy malymi a
szybkimi skanerami.
-Ca ("wyrownaj") nakazuje fleksowi powici rozmiar tablic w
wygenerowanych skanerach na rzecz szybkoci, gdy elementy tablic
mog by lepiej wyrownane pod ktem dostpu do pamici i oblicze. Na
niektorych architekturach RISC pobieranie i operowanie na
dlugich slowach jest efektywniejsze ni na mniejszych
jednostkach, takich jak krotkie slowa. Opcja ta moe podwoi
rozmiar tablic uywanych przez twoj skaner.
-Ce Nakazuje fleksowi budowanie klas r'ownowanoci, tj. zestawow
znakow o identycznych wlaciwociach leksykalnych (np. jeli
jedynym wystpieniem cyfr w pliku wejciowym fleksa jest klasa
znakow "[0-9]", to cyfry z przedzialy od 0 do 9 zostan wstawione
do tej samej klasy rownowanoci. Klasy takie zwykle znacznie
redukuj ostateczne rozmiary tablic/obiektow (zwykle 2-5 razy) i
s calkiem tanie od strony wydajnociowej (jedno podgldnicie w
tablicy na skanowany znak).
-Cf okrela, e naley generowa pe/lne tablice skanera - flex nie ma
ich kompresowa poprzez branie korzyci z podobnych funkcji przej
dla ronych stanow.
-CF okrela, e naley uy alternatywnej, szybkiej reprezentacji
skanera (opisanej pod flag -F). Opcja ta nie moe by uywana z
-+.
-Cm nakazuje fleksowi budowanie klas meta-r'ownowanoci, ktore s
zbiorami klas rownowanoci (lub znakow, jeli klasy rownowanoci
nie s uywane), ktore s czsto uywane wspolnie. Klasy takie s
czsto dobr rzecz podczas uywania skompresowanych tablic, lecz
maj one ju umiarkowany wplyw na wydajno (dwa lub jeden test "if"
i jedno podgldnicie tablicy na skanowany znak).
-Cr powoduje, e generowany skaner omija uycie standardowej
biblioteki I/O dla wejcia. Zamiast wola fread() lub getc(),
skaner bdzie uywa wywolania systemowego read(), zyskujc tak
troch na wydajnoci (w skali zalenej od systemu). W rzeczywistoci
jest to bez znaczenia, chyba e uywasz te -Cf lub -CF.
Wykorzystanie -Cr moe te spowodowa dziwne zachowanie jeli np.
odczytasz z yyin z pomoc stdio przed wywolaniem skanera (skaner
pominie tekst pozostawiony przez twoje odczyty w buforze
wejciowym stdio).
-Cr nie dziala jeli zdefiniujesz YY_INPUT (zobacz wyej
Generowany Skaner).
Samotne -C okrela, e tablice skanera powinny by kompresowane,
lecz nie naley uywa klas rownowanoci i klas metarownowanoci.
Opcje -Cf lub -CF i -Cm nie maj sensu razem - nie ma sytuacji
dla klas metarownowanoci jeli tablica nie jest kompresowana.
Poza tym opcje mona swobodnie lczy.
Domylnym ustawieniem jest -Cem, ktore okrela, e flex powinien
generowa klasy rownowanoci i metarownowanoci. Ustawienie to daje
najwyszy stopie kompresji tablic. Kosztem wikszych tablic mona
uzyska szybciej wykonujce si skanery. Nastpujce zestawienie jest
mniej wicej prawdziwe:
najwolniejsze i najmniejsze
-Cem
-Cm
-Ce
-C
-C{f,F}e
-C{f,F}
-C{f,F}a
najszybsze i najwiksze
Zauwa, e skanery z najmniejszymi tablicami s zwykle najszybciej
generowane i kompilowane, wic podczas prac rozwojowych
prawdopodobnie najchtniej uyjesz domylnej, maksymalnej
kompresji.
-Cfe jest czsto dobrym kompromisem midzy szybkoci a rozmiarem
dla skanerow gotowych do wdroenia (production scanners).
-ooutput
nakazuje fleksowi zapisanie skanera do pliku output zamiast do
lex.yy.c. Jeli polczysz -o z opcj -t, to skaner jest zapisywany
na stdout, lecz jego dyrektywy #line (zobacz wyej opcj -L),
odnosz si do pliku output.
-Pprefiks
zmienia domylny przedrostek yy uywany przez fleksa dla
wszystkich zmiennych i funkcji globalnych na prefiks. Na
przyklad -Pfoo zmienia nazw yytext na footext. Zmienia to te
nazw domylnego pliku wyjciowego z lex.yy.c na lex.foo.c. A oto
wszystkie nazwy, ktorych dotyczy takie zachowanie:
yy_create_buffer
yy_delete_buffer
yy_flex_debug
yy_init_buffer
yy_flush_buffer
yy_load_buffer_state
yy_switch_to_buffer
yyin
yyleng
yylex
yylineno
yyout
yyrestart
yytext
yywrap
(Jeli uywasz skanera C++, to dotyczy to bdzie tylko yywrap i
yyFlexLexer.) Wewntrz samego skanera mona wci uywa jednej i
drugiej konwencji nazywania; jednak z zewntrz dozwolone s tylko
nazwy zmodyfikowane.
Opcja ta umoliwia latwe lczenie w calo ronych programow fleksa w
jeden plik wykonywalny. Zauwa jednak, e uywanie tej opcji
zmienia te nazw yywrap(), wic musisz teraz albo udostpni wlasn
wersj tej procedury dla swojego skanera, albo uy %option
noyywrap, gdy konsolidacja z -lfl nie daje ju funkcji domylnej.
-Sskeleton_file
przeslania domylny plik szkieletowy, na podstawie ktorego flex
buduje swoje skanery. Nie bdziesz uywa tej opcji, chyba e
zajmujesz si rozwojem fleksa.
flex daje te mechanizm kontrolowania opcji z samej specyfikacji
skanera, zamiast linii polece. Dziala to przez wlczanie dyrektyw
%option w pierwszej sekcji specyfikacji skanera. W jednej dyrektywie
%option mona podawa wiele opcji, a w samej pierwszej sekcji pliku
wejciowego fleksa mona uywa wielu dyrektyw.
Wikszo opcji jest podawana po prostu jako nazwy, poprzedzone
opcjonalnie slowem "no" (bez bialych spacji w rodku), ktore neguje ich
znaczenie. Cz jest rownowana flagom fleksa lub ich negacjom:
7bit -7
8bit -8
align -Ca
backup -b
batch -B
c++ -+
caseful lub
case-sensitive przeciwne do -i (domylne)
case-insensitive lub
caseless -i
debug -d
default przeciwne do -s
ecs -Ce
fast -F
full -f
interactive -I
lex-compat -l
meta-ecs -Cm
perf-report -p
read -Cr
stdout -t
verbose -v
warn przeciwne do -w
(dla -w uyj "%option nowarn")
array rownowane "%array"
pointer rownowane "%pointer" (domylne)
Niektore %opcje daj wlaciwoci niedostpne gdzie indziej:
always-interactive
nakazuje fleksowi generowanie skanera, ktory zawsze uwaa swoje
wejcie za "interaktywne". Normalnie przy kadym pliku wejciowym
skaner wola isatty() do okrelenia czy wejcie skanera jest
interaktywne i powinno by czytane po znaku. Po uyciu tej opcji
wywolanie takie nie jest robione.
main nakazuje fleksowi udostpni domylny program main() dla skanera,
ktory po prostu wola yylex(). Opcja ta implikuje noyywrap
(zobacz niej).
never-interactive
nakazuje fleksowi generowanie skanera, ktory zawsze uwaa swoje
wejcie za "nieinteraktywne" (znow, nie jest wolane isatty()).
Opcja ta jest przeciwna do always-interactive.
stack wlcza uywanie stosow warunkow pocztkowych (zobacz wyej Warunki
Pocztkowe).
stdinit
jeli jest ustawione (np. %option stdinit) to zachodzi
inicjalizacja yyin i yyout na stdin i stdout, zamiast domylnych
nil. Niektore istniejce programy lex zale od tego zachowania,
nawet jeli nie jest ono zgodne z ANSI C, ktore nie wymagaj
stalych czasu kompilacji stdin i stdout.
yylineno
nakazuje fleksowi generowanie skanera, ktory przechowuje liczb
obecnie odczytanych linii w zmiennej globalnej yylineno. Opcja
ta jest wymuszana przez %option lex-compat.
yywrap jeli nie jest ustawione (np. %option noyywrap), to skaner nie
wola yywrap() na kocu pliku, lecz po prostu przyjmuje, e nie ma
ju plikow do skanowania (dopoki uytkownik nie wskae yyin na nowy
plik i nie wywola yylex() ponownie).
flex skanuje akcje regul w celu okrelenia czy uywasz wlaciwoci REJECT
lub yymore(). Opcje reject i yymore mog przesloni jego decyzj na tak,
jak ustawisz przy uyciu opcji, zarowno ustawiajc je (np. %option
reject) do wskazania, e wlaciwo jest rzeczywicie uywana, lub wylczajc
je, wskazujc, e wlaciwo nie jest uywana (np. %option noyymore).
Trzy opcje pobieraj wartoci lacuchowe, offsetowane znakiem '=':
%option outfile="ABC"
jest rownowane -oABC, a
%option prefix="XYZ"
jest rownowane -PXYZ. Poza tym,
%option yyclass="foo"
dotyczy tylko skanerow C++ (opcja -+). Mowi to fleksowi, e foo jest
wyprowadzone jako podklasa yyFlexLexer, wic flex bdzie umieszczal twoje
akcje w funkcji skladowej foo::yylex() zamiast w yyFlexLexer::yylex().
Powoduje to te generowanie funkcji skladowej yyFlexLexer::yylex(),
emitujcej po wywolaniu bld dzialania (przez wywolanie
yyFlexLexer::LexerError()). Dla dalszych informacji zobacz te niej
Generowanie Skanerow C++.
Istniej opcje dla purystow, nie chccych widzie w swoich skanerach
niepotrzebnych procedur. Kada z nastpujcych opcji (np. (np., %option
nounput), powoduje, e dana procedura nie pojawia si w wygenerowanym
skanerze:
input, unput
yy_push_state, yy_pop_state, yy_top_state
yy_scan_buffer, yy_scan_bytes, yy_scan_string
(chocia yy_push_state() i podobne i tak nie pojawi si dopoki nie uyjesz
%optionstack).
ROZWAANIA NAD WYDAJNOCI
Podstawowym zadaniem przy projektowaniu fleksa bylo zapewnienie, e
bdzie generowal wydajne skanery. Zostal zoptymalizowany do dobrej
wspolpracy z wielkimi zestawami regul. Poza omawianymi ju wplywami
opcji kompresji -C, istnieje jeszcze kilka akcji/opcji wplywajcych na
wydajno. S to, od najkosztowniejszej do najmniej kosztownej:
REJECT
%option yylineno
arbitralny wiszcy kontekst
zestawy wzorcow, wymagajce cofania
%array
%option interactive
%option always-interactive
'^' operator rozpoczcia linii
yymore()
z ktorych pierwsze trzy s bardzo kosztowne, a ostatnie dwa w miar
tanie. Zauwa te, e unput() jest implementowane jako wywolanie
procedurowe, ktore prawdopodobnie wykonuje sporo pracy, podczas gdy
yyless() jest tanim makrem; wic jeli wstawiasz z powrotem nadmiarowy
wyskanowany tekst, uyj yyless().
REJECT powinno by unikane za wszelk cen z punktu widzenia wydajnoci.
Jest to szczegolnie kosztowna opcja.
Pozbycie si cofania jest trudne i moe czsto prowadzi do bldow w
skomplikowanych skanerach. W praktyce zaczyna si od uycia flagi -b do
wygenerowania pliku lex.backup. Na przyklad dla wejcia
%%
foo return TOK_KEYWORD;
foobar return TOK_KEYWORD;
plik ten wyglda tak:
State #6 is non-accepting -
associated rule line numbers:
2 3
out-transitions: [ o ]
jam-transitions: EOF [ \001-n p-\177 ]
State #8 is non-accepting -
associated rule line numbers:
3
out-transitions: [ a ]
jam-transitions: EOF [ \001-` b-\177 ]
State #9 is non-accepting -
associated rule line numbers:
3
out-transitions: [ r ]
jam-transitions: EOF [ \001-q s-\177 ]
Compressed tables always back up.
Pierwszych kilka linii mowi, e istnieje stan skanera, w ktorym moe on
przyj 'o', lecz nie moe przyj innego znaku i e w tym stanie aktualnie
skanowany tekst nie pasuje do adnej reguly. Stan ten pojawia si podczas
proby dopasowania regul z linijek 2 i 3 pliku wejciowego. Jeli skaner
jest w tym stanie i odczyta cokolwiek innego ni 'o', to bdzie musial si
cofn i okreli, ktora regula pasuje. Po chwili skrobania si w glow mona
zauway, e musi to by stan, gdy skaner zobaczyl "fo". W tej sytuacji
otrzymanie czegokolwiek innego ni 'o' spowoduje cofnicie do prostego
dopasowania 'f' (regula domylna).
Komentarz odnonie stanu #8 mowi, e istnieje problem przy skanowaniu
"foob". Rzeczywicie, jeli pojawi si dowolny znak inny ni 'a', to skaner
bdzie musial si cofn do przyjmowania "foo". Podobnie sprawa ma si ze
stanem #9, mowicym o "fooba", po ktorym nie nastpuje 'r'.
Ostatni komentarz przypomina nam, e usuwanie cofania nie ma sensu jeli
nie uywamy -Cf lub -CF, gdy nie daje to adnego zysku wydajnoci na
skanerach kompresowanych.
Sposobem usuwania cofania jest dodawanie regul dla "bldow":
%%
foo return TOK_KEYWORD;
foobar return TOK_KEYWORD;
fooba |
foob |
fo {
/* falszywy alarm, nie jest to slowo kluczowe */
return TOK_ID;
}
Eliminowanie cofania mona przeprowadzi rownie przy uyciu reguly "lap-
wszystko":
%%
foo return TOK_KEYWORD;
foobar return TOK_KEYWORD;
[a-z]+ return TOK_ID;
Jest to, tam gdzie mona je zastosowa, najlepsze rozwizanie.
Komunikaty cofania czsto ukladaj si w kaskady. W skomplikowanych
zbiorach regul mona dosta setki komunikatow. Mimo to, jeli mona je
zdeszyfrowa, to ich usuwanie wymaga tylko tuzina regul (latwo si jednak
pomyli i spowodowa, e regula obslugi bldu bdzie pasowa do prawidlowego
tokena. Moliwe, e przyszle implementacje fleksa bd automatycznie
zajmowaly si usuwaniem cofania).
Wane jest pamitanie, e korzyci z eliminacji tego problemu zyskujesz
dopiero po zlikwidowaniu kadej instancji cofania. Pozostawienie cho
jednej oznacza, e nie zyskujesz niczego.
Zmienny wiszcy kontekst (gdzie zarowno prowadzca jak i koczca cz nie
maj ustalonej dlugoci) wprowadza utrat wydajnoci zblion do REJECT (tzn.
znaczn). Dlatego gdy tylko mona, to zapisz tak regul:
%%
mouse|rat/(cat|dog) run();
jako:
%%
mouse/cat|dog run();
rat/cat|dog run();
lub jako
%%
mouse|rat/cat run();
mouse|rat/dog run();
zwro uwag, e specjalna akcja '|' nie powoduje adnych oszczdnoci, a wrcz
moe pogorszy spraw (zobacz niej Niedostatki / Bldy).
Innym obszarem, gdzie uytkownik moe zwiksza wydajno skanera jest to, e
im dlusze s dopasowywane tokeny, tym szybciej dziala skaner. Jest tak
dlatego, e przetwarzanie dlugich tokenow wikszoci znakow wejciowych
zachodzi w wewntrznej (krotkiej) ptli skanujcej i rzadko musi
przechodzi przez dodatkow prac zwizan z ustawianiem rodowiska
skanujcego (np. yytext) dla akcji. Przypomnij sobie skaner komentarzy
C:
%x comment
%%
int line_num = 1;
"/*" BEGIN(comment);
<comment>[^*\n]*
<comment>"*"+[^*/\n]*
<comment>\n ++line_num;
<comment>"*"+"/" BEGIN(INITIAL);
Mona to przyspieszy nastpujco:
%x comment
%%
int line_num = 1;
"/*" BEGIN(comment);
<comment>[^*\n]*
<comment>[^*\n]*\n ++line_num;
<comment>"*"+[^*/\n]*
<comment>"*"+[^*/\n]*\n ++line_num;
<comment>"*"+"/" BEGIN(INITIAL);
Teraz zamiast sytuacji, gdzie nowa linia wymaga przetwarzania nastpnej
akcji, rozpoznawanie nowych linii jest "rozrzucone" na inne reguly.
Umoliwia to zachowanie jak najdluszego dopasowania. Zauwa, e dodawanie
regul nie spowalnia skanera! Jego szybko jest niezalena od liczby regul
i (w porownaniu do rozwaa z pocztku sekcji) ich stopnia skomplikowania
(z zastrzeeniem do operatorow takich jak '*' i '|').
Ostateczny przyklad przyspieszania skanera: zalomy, e chcesz skanowa
plik zawierajcy identyfikatory i slowa kluczowe w liczbie jednego na
lini, bez adnych obcych znakow i chcesz rozpoznawa wszystkie slowa
kluczowe. Naturalnym odruchem pocztkowym jest:
%%
asm |
auto |
break |
... etc ...
volatile |
while /* to jest slowo kluczowe */
.|\n /* a to nie... */
Aby wyeliminowa ledzenie wstecz, wprowad regul lap-wszystko:
%%
asm |
auto |
break |
... etc ...
volatile |
while /* to slowo kluczowe */
[a-z]+ |
.|\n /* a to nie... */
Obecnie, jeli mamy zagwarantowane, e mamy dokladnie jedno slowo w
linii, moemy zredukowa calkowit liczb dopasowa o polow przez wlczanie w
rozpoznawanie tokenow lapanie nowych linii.
%%
asm\n |
auto\n |
break\n |
... etc ...
volatile\n |
while\n /* to slowo kluczowe */
[a-z]+\n |
.|\n /* a to nie... */
Trzeba by tu ostronym, gdy wlanie wprowadzilimy do skanera cofanie. W
szczegolnoci, jeli my wiemy, e w wejciu nie bdzie nigdy znakow innych
ni litery i nowe linie, to flex nie moe tego wiedzie i bdzie planowal
ewentualno cofania podczas skanowania tokenu w rodzaju "auto", po
ktorym nie nastpi nowa linia lub litera. W poprzednim wypadku
nastpiloby po prostu dopasowanie reguly "auto", lecz teraz nie ma
"auto", ale "auto\n". Aby wyeliminowa moliwo cofania, moemy albo
zduplikowa wszystkie reguly bez kocowych nowych linii albo, jeli nie
spodziewamy si takiego wejcia i nie [interesuje nas] jego klasyfikacja,
moemy wprowadzi regul lap-wszystko, ktora nie zawiera nowej linii.
%%
asm\n |
auto\n |
break\n |
... etc ...
volatile\n |
while\n /* to slowo kluczowe */
[a-z]+\n |
[a-z]+ |
.|\n /* a to nie... */
Po kompilacji z -Cf, jest to prawie tak szybkie, jak tylko moliwe dla
fleksa dla tego problemu.
Ostatnia uwaga: flex jest wolny przy dopasowywaniu NUL-ow, szczegolnie
jeli token zawiera ich wiele. Najlepiej pisa reguly, dopasowujce
kr'otkie fragmenty takich tekstow.
Kolejna ostatnia uwaga o wydajnoci: jak wspomniano wyej w sekcji Jak
Dopasowywane jest Wejcie, dynamiczne zmiany rozmiarow yytext do
przyjmowania duych tokenow jest powolne, gdy obecnie wymaga by taki
token byl reskanowany od pocztku. Tak wic jeli wydajno jest istotna, to
powiniene dopasowywa "due" fragmenty tekstu, lecz nie "olbrzymie".
Granic midzy tymi pojciami jest okolo 8K znakow/token.
GENEROWANIE SKANER'OW C++
flex daje dwie drogi tworzenia skanerow przeznaczonych dla C++. Pierwsz
z nich jest proste skompilowanie fleksowego skanera kompilatorem C++
zamiast kompilatora C. Nie powiniene napotka adnych bldow kompilacji
(jeli si pojawi, to zglo to pod adres wskazany niej, w sekcji o
autorze). Moesz wowczas w akcjach swoich regul uywa kodu C++ zamiast C.
Zauwa, e domylnym rodlem dla skanera pozostaje yyin, a domylnym echem
jest wci yyout. Obydwa urzdzenia s zmiennymi FILE *, a nie
strumieniami C++.
Mona te uy fleksa do generowania klasy skanera C++. Sluy do tego opcja
-+ (lub, rownowanie %option c++), co jest przyjmowane automatycznie
jeli nazwa pliku wykonywalnego fleksa koczy si plusem, jak np. flex++.
Przy uyciu tej opcji, flex generuje skaner do pliku lex.yy.cc zamiast
lex.yy.c. Generowany skaner zawiera plik naglowkowy FlexLexer.h, ktory
definiuje interfejsy do dwoch klas C++.
Pierwsza klasa, FlexLexer, daje abstrakcyjn klas bazow, definiujc
ogolny interfejs klasy skanera. Daje nastpujce funkcje skladowe:
const char* YYText()
zwraca tekst ostatnio dopasowanego tokenu, rownowanik yytext.
int YYLeng()
zwraca dlugo ostatnio dopasowanego tokenu, rownowanik yyleng.
int lineno() const
zwraca numer aktualnej linii wejciowej (zobacz %option
yylineno), lub 1 jeli %option yylineno nie zostalo uyte.
void set_debug( int flag )
ustawia flag debuggujc dla skanera, rownowanik przypisania do
yy_flex_debug (zobacz wyej sekcj o opcjach). Zauwa, e aby wlcza
w skanerze informacje diagnostyczne, musisz skompilowa go z
uyciem %option debug.
int debug() const
zwraca biece ustawienie flagi debuggujcej.
Udostpniane s te funkcje skladowe rownowane yy_switch_to_buffer(),
yy_create_buffer() (chocia pierwszym argumentem jest wskanik istream*,
a nie FILE*), yy_flush_buffer(), yy_delete_buffer() i yyrestart() (i
znowu, pierwszym argumentem jest wskanik istream*).
Kolejn klas zdefiniowan w FlexLexer.h jest yyFlexLexer, ktory jest klas
pochodn FlexLexer. Zaiwera nastpujce dodatkowe funkcje skladowe:
yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 )
buduje obiekt yyFlexLexer stosujc podane strumienie jako wejcie
i wyjcie. Jeli nie zostan podane, to strumienie bd odpowiadaly
odpowiednio cin i cout.
virtual int yylex()
odgrywa t sam rol co yylex() dla normalnych skanerow fleksa:
skanuje strumie wejciowy, konsumuje tokeny a akcja reguly nie
zwroci wartoci. Jeli z yyFlexLexer wyprowadzisz podklas S i
zechcesz dosta si do funkcji i zmiennych skladowych S z wntrza
yylex(), to musisz uy %option yyclass="S" by poinformowa fleksa,
e bdziesz uywa podklasy zamiast yyFlexLexer. W tym wypadku
zamiast generowa yyFlexLexer::yylex(), flex generuje S::yylex()
(oraz generuje prosty yyFlexLexer::yylex(), ktory wola
yyFlexLexer::LexerError() po wywolaniu).
virtual void switch_streams(istream* new_in = 0,
ostream* new_out = 0) przypisuje yyin do new_in (jeli jest nie-
nil) oraz yyout do new_out (ditto), kasujc poprzedni bufor
wejciowy jeli przypisywana jest nowa warto yyin .
int yylex( istream* new_in, ostream* new_out = 0 )
najpierw przelcza strumienie wejciowe poprzez switch_streams(
new_in, new_out ), a nastpnie zwraca warto yylex().
Poza tym, yyFlexLexer definiuje nastpujce chronione (protected) funkcje
wirtualne, ktore mona przedefiniowa w klasach pochodnych, by dostosowa
skaner:
virtual int LexerInput( char* buf, int max_size )
odczytuje maksymalnie max_size znakow do buf i zwraca liczb
odczytanych znakow. Aby wskaza koniec wejcia zwracane jest 0
znakow. Zauwa, e skanery "interaktywne" (zobacz flagi -B oraz
-I) definiuj makro YY_INTERACTIVE. Jeli redefiniujesz
LexerInput() i potrzebujesz bra rone akcje, zalenie od tego czy
skaner skanuje rodlo interaktywne czy nie, to moesz sprawdza
obecno tej nazwy poprzez #ifdef.
virtual void LexerOutput( const char* buf, int size )
zapisuje size znakow z bufora buf ktory, o ile jest zakoczony
zerem, moe zawiera te "wewntrzne" zera jeli reguly skanera mog
lapa tekst z wewntrznymi zerami.
virtual void LexerError( const char* msg )
zglasza komunikat bldu krytycznego. Domylna wersja tej funkcji
zapisuje komunikat do strumienia cerr i koczy dzialanie
programu.
Zauwa, e obiekt yyFlexLexer zawiera swoj pe/lny stan skanowania. Tak wic
mona uywa takich obiektow do tworzenia wielobienych (reentrant)
skanerow. Moesz uywa wielu instancji tej samej klasy yyFlexLexer, jak
rownie moesz w jednym programie lczy wiele klas skanerow w calo, uywajc
opisanej wyej opcji -P .
Dla skanerow C++ nie jest dostpna wlaciwo %array, trzeba wic uywa
%pointer (tj. wartoci domylnej).
Oto przyklad prostego skanera C++:
// Przyklad uycia klasy skanera C++
%{
int mylineno = 0;
%}
string \"[^\n"]+\"
ws [ \t]+
alpha [A-Za-z]
dig [0-9]
name ({alpha}|{dig}|\$)({alpha}|{dig}|[_.\-/$])*
num1 [-+]?{dig}+\.?([eE][-+]?{dig}+)?
num2 [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)?
number {num1}|{num2}
%%
{ws} /* pomi spacje i tabulacje */
"/*" {
int c;
while((c = yyinput()) != 0)
{
if(c == '\n')
++mylineno;
else if(c == '*')
{
if((c = yyinput()) == '/')
break;
else
unput(c);
}
}
}
{number} cout << "number " << YYText() << '\n';
\n mylineno++;
{name} cout << "name " << YYText() << '\n';
{string} cout << "string " << YYText() << '\n';
%%
int main( int /* argc */, char** /* argv */ )
{
FlexLexer* lexer = new yyFlexLexer;
while(lexer->yylex() != 0)
;
return 0;
}
Jeli chcesz tworzy wiele (ronych) klas leksera, powiniene uy flagi -P
(lub opcji prefiks=) do zmiany nazwy kadego yyFlexLexer na inny
xxFlexLexer. Nastpnie moesz zalcza <FlexLexer.h> do swoich innych
rodel, raz na klas leksera, zmieniajc najpierw nazw yyFlexLexer w
nastpujcy sposob:
#undef yyFlexLexer
#define yyFlexLexer xxFlexLexer
#include <FlexLexer.h>
#undef yyFlexLexer
#define yyFlexLexer zzFlexLexer
#include <FlexLexer.h>
o ile (na przyklad) uyjesz opcji %option prefix="xx" dla jednego ze
swoich skanerow, a %option prefix="zz" dla drugiego.
WANE: obecna posta klasy skanujcej jest eksperymentalna i moe zmienia
si midzy glownymi wydaniami.
NIEZGODNOCI Z LEX I POSIX
flex jest przerobk narzdzia lex z AT&T Unix (jednake obie te
implementacje nie maj wspolnego kodu). Posiada pewne rozszerzenia i
niezgodnoci, ktore s istotne dla tych, ktorzy chc pisa skanery
dzialajce z oboma. Flex jest w pelni zgodny ze specyfikacj POSIX lex
poza szczegolem, e gdy uywa %pointer (domylne), to wywolanie unput()
niszczy zawarto yytext, co jest niezgodne ze specyfikacj POSIX.
W sekcji tej omowimy wszystkie znane obszary niezgodnoci fleksa z AT&T
lex i specyfikacj POSIX.
fleksowa opcja -l wlcza maksymaln zgodno z oryginalnym AT&T lex,
okupujc to jednak znacznymi stratami wydajnoci generowanego skanera.
Niej zaznaczymy, ktore niezgodnoci mona pokona uywajc opcji -l.
flex jest w pelni zgodny z leksem poza nastpujcymi wyjtkami:
- Nieudokumentowana zmienna wewntrzna skanera lex o nazwie
yylineno nie jest obslugiwana bez -l lub %option yylineno.
yylineno powinno by obslugiwane na poziomie buforowym, a nie na
skanerowym (pojedyncza zmienna globalna).
yylineno nie jest czci specyfikacji POSIX.
- Procedura input() nie jest redefiniowalna chocia moe by wolana
do czytania znakow nastpujcym po tym, co dopasowano do reguly.
Jeli input() napotka koniec pliku, to wykonywane jest normalne
przetwarzanie yywrap(). ``Prawdziwy'' koniec pliku jest
sygnalizowany przez input() zwroceniem wartoci EOF.
Wejcie jest natomiast sterowane przez definiowanie makra
YY_INPUT.
Ograniczenie fleksa, e input() nie moe by redefiniowany jest
zgodne ze specyfikacj POSIX, ktora po prostu nie okrela innego
adnego sposobu sterowania wejciem skanera ni poprzez dokonanie
pocztkowego przypisania do yyin.
- Procedura unput() nie jest redefiniowalna. Ograniczenie to jest
zgodne z POSIX.
- Skanery fleksa nie s tak wielobiene (reentrant) jak skanery lex.
W szczegolnoci, jeli masz interaktywny skaner i obslug przerwa,
ktora robi dlugi skok ze skanera, a skaner jest nastpnie wolany
ponownie, to moesz uzyska nastpujcy komunikat:
fatal flex scanner internal error--end of buffer missed
Aby wej na nowo do skanera, uyj najpierw
yyrestart( yyin );
Zauwa, e wywolanie to wyrzuci wszelkie buforowane wejcie; zwykle
jednak nie jest to problem przy skanerach interaktywnych.
Zauwa te, e klasy skanerow C++ s wielobiene (reentrant), wic
uywajc opcji C++ powiniene ich uywa. Zobacz sekcj o generowaniu
skanerow C++.
- output() nie jest obslugiwany. Wyjcie makra ECHO jest wykonywane
do wskanika plikowego yyout (domylnie stdout).
output() nie jest czci specyfikacji POSIX.
- lex nie obsluguje wykluczajcych warunkow pocztkowych (%x), cho
znajduj si one w specyfikacji POSIX.
- Przy rozwijaniu definicji, flex ujmuje je w nawiasy. W leksie,
nastpujce:
NAME [A-Z][A-Z0-9]*
%%
foo{NAME}? printf( "Znalazlem\n" );
%%
nie dopasuje si do lacucha "foo", gdy makro jest rozwijane tak,
e regula odpowiada "foo[A-Z][A-Z0-9]*?", a pierwszestwo jest
takie, e '?' jest wizany z "[A-Z0-9]*". We fleksie regula
zostalaby rozwinita do "foo([A-Z][A-Z0-9]*)?" i lacuch "foo"
zostalby dopasowany.
Zauwa, e jeli definicja rozpoczyna si od ^ lub koczy si na $ to
nie jest rozwijana w nawiasach, aby umoliwi tym operatorom
pojawienie si w definicjach bez utraty ich znaczenia. Ale
operatory <s>, / i <<EOF>> nie mog by uywane w definicji fleksa.
Uywanie -l skutkuje leksowym zachowaniem braku nawiasow wokol
definicji.
POSIX nakazuje ujmowanie definicji w nawiasy.
- Niektore implementacje leksa umoliwiaj rozpoczynanie akcji regul
w osobnej linii jeli wzorzec reguly ma doklejon bial spacj:
%%
foo|bar<tu spacja>
{ foobar_action(); }
flex nie obsluguje tej wlaciwoci.
- Leksowe %r (generuj skaner Ratfor) nie jest obslugiwane. Nie
jest czci specyfikacji POSIX.
- Po wywolaniu unput(), yytext jest niezdefiniowane a do
dopasowania nastpnego tokenu, chyba e skaner uywa %array.
Inaczej ma si sprawa z leksem lub specyfikacj POSIX. Opcja -l
zalatwia t niezgodno.
- Pierwszestwo operatora {} (zakresu numerycznego) jest inne. lex
interpretuje "abc{1,3}" jako "dopasuj 1, 2 lub 3 pojawienia
'abc'", a flex interpretuje to jako "dopasuj 'ab' z doklejonym
jednym, dwoma lub trzema znakami 'c'". Interpretacja fleksowa
jest zgodna ze specyfikacj POSIX.
- Pierwszestwo operatora ^ jest inne. lex interpretuje "^foo|bar"
jako "dopasuj albo 'foo' z pocztku linii albo 'bar'
gdziekolwiek", podczas gdy flex rozumie to jako "dopasuj 'foo'
lub 'bar' jeli pojawi si na pocztku linii". To drugie jest
zgodne ze specyfikacj POSIX.
- Specjalne deklaracje rozmiaru-tablicy, takie jak %a, obslugiwane
przez lex nie s wymagane przez skanery fleksa; flex je ignoruje.
- Nazwa FLEX_SCANNER jest #definiowana, wic skanery mog by pisane
z przeznaczeniem do uycia z fleksem lub leksem. Skanery
zawieraj rownie YY_FLEX_MAJOR_VERSION i YY_FLEX_MINOR_VERSION
wskazujc na wersj fleksa, ktora wygenerowala skaner (na przyklad
dla wydania 2.5 definiowane s odpowiednio liczby 2 i 5).
Nastpujce wlaciwoci fleksa nie s zawarte w specyfikacjach lex ani
POSIX:
Skanery C++
%option
zakresy warunkow pocztkowych
stosy warunkow pocztkowych
skanery interaktywne/nieinteraktywne
yy_scan_string() i koledzy
yyterminate()
yy_set_interactive()
yy_set_bol()
YY_AT_BOL()
<<EOF>>
<*>
YY_DECL
YY_START
YY_USER_ACTION
YY_USER_INIT
dyrektywy #line
%{} wokol akcji
wiele akcji w linii
plus prawie wszystkie flagi fleksa. Ostatnia wlaciwo listy odnosi si do
faktu, e we fleksie mona wstawia wiele akcji do jednej linii,
rozdzielajc je rednikami, podczas gdy w leksie, nastpujca instrukcja
foo handle_foo(); ++num_foos_seen;
jest (raczej niespodziewanie) obcinana do
foo handle_foo();
flex nie obcina akcji. Akcje ktore nie s objte klamrami kocz si
zwyczajnie na kocu linii.
DIAGNOSTYKA
warning, rule cannot be matched (ostrzeenie, regula nie moe by
dopasowana) wskazuje, e podana regula nie moe by dopasowana gdy
wystpuje za innymi regulami, ktore zawsze dopasuj jej tekst. Na
przyklad nastpujce foo nie moe by dopasowane, gdy pojawia si po regule
lap-wszystko:
[a-z]+ got_identifier();
foo got_foo();
Uycie w skanerze REJECT powstrzyma to ostrzeenie.
warning, -s option given but default rule can be matched (ostrzeenie,
podano opcj -s, lecz dopasowana moe by regula domylna) oznacza, e
moliwe jest (przypuszczalnie tylko w konkretnym warunku pocztkowym), e
regula domylna (dopasowania dowolnego znaku) jest jedyn, ktora dopasuje
si do konkretnego wejcia. Poniewa podano -s, zaklada si, e nie jest to
celowe.
reject_used_but_not_detected undefined lub yymore_used_but_not_detected
undefined (niezdefiniowana fraza pierwsza lub druga) - te bldy pojawiaj
si podczas kompilacji. Wskazuj one, e skaner uywa REJECT lub yymore(),
lecz flex nie poinformowal o tym fakcie. Znaczy to, e flex przeskanowal
pierwsze dwie sekcji w poszukiwaniu pojawienia si tych akcji, ale ich
nie znalazl, bo jako je przemycile (np. przez plik #include). Uyj
%option reject lub %option yymore do wskazania fleksowi, e naprawd
uywasz tych wlaciwoci.
flex scanner jammed - skaner skompilowany z -s napotkal lacuch
wejciowy, ktory nie zostal dopasowany do adnej z jego regul. Bld ten
moe si pojawi te z powodu problemow wewntrznych.
token too large, exceeds YYLMAX (token zbyt duy, przekracza YYLMAX) -
twoj skaner uywa %array a jedna z jego regul dopasowala si do lacucha
dluszego ni stala YYLMAX (domylnie 8K). Moesz zwikszy t warto zwikszajc
#definicj stalej YYLMAX w sekcji definicji swojego wejcia fleksa.
scanner requires -8 flag to use the character 'x' (skaner wymaga flagi
-8 do uywania znaku 'x') - specyfikacja twojego skanera zawiera
rozpoznawanie znaku 8-bitowego 'x', a nie podana zostala flaga -8, w
wyniku czego skaner uyl 7-bit z powodu wykorzystania opcji kompresji
tablic -Cf lub -CF. Dla szczegolow zobacz dyskusj flagi -7.
flex scanner push-back overflow - uyle unput() do wepchnicia z powrotem
tak dlugiego tekstu, e bufor skanera nie potrafil przetrzyma
wepchnitego tekstu i biecego tokena w yytext. Idealny skaner powinien
dynamicznie zmieni rozmiar bufora, lecz obecnie tak si nie dzieje.
input buffer overflow, can't enlarge buffer because scanner uses REJECT
(przekroczenie bufora wejciowego nie moe powikszy bufora gdy skaner
uywa REJECT) - skaner pracowal nad dopasowaniem bardzo duego tokenu i
potrzebowal rozszerzy bufor wejciowy. Nie dziala to ze skanerami,
uywajcymi REJECT.
fatal flex scanner internal error--end of buffer missed (krytyczny bld
wewntrzny skanera flex -- rozminito si z kocem bufora) - Moe si to
pojawi w skanerze, ktory jest uruchomiony po dlugim skoku z ramki
aktywacji skanera. Przed powrotem do skanera uyj:
yyrestart( yyin );
albo, jak wspomniano wyej, przelcz si na uywanie skanerow C++.
too many start conditions in <> construct! (zbyt wiele warunkow
pocztkowych w konstrukcji <>) - w konstrukcji <> pojawilo si wicej
warunkow pocztkowych ni istnieje w rzeczywistoci (wic przynajmniej
jeden z nich pojawil si dwukrotnie).
PLIKI
-lfl biblioteka, z ktor musz by lczone skanery.
lex.yy.c
generowany skaner (nazywany na niektorych systemach lexyy.c).
lex.yy.cc
generowana klasa skanera C++, po uyciu -+.
<FlexLexer.h>
plik naglowkowy definiujcy klas bazow skanera C++, FlexLexer i
klas pochodn, yyFlexLexer.
flex.skl
skaner szkieletowy. Plik ten jest uywany tylko przy budowaniu
fleksa, nie przy jego uruchamianiu.
lex.backup
informacje wspierajce (backing-up) dla flagi -b (nazywany jest
mianem lex.bck na niektorych systemach).
NIEDOSTATKI / B/LDY
Niektore wzorce wiszcego kontekstu nie mog by poprawnie dopasowane i
generuj komunikaty ostrzegawcze ("dangerous trailing context")
(niebezpieczny wiszcy kontekst). S to wzorce, gdzie zakoczenie
pierwszej czci reguly dopasowuje si do pocztku drugiej czci, takie jak
"zx*/xy*", gdzie 'x*' dopasowuje 'x' na pocztku wiszcego kontekstu.
(Zauwa, e projekt POSIX-a okrela, e dopasowany w takich wzorcach tekst
jest niezdefiniowany.)
Dla niektorych regul wiszcego kontekstu, czci ktore s w rzeczywistoci
okrelonej dlugoci nie s tak rozpoznawane. Prowadzi to do wspomnianej
wyej straty wydajnoci. W szczegolnoci, czci uywajce '|' lub {n} (takie
jak "foo{3}") zawsze s uwaane za zmienno-dlugociowe.
Lczenie wiszcego kontekstu z akcj specjaln '|' moe spowodowa, e
ustalony (fixed) wiszcy kontekst zostanie zmieniony w bardziej
kosztowny, zmienny wiszcy kontekst. Na przyklad nastpujce:
%%
abc |
xyz/def
Uywanie unput() uszkadza yytext i yyleng, chyba e uyto dyrektywy %array
lub opcji -l.
Dopasowywanie wzorcow NUL-i jest znacznie wolniejsze ni dopasowywanie
innych znakow.
Dynamiczne zmiany rozmiaru bufora s wolne i wymagaj reskanowania calego
tekstu dopasowanego dotd przez biecy (zwykle duy) token.
Z powodu buforowania wejcia i czytania z wyprzedzeniem, nie mona lczy z
regulami fleksa wywola <stdio.h>, np. getchar(). Zamiast tego wolaj
input().
Wpisy calej tablicy (total table entries) wymieniane przez flag -v nie
zawieraj niektorych wpisow, potrzebnych do okrelania, ktora regula
zostala dopasowana. Liczba wpisow jeli skaner nie uywa REJECT jest
rowna liczbie stanow DFA, a w przeciwnym wypadku jest troch wiksza.
REJECT nie moe by uywany z opcjami -f lub -F.
Wewntrzne algorytmy fleksa wymagaj udokumentowania.
ZOBACZ TAKE
lex(1), yacc(1), sed(1), awk(1).
John Levine, Tony Mason, and Doug Brown, Lex & Yacc, O'Reilly and
Associates. Upewnij si, e bierzesz 2-gie wydanie.
M. E. Lesk and E. Schmidt, LEX - Lexical Analyzer Generator
Alfred Aho, Ravi Sethi and Jeffrey Ullman, Compilers: Principles,
Techniques and Tools, Addison-Wesley (1986). Opisuje techniki
dopasowywania wzorcow uywane przez fleksa (deterministyczne automaty
skoczone).
AUTOR
Vern Paxson, z pomoc wielu pomyslow i inspiracji od Vana Jacobsona.
Oryginaln wersj napisal Jef Poskanzer. Reprezentacja szybkiej tablicy
jest czciow implementacj projektu Vana Jacobsona. Implementacja zostala
wykonana przez Kevina Gonga and Verna Paxsona.
Podzikowania dla wielu beta testerow, komentatorow i kontrybutorow
fleksa, z ktorych szczegolnie zasluone s nastpujce osoby: Francois
Pinard, Casey Leedom, Robert Abramovitz, Stan Adermann, Terry Allen,
David Barker-Plummer, John Basrai, Neal Becker, Nelson H.F. Beebe,
benson@odi.com, Karl Berry, Peter A. Bigot, Simon Blanchard, Keith
Bostic, Frederic Brehm, Ian Brockbank, Kin Cho, Nick Christopher, Brian
Clapper, J.T. Conklin, Jason Coughlin, Bill Cox, Nick Cropper, Dave
Curtis, Scott David Daniels, Chris G. Demetriou, Theo Deraadt, Mike
Donahue, Chuck Doucette, Tom Epperly, Leo Eskin, Chris Faylor, Chris
Flatters, Jon Forrest, Jeffrey Friedl, Joe Gayda, Kaveh R. Ghazi,
Wolfgang Glunz, Eric Goldman, Christopher M. Gould, Ulrich Grepel, Peer
Griebel, Jan Hajic, Charles Hemphill, NORO Hideo, Jarkko Hietaniemi,
Scott Hofmann, Jeff Honig, Dana Hudes, Eric Hughes, John Interrante,
Ceriel Jacobs, Michal Jaegermann, Sakari Jalovaara, Jeffrey R. Jones,
Henry Juengst, Klaus Kaempf, Jonathan I. Kamens, Terrence O Kane, Amir
Katz, ken@ken.hilco.com, Kevin B. Kenny, Steve Kirsch, Winfried Koenig,
Marq Kole, Ronald Lamprecht, Greg Lee, Rohan Lenard, Craig Leres, John
Levine, Steve Liddle, David Loffredo, Mike Long, Mohamed el Lozy, Brian
Madsen, Malte, Joe Marshall, Bengt Martensson, Chris Metcalf, Luke
Mewburn, Jim Meyering, R. Alexander Milowski, Erik Naggum, G.T. Nicol,
Landon Noll, James Nordby, Marc Nozell, Richard Ohnemus, Karsten
Pahnke, Sven Panne, Roland Pesch, Walter Pelissero, Gaumond Pierre,
Esmond Pitt, Jef Poskanzer, Joe Rahmeh, Jarmo Raiha, Frederic
Raimbault, Pat Rankin, Rick Richardson, Kevin Rodgers, Kai Uwe Rommel,
Jim Roskind, Alberto Santini, Andreas Scherer, Darrell Schiebel, Raf
Schietekat, Doug Schmidt, Philippe Schnoebelen, Andreas Schwab, Larry
Schwimmer, Alex Siegel, Eckehard Stolz, Jan-Erik Strvmquist, Mike
Stump, Paul Stuart, Dave Tallman, Ian Lance Taylor, Chris Thewalt,
Richard M. Timoney, Jodi Tsai, Paul Tuinenga, Gary Weik, Frank Whaley,
Gerhard Wilhelms, Kent Williams, Ken Yap, Ron Zellar, Nathan Zelle,
David Zuhn, oraz ci, ktorych nazwiska wylecialy z moich zdolnoci
archiwizowania poczty, lecz ktorych wklad jest rownie wany.
Keith Bostic, Jon Forrest, Noah Friedman, John Gilmore, Craig Leres,
John Levine, Bob Mulcahy, G.T. Nicol, Francois Pinard, Rich Salz i
Richard Stallman pomogli z ronymi problemami dystrybucji.
Esmond Pitt and Earle Horton pomogl z wsparciem 8-bit; Benson Margulies
i Fred Burke pomogli z wsparciem C++; Kent Williams i Tom Epperly
pomogli z wsparciem klas C++; Ove Ewerlid pomogl z wsparciem NUL-ow;
Eric Hughes pomogl z wielokrotnymi buforami.
Praca ta byla pocztkowo wykonywana gdy bylem z Real Time Systems Group
w Lawrence Berkeley Laboratory w Berkeley, CA. Wielkie dziki do
wszystkich za wsparcie, ktore uzyskalem.
Komentarze lij do vern@ee.lbl.gov.
INFORMACJE O T/LUMACZENIU
Powysze tlumaczenie pochodzi z nieistniejcego ju Projektu Tlumaczenia
Manuali i moe nie by aktualne. W razie zauwaenia ronic midzy powyszym
opisem a rzeczywistym zachowaniem opisywanego programu lub funkcji,
prosimy o zapoznanie si z oryginaln (angielsk) wersj strony podrcznika.