compiler.ml (4334B)
1 open Mips 2 open Ast.IR2 3 4 module Env = Map.Make(String) 5 6 type cinfo = { code: Mips.instr list 7 ; env: Mips.loc Env.t 8 ; fpo: int 9 ; counter: int 10 ; return: string } 11 12 let rec compile_expr e env = 13 match e with 14 (* | Value v -> compile_value v *) 15 | Data l -> [ La (V0, Lbl (l)) ] 16 | Bool b -> [ Li (V0, if b then 1 else 0) ] 17 | Nil -> [ Li (V0, 0) ] 18 | Int n -> [ Li (V0, n) ] 19 | Float f -> [ Lis (F0, f) ] 20 | Char c -> [ Li (V0, (int_of_char c)) ] 21 | Var v -> [ Lw (V0, Env.find v env) ] 22 | Call (f, args) -> 23 let ca = List.map (fun a -> 24 compile_expr a env 25 @ [ Addi (SP, SP, -4) 26 ; Sw (V0, Mem (SP, 0)) ]) 27 args in 28 List.flatten ca 29 @ [ Jal f 30 ; Addi (SP, SP, 4 * (List.length args)) ] 31 32 let rec compile_instr i info = 33 match i with 34 | Decl v -> 35 { info with 36 env = Env.add v (Mem (FP, -info.fpo)) info.env 37 ; fpo = info.fpo + 4 } 38 | Return e -> 39 { info with 40 code = info.code 41 @ compile_expr e info.env 42 @ [ B info.return ] } 43 | Expr e -> 44 { info with 45 code = info.code 46 @ compile_expr e info.env } 47 48 | Assign (lv, e) -> 49 { info with 50 code = (info.code 51 @ compile_expr e info.env 52 @ 53 match lv with 54 | Var v -> [ Sw (V0, Env.find v info.env) ]) 55 } 56 57 (* 58 TODO 59 | Assign (lv, e) -> { info with 60 code = info.code 61 @ compile_expr e info.env 62 @ (match lv with 63 | LVar v -> [ Sw (V0, Env.find v info.env) ] 64 | LAddr a -> [] 65 @ [ Addi (SP, SP, -4) 66 ; Sw (V0, Mem (SP, 0)) ] 67 @ compile_expr a info.env 68 @ [ Lw (T0, Mem (SP, 0)) 69 ; Addi (SP, SP, 4) 70 ; Sw (T0, Mem (V0, 0)) ]) } 71 *) 72 | Loop (c, t) -> 73 let uniq = string_of_int info.counter in 74 let ct = compile_block t { info with code = [] 75 ; counter = info.counter + 1 } in 76 { info with 77 code = info.code 78 @ [ Label ("startloop" ^ uniq) ] 79 @ compile_expr c info.env 80 @ [ Beqz (V0, "endloop" ^ uniq) ] 81 @ ct.code 82 @ [ B ("startloop" ^ uniq) ] 83 @ [ Label ("endloop" ^ uniq) ] 84 ; counter = ct.counter } 85 86 | Cond (c, t, e) -> 87 let uniq = string_of_int info.counter in 88 let ct = compile_block t { info with code = [] 89 ; counter = info.counter + 1 } in 90 let ce = compile_block e { info with code = [] 91 ; counter = ct.counter } in 92 { info with 93 code = info.code 94 @ compile_expr c info.env 95 @ [ Beqz (V0, "else" ^ uniq) ] 96 @ ct.code 97 @ [ B ("endif" ^ uniq) 98 ; Label ("else" ^ uniq) ] 99 @ ce.code 100 @ [ Label ("endif" ^ uniq) ] 101 ; counter = ce.counter } 102 103 and compile_block b info = 104 match b with 105 | [] -> info 106 | i :: r -> 107 compile_block r (compile_instr i info) 108 109 let compile_def (Func (name, args, b)) counter = 110 let cb = compile_block b 111 { code = [] 112 ; env = List.fold_left 113 (fun e (i, a) -> Env.add a (Mem (FP, 4 * i)) e) 114 Env.empty (List.mapi (fun i a -> i + 1, a) args) 115 ; fpo = 8 116 ; counter = counter + 1 117 ; return = "ret" ^ (string_of_int counter) } 118 in cb.counter, 119 [] 120 @ [ Label name 121 ; Addi (SP, SP, -cb.fpo) 122 ; Sw (RA, Mem (SP, cb.fpo - 4)) 123 ; Sw (FP, Mem (SP, cb.fpo - 8)) 124 ; Addi (FP, SP, cb.fpo - 4) ] 125 @ cb.code 126 @ [ Label cb.return 127 ; Addi (SP, SP, cb.fpo) 128 ; Lw (RA, Mem (FP, 0)) 129 ; Lw (FP, Mem (FP, -4)) 130 ; Jr (RA) ] 131 132 let rec compile_prog p counter = 133 match p with 134 | [] -> [] 135 | d :: r -> 136 let new_counter, cd = compile_def d counter in 137 cd @ (compile_prog r new_counter) 138 139 let compile (code, data) = 140 { text = Baselib.builtins @ compile_prog code 0 141 ; data = List.map (fun (l, s) -> (l, Asciiz s)) data }