Untitled
unknown
plain_text
3 years ago
4.4 kB
11
Indexable
(* Compiling code that saves the value of an expression e into register r.
The basic solution can ignore the case e = App (f, es) except for
f = "plus", f = "minus", f = "times", and f = "divide".
The basic function calls solution can ignore nested and recursive calls.
*)
let rec compile_exp env (r : register) (e : exp) : code = match e with
| Id s -> [Move (r, Env.find s env)]
| Numb n -> [Li (r, n)]
| App (f, es) ->
(match f, es with
| "plus", e1::e2::[] ->
compile_exp env t8 e1
@ push t8
@ compile_exp env t9 e2
@ pop t8
@ [Add (r, t8, t9)]
| "minus", e1::e2::[] ->
compile_exp env t8 e1
@ push t8
@ compile_exp env t9 e2
@ pop t8
@ [Sub (r, t8, t9)]
| "times", e1::e2::[] ->
compile_exp env t8 e1
@ push t8
@ compile_exp env t9 e2
@ pop t8
@ [Mul (r, t8, t9)]
| "divide", e1::e2::[] ->
compile_exp env t8 e1
@ push t8
@ compile_exp env t9 e2
@ pop t8
@ [Div (t8, t9); Mflo r]
| _, es -> raise (E "Not implemented")
)
(* Generate code that saves the values of a list of expressions into a list of registers.
This function will probably only be called if you implement function calls. *)
and compile_exps env (rs : register list) (es : exp list) : code = match rs, es with
| [], [] -> []
| r::rs', e::es' ->
compile_exp env r e
@ compile_exps env rs' es'
| _, _ -> raise(E "Not implemented")
let compile_branch o r1 r2 label = match o with
| Less -> Bge (r1, r2, label)
| LessEq -> Bgt (r1, r2, label)
| Eq -> Bne (r1, r2, label)
| NEq -> Beq (r1, r2, label)
let compile_cond env o e1 e2 label = compile_exp env t8 e1
@ push t8
@ compile_exp env t9 e2
@ pop t8
@ [compile_branch o t8 t9 label]
(* Generate code for a single command. *)
let rec compile_cmd env (c : statement) : code = match c with
| Assign (s,e) -> compile_exp env (Env.find s env) e
| Write (s) -> [Li (v0, 1)]
@ push a0
@ compile_exp env a0 s
@ [SysCall]
@ pop a0
| Read (s) -> let s_register = Env.find s env in
[Li (v0, 4)] @ push a0
@ [La (a0, "sinp"); SysCall; Li (v0, 5); SysCall; Move (s_register, v0)] @ pop a0
| If (c, cs) -> (let label = "IFEND" ^ string_of_int (next_val ()) in
match c with
| C (o, e1, e2) -> compile_cond env o e1 e2 label
@ compile_cmds env cs
@ [Label label])
| Ite (c, cs1, cs2) -> (let counter = string_of_int (next_val ()) in
let label_end = "IFEND" ^ counter in
let label_false = "IFFALSE" ^ counter in
match c with
| C (o, e1, e2) -> compile_cond env o e1 e2 label_false
@ compile_cmds env cs1
@ [J label_end]
@ [Label label_false]
@ compile_cmds env cs2
@ [Label label_end])
| While (c, cs) ->
(let counter = string_of_int (next_val ()) in
let label_loop = "WLOOP" ^ counter in
let label_end = "WEND" ^ counter in
match c with
| C (o, e1, e2) -> [Label label_loop]
@ compile_cond env o e1 e2 label_end
@ compile_cmds env cs
@ [J label_loop]
@ [Label label_end])
(* Generate code for a list of commands. *)
and compile_cmds env (cs : statement list) : code = match cs with
| [] -> []
| c:: cs' -> compile_cmd env c
@ compile_cmds env cs'Editor is loading...