AKADEMIA PODLASKA

 

 

 

 


 

 

 

 

 

 

Interpreter Pascal’a.

Projekt wykonany w ramach przedmiotu: „Sieci i systemy wirtualne”

 

 

 

 

 

 

 

autorzy projektu:

Mariusz Adameczek

Marek Obuchowski

Jacek Mucha

Dawid Dembowski

 

 

 

 

 

 

Siedlce, 2003

Spis treści

 

 

1. Cel projektu.................................................................................... 3

2. Wymagania sprzętowe............................................................... 4

3. Pliki projektu.................................................................................. 5

4. Uruchomienie Interpretera................................................... 6

5. Specyfikacja BNF............................................................................ 7

6. Zasady i ograniczenia pisania programów................... 11

7. Opis działania Interpretera................................................. 13

8. Opis  kodu programu.................................................................. 19

 

 

 

 

 

 

 

 

 

 

 


1. Cel projektu

 

 

Celem projektu było stworzenie interpretera wybranego języka programowania przy wykorzystaniu dowolnego języka programowania.

Interpreter powinien udostępniać następujące możliwości programistyczne:

        funkcja „main” programu,

        deklaracja zmiennych,

        tablice statyczne,

        zmienne dynamiczne,

        operacja przypisania,

        wypisanie na ekran,

        wczytanie z klawiatury,

        pętla,

        operacje matematyczne: „+”,  „-”,  „*”, „/”

 

Wybranym przez nas językiem programowania, który będzie interpretowany jest Pascal. Natomiast kod interpretera napisany został przy użyciu języka Java 1.4.

 

 

 

 

 

 

 

 

 

2. Wymagania sprzętowe

 

 

Program „Interpreter” został napisany w języku Java.

 

Wymagania programu:

      komputer PC,

      dowolny system operacyjny,

      zainstalowany interpreter Javy JDK 1.4 lub nowszy.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

3. Pliki projektu

 

 

Plik źródłowy – Interpreter.java

 

Pliki programu:

AnalizaPliku.class

Funkcje.class

Instrukcja.class

Interpreter.class

Tablica.class

Typy.class

Wskaznik.class

Zmienna.class

 

Pliki projektu dostępne są również na sourceforge pod adresem:

http://sourceforge.net/projects/pascal2delphi

 

Do projektu dołączone są również pliki z przykładowymi programami pokazujące działanie Interpretera. Opis tych programów znajduje się w następnym rozdziale.

 

 

 

 

 

 

 

4. Uruchomienie Interpretera

 

 

W celu uruchomienia programu należy uruchomić plik:

Interpreter.class

 

Interpreter  - bez parametrów wyświetli informację o programie.

Interpreter  <nazwa_pliku­_z_kodem_pascala>

 

np. Interpreter SILNIA.PAS

 

Do projektu dołączone zostały przykładowe pliki z kodem pascalowym.

        PLIK1.PAS – jest plikiem zawierającym kod programu, w którym wykorzystano wszystkie możliwe do zastosowania instrukcje programowe. Plik ten powstawał wraz z postępem prac nad Interpreterem uzyskując ostatecznie obecną formę. Zawiera zagnieżdżone pętle, operacje na wskaźnikach, instrukcje wypisania na ekran, wczytania z klawiatury, operacje przypisania, operacje na tablicach, wyrażenia matematyczne, itd. Pozwala na dogłębne przetestowanie Interpretera. Dokonując niewielkich modyfikacji można testować zachowanie Interpretera na różne sytuacje.

        SLNIA.PAS – program obliczający silnię. Program najpierw poprosi o wpisanie liczby, a następnie policzy silnię tej liczby.

        SUMA.PAS – program zawiera kilka pętli, wyświetla w pętli liczby, liczy, sumę liczb parzystych od 0 do 100, prosi o wpisanie tekstu, który później wyświetla na ekranie monitora.

 

 

 

 

 

 

 

5. Specyfikacja BNF

 

 

Specyfikacja języka została opisana przy pomocy notacji BNF (Backus-Naur Definition).

W notacji tej posługujemy się następującymi formami opisu:

        ::= - przypisanie

        []           - element może wystąpić 0 lub 1 raz (co najwyżej 1 raz)

        {}          - wybierz jeden z elementów występujących (dokładnie 1 raz)

        {}+        - element musi wystąpić co najmniej 1 raz (1 lub więcej razy)

        {}*        - element może wystąpić 0 lub więcej razy (0 lub więcej razy)

        <>         - zostało zdefiniowane wcześniej.

 

Treść specyfikacji.

 

zero::={0}

cyfra1_9::={1|2|3|4|5|6|7|8|9}

cyfra::={<zero>|<cyfra1_9>}

mala_litera::={a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z}

duza_litera::={A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z}

litera::={<mala_litera>|<duza_litera>}

znak::={<cyfra>|<litera>|_}

nazwa::=<litera>{<znak>}*

nazwa_zmiennej::=<nazwa>

nazwa_programu::=<nazwa>

spacja={" "}

separator::={;}

cudzyslow::={"}

znak_inny::={~|`|!|@|#|$|%|^|&|*|(|)|-|+|=|[|]|{|}|

             ;|:|<|>|,|.|/|?|\|"|"|<spacja>}

znak_x::={<znak>|<znak_inny>}

tekst::=<cudzyslow>{<znak_x>}*<cudzyslow>

operator_matematyczny::={+|-|*|/}

 

liczba_nat_bez_0::=<cyfra1_9>{<cyfra>}*

 

liczba_naturalna::=["-"]{<zero>|<liczba_nat_bez_0>}

liczba_zmiennoprzecinkowa::= ["-"]<liczba_naturalna>"."{<cyfra>}+

liczba::={<liczba_naturalna>|<liczba_zmiennoprzecinkowa>}

 

 

 

 

SŁOWA KLUCZOWE

 

s_array::={array}

s_begin::={begin}

s_do::={do}

s_end::={end}

s_for::={for}

s_nil::={nil}

s_of::={of}

s_program::={program}

s_to::={to}

s_var::={var}

 

 

 

TYPY

 

id_typu_podstawowego::={integer|real|string}

 

zakres_tablicy::=<liczba_naturalna>".."<liczba_naturalna>

 

typ_tablicowy::=<s_array>"["<zakres_tablicy>"]"<s_of>

                <id_typu_podstawowego><separator>

 

typ_wskznikowy::="^"{<id_typu_podstawowego>|<typ_tablicowy>}<separator>

 

id_typu::={<id_typu_podstawowego>|<typ_tablicowy>|<typ_wskaznikowy>}

 

 

 

DEKLARACJA ZMIENNEJ

 

deklaracja_zmiennych::=

         <nazwa_zmiennej>{","<nazwa_zmiennej>}*":"<id_typu><separator>

 

 

 

TABLICE I ZMIENNE DYNAMICZNE

 

zmienna_wskazywana::=<nazwa_zmiennej>"^"

 

indeks::={<liczba_naturalna>|<nazwa_zmiennej>}

zmienna_tab::=<nazwa_zmiennej>"["<indeks>"]"

 

zmienna_tab_wskazywana::=<zmienna_wskazywana>"["<indeks>"]"

 

utworzenie_zmiennej_dynamicznej::= "new("<nazwa_zmiennej>")"

skasowanie_zmiennej_dynamicznej::= "dispose("<nazwa_zmiennej>")"

 

 

 

OPERACJE MATEMATYCZNE

 

zmienna::={<nazwa_zmiennej>|<zmienna_wskazywana>|

           <zmienna_tab>|<zmienna_tab_wskazywana>

          }

 

wartosc::={<liczba>|<zmienna>}

 

 

 

operacja_matematyczna::=<wartosc>{<operator_matematyczny><wartosc>}*

operacja_mat_w_nawias::=

                 {<operacja_matematyczna>|"("<operacja_matematyczna>")"}

operacja_mat_z_nawias::=

   <operacja_mat_w_nawias>{<operator_matematyczny><operacja_mat_w_nawias>}*

 

operacja_mat_z_nawias - umożliwia kombinacje z nawiasami ale bez zagnieżdżeń nawiasów. W szczególnym przypadku da: operacja_matematyczna lub operacja_mat_w_nawias, a nawet liczbę lub wartosc (w nawiasach i bez nawiasów). Dzięki temu możliwe są konstrukcje takie jak:

2; a; a + b; a * (b - c); (a + b) / 3; a + b * (c - d); (a + b) * (c - d);

 

wyrazenie_mat::={

 "("{<operacja_mat_z_nawias>|<wyrazenie_mat>}

    {<operator_matematyczny><wyrazenie_mat>}*")"

                 |

    {<operacja_mat_z_nawias>|<wyrazenie_mat>}

    {<operator_matematyczny><wyrazenie_mat>}*

                 }

 

 

 

OPERACJA PRZYPISANIA

 

operacja_przypisania::=

<zmienna>":="{<liczba>|<zmienna>|<wyrazenie_mat>|<tekst>|<s_nil>}

             <separator>

 

 

OPERACJE EKRAN, KLAWIATURA

 

output::={<liczba>|<zmienna>|<wyrazenie_mat>|<tekst>}

 

proc_write::="write("<output>{","<output>}*")"<separator>

proc_writeln::="writeln("<output>{","<output>}*")"<separator>

 

proc_read::= "read("<zmienna>")"<separator>

proc_readln::= "readln("<zmienna>")"<separator>

 

wypisanie_na_ekran::={<proc_write>|<proc_writeln>}

wczytanie_z_klawiatury::={<proc_read>|<proc_readln>}

 

 

 

INSTRUKCJA I BLOK INSTRUKCJI

 

instrukcja::={<operacja_przypisania>            |

              <wypisanie_na_ekran>              |

              <wczytanie_z_klawiatury>          |

              <utworzenie_zmiennej_dynamicznej> |

              <skasowanie_zmiennej_dynamicznej> |

              <petlaFor>

             }

 

blok_instrukcji::=<s_begin> {<instrukcja>}* <s_end><separator>

 

 

 

 

 

 

PĘTLA

 

petlaFor::=

        <s_for><zmienna>":="{<liczba_naturalna>|<zmienna>|<wyrazenie_mat>}

        <s_to> {<liczba_naturalna>|<zmienna>|<wyrazenie_mat>}

        <s_do> <blok_instrukcji>

 

 

 

PROGRAM

 

def_programu::=

 

[<s_program><nazwa_programu><separator>]

[<s_var>{<deklaracja_zmiennych>}+]

<s_begin>

   {<instrukcja>}*

<s_end>"."

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

6. Zasady i ograniczenia pisania programów

 

 

1.     Małe i duże litery są rozróżnialne.

2.     Każdą instrukcję piszemy w oddzielnej linii i małymi literami.

3.     Dopuszczalne są białe znaki (spacje i tabulatory). W przypadku, gdy znaki te nie będą tolerowane pojawi się odpowiedni komunikat o błędzie.

4.     W deklaracji tablicy zakres tablicy musi spełniać warunki:

         - min: 0,

- max  65535,

- pierwszy indeks <= drugi indeks.

5.     Przy odwoływaniu się do komórek tablicy dozwolone jest korzystanie z liczb całkowitych bez znaku oraz nazw zmiennych (np: tab[5]; tab^[a];).

6.     Pętle piszemy jak w przykładzie poniżej:

       for i:=1 to 50 do begin   -> to musi być w jednej linii

                          ................................

           instrukcje lub ich brak (pętla może być pusta)

                           ................................

       end;

       Czyli w pętli zawsze stosujemy instrukcję złożoną.

7.     Pętle mogą być zagnieżdżone.

8.     W stringach stosujemy apostrof: " (podwójny).

9.     Instrukcje write i writeln mogą też być stosowane tak:

     write(.., .., ...);

      np: writeln("wiek dinozaura = ", wiek);

             writeln("wynik obliczenia = ", 2*(a+3)-9);

10.  Zakres liczby całkowitej „integer” - odpowiednik „int” w Javie (32 bity).

11.  Zakres liczby rzeczywistej „real” -  odpowiednik „double” w Javie (64 bity).

12.  Nie ma części TYPE ale typy są rozpoznawane np.

   

    var   tab1, tab2: ^array [1.50] of integer;

                 tab3: ^array [1.50] of integer;

                 tabAB: ^array [1.40] of integer;

 

         to przypisanie:  tab1:= tab3;   jest poprawne i nie ma błędu,

               natomiast :  tab1:= tabAB;  spowoduje zgłoszenie błędu niezgodności                                                   typów.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

7. Opis działania Interpretera

 

 

Działanie interpretera można podzielić na 3 główne etapy.

 

 

 

 

 

 

 

 

 


Rys. 1. Ogólna zasada działania Interpretera.

 

W pierwszym etapie następuje wczytanie pliku oraz analiza leksykalna i składniowa kodu programu. W trakcie tej operacji tworzone również są dwie specjalne listy: zmiennych i instrukcji. W listach tych umieszczone są stringi zmiennych i instrukcji według ściśle określonej notacji.

 

Ogólna notacja stringów w liście zmiennych wygląda następująco:

typ_zmiennej:[typ_składowy:indeks_początkowy:indeks_końcowy:]

nazwa_zmiennej:numer_linii

Możliwe warianty to:

      integer:nazwa_zmiennej:numer_linii

      real:nazwa_zmiennej:numer_linii

      string:nazwa_zmiennej:numer_linii

      tablica:typ_składowy:indeks_początkowy:indeks_końcowy: nazwa_zmiennej:numer_linii

      ^integer:nazwa_zmiennej:numer_linii

      ^real:nazwa_zmiennej:numer_linii

      ^string:nazwa_zmiennej:numer_linii

      ^tablica:typ_składowy:indeks_początkowy:indeks_końcowy: nazwa_zmiennej:numer_linii

 

Typ_składowy oznacza typ elementów tablicy i może przyjmować wartości: integer, real lub string, zaś indeks_początkowy i indeks_końcowy są liczbami całkowitymi i opisują rozmiar tablicy.

Znak „^” oznacza, że dana zmienna jest wskaźnikiem do określonego dalej typu.

Numer_linii mówi o tym, w której linii programu została zadeklarowana dana zmienna.

 

Ogólna notacja stringów w liście instrukcji wygląda następująco:

nazwa_instrukcji:[arg_1:arg_2: ... arg_N:]numer_linii

Możliwe warianty to:

      przypisz:na_co_przypisujemy:co_przypisujemy:numer_linii

      write:do_wyświetlenia:numer_linii

      writeln:do_wyświetlenia:numer_linii

      read:na_co_zczytujemy:numer_linii

      readln:na_co_zczytujemy:numer_linii

      new:nazwa_zmiennej:numer_linii

      dispose:nazwa_zmiennej:numer_linii

      petlaFor:zmienna_iteracyjna:wyrażenie_1:wyrażenie_2: ilość_instrukcji_w_pętli:numer_linii

 

Jeśli pierwszy etap zakończy się pomyślnie tzn. program nie zawiera błędów leksykalnych i składniowych, następuje utworzenie „właściwych” list: zmiennych i instrukcji, które posłużą do wykonania programu.

W trakcie tego etapu wykorzystane zostają utworzone wcześniej listy.

Jako pierwsza tworzona jest lista zmiennych. Wczytane zostają do niej wszystkie zadeklarowane zmienne. Każda zmienna zawiera następujące pola:

        int typ

        Object wartosc

Typ zmiennej zapisany jest jako wartość integer, która stanowi powiązanie z reprezentacją typu w postaci stringu. Powiązania nr_typu – opis_typu znajdują się w wcześniej utworzonym drzewie typów. Pozwala to na szybkie odnalezienie określonego numeru typu (na podstawie jego reprezantacji tekstowej) i ewentualne porównanie z typem typu innej zmiennej. Ponadto umieszczone tam opisy typów zawierają informacje, które posłużą do dynamicznego tworzenia zmiennych, w szczególności wskaźników do tablic.

Wartość zmiennej może być dowolnego typu, a dostęp do niej możliwy jest dzięki operacji rzutowania. Ostatecznie w tablicy zmiennych będą przechowywane wartości takie jak:

        liczba całkowita (integer),

        liczba zmiennoprzecinkowa (real),

        tekst (string),

        tablica

        wskaźnik do integer (^integer),

        wskaźnik do real (^real),

        wskaźnik do string (^string),

        wskaźnik tablicy (^tablica),

        wyrażenie matematyczne – po wczytaniu instrukcji.

 

W trakcie wczytywania zmiennych do tablicy następuje sprawdzenie poprawności zakresów tablicy oraz wyszukanie duplikatów nazw zmiennych.

 

Kolejnym krokiem w drugim etapie jest utworzenie „właściwej” listy instrukcji. Przed wykonaniem tego kroku utworzona zostaje lista stałych, które zostaną do niej wczytane podczas analizy kolejnych instrukcji. Ostatecznie wszystkie stałe znajdą się w tablicy zmiennych, zaś sama lista stałych potrzebna jest tylko do „wyłapania” powtarzających się wartości stałych. Dzięki temu, jeśli w kodzie programu w kilku różnych instrukcjach istnieją odwołania do takiej samej stałej (np.: liczba 9, tekst „jakis tekst”), to po wczytaniu wszystkich tych instrukcji będą się one odwoływały do jednej i tej samej wartości umieszczonej w tablicy zmiennych.

Wszystkie wczytane instrukcje zawierają następujące pola:

        int nrInstrukcji – numer instrukcji,

        Object[] argumenty – argumenty instrukcji,

        Int nrLinii – numer linii instrukcji.

 

Numery instrukcji mogą przyjmować wartości:

        0 - przypisz

        1 - write

        2 - writeln

        3 - read

        4 - readln

        5 - new

        6 - dispose

        7 - petlaFor

 

Tablica argumenty zawiera informacje o numerach zmiennych do których odwołuje się instrukcja oraz informacje o sposobie odwołania się do zmiennych. Może zawierać następujące wartości:

        wartość null,

        obiekt typu Integer

        obiekt typu int[]

Rodzaj instancji danego obiektu oraz wartości w nim zapisane pozwalają jednoznacznie zidentyfikować zmienną do której instrukcja się odwołuje oraz rodzaj odwołania. Przykładowo zmienna a może być zmienną typu: wskaźnik do tablicy integer. Zatem mogą wystąpić odwołania: a i a^[3]. Odczytując typ zmiennej oraz instancję reprezentującą daną zmienną w tablicy argumenty możliwa jest późniejsza identyfikacja sposobu odwołania do niej.

Oprócz opisanych czynności podczas tworzenia listy instrukcji wykonywane są również następujące zadania:

      powiązanie nazw zmiennych w instrukcjach ze zmiennymi w tablicy zmiennych oraz „wyłapanie” nieznanych identyfikatorów,

      sprawdzenie zgodności typów,

      ustalenie typów wyników operacji matematycznych.

 

Tak przygotowane i sprawdzone zmienne oraz instrukcje posłużą w trzecim etapie do wykonania programu. Wykonanie programu polega na sekwencyjnym pobraniu instrukcji z listy instrukcji i wykonaniu każdej instrukcji na przypisanych jej argumentach czyli zmiennych. W celu realizacji powyższego zaimplementowana została pętla:

do {

  switch (numer_instrukcji) {

     case 0 : instrukcja przypisania

     case 1 : instrukcja write

     case 2 : instrukcja writeln

     case 3 : instrukcja read

     case 4 : instrukcja readln

     case 5 : instrukcja new

     case 6 : instrukcja dispose

     case 7 : instrukcja pętlaFor (aktywacja pętli i dodanie jej na stos_pętli)

  }

   if (stos_pętli jest nie pusty) {

        steruj_przebiegiem_pętli;

        ustal_wartosc licznik_instrukcji;

   } else licznik_instrukcji++

} while (licznik_instrukcji < kolejny_numer_instrukcji);

W trakcie wykonywania programu sprawdzane są:

      odwołania do tablic (czy nie przekraczają zakresu tablicy),

      odwołania do wskazań zmiennych dynamicznych (czy nie nastąpiła próba odwołania do wartości, która nie istnieje);

      zakresy liczb, itp.

 

Na każdym etapie działania Interpretera może być wygenerowany komunikat o błędzie, który oprócz numeru linii i jej zawartości zawiera opis błędu.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

8. Opis  kodu programu

 

 

Interpreter został napisany przy użyciu języka Java. Kod Interpretera składa się z kilku klas, w których zaimplementowano poszczególne elementy programu. Poniżej zostały wyszczególnione wszystkie zaimplementowane klasy oraz ich pola i metody.

 

Zaimportowane klasy:

import java.io.*;

import java.util.*;

import java.util.regex.*;

 

 

Klasa „AnalizaPliku” służy do wczytania pliku oraz do analizy składniowej i leksykalnej kodu programu. Większość podanych poniżej metod bazuje na wyrażeniach regularnych. Wszystkie te wyrażenia można zastosować w wielu innych językach wykorzystujących wyrażenia regularne. Wpisując dane wyrażenie regularne można „sparsować” plik tekstowy tak aby był on możliwy do wykonania przez jądro interpretera. Podstawowe języki wykorzystujące wyrażenia regularne to: Perl, Python, gawk(awk) oraz narzędzia skryptowe takie jak sed, egrep.

 

class AnalizaPliku {

 

private String nazwaPliku;

private Vector tablicaLiniiOrginal; - oryginalna tablica linii pliku.

private Vector tablicaLinii; - tablica linii pliku wstępnie zmodyfikowana podczas wczytywania pliku.

private Vector tabZmiennych; - tablica „stringów” zmiennych tworzona podczas analizy leksykalnej i składniowej pliku.

private Vector tabInstrukcji; -  tablica „stringów” instrukcji tworzona podczas analizy leksykalnej i składniowej pliku.

private Vector defzmiennych; - tablica pomocnicza z nazwami instrukcji.

 

 

AnalizaPliku(String nazwaPliku) – konstruktor.

 

String wczytajPlik() – metoda wczytująca plik, zwraca ewentualny komunikat błędu lub pusty string - jeśli plik został wczytany bez błędu.

 

String removeallspace(String inputStr) - metoda usuwa wszystkie białe znaki z podanego „inputStr” i zwraca string bez białych znaków.

 

String removeDuplicateWhitespace(String inputStr)

 

int separateandremovevar(String inputStr,int numerlinii) - służy do wstawiania do tablicy zmiennych i sprawdzania poprawności wpisanych zmiennych. Zwraca kod błędu.

 

public static String find(String patternStr, CharSequence input) - jedna z najważniejszych metod. Sprawdza wystąpienie danego stringa z podanym regularnym wyrażeniem. Zwraca znalezioną cześć.

 

String[] cotozainstrukcja(String inputStr) - sprawdza czy dany string pasuje do definicji danej instrukcji i jeżeli pasuje to zwraca instrukcje z wcześniej zdefiniowanym ciągiem znaków.

 

Object analizujProgram() - główna metoda która dzieli cały dostępny kod z vector’a „tabLinii” na trzy grupy: program, definicja zmiennych oraz ciało programu a także uruchamia wcześniejsze metody które doprowadzają do postaci zrozumiałej dla jądra kompilatora.

 

String getLiniaOrginal(int nrLinii) – metoda zwraca linię programu o numerze podanym w argumencie.

 

String[][] getTabZmiennych() – zwraca tablicę zmiennych podzielonych na poszczególne argumenty. Bazuje na metodach z klasy „Funkcje”.

 

String[][] getTabInstrukcji() – zwraca tablicę instrukcji podzielonych na poszczególne argumenty. Bazuje na metodach z klasy „Funkcje”.

 

void usunTabliceLinii()

void usunTabliceZmiennych()

void usunTabliceInstrukcji()

Vector getTL()

Vector getTZ()

Vector getTI()

private static void wyswietlTablice(Vector tablica)

void wyswietlTabliceLinii()

void wyswietlTabliceZmiennych()

void wyswietlTabliceInstrukcji()

 

}

Klasa „Funkcje” jest swego rodzaju zbiorem funkcji, które są wykorzystywane w innych klasach. Są to zazwyczaj funkcje ogólnego zastosowania. Nie zawiera żadnych pól. Metody to:

 

class Funkcje {

 

static Vector getVParameters(String linia, String chrs) - pobiera ze stringu linia parametry (stringi) rozdzielone znakami (stringami) chrs.

 

static Vector getVParameters(String linia, String chrs,

                             String chrs1) – działa podobnie jak „getVParameters” z tą różnicą, że pomija znaczenie stringów chrs wewnątrz stringów chrs1.

 

static String[] getSAParameters(String linia, String chrs) – działa jak „getVParameters” tylko, że zwraca wynik w postaci tablicy.

 

static String[][] getTabTab(Vector v, String chrs) – zwraca tablicę tablic parametrów.

 

static String[] getSAParameters(String linia, String chrs,

                                String chrs1) – podobnie jak wyżej.

 

static String[][] getTabTab(Vector v, String chrs, String chrs1) – podobnie jak wyżej.

 

static boolean czyLiczbaNaturalna(String str)

static boolean czyLiczbaRzeczywista(String str)

static boolean czyTekst(String str)

static boolean czyNazwaZmiennej(String str)

static boolean czyZmiennaWskazywana(String str)

static boolean czyZmiennaTablicowa(String str)

static boolean czyZmiennaTablicowaWskazywana(String str)

 

Reszta poniższych metod klasy Funkcje służy do sprowadzenia wyrażenia matematycznego do postaci „odwrotnej notacji polskiej” ONP. Główna metoda to „getONP(...)”, której argumentem jest wyrażenie matematyczne z nawiasami. Wyrażenie zostaje przekonwertowane i zwrócone w postaci ONP jako string.

private static int priorytet(char operator)

private static int sprawdzZnak(char c)

private static void naStos(char element, Vector stos)

private static char zeStosu(Vector stos)

static String getONP(String wyrazenieMatematyczne)

 

}

 

 

Klasa „Typy” służy do przechowywania wszystkich typów zmiennych używanych w działającym programie. Posiada metody służące do szukania i dodawania określonego typu.

 

class Typy {

 

private static TreeMap TYPY; - drzewo przechowywanych typów.

private static int ileTypow; - ilość typów.

 

Typy()

static boolean containsTyp(String strTyp)

static boolean containsTyp(int intTyp)

static int getTyp(String strTyp)

static String getTyp(int intTyp)

static int addTyp(String strTyp)

 

}

 

 

Klasa „Tablica” służy do budowania tablic. Posiada metody umożliwiające stworzenie nowej tablicy, modyfikowanie zawartości już istniejącej oraz odczytanie zawartości określonej komórki tablicy. Klasa „Zmienna” posiada pole „wartosc”, które może być elementem typu „Tablica”.

 

 

class Tablica {

 

private Object tablica; - tablica.

private int rozmiar; - rozmiar tablicy.

private int indeksPocz; - indeks początkowy tablicy.

private int typSkladowy; - typ składowy tablicy.

 

 

Tablica(int typ,int indPocz, int indKon) – konstruktor.

 

boolean czyJestIndeks(int ktory) – sprawdza istnienie indeksu „który” w tablicy.

 

boolean zapiszElement(int ktory, Object arg) – zapisuje obiekt „arg” do tablicy pod indeksem „który”.

 

Object getElement(int ktory) – zwraca pobrany z tablicy element o numerze „który”.

 

}

Klasa „Wskaznik” posiada pola i metody umożliwiające implementację zmiennych dynamicznych. Podobnie, jak w przypadku tablic, pole „wartosc” z klasy „Zmienna” może być elementem typu „Wskaznik”.

 

class Wskaznik {

 

Object object;

 

Wskaznik() – konstruktor.

Wskaznik(Object object) – konstruktor.

boolean czyNull() – sprawdza, czy wskaźnik jest null.

Object getObject() – zwraca wskazywany obiekt;

void setObject(Object object) – ustawia wartość wskazywaną.

void dispose() – usunięcie wskazywanego obiektu.

 

}

 

 

Klasa „Zmienna” to jedna z najważniejszych klas. Stanowi podwalinę listy zmiennych używanej w czasie działania programu. Posiada pola i metody umożliwiające wszelkie operacje na zmiennych.

 

class Zmienna {

 

private int typ; - numer typu zmiennej.

private Object wartosc; - wartość zmiennej.

 

Zmienna(String[] tabTyp, Object wart) – konstruktor.

Zmienna(String strTyp, Object[] skladniki, Vector tabZmiennych) – konstruktor tylko dla wyrażeń matematycznych.

 

static int getNrZmiennej(Object odwolanie)

Integer getInteger()

 

private Object wykonajDzialanie(String operator,

                                Object arg1, Object arg2) – metoda ta wykonuje działanie arytmetyczne na argumentach „arg1” i „arg2”, po czym zwraca wynik lub kod błędu.

 

Object[] getWartosc(Object argInstrukcji, Vector tabZmiennych) – służy do odczytania wartości zmiennej. Odczyt zależy od „argInstrukcji”, która jest swego rodzaju „odwołaniem” do zmiennej, mówiącym jakiego rodzaju wartość ma zostać zwrócona (np. czy wskaźnik, czy wartość wskazywana). Metoda potrafi obliczyć także wartość wyrażenia matematycznego i zwrócić tę wartość jako wynik.  W przypadku niepomyślnego wykonania zwraca odpowiedni kod błędu.

int setWartosc(Object odwolanie, Object value, Vector tabZmiennych) – ustawia wartość zmiennej na „value”. Zwraca ewentualny kod błędu.

 

void setInteger(int value)

 

void newWskaznik() – tworzy nowy wskaźnik.

 

void disposeWskaznik() – usuwa wskaźnik.

 

void setNil() – ustawia wskaźnik na Nil.

 

int getTyp()

boolean czyInteger()

boolean czyReal()

boolean czyTypPodstawowy()

boolean czyWskaznik()

boolean czyWskaznikDoInteger()

boolean czyWskaznikDoReal()

boolean czyWskaznikDoTypuPodstawowego()

boolean czyTablica()

boolean czyTablicaInteger()

boolean czyTablicaReal()

boolean czyWskaznikDoTablicy()

boolean czyWskaznikDoTablicyInteger()

boolean czyWskaznikDoTablicyReal()

boolean czyWyrazenieMat()

boolean czyWyrazenieMatInteger()

 

int getTypKoncowy() – każda zmienna niezależnie od jej typu, ostatecznie przechowuje typ podstawowy (np. wskaźnik do integer). Metoda zwraca numer typu składowego, którym jest ostatecznie integer, real lub string.

 

boolean czyKoncowyInteger()

boolean czyKoncowyReal()

 

}

 

 

Klasa „Instrukcja” stanowi szkielet dla instrukcji umieszczonych  w liście instrukcji. Pozwala na usystematyzowanie informacji niezbędnych do wykonania instrukcji.

 

class Instrukcja {

 

private int nrInstrukcji; - numer instrukcji.

private Object[] argumenty; - argumenty instrukcji.

private int nrLinii; - numer linii z której pochodzi instrukcja.

 

 

Instrukcja(int nrInstrukcji, Object[] argumenty, int nrLinii) – konstruktor instrukcji.

 

int getNrInstrukcji()

Object[] getArgumenty()

int getNrLinii()

 

int przypisz(Vector tabZmiennych) – metoda służąca do wykonania instrukcji przypisania.

 

int write(Vector tabZmiennych, String naKoniecLinii) – metoda służąca do wykonania instrukcji write i writeln.

 

int read(String zKlawiatury, Vector tabZmiennych) – metoda służąca do wykonania instrukcji read i readln.

 

Object aktywujPetleFor(int pc, Vector tabZmiennych) – służy do aktywacji pętli, tzn. tworzy obiekt – tablicę – zawierającą wszelkie niezbędne informacje potrzebne przy wykonywaniu pętli. Obiekt ten umieszczany jest później na stosie pętli.

 

}

 

 

Klasa „Interpreter” zawiera metodę główną służącą do uruchomienia Interpretera. W metodzie tej zaimplementowana jest pętla, w której wykonuje się program.

 

class Interpreter {

 

 

static void procBLAD(int nrLinii, AnalizaPliku ap, int nrBladu) – metoda ta zawiera komunikaty błędów. Służy do wyświetlania wszystkich informacji związanych z błędem tj. numeru linii w której wystąpił błąd, opisu błędu oraz tekstu danej linii z błędem.

 

static int getNumerZmiennej(String nazwaZmiennej, String[][] tabZ) – metoda zwraca numer zmiennej w tablicy zmiennych na podstawie jej nazwy.

 

static int getRodzajArgumentu(String argument) – służy do określenia rodzaju argumentu instrukcji. Zwraca numer, gdzie:

0 - nil

1 – liczba naturalna

2 – liczba zmiennoprzecinkowa

3 - tekst

4 – nazwa zmiennej

5 – zmienna wskazywana

6 – zmienna tablicowa

7 – zmienna tablicowa wskazywana

8 – wyrażenie matematyczne

Metoda stosowana w metodzie „konwertujArgument(...)”.

 

 

static int getOrAddNumerZmiennejStalej(Object wartoscStalej,

                           Vector stale, Vector tabZmiennych) – metoda ta, służy do przeszukiwania tablicy stałych w celu optymalizacji ilości odwołań do stałych reprezentujących taką samą wartość. Dopisuje nowe wartości do tablicy stałych i listy zmiennych.

 

static Object konwertujArgument(String arg, String dozwolone,

              int nrLinii, AnalizaPliku ap, Vector tabZmiennych,

              String[][] tabZ, Vector stale) – bardzo ważna metoda. Przeprowadza wstępną analizę poprawności zastosowanych argumentów w instrukcjach oraz wiąże konkretne zmienne z argumentami instrukcji.

 

 

static void budujTabZmiennychiTabInstrukcji(AnalizaPliku ap,

                       Vector tabZmiennych, Vector tabInstrukcji) – podstawowa metoda służąca do budowy „właściwych” list: zmiennych i instrukcji. Korzysta z metod opisanych powyżej. Przeprowadza analizę zgodności typów.

 

public static void main(String[] args) – metoda główna programu.

 

}