digits -> letters
The abstract syntax of the language is specified by the following grammar:
Com ::= Ide := NExp assignment | Com ; Com concatenation | if BExp then Com else Com conditional | while BExp do Com iteration | begin Ide in Com end block with variable declaration | begin Ide alias Ide in Com end block with alias declarationThe intended meaning of a command like
begin x in c endis that a new variable x is introduced, and it is local to the block. The intended meaning of a command like
begin x alias y in c endis that a new name x is introduced, and it is associated to the same location of the variable y. In other words, in c we can access the same variable by two names: x and y.
NExp represents numerical expressions:
NExp ::= Num | Ide | NExp NOp NExp NOp ::= + | * | - | /BExp represents boolean expressions:
BExp ::= true | false | NExp COp NExp | not BExp | BExp BOp BExp COP ::= < | = BOP ::= and | orNum generates the natural numbers, that can be represented as sequences of digits starting with a digit different from 0:
Num ::= 0 | Non_Zero_Digit Seq_Digit Non_Zero_Digit ::= 1 | 2 | 3 | ... | 9 Digit ::= 0 | Non_Zero_Digit Seq_Digit ::= lambda | Digit Seq_DigitIde generates the identifiers, which can be choosen to simply be sequences of letters:
Ide ::= Letter | Letter Ide Letter ::= a | b | c | ... | zNote that the grammar is ambiguous, but we will not worry about that because we assume that it represents the abstract syntax.
We need trees with a different number of subtrees, up to three, depending on the command. For the assignment we need only one subtree; for the concatenation we need two subtrees, for the conditional we need three subtrees, etc. Hence we will declare a structure of the following kind:
class tree{ node* root; tree* first; tree* second; tree* third; public: tree* subtree(int n){ switch (n) of { case 1: return first; case 2: return second; case 3: return third; } } ... }The class node will be analogous to the homonimous class seen in the notes about the evaluation of expressions.
class environment{ string ide; location loc; environment* next; ... }We can assume that locations are numbers representing memory addreses.
class environment{ location loc; int value; state* next; ... }
Note: the program is written in C++like, meaning that we use features that we find convenient, even if they are not allowed in real C++ programs (for instance, the type string in the switch statement). Translating the program to a real C++ program should not be difficult.
int eval(tree* t, environment* r){ node* n = t->get_root(); string ty = n->get_type(); switch (ty) of { case "num": return n->get_value(); case "ide": return r->lookup(n->get_ide()); case "op" : int k1 = eval(t->get_left(), r); int k2 = eval(t->get_right(), r); switch (n->get_op()) of { case "+": return k1 + k2; case "*": return k1 * k2; case "-": return k1 - k2; case "/": return k1 / k2; } case "dec": string x = n->get_ide(); int k = t->get_left()->get_root()->get_value(); environment r1 = r->add(x,k); return eval(t->get_right(), r1); } }