Transcript LEX
Slide 1
LEX
Generator analizatorów
leksykalnych
Slide 2
GENERATOR L E X
Zadaniem generatora LEX jest
wygenerowanie kodu źródłowego
analizatora leksykalnego (domyślnie) w
języku C;
Kod źródłowy generowany jest przez
LEX’a w oparciu o plik zawierający
wszystkie reguły przetwarzania;
Plik z regułami tworzony jest przez
samego użytkownika;
2
Slide 3
GENERATOR L E X
Schemat organizacji działania LEX’a:
scan.l
LEX
scan.c
GCC
scane.exe
plik.txt
WYNIK
3
Slide 4
GENERATOR L E X
flex –l scan.l (użycie generatora
LEX)
gcc scan.c -o scan.exe (kompilacja
C++)
scan.exe < plik.txt (analiza plik.txt)
4
Slide 5
GENERATOR L E X
Ważną cechą analizatora jest możliwość
wykorzystania go do większych aplikacji;
Każdy wygenerowany kod źródłowy
zawiera bowiem funkcję, dzięki której
można podłączyć analizator leksykalny do
innych aplikacji. Funkcja o której mowa to
yylex();
5
Slide 6
TWORZENIE PLIKU REGUŁ
Każdy plik ze specyfikacją dla programu
LEX powinien składać się z trzech sekcji;
Pierwsza sekcja to sekcja definicji;
W sekcji definicji umieszczamy, jak sama
nazwa wskazuje, definicje i deklaracje
zmiennych, stałych, deklaracje stanów
oraz makra procesora;
6
Slide 7
TWORZENIE PLIKU REGUŁ
Sekcja definicji może zawierać fragment
kodu, który system przepisze
bezpośrednio do analizatora leksykalnego;
Kod ten musi być odpowiednio
„opakowany”;
Otwarcie fragmentu bezpośrednio
przepisywanego do analizatora powinno
być poprzedzone znacznikiem %{,
natomiast jej zamknięcie %};
7
Slide 8
TWORZENIE PLIKU REGUŁ
Przykład budowy sekcji definicji:
%{
#include
int zmienna;
int yylex();
int zmienna_druga=1;
%}
8
Slide 9
TWORZENIE PLIKU REGUŁ
Druga sekcja to sekcja przetwarzania;
W sekcji przetwarzania umieszczamy
wszelkie reguły postępowania, zgodnie z
którymi wygenerowany będzie analizator;
Reguły postępowania to inaczej przepisy
na to co analizator ma zrobić gdy
napotyka na określony „problem” (symbol);
9
Slide 10
TWORZENIE PLIKU REGUŁ
Budowa reguły przetwarzania opiera się
na dwóch zasadniczych częściach: wzorca
i operacji;
Jej budowa wygląda więc:
wzorzec
operacja
Wzorzec jest zapisywany jako wyrażenie
regularne;
Operacja jest blokiem instrukcji języka C;
10
Slide 11
TWORZENIE PLIKU REGUŁ
Przykład budowy reguły przetwarzania:
(a+b)*a(a+b)2 cout<<‘’W słowie A trzeci
symbol od końca
jest równy a’’;
11
Slide 12
WYRAŻENIA REGULARNE
Podamy teraz kilka symboli używanych
do zapisu wyrażeń regularnych
występujących we wzorcach reguł
przetwarzania:
1. Symbole linii:
^…- początek linii;
…$ - koniec linii;
12
Slide 13
WYRAŻENIA REGULARNE
2. Symbole operacji logicznych:
ab - konkatenacja;
a|b - alternatywa;
a* - domknięcie zwrotne (domknięcie);
a+ - domknięcie dodatnie (domknięcie po
odjęciu słowa pustego);
a? – opcjonalność (symbol „a” nie występuje
lub występuje jeden raz);
13
Slide 14
WYRAŻENIA REGULARNE
3. Powtarzanie symbolu:
a{n} – powtórzenie symbolu „a” n – razy;
a{n,m} – zakres powtarzania symbolu (czyli
an,…,am);
() – określają stopień ważności (c(a|d)|(e+)
);
14
Slide 15
WYRAŻENIA REGULARNE
4. Klasy znaków:
[a-z] - oznacza dowolny znak z zakresu od
małej litery „a” do małej litery „z”;
[^a-z] – oznacza dowolny znak spoza klasy
[a-z] (jak gdyby „negacja”
zakresu);
[a-zXY] – oznacza dowolny znak z zakresu
[a-z] lub wielką literę X lub Y;
[0-9] – oznacza dowolną cyfrę od 0 do 9;
Slide 16
WYRAŻENIA REGULARNE
4. Klasy znaków (c.d.):
. - oznacza dowolny znak nie będący
znakiem końca linii;
\... – poprzedza sekwencje specjalne
(podobnie jak w C) np.:
\n – oznacza znak końca linii;
\t – oznacza znak tabulatora;
16
Slide 17
TWORZENIE PLIKU REGUŁ
Przykład budowy reguły przetwarzania:
(a+b)*a(a+b)2 cout<<‘’W słowie A trzeci
symbol od końca
jest równy a’’;
Powinniśmy wpisać:
(a|b)*a(a|b){2} cout<<‘’W słowie A trzeci
symbol od końca
jest równy a’’;
17
Slide 18
WYRAŻENIA REGULARNE
Inne ważne zasady tworzenia wzorców:
Wzorce zawierające spacje ujmuje się w
cudzysłów;
Komentarz wpisuje się między znaczniki
/* a */;
Niedopasowane znaki są przepisywane
na wyjście;
18
Slide 19
Przykład
Wyrażenie regularne akceptujące adres strony
internetowej:
[Ww]{3} \. [A-Za-z0-9._-]+ \. [A-Za-z]{3} \. [Pp] [Ll]
19
Slide 20
Przykład
Wyrażenie regularne akceptujące słowa kluczowe
w Adzie begin i end:
[A-Za-z]{3,5}
[A-Za-z]{5} | [A-Za-z]{3}
[Bb][Ee][Gg][Ii][Nn] | [Ee][Nn][Dd]
20
Slide 21
Przykład
Wyrażenie regularne akceptujące wszelkie
identyfikatory (zmienne, stałe ) w C:
[A-Za-z _ ] [A-Za-z0-9 _ ]*
21
Slide 22
Przykład
Wyrażenie regularne akceptujące datę:
([0-9]{2} \- [0-9]{2} \- [0-9]{4}) |
([0-9]{2} \. [0-9]{2} \. [0-9]{4}) |
([0-9]{4} \- [0-9]{2} \- [0-9]{2}) |
([0-9]{4} \. [0-9]{2} \. [0-9]{2})
([0-9]{2} (\- | \.) [0-9]{2} (\- | \.) [0-9]{4}) |
([0-9]{4} (\- | \.) [0-9]{2} (\- | \.) [0-9]{2})
22
Slide 23
Przykład
Wyrażenie regularne akceptujące wszelkie
adresy poczty e-mail:
[A-Za-z0-9 . _ -]+@[A-Za-z0-9 . _ ]+\.[A-Za-z]{2,4}
23
Slide 24
TWORZENIE PLIKU REGUŁ
Trzecią sekcją składową pliku ze
specyfikacją dla programu LEX jest sekcja
podprogramów;
W skład sekcji podprogramów mogą, jak
sama nazwa wskazuje, wchodzić definicje
funkcje, które będą następnie
wykorzystywane przez analizator
leksykalny;
24
Slide 25
TWORZENIE PLIKU REGUŁ
Deklaracja funkcji wchodzących w skład
tej sekcji poddana jest regułą tworzenia
funkcji w języku C;
Funkcja yywrap() – jest to funkcja o
specjalnym znaczeniu. Gdy wywołujemy
(uprzednio wygenerowany) analizator
leksykalny, funkcja yywrap() jest
wykonywana zawsze po przetworzeniu
danych wejściowych;
25
Slide 26
Przykład
Przykład funkcji znajdującej się w sekcji
podprogramów:
int main()
{
return yylex();
}
Wymaga ona oczywiście wcześniejszej
deklaracji yylex’a w postaci zwrotu:
int yylex();
26
Slide 27
TWORZENIE PLIKU REGUŁ
Przy tworzeniu pliku reguł przetwarzania
można korzystać z zmiennych globalnych;
Deklaracja tego typu zmiennych znajduje
się w pierwszej sekcji (sekcji definicji)
pliku;
Zmienne globalne, mogą być oczywiście
wykorzystywane w każdej następnej
sekcji, np. inkrementowane, zmieniane,
czy odczytywane;
27
Slide 28
TWORZENIE PLIKU REGUŁ
Oprócz zmiennych globalnych można także
korzystać ze zmiennych wbudowanych;
Mamy dwie szczególnie ważne zmienne
wbudowane yyleng i yytext;
Zmienna yyleng jest typu int i okresla długość
dopasowania;
Zmienna yytext jest znakiem (char) a dokładniej
ciągiem znaków, wskazuje na leskem (odnajduje
w strumieniu danych wejściowych, zapis który
pasował do wzorca);
28
Slide 29
TWORZENIE PLIKU REGUŁ
Pożyteczną rolę odgrywają także definicje
regularne;
Tworzenie definicji regularnej to inaczej
przypisanie wyrażeniu regularnemu
pewnego identyfikatora;
Identyfikator ten może być wykorzystany
później w polu wzorca;
Definicja regularna jest tworzona w sekcji
definicji;
29
Slide 30
Przykład
Definicje regularną umieszczamy co
prawda w sekcji definicji, jednakże po
bloku bezpośrednio przepisywanym do
analizatora;
Zobaczmy następujący przykład, który
pokazuje sposób korzystania z
zadeklarowanego identyfikatora;
30
Slide 31
Przykład
%{
#include
int yylex();
%}
identyfikator [Ii] [Ff]
%%
{identyfikator} {cout<<‘’ Wczytano leksem IF’’;}
%%
31
Slide 32
TWORZENIE PLIKU REGUŁ
Wszystkie trzy omówione sekcje składowe
pliku ze specyfikacją dla programu LEX
oddzielane są podwójnym znakiem
procenta - %%;
Schemat pliku ze specyfikacją reguł dla
programu LEX możemy więc
zademonstrować w tabeli:
32
Slide 33
TWORZENIE PLIKU REGUŁ
SEKCJA DEFINICJI
%%
SEKCJA REGUŁ PRZETWARZANIA
%%
SEKCJA PODPROGRAMÓW
...
Slide 34
NIEJEDNOZNACZNOŚĆ
Gdy przeanalizowaliśmy już zasadę
działania generatora LEX, możemy
przyjrzeć się istotnemu problemowi
niejednoznaczności przy działaniu LEX;
Przykład:
m* {cout<<‘’*’’;}
mmm {cout<<‘’+’’;}
Dostarczamy strumień danych postaci:
mmmmmmmmmm;mmm
34
Slide 35
NIEJEDNOZNACZNOŚĆ
ZASADA NAJDŁUŻSZEGO
DOPASOWANIA – określa, iż jeśli mamy
dwie lub więcej reguł dla których wzorce
są spełnione, to wybierana jest ta reguła
dla której dopasowanie wzorca jest
najdłuższe;
ZASADA WCZEŚNIEJSZEGO
DOPASOWANIA – mówi iż, gdy
dopasowania maja identyczną długość,
wybrana jest reguła, która została
umieszczona pierwsza w pliku
specyfikacji;
35
Slide 36
NIEJEDNOZNACZNOŚĆ
Stosując zatem zasadę pierwszą w
przykładzie, dane wyjściowe będą
wyglądały:
*;+
Gdybyśmy zaś mieli dane wejściowe
postaci
mmm
to stosując drugą zasadę dostaniemy na
wyjściu
+
36
Slide 37
RETRAKCJA
Pojęcie retrakcji wiąże się ze sposobem
działania analizatora;
Analizator przetwarza wiele wzorców
równolegle w poszukiwaniu najlepszego
(tzn. najdłuższego) . Porzuca on z czasem
wzorce mniej „obiecujące” koncentrując
się na wzorcach, które mogą dać dłuższe
dopasowania;
W sytuacji niepowodzenia wraca do
porzuconych wzorców;...
37
Slide 38
KONIEC
KONIEC WYKŁADU TRZECIEGO
LEX
Generator analizatorów
leksykalnych
Slide 2
GENERATOR L E X
Zadaniem generatora LEX jest
wygenerowanie kodu źródłowego
analizatora leksykalnego (domyślnie) w
języku C;
Kod źródłowy generowany jest przez
LEX’a w oparciu o plik zawierający
wszystkie reguły przetwarzania;
Plik z regułami tworzony jest przez
samego użytkownika;
2
Slide 3
GENERATOR L E X
Schemat organizacji działania LEX’a:
scan.l
LEX
scan.c
GCC
scane.exe
plik.txt
WYNIK
3
Slide 4
GENERATOR L E X
flex –l scan.l (użycie generatora
LEX)
gcc scan.c -o scan.exe (kompilacja
C++)
scan.exe < plik.txt (analiza plik.txt)
4
Slide 5
GENERATOR L E X
Ważną cechą analizatora jest możliwość
wykorzystania go do większych aplikacji;
Każdy wygenerowany kod źródłowy
zawiera bowiem funkcję, dzięki której
można podłączyć analizator leksykalny do
innych aplikacji. Funkcja o której mowa to
yylex();
5
Slide 6
TWORZENIE PLIKU REGUŁ
Każdy plik ze specyfikacją dla programu
LEX powinien składać się z trzech sekcji;
Pierwsza sekcja to sekcja definicji;
W sekcji definicji umieszczamy, jak sama
nazwa wskazuje, definicje i deklaracje
zmiennych, stałych, deklaracje stanów
oraz makra procesora;
6
Slide 7
TWORZENIE PLIKU REGUŁ
Sekcja definicji może zawierać fragment
kodu, który system przepisze
bezpośrednio do analizatora leksykalnego;
Kod ten musi być odpowiednio
„opakowany”;
Otwarcie fragmentu bezpośrednio
przepisywanego do analizatora powinno
być poprzedzone znacznikiem %{,
natomiast jej zamknięcie %};
7
Slide 8
TWORZENIE PLIKU REGUŁ
Przykład budowy sekcji definicji:
%{
#include
int zmienna;
int yylex();
int zmienna_druga=1;
%}
8
Slide 9
TWORZENIE PLIKU REGUŁ
Druga sekcja to sekcja przetwarzania;
W sekcji przetwarzania umieszczamy
wszelkie reguły postępowania, zgodnie z
którymi wygenerowany będzie analizator;
Reguły postępowania to inaczej przepisy
na to co analizator ma zrobić gdy
napotyka na określony „problem” (symbol);
9
Slide 10
TWORZENIE PLIKU REGUŁ
Budowa reguły przetwarzania opiera się
na dwóch zasadniczych częściach: wzorca
i operacji;
Jej budowa wygląda więc:
wzorzec
operacja
Wzorzec jest zapisywany jako wyrażenie
regularne;
Operacja jest blokiem instrukcji języka C;
10
Slide 11
TWORZENIE PLIKU REGUŁ
Przykład budowy reguły przetwarzania:
(a+b)*a(a+b)2 cout<<‘’W słowie A trzeci
symbol od końca
jest równy a’’;
11
Slide 12
WYRAŻENIA REGULARNE
Podamy teraz kilka symboli używanych
do zapisu wyrażeń regularnych
występujących we wzorcach reguł
przetwarzania:
1. Symbole linii:
^…- początek linii;
…$ - koniec linii;
12
Slide 13
WYRAŻENIA REGULARNE
2. Symbole operacji logicznych:
ab - konkatenacja;
a|b - alternatywa;
a* - domknięcie zwrotne (domknięcie);
a+ - domknięcie dodatnie (domknięcie po
odjęciu słowa pustego);
a? – opcjonalność (symbol „a” nie występuje
lub występuje jeden raz);
13
Slide 14
WYRAŻENIA REGULARNE
3. Powtarzanie symbolu:
a{n} – powtórzenie symbolu „a” n – razy;
a{n,m} – zakres powtarzania symbolu (czyli
an,…,am);
() – określają stopień ważności (c(a|d)|(e+)
);
14
Slide 15
WYRAŻENIA REGULARNE
4. Klasy znaków:
[a-z] - oznacza dowolny znak z zakresu od
małej litery „a” do małej litery „z”;
[^a-z] – oznacza dowolny znak spoza klasy
[a-z] (jak gdyby „negacja”
zakresu);
[a-zXY] – oznacza dowolny znak z zakresu
[a-z] lub wielką literę X lub Y;
[0-9] – oznacza dowolną cyfrę od 0 do 9;
Slide 16
WYRAŻENIA REGULARNE
4. Klasy znaków (c.d.):
. - oznacza dowolny znak nie będący
znakiem końca linii;
\... – poprzedza sekwencje specjalne
(podobnie jak w C) np.:
\n – oznacza znak końca linii;
\t – oznacza znak tabulatora;
16
Slide 17
TWORZENIE PLIKU REGUŁ
Przykład budowy reguły przetwarzania:
(a+b)*a(a+b)2 cout<<‘’W słowie A trzeci
symbol od końca
jest równy a’’;
Powinniśmy wpisać:
(a|b)*a(a|b){2} cout<<‘’W słowie A trzeci
symbol od końca
jest równy a’’;
17
Slide 18
WYRAŻENIA REGULARNE
Inne ważne zasady tworzenia wzorców:
Wzorce zawierające spacje ujmuje się w
cudzysłów;
Komentarz wpisuje się między znaczniki
/* a */;
Niedopasowane znaki są przepisywane
na wyjście;
18
Slide 19
Przykład
Wyrażenie regularne akceptujące adres strony
internetowej:
[Ww]{3} \. [A-Za-z0-9._-]+ \. [A-Za-z]{3} \. [Pp] [Ll]
19
Slide 20
Przykład
Wyrażenie regularne akceptujące słowa kluczowe
w Adzie begin i end:
[A-Za-z]{3,5}
[A-Za-z]{5} | [A-Za-z]{3}
[Bb][Ee][Gg][Ii][Nn] | [Ee][Nn][Dd]
20
Slide 21
Przykład
Wyrażenie regularne akceptujące wszelkie
identyfikatory (zmienne, stałe ) w C:
[A-Za-z _ ] [A-Za-z0-9 _ ]*
21
Slide 22
Przykład
Wyrażenie regularne akceptujące datę:
([0-9]{2} \- [0-9]{2} \- [0-9]{4}) |
([0-9]{2} \. [0-9]{2} \. [0-9]{4}) |
([0-9]{4} \- [0-9]{2} \- [0-9]{2}) |
([0-9]{4} \. [0-9]{2} \. [0-9]{2})
([0-9]{2} (\- | \.) [0-9]{2} (\- | \.) [0-9]{4}) |
([0-9]{4} (\- | \.) [0-9]{2} (\- | \.) [0-9]{2})
22
Slide 23
Przykład
Wyrażenie regularne akceptujące wszelkie
adresy poczty e-mail:
[A-Za-z0-9 . _ -]+@[A-Za-z0-9 . _ ]+\.[A-Za-z]{2,4}
23
Slide 24
TWORZENIE PLIKU REGUŁ
Trzecią sekcją składową pliku ze
specyfikacją dla programu LEX jest sekcja
podprogramów;
W skład sekcji podprogramów mogą, jak
sama nazwa wskazuje, wchodzić definicje
funkcje, które będą następnie
wykorzystywane przez analizator
leksykalny;
24
Slide 25
TWORZENIE PLIKU REGUŁ
Deklaracja funkcji wchodzących w skład
tej sekcji poddana jest regułą tworzenia
funkcji w języku C;
Funkcja yywrap() – jest to funkcja o
specjalnym znaczeniu. Gdy wywołujemy
(uprzednio wygenerowany) analizator
leksykalny, funkcja yywrap() jest
wykonywana zawsze po przetworzeniu
danych wejściowych;
25
Slide 26
Przykład
Przykład funkcji znajdującej się w sekcji
podprogramów:
int main()
{
return yylex();
}
Wymaga ona oczywiście wcześniejszej
deklaracji yylex’a w postaci zwrotu:
int yylex();
26
Slide 27
TWORZENIE PLIKU REGUŁ
Przy tworzeniu pliku reguł przetwarzania
można korzystać z zmiennych globalnych;
Deklaracja tego typu zmiennych znajduje
się w pierwszej sekcji (sekcji definicji)
pliku;
Zmienne globalne, mogą być oczywiście
wykorzystywane w każdej następnej
sekcji, np. inkrementowane, zmieniane,
czy odczytywane;
27
Slide 28
TWORZENIE PLIKU REGUŁ
Oprócz zmiennych globalnych można także
korzystać ze zmiennych wbudowanych;
Mamy dwie szczególnie ważne zmienne
wbudowane yyleng i yytext;
Zmienna yyleng jest typu int i okresla długość
dopasowania;
Zmienna yytext jest znakiem (char) a dokładniej
ciągiem znaków, wskazuje na leskem (odnajduje
w strumieniu danych wejściowych, zapis który
pasował do wzorca);
28
Slide 29
TWORZENIE PLIKU REGUŁ
Pożyteczną rolę odgrywają także definicje
regularne;
Tworzenie definicji regularnej to inaczej
przypisanie wyrażeniu regularnemu
pewnego identyfikatora;
Identyfikator ten może być wykorzystany
później w polu wzorca;
Definicja regularna jest tworzona w sekcji
definicji;
29
Slide 30
Przykład
Definicje regularną umieszczamy co
prawda w sekcji definicji, jednakże po
bloku bezpośrednio przepisywanym do
analizatora;
Zobaczmy następujący przykład, który
pokazuje sposób korzystania z
zadeklarowanego identyfikatora;
30
Slide 31
Przykład
%{
#include
int yylex();
%}
identyfikator [Ii] [Ff]
%%
{identyfikator} {cout<<‘’ Wczytano leksem IF’’;}
%%
31
Slide 32
TWORZENIE PLIKU REGUŁ
Wszystkie trzy omówione sekcje składowe
pliku ze specyfikacją dla programu LEX
oddzielane są podwójnym znakiem
procenta - %%;
Schemat pliku ze specyfikacją reguł dla
programu LEX możemy więc
zademonstrować w tabeli:
32
Slide 33
TWORZENIE PLIKU REGUŁ
SEKCJA DEFINICJI
%%
SEKCJA REGUŁ PRZETWARZANIA
%%
SEKCJA PODPROGRAMÓW
...
Slide 34
NIEJEDNOZNACZNOŚĆ
Gdy przeanalizowaliśmy już zasadę
działania generatora LEX, możemy
przyjrzeć się istotnemu problemowi
niejednoznaczności przy działaniu LEX;
Przykład:
m* {cout<<‘’*’’;}
mmm {cout<<‘’+’’;}
Dostarczamy strumień danych postaci:
mmmmmmmmmm;mmm
34
Slide 35
NIEJEDNOZNACZNOŚĆ
ZASADA NAJDŁUŻSZEGO
DOPASOWANIA – określa, iż jeśli mamy
dwie lub więcej reguł dla których wzorce
są spełnione, to wybierana jest ta reguła
dla której dopasowanie wzorca jest
najdłuższe;
ZASADA WCZEŚNIEJSZEGO
DOPASOWANIA – mówi iż, gdy
dopasowania maja identyczną długość,
wybrana jest reguła, która została
umieszczona pierwsza w pliku
specyfikacji;
35
Slide 36
NIEJEDNOZNACZNOŚĆ
Stosując zatem zasadę pierwszą w
przykładzie, dane wyjściowe będą
wyglądały:
*;+
Gdybyśmy zaś mieli dane wejściowe
postaci
mmm
to stosując drugą zasadę dostaniemy na
wyjściu
+
36
Slide 37
RETRAKCJA
Pojęcie retrakcji wiąże się ze sposobem
działania analizatora;
Analizator przetwarza wiele wzorców
równolegle w poszukiwaniu najlepszego
(tzn. najdłuższego) . Porzuca on z czasem
wzorce mniej „obiecujące” koncentrując
się na wzorcach, które mogą dać dłuższe
dopasowania;
W sytuacji niepowodzenia wraca do
porzuconych wzorców;...
37
Slide 38
KONIEC
KONIEC WYKŁADU TRZECIEGO