Flex - ćwiczenie 01: zliczanie słów w tekście.

Ten tutorial powstał na podstawie innego tutoriala, do którego link znajduje się na dole strony.

Tym razem zrobimy prosty licznik słów dla wprowadzonego tekstu.

W stosunku do poprzedniego artykułu wykorzystamy następujące nowe rzeczy:

  1. Deklaracje zmiennych, symboli i włączanie nagłówków w części definicyjnej pliku flexa.
  2. Opcja noyywrap.
  3. Dodamy trochę kodu w C++ i skompilujemy całość za pomocą g++.
  4. Przepuścimy zewnętrzny tekst przez nasz program.

Plik lexa.

Nasz licznik będzie miał (koncepcyjnie) następującą strukturę:

włączenie nagłówków języka C++ (a konkretnie nagłówka <iostream>)
deklaracja licznika słów w języku C++.

Symbole:
jeśli napotkasz znak od a do z albo od A do Z, to wiedz, że jest to LITERA.
jeśli napotkasz jedną lub więcej LITER, to wiedz, że jest to SŁOWO.

%%

Jeśli napotkasz SŁOWO, to zwiększ licznik słów o 1

%%

main
{
    wywołaj funkcję yylex()
    wypisz wartość licznika słów
}

Pierwsze zagadnienie na jakie napotykamy, to kod C/C++ w części definicyjnej (pierwszej). zamieszczamy go między znacznikami %{ i %} w następujący sposób:

%{

    jakiś kod

%}

Druga rzecz, jaką zrobimy, to dodanie opcji noyywrap do części definicyjnej. Opcja ta powoduje, przynajmniej na pierwszy rzut oka, tylko tyle, że nie trzeba podczas kompilacji linkować biblioteki flexa (chyba są jakieś konkretniejsze niuanse, muszę jeszcze zajrzeć:]). Robi się to w następujący sposób:

%option noyywrap

Reszta już idzie normalnie. W funkcji main, dla odmiany i dla sportu, korzystamy z instrukcji języka C++.

Cały kod flexa ma następującą postać:

%{
    #include<iostream>
 
    unsigned int wordsCount = 0;
%}
 
%option noyywrap
 
LETTER      [a-zA-Z]
WORD       {LETTER}+
 
%%
 
{WORD}    { wordsCount++; }
 
%%
 
int main(void)
{
    yylex();
    std::cout << std::endl << "Number of words: " << wordsCount << std::endl;
    return 0;
}

Jak widać, do zdefiniowania zarówno LITERY (LETTER) jak i SŁOWA (WORD) zastosowaliśmy wyrażenia regularne.

Przjrzyjmy się jeszcze linijce:

{WORD}    { wordsCount++; }

Widać tutaj, że obie klamry - zamykająca i otwierająca, są w tej samej linijce. W takiej sytuacji trzeba uważać, żeby podczas komentowania kodu nie zakomentować sobie tej drugiej klamry, np.

{WORD}    {// wordsCount++; } //BŁĄD - zakomentowaliśmy nie tylko instrukcję języka C, ale też klamrę zamykającą ten blok!!

Nazwijmy nasz plik WordCounter.l.

Wygenerowanie kodu.

Tu się nic nie zmienia w stosunku do poprzedniego przykładu.

Kompilacja do postaci wykonywalnej.

Jako że w pliku lexa zawarty jest kod w języku C++, musimy użyć kompilatora C++. Wywołanie kompilatora będzie więc miało następującą postać (dla wprawy linkujemy z biblioteką flexa, chociaż nie musimy tego robić):

g++ lex.yy.c -o WordCounter -lfl

Można też oczywiście dodać flagi: -Wall -pedantic -O2.

Test.

Test utworzonego programu można przeprowadzić na dwa sposoby. Pierwszy to normalne wykonanie programu, wpisanie kilku słów, następnie wciśnięcie klawisza enter i potem ctrl+d (czyli wprowadzenie znaku EOF). Drugi sposób to przepuszczenie napisu przez aplikację za pomocą operatora '|'. Przykład takiego wywołania:

astral@astral-laptop:~/Programming/flex/exc01$ echo 'Siala Baba mak i dostala dziesiec lat' | ./WordCounter 

Number of words: 7

To tyle. W tutorialu wymienionym w literaturze jest pokazany troszkę bardziej zaawansowany przykład (na którym z resztą ten tutorial się opiera), w którym zliczane są też linie i znaki.

astralastral

Literatura:

Artykuł na bazie którego powstał ten tutorial.

O ile nie zaznaczono inaczej, treść tej strony objęta jest licencją Creative Commons Attribution-Share Alike 2.5 License.