Własny język programowania. Część 3: Reprezentacja i interpretacja języka programowania

13.07.2010 - Maciej Piróg
TrudnośćTrudność

Reprezentacja konstrukcji języków programowania

Teraz stworzymy nasz język programowania, a właściwie jego główną część, czyli ustalimy jakie instrukcje są potrzebne i jak je reprezentować wewnątrz interpretera. Póki co, w ogóle nie będziemy interesować się jego składnią, czyli tym, jak konstrukcje będą reprezentowane w postaci tekstowej (tym zajmiemy się w części czwartej).

Poszczególne instrukcje będą reprezentowane w postaci klas dziedziczących z nadrzędnej klasy Program:

1
2
3
class Program
{
};

Instrukcje proste

Ciekawostka: W języku C++ też jest instrukcja skip, choć jest zapisywana w dość dziwny sposób - jako sam średnik. Przykładowo, jeśli chcemy, by ciało pętli nic nie robiło, możemy napisać:
1
while (expr) ;
skip. Pierwsza instrukcja w naszym języku będzie banalna. Nie robi ona dokładnie nic -- jej wykonanie nie zmienia wartości zmiennych, ani nie wpływa na przebieg programu. Przyda się nam, gdyż instrukcja warunkowa będzie miała obowiązkową gałąź 'else'.

Klasa, która opisuje instrukcje skip na razie może być zdefiniowana jako:

1
2
3
class Skip : public Program
{
};

przypisanie. Przypisanie w naszym języku to instrukcja, która ma dwa argumenty - nazwę zmiennej do której przypisujemy i wyrażenie, którego wartość jest przypisywana (Expression to klasa, którą zajmowaliśmy się w 1. artykule cyklu):

1
2
3
4
5
6
7
8
class Assign : public Program
{
    string var;
    Expression* expr;
 
  public:
    Assign(string v, Expression* e) : var(v), expr(e) { }
};

read. Jest to instrukcja, która pobiera od użytkownika liczbę i zapisuje w zmiennej będącej argumentem:

1
2
3
4
5
6
7
class Read : public Program
{
    string var;
 
  public:
    Read(string v) : var(v) { }
};

write. Instrukcja siostrzana w stosunku do read. Jej zadanie to wypisywanie na ekran wartości zmiennej:

1
2
3
4
5
6
7
class Write : public Program
{
    string var;
 
  public:
    Write(string v) : var(v) { }
};

Instrukcje złożone

złożenie. Złożenie instrukcji będzie binarne, to znaczy będziemy mogli składać ze sobą tylko dwie instrukcje. Oczywiście taką złożoną instrukcję możemy złożyć z inną instrukcją, w ten sposób dostając "złożenie" trzech instrukcji. Trochę podobnie jest z dodawaniem: możemy zapisać "1 + 2 + 3 + 4", choć operator '+' jest binarny, a wyrażenie tak naprawdę oznacza ((1 + 2) + 3) + 4, tak samo blok {i1; i2; i3; i4;} można rozumieć jako blok {{{i1; i2}; i3}; i4}. Oczywiście w składni języka nie będzie tego widać (będzie podobnie jak w języku C++, ale o tym dowiemy się w 4. części cyklu). Złożenie można zdefiniować jako:

1
2
3
4
5
6
7
class Composition : public Program
{
    Program* left, * right;
 
  public:
    Composition(Program* l, Program* r) : left(l), right(r) { }
};

warunek. Warunek składa się z wyrażenia i dwóch instrukcji (jeśli wyrażenie będzie różne od zera, wykonujemy pierwszą instrukcję, jeśli wyrażenie będzie równe zero, wykonujemy drugą instrukcję).

1
2
3
4
5
6
7
8
9
class If : public Program
{
    Program* branch_then, * branch_else;
    Expression* condition;
 
  public:
    If(Expression* c, Program* t, Program* e)
      : condition(c), branch_then(t), branch_else(e) { }
};

pętla. Pętla składa się z wyrażenia i instrukcji będącej ciałem pętli. Ciało wykonujemy dopóki wartość wyrażenia jest różna od zera.

1
2
3
4
5
6
7
8
9
class While : public Program
{
    Program *body;
    Expression* condition;
 
  public:
    While(Expression* c, Program* b)
      : condition(c), body(b) { }
};

5
Twoja ocena: Brak Ocena: 5 (1 ocena)

Copyright © 2008-2010 Wrocławski Portal Informatyczny

design: rafalpolito.com