Specyfikacja projektu InterPascal
Autorzy:
Siwko Łukasz
Szczepaniuk Hubert
Terlikowski Grzegorz
Wereda Michał
Siedlce 2005
Spis
treści
2.
Dokument specyfikacji BNF analizatora leksykalnego
4.
Algorytm i opis działania kroku „Scan”.
5.
Funkcje składające się na działanie Skanera:
7.
Funkcje i procedury dla Parsera
8.
Funkcje i procedury dla modułu interpretera
Celem projektu jest
zaimplementowanie w środowisku Delphi kompilatora
podzbioru poleceń języka Pascal. Kompilator ma za zadanie dokonać podziału
analizowanego kodu na leksemy, sprawdzić jego poprawność i ostatecznie wykonać.
<operacja_przypisania>::=
“:=”
<cz_deklaracji>::= var
<deklaracja>::= <nazwa> ”: ” <typ_zmiennej>
<nazwa>::= <litera> | <litery_cyfry>
<litery_cyfry>::= <litera> | <litery_cyfry><literaz_cyfra>
<litera_cyfra>::=<litera>
| <cyfra>
<litera>::= ”a” | ”b” | ”c” |…| ”z” | ”A” |…| ”Z”
| ”_”
<cyfra>::= ”
<typ_zmiennej>::=
integer | real | bool
<wart_bool>::=
”true” | ”false”
<zmienna>::=<nazwa>
<operacja_arytmetyczna>::= + | - | * | /
<operacja_porownania> ::= < | > | = | <= | >=
<koniec_instrukcji>::= ;
<operacja_wejscia>::=read
| readln
<operacja_wyjscia>::=write
| writeln
<instrukcja>::= <zmienna> <operacja_przypisania> <zmienna> <operacja_arytmetyczna>
<cyfra><koniec_instrukcji> |
<zmienna><operacja_przypisania><cyfra> <operacja_arytmetyczna><zmienna>
<koniec_instrukcji> |
<zmienna><operacja_przypisania><cyfra>
<operacja_arytmetyczna><zmienna>
<koniec_instrukcji> |
<instrukcja_warunkowa>
<blok_instrukcji>::= ”begin” <instrukcja> ”end”
<koniec_instrukcji>
<warunek>::= <zmienna><operacja_porownania><zmienna> |
<zmienna><operacja_porownania><cyfra>
|
<zmienna><operacja_porownania><wart_bool>
<instrukcja_warunkowa>::= ”if”
<warunek> ”then”
<blok_instrukcji> |
”if” <warunek> ”then” <instrukcja>
<petla>::=
”while” <warunek> ”do” <blok_instrukcji>
Chodzi o to, że użytkownik
może wykonywać poszczególne kroki osobno, albo spowodować od razu ich wykonanie
automatycznie, sekwencyjnie (jeżeli nie ma błędów w
poprzednim kroku). Na diagramie tym nie ma akcji dotyczących wykonania kroku z
błędami.

Dzieli plik na leksemy i umieszcza je w zmiennej typu TStringList (dynamiczna lista przechowująca wartości typu String). Wykrywa leksemy:
':' '+' '-' '/' '*' '=' '>' '<' ',' '(' ')' ‘''’ ';' '.' ‘`’
a także ciągi znakowe rozdzielone spacjami i nie zawierające ww. leksemów. Leksemami są także liczby całkowite dodatnie i rzeczywiste (znak rozdzielający to ‘.’). Dodatkowym leksemem jest ciąg znaków, otoczony przez apostrofy, lecz ich niezawierający.
Skanowanie:
oznacz Blad_w_linii := -1; //na razie nie ma błędów
dla każdej linii pliku (zawartości kontrolki RichEdit1) wykonuj:
{
jeśli linia jest długości > 0
{
ustaw wskaźnik wsk na 1 //wskazuje na bieżące miejsce w linii
dopóki wsk jest w granicach długości linii wykonuj
{
oblicz wynik poprzez wywołanie spr_i_podaj_offset(linia,wsk)
jeśli wynik=0 then //nie leksem
{
ustaw flage blad_w_linii na numer linii ‘i’;
przerwij pętlę;
}
a w przec. Wypadku
jeśli wynik <0 then
{
zwiększ wsk o abs(wynik)
}
a w przec. wypadku
skopiuj leksem do listy ‘Leksemy’
zwiększ wsk o wynik
}
}
}
- funkcja scan zwracająca true
jeśli skanowanie przebiegło pomyślnie, a false w przeciwnym wypadku.
function scan():boolean;
- funkcja spr_i_podaj_offset zwracająca wartość liczbową większą od zera jeśli rozpoznany leksem na aktualnie rozpatrywanej
pozycji jest poprawny (wtedy zwraca liczbę określającą gdzie ten rozpatrzony
leksem się kończy). Zwraca zero, jeśli nie może rozpoznać leksemu w zmiennej linia od pozycji określonej przez
zmienną wsk.
Zwraca wartość ujemną gdy wykryto ciąg znaków otoczony
apostrofami oraz dodaje te leksemy ( apostrof ciag znaków apostrof)
do zmiennej globalnej leksemy.
function
spr_i_podaj_offset(linia:string;wsk:integer): integer;
- funkcja cyfra
zwracająca wartość logiczną wskazującą czy znak podany jako argument jest cyfrą
function
cyfra(c:char):boolean;
- funkcja liczba
zwracająca wartość logiczną wskazującą czy znak podany jako argument jest
liczbą
function
litera(c:char):boolean;
Zadaniem parsera jest
sprawdzenie składni programu napisanego przez użytkownika. W programie
sprawdzane są po kolei wszystkie kombinacje leksemów. I tak:
- po słowie kluczowym
„program” musi być nazwa programu,
- po nazwie programu musi
być „;”
- zmienne muszą być
prawidłowo zadeklarowane,
- po słowach kluczowych „if” i „while” musi być warunek,
- po słowach ‘write”, „writeln”, „read”, „readln” musi nastąpić
otwarcie nawiasu,
- po części deklaracyjnej
musi być „begin”
- na kncu
programu musi być „,” itd.
- funkcja parse zwracająca true
jeśli parsowanie przebiegło pomyślnie, a false w przeciwnym
wypadku,
function parse():boolean;
- procedura usun_zbedne_spacje-
usuwa nadmierną ilość spacji (np.: jeśli leksem jest ciągiem spacji),
-
funkcja czy_liczba – sprawdza
czy dany leksem jest liczbą,
- funkcja czy_zmienna –
sprawdza czy dany leksem jest zmienną,
- funkcja sprawdz_warunek – sprawdza
czy poprawna jest instrukcja warunkowa,
-
funkcja zwroc_il_leks – zwraca liczbę leksemów w nawiasach.
Procedura setTables;
- ustawiająca tablicę ze zmiennymi określonych typów oraz ich wartości
początkowe.
Szukaj słowa kluczowego ‘var’
i zapamiętaj jego indeks w tablicy leksemów
Dopóki nie napotkano słowa kluczowego ‘begin’
Szukaj słowa ‘real’, ‘integer’ i
‘boolean’
Gdy napotkałeś któryś z
powyższych typów to wstaw wszystkie zmienne od zapamiętanej wcześniej pozycji
do odpowiedniej tablicy typów zmiennych
Przesuń kursor za średnik
poprzedzony typem i zapamiętaj jego indeks.
Ustaw początkowe wartości w tablicach wartości dla
poszczególnych typów zmiennych.
Funkcja compareExpressions(startIdx:Integer; endIdx:Integer;):Boolean - sprawdzająca warunki między słowami
kluczowymi ‘while’ i ‘do’ oraz ‘if ‘ i ‘then’;
Przekazywane parametry:
startIdx – początkowy
indeks w tablicy leksemów,
endIdx - końcowy indeks w
tablicy leksemów
Dopóki nie napotkano
‘<’,’>’,’=’,’<=’lub’>=’ przesuwaj kursor w tablicy leksemów
Wykonaj
odpowiednią operację porównania i zwróć wynik, wywołując funkcję
calculateExpression(startIdx:Integer;endIdx:Integer):Real
Przykład.
i
– pozycja napotkanego operatora porównania
“result:=calculateExpression(startIdx,i-1)<=calculateExpression(i+1,endIdx)”
Funkcja needCutBreackets(startIdx:Integer;endIdx:Integer):Boolean;
- stwierdzająca czy należy pominąć nawiasy w obliczanym wyrażeniu;
startIdx – początkowy
indeks w tablicy leksemów,
endIdx - końcowy indeks w
tablicy leksemów
zliczaj nawiasy
otwierające i zamykające w wyrażeniu;
jeśli liczba
nawiasów otwierających i zamykających jest taka sama przerwij iterację
jeśli powyższy
warunek zaistniał gdy kursor dotarł do endIdx
zwróć true w przeciwnym wypadku zwróć false;
Funkcja calculateExpression(startIdx:Integer;endIdx:Integer):Real; - wyliczająca
wartość wyrażenia;
startIdx – początkowy
indeks w tablicy leksemów,
endIdx - końcowy indeks w
tablicy leksemów
dopóki metoda needCutBreackets; -zwraca wartość true wykonuj operacje
startIdx:= startIdx+1;
endIdx:= endIdx-1;
dopóki kursor nie
jest na endIdx zliczaj nawiasy otwierające i
zamykające w wyrażeniu;
jeśli liczba
nawiasów otwierających i zamykających jest taka sama i napotkano operator ‘+’,’-’,’*’
lub ‘/’ wprowadź go do tablicy operatorów i zapamiętaj jego pozycję w
tablicy leksemów;
szukaj w
zapamiętanych operatorach tego o najniższym priorytecie wykonania, a następnie
wykonaj odpowiednie działanie wywołując rekurencyjnie funkcję calculateExpression;
Przykład
“result:=calculateExpression(startIdx,position-1)+calculateExpression(position+1,endIdx);”
jeśli nie
znaleziono żadnego operatora, wywołaj funkcję getValue(pos:Integer):Real; stwierdzającą czy napotkano liczbę,
czy zmienną i zwracającą jej wartość;
funkcja getValue(pos:Integer):Real;
- zwracająca wartość napotkanej liczby lub zmiennej
Przekazywane parametry
pos
– pozycja leksemu w tablicy leksemów;
Przeszukuj
po kolei tablicę ze zmiennymi ‘Real’,’Integer’,’Boolean’
Jeśli
znaleziono zmienną to zwróć jej wartość
Jeśli nie napotkano zmiennej
to zwróć wartość leksemu konwertując go do typu Real;
Procedura setVariable(variable:string) – funkcja ustawiająca wartość dla
zmiennej wskazanej jako parametr;
Przekazywane parametry:
variable
– nazwa zmiennej do której należy przypisać wartość.
Przeszukuj
tablicę typów zmiennych aż do napotkania zmiennej,
pobierz wartość podaną przez użytkownika
przekonvertuj wartość na określony
typ wywołując procedurę: convertValue(variable:string;value:string;i:Integer;format:string) –
Procedura convertValue(variable:string;value:string;i:Integer;format:string) –
konwertująca podaną wartość na określony typ I przypisująca ją do określonej
zmiennej.
Przekazywane parametry:
variable – nazwa
zmiennej do której należy przypisać wartość,
value –
wartość do konwersacji,
i
– pozycja w tablicy typów zmiennych,
format
– typ zmiennej.
Przekonwertuj zmienną na
określony typ.
Jeśli błąd w konwertacji wywołaj procedurę setVariable(variable:string) - w celu wprowadzenia ponownie
wartości dla zmiennej
Funkcja executeCode(startIdx:Integer;endIdx:Integer):Integer; - funkcja
wykonująca bloki kodu
startIdx – początkowy
indeks w tablicy leksemów,
endIdx - końcowy indeks w
tablicy leksemów
Pomiń ewentualne wystąpienia ‘begin’,’end’
i ’;’
Jeśli początkowym leksemem jest ‘write’
lub ‘writeln’- wyświetl wszystkie leksemy aż
do napotkania ‘);’, pomijając znaki ‘,’ oraz ‘’’.Wartości
ewentualnych zmiennych przekonwertuj do postaci ‘łańcucha znaków’
Jeśli początkowym leksemem był ‘writeln’
przejdź do następnej linii.
Jeśli początkowym leksemem jest ‘read’
lub ‘readln’ przekaż zmienną w nawiasach
procedurze setVariable(variable:string)
Jeśli początkowym leksemem był ‘readln’
przejdź do następnej linii.
Jeśli drugim leksemem jest ‘:=’ to przekaż indeks od którego zaczyna się wyrażenie oraz indeks końcowy(poprzedzający
średnik) funkcji
calculateExpression(startIdx:Integer;endIdx:Integer):Real;
Jeśli początkowym leksemem jest ‘if’
szukaj leksemu ‘then’ i zapemiętaj
jego pozycję
dopóki
liczba wystąpień leksemów ‘begin’ i ‘end’ jest różna i
w przypadku nie wystąpienia
leksemu ‘begin’ nie napotkano ‘;’
Zliczaj liczbę wystąpień
leksemów ‘begin’ i ‘end’
Przekaż początkowy i końcowy indeks w tablicy leksemów
dla wyrażenia logicznego
Funkcji compareExpressions(startIdx:Integer;endIdx:Integer):Boolean;
Gdy powyższa funkcja zwróci wartość ‘true’ wykonaj blok kodu pomiędzy słowem kluczowym ‘then’ oraz pozycją kursora ustawionego w powyższej
pętli wywołując rekurencyjnie funkcję
executeCode(startIdx:Integer;endIdx:Integer):Integer;
Przesuń kursor początkowy ‘startIdx’
na pozycję końca bloku kodu do wykonania
Jeśli początkowym leksemem jest ‘while’
szukaj leksemu ‘do’ i zapemiętaj jego pozycję
dopóki
liczba wystąpień leksemów ‘begin’ i ‘end’ jest różna i
w przypadku nie wystąpienia
leksemu ‘begin’ nie napotkano ‘;’
Zliczaj liczbę wystąpień leksemów
‘begin’ i ‘end’
Dopóki funkcja compareExpressions(startIdx:Integer;endIdx:Integer)
:Boolean
Zwraca wartość ‘true’
Wykonuj blok kodu pomiędzy słowem kluczowym ‘do’
oraz pozycją kursora ustawionego w powyższej pętli wywołując rekurencyjnie
funkcję
executeCode(startIdx:Integer;endIdx:Integer):Integer;
Przesuń kursor początkowy ‘startIdx’
na pozycję końca bloku kodu do wykonania
Jeśli kursor początkowy nie stoi na pozycji kursora
końcowego wywołaj
executeCode(startIdx:Integer;endIdx:Integer):Integer;