refactor 'stack pointer' manip to be a parameter instead of a ref
This commit is contained in:
parent
fd3b356699
commit
32b3eda926
|
@ -10,13 +10,12 @@ type binding = {
|
||||||
|
|
||||||
let compile modl =
|
let compile modl =
|
||||||
let ep = Code.make_basic_block [] in
|
let ep = Code.make_basic_block [] in
|
||||||
let sp = ref 0 in
|
|
||||||
let bb = ref ep in
|
let bb = ref ep in
|
||||||
|
|
||||||
let emit is = Code.add_ins !bb is in
|
let emit is = Code.add_ins !bb is in
|
||||||
let emit_mov lhs rhs = if rhs <> Code.Reg lhs then emit (MOV (lhs, rhs)) in
|
let emit_mov lhs rhs = if rhs <> Code.Reg lhs then emit (MOV (lhs, rhs)) in
|
||||||
|
|
||||||
let rec compile_exp env = function
|
let rec compile_exp env sp = function
|
||||||
| Ast.Literal Nil -> Code.Cst_nil
|
| Ast.Literal Nil -> Code.Cst_nil
|
||||||
| Ast.Literal True -> Code.Cst_true
|
| Ast.Literal True -> Code.Cst_true
|
||||||
| Ast.Literal False -> Code.Cst_false
|
| Ast.Literal False -> Code.Cst_false
|
||||||
|
@ -25,57 +24,50 @@ let compile modl =
|
||||||
match Env.find name env with
|
match Env.find name env with
|
||||||
| exception Not_found -> Fmt.failwith "unbound: %S" name
|
| exception Not_found -> Fmt.failwith "unbound: %S" name
|
||||||
| { self; slot } ->
|
| { self; slot } ->
|
||||||
let ret = !sp in
|
emit_mov sp (Code.cst_of_int slot);
|
||||||
sp := ret + 1;
|
emit (GET (self, sp));
|
||||||
emit_mov ret (Code.cst_of_int slot);
|
Reg sp)
|
||||||
emit (GET (self, ret));
|
|
||||||
Reg ret)
|
|
||||||
| Ast.Binop (op, lhs, rhs) ->
|
| Ast.Binop (op, lhs, rhs) ->
|
||||||
let ret = !sp in
|
let lhs = compile_exp env sp lhs in
|
||||||
let lhs = compile_exp env lhs in
|
emit_mov sp lhs;
|
||||||
emit_mov ret lhs;
|
let rhs = compile_exp env (sp + 1) rhs in
|
||||||
sp := ret + 1;
|
|
||||||
let rhs = compile_exp env rhs in
|
|
||||||
(match op with
|
(match op with
|
||||||
| Ast.Add -> emit (ADD (ret, rhs))
|
| Ast.Add -> emit (ADD (sp, rhs))
|
||||||
| Ast.Sub -> emit (SUB (ret, rhs))
|
| Ast.Sub -> emit (SUB (sp, rhs))
|
||||||
| Ast.Mul -> emit (MUL (ret, rhs))
|
| Ast.Mul -> emit (MUL (sp, rhs))
|
||||||
| Ast.Div | Ast.Mod -> failwith "Bcc.compile_exp: TODO: div/mod"
|
| Ast.Div | Ast.Mod -> failwith "Bcc.compile_exp: TODO: div/mod"
|
||||||
| Ast.Eql -> emit (EQL (ret, rhs))
|
| Ast.Eql -> emit (EQL (sp, rhs))
|
||||||
| Ast.Not_eql ->
|
| Ast.Not_eql ->
|
||||||
emit (EQL (ret, rhs));
|
emit (EQL (sp, rhs));
|
||||||
emit (NOT ret)
|
emit (NOT sp)
|
||||||
| Ast.Lst -> emit (LST (ret, rhs))
|
| Ast.Lst -> emit (LST (sp, rhs))
|
||||||
| Ast.Lst_eql ->
|
| Ast.Lst_eql ->
|
||||||
emit (LST (ret, rhs));
|
emit (LST (sp, rhs));
|
||||||
emit (NOT ret)
|
emit (NOT sp)
|
||||||
| Ast.Grt -> emit (GRT (ret, rhs))
|
| Ast.Grt -> emit (GRT (sp, rhs))
|
||||||
| Ast.Grt_eql ->
|
| Ast.Grt_eql ->
|
||||||
emit (LST (ret, rhs));
|
emit (LST (sp, rhs));
|
||||||
emit (NOT ret));
|
emit (NOT sp));
|
||||||
Reg ret
|
Reg sp
|
||||||
| Ast.If (cnd, e1, e2) ->
|
| Ast.If (cnd, e1, e2) ->
|
||||||
let l1 = Code.make_basic_block [] in
|
let l1 = Code.make_basic_block [] in
|
||||||
let l2 = Code.make_basic_block [] in
|
let l2 = Code.make_basic_block [] in
|
||||||
let jp = Code.make_basic_block [] in
|
let jp = Code.make_basic_block [] in
|
||||||
let tmp = !sp in
|
emit (CBR (compile_exp env sp cnd, l1, l2));
|
||||||
emit (CBR (compile_exp env cnd, l1, l2));
|
|
||||||
sp := tmp;
|
|
||||||
bb := l1;
|
bb := l1;
|
||||||
emit_mov tmp (compile_exp env e1);
|
emit_mov sp (compile_exp env sp e1);
|
||||||
emit (JMP jp);
|
emit (JMP jp);
|
||||||
sp := tmp;
|
|
||||||
bb := l2;
|
bb := l2;
|
||||||
emit_mov tmp (compile_exp env e2);
|
emit_mov sp (compile_exp env sp e2);
|
||||||
emit (JMP jp);
|
emit (JMP jp);
|
||||||
sp := tmp + 1;
|
|
||||||
bb := jp;
|
bb := jp;
|
||||||
Reg tmp
|
Reg sp
|
||||||
| Ast.Obj body -> compile_obj env body
|
| Ast.Obj body -> compile_obj env sp body
|
||||||
| Ast.Scope body -> compile_scope env body
|
| Ast.Scope body -> compile_scope env sp body
|
||||||
| _ -> failwith "Bcc.compile_exp: TODO"
|
| _ -> failwith "Bcc.compile_exp: TODO"
|
||||||
and compile_block env items =
|
and compile_block env sp items =
|
||||||
let self = !sp in
|
let self = sp in
|
||||||
|
let sp = sp + 1 in
|
||||||
|
|
||||||
(* construct new env and vtable *)
|
(* construct new env and vtable *)
|
||||||
let elems = Hashtbl.create (List.length items * 2) in
|
let elems = Hashtbl.create (List.length items * 2) in
|
||||||
|
@ -97,40 +89,36 @@ let compile modl =
|
||||||
emit (CON (self, vtable));
|
emit (CON (self, vtable));
|
||||||
let emit_set name rhs =
|
let emit_set name rhs =
|
||||||
let slot = (Env.find name env).slot in
|
let slot = (Env.find name env).slot in
|
||||||
emit_mov (self + 2) rhs;
|
emit_mov sp (Code.cst_of_int slot);
|
||||||
emit_mov (self + 1) (Code.cst_of_int slot);
|
emit_mov (sp + 1) rhs;
|
||||||
emit (SET (self, self + 1))
|
emit (SET (self, sp))
|
||||||
in
|
in
|
||||||
let final_exp =
|
let final_exp =
|
||||||
List.fold_left
|
List.fold_left
|
||||||
(fun _ -> function
|
(fun _ -> function
|
||||||
| Ast.Item_fun (_, _, _) -> failwith "Bcc: unsupported: methods"
|
| Ast.Item_fun (_, _, _) -> failwith "Bcc: unsupported: methods"
|
||||||
| Ast.Item_exp e ->
|
| Ast.Item_exp exp -> Some (compile_exp env sp exp)
|
||||||
sp := self + 1;
|
|
||||||
Some (compile_exp env e)
|
|
||||||
| Ast.Item_obj (name, body) ->
|
| Ast.Item_obj (name, body) ->
|
||||||
sp := self + 2;
|
emit_set name (compile_obj env (sp + 1) body);
|
||||||
emit_set name (compile_obj env body);
|
|
||||||
None
|
None
|
||||||
| Ast.Item_val (name, rhs) ->
|
| Ast.Item_val (name, rhs) ->
|
||||||
sp := self + 2;
|
emit_set name (compile_exp env (sp + 1) rhs);
|
||||||
emit_set name (compile_exp env rhs);
|
|
||||||
None)
|
None)
|
||||||
None
|
None
|
||||||
items
|
items
|
||||||
in
|
in
|
||||||
self, final_exp
|
self, final_exp
|
||||||
and compile_obj env items =
|
and compile_obj env sp items =
|
||||||
let self, _ = compile_block env items in
|
let self, _ = compile_block env sp items in
|
||||||
sp := self + 1;
|
|
||||||
Code.Reg self
|
Code.Reg self
|
||||||
and compile_scope env items =
|
and compile_scope env sp items =
|
||||||
match compile_block env items with
|
let _, final_exp = compile_block env sp items in
|
||||||
| _, None -> failwith "block must end with an expression"
|
match final_exp with
|
||||||
| _, Some ret -> ret
|
| None -> failwith "block must end with an expression"
|
||||||
|
| Some ret -> ret
|
||||||
in
|
in
|
||||||
|
|
||||||
let env = Env.empty in
|
let env = Env.empty in
|
||||||
emit_mov 0 (compile_obj env modl.Ast.items);
|
emit_mov 0 (compile_obj env 0 modl.Ast.items);
|
||||||
emit RET;
|
emit RET;
|
||||||
Code.make_program ep
|
Code.make_program ep
|
||||||
|
|
Loading…
Reference in New Issue