flex

FLEX(1)                     General Commands Manual                    FLEX(1)



NAZWA
       flex - szybki generator analizatora leksykalnego

SKÅADNIA
       flex [-bcdfhilnpstvwBFILTV78+? -C[aefFmr] -ooutput -Pprefix -Sskeleton]
       [--help --version] [filename ...]

WPROWADZENIE
       PodrÄcznik ten opisuje narzÄdzie flex.  Jest ono przeznaczone do
       generowania programów, dokonywujÄcych dopasowywania wzorców na
       tekÅcie. PodrÄcznik zawiera zarówno sekcje przewodnikowe jak i
       informacyjne.

           Opis
            krótki przeglÄd możliwoÅci narzÄdzia

           Proste PrzykÅady

           Format Pliku WejÅciowego

           Wzorce
            rozszerzone wyrażenia regularne używane przez flex

           Sposób Dopasowywania WejÅcia
            reguÅy okreÅlania, co dopasowano

           Akcje
            jak podawaÄ, co robiÄ po dopasowaniu wzorca

           Generowany Skaner
            szczegóÅy o skanerze, tworzonym przez fleksa; jak kontrolowaÄ ÅºródÅo
            wejÅciowe

           Warunki Startowe
               wprowadzanie do skanerów kontekstu i obsÅuga "mini-skanerów"

           Wielokrotne Bufory WejÅciowe
            jak obsÅugiwaÄ wiele źródeÅ wejÅciowych; jak skanowaÄ z ÅaÅcuchów
            zamiast z plików

           ReguÅy KoÅca Pliku
            specjalne reguÅy dopasowywane do koÅca wejÅcia

           Różne Makra
            ogóŠmakr dostÄpnych z poziomu akcji

           WartoÅci DostÄpne Użytkownikowi
            ogóŠwartoÅci dostÄpnych z poziomu akcji

           ÅÄczenie z Yacc
            ÅÄczenie skanerów flex z analizatorami yacc

           Opcje
            opcje linii poleceÅ fleksa i dyrektywa "%option"

           Kwestie wydajnoÅciowe
            jak przyspieszaÄ skanery

           Generowanie Skanerów C++
            eksperymentalna wÅaÅciwoÅÄ generowania klas skanerów C++

           NiezgodnoÅci z Lex i POSIX
            czym flex różni siÄ od standardów AT&T lex i POSIX lex

           Diagnostyka
            objaÅnienie komunikatów o bÅÄdach, generowanych przez flex (lub
            skanery)

           Pliki
            pliki używane przez flex

           Niedostatki / BÅÄdy
            znane problemy fleksa

           Zobacz Także
            pozostaÅa dokumentacja i zwiÄzane z fleksem narzÄdzia

           Autor
            informacja kontaktu z autorem


OPIS
       flex jest narzÄdziem przeznaczonym do generowania skanerów:
       programów, rozpoznajÄcych wzorce leksykalne tekstu.  flex odczytuje
       podane pliki wejÅciowe (lub stdin gdy nie sÄ podane) i pobiera z nich
       opis generowanego skanera. Opis skÅada siÄ z par wyrażeÅ regularnych i
       kodu C. Pary te nazywane sÄ reguÅami.  flex jako wyjÅcie generuje plik
       źródÅowy 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 wejÅcie w
       poszukiwaniu wyrażeÅ regularnych. Gdy tylko takie siÄ znajdzie,
       wykonywany jest odpowiedni fragment kodu C.

PROSTE PRZYKÅADY
       Przedstawmy teraz trochÄ prostych przykÅadów aby obyÄ siÄ z używaniem
       flex.  NastÄpujÄcy plik wejÅciowy flex okreÅla skaner, który za
       każdym razem gdy napotka ÅaÅcuch "username", podmieni go nazwÄ
       użytkownika:

           %%
           username    printf( "%s", getlogin() );

       DomyÅlnie tekst, którego flex nie może dopasowaÄ jest kopiowany na
       wyjÅcie. Skaner bÄdzie wiÄc kopiowaÅ swój plik wejÅciowy na wyjÅcie,
       podmieniajÄc wszelkie pojawienia "username".  W tym przykÅadzie wejÅcia
       mamy tylko jednÄ reguÅÄ. Wzorcem jest "username", a akcjÄ jest
       "printf".  Znaki "%%" oznaczajÄ poczÄtek reguÅ.

       Oto kolejny prosty przykÅad:

                   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Ä znaków i liczbÄ linijek swojego wejÅcia (nie
       daje żadnego wyjÅcia, nie liczÄc koÅcowego raportu). Pierwsza linia
       deklaruje dwie zmienne globalne, "num_lines" i "num_chars", które sÄ
       dostÄpne wewnÄtrz funkcji yylex() i main(), zadeklarowanej po drugim
       "%%". Mamy tu dwie reguÅy: pierwsza dopasowuje siÄ do nowej linii
       ("\n") i inkrementuje licznik linii oraz znaków; druga dopasowuje siÄ
       do dowolnego znaku innego niż nowa linia (wyrażenie regularne ".") i
       zwiÄksza licznik liczby znaków.

       A oto trochÄ bardziej skomplikowany przykÅad:

           /* skaner dla zabawkowego Pascalo-podobnego jÄzyka */

           %{
           /* potrzebujemy tego do wywoÅania atof() */
           #include <math.h>
           %}

           DIGIT    [0-9]
           ID       [a-z][a-z0-9]*

           %%

           {DIGIT}+    {
                       printf( "Liczba caÅkowita: %s (%d)\n", yytext,
                               atoi( yytext ) );
                       }

           {DIGIT}+"."{DIGIT}*        {
                       printf( "Liczba zmiennoprzecinkowa: %s (%g)\n", yytext,
                               atof( yytext ) );
                       }

           if|then|begin|end|procedure|function        {
                       printf( "SÅowo kluczowe: %s\n", yytext );
                       }

           {ID}        printf( "Identyfikator: %s\n", yytext );

           "+"|"-"|"*"|"/"   printf( "Operator: %s\n", yytext );

           "{"[^}\n]*"}"     /* zjedz jednolinijkowe komentarze */

           [ \t\n]+          /* zjedz biaÅe 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 poczÄtki prostego skanera dla jÄzyka podobnego do Pascala.
       Rozróżnia poszczególne rodzaje tokenów i informuje co zobaczyÅ.

       SzczegóÅy tego przykÅadu zostanÄ wyjaÅnione w nastÄpnych sekcjach.

FORMAT PLIKU WEJÅCIOWEGO
       Plik wejÅciowy fleksa skÅada siÄ z trzech sekcji, rozdzielanych liniami
       z ÅaÅcuchem %%:

           definicje
           %%
           reguÅy
           %%
           kod użytkownika

       Sekcja definicji zawiera definicje prostych nazw, upraszczajÄcych
       później specyfikacjÄ skanera. Zawiera też deklaracje warunków
       poczÄtkowych, które objaÅniono w dalszej sekcji.

       Definicje nazw majÄ postaÄ:

           nazwa definicja

       gdzie "nazwa" jest sÅowem, rozpoczynajÄcym siÄ od litery lub
       podkreÅlenia ('_').  PozostaÅe znaki mogÄ byÄ literami, cyframi,
       podkreÅleniami lub myÅlnikami.  Definicja jest pobierana od momentu
       pojawienia siÄ pierwszego znaku, który nie jest spacjÄ i który
       znajduje siÄ za nazwÄ. Definicja rozciÄga siÄ do koÅca linii. Do takiej
       definicji można siÄ nastÄpnie odwoÅywaÄ przy użyciu konwencji
       "{nazwa}", która jest automatycznie rozwijana w "(definicjÄ)". Na
       przykÅad

           DIGIT    [0-9]
           ID       [a-z][a-z0-9]*

       definiuje "DIGIT" jako wyrażenie regularne, pasujÄce do pojedynczej
       cyfry, a "ID" jako wyrażenie regularne odpowiadajÄce literze z
       doklejonymi ewentualnymi literami lub cyframi.  Późniejsze
       odniesienie do

           {DIGIT}+"."{DIGIT}*

       jest równoważne

           ([0-9])+"."([0-9])*

       i dopasowuje jednÄ lub wiÄcej cyfr, po których wystÄpuje kropka i
       ewentualnie nastÄpne cyfry.

       Sekcja reguÅ wejÅcia fleksa zawiera szereg reguÅ w postaci:

           wzorzec   akcja

       Przed wzorcem nie może wystÄpiÄ wciÄcie, a akcja musi rozpoczynaÄ siÄ
       w tej samej linii.

       Dla dalszego opisu akcji patrz dalej.

       W koÅcu, sekcja kodu użytkownika jest zwyczajnie kopiowana do lex.yy.c
       (bez dokonywania w niej zmian).  Jest to używane do funkcji
       pomocniczych, które woÅajÄ lub sÄ woÅane przez skaner. ObecnoÅÄ tej
       sekcji jest opcjonalna; jeÅli nie istnieje, to ostatni %% pliku
       wejÅciowego może byÄ pominiÄty.

       JeÅli w sekcjach definicji lub reguÅ znajduje siÄ jakiÅ wciÄty
       (indentowany) tekst lub tekst ujÄty w %{ i %}, to jest on kopiowany
       dosÅownie na wyjÅcie (po usuniÄciu %{}).  Znaki %{} muszÄ pojawiÄ siÄ
       samodzielnie w liniach bez wciÄÄ.

       W sekcji reguÅ, tekst wciÄty lub tekst %{}, znajdujÄcy siÄ przed
       pierwszÄ reguÅÄ może sÅużyÄ deklarowaniu zmiennych lokalnych dla
       procedury skanujÄcej oraz (po deklaracjach) kodu, który ma byÄ
       wywoÅywany za każdym uruchomieniem procedury skanujÄcej.  PozostaÅe
       przypadki wciÄtego tekstu lub tekstu %{} sekcji reguÅ sÄ nadal
       kopiowane na wyjÅcie, lecz ich znaczenie nie jest dokÅadnie
       zdefiniowane i mogÄ spowodowaÄ bÅÄdy kompilacji (wÅaÅciwoÅÄ ta jest
       obecna dla zgodnoÅci z POSIX; zobacz niżej inne tego typu
       wÅaÅciwoÅci).

       W sekcji definicji na wyjÅcie kopiowane sÄ również nie-wciÄte bloki
       komentarza, ujÄte miÄdzy znaki "/*" i "*/".

WZORCE
       Wzorce wejÅciowe sÄ pisane z użyciem rozszerzonego zestawu wyrażeÅ
       regularnych. SÄ to:

           x          dopasowuje znak 'x'
           .          dowolny znak poza nowÄ liniÄ
           [xyz]      "klasa znaków"; w tym przypadku wzorzec odpowiada
                        zarówno 'x', 'y' jak i 'z'
           [abj-oZ]   "klasa znaków" z zakresem; odpowiada ona
                        'a', 'b', dowolnej literze od 'j' do 'o' oraz 'Z'
           [^A-Z]     zanegowana "klasa znaków" tj. dowolny znak poza
                        wymienionymi w klasie. W tym wypadku dowolny znak oprócz
                  dużych liter
           [^A-Z\n]  dowolny znak oprócz dużych liter lub nowej linii
           r*         zero lub wiÄcej r'ów, gdzie r jest wyrażeniem regularnym
           r+         jeden lub wiÄcej r'ów
           r?         zero lub jeden r (tj. "opcjonalny r")
           r{2,5}     od dwu do piÄciu r
           r{2,}      dwa lub wiÄcej r
           r{4}       dokÅadnie 4 r
           {nazwa}    rozwiniÄcie definicji "nazwa" (patrz wyżej)
           "[xyz]\"foo"
                      ÅaÅcuch literalny: [xyz]"foo
           \X        JeÅli X to 'a', 'b', 'f', 'n', 'r', 't' lub 'v',
                  to nastÄpuje interpretacja ANSI-C \x. W przeciwnym
                  wypadku używany jest literalny 'X' (używane do cytowania
                  operatorów--np. '*').
           \0        znak NUL (kod ASCII 0)
           \123      znak o wartoÅci ósemkowej 123
           \x2a      znak o wartoÅci szesnastkowej 2a
           (r)        dopasuj r; nawiasy sÄ używane do przeciÄżania priorytetów
                     (patrz niżej)


           rs         wyrażenie regularne r, za którym nastÄpuje wyrażenie
                  regularne s; nazywa siÄ to "ÅÄczeniem"


           r|s        r lub s


           r/s        r, lecz tylko jeÅli za nim nastÄpuje s. Tekst dopasowywany
                  przez s jest zaÅÄczany do okreÅlania czy ta reguÅa miaÅa
                  "najdÅuższe dopasowanie", lecz potem jest zwracany do
                  wejÅcia przed wykonaniem akcji. Tak wiÄc akcja widzi tylko
                  tekst dopasowany przez r. Ten rodzaj wzorca jest nazywany
                  "doklejonym kontekstem". (IstniejÄ pewne kombinacje r/s,
                  których flex nie potrafi wÅaÅciwie dopasowaÄ; zobacz uwagi
                  w dalszej sekcji Niedostatki / BÅÄdy w okolicach
                  "niebezpiecznego kontekstu doklejonego".)
           ^r         r, lecz tylko na poczÄtku linii (tj. zaraz po rozpoczÄciu
                  skanowania, lub po wyskanowaniu nowej linii).
           r$         r, lecz tylko na koÅcu linii (tj. tuż przed nowÄ liniÄ).
                  Równoważne "r/\n".

                   Zauważ, że notacja nowej linii fleksa jest dokÅadnie tym,
                   co byÅo używane jako '\n' przez kompilator C, użyty do
                   kompilacji fleksa; w praktyce na niektórych systemach DOS
                   musisz wyfiltrowaÄ \r lub jawnie używaÄ r/\r\n zamiast
                   "r$".


           <s>r       r, lecz tylko dla warunku poczÄtkowego s (zobacz niżej
                  dyskusjÄ o warunkach poczÄtkowych)
           <s1,s2,s3>r
                      to samo, lecz jeÅli dowolny z warunków poczÄtkowych s1,
                        s2 lub s3
           <*>r       r w dowolnym warunku poczÄtkowym, nawet wykluczajÄcym


           <<EOF>>    koniec pliku
           <s1,s2><<EOF>>
                      koniec pliku w warunkach poczÄtkowych s1 lub s2

       Zauważ, że w obrÄbie klasy znaków wszystkie operatory wyrażeÅ
       regularnych tracÄ swoje znaczenie specjalne (nie liczÄc cytowania '\',
       znaków klasy '-',

       Wymienione wyżej wyrażenia regularne sÄ pogrupowane zgodnie z
       priorytetami, liczÄc od najwyższego do najniższego (z góry na dóÅ).
       Te, które zgrupowano razem majÄ jednakowy priorytet. Na przykÅad,

           foo|bar*

       jest równoważne

           (foo)|(ba(r*))

       ponieważ operator '*' ma wyższy priorytet niż ÅÄczenie, a ÅÄczenie
       ma wyższy priorytet niż alternatywa ('|'). Wzorzec ten pasuje wiÄc
       albo do ÅaÅcucha "foo" albo do "ba", po którym może nastÄpiÄ zero lub
       wiÄcej r.  W celu dopasowania "foo" lub zero lub wiÄcej "bar"'ów,
       użyj:

           foo|(bar)*

       a żeby dopasowaÄ zero lub wiÄcej "foo"-lub-"bar"'ów:

           (foo|bar)*


       Poza znakami i zakresami znaków, klasy znaków mogÄ też zawieraÄ
       specjalne wyrażenia.  Wyrażenia te sÄ ujmowane w ograniczniki [: i :]
       (które muszÄ dodatkowo pojawiaÄ siÄ wewnÄtrz '[' i ']' klasy znaków;
       inne elementy w klasie znaków też mogÄ siÄ pojawiÄ).  PrawidÅowymi
       wyrażeniami sÄ:

           [:alnum:] [:alpha:] [:blank:]
           [:cntrl:] [:digit:] [:graph:]
           [:lower:] [:print:] [:punct:]
           [:space:] [:upper:] [:xdigit:]

       Wyrażenia te oznaczajÄ zestaw znaków, odpowiadajÄcy równoważnemu
       standardowi funkcji isXXX jÄzyka C. PrzykÅadowo [:alnum:] oznacza
       wszystkie znaki, dla których isalnum(3) zwraca prawdÄ - tj. wszelkie
       znaki alfabetyczne lub numeryczne.  Niektóre systemy nie udostÄpniajÄ
       isblank(3).  Flex definiuje [:blank:] jako spacjÄ lub tabulacjÄ.

       Na przykÅad nastÄpujÄce klasy sÄ sobie równoważne:

           [[:alnum:]]
           [[:alpha:][:digit:]
           [[:alpha:]0-9]
           [a-zA-Z0-9]

       JeÅli twój skaner jest niewrażliwy na wielkoÅÄ znaków (flaga (flaga
       -i), to [:upper:] i [:lower:] sÄ równoważne [:alpha:].

       TrochÄ uwag o wzorcach:

       -      Zanegowana klasa znaków, taka jak wyżej wymienione przykÅadowe
              "[^A-Z]" bÄdzie pasowaÄ do nowej linii, chyba że "\n" (lub
              równoważna sekwencja specjalna) jest jednym z jawnie obecnych
              w klasie znaków (np. "[^A-Z\n]"). Odbiega to od sposobu
              traktowania zanegowanych klas znaków przez inne narzÄdzia
              operujÄce na wyrażeniach regularnych, lecz niestety
              niespójnoÅÄ jest ugruntowana historycznie.  Dopasowywanie nowej
              linii oznacza, że wzorzec w rodzaju [^"]* może dopasowaÄ siÄ
              do caÅego wejÅcia, chyba że istnieje w nim drugi cudzysÅów.

       -      ReguÅa może mieÄ najwyżej jednÄ instancjÄ dowiÄzanego
              kontekstu (operatory siÄ tylko na poczÄtku wzorca i dodatkowo,
              podobnie jak '/' i '$', nie mogÄ byÄ grupowane w nawiasy. Znak
              '^', który nie pojawia siÄ na poczÄtku reguÅy, lub '$', nie
              znajdujÄcy siÄ na koÅcu traci swoje specjalne znaczenie.

              NastÄpujÄce wzorce sÄ niedozwolone:

                  foo/bar$
                  <sc1>foo<sc2>bar

              Zauważ, że pierwszy z nich może byÄ zapisany jako
              "foo/bar\n".

              NastÄpujÄce wzorce powodujÄ, że '$' lub '^' sÄ traktowane jak
              zwykÅe znaki:

                  foo|(bar$)
                  foo|^bar

              JeÅli oczekiwanÄ wartoÅciÄ jest "foo" lub "bar-z-nowÄ-liniÄ", to
              użyÄ można nastÄpujÄcego wzorca (akcja specjalna | jest
              wyjaÅniona niżej):

                  foo      |
                  bar$     /* tu rozpoczyna siÄ akcja */

              Podobna sztuczka powinna zadziaÅaÄ dla dopasowywania foo lub
              bar-na-poczÄtku-linii.

JAK DOPASOWYWANE JEST WEJÅCIE
       Po uruchomieniu skanera, analizuje on swoje wejÅcie w poszukiwaniu
       ÅaÅcuchów odpowiadajÄcych któremuÅ z jego wzorców. JeÅli znajdzie
       wiÄcej niż jeden pasujÄcy wzorzec, wybiera ten, który pasuje do
       najwiÄkszej iloÅci tekstu (w reguÅach z dowiÄzanym kontekstem oznacza
       to też dÅugoÅÄ czÄÅci dowiÄzanej, mimo faktu, że zostanie ona
       zwrócona na wejÅcie. JeÅli znajdzie dwa lub wiÄcej dopasowaÅ o tej
       samej dÅugoÅci, to wybierana jest pierwsza reguÅa.

       Po okreÅleniu dopasowania, tekst dopasowania (zwany dalej tokenem) jest
       udostÄpniany we wskaźnikowej zmiennej globalnej yytext, a jego dÅugoÅÄ
       w globalnej zmiennej caÅkowitej yyleng.  Wykonywana jest też
       odpowiadajÄca wzorcowi akcja (szczegóÅowy opis akcji jest dalej), a
       nastÄpnie pozostaÅa czÄÅÄ wejÅcia jest dopasowywana do kolejnego
       wzorca.

       JeÅli dopasowanie nie zostanie znalezione, wykonana zostanie reguÅa
       domyÅlna: nastÄpny znak wejÅcia jest uważany za dopasowany i kopiowany
       na stdout.  Tak wiÄc najprostszym poprawnym plikiem wejÅciowym fleksa
       jest:

           %%

       Generuje to skaner, który po prostu kopiuje swoje wejÅcie (jeden znak
       naraz) na wyjÅcie.

       Zauważ, że yytext może byÄ definiowane na dwa sposoby: jako
       wskaźnik do znaków lub jako tablica znaków.  Używanie konkretnej
       definicji można kontrolowaÄ, wÅÄczajÄc do pliku wejÅciowego w
       pierwszej sekcji specjalne dyrektywy %pointer lub %array.  DomyÅlnie
       używana jest dyrektywa %pointer, chyba że używa siÄ opcji -l
       zgodnoÅci z leksem i wtedy yytext staje siÄ tablicÄ.  KorzyÅciÄ z
       używania %pointer jest zwiÄkszenie szybkoÅci skanowania i
       zlikwidowanie przepeÅnieÅ bufora przy dopasowywaniu dużych tokenów
       (chyba że zabraknie pamiÄci dynamicznej).  WadÄ jest ograniczenie
       sposobu modyfikowania przez akcje zmiennej yytext (zobacz nastÄpnÄ
       sekcjÄ) i to, że wywoÅania funkcji unput() niszczÄ aktualnÄ zawartoÅÄ
       yytext, co może przyprawiaÄ o ból gÅowy podczas portowania skanerów
       miÄdzy różnymi wersjami lex.

       ZaletÄ %array jest możliwoÅÄ modyfikowania yytext i to, że woÅanie
       unput() nie niszczy yytext.  Poza tym, istniejÄce programy lex czasami
       zewnÄtrznie zaglÄdajÄ do yytext przy użyciu deklaracji w postaci:
           extern char yytext[];
       Definicja ta jest bÅÄdna przy użyciu z %pointer, lecz prawidÅowa dla
       %array.

       %array definiuje yytext jako tablicÄ YYLMAX znaków, co domyÅlnie jest
       doÅÄ duÅ¼Ä wartoÅciÄ. Możesz zmieniaÄ rozmiar przez proste
       #definiowanie YYLMAX na innÄ wartoÅÄ w pierwszej sekcji wejÅciowego
       pliku fleksa.  Jak wspomniano wyżej, dla %pointer yytext wzrasta
       dynamicznie, by przechowywaÄ duże tokeny. Chociaż oznacza to, że
       skaner %pointer może zbieraÄ duże tokeny (jak np. caÅe bloki
       komentarzy), to zakop sobie w pamiÄci, że za każdym razem gdy skaner
       zmienia rozmiar yytext to musi również reskanowaÄ caÅy token od
       poczÄtku, wiÄc może siÄ to okazaÄ powolne.  yytext w chwili obecnej
       nie zwiÄksza dynamicznie rozmiaru jeÅli wywoÅanie unput() powoduje
       wepchniÄcie z powrotem zbyt dużego bloku tekstu. Zamiast tego pojawia
       siÄ bÅÄd wykonania.

       Zauważ też, że postaci %array nie można używaÄ z klasami skanerów
       C++ (zobacz opcjÄ c++ poniżej).

AKCJE
       Każdy wzorzec reguÅy ma odpowiadajÄcÄ mu akcjÄ, która może byÄ
       dowolnÄ instrukcjÄ jÄzyka C. Wzorzec koÅczy siÄ na pierwszym
       niecytowanym znaku biaÅej spacji; reszta linijki jest akcjÄ. JeÅli
       akcja jest pusta, to token wejÅciowy jest zwyczajnie odrzucany. Na
       przykÅad oto program, kasujÄcy wszystkie pojawienia ÅaÅcucha "wytnij
       mnie":

           %%
           "wytnij mnie"

       (Wszystkie pozostaÅe znaki wejÅcia zostanÄ skopiowane na wyjÅcie, gdyż
       dopasujÄ siÄ do reguÅy domyÅlnej.)

       Oto program, który kompresuje wielokrotne spacje i tabulacje do
       pojedynczej spacji. Program wycina też wszystkie biaÅe spacje z koÅca
       linii:

           %%
           [ \t]+        putchar( ' ' );
           [ \t]+$       /* ignoruj ten token */


       JeÅli akcja zawiera znak '{', to rozciÄga siÄ ona aż do zamykajÄcego
       '}', nawet na przestrzeni wielu linii.  flex ma pewne wiadomoÅci o
       ÅaÅcuchach C i komentarzach, wiÄc nie zostanie ogÅupione przez klamry,
       które mogÄ siÄ w nich znajdowaÄ. Poza tym dozwolone sÄ też akcje,
       które zaczynajÄ siÄ od %{ i zawierajÄ tekst akcji aż do nastÄpnego %}
       (niezależnie od zwyczajnych klamer wewnÄtrz akcji).

       Akcja skÅadajÄca siÄ wyÅÄcznie z pionowej kreski ('|') oznacza "taka
       sama, jak akcja nastÄpnej reguÅy". Dla zobrazowania patrz niżej.

       Akcje mogÄ zawieraÄ kod C, wÅÄczajÄc w to instrukcje return,
       przeznaczone do zwracania wartoÅci do procedury, która wywoÅaÅa
       yylex().  Przy każdym wywoÅaniu yylex() kontynuuje przetwarzanie
       tokenów od miejsca, w którym ostatnio przerwaÅ aż do osiÄgniÄcia
       koÅca pliku lub wywoÅania return.

       Akcje mogÄ spokojnie modyfikowaÄ zmiennÄ yytext; nie mogÄ jej jednak
       wydÅużaÄ (dodawanie znaków do jej koÅca nadpisze dalsze znaki
       strumienia wejÅciowego). Odmiennie jest natomiast przy używaniu %array
       (patrz wyżej); wtedy yytext można spokojnie modyfikowaÄ w dowolny
       sposób.

       Podobnie do powyższej zmiennej, można spokojnie modyfikowaÄ yyleng,
       lecz należy uważaÄ by nie robiÄ tego jeÅli akcja używa yymore()
       (patrz niżej).

       Istnieje wiele dyrektyw specjalnych, które można zawrzeÄ w akcji:

       -      ECHO kopiuje wejÅcie yytext na wyjÅcie skanera.

       -      BEGIN z doklejonÄ nazwÄ warunku poczÄtkowego umieszcza skaner w
              odpowiednim warunku poczÄtkowym (patrz niżej).

       -      REJECT Kieruje skaner na dziaÅanie w "drugiej najlepszej"
              regule, która zostaÅa dopasowana do wzorca wejÅciowego (lub
              prefiksu wejÅcia). ReguÅa jest wybierana wedÅug zasad opisanych
              w "Jak dopasowywane jest wejÅcie", po czym nastÄpuje odpowiednie
              ustawienie yytext oraz yyleng.  Może to byÄ albo ta reguÅa,
              która dopasowaÅa siÄ do takiej samej iloÅci tekstu, jak
              poprzednia, lecz wystÄpiÅa później w pliku wejÅciowym fleksa,
              albo taka, która dopasowaÅa siÄ do mniejszej iloÅci tekstu.  Na
              przykÅad, nastÄpujÄcy przykÅad bÄdzie liczyÅ sÅowa wejÅciowe i
              woÅaÅ funkcjÄ special() dla każdego "frob":

                          int word_count = 0;
                  %%

                  frob        special(); REJECT;
                  [^ \t\n]+   ++word_count;

              Bez dyrektywy REJECT, sÅowa "frob" wejÅcia nie byÅyby zliczane
              jako sÅowa, gdyż skaner normalnie wykonuje tylko jednÄ akcjÄ na
              token. Dozwolonych jest wiele komend REJECT, z których każda
              wyszukuje najbardziej pasujÄcego nastÄpcÄ. Na przykÅad poniższy
              skaner skanujÄc token "abcd" zapisze na wyjÅciu "abcdabcaba":

                  %%
                  a        |
                  ab       |
                  abc      |
                  abcd     ECHO; REJECT;
                  .|\n     /* zjedz nietrafione znaki */

              (Pierwsze trzy reguÅy majÄ wspólnÄ akcjÄ z czwartÄ, gdyż
              używajÄ akcji specjalnej '|'.)  REJECT jest doÅÄ kosztownÄ
              wÅaÅciwoÅciÄ jeÅli chodzi o wydajnoÅÄ skanera; jeÅli jest
              używane w którejŠz akcji skanera, to spowolni wszystkie
              dopasowania skanera. Co wiÄcej, REJECT nie może byÄ używany z
              opcjami -Cf i -CF (zobacz niżej).

              Zauważ też, że, w przeciwieÅstwie do innych akcji
              specjalnych, REJECT jest odgaÅÄzieniem; kod akcji wystÄpujÄcy
              bezpoÅrednio po nim nie zostanie wykonany.

       -      yymore() mówi skanerowi, że przy nastÄpnym dopasowaniu reguÅy,
              odpowiadajÄcy token powinien byÄ doklejony do bieżÄcej wartoÅci
              yytext.  Na przykÅad, przy wejÅciu "mega-kludge", poniższy
              przykÅad na wyjÅciu wypisze "mega-mega-kludge":

                  %%
                  mega-    ECHO; yymore();
                  kludge   ECHO;

              Pierwsze "mega-" jest dopasowane i wydrukowane na wyjÅcie.
              NastÄpnie dopasowane jest "kludge", lecz poprzednie "mega-"
              wciÄż znajduje siÄ na poczÄtku yytext i komenda ECHO dla
              "kludge" wydrukuje w rzeczywistoÅci "mega-kludge".

       Dwie uwagi na temat yymore().  Po pierwsze, yymore() zależy od
       wartoÅci yyleng, odzwierciedlajÄcej rozmiar bieżÄcego tokenu. Zatem
       jeÅli używasz yymore(), nie modyfikuj tej zmiennej.  Po drugie,
       obecnoÅÄ yymore() w akcji skanera wpÅywa na pewne pogorszenie
       wydajnoÅci w szybkoÅci dokonywania przez skaner dopasowaÅ.

       -      yyless(n) zwraca wszystkie poza pierwszymi n znakami bieżÄcego
              tokenu z powrotem do strumienia wejÅciowego, skÄd zostanÄ one
              powtórnie przeskanowane przy dopasowywaniu nastÄpnego wzorca.
              yytext i yyleng sÄ odpowiednio dostrajane (tj.  yyleng bÄdzie
              teraz równe n).  Na przykÅad, przy wejÅciu "foobar",
              nastÄpujÄcy kod wypisze "foobarbar":

                  %%
                  foobar    ECHO; yyless(3);
                  [a-z]+    ECHO;

              Podanie yyless argumentu zerowego powoduje reskanowanie caÅego
              obecnego ÅaÅcucha wejÅciowego. O ile nie zmienisz sposobu
              kolejnego przetwarzania przez skaner wejÅcia (przy użyciu np.
              BEGIN), spowoduje to nieskoÅczonÄ pÄtlÄ.

       ZwrÃ³Ä uwagÄ, że yyless jest makrem i może byÄ używane tylko z pliku
       wejÅciowego fleksa, a nie z innych plików źródÅowych.

       -      unput(c) wstawia znak c z powrotem do strumienia wejÅciowego.
              BÄdzie to nastÄpny skanowany znak.  Poniższa akcja pobierze
              bieżÄcy token i spowoduje, że zostanie reskanowany po ujÄciu 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 );
                  }

              ZwrÃ³Ä uwagÄ, że skoro każdy unput() wstawia dany znak na
              poczÄtek strumienia, to wstawianie znaków musi odbywaÄ siÄ
              tyÅem-na-przód.

       Ważnym potencjalnym problemem używania unput() jest fakt, że jeÅli
       używasz dyrektywy %pointer (domyÅlne), wywoÅanie unput() niszczy
       zawartoÅÄ yytext, poczynajÄc od znaku najbardziej z prawej, idÄc w lewo
       za każdym wywoÅaniem.  JeÅli potrzebujesz zachowaÄ wartoÅÄ yytext po
       użyciu tej funkcji, (jak w powyższym przykÅadzie), musisz skopiowaÄ
       jej zawartoÅÄ gdzie indziej lub zbudowaÄ skaner z użyciem %array.

       Na koniec, zauważ też, że nie możesz wstawiaÄ tak znaków EOF.  Nie
       można tÄ metodÄ zaznaczaÄ koÅca pliku w strumieniu.

       -      input() odczytuje nastÄpny znak ze strumienia wejÅciowego. Na
              przykÅad, poniższe jest jednym ze sposobów pożerania
              komentarzy jÄzyka C:

                  %%
                  "/*"        {
                              register int c;

                              for ( ; ; )
                                  {
                                  while ( (c = input()) != '*' &&
                                          c != EOF )
                                      ;    /* zeżryj tekst komentarza */

                                  if ( c == '*' )
                                      {
                                      while ( (c = input()) == '*' )
                                          ;
                                      if ( c == '/' )
                                          break;    /* znalazÅem koniec */
                                      }

                                  if ( c == EOF )
                                      {
                                      error( "EOF w komentarzu" );
                                      break;
                                      }
                                  }
                              }

              (Zauważ, że jeÅli skaner jest skompilowany z użyciem C++, to
              input() nazywa siÄ yyinput().  Jest tak w celu zapobieżenia
              zderzeniu nazwy ze strumieniem C++ poprzez nazwÄ input.)

       -      YY_FLUSH_BUFFER wypróżnia wewnÄtrzny bufor skanera. Przy
              nastÄpnym razie gdy skaner bÄdzie dopasowywaÅ siÄ do tokenu,
              najpierw napeÅni na nowo bufor z użyciem YY_INPUT (zobacz
              niżej Generowany Skaner).  Akcja ta jest szczególnym
              przypadkiem bardziej ogólnej funkcji yy_flush_buffer(),
              opisanej niżej w sekcji Wielokrotne Bufory WejÅciowe.

       -      yyterminate() może byÄ używane zamiast instrukcji return
              akcji. KoÅczy dziaÅanie skanera i zwraca 0 do wywoÅujÄcego
              skaner, wskazujÄc, że "wszystko zrobione".  DomyÅlnie,
              yyterminate() jest wywoÅywane również po napotkaniu koÅca
              pliku. Jest to makro i może byÄ redefiniowane.

GENEROWANY SKANER
       Wynikiem dziaÅania fleksa jest plik lex.yy.c, zawierajÄcy procedurÄ
       skanujÄcÄ yylex() oraz zestaw tablic, używanych przez niego do
       dopasowywania tokenów i parÄ procedur i makr. DomyÅlnie yylex() jest
       deklarowany jako

           int yylex()
               {
               ... tu różne definicje i akcje ...
               }

       (JeÅli twoje Årodowisko obsÅuguje prototypy funkcji, to bÄdzie to "int
       yylex( void )".) DefinicjÄ tÄ można zmieniÄ definiujÄc makro
       "YY_DECL". Na przykÅad

           #define YY_DECL float lexscan( a, b ) float a, b;

       informuje fleksa, by nadaÄ procedurze skanujÄcej nazwÄ lexscan i że
       procedura ta ma zwracaÄ typ float i pobieraÄ dwa argumenty (też typu
       float). ZwrÃ³Ä uwagÄ, że jeÅli podajesz argumenty procedurze
       skanujÄcej, używajÄc deklaracji w niezaprototypowanym stylu K&R,
       musisz zakoÅczyÄ definicjÄ Årednikiem (;).

       Przy każdym wywoÅaniu yylex(), nastÄpuje skanowanie tokenów z
       globalnego pliku wejÅciowego yyin (który domyÅlnie wskazuje na stdin).
       Wczytywanie trwa aż do osiÄgniÄcia koÅca pliku, lub aż do napotkania
       w którejŠz akcji instrukcji return.

       JeÅli skaner osiÄga koniec pliku, to kolejne wywoÅania sÄ
       niezdefiniowane.  Sposobem na skorygowanie tego jest przekierowanie
       yyin na nowy plik wejÅciowy (w tym wypadku skanowanie nastÄpuje z
       nowego pliku) lub wywoÅanie yyrestart().  yyrestart() pobiera jeden
       argument: wskaźnik FILE * (który może byÄ nil, jeÅli ustawiÅeÅ
       YY_INPUT na skanowanie ze źródÅa innego niż yyin), i inicjalizuje
       yyin na poczÄtek tego pliku. W zasadzie nie ma różnicy miÄdzy zwykÅym
       przypisaniem yyin do nowego pliku i użyciem yyrestart(); Procedura ta
       jest dostÄpna z uwagi na kompatybilnoÅÄ z poprzednimi wersjami flex, a
       także dlatego, że może byÄ używana do przeÅÄczania plików
       wejÅciowych w Årodku skanowania.  Może byÄ też używana do porzucania
       bieżÄcego bufora wejÅciowego poprzez wywoÅanie z argumentem yyin;
       lepszym rozwiÄzaniem jest jednak użycie YY_FLUSH_BUFFER (patrz
       wyżej).  Zauważ, że yyrestart() nie resetuje warunku poczÄtkowego na
       INITIAL (zobacz niżej Warunki PoczÄtkowe).

       JeÅli yylex() koÅczy skanowanie z powodu wywoÅania instrukcji return w
       jednej z akcji, skaner może byÄ woÅany ponownie i wznowi dziaÅanie
       tam, gdzie skoÅczyÅ.

       DomyÅlnie (i dla celów wydajnoÅci) skaner zamiast pojedynczych getc()
       wykonuje odczyty blokowe z yyin.  Sposób pobierania wejÅcia może byÄ
       kontrolowany przez definiowanie makra YY_INPUT.  Sekwencja wywoÅujÄca
       YY_INPUT to "YY_INPUT(buf,wynik,max_rozmiar)".  Jej wynikiem jest
       umieszczenie co najwyżej max_rozmiar znaków w tablicy znakowej buf i
       zwrócenie w zmiennej caÅkowitej wynik albo liczby wczytanych znaków
       albo staÅej YY_NULL (0 w systemach uniksowych), okreÅlajÄcej EOF.
       DomyÅlnie, YY_INPUT czyta z globalnego wskaźnika "yyin".

       PrzykÅadowa definicja YY_INPUT (w sekcji definicji pliku wejÅciowego):

           %{
           #define YY_INPUT(buf,wynik,max_rozmiar) \
               { \
               int c = getchar(); \
               wynik = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
               }
           %}

       Definicja ta zmieni przetwarzanie wejÅcia tak, by naraz pojawiaÅ siÄ
       tylko jeden znak.

       W momencie, gdy skaner uzyska od YY_INPUT warunek koÅca pliku, to woÅa
       funkcjÄ yywrap().  JeÅli yywrap() zwróci zero, to zakÅada, że funkcja
       poszÅa dalej i skonfigurowaÅa yyin do wskazywania na nowy plik, a
       skanowanie trwa dalej. JeÅli zwróci wartoÅÄ niezerowÄ, skaner koÅczy
       dziaÅanie, zwracajÄc 0 do funkcji wywoÅujÄcej.  Zauważ, że w każdym
       przypadku warunek poczÄtkowy pozostaje niezmieniony; nie przechodzi on
       w INITIAL.

       JeÅli nie chcesz podawaÄ wÅasnej wersji yywrap(), to musisz albo użyÄ
       opcji %option noyywrap (wtedy skaner zachowuje siÄ, jakby yywrap()
       zwracaÅo 1), albo konsolidowaÄ z -lfl, uzyskujÄc tak domyÅlnÄ wersjÄ
       funkcji, zawsze zwracajÄcej 1.

       Do skanowania z buforów pamiÄciowych (a nie z plików) przeznaczone sÄ
       trzy procedury: yy_scan_string(), yy_scan_bytes() oraz
       yy_scan_buffer().  Zobacz niżej dyskusjÄ w sekcji Wielokrotne Bufory
       WejÅciowe.

       Swoje wyjÅcie ECHO skaner zapisuje do globalnego strumienia yyout
       (domyÅlnie stdout), który można przedefiniowaÄ dziÄki zwykÅemu
       przypisaniu tej zmiennej do innego wskaźnika FILE.

WARUNKI POCZÄTKOWE
       flex daje mechanizm warunkowej aktywacji reguÅ. ReguÅy rozpoczynajÄce
       siÄ od "<sc>" wÅÄczÄ siÄ tylko jeÅli skaner znajduje siÄ w warunku
       poczÄtkowym "sc". Na przykÅad,

           <STRING>[^"]*        { /* zjedz ciaÅo ÅaÅcucha ... */
                       ...
                       }

       bÄdzie aktywne tylko jeÅli skaner jest w warunku poczÄtkowym "STRING",
       a

           <INITIAL,STRING,QUOTE>\.        { /* obsÅuż cytowanie ... */
                       ...
                       }

       bÄdzie aktywne tylko jeÅli obecnym warunkiem poczÄtkowym jest albo
       "INITIAL", albo "STRING" albo "QUOTE".

       Warunki poczÄtkowe sÄ deklarowane w sekcji definicji wejÅcia przy
       użyciu niewciÄtych linii, zaczynajÄcych siÄ od %s lub %x, za którymi
       nastÄpuje lista nazw.  Pierwsza postaÄ deklaruje wÅÄczajÄce warunki
       poczÄtkowe, a druga wykluczajÄce.  Warunek poczÄtkowy wÅÄcza siÄ przy
       użyciu akcji BEGIN.  ReguÅy używajÄce danego warunku poczÄtkowego
       bÄdÄ aktywne aż do wywoÅania nastÄpnej akcji BEGIN.  JeÅli warunek
       poczÄtkowy jest wÅÄczajÄcy , to reguÅy bez warunków poczÄtkowych bÄdÄ
       również aktywne.  JeÅli jest wykluczajÄcy, to wykonywane bÄdÄ tylko
       reguÅy odpowiadajÄce warunkowi poczÄtkowemu.  Zestaw reguÅ opierajÄcych
       siÄ na tym samym wykluczajÄcym warunku poczÄtkowym, opisuje skaner,
       który jest niezależny od wszelkich innych reguÅ wejÅcia fleksa.  Z
       uwagi na to, warunki wykluczajÄce uÅatwiajÄ tworzenie "mini-skanerów",
       które skanujÄ czÄÅci wejÅcia, odmienne syntaktycznie od reszty (np.
       komentarze).

       W rozróżnieniu warunków wÅÄczajÄcych i wykluczajÄcych istnieje
       wciÄż pewna niejasnoÅÄ: oto przykÅad, ilustrujÄcy ich powiÄzanie.
       Zestaw reguÅ:

           %s przyklad
           %%

           <przyklad>foo  rob_cos();

           bar            cos_innego();

       jest równoważny

           %x przyklad
           %%

           <przyklad>foo   rob_cos();

           <INITIAL,przyklad>bar    cos_innego();

       Bez użycia kwalifikatora <INITIAL,przyklad>, wzorzec bar w drugim
       przykÅadzie nie byÅby aktywny (tj. nie dopasowaÅby siÄ) w warunku
       poczÄtkowym przyklad.  JeÅli użylibyÅmy do kwalifikowania bar tylko
       <przyklad>, to byÅoby aktywny tylko w warunku poczÄtkowym przyklad, ale
       nie w INITIAL, podczas gdy w pierwszym przykÅadzie jest aktywny w
       obydwu, gdyż warunek poczÄtkowy przyklad jest w nim wÅÄczajÄcy (%s).

       Zauważ też, że specjalny specyfikator <*> pasuje do dowolnego
       warunku poczÄtkowego. Tak wiÄc, powyższe można zapisaÄ również
       nastÄpujÄco:

           %x przyklad
           %%

           <przyklad>foo   rob_cos();

           <*>bar    cos_innego();


       ReguÅa domyÅlna (wykonywania ECHO na każdym niedopasowanym znaku)
       pozostaje aktywna w warunkach poczÄtkowych.  Jest to w sumie
       równoważne:

           <*>.|\n     ECHO;


       BEGIN(0) zwraca do stanu oryginalnego, w którym aktywne sÄ tylko
       reguÅy bez warunku poczÄtkowego. Stan ten jest oznaczany jako warunek
       poczÄtkowy "INITIAL", wiÄc można go ustawiÄ również poprzez
       BEGIN(INITIAL).  (Nawiasy wokóŠnazwy warunku poczÄtkowego nie sÄ
       wymagane, lecz sÄ w dobrym tonie.)

       Akcje BEGIN mogÄ byÄ podawane jako kod wciÄty na poczÄtku sekcji reguÅ.
       Na przykÅad, nastÄpujÄcy kod spowoduje, że skaner wejdzie w warunek
       poczÄtkowy "SPECIAL" za każdym razem, gdy wywoÅane zostanie yylex() a
       zmienna globalna enter_special bÄdzie ustawiona na prawdÄ:

                   int enter_special;

           %x SPECIAL
           %%
                   if ( enter_special )
                       BEGIN(SPECIAL);

           <SPECIAL>blahblahblah
           ...i kolejne ruguÅy...


       Dla zilustrowania wykorzystania warunków poczÄtkowych, oto skaner,
       który daje dwie różne interpretacje ÅaÅcucha "123.456". DomyÅlnie
       bÄdzie traktowaÅ go jako 3 elementy, liczbÄ caÅkowitÄ 123, kropkÄ i
       liczbÄ caÅkowitÄ "456".  JeÅli jednak ÅaÅcuch zostanie poprzedzony
       liniÄ z napisem "expect-floats", to bÄdzie go traktowaÅ jako pojedynczy
       element zmiennoprzecinkowy (123.456).

           %{
           #include <math.h>
           %}
           %s expect

           %%
           expect-floats        BEGIN(expect);

           <expect>[0-9]+"."[0-9]+      {
                       printf( "znalazÅem zmiennoprzecinkowÄ, = %f\n",
                               atof( yytext ) );
                       }
           <expect>\n           {
                       /* jest to koniec linii, wiÄc
                        * potrzebujemy kolejnego "expect-number"
                        * przed rozpoznawaniem dalszych liczb
                        */
                       BEGIN(INITIAL);
                       }

           [0-9]+      {
                       printf( "znalazÅem caÅkowitÄ, = %d\n",
                               atoi( yytext ) );
                       }

           "."         printf( "znalazÅem kropkÄ\n" );

       Oto skaner, który 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 których nie ma '/' */
           <comment>\n             ++line_num;
           <comment>"*"+"/"        BEGIN(INITIAL);

       Skaner ten może mieÄ problemy z dopasowaniem maksymalnej iloÅci tekstu
       w każdej z reguÅ. Ogólnie, przy pisaniu szybkich skanerów, próbuj
       dopasowywaÄ w każdej regule tyle, ile siÄ da.

       Zauważ, że nazwy warunków poczÄtkowych sÄ tak naprawdÄ wartoÅciami
       caÅkowitymi i mogÄ byÄ tak przechowywane. Tak wiÄc powyższe można
       rozwinÄÄ w nastÄpujÄcym 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 których nie ma '/' */
           <comment>\n             ++line_num;
           <comment>"*"+"/"        BEGIN(comment_caller);

       Co wiÄcej, możesz mieÄ dostÄp do bieżÄcego warunku poczÄtkowego
       poprzez makro YY_START (o wartoÅci caÅkowitej).  Na przykÅad, powyższe
       przypisania do comment_caller można by zapisaÄ jako

           comment_caller = YY_START;

       Flex jako alias do YY_START daje YYSTATE (gdyż jest to nazwa, używana
       przez AT&T lex).

       Zauważ, że warunki poczÄtkowe nie majÄ wÅasnej przestrzeni nazw; %s i
       %x-y deklarujÄ nazwy podobnie jak #define.

       Na deser, oto przykÅad dopasowywania cytowanych w stylu C napisów przy
       użyciu wykluczajÄcych warunków poczÄtkowych, wÅÄcznie z rozwijanymi
       sekwencjami specjalnymi (lecz bez sprawdzania czy ÅaÅcuch nie jest za
       dÅugi):

           %x str

           %%
                   char string_buf[MAX_STR_CONST];
                   char *string_buf_ptr;


           \"      string_buf_ptr = string_buf; BEGIN(str);

           <str>\"        { /* zobaczyÅem zamykajÄcy cytat - gotowe */
                   BEGIN(INITIAL);
                   *string_buf_ptr = '\0';
                   /* zwrÃ³Ä typ i wartoÅÄ tokenu staÅej ÅaÅcuchowej do
                    * analizatora
                    */
                   }

           <str>\n        {
                   /* bÅÄd - niezakoÅczona staÅa ÅaÅcuchowa */
                   /* generuj komunikat o bÅÄdzie */
                   }

           <str>\\[0-7]{1,3} {
                   /* ósemkowa sekwencja specjalna */
                   int result;

                   (void) sscanf( yytext + 1, "%o", &result );

                   if ( result > 0xff )
                           /* bÅÄd, staÅa poza zakresem */

                   *string_buf_ptr++ = result;
                   }

           <str>\\[0-9]+ {
                   /* generuj bÅÄd - zÅa 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++;
                   }


       CzÄsto, np. w niektórych przykÅadach powyżej można skoÅczyÄ piszÄc
       grupÄ reguÅ, rozpoczynajÄcych siÄ od tych samych warunków
       poczÄtkowych. Flex uÅatwia caÅoÅÄ wprowadzajÄc pojÄcie zakresu warunku
       poczÄtkowego.  Zakres rozpoczyna siÄ od:

           <SCs>{

       gdzie SCs jest listÄ jednego lub wiÄcej warunków poczÄtkowych.
       WewnÄtrz zakresu warunku poczÄtkowego każda reguÅa dostaje
       automatycznie przedrostek <SCs> aż do napotkania '}', który odpowiada
       startowemu '{'.  W ten sposób na przykÅad

           <ESC>{
               "\\n"   return '\n';
               "\\r"   return '\r';
               "\\f"   return '\f';
               "\\0"   return '\0';
           }

       jest równoważne:

           <ESC>"\\n"  return '\n';
           <ESC>"\\r"  return '\r';
           <ESC>"\\f"  return '\f';
           <ESC>"\\0"  return '\0';

       Zakresy warunków poczÄtkowych mogÄ byÄ zagnieżdżane.

       Do obsÅugi stosów warunków poczÄtkowych sÄ przeznaczone trzy
       procedury:

       void yy_push_state(int new_state)
              wrzuca bieżÄcy warunek poczÄtkowy na stos warunków
              poczÄtkowych i przeÅÄcza siÄ w stan new_state, zupeÅnie jak po
              użyciu BEGIN new_state (pamiÄtaj, że nazwy warunków
              poczÄtkowych sÄ również liczbami caÅkowitymi).

       void yy_pop_state()
              zdejmuje wartoÅÄ ze stosu i przeÅÄcza siÄ na niÄ przez BEGIN.

       int yy_top_state()
              zwraca wierzchoÅek stosu bez zmiany zawartoÅci stosu.

       Stos warunków poczÄtkowych roÅnie dynamicznie i nie ma żadnych
       wbudowanych ograniczeÅ. Po wyczerpaniu pamiÄci, wykonywanie programu
       jest przerywane.

       Aby korzystaÄ ze stosów warunków poczÄtkowych, skaner musi zawieraÄ
       dyrektywÄ %option stack (zobacz niżej rozdziaÅ Opcje).

WIELOKROTNE BUFORY WEJÅCIOWE
       Niektóre skanery (te, obsÅugujÄce pliki doÅÄczane "include") wymagajÄ
       odczytu z wielu strumieni wejÅciowych. Ponieważ skanery flex wykonujÄ
       sporo buforowania, nie można jednoznacznie zdecydowaÄ skÄd bÄdzie
       wykonywany nastÄpny odczyt przez proste napisanie YY_INPUT, które jest
       wrażliwe na kontekst skanowania.  YY_INPUT wywoÅywane jest tylko gdy
       skaner osiÄga koniec swojego bufora, który może byÄ daleko po
       wyskanowaniu instrukcji takiej jak "include", wymagajÄcej przeÅÄczenia
       źródÅa wejÅcia.

       Aby zaÅatwiÄ niektóre z tych problemów, flex daje mechanizm tworzenia
       i przeÅÄczania miÄdzy wielokrotnymi buforami wejÅciowymi. Bufor
       wejÅciowy jest tworzony z użyciem funkcji

           YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )

       która pobiera wskaźnik FILE i rozmiar size, a nastÄpnie tworzy bufor
       zwiÄzany z danym plikiem, którego wielkoÅÄ (w znakach) jest okreÅlona
       parametrem rozmiaru.  (w razie wÄtpliwoÅci użyj YY_BUF_SIZE jako
       rozmiaru). Funkcja zwraca uchwyt YY_BUFFER_STATE, który może byÄ
       potem przekazywany do innych procedur (zobacz niżej). Typ
       YY_BUFFER_STATE jest wskaźnikiem do struktury struct yy_buffer_state
       wiÄc można bezpiecznie inicjalizowaÄ zmienne YY_BUFFER_STATE na
       ((YY_BUFFER_STATE) 0) i odnosiÄ siÄ do struktury w celu poprawnego
       zadeklarowania buforów wejÅciowych w plikach źródÅowych innych niż
       ten od twojego skanera. Zauważ, że wskaźnik FILE w wywoÅaniu
       yy_create_buffer jest używany tylko jako wartoÅÄ yyin widzianego przez
       YY_INPUT; jeÅli redefiniujesz YY_INPUT tak, żeby nie używaÅo yyin, to
       możesz spokojnie przekazaÄ tu zerowy wskaźnik FILE.  Zadany bufor do
       skanowania wybiera siÄ za pomocÄ:

           void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )

       co przeÅÄcza bufor wejÅciowy skanera tak, że kolejne tokeny bÄdÄ
       pochodziÅy z bufora new_buffer.  Zauważ, że yy_switch_to_buffer()
       może byÄ używane przez yywrap() do zestawiania różnych rzeczy we
       wznowionym skanowaniu zamiast otwierania nowego pliku i ustawiania na
       nim yyin.  Zauważ też, że przeÅÄczanie źródeÅ wejÅciowych przez
       yy_switch_to_buffer() lub yywrap() nie zmienia warunku poczÄtkowego.

           void yy_delete_buffer( YY_BUFFER_STATE buffer )

       używane jest do odzyskania miejsca zwiÄzanego z buforem ( buffer może
       byÄ wartoÅciÄ nil, ale wtedy funkcja ta nic nie robi.)  Można też
       czyÅciÄ bieżÄcÄ zawartoÅÄ bufora, stosujÄc:

           void yy_flush_buffer( YY_BUFFER_STATE buffer )

       Funkcja ta niszczy zawartoÅÄ bufora, wiÄc przy nastÄpnej próbie
       dopasowania tokenu z bufora, skaner najpierw wypeÅni bufor na nowo
       używajÄc YY_INPUT.

       yy_new_buffer() jest synonimem yy_create_buffer(), udostÄpnionym dla
       zgodnoÅci z C++ narzÄdziami new i delete, sÅużÄcymi do tworzenia i
       niszczenia obiektów dynamicznych.

       Na koniec makro YY_CURRENT_BUFFER zwraca uchwyt YY_BUFFER_STATE do
       bieżÄcego bufora.

       A oto przykÅad używania tych wÅaÅciwoÅci w skanerze, rozwijajÄcym
       pliki zaÅÄczane (wÅaÅciwoÅÄ <<EOF>> jest opisywana niżej):

           /* stan "incl" jest używany do wybierania nazwy zaÅÄczanego 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 biaÅÄ spacjÄ */
           <incl>[^ \t\n]+   { /* mam nazwÄ pliku zaÅÄcznika */
                   if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
                       {
                       fprintf( stderr, "Zbyt zagnieżdżone zaÅÄczniki" );
                       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 buforów wejÅciowych dla skanowania ÅaÅcuchów z pamiÄci
       zamiast plików istniejÄ trzy procedury. Każda z nich tworzy nowy
       bufor wejÅciowy do skanowania ÅaÅcucha i zwraca odpowiadajÄcy uchwyt
       YY_BUFFER_STATE (który powinieneÅ skasowaÄ stosujÄc yy_delete_buffer()
       po zakoÅczeniu dziaÅania). PrzeÅÄczajÄ one też przetwarzanie na nowy
       bufor przy użyciu yy_switch_to_buffer(), wiÄc nastÄpne wywoÅanie
       yylex() rozpocznie skanowanie ÅaÅcucha.

       yy_scan_string(const char *str)
              skanuje ÅaÅcuch zakoÅczony zerem.

       yy_scan_bytes(const char *bytes, int len)
              skanuje len bajtów (dopuszczalne zera w Årodku) poczÄwszy od
              pozycji bytes.

       Zauważ, że obydwie funkcje tworzÄ i skanujÄ kopie oryginalnych
       danych. (Jest to pożÄdane, gdyż yylex() modyfikuje zawartoÅÄ
       skanowanego bufora.) Kopiowania można uniknÄÄ, stosujÄc:

       yy_scan_buffer(char *base, yy_size_t size)
              które skanuje bufor na miejscu, zaczynajÄc od base, a w
              dÅugoÅci size bajtów, z których dwa bajty muszÄ byÄ znakami
              YY_END_OF_BUFFER_CHAR (ASCII NUL).  Ostatnie dwa bajty nie sÄ
              skanowane; tak wiÄc skanowanie przebiega od base[0] do
              base[size-2] wÅÄcznie.

              JeÅli nie ustawisz odpowiednio base to yy_scan_buffer() zwraca
              wskaźnik nil zamiast tworzyÄ nowy bufor wejÅciowy.

              Typ yy_size_t jest typem caÅkowitym, na który rzutuje siÄ
              wyrażenie caÅkowite, okreÅlajÄce rozmiar bufora.

REGUÅY END-OF-FILE
       Specjalna reguÅa "<<EOF>>" okreÅla akcje, które należy wykonaÄ po
       osiÄgniÄciu koÅca pliku i gdy yywrap() zwraca zero (tj. wskazuje brak
       dalszych plików do przetworzenia). Akcja musi siÄ zakoÅczyÄ zrobieniem
       jednej z czterech rzeczy:

       -      przypisaniem yyin do nowego pliku wejÅciowego (w poprzednich
              wersjach fleksa po dokonaniu przypisania należaÅo wywoÅaÄ
              specjalnÄ akcjÄ YY_NEW_FILE; nie jest to już wymagane);

       -      wywoÅaniem instrukcji return;

       -      wywoÅaniem specjalnej akcji yyterminate();

       -      przeÅÄczeniem na nowy bufor za pomocÄ yy_switch_to_buffer().

       ReguÅy <<EOF>> nie mogÄ byÄ używane z innymi wzorcami; mogÄ one byÄ
       kwalifikowane jedynie listÄ warunków poczÄtkowych. JeÅli podana jest
       niekwalifikowana reguÅa <<EOF>>, to dotyczy ona wszystkich warunków
       poczÄtkowych, które nie majÄ jeszcze akcji <<EOF>>. Aby podaÄ reguÅÄ
       <<EOF>> tylko dla poczÄtkowego warunku poczÄtkowego użyj

           <INITIAL><<EOF>>


       Te reguÅy przydatne sÄ do Åapania rzeczy takich, jak niezamkniÄte
       cytaty. PrzykÅad:

           %x quote
           %%

           ...inne reguÅy cytatowe...

           <quote><<EOF>>   {
                    error( "nie zamkniÄty cytat" );
                    yyterminate();
                    }
           <<EOF>>  {
                    if ( *++filelist )
                        yyin = fopen( *filelist, "r" );
                    else
                       yyterminate();
                    }


RÃÅ»NE MAKRA
       Można zdefiniowaÄ makro YY_USER_ACTION, które sÅuży do podania akcji
       wykonywanej zawsze przed akcjÄ dopasowanej reguÅy. Na przykÅad może
       byÄ #definiowane do wywoÅywania procedury konwertujÄcej yytext na maÅe
       litery.  Gdy wywoÅywane jest YY_USER_ACTION, zmienna yy_act okreÅla
       numer dopasowanej reguÅy (reguÅy sÄ numerowane od 1). ZaÅóżmy, że
       chcesz wyprofilowaÄ jak czÄsto jest używana każda z reguÅ.
       RozwiÄzaniem jest nastÄpujÄcy kawaÅek kodu:

           #define YY_USER_ACTION ++ctr[yy_act]

       gdzie ctr jest tablicÄ przechowujÄcÄ zawartoÅÄ różnych reguÅ.
       Zauważ, że makro YY_NUM_RULES daje ogólnÄ liczbÄ reguÅ (ÅÄcznie z
       reguÅÄ domyÅlnÄ, nawet jeÅli używasz -s), wiÄc poprawnÄ deklaracjÄ ctr
       jest:

           int ctr[YY_NUM_RULES];


       Makro YY_USER_INIT sÅuży do podania akcji, która bÄdzie wykonywana
       zawsze przed pierwszym skanem (i przed wewnÄtrznymi inicjalizacjami
       skanera). Na przykÅad można to wykorzystaÄ do woÅania procedury
       czytajÄcej tablice danych lub otwierajÄcej plik raportowy.

       Makro yy_set_interactive(is_interactive) może byÄ używane do
       sterowania czy bieżÄcy bufor jest uważany za interaktywny.  Bufor
       interaktywny jest przetwarzany wolniej, lecz musi byÄ używany gdy
       wejÅcie rzeczywiÅcie jest interaktywne. Zapobiega to problemom
       zwiÄzanym z oczekiwaniem na wypeÅnienie buforów (zobacz niżej
       dyskusjÄ flagi -I).  WartoÅÄ niezerowa w wywoÅaniu makra zaznacza bufor
       jako interaktywny, a zero to wyÅÄcza. Zauważ, że użycie tego makra
       przesÅania %option always-interactiv lub %option never-interactive
       (zobacz niżej Opcje).  Przed rozpoczÄciem skanowania bufora, który
       jest (lub nie jest) interaktywny, należy wywoÅaÄ funkcjÄ
       yy_set_interactive().

       Makro yy_set_bol(at_bol) może byÄ wykorzystywane do sterowania czy
       bieżÄcy kontekst skanujÄcy bufora dla nastÄpnego dopasowania tokena
       jest dokonywany jak gdyby od poczÄtku linii. Niezerowa wartoÅÄ
       argumentu powoduje, że reguÅy zakotwiczone w '^' stajÄ siÄ aktywne, a
       wartoÅÄ zerowa je dezaktywuje.

       Makro YY_AT_BOL() zwraca prawdÄ jeÅli nastÄpny token skanowany z
       bieżÄcego bufora bÄdzie miaÅ aktywne reguÅy '^'. W przeciwnym wypadku
       zwraca faÅsz.

       W niektórych generowanych skanerach akcje sÄ zebrane wszystkie w jednÄ
       wielkÄ instrukcjÄ switch i sÄ rozdzielone makrem YY_BREAK, które
       można redefiniowaÄ. DomyÅlnie jest to po prostu "break".
       Redefiniowanie YY_BREAK umożliwia użytkownikom C++ zadeklarowanie, by
       makro nie robiÅo niczego (uważajÄc przy tym szczególnie, by każda
       reguÅa koÅczyÅa siÄ instrukcjÄ "break" lub "return"!). Można tak
       zapobiec cierpieniom spowodowanym ostrzeżeniami o tym, że przez
       zakoÅczenie akcji reguÅy instrukcjÄ return, YY_BREAK jest nieosiÄgalne.

WARTOÅCI DOSTÄPNE DLA UÅ»YTKOWNIKA
       Sekcja ta zestawia różne wartoÅci dostÄpne dla użytkownika w akcjach
       reguÅowych.

       -      char *yytext zawiera bieżÄcy tekst tokenu. Może byÄ
              modyfikowany, lecz nie może byÄ wydÅużany (nie można doklejaÄ
              dodatkowych znaków na koÅcu).

              JeÅli w pierwszej sekcji opisu skanera pojawi siÄ dyrektywa
              specjalna %array to yytext zostanie zadeklarowane jako
              charyytext[YYLMAX], gdzie YYLMAX jest makrodefinicjÄ, którÄ
              można przedefiniowaÄ w pierwszej sekcji (wartoÅÄ domyÅlna to
              ogólnie 8KB). Używanie %array daje wolniejsze skanery, lecz
              wartoÅÄ yytext staje siÄ odporna na wywoÅania input() i unput(),
              które potencjalnie niszczÄ jego wartoÅÄ kiedy yytext jest
              wskaźnikiem znakowym. PrzeciwnÄ dyrektywÄ do %array jest
              %pointer, która jest dyrektywÄ domyÅlnÄ.

              Dyrektywy %array nie można używaÄ do generowania klas skanera
              C++ (flaga -+).

       -      int yyleng przechowuje dÅugoÅÄ bieżÄcego tokenu.

       -      FILE *yyin jest plikiem, z którego flex domyÅlnie odczytuje
              wejÅcie. Może byÄ redefiniowany, lecz taki zabieg ma sens tylko
              nim rozpocznie siÄ skanowanie lub po napotkaniu EOF. Zmienianie
              tej wartoÅci w Årodku skanowania może daÄ nieoczekiwane
              rezultaty spowodowane buforowaniem wejÅcia. Zamiast tego użyj
              wtedy yyrestart().  Po zakoÅczeniu skanowania przez napotkanie
              koÅca pliku, można przypisaÄ wartoÅÄ yyin do nowego pliku
              wejÅciowego i wywoÅaÄ ponownie skaner by dokoÅczyÅ skanowanie.

       -      void yyrestart( FILE *new_file ) może byÄ woÅane do wskazywania
              yyin na nowy plik wejÅciowy. PrzeÅÄczenie na nowy plik jest
              natychmiastowe (wszelkie poprzednio buforowane wejÅcie jest
              tracone). Zauważ, że woÅanie yyrestart() z argumentem yyin
              porzuca bieżÄcy bufor wejÅciowy i kontynuuje skanowanie tego
              samego pliku wejÅciowego.

       -      FILE *yyout jest plikiem, do którego kierowane jest wyjÅcie
              akcji ECHO.  Użytkownik może mu przypisaÄ innÄ wartoÅÄ.

       -      YY_CURRENT_BUFFER zwraca uchwyt YY_BUFFER_STATE do bieżÄcego
              bufora.

       -      YY_START zwraca wartoÅÄ caÅkowitÄ, odpowiadajÄcÄ bieżÄcemu
              warunkowi poczÄtkowemu.  WartoÅci tej można używaÄ dalej z
              BEGIN do powrotu do tego warunku.

ÅÄCZENIE Z YACC
       Jednym z podstawowych zastosowaÅ fleksa jest wspóÅtowarzyszenie
       generatorowi analizatorów yacc.  Analizatory skÅadni yacc oczekujÄ
       wywoÅania procedury o nazwie yylex() celem znalezienia kolejnego tokenu
       wejÅciowego. Procedura powinna zwróciÄ typ nastÄpnego tokenu oraz
       wstawiÄ zwiÄzanÄ z nim wartoÅÄ do globalnej zmiennej yylval.  Aby
       używaÄ fleksa z yaccem, należy yaccowi przekazaÄ  opcjÄ -d, co każe
       mu generowaÄ plik y.tab.h zawierajÄcy definicje wszystkich
       %tokenów(%tokens) pojawiajÄcych siÄ w wejÅciu yacc.  Plik ten jest
       nastÄpnie zaÅÄczany do skanera fleksowego.  Na przykÅad jeÅli jednym z
       tokenów jest "TOK_NUMBER", to czÄÅÄ skanera może wyglÄdaÄ tak:

           %{
           #include "y.tab.h"
           %}

           %%

           [0-9]+        yylval = atoi( yytext ); return TOK_NUMBER;


OPCJE
       flex ma nastÄpujÄce opcje:

       -b     Generuje informacje zapasowe do lex.backup.  Oto lista stanów
              skanera, które wymagajÄ kopii zapasowych oraz znaki wejÅciowe
              dla których to zachodzi. DodajÄc reguÅy można usunÄÄ stany
              zapasowe. JeÅli wyeliminowane zostanÄ wszystkie stany zapasowe,
              a użyte bÄdzie -Cf lub -CF, wygenerowany skaner bÄdzie dziaÅaÅ
              szybciej (zobacz flagÄ -p).  OpcjÄ to powinni siÄ martwiÄ
              jedynie użytkownicy wyciskajÄcy ostatnie poty ze swoich
              skanerów. (Zobacz sekcjÄ o Rozważaniach nad WydajnoÅciÄ.)

       -c     nieużywana i niezalecana opcja dla zgodnoÅci z POSIX-em.

       -d     powoduje, że generowany skaner dziaÅa w trybie debug.  Za
              każdym razem po rozpoznaniu wzorca, gdy globalna zmienna
              yy_flex_debug jest niezerowa (co jest domyÅlne), skaner zapisze
              na stderr liniÄ w postaci:

                  --accepting rule at line 53 ("dopasowany tekst")

              Numer linii odnosi siÄ do poÅożenia reguÅy w pliku definiujÄcym
              skaner (tj.  w pliku, potraktowanym fleksem). Komunikaty sÄ
              również generowane gdy skaner robi kopie zapasowe, przyjmuje
              domyÅlnÄ reguÅÄ, dochodzi do koÅca bufora (lub napotyka NUL; w
              tym momencie obydwa [zdarzenia] wyglÄdajÄ jednakowo z punktu
              widzenia skanera) lub osiÄga koniec pliku.

       -f     okreÅla szybki skaner.  Nie dokonywana jest kompresja tabel i
              pomijane jest stdio. W efekcie kod jest duży, lecz szybki.
              Opcja ta jest równoważna -Cfr (zobacz niżej).

       -h     generuje zestawienie "pomocy" opcji fleksa na stdout i koÅczy
              dziaÅanie.  -?  i --help sÄ równoważnikami -h.

       -i     nakazuje fleksowi generowania skanera niewrażliwego na wielkoÅÄ
              znaków.  WielkoÅÄ liter we wzorcach zostanie zignorowany, a
              tokeny wejÅcia bÄdÄ dopasowywane niezależnie od wielkoÅci.
              Dopasowany tekst znajdujÄcy siÄ w yytext bÄdzie miaÅ zachowanÄ
              oryginalnÄ wielkoÅÄ liter.

       -l     wÅÄcza maksymalnÄ zgodnoÅÄ z oryginalnÄ implementacjÄ leksa z
              AT&T. Zauważ, że nie oznacza to peÅnej zgodnoÅci. Użycie tej
              opcji kosztuje sporo wydajnoÅci i eliminuje z użycia opcje
              -+,-f,-F,-Cf lub -CF.  Dla szczegóÅów o zapewnianej zgodnoÅci,
              zobacz niżej sekcjÄ o niezgodnoÅciach miÄdzy Leksem i POSIX-em.
              Opcja ta powoduje też z#definiowanie nazwy YY_FLEX_LEX_COMPAT w
              generowanym skanerze.

       -n     kolejna ignorowana opcja dodana dla zgodnoÅci z POSIX-em.

       -p     generuje raport o wydajnoÅci na stderr. Raport skÅada siÄ z
              komentarzy o wÅaÅciwoÅciach pliku wejÅciowego fleksa, wiÄc
              powoduje znacznÄ utratÄ wydajnoÅci skanera. JeÅli podasz tÄ
              flagÄ dwukrotnie, uzyskasz też komentarze o wÅaÅciwoÅciach,
              które doprowadziÅy do drugorzÄdnych utrat wydajnoÅci.

              Zauważ, że użycie REJECT, %option yylineno, i zmiennego
              wiszÄcego kontekstu (variable trailing context) (zobacz  niżej
              sekcjÄ o Niedostatkach / BÅÄdach) powoduje znacznÄ utratÄ
              wydajnoÅci; używanie yymore(), operatora ^ i flagi -I powoduje
              pomniejsze utraty wydajnoÅci.

       -s     powoduje, że domyÅlna reguÅa (powodujÄca echo niedopasowanego
              wejÅcia skanera na stdout) nie jest wykonywana. JeÅli skaner
              napotka wejÅcie, którego nie może dopasowaÄ do reguÅ, przerywa
              dziaÅanie z bÅÄdem. Opcja ta jest przydatna do znajdowania dziur
              w zbiorze reguÅ skanera.

       -t     nakazuje fleksowi zapisanie wygenerowanego skanera na
              standardowe wyjÅcie zamiast do pliku lex.yy.c.

       -v     nakazuje fleksowi pisanie na stderr zestawienia statystyk
              dotyczÄcych generowanego skanera.  WiÄkszoÅÄ statystyk jest
              pozbawiona znaczenia dla typowego użytkownika, lecz pierwsza z
              linijek wskazuje wersjÄ fleksa (to samo co zgÅasza opcja -V), a
              nastÄpna linia flagi użyte do generowania skanera, z domyÅlnymi
              wÅÄcznie.

       -w     powstrzymuje komunikaty o ostrzeżeniach.

       -B     nakazuje fleksowi generowanie skanera wsadowego, czyli
              odwrotnoÅÄ skanerów interaktywnych, generowanych przez -I
              (zobacz niżej). Ogólnie, opcji -B używa siÄ majÄc pewnoÅÄ,
              że skaner nigdy nie bÄdzie używany interaktywnie i chcÄc
              wycisnÄÄ jeszcze troszeczkÄ wiÄcej wydajnoÅci. JeÅli chcesz
              zyskaÄ wiÄcej wydajnoÅci, powinieneÅ użyÄ opcji -Cf lub -CF
              (opisanych niżej), które wÅÄczajÄ -B i tak automatycznie.

       -F     mówi, że należy użyÄ reprezentacji tablicy szybkiego skanera
              (i stdio ma byÄ pominiÄte). Reprezentacja ta jest mniej wiÄcej
              tak szybka jak reprezentacja peÅnej tablicy (-f), i dla
              niektórych zestawów wzorców bÄdzie znacznie mniejsza (a dla
              innych wiÄksza). Ogólnie, jeÅli wzorzec zawiera zarówno "sÅowa
              kluczowe" jak i ÅapiÄcÄ-wszystko reguÅÄ "identyfikatora", tak
              jak poniższy zestaw:

                  "case"    return TOK_CASE;
                  "switch"  return TOK_SWITCH;
                  ...
                  "default" return TOK_DEFAULT;
                  [a-z]+    return TOK_ID;

              to lepiej użyÄ reprezentacji peÅnej tablicy. JeÅli obecna jest
              tylko reguÅa "identyfikatora" i używasz potem hasza lub
              podobnej rzeczy do wykrywania sÅów kluczowych, to lepiej użyÄ
              opcji -F.

              Opcja ta odpowiada -CFr (zobacz niżej).  Nie można jej używaÄ
              z -+.

       -I     nakazuje fleksowi generowanie skanera interaktywnego.  Skaner
              interaktywny patrzy naprzód do wyboru dopasowania jedynie jeÅli
              musi.  Okazuje siÄ, że patrzenie o jeden dodatkowy znak dalej,
              nawet jeÅli skaner ma już doÅÄ do dopasowania tokenu jest
              trochÄ szybsze niż wersja minimalna.  Lecz skanery patrzÄce
              naprzód dajÄ dziadowskÄ wydajnoÅÄ interaktywnÄ; na przykÅad gdy
              użytkownik wpisze nowÄ liniÄ, to nie jest ona rozpoznawana jako
              token nowej linii dopóki nie wprowadzony zostanie nastÄpny
              token, co oznacza czÄsto wpisanie caÅej kolejnej linii.

              Skanery fleksa sÄ domyÅlnie interaktywne, chyba że użyjesz
              opcji kompresji tablicy -Cf lub -CF (zobacz niżej).  Jest tak
              dlatego, że jeÅli oczekujesz wysokiej wydajnoÅci, to powinieneÅ
              użyÄ jednej z tych opcji, a jeÅli tego nie zrobiÅeÅ, flex
              zakÅada, że jesteÅ gotów poÅwiÄciÄ trochÄ wydajnoÅci na rzecz
              intuicyjnego zachowania interaktywnego. Zauważ też, że nie
              możesz użyÄ -I w poÅÄczeniu z -Cf lub -CF.  Z tej przyczyny
              opcja ta nie jest w rzeczywistoÅci wymagana; jest domyÅlnie
              wÅÄczona dla tych przypadków, dla których jest dopuszczalna.

              OpcjÄ -B możesz wymusiÄ by skaner nie byÅ interaktywny (zobacz
              powyżej).

       -L     nakazuje fleksowi nie generowaÄ dyrektyw #line.  Bez tej opcji
              flex przyprawia generowany skaner dyrektywami #line, wiÄc
              komunikaty o bÅÄdach w akcjach bÄdÄ poprawnie poÅożone wzglÄdem
              oryginalnego pliku wejÅciowego fleksa (jeÅli bÅÄdy wynikajÄ z
              kodu w pliku wejÅciowym) lub [wzglÄdem] lex.yy.c (jeÅli bÅÄdy sÄ
              winÄ fleksa -- powinieneÅ zgÅosiÄ takie bÅÄdy pod adres e-mail
              podany poniżej.)

       -T     powoduje, że flex dziaÅa w trybie Åledzenia.  BÄdzie generowaÅ
              na stderr wiele komunikatów o postaci wejÅcia i wynikajÄcych
              zeÅ niedeterministycznych i deterministycznych automatach
              skoÅczonych. Opcja ta jest używana zwykle w opiece nad fleksem.

       -V     drukuje numer wersji na stdout i koÅczy dziaÅanie.  --version
              jest synonimem -V.

       -7     nakazuje fleksowi generowanie skanera 7-bitowego, tj. takiego
              który może rozpoznawaÄ w swoim wejÅciu tylko znaki 7-bitowe.
              ZaletÄ używania -7 jest to, że tablice skanera bÄdÄ o poÅowÄ
              mniejsze niż wygenerowane opcjÄ -8 (zobacz niżej). WadÄ jest
              to, że skanery takie czÄsto siÄ zawieszajÄ lub zaÅamujÄ jeÅli
              na ich wejÅciu znajdzie siÄ znak 8-bitowy.

              Zauważ jednak, że jeÅli generujesz skaner z użyciem opcji
              kompresji tablic -Cf lub -CF, to użycie -7 zachowa jedynie
              niewielki rozmiar przestrzeni tablic, a spowoduje, że skaner
              bÄdzie znaczÄco mniej przenoÅny.  DomyÅlnym zachowaniem fleksa
              jest generowanie skanerów 8-bitowych, chyba że użyto opcji
              -Cf lub -CF, i wtedy flex generuje domyÅlnie skaner 7-bitowy,
              chyba że twoja maszyna zawsze byÅa skonfigurowana na
              generowanie skanerów 8-bitowych (co czÄsto siÄ zdarza poza
              USA). To, czy flex wygenerowaŠskaner 7 czy 8 bitowy, można
              okreÅliÄ, sprawdzajÄc zestawienie flag w wyjÅciu -v, co opisano
              wyżej.

              Zauważ, że jeÅli używasz -Cfe lub -CFe, flex wciÄż domyÅlnie
              generuje skaner 8-bitowy, gdyż po kompresji peÅne tablice
              8-bitowe nie sÄ wiele wiÄksze od 7-bitowych.

       -8     nakazuje fleksowi generowanie skanera 8-bitowego, tj. takiego,
              który rozpoznaje znaki 8-bitowe. Flaga ta jest wymagana jedynie
              dla skanerów wygenerowanych z użyciem -Cf lub -CF, gdyż w
              innych wypadkach jest ona przyjmowana jako domyÅlna.

       -+     okreÅla, że chcesz by fleks wygenerowaÅ klasÄ skanera w C++.
              Zobacz sekcjÄ o generowaniu skanerów C++.

       -C[aefFmr]
              steruje poziomem kompresji tablic, balansujÄc miÄdzy maÅymi a
              szybkimi skanerami.

              -Ca ("wyrównaj") nakazuje fleksowi poÅwiÄciÄ rozmiar tablic w
              wygenerowanych skanerach na rzecz szybkoÅci, gdyż elementy
              tablic mogÄ byÄ lepiej wyrównane pod kÄtem dostÄpu do pamiÄci i
              obliczeÅ. Na niektórych architekturach RISC pobieranie i
              operowanie na dÅugich sÅowach jest efektywniejsze niż na
              mniejszych jednostkach, takich jak krótkie sÅowa. Opcja ta
              może podwoiÄ rozmiar tablic używanych przez twój skaner.

              -Ce Nakazuje fleksowi budowanie klas równoważnoÅci, tj.
              zestawów znaków o identycznych wÅaÅciwoÅciach leksykalnych
              (np. jeÅli jedynym wystÄpieniem cyfr w pliku wejÅciowym fleksa
              jest klasa znaków "[0-9]", to cyfry z przedziaÅy od 0 do 9
              zostanÄ wstawione do tej samej klasy równoważnoÅci. Klasy
              takie zwykle znacznie redukujÄ ostateczne rozmiary
              tablic/obiektów (zwykle 2-5 razy) i sÄ caÅkiem tanie od strony
              wydajnoÅciowej (jedno podglÄdniÄcie w tablicy na skanowany
              znak).

              -Cf okreÅla, że należy generowaÄ peÅne tablice skanera - flex
              nie ma ich kompresowaÄ poprzez branie korzyÅci z podobnych
              funkcji przejÅÄ dla różnych stanów.

              -CF okreÅla, że należy użyÄ alternatywnej, szybkiej
              reprezentacji skanera (opisanej pod flagÄ -F).  Opcja ta nie
              może byÄ używana z -+.

              -Cm nakazuje fleksowi budowanie klas meta-równoważnoÅci,
              które sÄ zbiorami klas równoważnoÅci (lub znaków, jeÅli
              klasy równoważnoÅci nie sÄ używane), które sÄ czÄsto
              używane wspólnie. Klasy takie sÄ czÄsto dobrÄ rzeczÄ podczas
              używania skompresowanych tablic, lecz majÄ one już umiarkowany
              wpÅyw na wydajnoÅÄ (dwa lub jeden test "if" i jedno
              podglÄdniÄcie tablicy na skanowany znak).

              -Cr powoduje, że generowany skaner omija użycie standardowej
              biblioteki I/O dla wejÅcia. Zamiast woÅaÄ fread() lub getc(),
              skaner bÄdzie używaÄ wywoÅania systemowego read(), zyskujÄc tak
              trochÄ na wydajnoÅci (w skali zależnej od systemu). W
              rzeczywistoÅci jest to bez znaczenia, chyba że używasz też
              -Cf lub -CF.  Wykorzystanie -Cr może też spowodowaÄ dziwne
              zachowanie jeÅli np. odczytasz z yyin z pomocÄ stdio przed
              wywoÅaniem skanera (skaner pominie tekst pozostawiony przez
              twoje odczyty w buforze wejÅciowym stdio).

              -Cr nie dziaÅa jeÅli zdefiniujesz YY_INPUT (zobacz wyżej
              Generowany Skaner).

              Samotne -C okreÅla, że tablice skanera powinny byÄ
              kompresowane, lecz nie należy używaÄ klas równoważnoÅci i
              klas metarównoważnoÅci.

              Opcje -Cf lub -CF i -Cm nie majÄ sensu razem - nie ma sytuacji
              dla klas metarównoważnoÅci jeÅli tablica nie jest
              kompresowana. Poza tym opcje można swobodnie ÅÄczyÄ.

              DomyÅlnym ustawieniem jest -Cem, które okreÅla, że flex
              powinien generowaÄ klasy równoważnoÅci i metarównoważnoÅci.
              Ustawienie to daje najwyższy stopieŠkompresji tablic. Kosztem
              wiÄkszych tablic można uzyskaÄ szybciej wykonujÄce siÄ skanery.
              NastÄpujÄce zestawienie jest mniej wiÄcej prawdziwe:

                  najwolniejsze i najmniejsze
                        -Cem
                        -Cm
                        -Ce
                        -C
                        -C{f,F}e
                        -C{f,F}
                        -C{f,F}a
                  najszybsze i najwiÄksze

              Zauważ, że skanery z najmniejszymi tablicami sÄ zwykle
              najszybciej generowane i kompilowane, wiÄc podczas prac
              rozwojowych prawdopodobnie najchÄtniej użyjesz domyÅlnej,
              maksymalnej kompresji.

              -Cfe jest czÄsto dobrym kompromisem miÄdzy szybkoÅciÄ a
              rozmiarem dla skanerów gotowych do wdrożenia (production
              scanners).

       -ooutput
              nakazuje fleksowi zapisanie skanera do pliku output zamiast do
              lex.yy.c.  JeÅli poÅÄczysz -o z opcjÄ -t, to skaner jest
              zapisywany na stdout, lecz jego dyrektywy #line (zobacz wyżej
              opcjÄ -L), odnoszÄ siÄ do pliku output.

       -Pprefiks
              zmienia domyÅlny przedrostek yy używany przez fleksa dla
              wszystkich zmiennych i funkcji globalnych na prefiks.  Na
              przykÅad -Pfoo zmienia nazwÄ yytext na footext.  Zmienia to też
              nazwÄ domyÅlnego pliku wyjÅciowego z lex.yy.c na lex.foo.c.  A
              oto wszystkie nazwy, których 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

              (JeÅli używasz skanera C++, to dotyczyÄ to bÄdzie tylko yywrap
              i yyFlexLexer.)  WewnÄtrz samego skanera można wciÄż używaÄ
              jednej i drugiej konwencji nazywania; jednak z zewnÄtrz
              dozwolone sÄ tylko nazwy zmodyfikowane.

              Opcja ta umożliwia Åatwe ÅÄczenie w caÅoÅÄ różnych programów
              fleksa w jeden plik wykonywalny. Zauważ jednak, że używanie
              tej opcji zmienia też nazwÄ yywrap(), wiÄc musisz teraz albo
              udostÄpniÄ wÅasnÄ wersjÄ tej procedury dla swojego skanera, albo
              użyÄ %option noyywrap, gdyż konsolidacja z -lfl nie daje już
              funkcji domyÅlnej.

       -Sskeleton_file
              przesÅania domyÅlny plik szkieletowy, na podstawie którego flex
              buduje swoje skanery. Nie bÄdziesz używaÄ tej opcji, chyba że
              zajmujesz siÄ rozwojem fleksa.

       flex daje też mechanizm kontrolowania opcji z samej specyfikacji
       skanera, zamiast linii poleceÅ. DziaÅa to przez wÅÄczanie dyrektyw
       %option w pierwszej sekcji specyfikacji skanera. W jednej dyrektywie
       %option można podawaÄ wiele opcji, a w samej pierwszej sekcji pliku
       wejÅciowego fleksa można używaÄ wielu dyrektyw.

       WiÄkszoÅÄ opcji jest podawana po prostu jako nazwy, poprzedzone
       opcjonalnie sÅowem "no" (bez biaÅych spacji w Årodku), które neguje
       ich znaczenie.  CzÄÅÄ jest równoważna flagom fleksa lub ich negacjom:

           7bit            -7
           8bit            -8
           align           -Ca
           backup          -b
           batch           -B
           c++             -+

           caseful lub
           case-sensitive  przeciwne do -i (domyÅlne)

           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 użyj "%option nowarn")

           array           równoważne "%array"
           pointer         równoważne "%pointer" (domyÅlne)

       Niektóre %opcje dajÄ wÅaÅciwoÅci niedostÄpne gdzie indziej:

       always-interactive
              nakazuje fleksowi generowanie skanera, który zawsze uważa
              swoje wejÅcie za "interaktywne". Normalnie przy każdym pliku
              wejÅciowym skaner woÅa isatty() do okreÅlenia czy wejÅcie
              skanera jest interaktywne i powinno byÄ czytane po znaku. Po
              użyciu tej opcji wywoÅanie takie nie jest robione.

       main   nakazuje fleksowi udostÄpniÄ domyÅlny program main() dla
              skanera, który po prostu woÅa yylex().  Opcja ta implikuje
              noyywrap (zobacz niżej).

       never-interactive
              nakazuje fleksowi generowanie skanera, który zawsze uważa
              swoje wejÅcie za "nieinteraktywne" (znów, nie jest woÅane
              isatty()).  Opcja ta jest przeciwna do always-interactive.

       stack  wÅÄcza używanie stosów warunków poczÄtkowych (zobacz wyżej
              Warunki PoczÄtkowe).

       stdinit
              jeÅli jest ustawione (np.  %option stdinit) to zachodzi
              inicjalizacja yyin i yyout na stdin i stdout, zamiast domyÅlnych
              nil.  Niektóre istniejÄce programy lex zaleÅ¼Ä od tego
              zachowania, nawet jeÅli nie jest ono zgodne z ANSI C, które nie
              wymagajÄ staÅych czasu kompilacji stdin i stdout.

       yylineno
              nakazuje fleksowi generowanie skanera, który przechowuje liczbÄ
              obecnie odczytanych linii w zmiennej globalnej yylineno.  Opcja
              ta jest wymuszana przez %option lex-compat.

       yywrap jeÅli nie jest ustawione (np.  %option noyywrap), to skaner nie
              woÅa yywrap() na koÅcu pliku, lecz po prostu przyjmuje, że nie
              ma już plików do skanowania (dopóki użytkownik nie wskaże
              yyin na nowy plik i nie wywoÅa yylex() ponownie).

       flex skanuje akcje reguÅ w celu okreÅlenia czy używasz wÅaÅciwoÅci
       REJECT lub yymore().  Opcje reject i yymore mogÄ przesÅoniÄ jego
       decyzjÄ na takÄ, jakÄ ustawisz przy użyciu opcji, zarówno ustawiajÄc
       je (np.  %option reject) do wskazania, że wÅaÅciwoÅÄ jest rzeczywiÅcie
       używana, lub wyÅÄczajÄc je, wskazujÄc, że wÅaÅciwoÅÄ nie jest
       używana (np.  %option noyymore).

       Trzy opcje pobierajÄ wartoÅci ÅaÅcuchowe, offsetowane znakiem '=':

           %option outfile="ABC"

       jest równoważne -oABC, a

           %option prefix="XYZ"

       jest równoważne -PXYZ.  Poza tym,

           %option yyclass="foo"

       dotyczy tylko skanerów C++ (opcja -+).  Mówi to fleksowi, że foo
       jest wyprowadzone jako podklasa yyFlexLexer, wiÄc flex bÄdzie
       umieszczaÅ twoje akcje w funkcji skÅadowej foo::yylex() zamiast w
       yyFlexLexer::yylex().  Powoduje to też generowanie funkcji skÅadowej
       yyFlexLexer::yylex(), emitujÄcej po wywoÅaniu bÅÄd dziaÅania (przez
       wywoÅanie yyFlexLexer::LexerError()).  Dla dalszych informacji zobacz
       też niżej Generowanie Skanerów C++.

       IstniejÄ opcje dla purystów, nie chcÄcych widzieÄ w swoich skanerach
       niepotrzebnych procedur. Każda z nastÄpujÄcych 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Ä dopóki nie
       użyjesz %optionstack).

ROZWAÅ»ANIA NAD WYDAJNOÅCIÄ
       Podstawowym zadaniem przy projektowaniu fleksa byÅo zapewnienie, że
       bÄdzie generowaÅ wydajne skanery. ZostaÅ zoptymalizowany do dobrej
       wspóÅpracy z wielkimi zestawami reguÅ. Poza omawianymi już wpÅywami
       opcji kompresji -C, istnieje jeszcze kilka akcji/opcji wpÅywajÄcych na
       wydajnoÅÄ. SÄ to, od najkosztowniejszej do najmniej kosztownej:

           REJECT
           %option yylineno
           arbitralny wiszÄcy kontekst

           zestawy wzorców, wymagajÄce cofania
           %array
           %option interactive
           %option always-interactive

           '^' operator rozpoczÄcia linii
           yymore()

       z których pierwsze trzy sÄ bardzo kosztowne, a ostatnie dwa w miarÄ
       tanie.  Zauważ też, że unput() jest implementowane jako wywoÅanie
       procedurowe, które prawdopodobnie wykonuje sporo pracy, podczas gdy
       yyless() jest tanim makrem; wiÄc jeÅli wstawiasz z powrotem nadmiarowy
       wyskanowany tekst, użyj yyless().

       REJECT powinno byÄ unikane za wszelkÄ cenÄ z punktu widzenia
       wydajnoÅci.  Jest to szczególnie kosztowna opcja.

       Pozbycie siÄ cofania jest trudne i może czÄsto prowadziÄ do bÅÄdów w
       skomplikowanych skanerach. W praktyce zaczyna siÄ od użycia flagi -b
       do wygenerowania pliku lex.backup.  Na przykÅad dla wejÅcia

           %%
           foo        return TOK_KEYWORD;
           foobar     return TOK_KEYWORD;

       plik ten wyglÄda 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 mówi, że istnieje stan skanera, w którym
       może on przyjÄÄ 'o', lecz nie może przyjÄÄ innego znaku i że w tym
       stanie aktualnie skanowany tekst nie pasuje do żadnej reguÅy. Stan ten
       pojawia siÄ podczas próby dopasowania reguÅ z linijek 2 i 3 pliku
       wejÅciowego. JeÅli skaner jest w tym stanie i odczyta cokolwiek innego
       niż 'o', to bÄdzie musiaÅ siÄ cofnÄÄ i okreÅliÄ, która reguÅa pasuje.
       Po chwili skrobania siÄ w gÅowÄ można zauważyÄ, że musi to byÄ stan,
       gdy skaner zobaczyÅ "fo". W tej sytuacji otrzymanie czegokolwiek innego
       niż 'o' spowoduje cofniÄcie do prostego dopasowania 'f' (reguÅa
       domyÅlna).

       Komentarz odnoÅnie stanu #8 mówi, że istnieje problem przy skanowaniu
       "foob". RzeczywiÅcie, jeÅli pojawi siÄ dowolny znak inny niż 'a', to
       skaner bÄdzie musiaÅ siÄ cofnÄÄ do przyjmowania "foo". Podobnie sprawa
       ma siÄ ze stanem #9, mówiÄcym o "fooba", po którym nie nastÄpuje 'r'.

       Ostatni komentarz przypomina nam, że usuwanie cofania nie ma sensu
       jeÅli nie używamy -Cf lub -CF, gdyż nie daje to żadnego zysku
       wydajnoÅci na skanerach kompresowanych.

       Sposobem usuwania cofania jest dodawanie reguÅ dla "bÅÄdów":

           %%
           foo         return TOK_KEYWORD;
           foobar      return TOK_KEYWORD;

           fooba       |
           foob        |
           fo          {
                       /* faÅszywy alarm, nie jest to sÅowo kluczowe */
                       return TOK_ID;
                       }


       Eliminowanie cofania można przeprowadziÄ również przy użyciu reguÅy
       "Åap-wszystko":

           %%
           foo         return TOK_KEYWORD;
           foobar      return TOK_KEYWORD;

           [a-z]+      return TOK_ID;

       Jest to, tam gdzie można je zastosowaÄ, najlepsze rozwiÄzanie.

       Komunikaty cofania czÄsto ukÅadajÄ siÄ w kaskady. W skomplikowanych
       zbiorach reguÅ można dostaÄ setki komunikatów. Mimo to, jeÅli można
       je zdeszyfrowaÄ, to ich usuwanie wymaga tylko tuzina reguÅ (Åatwo siÄ
       jednak pomyliÄ i spowodowaÄ, że reguÅa obsÅugi bÅÄdu bÄdzie pasowaÄ do
       prawidÅowego tokena. Możliwe, że przyszÅe implementacje fleksa bÄdÄ
       automatycznie zajmowaÅy siÄ usuwaniem cofania).

       Ważne jest pamiÄtanie, że korzyÅci z eliminacji tego problemu
       zyskujesz dopiero po zlikwidowaniu każdej instancji cofania.
       Pozostawienie choÄ jednej oznacza, że nie zyskujesz niczego.

       Zmienny wiszÄcy kontekst (gdzie zarówno prowadzÄca jak i koÅczÄca
       czÄÅÄ nie majÄ ustalonej dÅugoÅci) wprowadza utratÄ wydajnoÅci
       zbliżonÄ do REJECT (tzn. znacznÄ). Dlatego gdy tylko można, to zapisz
       takÄ reguÅÄ:

           %%
           mouse|rat/(cat|dog)   run();

       jako:

           %%
           mouse/cat|dog         run();
           rat/cat|dog           run();

       lub jako

           %%
           mouse|rat/cat         run();
           mouse|rat/dog         run();

       zwrÃ³Ä uwagÄ, że specjalna akcja '|' nie powoduje żadnych
       oszczÄdnoÅci, a wrÄcz może pogorszyÄ sprawÄ (zobacz niżej Niedostatki
       / BÅÄdy).

       Innym obszarem, gdzie użytkownik może zwiÄkszaÄ wydajnoÅÄ skanera
       jest to, że im dÅuższe sÄ dopasowywane tokeny, tym szybciej dziaÅa
       skaner. Jest tak dlatego, że przetwarzanie dÅugich tokenów wiÄkszoÅci
       znaków wejÅciowych zachodzi w wewnÄtrznej (krótkiej) pÄtli skanujÄcej
       i rzadko musi przechodziÄ przez dodatkowÄ pracÄ zwiÄzanÄ z ustawianiem
       Årodowiska skanujÄcego (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);

       Można to przyspieszyÄ nastÄpujÄco:

           %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 nastÄpnej
       akcji, rozpoznawanie nowych linii jest "rozrzucone" na inne reguÅy.
       Umożliwia to zachowanie jak najdÅuższego dopasowania. Zauważ, że
       dodawanie reguÅ nie spowalnia skanera! Jego szybkoÅÄ jest niezależna
       od liczby reguÅ i (w porównaniu do rozważaÅ z poczÄtku sekcji) ich
       stopnia skomplikowania (z zastrzeżeniem do operatorów takich jak '*'
       i '|').

       Ostateczny przykÅad przyspieszania skanera: zaÅóżmy, że chcesz
       skanowaÄ plik zawierajÄcy identyfikatory i sÅowa kluczowe w liczbie
       jednego na liniÄ, bez żadnych obcych znaków i chcesz rozpoznawaÄ
       wszystkie sÅowa kluczowe.  Naturalnym odruchem poczÄtkowym jest:

           %%
           asm      |
           auto     |
           break    |
           ... etc ...
           volatile |
           while    /* to jest sÅowo kluczowe */

           .|\n     /* a to nie... */

       Aby wyeliminowaÄ Åledzenie wstecz, wprowadź reguÅÄ Åap-wszystko:

           %%
           asm      |
           auto     |
           break    |
           ... etc ...
           volatile |
           while    /* to sÅowo kluczowe */

           [a-z]+   |
           .|\n     /* a to nie... */

       Obecnie, jeÅli mamy zagwarantowane, że mamy dokÅadnie jedno sÅowo w
       linii, możemy zredukowaÄ caÅkowitÄ liczbÄ dopasowaÅ o poÅowÄ przez
       wÅÄczanie w rozpoznawanie tokenów Åapanie nowych linii.

           %%
           asm\n    |
           auto\n   |
           break\n  |
           ... etc ...
           volatile\n |
           while\n  /* to sÅowo kluczowe */

           [a-z]+\n |
           .|\n     /* a to nie... */

       Trzeba byÄ tu ostrożnym, gdyż wÅaÅnie wprowadziliÅmy do skanera
       cofanie. W szczególnoÅci, jeÅli my wiemy, że w wejÅciu nie bÄdzie
       nigdy znaków innych niż litery i nowe linie, to flex nie może tego
       wiedzieÄ i bÄdzie planowaÅ ewentualnoÅÄ cofania podczas skanowania
       tokenu w rodzaju "auto", po którym nie nastÄpi nowa linia lub litera.
       W poprzednim wypadku nastÄpiÅoby po prostu dopasowanie reguÅy "auto",
       lecz teraz nie ma "auto", ale "auto\n". Aby wyeliminowaÄ możliwoÅÄ
       cofania, możemy albo zduplikowaÄ wszystkie reguÅy bez koÅcowych nowych
       linii albo, jeÅli nie spodziewamy siÄ takiego wejÅcia i nie [interesuje
       nas] jego klasyfikacja, możemy wprowadziÄ reguÅÄ Åap-wszystko, która
       nie zawiera nowej linii.

           %%
           asm\n    |
           auto\n   |
           break\n  |
           ... etc ...
           volatile\n |
           while\n  /* to sÅowo kluczowe */

           [a-z]+\n |
           [a-z]+   |
           .|\n     /* a to nie... */

       Po kompilacji z -Cf, jest to prawie tak szybkie, jak tylko możliwe dla
       fleksa dla tego problemu.

       Ostatnia uwaga: flex jest wolny przy dopasowywaniu NUL-ów,
       szczególnie jeÅli token zawiera ich wiele.  Najlepiej pisaÄ reguÅy,
       dopasowujÄce krótkie fragmenty takich tekstów.

       Kolejna ostatnia uwaga o wydajnoÅci: jak wspomniano wyżej w sekcji Jak
       Dopasowywane jest WejÅcie, dynamiczne zmiany rozmiarów yytext do
       przyjmowania dużych tokenów jest powolne, gdyż obecnie wymaga by
       taki token byÅ reskanowany od poczÄtku. Tak wiÄc jeÅli wydajnoÅÄ jest
       istotna, to powinieneÅ dopasowywaÄ "duże" fragmenty tekstu, lecz nie
       "olbrzymie".  GranicÄ miÄdzy tymi pojÄciami jest okoÅo 8K
       znaków/token.

GENEROWANIE SKANERÃW C++
       flex daje dwie drogi tworzenia skanerów przeznaczonych dla C++.
       PierwszÄ z nich jest proste skompilowanie fleksowego skanera
       kompilatorem C++ zamiast kompilatora C. Nie powinieneÅ napotkaÄ
       żadnych bÅÄdów kompilacji (jeÅli siÄ pojawiÄ, to zgÅoÅ to pod adres
       wskazany niżej, w sekcji o autorze). Możesz wówczas w akcjach swoich
       reguÅ używaÄ kodu C++ zamiast C. Zauważ, że domyÅlnym źródÅem dla
       skanera pozostaje yyin, a domyÅlnym echem jest wciÄż yyout.  Obydwa
       urzÄdzenia sÄ zmiennymi FILE *, a nie strumieniami C++.

       Można też użyÄ fleksa do generowania klasy skanera C++. SÅuży do
       tego opcja -+ (lub, równoważnie %option c++), co jest przyjmowane
       automatycznie jeÅli nazwa pliku wykonywalnego fleksa koÅczy siÄ plusem,
       jak np.  flex++.  Przy użyciu tej opcji, flex generuje skaner do pliku
       lex.yy.cc zamiast lex.yy.c.  Generowany skaner zawiera plik nagÅówkowy
       FlexLexer.h, który definiuje interfejsy do dwóch klas C++.

       Pierwsza klasa, FlexLexer, daje abstrakcyjnÄ klasÄ bazowÄ, definiujÄcÄ
       ogólny interfejs klasy skanera.  Daje nastÄpujÄce funkcje skÅadowe:

       const char* YYText()
              zwraca tekst ostatnio dopasowanego tokenu, równoważnik yytext.

       int YYLeng()
              zwraca dÅugoÅÄ ostatnio dopasowanego tokenu, równoważnik
              yyleng.

       int lineno() const
              zwraca numer aktualnej linii wejÅciowej (zobacz %option
              yylineno), lub 1 jeÅli %option yylineno nie zostaÅo użyte.

       void set_debug( int flag )
              ustawia flagÄ debuggujÄcÄ dla skanera, równoważnik przypisania
              do yy_flex_debug (zobacz wyżej sekcjÄ o opcjach). Zauważ, że
              aby wÅÄczaÄ w skanerze informacje diagnostyczne, musisz
              skompilowaÄ go z użyciem %option debug.

       int debug() const
              zwraca bieżÄce ustawienie flagi debuggujÄcej.

       UdostÄpniane sÄ też funkcje skÅadowe równoważne
       yy_switch_to_buffer(), yy_create_buffer() (chociaż pierwszym
       argumentem jest wskaźnik istream*, a nie FILE*), yy_flush_buffer(),
       yy_delete_buffer() i yyrestart() (i znowu, pierwszym argumentem jest
       wskaźnik istream*).

       KolejnÄ klasÄ zdefiniowanÄ w FlexLexer.h jest yyFlexLexer, który jest
       klasÄ pochodnÄ FlexLexer.  Zaiwera nastÄpujÄce dodatkowe funkcje
       skÅadowe:

       yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 )
              buduje obiekt yyFlexLexer stosujÄc podane strumienie jako
              wejÅcie i wyjÅcie. JeÅli nie zostanÄ podane, to strumienie bÄdÄ
              odpowiadaÅy odpowiednio cin i cout.

       virtual int yylex()
              odgrywa tÄ samÄ rolÄ co yylex() dla normalnych skanerów fleksa:
              skanuje strumieÅ wejÅciowy, konsumuje tokeny aż akcja reguÅy
              nie zwróci wartoÅci. JeÅli z yyFlexLexer wyprowadzisz podklasÄ
              S i zechcesz dostaÄ siÄ do funkcji i zmiennych skÅadowych S z
              wnÄtrza yylex(), to musisz użyÄ %option yyclass="S" by
              poinformowaÄ fleksa, że bÄdziesz używaÄ podklasy zamiast
              yyFlexLexer.  W tym wypadku zamiast generowaÄ
              yyFlexLexer::yylex(), flex generuje S::yylex() (oraz generuje
              prosty yyFlexLexer::yylex(), który woÅa
              yyFlexLexer::LexerError() po wywoÅaniu).

       virtual void switch_streams(istream* new_in = 0,
              ostream* new_out = 0) przypisuje yyin do new_in (jeÅli jest nie-
              nil) oraz yyout do new_out (ditto), kasujÄc poprzedni bufor
              wejÅciowy jeÅli przypisywana jest nowa wartoÅÄ yyin .

       int yylex( istream* new_in, ostream* new_out = 0 )
              najpierw przeÅÄcza strumienie wejÅciowe poprzez switch_streams(
              new_in, new_out ), a nastÄpnie zwraca wartoÅÄ yylex().

       Poza tym, yyFlexLexer definiuje nastÄpujÄce chronione (protected)
       funkcje wirtualne, które można przedefiniowaÄ w klasach pochodnych,
       by dostosowaÄ skaner:

       virtual int LexerInput( char* buf, int max_size )
              odczytuje maksymalnie max_size znaków do buf i zwraca liczbÄ
              odczytanych znaków. Aby wskazaÄ koniec wejÅcia zwracane jest 0
              znaków. Zauważ, że skanery "interaktywne" (zobacz flagi -B
              oraz -I) definiujÄ makro YY_INTERACTIVE.  JeÅli redefiniujesz
              LexerInput() i potrzebujesz braÄ różne akcje, zależnie od
              tego czy skaner skanuje źródÅo interaktywne czy nie, to
              możesz sprawdzaÄ obecnoÅÄ tej nazwy poprzez #ifdef.

       virtual void LexerOutput( const char* buf, int size )
              zapisuje size znaków z bufora buf który, o ile jest zakoÅczony
              zerem, może zawieraÄ też "wewnÄtrzne" zera jeÅli reguÅy
              skanera mogÄ ÅapaÄ tekst z wewnÄtrznymi zerami.

       virtual void LexerError( const char* msg )
              zgÅasza komunikat bÅÄdu krytycznego. DomyÅlna wersja tej funkcji
              zapisuje komunikat do strumienia cerr i koÅczy dziaÅanie
              programu.

       Zauważ, że obiekt yyFlexLexer zawiera swój peÅny stan skanowania.
       Tak wiÄc można używaÄ takich obiektów do tworzenia wielobieżnych
       (reentrant) skanerów. Możesz używaÄ wielu instancji tej samej klasy
       yyFlexLexer, jak również możesz w jednym programie ÅÄczyÄ wiele klas
       skanerów w caÅoÅÄ, używajÄc opisanej wyżej opcji -P .

       Dla skanerów C++ nie jest dostÄpna wÅaÅciwoÅÄ %array, trzeba wiÄc
       używaÄ %pointer (tj. wartoÅci domyÅlnej).

       Oto przykÅad prostego skanera C++:

               // PrzykÅad użycia 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;
               }
       JeÅli chcesz tworzyÄ wiele (różnych) klas leksera, powinieneÅ użyÄ
       flagi -P (lub opcji prefiks=) do zmiany nazwy każdego yyFlexLexer na
       inny xxFlexLexer.  NastÄpnie możesz zaÅÄczaÄ <FlexLexer.h> do swoich
       innych źródeÅ, raz na klasÄ leksera, zmieniajÄc najpierw nazwÄ
       yyFlexLexer w nastÄpujÄcy sposób:

           #undef yyFlexLexer
           #define yyFlexLexer xxFlexLexer
           #include <FlexLexer.h>

           #undef yyFlexLexer
           #define yyFlexLexer zzFlexLexer
           #include <FlexLexer.h>

       o ile (na przykÅad) użyjesz opcji %option prefix="xx" dla jednego ze
       swoich skanerów, a %option prefix="zz" dla drugiego.

       WAÅ»NE: obecna postaÄ klasy skanujÄcej jest eksperymentalna i może
       zmieniaÄ siÄ miÄdzy gÅównymi wydaniami.

NIEZGODNOÅCI Z LEX I POSIX
       flex jest przeróbkÄ narzÄdzia lex z AT&T Unix (jednakże obie te
       implementacje nie majÄ wspólnego kodu). Posiada pewne rozszerzenia i
       niezgodnoÅci, które sÄ istotne dla tych, którzy chcÄ pisaÄ skanery
       dziaÅajÄce z oboma. Flex jest w peÅni zgodny ze specyfikacjÄ POSIX lex
       poza szczegóÅem, że gdy używa %pointer (domyÅlne), to wywoÅanie
       unput() niszczy zawartoÅÄ yytext, co jest niezgodne ze specyfikacjÄ
       POSIX.

       W sekcji tej omówimy wszystkie znane obszary niezgodnoÅci fleksa z
       AT&T lex i specyfikacjÄ POSIX.

       fleksowa opcja -l wÅÄcza maksymalnÄ zgodnoÅÄ z oryginalnym AT&T lex,
       okupujÄc to jednak znacznymi stratami wydajnoÅci generowanego skanera.
       Niżej zaznaczymy, które niezgodnoÅci można pokonaÄ używajÄc opcji
       -l.

       flex jest w peÅni zgodny z leksem poza nastÄpujÄcymi wyjÄtkami:

       -      Nieudokumentowana zmienna wewnÄtrzna skanera lex o nazwie
              yylineno nie jest obsÅugiwana bez -l lub %option yylineno.

              yylineno powinno byÄ obsÅugiwane na poziomie buforowym, a nie na
              skanerowym (pojedyncza zmienna globalna).

              yylineno nie jest czÄÅciÄ specyfikacji POSIX.

       -      Procedura input() nie jest redefiniowalna chociaż może byÄ
              woÅana do czytania znaków nastÄpujÄcym po tym, co dopasowano do
              reguÅy. JeÅli input() napotka koniec pliku, to wykonywane jest
              normalne przetwarzanie yywrap().  ``Prawdziwy'' koniec pliku
              jest sygnalizowany przez input() zwróceniem wartoÅci EOF.

              WejÅcie jest natomiast sterowane przez definiowanie makra
              YY_INPUT.

              Ograniczenie fleksa, że input() nie może byÄ redefiniowany
              jest zgodne ze specyfikacjÄ POSIX, która po prostu nie okreÅla
              innego żadnego sposobu sterowania wejÅciem skanera niż poprzez
              dokonanie poczÄtkowego przypisania do yyin.

       -      Procedura unput() nie jest redefiniowalna. Ograniczenie to jest
              zgodne z POSIX.

       -      Skanery fleksa nie sÄ tak wielobieżne (reentrant) jak skanery
              lex.  W szczególnoÅci, jeÅli masz interaktywny skaner i obsÅugÄ
              przerwaÅ, która robi dÅugi skok ze skanera, a skaner jest
              nastÄpnie woÅany ponownie, to możesz uzyskaÄ nastÄpujÄcy
              komunikat:

                  fatal flex scanner internal error--end of buffer missed

              Aby wejÅÄ na nowo do skanera, użyj najpierw

                  yyrestart( yyin );

              Zauważ, że wywoÅanie to wyrzuci wszelkie buforowane wejÅcie;
              zwykle jednak nie jest to problem przy skanerach interaktywnych.

              Zauważ też, że klasy skanerów C++ wielobieżne
              (reentrant), wiÄc używajÄc opcji C++ powinieneÅ ich używaÄ.
              Zobacz sekcjÄ o generowaniu skanerów C++.

       -      output() nie jest obsÅugiwany. WyjÅcie makra ECHO jest
              wykonywane do wskaźnika plikowego yyout (domyÅlnie stdout).

              output() nie jest czÄÅciÄ specyfikacji POSIX.

       -      lex nie obsÅuguje wykluczajÄcych warunków poczÄtkowych (%x),
              choÄ znajdujÄ siÄ one w specyfikacji POSIX.

       -      Przy rozwijaniu definicji, flex ujmuje je w nawiasy.  W leksie,
              nastÄpujÄce:

                  NAME    [A-Z][A-Z0-9]*
                  %%
                  foo{NAME}?      printf( "ZnalazÅem\n" );
                  %%

              nie dopasuje siÄ do ÅaÅcucha "foo", gdyż makro jest rozwijane
              tak, że reguÅa odpowiada "foo[A-Z][A-Z0-9]*?", a pierwszeÅstwo
              jest takie, że '?' jest wiÄzany z "[A-Z0-9]*". We fleksie
              reguÅa zostaÅaby rozwiniÄta do "foo([A-Z][A-Z0-9]*)?" i ÅaÅcuch
              "foo" zostaÅby dopasowany.

              Zauważ, że jeÅli definicja rozpoczyna siÄ od ^ lub koÅczy siÄ
              na $ to nie jest rozwijana w nawiasach, aby umożliwiÄ tym
              operatorom pojawienie siÄ w definicjach bez utraty ich
              znaczenia. Ale operatory <s>, / i <<EOF>> nie mogÄ byÄ używane
              w definicji fleksa.

              Używanie -l skutkuje leksowym zachowaniem braku nawiasów
              wokóŠdefinicji.

              POSIX nakazuje ujmowanie definicji w nawiasy.

       -      Niektóre implementacje leksa umożliwiajÄ rozpoczynanie akcji
              reguÅ w osobnej linii jeÅli wzorzec reguÅy ma doklejonÄ biaÅÄ
              spacjÄ:

                  %%
                  foo|bar<tu spacja>
                    { foobar_action(); }

              flex nie obsÅuguje tej wÅaÅciwoÅci.

       -      Leksowe %r (generuj skaner Ratfor) nie jest obsÅugiwane. Nie
              jest czÄÅciÄ specyfikacji POSIX.

       -      Po wywoÅaniu unput(), yytext jest niezdefiniowane aż do
              dopasowania nastÄpnego tokenu, chyba że skaner używa %array.
              Inaczej ma siÄ sprawa z leksem lub specyfikacjÄ POSIX. Opcja -l
              zaÅatwia tÄ niezgodnoÅÄ.

       -      PierwszeÅstwo 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.

       -      PierwszeÅstwo operatora ^ jest inne.  lex interpretuje
              "^foo|bar" jako "dopasuj albo 'foo' z poczÄtku linii albo 'bar'
              gdziekolwiek", podczas gdy flex rozumie to jako "dopasuj 'foo'
              lub 'bar' jeÅli pojawiÄ siÄ na poczÄtku linii". To drugie jest
              zgodne ze specyfikacjÄ POSIX.

       -      Specjalne deklaracje rozmiaru-tablicy, takie jak %a, obsÅugiwane
              przez lex nie sÄ wymagane przez skanery fleksa; flex je
              ignoruje.

       -      Nazwa FLEX_SCANNER jest #definiowana, wiÄc skanery mogÄ byÄ
              pisane z przeznaczeniem do użycia z fleksem lub leksem.
              Skanery zawierajÄ również YY_FLEX_MAJOR_VERSION i
              YY_FLEX_MINOR_VERSION wskazujÄc na wersjÄ fleksa, która
              wygenerowaÅa skaner (na przykÅad dla wydania 2.5 definiowane sÄ
              odpowiednio liczby 2 i 5).

       NastÄpujÄce wÅaÅciwoÅci fleksa nie sÄ zawarte w specyfikacjach lex ani
       POSIX:

           Skanery C++
           %option
           zakresy warunków poczÄtkowych
           stosy warunków poczÄtkowych
           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
           %{} wokóŠakcji
           wiele akcji w linii

       plus prawie wszystkie flagi fleksa. Ostatnia wÅaÅciwoÅÄ listy odnosi
       siÄ do faktu, że we fleksie można wstawiaÄ wiele akcji do jednej
       linii, rozdzielajÄc je Årednikami, podczas gdy w leksie, nastÄpujÄca
       instrukcja

           foo    handle_foo(); ++num_foos_seen;

       jest (raczej niespodziewanie) obcinana do

           foo    handle_foo();

       flex nie obcina akcji. Akcje które nie sÄ objÄte klamrami koÅczÄ siÄ
       zwyczajnie na koÅcu linii.

DIAGNOSTYKA
       warning, rule cannot be matched (ostrzeżenie, reguÅa nie może byÄ
       dopasowana) wskazuje, że podana reguÅa nie może byÄ dopasowana gdyż
       wystÄpuje za innymi reguÅami, które zawsze dopasujÄ jej tekst. Na
       przykÅad nastÄpujÄce foo nie może byÄ dopasowane, gdyż pojawia siÄ po
       regule Åap-wszystko:

           [a-z]+    got_identifier();
           foo       got_foo();

       Użycie w skanerze REJECT powstrzyma to ostrzeżenie.

       warning, -s option given but default rule can be matched (ostrzeżenie,
       podano opcjÄ -s, lecz dopasowana może byÄ reguÅa domyÅlna) oznacza,
       że możliwe jest (przypuszczalnie tylko w konkretnym warunku
       poczÄtkowym), że reguÅa domyÅlna (dopasowania dowolnego znaku) jest
       jedynÄ, która dopasuje siÄ do konkretnego wejÅcia. Ponieważ podano
       -s, zakÅada 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 bÅÄdy
       pojawiajÄ siÄ podczas kompilacji. WskazujÄ one, że skaner używa
       REJECT lub yymore(), lecz flex nie poinformowaÅ o tym fakcie. Znaczy
       to, że flex przeskanowaŠpierwsze dwie sekcji w poszukiwaniu
       pojawienia siÄ tych akcji, ale ich nie znalazÅ, bo jakoÅ je przemyciÅeÅ
       (np. przez plik #include). Użyj %option reject lub %option yymore do
       wskazania fleksowi, że naprawdÄ używasz tych wÅaÅciwoÅci.

       flex scanner jammed - skaner skompilowany z -s napotkaÅ ÅaÅcuch
       wejÅciowy, który nie zostaÅ dopasowany do żadnej z jego reguÅ. BÅÄd
       ten może siÄ pojawiÄ też z powodu problemów wewnÄtrznych.

       token too large, exceeds YYLMAX (token zbyt duży, przekracza YYLMAX) -
       twój skaner używa %array a jedna z jego reguÅ dopasowaÅa siÄ do
       ÅaÅcucha dÅuższego niż staÅa YYLMAX (domyÅlnie 8K). Możesz zwiÄkszyÄ
       tÄ wartoÅÄ zwiÄkszajÄc #definicjÄ staÅej YYLMAX w sekcji definicji
       swojego wejÅcia fleksa.

       scanner requires -8 flag to use the character 'x' (skaner wymaga flagi
       -8 do używania znaku 'x') - specyfikacja twojego skanera zawiera
       rozpoznawanie znaku 8-bitowego 'x', a nie podana zostaÅa flaga -8, w
       wyniku czego skaner użyŠ7-bit z powodu wykorzystania opcji kompresji
       tablic -Cf lub -CF.  Dla szczegóÅów zobacz dyskusjÄ flagi -7.

       flex scanner push-back overflow - użyÅeÅ unput() do wepchniÄcia z
       powrotem tak dÅugiego tekstu, że bufor skanera nie potrafiÅ
       przetrzymaÄ wepchniÄtego tekstu i bieżÄcego 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 wejÅciowego nie może powiÄkszyÄ bufora gdyż
       skaner używa REJECT) - skaner pracowaŠnad dopasowaniem bardzo dużego
       tokenu i potrzebowaÅ rozszerzyÄ bufor wejÅciowy. Nie dziaÅa to ze
       skanerami, używajÄcymi REJECT.

       fatal flex scanner internal error--end of buffer missed (krytyczny bÅÄd
       wewnÄtrzny skanera flex -- rozminiÄto siÄ z koÅcem bufora) - Może siÄ
       to pojawiÄ w skanerze, który jest uruchomiony po dÅugim skoku z ramki
       aktywacji skanera. Przed powrotem do skanera użyj:

           yyrestart( yyin );

       albo, jak wspomniano wyżej, przeÅÄcz siÄ na używanie skanerów C++.

       too many start conditions in <> construct!  (zbyt wiele warunków
       poczÄtkowych w konstrukcji <>) - w konstrukcji <> pojawiÅo siÄ wiÄcej
       warunków poczÄtkowych niż istnieje w rzeczywistoÅci (wiÄc
       przynajmniej jeden z nich pojawiÅ siÄ dwukrotnie).

PLIKI
       -lfl   biblioteka, z którÄ muszÄ byÄ ÅÄczone skanery.

       lex.yy.c
              generowany skaner (nazywany na niektórych systemach lexyy.c).

       lex.yy.cc
              generowana klasa skanera C++, po użyciu -+.

       <FlexLexer.h>
              plik nagÅówkowy definiujÄcy klasÄ bazowÄ skanera C++, FlexLexer
              i klasÄ pochodnÄ, yyFlexLexer.

       flex.skl
              skaner szkieletowy. Plik ten jest używany tylko przy budowaniu
              fleksa, nie przy jego uruchamianiu.

       lex.backup
              informacje wspierajÄce (backing-up) dla flagi -b (nazywany jest
              mianem lex.bck na niektórych systemach).

NIEDOSTATKI / BÅÄDY
       Niektóre wzorce wiszÄcego kontekstu nie mogÄ byÄ poprawnie dopasowane
       i generujÄ komunikaty ostrzegawcze ("dangerous trailing context")
       (niebezpieczny wiszÄcy kontekst). SÄ to wzorce, gdzie zakoÅczenie
       pierwszej czÄÅci reguÅy dopasowuje siÄ do poczÄtku drugiej czÄÅci,
       takie jak "zx*/xy*", gdzie 'x*' dopasowuje 'x' na poczÄtku wiszÄcego
       kontekstu.  (Zauważ, że projekt POSIX-a okreÅla, że dopasowany w
       takich wzorcach tekst jest niezdefiniowany.)

       Dla niektórych reguÅ wiszÄcego kontekstu, czÄÅci które sÄ w
       rzeczywistoÅci okreÅlonej dÅugoÅci nie sÄ tak rozpoznawane. Prowadzi to
       do wspomnianej wyżej straty wydajnoÅci. W szczególnoÅci, czÄÅci
       używajÄce '|' lub {n} (takie jak "foo{3}") zawsze sÄ uważane za
       zmienno-dÅugoÅciowe.

       ÅÄczenie wiszÄcego kontekstu z akcjÄ specjalnÄ '|' może spowodowaÄ,
       że ustalony (fixed) wiszÄcy kontekst zostanie zmieniony w bardziej
       kosztowny, zmienny wiszÄcy kontekst. Na przykÅad nastÄpujÄce:

           %%
           abc      |
           xyz/def


       Używanie unput() uszkadza yytext i yyleng, chyba że użyto dyrektywy
       %array lub opcji -l.

       Dopasowywanie wzorców NUL-i jest znacznie wolniejsze niż
       dopasowywanie innych znaków.

       Dynamiczne zmiany rozmiaru bufora sÄ wolne i wymagajÄ reskanowania
       caÅego tekstu dopasowanego dotÄd przez bieżÄcy (zwykle duży) token.

       Z powodu buforowania wejÅcia i czytania z wyprzedzeniem, nie można
       ÅÄczyÄ z reguÅami fleksa wywoÅaÅ <stdio.h>, np.  getchar().  Zamiast
       tego woÅaj input().

       Wpisy caÅej tablicy (total table entries) wymieniane przez flagÄ -v nie
       zawierajÄ niektórych wpisów, potrzebnych do okreÅlania, która reguÅa
       zostaÅa dopasowana. Liczba wpisów jeÅli skaner nie używa REJECT jest
       równa liczbie stanów DFA, a w przeciwnym wypadku jest trochÄ wiÄksza.

       REJECT nie może byÄ używany z opcjami -f lub -F.

       WewnÄtrzne algorytmy fleksa wymagajÄ udokumentowania.

ZOBACZ TAKŻE
       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 wzorców używane przez fleksa (deterministyczne automaty
       skoÅczone).

AUTOR
       Vern Paxson, z pomocÄ wielu pomysÅów i inspiracji od Vana Jacobsona.
       OryginalnÄ wersjÄ napisaÅ Jef Poskanzer.  Reprezentacja szybkiej
       tablicy jest czÄÅciowÄ implementacjÄ projektu Vana Jacobsona.
       Implementacja zostaÅa wykonana przez Kevina Gonga and Verna Paxsona.

       PodziÄkowania dla wielu beta testerów, komentatorów i kontrybutorów
       fleksa, z których szczególnie zasÅużone sÄ nastÄpujÄce 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, których nazwiska wyleciaÅy z moich zdolnoÅci
       archiwizowania poczty, lecz których wkÅad jest równie ważny.

       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 różnymi problemami dystrybucji.

       Esmond Pitt and Earle Horton pomógŠ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 pomógŠz wsparciem
       NUL-ów; Eric Hughes pomógŠz wielokrotnymi buforami.

       Praca ta byÅa poczÄtkowo wykonywana gdy byÅem z Real Time Systems Group
       w Lawrence Berkeley Laboratory w Berkeley, CA. Wielkie dziÄki do
       wszystkich za wsparcie, które uzyskaÅem.

       Komentarze Ålij do vern@ee.lbl.gov.



Wersja 2.5                       KwiecieÅ 1995                         FLEX(1)