MENU

 




Menager

kazy69@iis.siedlce.pl



Pascal-GTW


 

 

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. Przejścia poszczególnych kroków 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).

 

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 sprawdz_znak(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 scanuj():boolean;

- funkcja sprawdz_znak 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 sprawdz_znak(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_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.

 

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



   
 
 
AP Siedlce @ 2007