open Printf
open MIPSOps
open Primitive
open InterpretUPP
open InterpretERTL
open InterpretLTL
open LIN
open Integer
exception RuntimeError = InterpretPP.RuntimeError
type lin_label =
| LL of Label.t
| LI of instruction list
type lin_procedure =
instruction list Label.Map.t * int32
type address =
(lin_procedure, lin_label) InterpretERTL.address
type value =
address InterpretUPP.value
let interpret p =
let henv : value henv = MIPS.RegisterMap.lift allocate MIPS.registers in
hwrite henv MIPS.gp (VArray (Array.make (p.globals / MIPS.word) (VInt 0l), 0l));
let rec interpret_call (stack : value stack) callee (next : address) =
match callee with
| CPrimitiveFunction p ->
interpret_primitive henv p;
interpret_jump stack next
| CUserFunction f ->
let proc =
try
StringMap.find f p.defs
with Not_found ->
assert false
in
let rec build = function
| ILabel l :: instructions ->
Label.Map.add l instructions (build instructions)
| _ :: instructions ->
build instructions
| [] ->
Label.Map.empty
in
hwrite henv MIPS.ra (VCode next);
interpret_instructions stack (build proc.code, proc.locals) proc.code
and interpret_instructions stack proc instructions =
match instructions with
| [] ->
fprintf stderr "Runtime error -- fell off the instruction stream.\n";
raise RuntimeError
| i :: instructions ->
interpret_instruction stack proc i instructions
and interpret_jump stack address =
match address with
| AddrInit ->
()
| AddrCode (proc, LI instructions) ->
interpret_instructions stack proc instructions
| AddrCode (proc, LL l) ->
let instructions =
try
let graph, _ = proc in
Label.Map.find l graph
with Not_found ->
fprintf stderr
"Runtime error -- no instruction is associated with the current label (%s).\n" (Label.print l);
raise RuntimeError
in
interpret_instructions stack proc instructions
and interpret_instruction (stack : value stack) (proc : lin_procedure) i instructions =
match i with
| INewFrame ->
let _, locals = proc in
interpret_instructions (newframe stack locals) proc instructions
| IDeleteFrame ->
interpret_instructions (deleteframe stack) proc instructions
| IGetStack (destr, slot) ->
hwrite henv destr (sread stack slot);
interpret_instructions stack proc instructions
| ISetStack (slot, sourcer) ->
swrite stack slot (hread henv sourcer);
interpret_instructions stack proc instructions
| IConst (destr, i) ->
hwrite henv destr (VInt i);
interpret_instructions stack proc instructions
| IUnOp (op, destr, sourcer) ->
hwrite henv destr (unop op (hread henv sourcer));
interpret_instructions stack proc instructions
| IBinOp (op, destr, sourcer1, sourcer2) ->
hwrite henv destr (binop op (hread henv sourcer1) (hread henv sourcer2));
interpret_instructions stack proc instructions
| ICall (callee) ->
interpret_call stack callee (AddrCode (proc, LI instructions))
| ILoad (destr, addressr, offset) ->
hwrite henv destr (load (hread henv addressr) offset);
interpret_instructions stack proc instructions
| IStore (addressr, offset, valuer) ->
store (hread henv addressr) offset (hread henv valuer);
interpret_instructions stack proc instructions
| IGoto l ->
interpret_jump stack (AddrCode (proc, LL l))
| IUnBranch (cond, sourcer, l) ->
if InterpretMIPS.uncon cond (asInt (hread henv sourcer)) then
interpret_jump stack (AddrCode (proc, LL l))
else
interpret_instructions stack proc instructions
| IBinBranch (cond, sourcer1, sourcer2, l) ->
if InterpretMIPS.bincon cond (asInt (hread henv sourcer1)) (asInt (hread henv sourcer2)) then
interpret_jump stack (AddrCode (proc, LL l))
else
interpret_instructions stack proc instructions
| IReturn ->
interpret_jump stack (asAddress (hread henv MIPS.ra))
| ITailCall callee ->
interpret_call stack callee (asAddress (hread henv MIPS.ra))
| ILabel l ->
interpret_instructions stack proc instructions
in
interpret_call empty_stack (CUserFunction "_main") AddrInit