This lab is a continuation of Lab 8, Lab 9, Lab 10, and Lab 11. Our SPL interpreter up to this point is completely untyped, meaning that the interpreter itself has no clue what types the objects it manipulates have. Thus. it'll happily do things like this:write 5 < 8; 1 write 4/true; 4 if (5) { write 555; } else { write 444; } 555 new f := 8; write f(3); Segmentation faultThat last one, in particular, is a bad thing. We need to add type checking and type-aware behavior to our interpreter! We'll add a dynamic type system so that instead of the above garbage, we get this kind of thing:write 5 < 8; true if (5) { write 555; } else { write 444; } Non-bool value in a bool context! new f := 8; write f(3); Error! Applying non-function object! undef
class Closure; // forward declaration
// Structure for representing SPL objects by a type/value pair
class Obj
{
public:
int otype; union { int ival; bool bval; Closure *fval; };
};
// Object "otype" codes: "_oundef" means undefined - it comes in handy
const int _oundef = 0, _oint = 1, _obool = 2, _ofun = 3;
// Handy functions for creating an Obj from a value
Obj mkobj(int k) { Obj o; o.otype = _oint; o.ival = k; return o; }
Obj mkobj(bool b) { Obj o; o.otype = _obool; o.bval = b; return o; }
Obj mkobj(Closure* p) { Obj o; o.otype = _ofun; o.fval = p; return o; }
Hopefully you remember our discussion of union
types in C/C++ ... if not, flag me down in lab. You need to
add the above definitions to your code, change frames to be
name-Obj maps instead of name-int maps, and change eval to return
an Obj instead of an int. Make the above changes, comment out
the entire body of eval, and add to
the top of eval a line to create an
_oundef Obj, and then a line to
return that Obj. This version of your program
ought to actually compile!
_num,
_bool,
_lambda, and
_write to work, and leave the rest commented out.
You ought to be able to do something like this:
write 5;
5
write true;
true
write lambda x { res := 6; };
function:0x8072c78
Notice how write reacts correctly to the type of the object
you send it. Of course you won't be able to call functions or
do arithmetic or any of that.
Obj with type _oundef.
_new,
_asn, and
_id to work. You ought to be able to do
something like this:
new x := false;
write x;
false
x := 0;
write x;
0
x := lambda x { res := 6; };
write x;
function:0x8072cd8
_binop and _unop
working. Remember:
+,-,*,/,<, >, <=, >= should only work
on integer objects, and, or and
! should only work on boolean objects. Finally,
= and != should work on any type of
object, but the two operands had better be of the same type!. If you get this right, you should be able to do
something like this:
new x := 6;
write x > 2 and x < 10;
true
write x*5 + (x != 0);
Type mismatch in +!
undef
write (x = 6) != false;
true
write x = lambda x { res := x*x; };
Type mismatch in =!
new f := lambda x { res := x*x; };
write f = f;
true
write !false;
true;
write 5 = true;
type mismatch for eq!
_if,
_while, and
_funcall.
Now you should be able to do fun things like this:
new f := lambda x { 3+4; }; # Since res never gets set, this returns an Obj of type _oundef
new err := f(0);
write err;
undef
new g := lambda x # g(x) returns the floor of sqrt(x)
{
if (x >= 0)
{
res := 0;
while((res+1)*(res+1) <= x) { res := res + 1; }
}
};
write g(9);
3
write g(67);
8
write g(-4);
undef
lab12. Make sure your code contains your names.
Submit via the usual submit script before the deadline.