Provided by: manpages-pl_0.7-1_all bug

NAZWA

       flex - szybki generator analizatora leksykalnego

SKŁADNIA

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

WPROWADZENIE

        Uwaga! To tłumaczenie może być nieaktualne!

       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 '-', ']' oraz '^' na początku 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 '/' lub '$'). Wzorce
              warunku początkowego '^' oraz "<<EOF>>" mogą pojawić 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.

INFORMACJE O TŁUMACZENIU

       Powyższe tłumaczenie pochodzi z nieistniejącego już Projektu Tłumaczenia Manuali i może nie być aktualne.
       W  razie  zauważenia  różnic  między powyższym opisem a rzeczywistym zachowaniem opisywanego programu lub
       funkcji, prosimy o zapoznanie się z oryginalną (angielską) wersją strony podręcznika za pomocą polecenia:

              man --locale=C 1 flex

       Prosimy  o  pomoc  w  aktualizacji  stron  man  -   więcej   informacji   można   znaleźć   pod   adresem
       http://sourceforge.net/projects/manpages-pl/.