Exp ::= Num | Exp + Exp | ~ Exp | (Exp) Num ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9where Exp and Num are non-terminals and all the other symbols are terminal.
Exp ::= Num | Ide | Exp Op Exp | let Ide = Num in Exp end | (Exp) Op ::= + | * | - | / Num ::= ... // sequence of digits representing a natural number Ide ::= ... // sequence of lettersand the interpreter eval for such language
int eval(tree* t, environment* r){ node* n = t->get_root(); string ty = n->get_type(); switch (ty) { 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()) { 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(); r->add(x,k); int result = eval(t->get_right(), r); r->pop(); return result; } } }Assume that we want to modify the language by adding the possibility of declaring names associated to the result of generic expressions. For instance, we want to allow expressions like the following one
let x = 1 in let y = 2 in let x = x + y in x end end endThe expression in the declaration should be evaluated in the current environment at the moment in which the declaration is evaluated. Thus, for instance, the result of the above expressions should be 3.
void p(int <parameter-passing method> x){ int temp; temp = x; x = y + 1; y = temp + y + 2; }where y is a global variable of type integer. Say what is the final value of y after the following fragment of code:
y = 0; p(y);under each of the following assumptions:
Exp ::= Exp implies Expand with a non-strict semantics of the following form:
the result of e1 implies e2 is - true if e1 is false - true if e1 is true and e2 is true - false if e1 is true and e2 is false
x > 0 implies (x = 1 or x > 1 or 1/x > 1)
procedure p; var x,y: integer; (* variables x,y local to p *) procedure q(y: integer); (* procedure q local to p *) begin if x = y then r(y) else write(y) end; (* body of q *) procedure r(x: integer); (* procedure r local to p *) begin if x = y then write(y) else q(x+1) end; (* body of r *) begin (* begin body of p *) x := 1; (* assign 1 to x *) y := 2; (* assign 2 to y *) q(x) (* call to q with actual x *) end; (* end body of p *)Assume that at a certain point, the main program contains a call of the form
p(1);
int* x; void p(int y){ int z = 2; *x = y+z; } void main(){ x = new int; *x = 3; p(*x); cout << *x; delete x; ... }Discuss the allocation of memory during the execution of P(). For each variable, specify whether it is local, global, or dynamic, what is its lifetime, and where it is allocated (stack/heap/globals' space).