open Printf
open MIPSOps
open Primitive
open InterpretUPP
open RTL
open Integer
exception RuntimeError = InterpretPP.RuntimeError
let lookup (env : 'value ref Register.Map.t) r =
try
Register.Map.find r env
with Not_found ->
fprintf stderr "Runtime error -- reference to undefined pseudo-register (%s).\n" (Register.print r);
raise RuntimeError
let read env r =
!(lookup env r)
let write env r v =
(lookup env r) := v
type void
exception Transmit of void value option
let interpret p =
let genv = Array.make (p.globals / MIPS.word) (VInt 0l) in
let rec interpret_call env callee actuals : 'address value option =
match callee with
| CPrimitiveFunction p ->
interpret_primitive p actuals
| CUserFunction f ->
let proc =
try
StringMap.find f p.defs
with Not_found ->
assert false
in
let env =
Register.Map.addm (Register.Map.lift allocate proc.locals) Register.Map.empty
in
List.iter2 (write env) proc.formals actuals;
try
interpret_graph env proc.graph proc.exit proc.entry;
Option.map (read env) proc.result
with Transmit result ->
match proc.result, result with
| None, _ ->
None
| Some _, None ->
assert false
| Some _, Some _ ->
result
and interpret_graph env graph exitl l =
try
let i = Label.Map.find l graph in
if Label.equal l exitl then begin
fprintf stderr "Runtime error -- an instruction is associated with the exit label (%s).\n" (Label.print l);
raise RuntimeError
end;
interpret_graph env graph exitl (interpret_instruction_at env l i)
with Not_found ->
if not (Label.equal l exitl) then begin
fprintf stderr "Runtime error -- no instruction is associated with the current label (%s).\n" (Label.print l);
raise RuntimeError
end
and interpret_instruction_at env l i =
try
interpret_instruction env i
with RuntimeError as e ->
fprintf stderr "Runtime error -- at label: %s\n" (Label.print l);
raise e
and interpret_instruction env (i : instruction) =
match i with
| IConst (destr, i, l) ->
write env destr (VInt i);
l
| IUnOp (op, destr, sourcer, l) ->
write env destr (unop op (read env sourcer));
l
| IBinOp (op, destr, sourcer1, sourcer2, l) ->
write env destr (
binop op (read env sourcer1) (read env sourcer2)
);
l
| ICall (destro, callee, rs, l) ->
begin match destro, interpret_call env callee (List.map (read env) rs) with
| Some destr, Some result ->
write env destr result
| None, None ->
()
| _ ->
assert false
end;
l
| ITailCall (callee, rs) ->
raise (Transmit (interpret_call env callee (List.map (read env) rs)))
| ILoad (destr, addressr, offset, l) ->
write env destr (load (read env addressr) offset);
l
| IStore (addressr, offset, valuer, l) ->
store (read env addressr) offset (read env valuer);
l
| IGetGlobal (destr, offset, l) ->
write env destr (gread genv offset);
l
| ISetGlobal (offset, sourcer, l) ->
gwrite genv offset (read env sourcer);
l
| IGoto l ->
l
| IUnBranch (cond, sourcer, l1, l2) ->
if InterpretMIPS.uncon cond (asInt (read env sourcer)) then l1 else l2
| IBinBranch (cond, sourcer1, sourcer2, l1, l2) ->
if InterpretMIPS.bincon cond (asInt (read env sourcer1)) (asInt (read env sourcer2)) then l1 else l2
in
let (_ : 'address value option) =
interpret_call Register.Map.empty (CUserFunction "_main") []
in
()