void exec();
method for all statements should end with
getNext()->exec();which tells the next statement in the list to exec() itself.' Warning! you will forget to do this, and you will be confused as to why only part of your SPL program executes!
$ ./spl
spl> { new x := 5; write x; { x := 6; new y := x*x; write y; } write x; }
5
36
6
if and ifelse.
To understand how the AST is constructed for these two ifs, you
should look at spl.ypp and see what the parser builds in those two
cases. Add ifs to the interpreter so that code like the following
works:
$ ./spl
spl> { new x := read; new y := 2020; if x != 0 { y := y / x; } write y; }
read> 17
118
$ ./spl
spl> { new x := read; new y := 2020; if x != 0 { y := y / x; } write y; }
read> 0
2020
$ ./spl
spl> { new x := read; new y := 2020; ifelse x != 0 { y := y / x; } { y := y / 21; } write y; }
read> 0
96
$ ./spl
spl> { new x := read; new i := 1; while i <= x { if i*(x/i) = x { write i; } i := i + 1; } }
read> 42
1
2
3
6
7
14
21
42
$ ./spl spl> new x := 0; spl> write x = 0 or 25/x > 2; true spl> write 25/x > 2 or x = 0; ERROR: Divide by zeroBe sure to test both AND and OR thoroughly!
ret that you
assign to in order to specify the return value. As soon as you
have a function calling a function you have problems because of
this. So ...
we're going to implement a simplified form of dynamic scoping!
This means that you must do the following:
stack<int> S; S.push(42); S.push(2020); S.push(1992); S.top() = 1920; // top returns top element by reference, so you can modify it, but doesn't remove it cout << S.top() << endl; // prints 1920 S.pop(); // pop removes the top element, but is a void function cout << S.top() << endl; // prints 2020This means you will need to change Id's eval(), NewStmt's exec() and Asn's exec() to use this new kind of symbol table.
Lambda* (as opposed to a wrapper around an
int or a bool). So eval()-ing a Lambda in the AST should
return a Value containing a pointer to that very same
Lambda.
Note that in C++ the keyword this inside a
member function is a pointer to the object the member
function was called on (just like Java). We can't test much
at this point, but at least the following should work:
$ ./spl
spl> write lambda x { ret := x*x; };
lambda expression
{ new f := lambda x { ret := x*x; }; write f@(5+1); }
Think about what's involved in
the function call f@(5+1).
$ ./spl
spl> { new f := lambda x { ret := x*x; }; write f@(5+1); }
36
$ ./spl
spl> { new f := lambda x { ret := x*x; }; new g := lambda y { ret := f @ (2*y); }; write g @ 5; }
100
$ ./spl
spl> new f := lambda x { ifelse x = 0 { ret := 1; } { ret := x * f@(x-1); } }; # Recursion!
spl> write f@6;
720
spl> write f@12;
479001600
Try defining an pow2 function such that pow2@5 computes 2^5.
Note: We only have dynamic scope implemented for parameters and the sepecial "ret" value in functions. This means that all other variables are operating under single global scope rules.
As an extra piece that could be helpful in your future, try
adding debugging statements.
Debugging statements are little snippets of text that print to the
screen when a certain part of your code is reached. Since SPL doesn't
have any support for strings, we have to add a language feature to support
this. Our approach will be that anything enclosed in double-quotes is
a debugging statement, and there will be no escaping double
quotes with backslash.
(note: "[^"\n]*" is a regular expression
that matches strings.)
This will require a new AST Stmt node
class
called Debug, which you will have to create.
Some specifics on the debug statements
write 5; "hello!" write 6; would be OK, but not
write "the interruptor!" 5;.
if false { "toodaloo" }should not result in any output.
Here is an example run:
$ ./spl
spl> new s := 0;
spl> new i := 5;
spl> while i > 0 { "in loop!" s := s + i; i := i - 1; }
in loop!
in loop!
in loop!
in loop!
in loop!
spl> write s;
15
Note: please write your output using "resout" or
"cout", but not "errout" or "cerr".
submit-external -c=SI413 -p=lab09 ast.cpp ast.hpp colorout.hpp Makefile readlineistream.hpp spl.lpp spl.ypp value.cpp value.hpp