141 lines
3.8 KiB
OCaml
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
|
|
}
|
|
;;
|