YACC Generator analizatorw skadniowych GENERATOR YACC Zadaniem generatora

  • Slides: 34
Download presentation
YACC Generator analizatorów składniowych

YACC Generator analizatorów składniowych

GENERATOR YACC Zadaniem generatora YACC jest wygenerowanie kodu źródłowego analizatora składniowego (domyślnie) w języku

GENERATOR YACC Zadaniem generatora YACC jest wygenerowanie kodu źródłowego analizatora składniowego (domyślnie) w języku C; Pożyteczną rzeczą jest fakt, iż generator Yacc doskonale współpracuje z generatorem analizatorów leksykalnych Lex. Kod źródłowy generowany jest przez Yacc’a w oparciu o plik ze specyfikacją; Plik z regułami tworzony jest przez samego użytkownika; 2

GENERATOR YACC Schemat organizacji działania Yacc’a: scan. l gram. y LEX YACC scan. c

GENERATOR YACC Schemat organizacji działania Yacc’a: scan. l gram. y LEX YACC scan. c y. tab. h GCC scane. exe plik. txt WYNIK 3

GENERATOR YACC Plik y. tab. c jest reprezentacją analizatora LALR napisaną w C, razem

GENERATOR YACC Plik y. tab. c jest reprezentacją analizatora LALR napisaną w C, razem z innymi procedurami w języku C, które użytkownik mógł przygotować; Opcja kompilacji "-d" powoduje zapisanie pliku nagłówkowego y. tab. h, w którym będą znajdować się definicje tokenów języka; 4

GENERATOR YACC flex –l scan. l (użycie generatora LEX) lex. yy. c yacc -d

GENERATOR YACC flex –l scan. l (użycie generatora LEX) lex. yy. c yacc -d gram. y (uzycie generatora Yacc dla pliku specyfikacji gram. y) y. tab. c i y. tab. h gcc y. tab. c lex. yy. c (kompilacja C++). /a. out < plik. in (analiza pliku) 55

GENERATOR YACC Ważną cechą analizatora jest możliwość wykorzystania go do większych aplikacji; Każdy wygenerowany

GENERATOR YACC Ważną cechą analizatora jest możliwość wykorzystania go do większych aplikacji; Każdy wygenerowany kod źródłowy zawiera bowiem funkcję, dzięki której można podłączyć analizator składniowy do innych aplikacji. Funkcja o której mowa to yyparse(); 6

GENERATOR YACC Zasady działania programu: Ø Wygenerowany przez program YACC analizator redukujący działa w

GENERATOR YACC Zasady działania programu: Ø Wygenerowany przez program YACC analizator redukujący działa w oparciu o tablicę LALR; Ø Jako symbol startowy gramatyki, przyjmowany jest, przez domniemanie, nieterminal znajdujący się po lewej stronie pierwszej produkcji; 7

GENERATOR YACC Ø Wygenerowany parser ma postać funkcji int yyparse(). Aby uruchomić parser zawarty

GENERATOR YACC Ø Wygenerowany parser ma postać funkcji int yyparse(). Aby uruchomić parser zawarty w tej funkcji potrzebujemy dwóch innych funkcji: main() i yylex(); Ø Funkcja main(), która wywołuje funkcję yyparse(); Ø Parser wywołuje lexer (yylex()), kiedy tylko pobiera token z wejścia; Ø Yacc definiuje nazwy tokenów w parserze jako nazwy preprocesora C w y. tab. h, więc lexer może je użyć. 8

GENERATOR YACC Ø Gdy lexer znajdzie token, który interesuje parser, zwraca do parsera jego

GENERATOR YACC Ø Gdy lexer znajdzie token, który interesuje parser, zwraca do parsera jego numeryczną wartość, umieszczając ja w zmiennej yyval; Ø Funkcja yylex może być umieszczona w osobnym module (np. generowana programem lex); Ø Jeżeli korzystamy z zewnętrznego skanera, przy kompilacji dokładamy opcję "-d„ (y. tab. h, w którym będą zawarte definicje tokenów języka); 9

TWORZENIE PLIKU SPECYFIKACJI Każdy plik ze specyfikacją dla programu Yacc powinien składać się z

TWORZENIE PLIKU SPECYFIKACJI Każdy plik ze specyfikacją dla programu Yacc powinien składać się z trzech sekcji; Pierwsza sekcja to sekcja definicji; W sekcji definicji umieszczamy, jak sama nazwa wskazuje, definicje i deklaracje zmiennych, stałych, deklaracje stanów oraz makra procesora; 10

TWORZENIE PLIKU SPECYFIKACJI Sekcja definicji może zawierać fragment kodu, który system przepisze bezpośrednio do

TWORZENIE PLIKU SPECYFIKACJI Sekcja definicji może zawierać fragment kodu, który system przepisze bezpośrednio do analizatora składniowego; Kod ten musi być odpowiednio „opakowany”; Otwarcie fragmentu bezpośrednio przepisywanego do analizatora powinno być poprzedzone znacznikiem %{, natomiast jej zamknięcie %}; 11

TWORZENIE PLIKU SPECYFIKACJI Przykład budowy sekcji definicji: %{ #include<iostream. h> int zmienna; int zmienna_druga=1;

TWORZENIE PLIKU SPECYFIKACJI Przykład budowy sekcji definicji: %{ #include<iostream. h> int zmienna; int zmienna_druga=1; %} 12

TWORZENIE PLIKU SPECYFIKACJI Druga sekcja to sekcja przetwarzania; W sekcji przetwarzania umieszczamy wszelkie reguły

TWORZENIE PLIKU SPECYFIKACJI Druga sekcja to sekcja przetwarzania; W sekcji przetwarzania umieszczamy wszelkie reguły postępowania, zgodnie z którymi wygenerowany będzie analizator; Reguły postępowania to inaczej przepisy na to co analizator ma zrobić gdy dokona redukcji zgodnie ze związaną z tą operacją produkcją; 13

TWORZENIE PLIKU REGUŁ Budowa reguły przetwarzania opiera się na dwóch zasadniczych częściach: produkcji i

TWORZENIE PLIKU REGUŁ Budowa reguły przetwarzania opiera się na dwóch zasadniczych częściach: produkcji i operacji; Jej budowa wygląda więc: produkcja operacja Produkcja jest zapisana w notacji programu Yacc. Strzałka w produkcji jest zastąpiona znakiem „ : ”; Operacja jest blokiem instrukcji języka C; 14

TWORZENIE PLIKU SPECYFIKACJI Jeśli w gramatyce mamy produkcję S->T+T, to przykładowa reguła produkcji może

TWORZENIE PLIKU SPECYFIKACJI Jeśli w gramatyce mamy produkcję S->T+T, to przykładowa reguła produkcji może wyglądać nastepująco: S : T ‘+’ T {printf(”liczba + liczba”); } ; Podobnie jak w przypadku LLgen terminale, które nie są literałami (są nazwane) muszą być zadeklarowane za pomocą słowa kluczowego %token; 15

NOTACJA YACC’a Rozważmy gramatykę, w której zbiór produkcji jest następujący: E -> E +

NOTACJA YACC’a Rozważmy gramatykę, w której zbiór produkcji jest następujący: E -> E + T; E -> T; T -> T * F; T -> F; F -> ( E ); F -> num; 16

ANALIZA ZSTĘPUJĄCA Sprawdźmy, w jaki sposób można te produkcje przedstawić w notacji Yacc’a? %token

ANALIZA ZSTĘPUJĄCA Sprawdźmy, w jaki sposób można te produkcje przedstawić w notacji Yacc’a? %token num %% E->E+T E : E ‘+’ T E->T |T T->T*F ; T->F F : ‘(‘ E ’)’ T : T ‘*’ F F->(E) | num |F F->num ; ; 17

NOTACJA YACC’a Niech G będzie gramatyką z produkcjami T->(T) i T->. Wtedy pustą produkcję

NOTACJA YACC’a Niech G będzie gramatyką z produkcjami T->(T) i T->. Wtedy pustą produkcję możemy zapisać w notacji Yacc następująco: %% T : ‘(‘ T ‘)’ | ; 18

AKCJE SEMANTYCZNE Akcja semantyczna Yacc’a jest sekwencją instrukcji w C; Symbol $$ odwołuje się

AKCJE SEMANTYCZNE Akcja semantyczna Yacc’a jest sekwencją instrukcji w C; Symbol $$ odwołuje się do wartości atrybutu skojarzonej z nieterminalem po lewej stronie; Symbol $i odwołuje się do wartości skojarzonej z i-tym symbolem gramatyki po prawej stronie; Akcja semantyczna wywoływana jest zawsze, gdy redukujemy według związanej z nią produkcji; 19

AKCJE SEMANTYCZNE Rozważmy dwie produkcje: E->E+T | T; wyr : wyr ‘+’ term {$$

AKCJE SEMANTYCZNE Rozważmy dwie produkcje: E->E+T | T; wyr : wyr ‘+’ term {$$ = $1 +$3; } | term ; 20

y. tab. h #define liczba 257 %token liczba %% E : E ‘+’ T

y. tab. h #define liczba 257 %token liczba %% E : E ‘+’ T | T %{ ; #include „y. tab. h” T : T ‘-’ F %} | F %% ; F : ‘(‘ E ‘)’ [+-()] return yytext[0]; 21+18 wejście [0 -9]+ return liczba; [ t] num+num | liczba ; ; . Yy_fatal(”? ? ? ”); 21

WSPÓŁPRACA Z LEX Aby powiązać Yacc z Lex’em musimy stworzyć analizator leksykalny, który będzie

WSPÓŁPRACA Z LEX Aby powiązać Yacc z Lex’em musimy stworzyć analizator leksykalny, który będzie zwracał kolejny odnaleziony symbol; %{ #include ”y. tab. h” %} %% [+-() ] return yytext[0]; [0 -9]+ return liczba; [ t] ; . YY_FATAL(”? ? ? ”); 22

Współpraca z LEX Teraz możemy dopisać analizator składniowy: %token liczba %% W : ’(‘

Współpraca z LEX Teraz możemy dopisać analizator składniowy: %token liczba %% W : ’(‘ S ’)’ S : S ’+’ T |T | liczba ; ; T : T ’-’ W | W ; 23

%token liczba %% %{ #include ”y. tab. h” %} 14+21+ -4 | T ;

%token liczba %% %{ #include ”y. tab. h” %} 14+21+ -4 | T ; %% T : T ‘-’ W [+ - ()] return yytext[0]; [0 -9]+ return liczba; [ t] S : S ‘+’ T ; . YY_FATAL(”? ? ? ”); OK | W ; W : ‘(‘ S ‘)’ | liczba ; BŁĄD 24

%token liczba %% %{ #include „y. tab. h” %} 14*4 | T ; %%

%token liczba %% %{ #include „y. tab. h” %} 14*4 | T ; %% T : T ‘-’ W [+ - ()] return yytext[0]; [0 -9]+ return liczba; [ t] S : S ‘+’ T ; . Yy_fatal(”? ? ? ”); BŁĄD | W ; W : ‘(‘ S ‘)’ | liczba ; 25

%token liczba %% %{ #include „y. tab. h” %} 14+21+4 S : S ‘+’

%token liczba %% %{ #include „y. tab. h” %} 14+21+4 S : S ‘+’ T | T ; %% T : T ‘*’ W [+*()] return yytext[0]; | W [0 -9]+ return liczba; ; [ t] ; . Yy_fatal(”? ? ? ”); OK W : ‘(‘ S ‘)’ | liczba ; OK 26

Współpraca z LEX Teraz możemy dopisać produkcję akceptującą: Q : S {puts(”OK”); } %token

Współpraca z LEX Teraz możemy dopisać produkcję akceptującą: Q : S {puts(”OK”); } %token liczba ; %% S : S ’+’ T |T W : ’(‘ S ’)’ ; T : T ’-’ W | liczba | W ; ; 27

PLIK SPECYFIKACJI Generator Yacc pozwala na korzystanie ze zmiennych; Oczywiście zmienna z której chcemy

PLIK SPECYFIKACJI Generator Yacc pozwala na korzystanie ze zmiennych; Oczywiście zmienna z której chcemy skorzystać, musi być uprzednio zadeklarowana w sekcji deklaracji; Następnie może być przetwarzana, inkrementowana i zmieniana w sekcji reguł; Sposób deklaracji: typ_zmiennej nazwa_zmiennej=wartość; 28

PLIK SPECYFIKACJI Oprócz zmiennych Yacc pozwala także na używanie funkcji; Każda taka funkcja może

PLIK SPECYFIKACJI Oprócz zmiennych Yacc pozwala także na używanie funkcji; Każda taka funkcja może być używana w regule przetwarzania; Należy jednak pamiętać o zdefiniowaniu funkcji. Definicja ciała funkcji znajduje się w trzeciej części pliku specyfikacji – części definicji; Funkcję definiuje się według standardów języka C; 29

Przykład Załóżmy, że mamy za zadanie napisać analizator dla języka, który składać się powinien,

Przykład Załóżmy, że mamy za zadanie napisać analizator dla języka, który składać się powinien, z tej samej liczby nawiasów otwierających co zamykających. Dodatkową trudnością niech będzie konieczność podania przez analizator liczby par nawiasów (otwierających i zamykających); Produkcje gramatyki łatwo wyznaczyć: S -> ( S ), S -> ; . . . 30

SPECYFIKACJA YACC W pliku specyfikacji dla generatora Yacc możemy również korzystać z nowych symboli

SPECYFIKACJA YACC W pliku specyfikacji dla generatora Yacc możemy również korzystać z nowych symboli leksykalnych; Deklarację symbolu leksykalnego poprzedza słowo kluczowe %token np. . %token nazwa_symbolu; Deklarację tę należy umieścić w sekcji pierwszej pliku specyfikacji; . . . 31

SPECYFIKACJA YACC W pliku specyfikacji dla generatora Yacc możemy również korzystać z wbudowanego w

SPECYFIKACJA YACC W pliku specyfikacji dla generatora Yacc możemy również korzystać z wbudowanego w program Yacc nieterminala error; Wbudowany nieterminal error jest bardzo przydatny przy wykrywaniu, eliminacji błędu; Można go także zastosować przy powrocie po błędzie; 32

Przykład Zmodyfikujmy nieco rozważaną poprzednio gramatykę dla języka składającego się z jednakowej liczby nawiasów,

Przykład Zmodyfikujmy nieco rozważaną poprzednio gramatykę dla języka składającego się z jednakowej liczby nawiasów, i rozważmy gramatykę dla języka którym jest niepusty ciąg liczb w nawiasach; Produkcjie tej gramatyki to: C ->(L); L->Liczba; L->L , Liczba. . .

KONIEC WYKŁADU ÓSMEGO

KONIEC WYKŁADU ÓSMEGO