Metoda pierwszeństwa operatorów

Slides:



Advertisements
Podobne prezentacje
Lingwistyka Matematyczna
Advertisements

Lingwistyka Matematyczna
Lingwistyka Matematyczna
Wprowadzenie w problematykę związaną z twierdzeniem Gödla
Sympleksy n=2.
C++ wykład 4 ( ) Przeciążanie operatorów.
CIĄGI.
Grażyna Mirkowska PJWSTK 15 listopad 2000
Wykład 10 Metody Analizy Programów Specyfikacja Struktur Danych
Wykład 6 Najkrótsza ścieżka w grafie z jednym źródłem
Ciągi de Bruijna generowanie, własności
Analiza Składniowa Wstępująca
Lingwistyka Matematyczna
Generator analizatorów składniowych
Materiały do zajęć z przedmiotu: Narzędzia i języki programowania Programowanie w języku PASCAL Część 8: Wykorzystanie procedur i funkcji © Jan Kaczmarek.
Języki formalne i gramatyki
Wykład 2: Upraszczanie, optymalizacja i implikacja
Materiały pomocnicze do wykładu
Made by Mateusz Szirch Kilka słów o JavaScript.
AWK Zastosowania Informatyki Wykład 1 Copyright, 2003 © Adam Czajka.
Zależności funkcyjne.
Podstawy programowania
Podstawy układów logicznych
ANALIZA LEKSYKALNA. Zadaniem analizatora leksykalnego jest przetwarzanie danych pochodzących ze strumienia wejściowego a także rozpoznawanie ciągów znaków.
ANALIZA METODĄ WSTĘPUJĄCĄ
Informatyka I Wykład 5 OPERATORY Priorytety i kolejność obliczeń
Elementy Rachunku Prawdopodobieństwa i Statystyki
Gramatyki Lindenmayera
Generator analizatorów składniowych
Elementy Rachunku Prawdopodobieństwa i Statystyki
STEROWANIE Ale nie tylko
XML – eXtensible Markup Language
Elementy Rachunku Prawdopodobieństwa i Statystyki
Model relacyjny.
Translatory Copyright, 2006 © Jerzy R. Nawrocki Wprowadzenie do informatyki Wykład 11.
Gramatyki i translatory
ZWIĄZKI MIĘDZY KLASAMI KLASY ABSTRAKCYJNE OGRANICZENIA INTERFEJSY SZABLONY safa Michał Telus.
Intuicjonizm etyczny George’a E. Moore’a
W ą t e k (lekki proces) thread.
Projektowanie stron WWW
Obliczalność czyli co da się policzyć i jak Model obliczeń maszyna licznikowa dr Kamila Barylska.
Wyszukiwanie maksimum funkcji za pomocą mrówki Pachycondyla Apicalis.
Metody matematyczne w Inżynierii Chemicznej
Zagadnienia AI wykład 2.
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski informatyka +
Języki formalne i gramatyki Copyright, 2005 © Jerzy R. Nawrocki Teoretyczne podstawy.
Instrukcje wyboru.
PHP Instrukcja warunkowa if Damian Urbańczyk. Warunek? Instrukcję warunkową wykorzystujemy wtedy, gdy chcemy sprawdzić pewien fakt, który może być prawdziwy.
Języki formalne Copyright, 2006 © Jerzy R. Nawrocki Wprowadzenie do informatyki Wykład.
Gromadzenie informacji
ANALIZA SKŁADNIOWA.
ANALIZA METODĄ WSTĘPUJĄCĄ. ANALIZA WSTĘPUJĄCA Dla danej gramatyki G oraz S=>* , to wówczas:  Jeśli  zawiera tylko terminale, to  nazywamy zdaniem;
Projektowanie obiektowe. Przykład: Punktem wyjścia w obiektowym tworzeniu systemu informacyjnego jest zawsze pewien model biznesowy. Przykład: Diagram.
Projektowanie bazy danych z użyciem diagramów UML Obiektowe projektowanie relacyjnej bazy danych Paweł Jarecki.
Y A C C Generator analizatorów składniowych. GENERATOR YACC Zadaniem generatora YACC jest wygenerowanie kodu źródłowego analizatora składniowego (domyślnie)
Systemy wspomagające dowodzenie twierdzeń
Wykład Rozwinięcie potencjału znanego rozkładu ładunków na szereg momentów multipolowych w układzie sferycznym Rozwinięcia tego można dokonać stosując.
Wstęp do programowania Wykład 9
Wstęp do programowania Wykład 2 Dane, instrukcje, program.
Pojęcia podstawowe c.d. Rachunek podziałów Elementy teorii grafów
 Formuła to wyrażenie algebraiczne (wzór) określające jakie operacje ma wykonać program na danych. Może ona zawierać liczby, łańcuchy znaków, funkcje,
”FALSE FRIENDS” (Źródła ilustracji:
Wyrażenia algebraiczne
Elementy cyfrowe i układy logiczne
HISTORIA CYFR RZYMSKICH
Systemy liczbowe.
Zrozumieć, przeanalizować i rozwiązać
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski informatyka +
ALGORYTMY I STRUKTURY DANYCH
Instrukcja warunkowa if
Zapis prezentacji:

Metoda pierwszeństwa operatorów Wykład 9 Metoda pierwszeństwa operatorów

Metoda pierwszeństwa operatorów Dla ważnej klasy gramatyk (gramatyka operatorowa) możemy łatwo ręcznie budować wydajne analizatory redukujące. Cecha charakterystyczną tej ważnej, lecz wąskiej grupy gramatyk jest to, że: prawa strona jakiejkolwiek produkcji nie jest Ʌ, nie zawiera dwóch sąsiadujących nieterminali

Gramatyka operatorowa E->EAE | (E) | -E | id, A-> + | - | * | / | ↑ nie jest gramatyką operatorową. E->E+E | E-E | E*E | E/E | E↑E | (E) | -E | id Jest gramatyką operatorową.

Technika pierwszeństwa operatorów Metoda pierwszeństwa operatorów została najpierw opisana jako manipulacje na symbolach, bez żadnych odwołań do ukrytej gramatyki. Gdy skończymy budować analizator dla gramatyki pisany metodą pierwszeństwa operatorów, możemy ignorować gramatykę, używając nieterminali na stosie tylko do zajmowania miejsca dla atrybutów związanych z nieterminalami.

Technika pierwszeństwa operatorów Wady metody pierwszeństwa operatorów: Niektóre symbole są trudne do obsłużenia. , np. znak minus (-), który ma dwa różne priorytety w zależności od tego czy ma jeden czy dwa argumenty; Związek pomiędzy analizowaną gramatyką a analizatorem napisanym metoda pierwszeństwa jest słaby; Metodą pierwszeństwa operatorów można analizować tylko małą klasę gramatyk.

Metoda pierwszeństwa operatorów W metodzie pierwszeństwa operatorów między pewnymi parami terminali definiujemy trzy rozłączne relacje priorytetów: <· , = , ·> Kierują one wyborem uchwytów i mają następujące znaczenie: a<·b - a ma mniejszy priorytet niż b; a=b – a ma taki sam priorytet jak b; a·>b – a ma większy priorytet niż b.

Metoda pierwszeństwa operatorów Uwaga. Podobieństwo do relacji arytmetycznych jest iluzoryczne. Relacje priorytetów mają całkiem inne własności. Przykład: dla tego samego języka może zachodzić a<·b i a·>b. dla pewnej pary terminali a i b może nie zachodzić ani a<·b ani a=b ani a·>b .

Metoda pierwszeństwa operatorów Istnieją dwie metody sprawdzania, jakie relacje priorytetów zachodzą miedzy parami terminali: Metoda intuicyjna – opiera się na tradycyjnych pojęciach łączności i priorytetów operatorów; Metoda wyboru relacji priorytetów.

E->E+E | E-E | E*E | E/E | E↑E | (E) | -E | id Metoda intuicyjna Metoda intuicyjna – opiera się na tradycyjnych pojęciach łączności i priorytetów operatorów. Przykład: Jeśli * ma wyższy priorytet niż +, to ustalamy +<·* oraz *·>+. Podejście takie usuwa niejednoznaczność z gramatyki E->E+E | E-E | E*E | E/E | E↑E | (E) | -E | id oraz pozwala nam napisać dla niej analizator metodą pierwszeństwa operatorów (pomimo iż jednoargumentowy minus stwarza problemy).

Metoda wyboru relacji priorytetów Metoda wyboru relacji priorytetów polega na zbudowaniu jednoznacznej gramatyki dla języka, takiej, że drzewa wyprowadzenia budowane przy jej użyciu będą oddawać właściwą łączność i priorytety operatorów. Przykładowo dla często spotykanego źródła niejednoznaczności „wiszącego else” modelem może być gramatyka:......

Metoda wyboru relacji priorytetów instr -> dopas_instr | niedopas_instr dopas_instr -> if wyr then dopas_instr else dopas_instr | inna niedopas_instr -> if wyr then instr | if wyr then dopas_instr else niedopas_instr

Metoda wyboru relacji priorytetów Gdy dysponujemy już jednoznaczną gramatyką, korzystamy z mechanicznego sposobu, aby używając jej, skonstruować relacje priorytetów. Relacje te mogą nie być rozłączne i mogą pozwalać na analizowanie innych języków niż generowane przez początkową gramatykę, ale przy standardowych wyrażeniach arytmetycznych w praktyce nie spotyka się wielu problemów.

Relacje priorytetów operatorów Zadaniem relacji priorytetów jest oddzielenie uchwytów prawostronnych form zdanio-wych, z <· oznaczającym lewy kraniec, = występującym w środku uchwytu i ·> na prawym krańcu.

Relacje priorytetów operatorów Przyjmijmy, że mamy prawostronną formę zdaniową gramatyki operatorowej. Możemy prawostronną formę zdaniową zapisać jako : β0 a1 β1 a2 β2 ... an βn gdzie każde z βi jest albo Ɛ (pustym ciągiem) albo nieterminalem, zaś ai jest pojedynczym terminalnym, i=1,...,n. Załóżmy, że między ai i ai+1 zachodzi dokladnie jedna z relacji: <· , = lub ·> .

Relacje priorytetów operatorów Do ustalenia końca ciągu będziemy używali symbolu $ oraz ustalimy, że dla wszystkich symboli terminalnych $ <· b oraz b ·> $. Przypuśćmy teraz, że usuwamy nieterminale z ciągu i umieszczamy symbol właściwej relacji <· = lub ·>. Symbol ten umieszczamy między każdą parą terminali i między krańcowymi terminalami i znakami $ oznaczającymi krańce ciągu. Przykładowo dla ciągu: id + id * id Otrzymujemy: $ <· id ·> + <· id ·> * <· id ·> $.

Relacje priorytetów operatorów Ustalamy relację priorytetów operatorów id + * $ ·> <·

Relacje priorytetów operatorów Metoda znalezienia uchwytu. - Przeglądamy ciąg od lewej strony aż do napotkania pierwszego ·>. $ <· id ·> + <· id ·> * <· id ·> $. - Następnie przechodzimy do tyłu (w prawo) po kolejnych =, aż napotkamy <· . - Uchwyt składa się ze wszystkich symboli leżących między pierwszym ·> z prawej strony a <· z lewej strony, włączając wszystkie zawarte lub otaczające nieterminale. UWAGA: Dołączenie otaczających nieterminali jest konieczne, aby nie spowodować sąsiadowania dwóch nieterminali w prawostronnej formie zdaniowej.

Relacje priorytetów operatorów Zatem uchwytem jest w tym przypadku id. Przypomnijmy gramatykę: E->E+E | E-E | E*E | E/E | E↑E | (E) | -E | id Po dokonaniu redukcji względem produkcji E->id dostajemy prawostronną formę zdaniową E + id * id . Następnie po eliminacji w ciągu nieterminali i zastosowaniu symbolu właściwej relacji dostajemy $ <· + <· id ·> * <· id ·> $. Po analogicznym zredukowaniu dwóch pozostałych id do E otrzymamy prawostronną formę zdaniową E + E * E $ <· + <· * ·> $. Oznacza to, że lewy koniec uchwytu jest między + oraz *, zaś prawy między * a $. Takie relacje priorytetów wskazują, że w prawostronnej formie zdaniowej uchwytem jest E * E .

Relacje priorytetów operatorów Aby uniknąć sytuacji, gdy w każdym kroku aby znaleźć uchwyt przeglądamy całą prawostronną formę zdaniową, używamy stosu do przechowywania już obejrzanych symboli wejściowych i korzystamy z relacji priorytetów do sterowania działaniem analizatora redukującego. Jeśli między termnalem na wierzchołku stosu a kolejnym symbolem z wyjścia zachodzi <· lub = , analizator wykonuje przesunięcie (oznacza to że nie znalazł jeszcze uchwytu); Jeżeli zachodzi ·> , to wykonywana jest redukcja (w tym momencie analizator znalazł prawy koniec uchwytu, a relacji priorytetów można użyć do znalezienia na stosie lewego krańca). Jeśli między parą terminali nie zachodzi żadna z relacji (id id), to wykryto błąd składniowy i należy wywołać procedurę obsługi błędu.

Algorytm analizy metodą pierwszeństwa operatorów Wejście: Tekst wejściowy ω i tablica relacji priorytetów. Wyjście: Jeśli ω jest poprawny – szkieletowe drzewo wyprowadzenia, z zajmującym miejsce nieterminalem E etykietującym wszystkie węzły wewnętrzne, w prze-ciwnym wypadku informacja o błędzie;

Algorytm analizy metodą pierwszeństwa operatorów Metoda: Początkowo stos zawiera $, a bufor ω$. Zainicjuj ip tak, aby wskazywał pierwszy symbol ω$. Repeat forever if $ jest na wierzcholku stosu oraz ip wskazuje $ then return else begin niech a będzie symbolem z wierzcholku stosu a b – symbolem wskazanym przez ip; if a<·b lub a=b then begin odloz b na stos; przesun ip do nastepnego symbolu wejsciowego; end; else if a·>b then /*redukcja*/ repeat zdejmi element ze stosu until szczytowy element ze stosu jest w relacji <· z poprzednio zdjetym terminalem else blad(); end

Wyznaczanie relacji priorytetów z łączności i priorytetów operatorów 1) Jeśli operator θ1 ma wyższy priorytet niż θ2 , przyjmujemy, że θ1 ·> θ2 oraz θ2 <· θ1 Jeśli przykładowo, priorytet * jest większy niż +, przyjmujemy, że * ·> + oraz + <· * (relacje te gwarantują, że, w wyrażeniach E+E*E+E, centralne E*E jest uchwytem, który będzie zredukowany jako pierwszy); 2) Jeśli θ1 i θ2 są operatorami o tym samym priorytecie (lub jest to jeden operator) przyjmijmy, że: θ1 ·> θ2 oraz θ2 ·> θ1 – jeśli te operatory są łączne lewostronnnie, θ1 <· θ2 oraz θ2 <· θ1 – jeśli te operatory są łączne lewostronnnie. Jeśli przykładowo, + i – są lewostronnie łączne, to przyjmijmy: + ·> + , + ·> - , - ·> - , - ·> + Jeśli natomiast operator ↑ jest łączny prawostronnie, to przyjmujemy ↑ <· ↑ (relacje te dają pewność, że w E-E+E wybranym uchwytem będzie E-E, a w E ↑ E ↑ E wybrane zostanie drugie E ↑ E .

Wyznaczanie relacji priorytetów z łączności i priorytetów operatorów 3) Przyjmijmy, że θ <· id , id ·> θ , θ <· ( , (·> θ , θ ·> ) , θ ·> $ <· θ dla wszystkich operatorów θ. Ponad to niech ( = ) $ <· ( $ <· id ( <· ( id ·> $ ) <· id ( <· id id ·> ) ) ·> ) (reguły te zapewniają zredukowanie id i () do E. Ponadto, $ będący znakiem zarówno lewego, jaki i prawego krańca, powoduje - tak długo jak to możliwe – wyszukiwanie kolejnych uchwytów $.

Relacje priorytetów operatorów + - * / ↑ Id ( ) $ ·> <· id = Przyjmujemy, że: Operator ↑ ma najwyższy priorytet i jest prawostronnie łączny; * oraz / mają drugi w kolejności priorytet i są lewostronnie łączne; + oraz - mają najniższy priorytet i są lewostronnie łączne.

Obsługa operatorów jednoargumentowych Mamy dwa rodzaje operatorów jednoargumento-wych: ¬ (negacja logiczna) - nie jest on jednocześnie operatorem dwuargumentowym; Znak - , który jest zarówno prefiksowym operatorem jednoargumentowym (np. -6), jaki i infiksowanym operatorem dwuargumentowym.

Obsługa operatorów jednoargumentowych ¬ (negacja logiczna) – operator ten możemy dołączyć do schematu tworzenia relacji priorytetów operatorów. A. Zakładając, że ¬ jest prefiksowym operatorem jedno-argumentowym, przyjmujemy θ <· ¬ dla wszystkich operatorów θ, zarówno jedno-, jak i dwuargumentowych; Ponadto, jeśli ¬ ma wyższy priorytet niż θ, to przyjmujemy, że: ¬ ·> θ a jeśli nie, to przyjmujemy: ¬ <· θ B. Reguły dla postfiksowych operatorów jednoargumentowych są analogiczne.

Obsługa operatorów jednoargumentowych ¬ (negacja logiczna) – przykład Jeśli ¬ ma wyższy priorytet niż &, a & jest lewostronnie łączny, to według tych reguł formę: E&¬ E&E odczytalibyśmy jako: ( E & (¬ E) ) & E

Obsługa operatorów jednoargumentowych Znak - jest zarówno prefiksowym operatorem jednoargumentowym (np. -6), jaki i infiksowanym operatorem dwuargumentowym. Nawet jeśli jedno- i dwuargumentowemu minusowi nadamy ten sam priorytet, relacje opisane wyżej nie pozwolą poprawnie przeanalizować wejścia, takiego jak np. id*-id. Najlepszym podejściem jest w takim przypadku zmiana analizatora leksykalnego tak aby rozróżniał minus jednoargumentowy od dwuargumentowego i zwracał dla nich różne symbole. Niestety analizator leksykalny nie może podglądać symboli w celu ich odróżnienia (musi on pamiętać poprzedni symbol). Można to zrobić na przykład: minus jest jednoargumentowy, jeśli poprzednim symbolem był operator, lewy nawias, przecinek, albo symbol przypisania.

Funkcje priorytetów Kompilatory używające analizatorów działających metoda pierwszeństwa operatorów nie muszą przechowywać tablic opisujących relację priorytetów. W większości przypadków tablice te można zakodować przy użyciu dwóch funkcji priorytetów f: T->Z i g: T->Z (odwzorowujące symbole terminalne w liczby całkowite). Można więc odczytać relację priorytetów a i b, porównując ze sobą funkcje. Próbujemy dobrać f i g tak aby dla symboli a i b zachodziło: f(a) < f(b), gdy a<·b f(a) = f(b), gdy a=b f(a) > f(b), gdy a·>b

Funkcje priorytetów UWAGI. Przy wykorzystaniu funkcji priorytetów tracimy informacje o błędach zapisane w tablicy priorytetów (id i id były nieporównywalne), gdyż niezależnie od wartości f(a) i f(b) – jeden z powyższych warunków zawsze będzie zachodzić. Zazwyczaj utrata możliwości wykrywania błędów nie jest na tyle ważna, żeby rezygnować z użycia funkcji priorytetów jeśli tylko jest to możliwe ( błędy mogą być wykrywane, gdy chcemy wykonać redukcję, a nie możemy znaleźć uchwytu). Nie wszystkie tablice dla relacji priorytetów mają odpowiadające im funkcje priorytetów, ale w praktyce zazwyczaj takie funkcje daje się znaleźć.

Tablica priorytetów . . + - * / ↑ Id ( ) $ ·> <· id =

Tablica priorytetów + - * / ↑ ( ) id $ f g 2 4 6 g 1 3 5 Mamy, na przykład, * <· id oraz f(*)=4 < 5=g(id) Zauważmy, że chociaż f(id) >g(id), sugeruje, że id ·> id, to id nie jest w żadnej relacji z id.

Algorytm wyznaczania funkcji priorytetów Wejście: Tablica priorytetów operatorów. Wyjście: Funkcje priorytetów reprezentujące wejściową tablicę albo informacja, że one nie istnieją. Metoda:

Algorytm wyznaczania funkcji priorytetów KROK I. Dla każdego a, będącego terminalem lub symbolem $, stwórz symbole fa i ga. KROK II. Podziel uzyskane symbole na tak wiele grup, jak jest to możliwe i w taki sposób, aby fa i fb były w tej samej grupie, jeśli a=b. (Zauważmy, że możemy umieścić symbole w tej samej grupie, nawet jeśli nie są one w relacji =. Istotnie, jeśli na przykład a=b oraz c=b, to fa i fc będą w tej samej grupie, co gb. Jeśli dodatkowo c=d to fa i gd będą w tej samej grupie, mimo, że wcale nie musi zachodzić a=d).

Algorytm wyznaczania funkcji priorytetów KROK III. Stwórz graf skierowany, którego wierzchołkami są grupy znalezione w kroku II. Dla dowolnego a i b, - jeśli a <· b, dodaj do grafu krawędź z grupy, w której jest gb, do grupy z fa. - jeśli a ·> b, dodaj krawędź od grupy z fa do grupy z gb Krawędź będąca ścieżką z fa do gb oznacza, że f(a) musi być większe od g(b), itd. KROK IV. Jeśli w grafie uzyskanym w kroku III są cykle, to funkcje priorytetów nie istnieją. Jeśli cykli nie ma, to niech f(a) będzie długością najdłuższej ścieżki zaczynającej się w grupie z fa; niech g(b) będzie długością najdłuższej ścieżki o początku w grupie z gb.

Relacje priorytetów operatorów Ustalamy relację priorytetów operatorów id + * $ ·> <·

Relacje priorytetów operatorów W grafie nie ma cykli, więc funkcje priorytetów Istnieją; Ponieważ z f$ i g$ nie wychodzą żadne krawę- dzie, to f($)=g($)=0; Najdłuższa ścieżka z g+ ma długość 1, więc g(+)=1; Istnieje ścieżka z gid do f* do g* do f+ do g+ do f$, więc g(id)=5. + * Id $ f 2 4 g 1 3 5

Obsługa błędów w analizatorach Istnieją dwa miejsca, w których analizator działający metodą pierwszeństwa operatorów może wykryć błędy: Jeśli terminal na wierzchołku stosu i aktualny symbol wejściowy nie są ze sobą w żadnej relacji priorytetów; Jeśli znaleziono uchwyt, ale nie ma produkcji, dla której ten uchwyt byłby prawą stroną.

Obsługa błędów w analizatorach UWAGI. Algorytm analizy metodą pierwszeństwa operatorów zdaje się redukować uchwyty złożone tylko z terminali. Jednakże, mimo że nieterminale są traktowane anonimowo, to na stosie analizatora dla każdego z niech jest zajęte miejsce. Czyli, gdy w powyższym błędzie 2. mówimy o uchwycie pasującym do prawej strony produkcji, oznacza to, że terminale do siebie pasują i pozycje zajmowane przez nieterminale są takie same.

Obsługa błędów w analizatorach UWAGI. Sam fakt, że znaleźliśmy na stosie ciąg symboli a <· b1 = b2 =... =bk, nie oznacza, że b1b2...bk jest ciągiem terminali po prawej stronie jakiejś produkcji. Nie sprawdzaliśmy tego warunku w algorytmie, ale możemy to zrobić, a nawet musimy, jeśli chcemy z redukcjami związać akcje semantyczne. Mamy więc możliwość wykrywania błędów w algorytmie z krokami (10)-(12) zmodyfikowanymi tak, aby sprawdzać, która z produkcji jest uchwytem podczas redukcji.

Obsługa błędów podczas redukcji Procedurę wykrywania i obsługi błędów możemy podzielić na kilka części. Pierwsza z nich obsługuje błędy typu 2. Procedura ta może, na przykład, zdejmować symbole ze stosu, tak jak korki (10)-(12) algorytmu. Ponieważ nie ma produkcji, zgodnie z którą można by wykonać redukcję, więc nie jest wykonywana żadna akcja semantyczna. Zamiast tego wypisywany jest komunikat diagnostyczny. Aby stwierdzić jak ma wyglądać ten komunikat, procedura obsługująca przypadek 2. musi zdecydować, do której produkcji „jest podobna” prawa strona zdejmowana ze stosu.

Obsługa błędów podczas redukcji Przykład: Zdejmujemy abc i nie ma prawej strony produkcji składającej się z a,b,c oraz zera lub więcej nieterminali. Możemy wówczas sprawdzić, czy usuniecie któregoś z a, b lub c daje popraną prawą stronę (z pominiętymi terminalami). Przykładowo jeśli prawa strona jest: aEcE to możemy wypisać komunikat: nieprawidlowy symbol b w wierszu (wiersz zawierajacy b)

Obsługa błędów podczas redukcji Przykład: Zdejmujemy abc i nie ma prawej strony produkcji składającej się z a,b,c oraz zera lub więcej nieterminali. Możemy również rozważać zmianę bądź wstawienie terminala. Jeśli prawą stroną byłyby napis abEdc, to moglibyśmy wypisać komunikat: pominiete d w wierszu (wiersz zawierajacy c) Może się również okazać, że prawa strona jest właściwym ciągiem terminali, ale z inaczej położonymi nieterinalami. Jeśli abc jest zdejmowane ze stosu bez zawartych lub otaczających nieterminali i abc nie jest prawą stroną, ale aEbc jest, możemy wypisać komunikat: pominiete E w wierszu (wiersz zawierajacy b) gdzie E oznacza odpowiednią kategorię składniową reprezsentowaną przez nieterminal E.

Obsługa błędów podczas redukcji Trudność znalezienia właściwego komunikatu, gdy nie znaleziono odpowiedniej prawej strony, zależy od tego, czy istnieje skończenie, czy nieskończenie wiele ciągów, które mogą być zdejmowane ze stosu w wierszach (10)-(12). W każdym takim ciągu b1b2...bk, sąsiednie symbole muszą być w relacji =, czyli b1 = b2 =... =bk. Jeśli z tablicy priorytetów operatorów wynika, że istnieje tylko skończona liczba ciągów terminali powiązanych ze sobą relacją =, to możemy rozpatrywać te ciągi indywidualnie. Dla każdego takiego ciągu x możemy wcześniej wyznaczyć najbliższą mu prawą stronę y i wypisywać komunikat mówiący, że znaleziono x a oczekiwano y.

Obsługa błędów podczas redukcji Łatwo jest wyznaczyć wszystkie ciągi, które mogą być zdejmowane ze stosu w krokach (10)-(12), gdyż są one widoczne w grafie skierowanym, którego wierzchołki reprezentują terminale, a krawędź od a do b istnieje wtedy i tylko wtedy gdy a=b. Możliwe ciągi składają się wówczas z etykiet wierzchołków leżących na ścieżkach w tym grafie. Ścieżki mogą składać się z jednego wierzchołka Aby ścieżkę b1b2...bk można było zdjąć przy jakimś wejściu, musi: istnieć symbol a (może nim być $), taki że a<· b1 = b2 =... =bk (b1 nazwijmy początkowy) istnieć symbol c (może nim być $) taki, że bk·>c (bk nazwijmy końcowym). Tylko jeśli takie symbole istnieją może wystąpić redukcja, w wyniku której ze stosu zdejmiemy b1b2...bk. Jeśli w grafie istnieje ścieżka od wierzchołka początkowego do końcowego zawierająca cykl, to istnieje nieskończenie wiele ciągów, które mogą zostać zdjęte ze stosu. W przeciwnym razie ciągów jest skończona liczba.

Obsługa błędów podczas redukcji Przypomnijmy gramatykę: E->E+E | E-E | E*E | E/E | E↑E | (E) | -E | id Tablica priorytetów Graf tablicy priorytetów

Obsługa błędów podczas redukcji Procedura wyszukująca błędy: Jeśli redukowany jest +,-,*,/ lub ↑, sprawdza, że nieterminale są po obu stronach. Jeśli nie to wypisuje komunikat: . brakuje oczekiwanych argumentow Jeśli redukowany jest id sprawdza, czy po obu stronach nie ma nieterminali. Jeśli jakiś jest, to ostrzega: brakuje oczekiwanego operatora Jeśli redukowane są ( ) to sprawdza, czy między nawiasami jest nieteriminal. Jeśli nie to może poinformować nie ma wyrażenia pomiędzy nawiasami Procedura musi ponadto sprawdzić, że nie ma nieterminala po lewej lub prawej stronie nawiasów. Jeśli jest, to procedura wypisuje komunikat:

Obsługa błędów przesunięcie/redukcja Gdy zaglądamy do tablicy priorytetów, aby zdecydować, czy wykonujemy przesunięcie czy redukcję (wiersze (6) i (9), może okazać się, że symbole z wierzchołka stosu i pierwszy symbol z wejścia nie są ze sobą w żadnej relacji. Przypuśćmy że a i b to dwa symbole z wierzchołka stosu ( b jest na wierzchu), c i d to dwa kolejne symbole wejściowe oraz, że b i c nie są w żadnej relacji priorytetów. b a $ c d $ wejście stos

Obsługa błędów przesunięcie/redukcja Aby odzyskać kontrolę, musimy zmodyfikować stos, wejście albo jedno i drugie. Możemy wówczas: zmieniać symbole; wstawiać symbole na stos i do wejścia kasować symbole z wejścia i stosu. Jeśli wstawiamy lub zmieniamy symbole, musimy uważać, żeby nie wpaść w pętlę nieskończoną, w której na przykład ciągle wstawialibyśmy symbole na początek wejścia, nie mogąc zredukować ani przesunąć żadnego z wstawionych symboli.

Obsługa błędów przesunięcie/redukcja Nie stworzymy pętli nieskończonych jeśli zapewnimy, aby po odzyskaniu kontroli aktualny symbol z wejścia mógł być przesunięty ( jeśli aktualnym symbolem jest $, mamy pewność, że nie dodamy symboli do wejścia, a stos w końcu się zmniejszy). Przykład. gdy ab jest na stosie a cd jest na wejściu, to jeśli a<·=c, to możemy zdjąć b ze stosu; Jeśli b<·=d, to możliwe jest usunięcie c ze stosu; Jeśli uda się znaleźć taki symbol e, że b<·=e <·=c, to możliwe jest wstawienie e przed c na wejściu. Ogólniej możemy wstawić taki ciąg symboli, że b<·=e1<·=... <·=en<·=c (jeśli nie możemy znaleźć pojedynczego symbolu do wstawienia). Dla każdego pustego miejsca w tablicy priorytetów musimy podać procedurę obsługi błędów (ta sama procedura może być używana w kilku miejscach). Gdy analizator sprawdza wpis dla a i b w kroku (6) a a i b nie są w żadnej z relacji priorytetów – znajduje on wskaźnik procedury obsługi dla tego błędu.

Obsługa błędów przesunięcie/redukcja Przypomnijmy gramatykę: E->E+E | E-E | E*E | E/E | E↑E | (E) | -E | id Tablica priorytetów Wiersze i kolumny, w których było co najmniej jedno puste miejsce wypełniliśmy nazwami procedur obsługi błędów:

Obsługa błędów przesunięcie/redukcja Najważniejsze części procedur obsługi błędów: e1: /* wywoływana gdy nie ma całego wyrażenia */ wstaw id na wejście; wypisz komunikat: „ nie ma oczekiwanego argumentu”; e2: /* wywoływana gdy wyrażenia zaczyna się od prawego nawiasu */ . usuń ) z wejścia wypisz komunikat: „nieoczekiwany prawy nawias”; e3: /* wywoływana gdy po id lub ) jest id lub ( */ wstaw + na wejście; wypisz komunikat: „ nie ma oczekiwanego operatora”; e4: /* wywoływana gdy wyrażenia kończy się lewym nawiasem */ zdejmij ze stosu ( wypisz komunikat: „nie ma oczekiwanego prawego nawiasu”;

Obsługa błędów przesunięcie/redukcja Sprawdźmy jak ten mechanizm obsługi błędów obsłuży błędne wejście: id + ) $ id + ) $ wejście stos

Obsługa błędów przesunięcie/redukcja Sprawdźmy jak ten mechanizm obsługi błędów obsłuży błędne wejście: id + ) E $ + ) $ wejście stos

Obsługa błędów przesunięcie/redukcja Sprawdźmy jak ten mechanizm obsługi błędów obsłuży błędne wejście: id + ) + E $ ) $ wejście Ponieważ +·>), powinniśmy wyko- nać redukcję, uchwytem jest +. Procedura wyszukująca błędy sprawdza czy po lewej i prawej stronie plusa jest E. Nie ma więc wypisuje komunikat. stos brakuje oczekiwanych argumentow

Obsługa błędów przesunięcie/redukcja Sprawdźmy jak ten mechanizm obsługi błędów obsłuży błędne wejście: id + ) E $ ) $ wejście stos Ponieważ $ i ), nie są w żadnej relacji dla tej pary symboli mamy e2 nieoczekiwany prawy nawias

Obsługa błędów przesunięcie/redukcja Sprawdźmy jak ten mechanizm obsługi błędów obsłuży błędne wejście: id + ) E $ $ wejście stos

Koniec wykładu dziewiątego