Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
4.4 kB
3
Indexable
Never
(* 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'