AMIGA REVIEW obsah časopisu online!
  Domov     Software     Hry     Obaly     Download  

ADE: Flex 2.5.4

Jan Skýpala

Flex znamená Fast lexical analyzer generator, tedy generátor rychlé lexikální analýzy. Souvisí se zpracováním vstupu zapsaného v nějakém jazyce (přečtěte si prosím text o překladu programu před čtením tohoto článku).

Flex je utilitou pro generování „scannerů“ - programů, které umí rozpoznávat ve svém vstupu jednotlivé prvky nějakého jazyka na základě uvedených vzorů. Flex čte vstupní soubor (nebo standardní vstup, když mu není žádný vstupní soubor zadán), který obsahuje popis generovaného scanneru. Tento popis je složen jednak z regulárních výrazů - vzorů popisujících prvky jazyka a céčkovských rutin. Jako output je vygenerován zdroják v céčku, který obsahuje hlavní funkci yylex(). Tento soubor může být zkompilován a slinkován s knihovnou libfl.a a když bude spuštěn, bude analyzovat svůj vstup na výskyt jednotlivých prvků odpovídajících zadaným vzorům. Když je daný vzor rozpoznán, je vykonán odpovídající kód v céčku.
Zkusme si nyní naprosto banální příklad takového scanneru. Vytvořte soubor nazvaný třeba pokus1.l (přípona .l je standardem pro vstup pro lex či flex), který bude obsahovat:

%%
PC printf(„Amiga“);

Nyní spusťte flex pokus1.l a bude vygenerován soubor nový, se jménem lex.yy.c (to je standard, pomocí parametru t lze jako výstup zvolit standardní výstup a ten pak přesměrovat do souboru jiného jména). Nyní spusťte gcc lex.yy.c -lfl a na disk bude vygenerován program (a.out), který bude číst standardní vstup, a kdekoliv se v něm objeví PC, bude zaměněno za Amiga.
Základní funkce scanneru vygenerovaného flexem je číst standardní vstup, a když v něm není nalezen žádný vzor, pouze jej zkopíruje na výstup. Pokud ale je vzor rozpoznán, je vykonána odpovídající akce. Náš malý příklad měl jediné pravidlo, v němž PC je vzorem a printf(„Amiga“); je akce. Znaky %% označují začátek pravidel.
To byl pochopitelně velmi jednoduchý příklad. Před ony dva znaky označující začátek pravidel lze uvést jména proměnných, které budete používat. Takže tam přidejte lines=0;. Přidejte pravidlo, jehož vzorem bude (známý céčkový dvojznak pro nový řádek) a jeho akci fines++; (mezi pravidly vynechte volný řádek). Za pravidla přidejte opět dva znaky %% a za ně můžete připojit libovolné céčkové rutiny. Takže tam napište:

main()
{
yylex();
printf(„ %d “, lines);
}

Když teď tento lexový program přeložíte až do spustitelného programu a spustíte, zjistíte, že po přechroustání vstupu bude navíc vypsán počet řádku vstupu.
Pochopitelně není vhodné číst vstup pouze z konzoly či používat přesměrování standardního vstupu, proto když otevřete (standardní céčkovou funkci fopen()) soubor do proměnné se jménem yyin, bude vstup čten z tohoto souboru místo ze standardního vstupu. Podobně yyout může specifikovat výstupní soubor.
Ve vzorech lze pochopitelně specifikovat nejen nový řádek, ale třeba i tabulátor ( ), znak tečka bude označovat jakýkoliv znak. [0-9] znamená jednu číslici, [0-9]+ znamená několik číslic (ale alespoň jedna), kdežto použití hvězdičky místo plusu znamená žádná nebo několik číslic.
Shrňme si znovu formát vstupního souboru. Ten je rozdělen do tří částí: definice, pravidla a uživatelský kód. Mezi dvěma částmi je vždy řádek, na němž jsou pouze znaky %%. V definicích je možné uvést proměnné, které pak budou v analyzátoru uvedeny. Je zde také možné definovat symbolické jméno pro nějaké symboly, například řádek DIGIT [0-9] zajistí, že kdykoliv později v pravidlech uvedeme {DIGIT}, bude toto nahrazeno zadefinovaným výrazem.
Část s pravidly nám umožňuje ke každému vzoru zadat akci (kód v céčku), která bude provedena, je-li ve vstupu rozpoznán nějaký text odpovídající uvedenému vzoru. Odpovídá-li text více vzorům, bude vybrán vzor, podle něhož je text nejdelší. Pokud existuje více vzorů popisujících stejnou maximální délku textu, bude použit vzor, který je uvedený jako první.
Akce uvedené v části s pravidly jsou zahrnuty přímo do generované funkce yylex() a tato funkce vrací hodnotu typu integer. To je velice vhodné, jelikož do akce můžeme dát např. return(NUMBER);, kde NUMBER bude symbol označující číslo a tento symbol bude pak zpracovávat syntaktická analýza. Takto je zapojený lexikální analyzátor do syntaktického analyzátoru vygenerovaného yacc-em (nebo bisonem) a pro každý rozpoznaný vstupní symbol nám funkce yylex() vrátí jeho kód, pro nerozpoznané se vloží rutina pro vypsání chyby.
Do poslední části si pak můžete zapsat podpůrné rutiny, které budete potřebovat volat v akcích, případně nějaké funkce navíc, které přímo souvisí s lexikální analýzou, a tudíž je vhodné je držet v jednom souboru s definicí scanneru.
Vraťme se ještě k definic pravidel. Jak si určitě pozorný čtenář všiml, to že tečka je použita jako vyjádření jakéhokoliv znaku (tudíž je většinou použita pro odhalení chyby, jelikož bude vybrána právě když nesedí žádné jiné pravidlo), což ovšem zabraňuje jejímu použití jako symbolu vstupu. To lze pochopitelně velmi jednoduše vyřešit - stačí ji uzavřít do uvozovek a bude rozpoznána takto. Podobně jsou použity jiné znaky - kromě již výše zmíněných hranatých závorek je to třeba lomítko: vzor R/S nám rozpozná na vstupu symbol R pouze tehdy, je-li za ním symbol S. Takto lze kontextově odlišit přímo v lexikální analýze různé významy stejného symbolu.
Pochopitelně je vhodné také třeba rozpoznat nějaký symbol v závislosti na tom, co bylo před ním. Protože se ve vstupu nelze jednoduše vracet (vstup může být složen z více souborů), lze definovat stavy, v kterých se scanner nachází. Takto lze například zadefinovat pro Pascal

if BEGIN(IF);
<IF>then BEGIN(INITIAL);
then error();

Pochopitelně to chce uvést více kódu ke každému pravidlu, ale takto zadefinovaná pravidla nám umožňují již v lexikální analýze rozpoznat, kdy je příkaz then uveden na špatném místě (ve skutečnosti by ale bylo správné tuto kontrolu uvést až v syntaktické analýze; jedno praktické využití se ale nabízí - při začátku poznámky v programu bude nastaven nový stav a vše přicházející se bude řídit podle nového podmíněného pravidla až do konce poznámky).
Bylo by pochopitelně neužitečné, kdyby funkce yylex() uměla číst vstup pouze ze souboru. Jak se dalo předpokládat, umí tato funkce číst vstup i z oblasti paměti (bud řetězce ukončeného nulou anebo obecně z kusu paměti o zadané délce), pomocí podmíněných pravidel lze ale i velice rozumně zvládnout i vkládání souborů do sebe (např. to, co dělá direktiva #include v céčku). Po rozpoznání direktivy uvozující jméno vkládaného souboru se podmíněným pravidlem načte jméno souboru, automat upraví na nový vstup a do zásobníku se uloží, že se automat vnořil. Jakmile dojde scanner na konec tohoto souboru, zavolá funkci yywrap(), která má vrátit jedničku, pokud se skutečně jedná o konec vstupu, nulu pokud bude vstup ještě pokračovat - tehdy se nastaví pokračování ve čtení původního souboru.
Jazyk pro Flex toho umí mnohem více, ale dále se podrobnostmi nebudu zabývat. Každý, kdo si chce napsat vlastní programovací jazyk či alespoň nějaký interní jazyk pro svou aplikaci, se vše dočte v obsáhlé (111kB) dokumentaci.
Novinkou u Flexe je možnost generování výstupu pro jazyk C++, kde je scanner vytvořen jako třída yyFlexLexer, která drží potřebné informace pro scanner jako svá data (na rozdíl od výstupu vygenerovaného pro obyčejné céčko, kde jsou vygenerovány jako globální proměnné), což umožňuje mít v programu scannerů několik, případně i reenratntní scannery. Potřebné funkce jsou pak pochopitelně dostupné jako metody objektu této třídy a u vstupu a výstupu je místo souboru použit stream. Vygenerovaný soubor se bude jmenovat lex.yy.cc, vstupní soubor je pochopitelně stejný při generování jak pro C tak pro C++. Generování pro C++ lze zapnout parametrem -+, případně uvedením %option c++ na začátku vstupního souboru.
Flex vám ušetří spoustu práce, pokud chcete psát nějakou lexikální analýzu a nemáte čas nakódovat si vlastní scanner. Ten může být pochopitelně rychlejší, ale ne o mnoho, Flex generuje velice rychlé automaty řízené tabulkami. Pokud skutečně máte spoustu času a chuti, sežeňte si o tom literaturu a napište si scanner vlastní, jinak použijte Flex.
A pochopitelně Flex je napsán s pomocí Flexe (a Bisona).

Flex 2.5.4

Hodnocení: 9,0 z 10
Autor: V. Paxson
Cena: -
Typ: freeware

+

podmíněná pravidla, C++ interface, zdarma

-

další programovací jazyk

Vytlačiť článok



Pozn.: články boli naskenované ako text a preto obsahujú aj zopár chýb. Taktiež neručíme za zdrojové kódy (Asm, C, Arexx, AmigaGuide, Html) a odkazy na web. Dúfame, že napriek tomu vám táto databáza dobre poslúži.

Žiadna časť nesmie byť reprodukovaná alebo inak šírená bez písomného povolenia vydavatela © ATLANTIDA Publishing



none

AMIGA REVIEW

57 ( 11-12 / 2000 )
56 ( 9-10 / 2000 )
55 ( 7-8 / 2000 )
54 ( 5-6 / 2000 )
53 ( 3-4 / 2000 )
52 ( 1-2 / 2000 )
 
51 ( 12 / 1999 )
50 ( 11 / 1999 )
49 ( 10 / 1999 )
48 ( 9 / 1999 )
46-47 ( 7-8 / 1999 )
45 ( 6 / 1999 )
44 ( 5 / 1999 )
43 ( 4 / 1999 )
42 ( 3 / 1999 )
41 ( 2 / 1999 )
40 ( 1 / 1999 )
 
39 ( 12 / 1998 )
38 ( 11 / 1998 )
37 ( 10 / 1998 )
36 ( 9 / 1998 )
35 ( x / 1998 )
34 ( x / 1998 )
33 ( 1-2 / 1998 )
 
32 ( 11-12 / 1997 )
31 ( 9-10 / 1997 )
30 ( 7-8 / 1997 )
29 ( 6 / 1997 )
28 ( 5 / 1997 )
27 ( 4 / 1997 )
26 ( 3 / 1997 )
25 ( 2 / 1997 )
24 ( 1 / 1997 )
 
23 ( 12 / 1996 )
22 ( 11 / 1996 )
21 ( 10 / 1996 )
20 ( 9 / 1996 )
18-19 ( 7-8 / 1996 )
17 ( 6 / 1996 )
16 ( 5 / 1996 )
15 ( 4 / 1996 )
14 ( 3 / 1996 )
13 ( 2 / 1996 )
12 ( 1 / 1996 )
 
11 ( 12 / 1995 )
10 ( 11 / 1995 )
9 ( 10 / 1995 )
8 ( 9 / 1995 )
7 ( 7 / 1995 )
6 ( 5 / 1995 )

ATLANTIDA NEWS

5 ( 3 / 1995 )
4 ( 1 / 1995 )
 
3 ( 11 / 1994 )
2 ( 9 / 1994 )
1 ( 7 / 1994 )
0 ( 5 / 1994 )