Specyfikacja projektu InterPascal

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Autorzy:

Siwko Łukasz

Szczepaniuk Hubert

Terlikowski Grzegorz

Wereda Michał

 

 

 

Siedlce 2005

 

 

Spis treści

 

 

1. Cel projektu.. 5

2. Dokument specyfikacji BNF analizatora leksykalnego.. 5

3. Diagram przejść stanów procesu działania interpretera (wykonywania operacji skanowania, parsowania i wykonywania). 5

4. Algorytm i opis działania kroku „Scan”. 5

5. Funkcje składające się na działanie Skanera:. 5

6. Parser.. 5

7. Funkcje i procedury dla Parsera.. 5

8. Funkcje i procedury dla modułu interpretera.. 5

 

 

1. Cel projektu

 

 

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ć.

 

 

2. Dokument specyfikacji BNF analizatora leksykalnego

 

 

<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>::= ”0” | ”1” | ”2” | … |  9”

<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>

 

 

 

3. Diagram przejść stanów procesu działania interpretera (wykonywania operacji skanowania, parsowania i wykonywania)

 

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.

 

 

 

 

4. Algorytm i opis działania kroku „Scan

 

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

                        }

            }

}

 

 

 

5. Funkcje składające się na działanie Skanera:

 

- 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;

 

 

 

6. Parser

 

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.

 

 

 

7. Funkcje i procedury dla Parsera

 

- 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_liczbasprawdza czy dany leksem jest liczbą,

- funkcja czy_zmienna sprawdza czy dany leksem jest zmienną,

- funkcja sprawdz_waruneksprawdza czy poprawna jest instrukcja warunkowa,

-   funkcja zwroc_il_leks – zwraca liczbę leksemów w nawiasach.

 

 

 

8. Funkcje i procedury dla modułu interpretera

 

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:

                startIdxpoczą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;

                startIdxpoczą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;

                startIdxpoczą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:

variablenazwa 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:

variablenazwa zmiennej do której należy przypisać wartość,

value wartość do konwersacji,

ipozycja w tablicy typów zmiennych,

formattyp 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

                startIdxpoczą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;