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 1. Gdy lexer znajdzie token, który interesuje parser, zwraca do parsera jego

GENERATOR YACC 1. Gdy lexer znajdzie token, który interesuje parser, zwraca do parsera jego numeryczną wartość, umieszczając ja w zmiennej yyval; 2. Funkcja yylex może być umieszczona w osobnym module (np. generowana programem lex); 3. 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