minic/compiler.ml

141 lines
3.8 KiB
OCaml

open Mips
open Ast.IR2
module Env = Map.Make (String)
type cinfo =
{ code : Mips.instr list
; env : Mips.loc Env.t
; fpo : int
; counter : int
; return : string
}
let compile_v = function
| Nil -> [ Li (V0, 0) ]
| Bool b -> [ Li (V0, if b then 1 else 0) ]
| Int n -> [ Li (V0, n) ]
| Float f -> [ Lis (F0, f) ]
| Char c -> [ Li (V0, int_of_char c) ]
| Data l -> [ La (V0, Lbl l) ]
let rec compile_expr e env =
match e with
| Value v -> compile_v v
| Var v -> [ Lw (V0, Env.find v env) ]
| Call (f, args) ->
let ca =
List.map
(fun a -> compile_expr a env @ [ Addi (SP, SP, -4); Sw (V0, Mem (SP, 0)) ])
args
in
List.flatten ca @ [ Jal f; Addi (SP, SP, 4 * List.length args) ]
;;
let rec compile_instr i info =
match i with
| Decl v ->
{ info with env = Env.add v (Mem (FP, -info.fpo)) info.env; fpo = info.fpo + 4 }
| Return e ->
{ info with code = info.code @ compile_expr e info.env @ [ B info.return ] }
| Expr e -> { info with code = info.code @ compile_expr e info.env }
| Assign (lv, e) ->
{ info with
code =
(info.code
@ compile_expr e info.env
@
match lv with
| Var v -> [ Sw (V0, Env.find v info.env) ]
| _ -> failwith "WTF???")
}
(* | LVar v -> [ Sw (V0, Env.find v info.env) ] *)
(* | LAddr a -> [] *)
(* @ [ Addi (SP, SP, -4) *)
(* ; Sw (V0, Mem (SP, 0)) ] *)
(* @ compile_expr a info.env *)
(* @ [ Lw (T0, Mem (SP, 0)) *)
(* ; Addi (SP, SP, 4) *)
(* ; Sw (T0, Mem (V0, 0)) ]) } *)
| Cond (c, t, e) ->
let uniq = string_of_int info.counter in
let ct = compile_block t { info with code = []
; counter = info.counter + 1 } in
let ce = compile_block e { info with code = []
; counter = ct.counter } in
{ info with
code = info.code
@ compile_expr c info.env
@ [ Beqz (V0, "else" ^ uniq) ]
@ ct.code
@ [ B ("endif" ^ uniq)
; Label ("else" ^ uniq) ]
@ ce.code
@ [ Label ("endif" ^ uniq) ]
; counter = ce.counter }
| Loop (c, t) ->
let uniq = string_of_int info.counter in
let ct = compile_block t { info with code = []
; counter = info.counter + 1 } in
{ info with
code = info.code
@ [ Label ("loop" ^ uniq) ]
@ compile_expr c info.env
@ [ Beqz (V0, "endloop" ^ uniq) ]
@ ct.code
@ [ J ("loop" ^ uniq) ]
@ [ Label ("endloop" ^ uniq) ]
; counter = ct.counter }
and compile_block b info =
match b with
| [] -> info
| i :: r -> compile_block r (compile_instr i info)
;;
let compile_def (Func (name, args, b)) counter =
let cb =
compile_block
b
{ code = []
; env =
List.fold_left
(fun e (i, a) -> Env.add a (Mem (FP, 4 * i)) e)
Env.empty
(List.mapi (fun i a -> i + 1, a) args)
; fpo = 8
; counter = counter + 1
; return = "ret" ^ string_of_int counter
}
in
( cb.counter
, []
@ [ Label name
; Addi (SP, SP, -cb.fpo)
; Sw (RA, Mem (SP, cb.fpo - 4))
; Sw (FP, Mem (SP, cb.fpo - 8))
; Addi (FP, SP, cb.fpo - 4)
]
@ cb.code
@ [ Label cb.return
; Addi (SP, SP, cb.fpo)
; Lw (RA, Mem (FP, 0))
; Lw (FP, Mem (FP, -4))
; Jr RA
] )
;;
let rec compile_prog p counter =
match p with
| [] -> []
| d :: r ->
let new_counter, cd = compile_def d counter in
cd @ compile_prog r new_counter
;;
let compile (code, data) =
{ text = Baselib.builtins @ compile_prog code 0
; data = List.map (fun (l, s) -> l, Asciiz s) data
}
;;