Untitled
unknown
plain_text
2 years ago
4.4 kB
8
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...