Metody Kompilacji Wykład 7 Analiza Syntaktyczna

Podobne dokumenty
Metody Kompilacji Wykład 8 Analiza Syntaktyczna cd. Włodzimierz Bielecki WI ZUT

Metody Kompilacji Wykład 13

Metody Kompilacji Wykład 3

0.1 Lewostronna rekurencja

Matematyczne Podstawy Informatyki

Wprowadzenie do analizy składniowej. Bartosz Bogacki.

Wykład 5. Jan Pustelnik

Analizator syntaktyczny

Analiza metodą zstępującą. Bartosz Bogacki.

JIP. Analiza składni, gramatyki

Analiza leksykalna 1. Teoria kompilacji. Dr inż. Janusz Majewski Katedra Informatyki

Języki formalne i automaty Ćwiczenia 4

Efektywna analiza składniowa GBK

Uproszczony schemat działania kompilatora

Języki formalne i automaty Ćwiczenia 2

Podstawy programowania 2. Temat: Drzewa binarne. Przygotował: mgr inż. Tomasz Michno

Włączenie analizy leksykalnej do analizy składniowej jest nietrudne; po co więc jest wydzielona?

JAO - Wprowadzenie do Gramatyk bezkontekstowych

Zadanie analizy leksykalnej

10. Translacja sterowana składnią i YACC

Uproszczony schemat działania kompilatora

Gramatyka operatorowa

Metody Kompilacji Wykład 1 Wstęp

2.2. Gramatyki, wyprowadzenia, hierarchia Chomsky'ego

Generatory analizatorów

3.4. Przekształcenia gramatyk bezkontekstowych

Automat ze stosem. Języki formalne i automaty. Dr inż. Janusz Majewski Katedra Informatyki

Gramatyki rekursywne

Języki formalne i automaty Ćwiczenia 1

Języki formalne i automaty Ćwiczenia 3

Języki formalne i automaty Ćwiczenia 9

Teoretyczne podstawy informatyki. Wykład 12: Gramatyki. E. Richter-Was 1

Gramatyki, wyprowadzenia, hierarchia Chomsky ego. Gramatyka

Gramatyki atrybutywne

Podstawy generatora YACC. Bartosz Bogacki.

PARADYGMATY I JĘZYKI PROGRAMOWANIA. Analiza leksykalna i syntaktyczna. w- 5

Lingwistyka Matematyczna Języki formalne i gramatyki Analiza zdań

Analiza leksykalna 1. Języki formalne i automaty. Dr inż. Janusz Majewski Katedra Informatyki

Algorytmy i struktury danych. Drzewa: BST, kopce. Letnie Warsztaty Matematyczno-Informatyczne

GRAMATYKI BEZKONTEKSTOWE

Języki formalne i automaty Ćwiczenia 8

JAO - lematy o pompowaniu dla jezykow bezkontekstowy

Wykład 10. Translacja sterowana składnią

Opis wzorców polegający na na wykorzystaniu modelu definicji rekurencyjnych, nazywamy gramatyką bezkontekstową (ang. contex-free grammar).

Program We Kompilator Wy Źródłowy

Wybrane narzędzia do tworzenia analizatorów leksykalnych i składniowych w C/C++ by Kapitol Team

11 Probabilistic Context Free Grammars

Metody Realizacji Języków Programowania

Analiza semantyczna. Gramatyka atrybutywna

Hierarchia Chomsky ego Maszyna Turinga

Wstęp do programowania. Drzewa podstawowe techniki. Piotr Chrząstowski-Wachtel

Wstęp do programowania. Drzewa. Piotr Chrząstowski-Wachtel

Przegląd metod error recovery (dla parsingu top-down, przykłady)

Algorytmy i struktury danych. wykład 5

Metody kompilacji Wykłady 4-5

Algorytmy i struktury danych. wykład 2

Programowanie w języku Python. Grażyna Koba

Języki, automaty i obliczenia

Porządek symetryczny: right(x)

Wykład 2. Drzewa poszukiwań binarnych (BST)

Matematyczne Podstawy Informatyki

Tworzenie aplikacji w języku Java

prowadzący dr ADRIAN HORZYK /~horzyk tel.: Konsultacje paw. D-13/325

SYSTEMY UCZĄCE SIĘ WYKŁAD 3. DRZEWA DECYZYJNE. Dr hab. inż. Grzegorz Dudek Wydział Elektryczny Politechnika Częstochowska.

Generator YACC: gramatyki niejednoznaczne

Elżbieta Kula - wprowadzenie do Turbo Pascala i algorytmiki

Poprawność semantyczna

12. Rekurencja. UWAGA Trzeba bardzo dokładnie ustalić <warunek>, żeby mieć pewność, że ciąg wywołań się zakończy.

Wstęp do Programowania Obiektowego. Wykład 13 Paradygmaty. Składnia i semantyka.

Język programowania PASCAL

PoniŜej znajdują się pytania z egzaminów zawodowych teoretycznych. Jest to materiał poglądowy.

Informatyka 1. Wyrażenia i instrukcje, złożoność obliczeniowa

Sortowanie topologiczne skierowanych grafów acyklicznych

Ćwiczenia nr 11. Translatory. Wprowadzenie teoretyczne

Algorytmy i Struktury Danych

Programowanie w Logice Gramatyki metamorficzne. Przemysław Kobylański na podstawie [CM2003] i [SS1994]

Drzewa podstawowe poj

1. Nagłówek funkcji: int funkcja(void); wskazuje na to, że ta funkcja. 2. Schemat blokowy przedstawia algorytm obliczania

Algorytm - pojęcie algorytmu, sposób zapisu, poziom szczegółowości, czynności proste i strukturalne. Pojęcie procedury i funkcji.

Lista 5 Gramatyki bezkontekstowe i automaty ze stosem

Kolejka priorytetowa. Często rozważa się kolejki priorytetowe, w których poszukuje się elementu minimalnego zamiast maksymalnego.

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Sortowanie. Kolejki priorytetowe i algorytm Heapsort Dynamiczny problem sortowania:

ALGORYTMY I STRUKTURY DANYCH

Bison - generator analizatorów składniowych

Hierarchia Chomsky ego

Algorytmy z powrotami. Algorytm minimax

Aproksymacja funkcji a regresja symboliczna

Języki programowania zasady ich tworzenia

Drzewa binarne. Drzewo binarne to dowolny obiekt powstały zgodnie z regułami: jest drzewem binarnym Jeśli T 0. jest drzewem binarnym Np.

Obiektowa implementacja parsera klasy LL(1)

Nierówność Krafta-McMillana, Kodowanie Huffmana

Generator LLgen. Wojciech Complak Generator LLgen - charakterystyka. Generator LLgen -składnia specyfikacji

Wykład 6. Drzewa poszukiwań binarnych (BST)

Przeszukiwanie z nawrotami. Wykład 8. Przeszukiwanie z nawrotami. J. Cichoń, P. Kobylański Wstęp do Informatyki i Programowania 238 / 279

procesów Współbieżność i synchronizacja procesów Wykład prowadzą: Jerzy Brzeziński Dariusz Wawrzyniak

INSTRUKCJA PUSTA. Nie składa się z żadnych znaków i symboli, niczego nie robi. for i := 1 to 10 do {tu nic nie ma};

Złożoność obliczeniowa zadania, zestaw 2

JĘZYKI FORMALNE I METODY KOMPILACJI

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Transkrypt:

Metody Kompilacji Wykład 7 Analiza Syntaktyczna

Parsowanie Parsowanie jest to proces określenia jak ciąg terminali może być generowany przez gramatykę. Włodzimierz Bielecki WI ZUT 2/57

Parsowanie Dla każdej gramatyki bezkontekstowej istnieje parser, dla którego czas parsowania ciągu z n terminali zajmuje co najwyżej O(n^3) czasu. Ale czas ten jest zazwyczaj nie do przyjęcia w praktyce. Na szczęście, dla rzeczywistych języków programowania, możemy zaprojektować gramatykę, która może szybko parsować. Włodzimierz Bielecki WI ZUT 3

Parsowanie Dla większości języków programowania zostały opracowane algorytmy parsowania o złożoności liniowej. Włodzimierz Bielecki WI ZUT 4

Parsowanie Analizatory składni języka programowania prawie zawsze przeglądają ciąg wejściowy od lewej do prawej strony, biorąc pod uwagę tylko jeden terminal w danym momencie. Włodzimierz Bielecki WI ZUT 5

Parsowanie Większość metod parsowania należy do jednej z dwóch klas: metody zstępujące (top-down) i metody wstępujące (bottom-up). Terminy te odnoszą się do kolejności, w jakiej są budowane węzły w drzewie parsowania. Włodzimierz Bielecki WI ZUT 6

Parsowanie W parserach zstępujących ( top-down), tworzenie drzewa rozpoczyna się od korzenia i polega na przechodzeniu do liści, natomiast w parserach wstępujących(bottom-up) budowa rozpoczyna się od liści i przebiega w kierunku korzenia. Włodzimierz Bielecki WI ZUT 7

Parsowanie Popularność parserów zstępujących jest spowodowana tym, że łatwo mogą być zbudowane wydajne parsery przez mały nakład pracy programisty. Włodzimierz Bielecki WI ZUT 8

Parsowanie Parser wstępujący może obsłużyć jednak więcej bardziej złożonych gramatyk i schematów translacji, czyli jego zakres stosowalności jest szerszy. Włodzimierz Bielecki WI ZUT 9

Parsowanie zstępujące W parsowaniu zstępującym budowa drzewa syntaktycznego dokonuje się począwszy od korzenia, oznakowanego przez nieterminal startowy, i następnie wielokrotnie są wykonywane następujące dwa kroki. Włodzimierz Bielecki WI ZUT 10

Parsowanie zstępujące 1. W węźle N, oznaczonym nieterminalem A, wybierz jedną z produkcji, której lewa strona jest A, i utwórz dzieci dla N oznaczone symbolami prawej strony tej produkcji. 2. Znajdź następny węzeł, w którym poddrzewo ma być utworzone, zazwyczaj jest to skrajny lewy nieterminal drzewa bieżącego. Włodzimierz Bielecki WI ZUT 11

Parsowanie zstępujące Aktualny symbol terminalny z ciągu wejściowego jest często nazywany symbolem bieżącym -- lookahead. Początkowo symbolem bieżącym jest pierwszy terminal z lewej strony ciągu wejściowego. Włodzimierz Bielecki WI ZUT 12

Parsowanie zstępujące Parser próbuje utworzyć drzewo parsujące od korzenia w kierunku liści skanując wejście od lewej do prawej strony. Przykład: dla wejścia id+id*id jest tworzone drzewo parsowania: lm oznacza wyprowadzenie lewostronne, czyli zawsze jest wybierany skrajny lewy nieterminal E -> TE E -> +TE Ɛ T -> FT T -> *FT Ɛ F -> (E) id E E E lm lm lm E lm E T E T E T E T E F T F T F T id id Ɛ E lm T E F T + T E id Ɛ Włodzimierz Bielecki WI ZUT 13

Parsowanie zstępujące: tworzenie kodu parsera 1. Tworzymy jedną procedurę dla wszystkich symboli terminalnych 2. Tworzymy jedną procedurę dla każdego symbolu pomocniczego 3. Tworzymy kod dla każdej produkcji jako ciąg procedur zgodnie z kolejnością symboli w prawej stronie odpowiedniej produkcji. Włodzimierz Bielecki WI ZUT 14

Parsowanie zstępujące: przykład stmt expr ; if ( expr ) stmt for ( optexpr ; optexpr ; optexpr ) stmt other optexpr expr stmt Drzewo parsowania dla produkcji stmt->for ( optexpr; optexpr ; optexpr ) stmt dla kodu o przykładowej strukturze: for ( ; i<n ; i+=2*k) p=i; for ( optexpr ; optexpr ; optexpr ) stmt ε expr expr other Włodzimierz Bielecki WI ZUT 15

Pseudokod parsera, który sprawdza czy ciąg wejściowy zawiera błędy syntaktyczne stmt expr ; if ( expr ) stmt for ( optexpr ; optexpr ; optexpr ) stmt other Zastosowanie ε-produkcji: optexpr expr void stmt() { switch ( lookahead ) { case expr: match(expr); match( ; ); break; case if: match(if); match( ( ); match(expr); match( ) ); stmt(); break; case for: match(for); match( ( ); optexpr(); match( ; ); optexpr(); match( ; ); optexpr(); match( ) ); stmt(); break; case other: match(other); break; default: report( syntax error ); } } void optexpr() { if ( lookahead == expr ) match(expr); } Sprawdzenie pasowania terminala t do symbolu wejścia Włodzimierz Bielecki WI ZUT void match(terminal t) { if ( lookahead == t ) lookahead = nextterminal; else } report( syntax error ); 16

Pseudokod: stmt expr ; if ( expr ) stmt for ( optexpr ; optexpr ; optexpr ) stmt other Zastosowanie ε-produkcji: optexpr expr void stmt() { switch ( lookahead ) { case expr: match(expr); match( ; ); break; case if: match(if); match( ( ); match(expr); match( ) ); stmt(); break; case for: match(for); match( ( ); optexpr(); match( ; ); optexpr(); match( ; ); optexpr(); match( ) ); stmt(); break; case other: match(other); break; default: report( syntax error ); } } void optexpr() { if ( lookahead == expr ) match(expr); } Jeśli wartość lookahead równa się expr, to wywołaj funkcje void match(terminal t) { if ( lookahead == t ) lookahead = nextterminal; else match(expr) Włodzimierz Bielecki report( syntax WI ZUT error ); 17 }

Pseudokod: stmt expr ; if ( expr ) stmt for ( optexpr ; optexpr ; optexpr ) stmt other Zastosowanie ε-produkcji: optexpr expr void stmt() { switch ( lookahead ) { case expr: match(expr); match( ; ); break; case if: match(if); match( ( ); match(expr); match( ) ); stmt(); break; case for: match(for); match( ( ); optexpr(); match( ; ); optexpr(); match( ; ); optexpr(); match( ) ); stmt(); break; case other: match(other); break; default: report( syntax error ); } } void optexpr() { if ( lookahead == expr ) match(expr); } Jeśli terminal t jest taki sam jak wartość lookahead, to wczytaj następny znak, inaczej jest błąd składni void match(terminal t) { if ( lookahead == t ) lookahead = nextterminal; else } report( syntax error ); 18

Pseudokod: Kolejność wywołania funkcji jest taka sama jak i kolejność symboli w prawej stronie odpowiedniej produkcji stmt expr ; if ( expr ) stmt for ( optexpr ; optexpr ; optexpr ) stmt other Zastosowanie ε-produkcji: optexpr expr void stmt() { switch ( lookahead ) { case expr: match(expr); match( ; ); break; case if: match(if); match( ( ); match(expr); match( ) ); stmt(); break; case for: match(for); match( ( ); optexpr(); match( ; ); optexpr(); match( ; ); optexpr(); match( ) ); stmt(); break; case other: match(other); break; default: report( syntax error ); } } void optexpr() { if ( lookahead == expr ) match(expr); } void match(terminal t) { if ( lookahead == t ) lookahead = nextterminal; else } report( syntax error ); 19

stmt expr ; if ( expr ) stmt for ( optexpr ; optexpr ; optexpr ) stmt other optexpr expr expr ; if ( expr ) stmt for ( optexpr ; optexpr ; optexpr ) stmt other Zastosowanie ε-produkcji: void stmt() { switch ( lookahead ) { case expr: match(expr); match( ; ); break; case if: match(if); match( ( ); match(expr); match( ) ); stmt(); break; case for: match(for); match( ( ); optexpr(); match( ; ); optexpr(); match( ; ); optexpr(); match( ) ); stmt(); break; case other: match(other); break; default: report( syntax error ); } } void optexpr() { if ( lookahead == expr ) match(expr); } void match(terminal t) { if ( lookahead == t ) lookahead = nextterminal; else } report( syntax error ); 20

Parsowanie zstępujące: przykład Drzewo parsowania stmt for ( optexpr ; optexpr ; optexpr ) stmt match(for) match( ( ) optexpr() match( ; ) optexpr() match( ; ) optexpr() match( ) ) stmt() Wejście for ( ; expr ; expr ) other lookahead Włodzimierz Bielecki WI ZUT 21

Parsowanie zstępujące: przykład Krok 1: stmt for ( optexpr ; optexpr ; optexpr ) stmt match(for) match( ( ) optexpr() match( ; ) optexpr() match( ; ) optexpr() match( ) ) stmt() Wejście for ( ; expr ; expr ) other lookahead Włodzimierz Bielecki WI ZUT 22

Parsowanie zstępujące: przykład Krok 2: stmt for ( optexpr ; optexpr ; optexpr ) stmt match(for) match( ( ) optexpr() match( ; ) optexpr() match( ; ) optexpr() match( ) ) stmt() Wejście for ( ; expr ; expr ) other lookahead Włodzimierz Bielecki WI ZUT 23

Parsowanie zstępujące: przykład Krok 3: stmt Problem: brak dopasowania. Wybieramy produkcję: optexpr for ( optexpr ; optexpr ; optexpr ) stmt match(for) match( ( ) optexpr() match( ; ) optexpr() match( ; ) optexpr() match( ) ) stmt() Wejście for ( ; expr ; expr ) other lookahead Włodzimierz Bielecki WI ZUT 24

Parsowanie zstępujące: przykład Krok 4: stmt for ( optexpr ; optexpr ; optexpr ) stmt match(for) match( ( ) optexpr() match( ; ) optexpr() match( ; ) optexpr() match( ) ) stmt() Wejście for ( ; expr ; expr ) other lookahead Włodzimierz Bielecki WI ZUT 25

Parsowanie zstępujące: przykład Krok 5: stmt void optexpr() { if ( lookahead == expr ) match(expr); } for ( optexpr ; optexpr ; optexpr ) stmt match(for) match( ( ) optexpr() match( ; ) optexpr() match( ; ) optexpr() match( ) ) stmt() Wejście for ( ; expr ; expr ) other lookahead Włodzimierz Bielecki WI ZUT 26

Parsowanie zstępujące: przykład Krok 6: stmt for ( optexpr ; optexpr ; optexpr ) stmt match(for) match( ( ) optexpr() match( ; ) optexpr() match( ; ) optexpr() match( ) ) stmt() Wejście for ( ; expr ; expr ) other lookahead Włodzimierz Bielecki WI ZUT 27

Parsowanie zstępujące: przykład Krok 7: stmt for ( optexpr ; optexpr ; optexpr ) stmt match(for) match( ( ) optexpr() match( ; ) optexpr() match( ; ) optexpr() match( ) ) stmt() Wejście for ( ; expr ; expr ) other lookahead Włodzimierz Bielecki WI ZUT 28

Parsowanie zstępujące: przykład Krok 7: stmt for ( optexpr ; optexpr ; optexpr ) stmt match(for) match( ( ) optexpr() match( ; ) optexpr() match( ; ) optexpr() match( ) ) stmt() Wejście for ( ; expr ; expr ) other Włodzimierz Bielecki WI ZUT lookahead 29

Parsowanie zstępujące: przykład Krok 8: for ( stmt Wywołanie stmt() dla lookahead other kończy się zakończeniem programu bez sygnalizacji błędu syntaktycznego, czyli wejście jest poprawne optexpr ; optexpr ; optexpr ) stmt match(for) match( ( ) optexpr() match( ; ) optexpr() match( ; ) optexpr() match( ) ) stmt() Wejście for ( ; expr ; expr ) other Włodzimierz Bielecki WI ZUT lookahead 30

Parsowanie zstępujące Kroki parsowania: ε-produkcje ( produkcje, których prawa strona jest napisem pustym ε ) wymagają specjalnego traktowania. Używamy je jako domyślnych, gdy żadna inna produkcja nie może być użyta. Włodzimierz Bielecki WI ZUT 31

Parsowanie zstępujące Kroki parsowania: Z nieterminalem optexpr i symbolem bieżącym ; ε-produkcja jest wykorzystywana, ponieważ nie ma takiej produkcji, której lewa strona jest optexpr, a prawą stroną jest symbol ;. Włodzimierz Bielecki WI ZUT 32

Parsowanie zstępujące Kroki parsowania: Ogólnie rzecz biorąc, wybór produkcji dla nieterminala może być oparty na metodzie prób i błędów; to znaczy, możemy spróbować jakiejś produkcji, jeśli jest ona niewłaściwa, to możemy wrócić i spróbować innej produkcji i t.d. Włodzimierz Bielecki WI ZUT 33

Parsowanie zstępujące: przykład type simple ^ id array [ simple ] of type simple integer char num dotdot num Ile procedur należy utworzyć? Włodzimierz Bielecki WI ZUT 34

Parsowanie zstępujące:program procedure match(t : token); begin if lookahead = t then lookahead := nexttoken() else error() end; procedure type(); begin if lookahead in { integer, char, num } then simple() else if lookahead = ^ then match( ^ ); match(id) else if lookahead = array then match( array ); match( [ ); simple(); match( ] ); match( of ); type() else error() end; Włodzimierz Bielecki WI ZUT procedure simple(); begin if lookahead = integer then match( integer ) else if lookahead = char then match( char ) else if lookahead = num then match( num ); match( dotdot ); match( num ) else error() end; 35

Parsowanie zstępujące:program procedure match(t : token); begin if lookahead = t then lookahead := nexttoken() else error() end; simple integer char num dotdot num procedure type(); begin if lookahead in { integer, char, num } then simple() else if lookahead = ^ then match( ^ ); match(id) else if lookahead = array then match( array ); match( [ ); simple(); match( ] ); match( of ); type() else error() end; Włodzimierz Bielecki WI ZUT procedure simple(); begin if lookahead = integer then match( integer ) else if lookahead = char then match( char ) else if lookahead = num then match( num ); match( dotdot ); match( num ) else error() end; 36

Parsowanie zstępujące:program procedure match(t : token); begin if lookahead = t then lookahead := nexttoken() else error() end; type simple ^ id array [ simple ] of type procedure type(); begin if lookahead in { integer, char, num } then simple() else if lookahead = ^ then match( ^ ); match(id) else if lookahead = array then match( array ); match( [ ); simple(); match( ] ); match( of ); type() else error() end; Włodzimierz Bielecki WI ZUT procedure simple(); begin if lookahead = integer then match( integer ) else if lookahead = char then match( char ) else if lookahead = num then match( num ); match( dotdot ); match( num ) else error() end; 37

Parsowanie zstępujące: krok 1 match( array ) type() procedure type(); begin if lookahead in { integer, char, num } then simple() else if lookahead = ^ then match( ^ ); match(id) else if lookahead = array then match( array ); match( [ ); simple(); match( ] ); match( of ); type() else error() end; Input: array [ num dotdot num ] of integer lookahead Włodzimierz Bielecki WI ZUT 38

Parsowanie zstępujące: krok 2 type() match( array ) match( [ ) Input: array [ num dotdot num ] of integer lookahead Włodzimierz Bielecki WI ZUT 39

Parsowanie zstępujące: krok 3 match( array ) match( num ) match( [ ) type() simple() procedure simple(); begin if lookahead = integer then match( integer ) else if lookahead = char then match( char ) else if lookahead = num then match( num ); match( dotdot ); match( num ) else error() end; Input: array [ num dotdot num ] of integer lookahead Włodzimierz Bielecki WI ZUT 40

Parsowanie zstępujące: krok 4 type() match( array ) match( [ ) simple() match( num ) match( dotdot ) Input: array [ num dotdot num ] of integer lookahead Włodzimierz Bielecki WI ZUT 41

Parsowanie zstępujące: krok 5 type() match( array ) match( [ ) simple() match( num ) match( dotdot ) match( num ) Input: array [ num dotdot num ] of integer Włodzimierz Bielecki WI ZUT lookahead 42

Parsowanie zstępujące: krok 6 match( array ) match( [ ) type() simple() match( ] ) procedure type(); begin. else if lookahead = array then simple(); match( ] ); match( of ); type() else error() end; match( num ) match( dotdot ) match( num ) Input: array [ num dotdot num ] of integer Włodzimierz Bielecki WI ZUT lookahead 43

Parsowanie zstępujące: krok 7 type() match( array ) match( [ ) simple() match( ] ) match( of ) match( num ) match( dotdot ) match( num ) Input: array [ num dotdot num ] of integer Włodzimierz Bielecki WI ZUT lookahead 44

Parsowanie zstępujące: krok 8 type() match( array ) match( [ ) simple() match( ] ) match( of ) type() match( num ) match( dotdot ) match( num ) simple() Input: match( integer ) array [ num dotdot num ] of integer Włodzimierz Bielecki WI ZUT lookahead 45

Parsowanie zstępujące Rekurencja lewostronna Dla parsera zstępującego możliwe jest zapętlenie. Problem pojawia się, gdy korzystamy z produkcji lewostronnie rekurencyjnych, takich jak: expr -> expr + term, gdzie lewy skrajny symbol ciała produkcji jest taki sam jak symbol po lewej stronie produkcji. Włodzimierz Bielecki WI ZUT 46

Parsowanie zstępujące Rekurencja lewostronna Produkcja lewostronnie rekurencyjna może być wyeliminowana poprzez jej modyfikację. Rozważmy produkcje: A->Aα β gdzie α i β są to ciągi terminali i nieterminali, które nie zaczynają się od A. Włodzimierz Bielecki WI ZUT 47

Parsowanie zstępujące Rekurencja lewostronna Na przykład, dla produkcji expr -> expr + term term Nieterminal A = expr, ciąg α= +term, ciąg β = term. Włodzimierz Bielecki WI ZUT 48

Parsowanie zstępujące Rekurencja lewostronna Nieterminal A i jego produkcja są lewostronnie rekurencyjne. W ogólnym przypadku, gramatyka może być lewostronnie rekurencyjna, jeśli nieterminal A wyprowadza napis Aα przez zastosowanie dwóch lub więcej produkcji bezpośrednich. Włodzimierz Bielecki WI ZUT 49

Parsowanie zstępujące Rekurencja lewostronna Powtarzające się stosowanie tej produkcji tworzy sekwencję ciągu α po prawej stronie A. Włodzimierz Bielecki WI ZUT 50

Rekurencja lewostronna A A A Parser zawsze będzie wybierał pierwszą produkcję dla gramatyki: A->Aα β A A A->Aα-> Aαα->Aααα-> -> Aααα α-> β α ααα β α α α α Zapętlenie Włodzimierz Bielecki WI ZUT 51

Parsowanie zstępujące Rekurencja lewostronna Jeśli w końcu symbol A zostanie zastąpiony przez β, to uzyskamy β, po którym następuje sekwencja zero lub więcej α. Problem: A nigdy nie zostanie zastąpione przez β ponieważ zawsze będzie wybrana pierwsza produkcja: A->Aα. Włodzimierz Bielecki WI ZUT 52

Przykład Gramatyka: expr -> expr + term term term->0,1,9 Dla wejścia: 2+2, proces tworzenia drzewa parsowania jest nieskończony. expr expr + term expr + term Włodzimierz Bielecki WI ZUT 53

Parsowanie zstępujące Rekurencja lewostronna Problem można rozwiązać przez przepisanie produkcji dla A A->Aα β w następujący sposób przy użyciu nowego nieterminala R: A->βR R->αR ε Włodzimierz Bielecki WI ZUT 54

Parsowanie zstępujące Rekurencja prawostronna Nieterminal R i jego produkcja R->αR są prawostronnie rekurencyjne. Produkcje prawostronnie rekurencyjne prowadzą do drzew, które rosną w dół i w prawo jak jest pokazane na rysunku na następnym slajdzie Włodzimierz Bielecki WI ZUT 55

A->βR R->αR ε Rekurencja prawostronna A->βR->βαR-> βααr-> βαα αr-> βαα αε A R R R R β α α. α ε Włodzimierz Bielecki WI ZUT 56

Przykład Gramatyka: expr -> expr + term term term->0,1,9 Przekonwertowana do postaci expr -> term R R-> +term R ε term->0,1,9 term expr Dla wejścia: 2+2 drzewo parsowania wygląda jak wyżej. R 2 + term R 2 ε Liście drzewa tworzą zdanie wejściowe, więc parser kończy pracę Włodzimierz Bielecki WI ZUT 57

Dziękuję za uwagę Włodzimierz Bielecki WI ZUT 58