1 / 42

L L G E N

L L G E N. Generator analizatorów składniowych. GENERATOR L LGEN. Zadaniem generatora LLgen jest wygenerowanie analizatora składniowego, inaczej parsera (w języku C) metodą zejść rekurencyjnych, bez nawrotów;

jaxon
Download Presentation

L L G E N

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. L L G E N Generator analizatorów składniowych

  2. 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 korzystanie z gramatyk niejednoznacznych; 2

  3. GENERATOR LLGEN • Schemat organizacji działania LLgen’a: scan.l gram.g L E X LLgen scan.c gram.c Lpars.c Lpars.h G C C scane.exe plik.txt 3 WYNIK

  4. 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) 4 4

  5. 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

  6. 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 plikLpars.h; 6

  7. 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

  8. 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

  9. 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

  10. 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

  11. 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

  12. 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 nazwa1, nazwa2, nazwa3; • Każde użycie terminala musi być poprzedzone jego deklaracją; 12

  13. 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

  14. 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

  15. 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

  16. 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

  17. 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

  18. 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

  19. 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

  20. 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

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

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

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

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

  25. 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

  26. 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

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

  28. 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

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

  30. 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

  31. 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

  32. 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

  33. 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

  34. 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

  35. 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

  36. 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

  37. 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

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

  39. 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

  40. 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

  41. 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

  42. KONIEC KONIEC WYKŁADU SZÓSTEGO

More Related