add code interpreter

This commit is contained in:
tali 2023-11-29 16:50:26 -05:00
parent ee5ca040c7
commit fb8a2cdcab
4 changed files with 104 additions and 1 deletions

View File

@ -13,5 +13,11 @@ let () =
in in
let prog = Spice.Code.make_program ep in let prog = Spice.Code.make_program ep in
Fmt.pr "%a" Spice.Code.pp_program prog let ret = Spice.run prog in
Fmt.pr
"{\"program\":%a,\"output\":%a}"
Spice.Code.pp_program
prog
Spice.Value.pp
ret
with Spice.Error msg -> Logs.err (fun m -> m "%s" msg) with Spice.Error msg -> Logs.err (fun m -> m "%s" msg)

View File

@ -40,6 +40,36 @@ type program = { entrypoint : basic_block }
let make_program entrypoint = { entrypoint } let make_program entrypoint = { entrypoint }
let frame_size prog =
let visited = ref [] in
let work_list = ref [ prog.entrypoint ] in
let enqueue bb = if not (List.memq bb !visited) then work_list := bb :: !work_list in
let reg acc i = max acc (i + 1) in
let op acc = function
| Reg i -> reg acc i
| _ -> acc
in
let ins acc = function
| MOV (l, r) | ADD (l, r) | SUB (l, r) | MUL (l, r) -> op (reg acc l) r
| BRT (v, b1, b2) ->
enqueue b1;
enqueue b2;
op acc v
| JMP b ->
enqueue b;
acc
| RET -> acc
in
let rec loop acc =
match !work_list with
| [] -> acc
| bb :: rest ->
visited := bb :: !visited;
work_list := rest;
List.fold_left ins acc (instructions bb) |> loop
in
loop 1
(* pretty printing *) (* pretty printing *)
let pp_reg ppf r = Fmt.pf ppf "$%d" r let pp_reg ppf r = Fmt.pf ppf "$%d" r

63
lib/runtime/interp.ml Normal file
View File

@ -0,0 +1,63 @@
exception Runtime_error of string
module Op = struct
let add v1 v2 =
match v1, v2 with
| Value.Int x, Value.Int y -> Value.Int (Int64.add x y)
| _, _ -> raise (Runtime_error "cannot add non integer values")
let sub v1 v2 =
match v1, v2 with
| Value.Int x, Value.Int y -> Value.Int (Int64.sub x y)
| _, _ -> raise (Runtime_error "cannot sub non integer values")
let mul v1 v2 =
match v1, v2 with
| Value.Int x, Value.Int y -> Value.Int (Int64.mul x y)
| _, _ -> raise (Runtime_error "cannot mul non integer values")
let is_true = function
| Value.True -> true
| _ -> false
end
type frame = {
regs : Value.t array;
mutable pc : Code.ins list;
}
let make_frame prog =
{
regs = Array.make (Code.frame_size prog) Value.Nil;
pc = Code.instructions Code.(prog.entrypoint);
}
let return_value fr = fr.regs.(0)
let eval fr = function
| Code.Cst_nil -> Value.Nil
| Code.Cst_true -> Value.Nil
| Code.Cst_false -> Value.Nil
| Code.Cst_int n -> Value.Int n
| Code.Reg i -> fr.regs.(i)
let exec fr = function
| Code.MOV (l, r) -> fr.regs.(l) <- eval fr r
| Code.ADD (l, r) -> fr.regs.(l) <- Op.add fr.regs.(l) (eval fr r)
| Code.SUB (l, r) -> fr.regs.(l) <- Op.add fr.regs.(l) (eval fr r)
| Code.MUL (l, r) -> fr.regs.(l) <- Op.mul fr.regs.(l) (eval fr r)
| Code.RET -> fr.pc <- []
| Code.JMP l -> fr.pc <- Code.instructions l
| Code.BRT (v, l1, l2) ->
if Value.equal (eval fr v) True then fr.pc <- Code.instructions l1
else fr.pc <- Code.instructions l2
let rec run fr =
match fr.pc with
| [] -> return_value fr
| is :: rest ->
fr.pc <- rest;
exec fr is;
run fr
let run_program pr = run (make_frame pr)

View File

@ -16,3 +16,7 @@ let parse input =
let compile syn = let compile syn =
try Spice_lower.Normalize.to_anf syn try Spice_lower.Normalize.to_anf syn
with Failure msg -> failf "compilation error: %s" msg with Failure msg -> failf "compilation error: %s" msg
let run prog =
try Spice_runtime.Interp.run_program prog
with Spice_runtime.Interp.Runtime_error msg -> failf "runtime error: %s" msg