Zajęcia P2AM. Analizator składniowy (Flex + Bison, Linux)
Transkrypt
Zajęcia P2AM. Analizator składniowy (Flex + Bison, Linux)
Zajęcia P2AM. Analizator składniowy (Flex + Bison, Linux) 1. Cel ćwiczeń Celem ćwiczeń jest stworzenie analizatora składniowego dla języka będącego podzbiorem języka wysokiego poziomu (Ada lub Modula2). Przy tworzeniu analizatora należy skorzystać ze stworzonego analizatora leksykalnego. Sprawdzenie działania analizatora należy przeprowadzić dla zadanego programu testowego (listascii.adb lub test.mod). 2. Środowisko Linux, Flex + Bison A) po włączeniu komputera wybieramy system operacyjny Linux (użytkownik student) B) uruchomienie edytora tekstu i konsoli roboczej C) utworzenie w oknie konsoli własnego katalogu (mkdir nazwisko) D) przejście do własnego katalogu (cd nazwisko) E) UWAGA! Po zakończeniu zajęć należy skopiować własne projekty, a następnie skasować je z twardego dysku. 3. Informacja o programach Lex/Flex oraz Yacc/Bison A) Do utworzenia programu zaleca się skorzystać z pliku Makefile, który można ściągnąć (nie kopiować z edytora) ze strony przedmiotu! Kompilacji i łączenia dokonuje się za pomocą polecenia make. Wykonywalny plik programu nosi nazwę x, gdzie x to ada lub modula. Alternatywnie można wykonać poniższe polecenia: a. Generacja kodu analizatora składniowego (pliki y.tab.c oraz y.tab.h): bison –d x.y b. Generacja kodu skanera (plik lex.yy.c): flex -t x.l > x.c c. Kompilacja kodu parsera (plik zad): gcc x.tab.c x.c –o x B) Przekierowanie standardowych strumieni: ./x <plik_we >plik_wy C) wartość wykrytego tokena należy ustawić w zmiennej yylval (w kodzie dla Flex’a) D) postać reguł składniowych: A: B C D {akcja semantyczna} ; E) wartość zmiennej po lewej stronie reguły składniowej: $$ (left value) F) wartość tokenów i zmiennych po prawej stronie reguły składniowej: $1, $2, $3 G) predefiniowany token błędu: yyerror H) predefiniowane makra dla akcji semantycznych w Yacc’u: YYABORT – zakończenie działania parsera z sygnalizacją błędu YYACCEPT – zakończenie działania parsera z sygnalizacją akceptacji YYERROR – generuje błąd składniowy jednak bez wywoływania procedury yyerror 4. Analizator składniowy (realizowany stopniowo zgodnie z instrukcjami zapisanymi w pliku *.y). UWAGA 1! Zadanie należy realizować krok po kroku sprawdzając efekty działania kolejnych realizowanych reguł składniowych. Po rozpoznaniu konstrukcji składniowej należy wypisać stosowny komunikat. UWAGA 2! Do wypisywania informacji o znalezionych strukturach składniowych należy używać funkcji found() z pliku x.y. A) Czynności wstępne a) b) c) d) e) f) Wgranie własnego pliku x.l (x to ada lub modula) Ściągnięcie ze strony przedmiotu i rozpakowanie pliku x-syn.tgz Zapisanie informacji o autorze w pliku parser.y. Wypisywanie własnego imienia i nazwiska na początku programu (funkcja main() w x.y). Kompilacja programu z wykorzystaniem pliku Makefile lub za pomocą poleceń (pkt 3). Uruchomienie programu B) Rozpoznawane konstrukcje języka Ada a) specyfikacja kontekstu (klauzule with i Modula a) deklaracja IMPORT b) c) d) e) f) g) h) i) j) use) nagłówek procedury deklaracja pakietu deklaracje zmiennych wywołanie procedury przypisanie pętla for blok ciało pakietu instrukcja warunkowa procedury b) c) d) e) f) g) h) i deklaracja stałej deklaracja zmiennej wywołanie procedury pętla FOR przypisanie instrukcja warunkowa moduł programu deklaracja UWAGA 3! Składnia języków ada i modula 2 jest o wiele bardziej skomplikowana niż może to wynikać z realizowanego projektu. Na laboratorium upraszczamy tę składnię tak, by można było przeanalizować program testowy. Pliki testowe: Przykładowy plik testowy dla języka ada Przykładowy plik testowy dla moduli 2 Ten program drukuje znaki i ich kody ASCII (********************************************************) Kompilacja: gnatmake test (* Program pokazuje kody ASCII *) (* Kompilacja: *) with Ada.Text_IO; use Ada.Text_IO; (* m2c all test.mod o test *) with Ada.Integer_Text_IO; (* Uruchomienie: *) (* ./test *) procedure Test is (********************************************************) MODULE test; package MyTest is procedure ListAscii(LowerBound: in Integer; UpperBound: in Integer); end MyTest; package body MyTest is FROM InOut IMPORT Write, WriteCard, WriteString, WriteLn; CONST FromAscii = 32; ToAscii = 127; VAR procedure ListAscii(LowerBound: in Integer; UpperBound: in Integer) is i : CARDINAL; Uc : Character := ' '; zmienna fl : REAL; Fl : Float; BEGIN begin WriteString("Kody ASCII"); New_Line; WriteLn; Put_Line("Kody ASCII:"); FOR i := FromAscii TO ToAscii DO for I in Integer range LowerBound .. UpperBound loop WriteCard(i, 3); Ada.Integer_Text_IO.Put(I); procedura z Ada.Integer_Text_IO Write(' '); Put(' '); to jest procedura z Ada.Text_IO Put(Uc); Uc := Character'Succ(Uc); kolejny znak New_Line; end loop; tylko test Write(CHR(i)); WriteLn END; fl := 1.1 + 1.0E2 + 1.0E+2 + 1.0E1; (* liczby rzeczywiste *) IF (fl <= 11.11) AND (fl >= 1.111E1) THEN WriteString("Zgodnie z oczekiwaniami") ELSE Fl := 1.1 * 0.1 + 1.0e2; po kropce i przed zawsze cyfra WriteString("Olaboga!") end ListAscii; END; WriteLn end MyTest; use MyTest; FromASCII : constant Integer := 32; ToASCII : constant Integer := 127; begin END test. if FromAscii <= ToAscii then ListAscii(FromAscii, ToAscii); else Put_Line("Figa"); New_Line; end if; end Test; Przykładowy efekt działania analizatora składniowego Język ada Imie i Nazwisko yytext znakowo Modula 2 Typ tokena Wartosc tokena with KW_WITH Ada IDENT Ada . . Text_IO IDENT Text_IO ; ; ===== FOUND: WITH_CLAUSE ===== use KW_USE Ada IDENT Ada . . Text_IO IDENT Text_IO ; ; ===== FOUND: USE_CLAUSE ===== ===== FOUND: CONTEXT_SPEC ===== with KW_WITH Ada IDENT Ada . . Integer_Text_IO IDENT Integer_Text_IO ; ; ===== FOUND: WITH_CLAUSE ===== procedure KW_PROCEDURE ===== FOUND: CONTEXT_SPEC ===== Test IDENT Test is KW_IS ===== FOUND: PROC_HEADER 'Test'===== package KW_PACKAGE MyTest IDENT MyTest is KW_IS procedure KW_PROCEDURE ListAscii IDENT ListAscii ( ( LowerBound IDENT LowerBound : : in KW_IN Integer IDENT Integer ; ; UpperBound IDENT UpperBound : : in KW_IN Integer IDENT Integer ) ) ===== FOUND: PROC_HEADER 'ListAscii'===== ; ; ===== FOUND: PROC_DECL 'ListAscii'===== end KW_END MyTest IDENT MyTest ; ; ===== FOUND: PACKAGE_DECL 'MyTest'===== package KW_PACKAGE body KW_BODY MyTest IDENT MyTest is KW_IS procedure KW_PROCEDURE ListAscii IDENT ListAscii ( ( LowerBound IDENT LowerBound : : in KW_IN Integer IDENT Integer ; ; UpperBound IDENT UpperBound : : in KW_IN Integer IDENT Integer ) ) ===== FOUND: PROC_HEADER 'ListAscii'===== Imie i Nazwisko yytext tokena znakowo MODULE test ; FROM InOut IMPORT Write , WriteCard , WriteString , WriteLn ; ===== FOUND: CONST FromAscii = 32 ===== FOUND: ; ToAscii = 127 ===== FOUND: ; VAR i : CARDINAL ; ===== FOUND: fl : REAL ; ===== FOUND: BEGIN WriteString ( "Kody ASCII" ) ===== FOUND: ; WriteLn ; ===== FOUND: FOR i := FromAscii TO ToAscii DO WriteCard ( i , 3 ) ===== FOUND: ; Write ( ' ' ) Typ tokena Wartosc KW_MODULE IDENT test ; KW_FROM IDENT InOut KW_IMPORT IDENT Write , IDENT WriteCard , IDENT WriteString , IDENT WriteLn ; IMPORT 'InOut'===== KW_CONST IDENT FromAscii = INTEGER_CONST 32 CONST_DECL 'FromAscii'===== ; IDENT ToAscii = INTEGER_CONST 127 CONST_DECL 'ToAscii'===== ; KW_VAR IDENT i : IDENT CARDINAL ; VAR_DECL ===== IDENT fl : IDENT REAL ; VAR_DECL ===== KW_BEGIN IDENT WriteString ( STRING_CONST "Kody ASCII" ) PROCEDURE_CALL 'WriteString'===== ; IDENT WriteLn ; PROCEDURE_CALL 'WriteLn'===== KW_FOR IDENT i ASSIGN IDENT FromAscii KW_TO IDENT ToAscii KW_DO IDENT WriteCard ( IDENT i , INTEGER_CONST 3 ) PROCEDURE_CALL 'WriteCard'===== ; IDENT Write ( STRING_CONST ' ' ) is KW_IS Uc IDENT Uc : : Character IDENT Character := ASSIGN ' ' CHARACTER_CONST ' ' ; ; ===== FOUND: VAR_DECL 'Uc'===== Fl IDENT Fl : : Float IDENT Float ; ; ===== FOUND: VAR_DECL 'Fl'===== begin KW_BEGIN New_Line IDENT New_Line ; ; ===== FOUND: PROCEDURE_CALL 'New_Line'===== Put_Line IDENT Put_Line ( ( "Kody ASCII:" STRING_CONST "Kody ASCII:" ) ) ===== FOUND: PROCEDURE_CALL 'Put_Line'===== ; ; for KW_FOR I IDENT I in KW_IN Integer IDENT Integer range KW_RANGE LowerBound IDENT LowerBound .. RANGE ===== FOUND: PROCEDURE_CALL 'LowerBound'===== UpperBound IDENT UpperBound loop KW_LOOP ===== FOUND: PROCEDURE_CALL 'UpperBound'===== Ada IDENT Ada . . Integer_Text_IO IDENT Integer_Text_IO . . Put IDENT Put ( ( I IDENT I ) ) ===== FOUND: PROCEDURE_CALL 'I'===== ===== FOUND: PROCEDURE_CALL 'Ada.Integer_Text_IO.Put'===== ; ; Put IDENT Put ( ( ' ' CHARACTER_CONST ' ' ) ) ===== FOUND: PROCEDURE_CALL 'Put'===== ; ; Put IDENT Put ( ( Uc IDENT Uc ) ) ===== FOUND: PROCEDURE_CALL 'Uc'===== ===== FOUND: PROCEDURE_CALL 'Put'===== ; ; Uc IDENT Uc := ASSIGN Character IDENT Character ' ' Succ IDENT Succ ( ( Uc IDENT Uc ) ) ===== FOUND: PROCEDURE_CALL 'Uc'===== ===== FOUND: PROCEDURE_CALL 'Character'===== ; ; ===== FOUND: ASSIGNMENT 'Uc'===== New_Line IDENT New_Line ; ; ===== FOUND: PROCEDURE_CALL 'New_Line'===== end KW_END loop KW_LOOP ; ; ===== FOUND: FOR_LOOP ===== Fl IDENT Fl := ASSIGN 1.1 FLOAT_CONST 1.1 * * 0.1 FLOAT_CONST 0.1 + + 1.0e-2 FLOAT_CONST 1.0e-2 ===== FOUND: PROCEDURE_CALL 'Write'===== ; ; Write IDENT Write ( ( CHR IDENT CHR ( ( i IDENT i ) ) ) ) ===== FOUND: PROCEDURE_CALL 'Write'===== ; ; WriteLn IDENT WriteLn END KW_END ===== FOUND: PROCEDURE_CALL 'WriteLn'===== ===== FOUND: FOR_STATEMENT 'i'===== ; ; fl IDENT fl := ASSIGN 1.1 FLOAT_CONST 1.1 + + 1.0E-2 FLOAT_CONST 1.0E-2 + + 1.0E+2 FLOAT_CONST 1.0E+2 + + 1.0E1 FLOAT_CONST 1.0E1 ; ; ===== FOUND: ASSIGNMENT 'fl'===== IF KW_IF ( ( fl IDENT fl <= LE 11.11 FLOAT_CONST 11.11 ) ) AND KW_AND ( ( fl IDENT fl >= GE 1.111E1 FLOAT_CONST 1.111E1 ) ) THEN KW_THEN WriteString IDENT WriteString ( ( "Zgodnie z oczekiwanSTRING_CONST "Zgodnie z oczekiwaniami" ) ) ===== FOUND: PROCEDURE_CALL 'WriteString'===== ELSE KW_ELSE WriteString IDENT WriteString ( ( "Olaboga!" STRING_CONST "Olaboga!" ) ) ===== FOUND: PROCEDURE_CALL 'WriteString'===== END KW_END ===== FOUND: IF_STATEMENT ===== ; ; WriteLn IDENT WriteLn END KW_END ===== FOUND: PROCEDURE_CALL 'WriteLn'===== test IDENT test . . ===== FOUND: PROGRAM_MODULE 'test'===== ; ===== FOUND: end ListAscii ===== FOUND: ; ===== FOUND: end MyTest ; ===== FOUND: use MyTest ; ===== FOUND: FromASCII : constant Integer := 32 ; ===== FOUND: ToASCII : constant Integer := 127 ; ===== FOUND: begin if FromAscii <= ===== FOUND: ToAscii then ===== FOUND: ListAscii ( FromAscii , ===== FOUND: ToAscii ) ===== FOUND: ===== FOUND: ; else Put_Line ( "Figa" ) ===== FOUND: ; New_Line ; ===== FOUND: end if ; ===== FOUND: end Test ===== FOUND: ; ===== FOUND: ; ASSIGNMENT 'Fl'===== KW_END IDENT ListAscii BLOCK ===== ; PROC_DEFINITION 'ListAscii'===== KW_END IDENT MyTest ; PACKAGE_BODY 'MyTest'===== KW_USE IDENT MyTest ; USE_CLAUSE ===== IDENT FromASCII : KW_CONSTANT IDENT Integer ASSIGN INTEGER_CONST 32 ; CONST_DECL 'FromASCII'===== IDENT ToASCII : KW_CONSTANT IDENT Integer ASSIGN INTEGER_CONST 127 ; CONST_DECL 'ToASCII'===== KW_BEGIN KW_IF IDENT FromAscii LE PROCEDURE_CALL 'FromAscii'===== IDENT ToAscii KW_THEN PROCEDURE_CALL 'ToAscii'===== IDENT ListAscii ( IDENT FromAscii , PROCEDURE_CALL 'FromAscii'===== IDENT ToAscii ) PROCEDURE_CALL 'ToAscii'===== PROCEDURE_CALL 'ListAscii'===== ; KW_ELSE IDENT Put_Line ( STRING_CONST "Figa" ) PROCEDURE_CALL 'Put_Line'===== ; IDENT New_Line ; PROCEDURE_CALL 'New_Line'===== KW_END KW_IF ; IF_STATEMENT ===== KW_END IDENT Test BLOCK ===== ; PROC_DEFINITION 'Test'=====