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.0E­2 + 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.0e­2; ­­ 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'=====