LLGEN Generator analizatorw skadniowych GENERATOR L LGEN Zadaniem

  • Slides: 42
Download presentation
LLGEN Generator analizatorów składniowych

LLGEN Generator analizatorów składniowych

GENERATOR L LGEN Zadaniem generatora LLgen jest wygenerowanie analizatora składniowego, inaczej parsera (w języku

GENERATOR L LGEN Zadaniem generatora LLgen jest wygenerowanie analizatora składniowego, inaczej parsera (w języku C) metodą zejść rekurencyjnych, bez nawrotów; Kod źródłowy generowany jest przez LLgen’a w oparciu o plik zawierający specyfikację; W specyfikacji można korzystać z rozszerzonych specyfikacji gramatyk LL(1). Ponieważ LLgen zawiera wbudowane mechanizmy statycznego i dynamicznego rozstrzygania konfliktów, pozwala on na 2 korzystanie z gramatyk niejednoznacznych;

GENERATOR LLGEN Schemat organizacji działania LLgen’a: scan. l gram. g LEX LLgen scan. c

GENERATOR LLGEN Schemat organizacji działania LLgen’a: scan. l gram. g LEX LLgen scan. c gram. c Lpars. h GCC scane. exe plik. txt WYNIK 3

GENERATOR LLGEN flex –l scan. l (użycie generatora LEX) lex. yy. c LLgen gram.

GENERATOR LLGEN flex –l scan. l (użycie generatora LEX) lex. yy. c LLgen gram. g (uzycie generatora LLgen dla pliku specyfikacji gram. g) Lpars. c i Lparse. h gcc lex. yy. c Lpars. c gram. c (kompilacja C++) . /a. out < plik. in (analiza pliku) 44

GENERATOR LLGEN Generator LLgen domyślnie korzysta z zewnętrznego analizatora leksykalnego, (wygenerowanego za pomocą LEX’a).

GENERATOR LLGEN Generator LLgen domyślnie korzysta z zewnętrznego analizatora leksykalnego, (wygenerowanego za pomocą LEX’a). W tym celu wywoływana jest funkcja yylex(); Plik Lpars. h, który powstaje podczas pracy generatora LLgen, zawiera definicje przypisujące stałe liczbowe nazwom zadeklarowanych token-ów; 5

GNENRATOR LLGEN Sposoby na wykorzystanie innego analizatora są następujące: Ø umieścić implementację skanera bezpośrednio

GNENRATOR LLGEN Sposoby na wykorzystanie innego analizatora są następujące: Ø umieścić implementację skanera bezpośrednio w specyfikacji gramatyki (w bloku ’{’ ’}’ lub w zewnętrznym pliku; Ø W specyfikacji wskazać nazwę funkcji, którą Llgen ma wywołać; %lexical nazwa_funkcji; Ø w razie potrzeby włączyć do analizatora leksykalnego plik Lpars. h; 6

GENERATOR LLGEN LLgen jest narzędziem wierszowym, do którego plik specyfikacji przygotowujemy w zwykłym pliku

GENERATOR LLGEN LLgen jest narzędziem wierszowym, do którego plik specyfikacji przygotowujemy w zwykłym pliku tekstowym, czasem w kilku plikach; Każdy wygenerowany kod źródłowy zawiera produkcje, dyrektywy generatora LLgen i deklaracje i kod w języku C 7

TWORZENIE SPECYFIKACJI Każdy produkcja ze specyfikacji dla programu LLgen składa się z: nieterminalu, znaku

TWORZENIE SPECYFIKACJI Każdy produkcja ze specyfikacji dla programu LLgen składa się z: nieterminalu, znaku „ : ” i prawej strony produkcji. Zakończona jest średnikiem; Alternatywne prawe strony produkcji rozdzielane są znakiem „|”; Prawa strona produkcji może składać się z terminali, nieterminali i akcji semantycznych; nieterminal : prawa strona produkcji ; 8

TWORZENIE SPECYFIKACJI Reguły tworzenia specyfikacji: Ø białe spacje są ignorowane, jednak nie mogą występować

TWORZENIE SPECYFIKACJI Reguły tworzenia specyfikacji: Ø białe spacje są ignorowane, jednak nie mogą występować w obrębie nazwy; Ø Komentarze wprowadzamy po znaku „/*” a zamykamy „*/”; Ø Komentarze nie mogą być zagnieżdżone; Ø Komentarze mogą wystąpić w każdym miejscu, gdzie dozwolone jest wystąpienie nazwy; 9

TWORZENIE SPECYFIKACJI Reguły tworzenia specyfikacji c. d. : Ø Nazwy symboli terminalnych i nieterminalnych

TWORZENIE SPECYFIKACJI Reguły tworzenia specyfikacji c. d. : Ø Nazwy symboli terminalnych i nieterminalnych mogą być dowolnej długości. Maja one składnię taką, jak identyfikatory języka C; Ø Nazwy symboli nie mogą kolidować ze słowami kluczowymi języka C; Ø Wielkość liter w nazwie jest rozróżnialna; 10

TWORZENIE SPECYFIKACJI Reguły tworzenia specyfikacji c. d. : Ø Nazwy symboli mogą być dowolnej

TWORZENIE SPECYFIKACJI Reguły tworzenia specyfikacji c. d. : Ø Nazwy symboli mogą być dowolnej długości, jednak w LLgen znaczących jest 50 pierwszych znaków; Ø Wszystkie nazwy generowane i wykorzystywane przez LLgen rozpoczynają się prefiksem LL; 11

DEKLARACJA TERMINALI Terminale, które nie są literałami deklarujemy: %token ken; Jeśli mamy kilka terminali

DEKLARACJA TERMINALI Terminale, które nie są literałami deklarujemy: %token ken; Jeśli mamy kilka terminali do deklaracji możemy to zrobić tak: %token nazwa 1, nazwa 2, nazwa 3; Każde użycie terminala musi być poprzedzone jego deklaracją; 12

DEKLRACJE TERMINALI Ø Ø Ø Ø Terminale, które są literałami są ujmowane w apostrofy;

DEKLRACJE TERMINALI Ø Ø Ø Ø Terminale, które są literałami są ujmowane w apostrofy; LLgen rozpoznaje także (podobnie jak C) zestaw literałów specjalnych, tzn. : nowa linia ‘n’ tabulator ‘t’ powrót karetki ‘r’ apostrof ‘’’ wycofanie znaku ‘b’ odwrotny ukośnik ‘\’ liczba oktalna ‘xxx’ 13

DEKLRACJE TERMINALI ZAPAMIETAJ!!! Napotkana w pliku specyfikacji nazwa, która nie była zadeklarowana jako token,

DEKLRACJE TERMINALI ZAPAMIETAJ!!! Napotkana w pliku specyfikacji nazwa, która nie była zadeklarowana jako token, będzie traktowana przez LLgen jako symbol nieterminalny; 14

DEKLRACJE TERMINALI Nieterminal jest implementowany jako funkcja języka C; W LLgenie możemy korzystać ze

DEKLRACJE TERMINALI Nieterminal jest implementowany jako funkcja języka C; W LLgenie możemy korzystać ze zmiennych lokalnych funkcji. Generator pozwala je deklarować, w nawiasach klamrowych, jedynie po lewej stronie produkcji za symbolem nieterminalnym, np. : A {int zmienna; } : S ken T ; 15

DEKLRACJE TERMINALI Przez akcję semantyczną rozumiemy dowolną pojedynczą instrukcję (grupę instrukcji) napisaną w języku

DEKLRACJE TERMINALI Przez akcję semantyczną rozumiemy dowolną pojedynczą instrukcję (grupę instrukcji) napisaną w języku C, które są ujęte w nawiasy klamrowe; W LLgenie akcje semantyczne możemy wstawić jedynie po prawej stronie produkcji, np. : A {int zmienna} : S ken {licznik=1; } T ; 16

NIETERMINAL STARTOWY Analizatory generowane przez LLgen mogą posiadać wiele nieterminali startowych; Deklaracja nieterminalu startowego

NIETERMINAL STARTOWY Analizatory generowane przez LLgen mogą posiadać wiele nieterminali startowych; Deklaracja nieterminalu startowego inaczej aksjomatu wygląda następująco: %start funkcja , nazwa_nieterminala; np. : %start parse, S; 17

KOMPILACJA Polecenie, które służy do uruchomienia generatora to LLgen. Polecenie to jest wywoływane dla

KOMPILACJA Polecenie, które służy do uruchomienia generatora to LLgen. Polecenie to jest wywoływane dla pilku specyfikacji (rozszerzenie g), np. : LLgen gram. g Generator Llgen na wyjściu produkuje trzy pliki: Ø gram. c – plik w C zwierający implementację parsera; Ø Lpars. h – plik zawierający interfejs analizatora leksykalnego; Ø Lpars. c – szkielet parsera i tablica sterująca; 18

OPCJA -V Czasem warto jest przy uruchamianiu i testowaniu parsera korzystać z opcji –v;

OPCJA -V Czasem warto jest przy uruchamianiu i testowaniu parsera korzystać z opcji –v; Dzięki opcji –v wygenerowany zostanie plik LL. output, który będzie zwierał informacje o nierozwiązanych konfliktach, które pojawiły się w gramatyce; 19

ROZSZERZENIE SKŁADNI GRAMATRYK Rozszerzenia standardowej składni gramatyk bezkontekstowych: Ø * (*liczba) – domknięcie zwrotne

ROZSZERZENIE SKŁADNI GRAMATRYK Rozszerzenia standardowej składni gramatyk bezkontekstowych: Ø * (*liczba) – domknięcie zwrotne Ø + (+liczba) – domknięcie dodatnie ; Ø ? – operator opcjonalności; Ø [. . . ] – możliwość grupowania symboli; 20

Przykład Niech ={a, b}. Rozważmy język regularny L=L(b*a). Wówczas: S: BA ; B: |

Przykład Niech ={a, b}. Rozważmy język regularny L=L(b*a). Wówczas: S: BA ; B: | ‘b’ B ; A : ‘a’ ; S: BA ; B : ‘b’ * ; A : ‘a’ ; 21

Przykład Niech ={a, b}. Rozważmy język L={b, aab, aaab}. Wówczas: S: AB ; A:

Przykład Niech ={a, b}. Rozważmy język L={b, aab, aaab}. Wówczas: S: AB ; A: | ‘a’ C ; C: | ‘a’ ; B : ‘b’ ; S: AB ; A : ‘a’ *3 ; B : ‘b’ ; 22

Przykład Niech ={a, b}. Rozważmy język L={ab, aaab}. Wówczas: S: AB ; A :

Przykład Niech ={a, b}. Rozważmy język L={ab, aaab}. Wówczas: S: AB ; A : ‘a’ C ; C: | ‘a’ ; B : ‘b’ ; S: AB ; A : ‘a’ +3 ; B : ‘b’ ; 23

Przykład Niech ={a, b}. Rozważmy język L={b, ab}. Wówczas: S: AB ; A: |

Przykład Niech ={a, b}. Rozważmy język L={b, ab}. Wówczas: S: AB ; A: | ‘a’ ; B : ‘b’ ; S: AB ; A : ‘a’ ? ; B : ‘b’ ; 24

Przykład Niech ={a, b}. Rozważmy język L={A * : |A|=2}. Wówczas: S : ‘a’

Przykład Niech ={a, b}. Rozważmy język L={A * : |A|=2}. Wówczas: S : ‘a’ B | ‘b’ B ; B : ‘a’ | ‘b’ ; S : [ ‘a’ | ‘b’ ] +2 ; 25

PORÓWNANIE Rozważmy gramatykę, która nie jest gramatyką LL(1). Porównajmy pracochłonność procedury dostosowania gramatyki a

PORÓWNANIE Rozważmy gramatykę, która nie jest gramatyką LL(1). Porównajmy pracochłonność procedury dostosowania gramatyki a bezpośrednią implemantacją gramatyki w generatorze LLgen’; Niech =[a, b}. Napiszmy program akceptujący język bezkontekstowy L={A * : A=an bn ; n }; 26

PORÓWNANIE { int ilosc_a, ilosc_b; } %start parse , S; S: AB { if

PORÓWNANIE { int ilosc_a, ilosc_b; } %start parse , S; S: AB { if (ilosc_a= = ilosc_b) puts(’’OK. ’’); else puts(’’Blad’’); } ; 27

PORÓWNANIE Usuwamy lewostronną rekurencję; A : ’a’ { ilosc_a=1; } | A ’a’ {

PORÓWNANIE Usuwamy lewostronną rekurencję; A : ’a’ { ilosc_a=1; } | A ’a’ { ilosc_a++; } ; B : ‘b’ { ilosc_b=1; } | B ‘b’ { ilosc_b++; } ; A : ’a’ { ilosc_a=1; } | ’a’ A { ilosc_a++; } ; B : ‘b’ { ilosc_b=1; } | ‘b’ B { ilosc_b++; } ; 28

PORÓWNANIE A : ’a’ C ; C: | ’a’ C ; B : ’b’

PORÓWNANIE A : ’a’ C ; C: | ’a’ C ; B : ’b’ D ; D: | ’b’ D ; { ilosc_a++; } { ilosc_a=0; } { ilosc_a++; } { ilosc_b=0; } { ilosc_b++; } 29

PORÓWNANIE S : {ilosc_a=ilosc_b=0} A B { if (ilosc_a= = ilosc_b) puts(’’OK. ’’); else

PORÓWNANIE S : {ilosc_a=ilosc_b=0} A B { if (ilosc_a= = ilosc_b) puts(’’OK. ’’); else puts(’’Blad’’); } ; A : [ ’a’ {ilosc_a++} ] + ; B : [ ’b’ {ilosc_b++} ] + ; 30

LLSYMB LLsymb jest globalną zmienną całkowitą, która może przyjmować różne wartości. To jaka wartość

LLSYMB LLsymb jest globalną zmienną całkowitą, która może przyjmować różne wartości. To jaka wartość będzie przyjęta, zależy od położenia głowicy czytającej po prawej stronie produkcji: Możliwe wartości: Ø Jeśli przeczytany został token, to LLsymb przechowuje token; Ø Po grupowaniu i alternatywie w zmiennej znajduje się podglądany token; 31

TWORZENIE SPECYFIKACJI W pliku ze specyfikacją do generatora LLgen obowiązkowo powinna znaleźć się implementacja

TWORZENIE SPECYFIKACJI W pliku ze specyfikacją do generatora LLgen obowiązkowo powinna znaleźć się implementacja funkcji main; %start parse, S ; int main(){ parse(); return 0; } 32

TWORZENIE SPECYFIKACJI W pliku ze specyfikacją do generatora LLgen powinna także znaleźć się implementacja

TWORZENIE SPECYFIKACJI W pliku ze specyfikacją do generatora LLgen powinna także znaleźć się implementacja funkcji LLmessage; Funkcja ta jest automatycznie wywoływana przez parser, gdy wystąpi bład składniowy; void LLmessage ( int tk ); Nie zwraca żadnej wartości Ma jeden parametr typu całkowitego 33

TWORZENIE SPECYFIKACJI Zmienna tk przyjmuje następujące wartości: Ø gdy oczekiwany był token „tk” –

TWORZENIE SPECYFIKACJI Zmienna tk przyjmuje następujące wartości: Ø gdy oczekiwany był token „tk” – tk > 0; Ø gdy wczytany został nieoczekiwany token i został on usunięty – tk = 0; Ø gdy nie został napotkany oczekiwany koniec pliku i pozostałe wejście będzie pominięte – tk = - 1; 34

Przykład Działanie generatora LLgen najlepiej zobaczyć na przykładzie. Na wejściu znajduje się ciąg słów

Przykład Działanie generatora LLgen najlepiej zobaczyć na przykładzie. Na wejściu znajduje się ciąg słów złożonych z alfabetu naturalnego, słowa kończą się znakiem dwukropka i są rozdzielane przecinkiem. Dany na wejście ciąg zawiera co najmniej jedno słowo. . 35

KONFLIKTY W trakcie pracy generatora składniowego może dojść do konfliktu polegającego na: Ø nie

KONFLIKTY W trakcie pracy generatora składniowego może dojść do konfliktu polegającego na: Ø nie jesteśmy w stanie określić, którą z prawych stron należy rozwijać – konflikt alternatyw; Ø Konstrukcja która jest aktualnie przetwarzana zawiera domkniecie i trudno określić, czy wejście jest jej dalszym ciągiem, czy też rozpoczyna inną konstrukcję – konflikt powtórzeń; 36

KONFLIKTY Konflikt alternatyw można rozstrzygnąć na dwa sposoby: ü dynamiczne rozstrzyganie konfliktu alternatywy: %if

KONFLIKTY Konflikt alternatyw można rozstrzygnąć na dwa sposoby: ü dynamiczne rozstrzyganie konfliktu alternatywy: %if (warunek) ü statyczne rozstrzyganie konfliktu alternatyw: %prefer %if(1) %aviod %if(0) 37

Przykład Rozważmy zadanie badania parzystości liczby binarnej; Analizator leksykalny rozpoznaje i zwraca liczby binarne;

Przykład Rozważmy zadanie badania parzystości liczby binarnej; Analizator leksykalny rozpoznaje i zwraca liczby binarne; %% [01] { return yytext[0]; } 38

Przykład { int wczytcyfra; } %start parse, S; S : ’ 0’ { wczytcyfra

Przykład { int wczytcyfra; } %start parse, S; S : ’ 0’ { wczytcyfra = 0; } R | ’ 1’ { wczytcyfra = 1; } R ; R : %if (wczytcyfra ==0 ) {puts(”parzysta”); } | {puts(”nieparzysta”); } |S ; 39

ROZWIĄZYWANIE KONFLIKTÓW Przykład użycia mechanizmu statycznego rozwiązywania konfliktów alternatyw jest problemem tzw. „wiszącego else”;

ROZWIĄZYWANIE KONFLIKTÓW Przykład użycia mechanizmu statycznego rozwiązywania konfliktów alternatyw jest problemem tzw. „wiszącego else”; Problem ten omówimy szczegółowo na wykładzie poświęconym generatorowi YACC; 40

ROZWIĄZYWANIE KONFLIKTÓW Konflikt powtórzeń jest rozstrzygany przy pomocy słowa kluczowego %while; %while ( warunek

ROZWIĄZYWANIE KONFLIKTÓW Konflikt powtórzeń jest rozstrzygany przy pomocy słowa kluczowego %while; %while ( warunek ) W ewaluacji warunku bardzo przydatne może być makro języka C, które jest generowane przez Llgen na podstawie słowa kluczowego %first; %first fmac, nonterm ; 41

KONIEC WYKŁADU SZÓSTEGO

KONIEC WYKŁADU SZÓSTEGO