Trywialny projekt w flex krok po kroku

Stworzenie prostego leksera będzie składać się z następujących kroków:

  1. Stworzenie pliku lexa.
  2. Wygenerowanie kodu.
  3. Skompilowanie całości do postaci wykonywalnej.
  4. Test.

Naszym celem w trakcie tego poradnika jest stworzenie prostego leksera, który każde wystąpienie słowa username będzie zastępować naszym prawdziwym loginem (za poradnikiem którego adresu nie pamiętam:P).

Stworzenie pliku lexa.

cała struktura pliku lexa składa się z trzech sekcji:

definicje
%%
reguły
%%
kod użytkownika
definicje
definiują używane symbole (bardzo często za pomocą wyrażeń regularnych), np. "jeśli napotkasz znak od 0 do 9 to wiedz, że jest to symbol cyfra". Często znajduje się tutaj też dodatkowa podsekcja dodawania do wygenerowanego kodu dodatkowych deklaracji języka C i C++ (takich jak deklaracje zmiennych globalnych, instrukcje włączania #include itp.).
reguły
określają, jaki kod wygenerować dla danego symbolu, np. "jeśli napotkany symbol jest liczbą, to zrób to i to".
kod użytkownika
kod który ma być dodany do wygenerowanego pliku. Najczęściej jest to funkcja main, w której m. in. wywoływana jest funkcja yylex();

Skoro już wiemy, co znajduje się w każdej sekcji, możemy przystąpić do pisania własnego pliku.
Nasza struktura będzie oparta na takiej koncepcji:

nic nie definiujemy, bo nie mamy takiej potrzeby
%%
jeśli napotkasz ciąg znaków "username", to w jego miejsce wypisz mój login
%%
main
{
    wywołaj funkcją yylex()
}

Teraz przeniesiemy to do prawdziwego kodu. Do wypisania loginu wykorzystamy funkcję systemową Linuxa: getlogin().

%%
 
username printf("%s", getlogin());
 
%%
 
int main(int argc, char** argv)
{
 yylex(); //wywołujemy funkcję yylex(), która zostanie dla nas wygenerowana.
 return 0;
}

W ten sposób mamy gotowy plik lexa. Nazwijmy go sobie user.l

Wygenerowanie kodu.

Kod za pomocą lexa generuje się w najprostszym wypadku następującym poleceniem:

flex nazwapliku

Na skutek tego wywołania powinien powwstać plik o nazwie lex.yy.c. Zawiera on także naszego maina, którego napisaliśmy w pliku user.l. Można też, jeśli komuś nie podoba się nazwa wygenerowanego pliku, zastosować przełącznik -o, np.

flex -o user.c user.l

Jedyna różnica jest w nazwie wygenerowanego pliku (tu nazywa się user.c zamiast lex.yy.cc). Dalej zakładam, że plik nosi standardową nazwę lex.yy.cc.

Skompilowanie całości do postaci wykonywalnej.

Przy kompilacji należy pamiętać o jednej rzeczy - zlinkowaniu biblioteki flexa za pomocą przełącznika -lfl. Cała reszta jest standardowa:

gcc lex.yy.c -o user -lfl

Lub, jeśli ktoś woli:
gcc lex.yy.c -o user -Wall -pedantic -O2 -lfl

Wyprodukuje to plik wykonywalny o nazwie user.

Test.

Pozostaje teraz odpalenie programu user. Będzie on konwertować łańcuch "username" w wpisanym przez nas tekście na nasz login. Przykładowa sesja z programem może wyglądać tak:

astral@astral-laptop:~/Programming/flex$ ./user
Mój login to username. Podkreślam jeszcze raz: username!
Mój login to astral. Podkreślam jeszcze raz: astral!

astralastral

Literatura:

Dokumentacja flexa, z której pochodzi zamieszczony przykład.
Bardzo zwięzłe wprowadzenie. Zero lania wody. Same konkrety.

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