Metody Kompilacji Wykład 13

Podobne dokumenty
Metody Kompilacji Wykład 7 Analiza Syntaktyczna

Metody Kompilacji Wykład 3

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

Parsery LL(1) Teoria kompilacji. Dr inż. Janusz Majewski Katedra Informatyki

Generatory analizatorów

10. Translacja sterowana składnią i YACC

Metody Kompilacji Wykład 1 Wstęp

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

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

Ćwiczenia nr 11. Translatory. Wprowadzenie teoretyczne

Podstawy generatora YACC. Bartosz Bogacki.

Bison - generator analizatorów składniowych

Wprowadzenie do analizy składniowej. Bartosz Bogacki.

Zadanie analizy leksykalnej

JIP. Analiza składni, gramatyki

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

Programowanie obiektowe

Wykład 5. Jan Pustelnik

Gramatyka operatorowa

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

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Podstawy Kompilatorów

Matematyczne Podstawy Informatyki

Podstawy programowania skrót z wykładów:

Elementy języka C. ACprogramislikeafastdanceonanewlywaxeddancefloorbypeople carrying razors.

Wykład 4: Klasy i Metody

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Opis zagadnieo 1-3. Iteracja, rekurencja i ich realizacja

Interfejsy. Programowanie obiektowe. Paweł Rogaliński Instytut Informatyki, Automatyki i Robotyki Politechniki Wrocławskiej

Wykład 10. Translacja sterowana składnią

Metody kompilacji Wykłady 4-5

Podstawowe elementy proceduralne w C++ Program i wyjście. Zmienne i arytmetyka. Wskaźniki i tablice. Testy i pętle. Funkcje.

Zofia Kruczkiewicz, Programowanie obiektowe - java, wykład 2 1

Podstawy i języki programowania

JAO - Wprowadzenie do Gramatyk bezkontekstowych

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

Laboratorium 03: Podstawowe konstrukcje w języku Java [2h]

Programowanie - wykład 4

Języki formalne i gramatyki

Język C++ wykład VIII

Podstawy programowania. Wykład Pętle. Tablice. Krzysztof Banaś Podstawy programowania 1

Gramatyki atrybutywne

Uproszczony schemat działania kompilatora

Tablice (jedno i wielowymiarowe), łańcuchy znaków

Wstęp do programowania

Wstęp do programowania

2.2. Gramatyki, wyprowadzenia, hierarchia Chomsky'ego

Pętla for. Wynik działania programu:

Translacja sterowana składnią w generatorze YACC

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Wykład 2 Wybrane konstrukcje obiektowych języków programowania (1)

Zmienne, stałe i operatory

Podstawy i języki programowania

PARADYGMATY PROGRAMOWANIA Wykład 4

WYKŁAD 8. Funkcje i algorytmy rekurencyjne Proste przykłady. Programy: c3_1.c..., c3_6.c. Tomasz Zieliński

3.4. Przekształcenia gramatyk bezkontekstowych

Wykład 8: Obsługa Wyjątków

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Diagramy klas. dr Jarosław Skaruz

Projektowanie algorytmów rekurencyjnych

0.1 Lewostronna rekurencja

Programowanie obiektowe

PARADYGMATY PROGRAMOWANIA Wykład 3

Translacja sterowana składnią w metodzie zstępującej

Programowanie obiektowe

Podstawy Kompilatorów

Podstawy Programowania C++

Semantyka i Weryfikacja Programów - Laboratorium 6

Przypomnienie o klasach i obiektach

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Polimorfizm, metody wirtualne i klasy abstrakcyjne

Programowanie obiektowe

Kurs programowania. Wykład 9. Wojciech Macyna. 28 kwiecień 2016

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

Klasy abstrakcyjne i interfejsy

Uproszczony schemat działania kompilatora

Gramatyki, wyprowadzenia, hierarchia Chomsky ego. Gramatyka

Podstawy i języki programowania

Kompilacja javac prog.java powoduje wyprodukowanie kilku plików o rozszerzeniu.class, m.in. Main.class wykonanie: java Main

KOTLIN. Język programowania dla Androida

Pętle while, for, do while, instrukcje break, continue, switch 1. Pętle

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

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

Programowanie proceduralne INP001210WL rok akademicki 2015/16 semestr letni. Wykład 6. Karol Tarnowski A-1 p.

Informatyka I. Dziedziczenie. Nadpisanie metod. Klasy abstrakcyjne. Wskaźnik this. Metody i pola statyczne. dr inż. Andrzej Czerepicki

Język C++ zajęcia nr 2

Wykład 2: Podstawy Języka

Podstawy kompilatorów. Generator LLgen. Wojciech Complak.

Wyrażenie include(sciezka_do_pliku) pozwala na załadowanie (wnętrza) pliku do skryptu php. Plik ten może zawierać wszystko, co może się znaleźć w

Języki Programowania II Wykład 3. Java podstawy. Przypomnienie

Języki i metody programowania Java. Wykład 2 (część 2)

PODSTAWY INFORMATYKI 1 PRACOWNIA NR 6

Jerzy Nawrocki, Wprowadzenie do informatyki

OPERACJE WEJŚCIA / WYJŚCIA. wysyła sformatowane dane do standardowego strumienia wyjściowego (stdout)

Programowanie obiektowe

Program We Kompilator Wy Źródłowy

Języki i metodyka programowania. Typy, operatory, wyrażenia. Wejście i wyjście.

Instrukcje sterujące. wer. 11 z drobnymi modyfikacjami! Wojciech Myszka :53:

Metody Metody, parametry, zwracanie wartości

Transkrypt:

Metody Kompilacji Wykład 13

Prosty Translator Translator dla prostych wyrażeń Schemat translacji sterowanej składnią często służy za specyfikację translatora. Schemat na następnym slajdzie zostanie użyty jako definicja translacji, która przekształca wyrażenia arytmetyczne na odwrotną notację polską. Włodzimierz Bielecki WI ZUT 2

Prosty Translator Translator dla prostych wyrażeń expr -> expr + term { print('+') I expr - term { print('-') I term term -> 0 { print ('0') I 1 { print( 1 )... 9 { print ('9') Gramatyka jest lewostronnie rekurencyjna Włodzimierz Bielecki WI ZUT 3

Prosty Translator Zastosowanie analizy zstępującej Włodzimierz Bielecki WI ZUT 4

Prosty Translator Translator dla prostych wyrażeń Gramatyka jest lewostronnie rekurencyjna, więc parser przewidujący jej nie obsługuje. Mamy konflikt: z jednej strony potrzebujemy gramatyki, która ułatwia translację, z drugiej strony musimy mieć zupełnie inną gramatykę, która ułatwia parsowanie. Włodzimierz Bielecki WI ZUT 5

Prosty Translator Translator dla prostych wyrażeń Rozwiązanie polega na tym, aby rozpocząć od gramatyki dla łatwej translacji i starannie przekształcić ją w celu ułatwienia parsowania. Eliminując rekurencję lewostronną, możemy uzyskać gramatykę odpowiednią do zastosowania parsera przewidującego. Włodzimierz Bielecki WI ZUT 6

Prosty Translator Składnia abstrakcyjna i konkretna W abstrakcyjnym drzewie syntaktycznym dla wyrażenia, każdemu węzłowi wewnętrznemu odpowiada operator; dzieci węzła reprezentują argumenty operatora. Włodzimierz Bielecki WI ZUT 7

Prosty Translator Składnia abstrakcyjna i konkretna Bardziej ogólnie, każda konstrukcja języka programowania może być obsługiwana przez operator dla tej konstrukcji, operandami tego operatora są semantycznie sensowne elementy tej konstrukcji. Włodzimierz Bielecki WI ZUT 8

Prosty Translator Składnia abstrakcyjna i konkretna Drzewo abstrakcyjne dla 9-5+2: + - 2 9 5 Włodzimierz Bielecki WI ZUT 9

Prosty Translator Składnia abstrakcyjna i konkretna Abstrakcyjne drzewo syntaktyczne, lub po prostu drzewo syntaktyczne, przypomina w niektórym stopniu drzewo parsowania. Jednak w drzewie syntaktycznym, węzły wewnętrzne reprezentują konstrukcje programistyczne, podczas gdy w drzewie parsowania, węzły wewnętrzne reprezentują nieterminale. Włodzimierz Bielecki WI ZUT 10

Prosty Translator Składnia abstrakcyjna i konkretna Wiele symboli nieterminalnych gramatyki reprezentują konstrukcje programistyczne, ale inne to są tak zwane "pomocnicy, jak na przykład symbole terms i factors (wprowadzone na wykładzie 2) stosowane są do wyprowadzenia wyrażeń arytmetycznych. Włodzimierz Bielecki WI ZUT 11

Prosty Translator Składnia abstrakcyjna i konkretna W drzewie syntaktycznym, te pomocnicy zazwyczaj nie są potrzebne i są usuwane. Aby podkreślić kontrast, drzewo parsowania jest czasami nazywane konkretnym drzewem syntaktycznym, natomiast odpowiednia gramatyka jest nazywana konkretną składnią języka. Włodzimierz Bielecki WI ZUT 12

Prosty Translator Składnia abstrakcyjna i konkretna Wskazane jest, aby schemat translacji był oparty na gramatyce, której drzewa parsowania byłyby tak blisko drzew syntaktycznych, jak to tylko możliwe. Włodzimierz Bielecki WI ZUT 13

Prosty Translator Dostosowanie schematu translacji Technika eliminacji rekurencji lewostronnej (została przedstawiona na wykładzie nr 4) może być zastosowana do produkcji zawierających akcje semantyczne. Włodzimierz Bielecki WI ZUT 14

Prosty Translator Dostosowanie schematu translacji Rozważmy gramatykę: expr -> expr + term { print('+') I expr - term { print('-') I term term -> 0 { print ('0') I 1 { print( 1 )... 9 { print ('9') Włodzimierz Bielecki WI ZUT 15

Prosty Translator Dostosowanie schematu translacji Zgodnie z techniką eliminacji rekurencji lewostronnej, w naszym przykładzie A jest to expr i są dwie produkcje lewostronnie rekurencyjne dla expr oraz jedna, która nie jest rekurencyjna. Włodzimierz Bielecki WI ZUT 16

Prosty Translator Dostosowanie schematu translacji Technika dokonuje transformacji produkcji A -> Aα Aβ I γ na produkcje A-> γr R-> αr βr ε Włodzimierz Bielecki WI ZUT 17

Prosty Translator Dostosowanie schematu translacji Musimy także przekształcić produkcje z akcjami semantycznymi. Akcje semantyczne po prostu są traktowane, jak gdyby były one terminalami. Włodzimierz Bielecki WI ZUT 18

Prosty Translator Dostosowanie schematu translacji Niech: A = expr α = + term { print ('+') β = - term { print('-') γ = term Włodzimierz Bielecki WI ZUT 19

Prosty Translator Dostosowanie schematu translacji Wtedy transformacja usuwania rekurencji lewostronnej produkuje następujący schemat: Włodzimierz Bielecki WI ZUT 20

Usuwanie rekurencji lewostronnej expr term rest rest + term { print( + ) rest term { print( - ) rest ε term 0 { print( 0 ) term 1 { print( 1 ) term 9 { print( 9 ) Włodzimierz Bielecki WI ZUT 21

Usuwanie rekurencji lewostronnej expr term 9 { print( 9 ) rest - term { print( - ) rest 5 { print( 5 ) + term { print( + ) rest 2 { print( 2 ) ε expr term rest rest + term { print( + ) rest term { print( - ) rest ε term 0 { print( 0 ) 1 { print( 1 ) 9 { print( 9 ) 22

Pseudokod dla nieterminali expr term rest rest + term { print( + ) rest term { print( - ) rest ε term dig { print( dig ) void expr() { term(); rest(); void rest() { if ( lookahead == + ) { match( + ); term(); print( + ); rest(); else if ( lookahead == - ) { match( - ); term(); print( - ); rest(); else { //do nothing with the input void term() { if ( lookahead is a digit ) { t = lookahead; match(lookahead); print(t); else report( syntax error ); 23

Pseudokod dla nieterminali expr term rest rest + term { print( + ) rest term { print( - ) rest ε term dig { print( dig ) void expr() { term(); rest(); Funkcja expr implementuje void rest() { if ( produkcję lookahead == dla + nieterminala ) { match( + ); term(); print( + ); expr. rest(); else if ( lookahead == - ) { match( - ); term(); print( - ); rest(); else { //do nothing with the input void term() { if ( lookahead is a digit ) { t = lookahead; match(lookahead); print(t); else report( syntax error ); 24

Pseudokod dla nieterminali expr term rest Funkcja rest implementuje trzy rest produkcje + term dla { print( + ) rest nieterminala rest. Ona stosuje pierwszą produkcję, term jeśli { print( - ) rest symbolem bieżącym jest znak plus, ε drugą produkcję jeśli symbolem bieżącym jest znak minus, term dig i produkcję { print( dig ) rest ->ε we wszystkich innych przypadkach. void expr() { term(); rest(); void rest() { if ( lookahead == + ) { match( + ); term(); print( + ); rest(); else if ( lookahead == - ) { match( - ); term(); print( - ); rest(); else { //do nothing with the input void term() { if ( lookahead is a digit ) { t = lookahead; match(lookahead); print(t); else report( syntax error ); 25

Pseudokod dla nieterminali expr term rest rest + term { print( + ) rest term { print( - ) rest ε term dig { print( dig ) void expr() { term(); rest(); Dziesięć produkcji dla term generują dziesięć void rest() { cyfr. if ( lookahead == + ) { match( + ); term(); Ponieważ print( + ); każda z rest(); tych produkcji generuje i else if ( lookahead == - ) { drukuje match( - ); cyfrę, ten term(); sam kod realizuje print( - ); je wszystkie. rest(); else { //do nothing with the input void term() { if ( lookahead is a digit ) { t = lookahead; match(lookahead); print(t); else report( syntax error ); 26

Pseudokod dla nieterminali expr term rest rest + term { print( + ) rest term { print( - ) rest ε term dig { print( dig ) void expr() { term(); rest(); void rest() { if ( lookahead == + ) { Jeśli test match( + ); zakończy term(); się print( + ); rest(); pomyślnie, zmienna t przechowuje else if ( lookahead cyfrę == - ) { match( - ); term(); reprezentowaną print( - ); przez rest(); symbol bieżący. else { //do nothing with the input void term() { if ( lookahead is a digit ) { t = lookahead; match(lookahead); print(t); else report( syntax error ); 27

Pseudokod dla nieterminali expr term rest void expr() { term(); rest(); rest + term { print( + ) rest term { print( - ) rest ε void rest() { if ( lookahead == + ) { match( + ); term(); print( + ); rest(); else if ( lookahead == - ) { match( - ); term(); print( - ); rest(); else { //do nothing with the input Należy pamiętać, że funkcja match zmienia symbol bieżący, więc cyfra musi być zapisana w celu późniejszego wydrukowania. term dig { print( dig ) void term() { if ( lookahead is a digit ) { t = lookahead; match(lookahead); print(t); else report( syntax error ); 28

Pseudokod dla nieterminali expr term rest rest + term { print( + ) rest term { print( - ) rest ε Gdy podczas wykonywania procedury, ostatnią czynnością jest wywołanie rekurencyjne tej samej procedury, to mówimy, że jest to rekurencja ogonowa (tail recursive). void expr() { term(); rest(); void rest() { if ( lookahead == + ) { match( + ); term(); print( + ); rest(); else if ( lookahead == - ) { match( - ); term(); print( - ); rest(); else { //do nothing with the input term dig { print( dig ) void term() { if ( lookahead is a digit ) { t = lookahead; match(lookahead); print(t); else report( syntax error ); 29

Pseudokod dla nieterminali expr term rest Wywołania rekurencyjne mogą być zastąpione przez void expr() { term(); iteracje. rest(); rest + term { print( + ) rest term { print( - ) rest ε term dig { print( dig ) void rest() { if ( lookahead == + ) { match( + ); term(); print( + ); rest(); else if ( lookahead == - ) { match( - ); term(); print( - ); rest(); else { //do nothing with the input void term() { if ( lookahead is a digit ) { t = lookahead; match(lookahead); print(t); else report( syntax error ); 30

Pseudokod Dla dla procedury nieterminali bez parametrów, expr term rest rekurencję ogonową można wymienić na instrukcję skoku na początek procedury. void expr() { term(); rest(); rest + term { print( + ) rest term { print( - ) rest ε term dig { print( dig ) void rest() { if ( lookahead == + ) { match( + ); term(); print( + ); rest(); else if ( lookahead == - ) { match( - ); term(); print( - ); rest(); else { //do nothing with the input void term() { if ( lookahead is a digit ) { t = lookahead; match(lookahead); print(t); else report( syntax error ); 31

Uproszczenie kodu Dopóki symbolem bieżącym jest znak plus lub minus, procedura rest wywołuje procedurę term. W przeciwnym razie, wykonywanie pętli while się kończy. void rest() { if ( lookahead == + ) { match( + ); term(); print( + ); rest(); else if (lookahead == - ) { match( - ); term(); print( - ); rest(); else { void rest() { while ( true ) { if ( lookahead == + ) { match( + ); term(); print( + ); continue; else if (lookahead == - ) { match( - ); term(); print( - ); continue; break; Włodzimierz Bielecki WI ZUT 32

Uproszczenie kodu Gdy rekurencja ogonowa jest realizowana przez iteracje, zostaje tylko jedno wywołanie procedury rest z wewnątrz procedury expr. Dwie procedury mogą być zatem zintegrowane w jedną przez zastąpienie procedury rest() przez jej ciało. void rest() { if ( lookahead == + ) { match( + ); term(); print( + ); rest(); else if (lookahead == - ) { match( - ); term(); print( - ); rest(); else { void rest() { while ( true ) { if ( lookahead == + ) { match( + ); term(); print( + ); continue; else if (lookahead == - ) { match( - ); term(); print( - ); continue; break; Włodzimierz Bielecki WI ZUT 33

Klasa Parser w Javie import java.io.*; class Parser { static int lookahead; public Parser() throws IOException { lookahead = System.in.read(); void expr() { term(); while ( true ) { if ( lookahead == + ) { match( + ); term(); System.out.write( + ); continue; else if (lookahead == - ) { match( - ); term(); System.out.write( - ); continue; else return; void term() throws IOException { if (Character.isDigit((char)lookahead){ System.out.write((char)lookahead); match(lookahead); else throw new Error( syntax error ); void match(int t) throws IOException { if ( lookahead == t ) lookahead = System.in.read(); else throw new Error( syntax error ); Włodzimierz Bielecki WI ZUT 34

Klasa Parser w Javie import java.io.*; class Parser { static int lookahead; public Parser() throws IOException { lookahead = System.in.read(); Klasa Parser zawiera zmienną lookahead i funkcje Parser, expr, term, and match. void expr() { term(); while ( true ) { if ( lookahead == + ) { match( + ); term(); System.out.write( + ); continue; else if (lookahead == - ) { match( - ); term(); System.out.write( - ); continue; else return; void term() throws IOException { if (Character.isDigit((char)lookahead){ System.out.write((char)lookahead); match(lookahead); else throw new Error( syntax error ); void match(int t) throws IOException { if ( lookahead == t ) lookahead = System.in.read(); else throw new Error( syntax error ); Włodzimierz Bielecki WI ZUT 35

Klasa Parser w Javie import java.io.*; class Parser { static int lookahead; public Parser() throws IOException { lookahead = System.in.read(); void expr() { term(); while ( true ) { if ( lookahead == + ) { match( + ); term(); System.out.write( + ); continue; else if (lookahead == - ) { match( - ); term(); System.out.write( - ); continue; else return; Funkcja Parser o takiej samej nazwie jak klasa, jest konstruktorem. Jest wywoływana automatycznie, gdy obiekt klasy jest tworzony. void term() throws IOException { if (Character.isDigit((char)lookahead){ Konstruktor Parser System.out.write((char)lookahead); inicjalizuje zmienną match(lookahead); lookahead przez wczytanie else throw tokena. new Error( syntax error ); void match(int t) throws IOException { if ( lookahead == t ) lookahead = System.in.read(); else throw new Error( syntax error ); Włodzimierz Bielecki WI ZUT 36

Klasa Parser w Javie import java.io.*; class Parser { static int lookahead; public Parser() throws IOException { lookahead = System.in.read(); Funkcja expr realizuje nieterminale expr and rest void expr() { term(); while ( true ) { if ( lookahead == + ) { match( + ); term(); System.out.write( + ); continue; else if (lookahead == - ) { match( - ); term(); System.out.write( - ); continue; else return; void term() throws IOException { if (Character.isDigit((char)lookahead){ System.out.write((char)lookahead); match(lookahead); else throw new Error( syntax error ); void match(int t) throws IOException { if ( lookahead == t ) lookahead = System.in.read(); else throw new Error( syntax error ); Włodzimierz Bielecki WI ZUT 37

Klasa Parser w Javie import java.io.*; class Parser { static int lookahead; public Parser() throws IOException { lookahead = System.in.read(); expr wywołuje funkcje term, a następnie ma pętlę while, która sprawdza, czy Lookahead pasuje albo do "+" lub do "-". void expr() { term(); while ( true ) { if ( lookahead == + ) { match( + ); term(); System.out.write( + ); continue; else if (lookahead == - ) { match( - ); term(); System.out.write( - ); continue; else return; void term() throws IOException { if (Character.isDigit((char)lookahead){ System.out.write((char)lookahead); match(lookahead); else throw new Error( syntax error ); void match(int t) throws IOException { if ( lookahead == t ) lookahead = System.in.read(); else throw new Error( syntax error ); Włodzimierz Bielecki WI ZUT 38

Klasa Parser w Javie import java.io.*; class Parser { static int lookahead; public Parser() throws IOException { lookahead = System.in.read(); Funkcja term korzysta z funkcji isdigit należącej do klasy Character języka Java aby sprawdzić, czy symbol lookahead jest cyfrą. void expr() { term(); while ( true ) { if ( lookahead == + ) { match( + ); term(); System.out.write( + ); continue; else if (lookahead == - ) { match( - ); term(); System.out.write( - ); continue; else return; void term() throws IOException { if (Character.isDigit((char)lookahead){ System.out.write((char)lookahead); match(lookahead); else throw new Error( syntax error ); void match(int t) throws IOException { if ( lookahead == t ) lookahead = System.in.read(); else throw new Error( syntax error ); Włodzimierz Bielecki WI ZUT 39

Klasa Parser w Javie import java.io.*; class Parser { static int lookahead; public Parser() throws IOException { lookahead = System.in.read(); void expr() { term(); while ( true ) { if ( lookahead == + ) { match( + ); term(); System.out.write( + ); continue; else if (lookahead == - ) { match( - ); term(); System.out.write( - ); continue; else return; Konstrukcja (char) lookahead konwertuje lookahead na znak ponieważ lookahead jest zdeklarowana jako zmienna całkowita void term() throws IOException { if (Character.isDigit((char)lookahead){ System.out.write((char)lookahead); match(lookahead); else throw new Error( syntax error ); void match(int t) throws IOException { if ( lookahead == t ) lookahead = System.in.read(); else throw new Error( syntax error ); Włodzimierz Bielecki WI ZUT 40

Klasa Parser w Javie import java.io.*; class Parser { static int lookahead; public Parser() throws IOException { lookahead = System.in.read(); Funkcja match sprawdza terminale; odczytuje następny terminal jeśli symbol lookahead jest dopasowany do t, inaczej sygnalizuje błąd, wykonując throw new Error( syntax error") ; void expr() { term(); while ( true ) { if ( lookahead == + ) { match( + ); term(); System.out.write( + ); continue; else if (lookahead == - ) { match( - ); term(); System.out.write( - ); continue; else return; void term() throws IOException { if (Character.isDigit((char)lookahead){ System.out.write((char)lookahead); match(lookahead); else throw new Error( syntax error ); void match(int t) throws IOException { if ( lookahead == t ) lookahead = System.in.read(); else throw new Error( syntax error ); Włodzimierz Bielecki WI ZUT 41

Klasa Parser w Javie import java.io.*; class Parser { static int lookahead; public Parser() throws IOException { lookahead = System.in.read(); Ten kod tworzy nowy wyjątek klasy Error void expr() { term(); while ( true ) { if ( lookahead == + ) { match( + ); term(); System.out.write( + ); continue; else if (lookahead == - ) { match( - ); term(); System.out.write( - ); continue; else return; void term() throws IOException { if (Character.isDigit((char)lookahead){ System.out.write((char)lookahead); match(lookahead); else throw new Error( syntax error ); void match(int t) throws IOException { if ( lookahead == t ) lookahead = System.in.read(); else throw new Error( syntax error ); Włodzimierz Bielecki WI ZUT 42

Program w języku C Włodzimierz Bielecki WI ZUT 43

Program w C #include <stdio.h> #include <ctype.h> #include <stdlib.h> int lookahead; void error() { printf("syntax error\n"); exit(exit_failure); void match(int t) { if (lookahead == t) lookahead = getchar(); else error(); Kolejność void term () { wołania funkcji if (isdigit(lookahead)) { określa lewa putchar(lookahead); strona produkcji: match(lookahead); expr term rest else rest + term error(); { print( + ) rest term { print( - ) void rest() { rest if (lookahead == '+') { ε match('+'); term(); putchar('+'); rest(); term 0 { print( 0 ) else if (lookahead == '-') { term 1 match('-'); term(); putchar('-'); rest(); { print( 1 ) term 9 else { print( 9 ) ; Włodzimierz Bielecki WI ZUT 44

Program w C void expr() { term(); rest(); int main(void) { lookahead = getchar(); expr(); putchar('\n'); return EXIT_SUCCESS; Kolejność wołania funkcji określa lewa strona produkcji: expr term rest rest + term { print( + ) rest term { print( - ) rest ε term 0 { print( 0 ) term 1 { print( 1 ) term 9 { print( 9 ) Włodzimierz Bielecki WI ZUT 45

Program w C #include <stdio.h> #include <ctype.h> #include <stdlib.h> int lookahead; void error() { printf("syntax error\n"); exit(exit_failure); void match(int t) { if (lookahead == t) lookahead = getchar(); else error(); Kolejność void term () { wołania if (isdigit(lookahead)) { funkcji określa putchar(lookahead); lewa strona produkcji: expr term rest else rest + term error(); { print( + ) rest match(lookahead); term void rest() { { print( - ) rest ε term 0 { print( 0 ) term 1 { print( 1 ) term 9 { print( 9 ) if (lookahead == '+') { match('+'); term(); putchar('+'); rest(); else if (lookahead == '-') { match('-'); term(); putchar('-'); rest(); else ; Włodzimierz Bielecki WI ZUT zwraca wartość różną od zera gdy argument, który został przekazany do funkcji jest cyfrą. 46

Program w C, cd #include <stdio.h> #include <ctype.h> #include <stdlib.h> int lookahead; void error() { printf("syntax error\n"); exit(exit_failure); void match(int t) { if (lookahead == t) lookahead = getchar(); else error(); Kolejność void term () { wołania if (isdigit(lookahead)) { funkcji określa putchar(lookahead); lewa strona produkcji: expr term rest else rest + term error(); { print( + ) rest match(lookahead); term void rest() { { print( - ) rest ε term 0 { print( 0 ) term 1 { print( 1 ) term 9 { print( 9 ) if (lookahead == '+') { match('+'); term(); putchar('+'); rest(); else if (lookahead == '-') { match('-'); term(); putchar('-'); rest(); else ; Włodzimierz Bielecki WI ZUT wysyła znak na standardowe wyjście, implementuje akcje { print( + ) 47

Zastosowanie analizy wstępującej w oparciu o Lex i Yacc Włodzimierz Bielecki WI ZUT 48

Zastosowanie Lex a i Yacc a Lex file: %{ #include <stdlib.h> #include "y.tab.h" void yyerror(char *); % VAR [a-z] %% {VAR {yylval.value[0]=*yytext; yylval.value[1]='\0'; return VAR; [-+*/"^"\n] return *yytext; [ \t] ; yyerror("invalid Char"); %% int yywrap(void) { return 1; [a-z] = a b c z, Definiuje terminal VAR Określa wartości atrybutów tokenów za pomocą odpowiedniego pola unii, zdeklarowanej na następnym slajdzie Włodzimierz Bielecki WI ZUT 49

Zastosowanie Lex a i Yacc a Yacc file: %{ void yyerror(char *); int yylex(void); #include<stdio.h> char prefix[300]; char postfix[300]; char temp[52]; % %union { char value[300]; %token <value> VAR %type <value> exp term fact w celu zadeklarowania typów symboli należy najpierw zdefiniować typ atrybutów za pomocą deklaracji %union Definiuje symbole terminalne Definiuje symbole nieterminalne Włodzimierz Bielecki WI ZUT 50

Zastosowanie Lex a i Yacc a %% program: exp '\n' { printf("%s\n",$1); ; exp: term { strcpy($$,$1); exp '+' term { /*strcat ($$,$1);*/ strcat ($$,$3); strcat ($$,"+"); exp '-' term { /*strcat ($$,$1)*/; strcat ($$,$3); strcat ($$,"-"); ; kopiuje tekst z $1 do $$. dopisuje tekst z $$ na koniec tekstu w $3. Włodzimierz Bielecki WI ZUT 51

Zastosowanie Lex a i Yacc a term: fact { strcpy($$,$1); term '*' fact { strcat ($$,$3); strcat ($$,"*"); term '/' fact { strcat ($$,$3); strcat ($$,"/"); fact: VAR { strcpy($$,$1); fact '^' VAR { strcat ($$,$3); strcat($$,"^"); %% Włodzimierz Bielecki WI ZUT 52

Zastosowanie Lex a i Yacc a void yyerror(char *s) { fprintf(stderr, "%s\n", s); int main(void) { yyparse(); return 0; Włodzimierz Bielecki WI ZUT 53

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