Zajęcia P2AM. Analizator składniowy (Flex + Bon, Lux) 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 (ltascii.adb lub test.mod). 2. Środowko Lux, Flex + Bon A) po włączeniu komputera wybieramy system operacyjny Lux (użytkownik student) B) uruchomienie edytora tekstu i konsoli roboczej C) utworzenie w oknie konsoli własnego katalogu (mkdir nazwko) D) przejście do własnego katalogu (cd nazwko) 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/Bon 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): bon 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) predefiowany token błędu: yyerror H) predefiowane 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 strukcjami zapanymi 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 wypać stosowny komunikat. UWAGA 2! Do wypywania formacji o znalezionych strukturach składniowych należy używać funkcji found() z pliku x.y. A) Czynności wstępne a) Wgranie własnego pliku x.l (x to ada lub modula) b) Ściągnięcie ze strony przedmiotu i rozpakowanie pliku x-syn.tgz c) Zapanie formacji o autorze w pliku parser.y. d) Wypywanie własnego imienia i nazwka na początku programu (funkcja ma() w x.y). e) Kompilacja programu z wykorzystaniem pliku Makefile lub za pomocą poleceń (pkt 3). f) Uruchomienie programu B) Rozpoznawane konstrukcje języka Ada Modula a) specyfikacja kontekstu (klauzule with i a) deklaracja IMPORT
use) b) nagłówek procedury c) deklaracja pakietu d) deklaracje zmiennych e) wywołanie procedury f) przypanie g) pętla for h) blok i) ciało pakietu j) strukcja warunkowa i deklaracja procedury b) deklaracja stałej c) deklaracja zmiennej d) wywołanie procedury e) pętla FOR f) przypanie g) strukcja warunkowa h) moduł programu 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; with Ada.Integer_Text_IO; (* m2c all test.mod o test *) (* Uruchomienie: *) (*./test *) Test (********************************************************) MODULE test; package MyTest LtAscii(LowerBound: Integer; UpperBound: Integer); MyTest; package body MyTest LtAscii(LowerBound: Integer; UpperBound: Integer) Uc : Character := ' '; Fl : Float; Put_Le("Kody ASCII:"); zmienna for I Integer range LowerBound.. UpperBound loop Ada.Integer_Text_IO.Put(I); Ada.Integer_Text_IO cyfra Put(' '); Put(Uc); Uc := Character'Succ(Uc); loop; tylko test procedura z to jest procedura z Ada.Text_IO kolejny znak Fl := 1.1 * 0.1 + 1.0e 2; po kropce i przed zawsze LtAscii; MyTest; FROM InOut IMPORT Write, WriteCard, WriteStrg, WriteLn; CONST FromAscii = 32; ToAscii = 127; VAR i : CARDINAL; fl : REAL; BEGIN WriteStrg("Kody ASCII"); WriteLn; FOR i := FromAscii TO ToAscii DO WriteCard(i, 3); Write(' '); Write(CHR(i)); WriteLn ; fl := 1.1 + 1.0E 2 + 1.0E+2 + 1.0E1; (* liczby rzeczywte *) IF (fl <= 11.11) AND (fl >= 1.111E1) THEN WriteStrg("Zgodnie z oczekiwaniami") ELSE WriteStrg("Olaboga!") ; WriteLn test. use MyTest; FromASCII : constant Integer := 32; ToASCII : constant Integer := 127;
if FromAscii <= ToAscii then LtAscii(FromAscii, ToAscii); else Put_Le("Figa"); if; Test; Przykładowy efekt działania analizatora składniowego Język ada Modula 2 Imie i Nazwko yytext Typ tokena Wartosc tokena znakowo Imie i Nazwko yytext Typ tokena Wartosc tokena znakowo with KW_WITH Text_IO IDENT Text_IO ===== FOUND: WITH_CLAUSE ===== use KW_USE Text_IO IDENT Text_IO ===== FOUND: USE_CLAUSE ===== ===== FOUND: CONTEXT_SPEC ===== with KW_WITH Integer_Text_IO IDENT Integer_Text_IO ===== FOUND: WITH_CLAUSE ===== ===== FOUND: CONTEXT_SPEC ===== Test IDENT Test ===== FOUND: PROC_HEADER 'Test'===== package KW_PACKAGE LtAscii IDENT LtAscii ===== FOUND: PROC_HEADER 'LtAscii'===== ===== FOUND: PROC_DECL 'LtAscii'===== ===== FOUND: PACKAGE_DECL 'MyTest'===== package KW_PACKAGE body KW_BODY LtAscii IDENT LtAscii ===== FOUND: PROC_HEADER 'LtAscii'===== MODULE KW_MODULE test IDENT test FROM KW_FROM InOut IDENT InOut IMPORT KW_IMPORT WriteCard IDENT WriteCard WriteStrg IDENT WriteStrg ===== FOUND: IMPORT 'InOut'===== CONST KW_CONST = = 32 INTEGER_CONST 32 ===== FOUND: CONST_DECL 'FromAscii'===== = = 127 INTEGER_CONST 127 ===== FOUND: CONST_DECL 'ToAscii'===== VAR KW_VAR CARDINAL IDENT CARDINAL ===== FOUND: VAR_DECL ===== REAL IDENT REAL ===== FOUND: VAR_DECL ===== BEGIN WriteStrg IDENT WriteStrg "Kody ASCII" STRING_CONST "Kody ASCII" ===== FOUND: PROCEDURE_CALL 'WriteStrg'===== FOR KW_FOR TO KW_TO DO KW_DO WriteCard IDENT WriteCard 3 INTEGER_CONST 3 ===== FOUND: PROCEDURE_CALL 'WriteCard'===== ' ' STRING_CONST ' '
Character IDENT Character ' ' CHARACTER_CONST ' ' ===== FOUND: VAR_DECL 'Uc'===== Fl IDENT Fl Float IDENT Float ===== FOUND: VAR_DECL 'Fl'===== New_Le IDENT New_Le ===== FOUND: PROCEDURE_CALL 'New_Le'===== Put_Le IDENT Put_Le "Kody ASCII:" STRING_CONST "Kody ASCII:" ===== FOUND: PROCEDURE_CALL 'Put_Le'===== for KW_FOR I IDENT I range KW_RANGE.. RANGE ===== FOUND: PROCEDURE_CALL 'LowerBound'===== loop KW_LOOP ===== FOUND: PROCEDURE_CALL 'UpperBound'===== Integer_Text_IO IDENT Integer_Text_IO I IDENT I ===== FOUND: PROCEDURE_CALL 'I'===== ===== FOUND: PROCEDURE_CALL 'Ada.Integer_Text_IO.Put'===== ' ' CHARACTER_CONST ' ' ===== FOUND: PROCEDURE_CALL 'Put'===== ===== FOUND: PROCEDURE_CALL 'Uc'===== ===== FOUND: PROCEDURE_CALL 'Put'===== Character IDENT Character ' ' Succ IDENT Succ ===== FOUND: PROCEDURE_CALL 'Uc'===== ===== FOUND: PROCEDURE_CALL 'Character'===== ===== FOUND: ASSIGNMENT 'Uc'===== New_Le IDENT New_Le ===== FOUND: PROCEDURE_CALL 'New_Le'===== loop KW_LOOP ===== FOUND: FOR_LOOP ===== Fl IDENT Fl 1.1 FLOAT_CONST 1.1 * * 0.1 FLOAT_CONST 0.1 1.0e-2 FLOAT_CONST 1.0e-2 ===== FOUND: PROCEDURE_CALL 'Write'===== CHR IDENT CHR ===== FOUND: PROCEDURE_CALL 'Write'===== ===== FOUND: FOR_STATEMENT 'i'===== 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 <= LE 11.11 FLOAT_CONST 11.11 AND KW_AND >= GE 1.111E1 FLOAT_CONST 1.111E1 THEN KW_THEN WriteStrg IDENT WriteStrg "Zgodnie z oczekiwanstring_const "Zgodnie z oczekiwaniami" ===== FOUND: PROCEDURE_CALL 'WriteStrg'===== ELSE KW_ELSE WriteStrg IDENT WriteStrg "Olaboga!" STRING_CONST "Olaboga!" ===== FOUND: PROCEDURE_CALL 'WriteStrg'===== ===== FOUND: IF_STATEMENT ===== test IDENT test ===== FOUND: PROGRAM_MODULE 'test'=====
===== FOUND: ASSIGNMENT 'Fl'===== LtAscii IDENT LtAscii ===== FOUND: BLOCK ===== ===== FOUND: PROC_DEFINITION 'LtAscii'===== ===== FOUND: PACKAGE_BODY 'MyTest'===== use KW_USE ===== FOUND: USE_CLAUSE ===== FromASCII IDENT FromASCII constant KW_CONSTANT 32 INTEGER_CONST 32 ===== FOUND: CONST_DECL 'FromASCII'===== ToASCII IDENT ToASCII constant KW_CONSTANT 127 INTEGER_CONST 127 ===== FOUND: CONST_DECL 'ToASCII'===== if <= LE ===== FOUND: PROCEDURE_CALL 'FromAscii'===== then KW_THEN ===== FOUND: PROCEDURE_CALL 'ToAscii'===== LtAscii IDENT LtAscii ===== FOUND: PROCEDURE_CALL 'FromAscii'===== ===== FOUND: PROCEDURE_CALL 'ToAscii'===== ===== FOUND: PROCEDURE_CALL 'LtAscii'===== else KW_ELSE Put_Le IDENT Put_Le "Figa" STRING_CONST "Figa" ===== FOUND: PROCEDURE_CALL 'Put_Le'===== New_Le IDENT New_Le ===== FOUND: PROCEDURE_CALL 'New_Le'===== if ===== FOUND: IF_STATEMENT ===== Test IDENT Test ===== FOUND: BLOCK ===== ===== FOUND: PROC_DEFINITION 'Test'=====