Zajęcia P1AM. Analizator leksykalny (Flex + Bison, Linux)

Transkrypt

Zajęcia P1AM. Analizator leksykalny (Flex + Bison, Linux)
Zajęcia P1AM. Analizator leksykalny (Flex + Bison, Linux)
1. Cel ćwiczeń
Celem ćwiczenia jest stworzenie prostego analizatora leksykalnego dla wybranego języka
programowania (C, Turbo Pascal, Modula, Ada). Zadaniem tworzonego analizatora leksykalnego
jest:
- rozpoznawania tokenów i określanie ich właściwej wartości
- eliminacja komentarzy i białych znaków
- wykrywanie wskazanych dyrektyw
- wykrywanie błędów analizy leksykalnej
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ę ada lub modula i można go wywołać
pisząc ./ oraz nazwę programu. Alternatywnie można wykonać poniższe polecenia, gdzie x to
ada lub modula:
B) Generacja kodu parsera (pliki y.tab.c oraz y.tab.h): bison –d x.y
C) Generacja kodu skanera (plik lex.yy.c): flex x.l
D) Kompilacja kodu parsera (plik zad): gcc x.tab.c x.c –o x
E) Przekierowanie standardowych strumieni: ./x <plik_we >plik_wy
4. Zadania do wykonania (analizator leksykalny)
A) Czynności wstępne
a) Ściągnięcie ze strony przedmiotu i przejrzenie wskazanych plików
b) Zapisanie informacji o autorze w plikach z rozszerzeniem l i y.
c) Wypisywanie własnego imienia i nazwiska na początku programu (funkcja main() w pliku
z rozszerzeniem y).
d) Kompilacja programu z wykorzystaniem polecenia make i pliku Makefile lub za pomocą
poleceń (pkt 3).
e) Uruchomienie programu
B) Wykrywanie tokenów
a) Wykrywanie słów kluczowych występujących w programie testowym.
b) Wykrywanie tokenów wieloznakowych występujących w pliku testowym (np. ‘<=’, ‘..’
‘:=’ - zależne od użytego języka)
c) Wykrywanie identyfikatorów, liczb całkowitych i zmiennoprzecinkowych.
d) Wykrywanie napisów bez użycia mechanizmu stanów.
e) Wykrywanie stałych znakowych (liter i symboli) bez użycia mechanizmu stanów.
f) Wykrywanie tokenów jednoznakowych (operatory, interpunkcja).
UWAGI do podpunktu B!
- Dla KAŻDEGO wykrytego tokena należy za pomocą gotowej funkcji process_token()
wyświetlić w oddzielnym wierszu w 3 kolumnach: wykryty tekst, typ tokena oraz jego wartość
znakową (yytext). Wartość tokena (3 kolumna) powinna być wyświetlana wyłącznie dla
identyfikatorów, stałych liczbowych, znakowych oraz łańcuchowych (por. tab.P1_1).
- Akcję należy zakończyć zwróceniem typu tokena: return( process_token( .. ) );
- Typy tokenów są zdefiniowana w pliku parser.y. Tokenów jednoznakowych nie trzeba definiować,
gdyż są one jednoznacznie identyfikowane przez swój kod ASCII.
C) Usuwanie (ignorowanie) komentarzy i białych znaków
g) Usuwanie białych znaków (spacja, tabulacja). UWAGA! musi się znaleźć w kodzie przed
j)!!!
h) Usuwanie komentarzy bez użycia mechanizmu stanów.
D) Zaawansowane przetwarzanie z użyciem mechanizmu stanów (warunków początkowych)
i)Wykrywanie łańcuchów znaków (napisów) oraz usuwanie komentarzy
j)Wykrywanie błędów: nierozpoczęty komentarz (tylko modula)
k) Wykrywanie błędów: niezamkniętego komentarza wielowierszowego (tylko modula) oraz
napisów wraz ze wskazaniem wiersza, w którym zostały otwarte
INFORMACJE do podpunktu D)
• Przykładowa deklaracja stanów (ang. start conditions) w sekcji 1
%x
stan1 stan2
• Dopasowanie do wyrażenia regularnego dla automatu znajdującego się w pewnym stanie (sekcja 2):
<stan1>wyr_reg1
akcja1;
<stan1,stan2,INITIAL>wyr_reg2
akcja2;
lub
<*>wyr_reg2
akcja2;
• Zmiana stanu następuje po wykonaniu akcji:
<stan1>wyr_reg { .. BEGIN stan2; }
• Stan początkowy – INITIAL
• Stan bieżący - YYSTATE (dostępny jest również w 3 sekcji):
int yywrap() {
if ( YYSTATE == COMMENT )
printf( "Niezamknięty komentarz" );
...
}
Tabela P1_1. Pliki testowe i przykłady działania analizatora leksykalnego
Plik testowy listascii.adb:
Plik testowy test.mod:
-- Ten program drukuje znaki i ich kody ASCII
-- Kompilacja: gnatmake listascii
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO;
procedure ListAscii is
FromASCII : constant Integer := 32;
ToASCII : constant Integer := 127;
Uc : Character := ' ';
-- zmienna
Fl : Float;
begin
New_Line;
Put_Line("Kody ASCII:");
for I in Integer range FromASCII .. ToASCII loop
Ada.Integer_Text_IO.Put(I);
-- procedura z
Ada.Integer_Text_IO
Put(' ');
-- to jest procedura z Ada.Text_IO
widoczna z powodu ,,use''
Put(Uc);
Uc := Character'Succ(Uc);
-- kolejny znak
New_Line;
end loop;
-- tylko test
Fl := 1.1 * 0.1 + 1.0e-2;
-- w rzeczywistych po
kropce i przed zawsze cyfra
end ListAscii;
(*******************************************)
(*Program pokazuje kody ASCII
*)
(*Kompilacja:
*)
(*m2c -all test.mod -o test
*)
(*Uruchomienie:
*)
(*./test
*)
(*******************************************)
MODULE test;
FROM
InOut
IMPORT
Write,
WriteCard,
WriteString, WriteLn;
CONST
FromAscii = 32;
ToAscii = 127;
VAR
i : CARDINAL;
fl : REAL;
BEGIN
WriteString("Kody ASCII");
WriteLn;
FOR i := FromAscii TO ToAscii DO
WriteCard(i, 3);
Write(' ');
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
WriteString("Olaboga!")
END;
WriteLn
END test.
Początek przykładowego wyjścia analizatora leksykalnego (konkretne wartości typów tokenów
zależą od kolejności ich deklaracji w pliku z rozszerzeniem y)
Ada
Modula 2
yytext
znakowo
Typ tokena
with
Ada
.
Text_IO
;
use
Ada
.
Text_IO
;
with
Ada
.
Integer_Text_IO
;
procedure
ListAscii
is
FromASCII
:
constant
Integer
:=
32
;
ToASCII
:
constant
Integer
:=
127
;
Uc
:
Character
:=
' '
;
Fl
:
Float
;
begin
New_Line
;
Put_Line
(
"Kody ASCII:"
)
;
for
I
in
Integer
range
FromASCII
..
ToASCII
loop
Ada
.
Integer_Text_IO
.
Put
(
I
)
;
Put
(
' '
)
;
Put
(
Uc
KW_WITH
IDENT
.
IDENT
;
KW_USE
IDENT
.
IDENT
;
KW_WITH
IDENT
.
IDENT
;
KW_PROCEDURE
IDENT
KW_IS
IDENT
:
KW_CONSTANT
IDENT
ASSIGN
INTEGER_CONST
;
IDENT
:
KW_CONSTANT
IDENT
ASSIGN
INTEGER_CONST
;
IDENT
:
IDENT
ASSIGN
CHARACTER_CONST
;
IDENT
:
IDENT
;
KW_BEGIN
IDENT
;
IDENT
(
STRING_CONST
)
;
KW_FOR
IDENT
KW_IN
IDENT
KW_RANGE
IDENT
RANGE
IDENT
KW_LOOP
IDENT
.
IDENT
.
IDENT
(
IDENT
)
;
IDENT
(
CHARACTER_CONST
)
;
IDENT
(
IDENT
Wartosc tokena
Ada
Text_IO
Ada
Text_IO
Ada
Integer_Text_IO
ListAscii
FromASCII
Integer
32
ToASCII
Integer
127
Uc
Character
' '
Fl
Float
New_Line
Put_Line
"Kody ASCII:"
I
Integer
FromASCII
ToASCII
Ada
Integer_Text_IO
Put
I
Put
' '
Put
Uc
yytext
tokena znakowo
Typ tokena
MODULE
test
;
FROM
InOut
IMPORT
Write
,
WriteCard
,
WriteString
,
WriteLn
;
CONST
FromAscii
=
32
;
ToAscii
=
127
;
VAR
i
:
CARDINAL
;
fl
:
REAL
;
BEGIN
WriteString
(
"Kody ASCII"
ASCII"
)
;
WriteLn
;
FOR
i
:=
FromAscii
TO
ToAscii
DO
WriteCard
(
i
,
3
)
;
Write
(
' '
)
;
Write
(
CHR
(
i
)
)
;
WriteLn
END
;
fl
:=
1.1
+
1.0E-2
KW_MODULE
IDENT
test
;
KW_FROM
IDENT
InOut
KW_IMPORT
IDENT
Write
,
IDENT
WriteCard
,
IDENT
WriteString
,
IDENT
WriteLn
;
KW_CONST
IDENT
FromAscii
=
INTEGER_CONST
32
;
IDENT
ToAscii
=
INTEGER_CONST
127
;
KW_VAR
IDENT
i
:
IDENT
CARDINAL
;
IDENT
fl
:
IDENT
REAL
;
KW_BEGIN
IDENT
WriteString
(
STRING_CONST
"Kody
)
;
IDENT
;
KW_FOR
IDENT
ASSIGN
IDENT
KW_TO
IDENT
KW_DO
IDENT
(
IDENT
,
INTEGER_CONST
)
;
IDENT
(
STRING_CONST
)
;
IDENT
(
IDENT
(
IDENT
)
)
;
IDENT
KW_END
;
IDENT
ASSIGN
FLOAT_CONST
+
FLOAT_CONST
Wartosc
WriteLn
i
FromAscii
ToAscii
WriteCard
i
3
Write
' '
Write
CHR
i
WriteLn
fl
1.1
1.0E-2
)
;
Uc
:=
Character
'
Succ
(
Uc
)
;
New_Line
;
end
loop
;
Fl
:=
1.1
*
0.1
+
1.0e-2
;
end
ListAscii
;
)
;
IDENT
ASSIGN
IDENT
'
IDENT
(
IDENT
)
;
IDENT
;
KW_END
KW_LOOP
;
IDENT
ASSIGN
FLOAT_CONST
*
FLOAT_CONST
+
FLOAT_CONST
;
KW_END
IDENT
;
Uc
Character
Succ
Uc
New_Line
Fl
1.1
0.1
1.0e-2
ListAscii
+
+
1.0E+2
FLOAT_CONST
+
+
1.0E1
FLOAT_CONST
;
;
IF
KW_IF
(
(
fl
IDENT
<=
LE
11.11
FLOAT_CONST
)
)
AND
KW_AND
(
(
fl
IDENT
>=
GE
1.111E1
FLOAT_CONST
)
)
THEN
KW_THEN
WriteString
IDENT
(
(
"Zgodnie z oczekiwanSTRING_CONST
oczekiwaniami"
)
)
ELSE
KW_ELSE
WriteString
IDENT
(
(
"Olaboga!"
STRING_CONST
)
)
END
KW_END
;
;
WriteLn
IDENT
END
KW_END
test
IDENT
.
.
1.0E+2
1.0E1
fl
11.11
fl
1.111E1
WriteString
"Zgodnie z
WriteString
"Olaboga!"
WriteLn
test

Podobne dokumenty