(*
   finalize.ml
   15-411
   by Roland Flury
   modified 15 Sep 2004 by Arthur O'Dwyer
*)
(* @version $Id: finalize.ml,v 1.3 2004/10/30 19:33:22 ajo Exp $ *)

module HA = Hashtbl
module A = Assem
open Types

(*
   Produces the output by replacing the temps by strings in the 
   instructions.
   |prog| is a list of instructions.
   |file_Name| is the name of the source file.
*)
let finalize_prog (prog, numslots, raf) file_Name =
  (* Make an arbitrary string quote-safe *)
  let quote s = begin
      let s = Str.global_replace (Str.regexp_string "\\") "\\\\" s in
      let s = Str.global_replace (Str.regexp_string "\"") "\\\"" s in
      s
    end
  in
  (* Returns a string-representation for a temporary *)
  let temp2string temp = match (raf temp) with
    | REGISTER(1) -> "%eax"
    | REGISTER(2) -> "%ebx"
    | REGISTER(3) -> "%ecx"
    | REGISTER(4) -> "%edx"
    | REGISTER(5) -> "%esi"
    | REGISTER(6) -> "%edi"
    | REGISTER(7) -> "%ebp"
    | REGISTER(8) -> "%esp"
    | REGISTER(r) -> begin
          (Printf.printf "Register %d does not exist\n"  r);
          ""
      end
    | STACKSLOT(i) -> Printf.sprintf "%d(%%ebp)" (-4*i)
    | _ -> begin
          (Printf.printf "Serious bug here!");
          ""
      end
in
  let prog_str = List.fold_left
    (fun res i -> res ^ (A.format temp2string i)) "" prog
  in begin
    (Printf.sprintf "\t.file\t\"%s\"\n" (quote file_Name))^
    "\t.section\t.rodata\n"^
    ".Lfilename:\n"^
    (Printf.sprintf "\t.string \"%s\"\n" (quote file_Name))^
    ".Lnpd:\t.string \"Null pointer dereference\"\n"^
    ".Lbpb:\t.string \"Pointer out of range below\"\n"^
    ".Lbpa:\t.string \"Pointer out of range above\"\n"^
    ".Ldvz:\t.string \"Division by zero attempted\"\n"^
    ".Ldmz:\t.string \"Modulo by zero attempted\"\n"^
    ".Lnullptr:\n"^
    "\t.long 0\n"^
    "\t.long 0\n"^
    "\t.long 0\n"^
    "\t.text\n"^
    ".globl\t_l2_main\n"^
    "\t.type\t_l2_main,@function\n"^
    ".globl\t_null_dereference\n"^
    "\t.type\t_null_dereference,@function\n"^
    "_l2_main:\n"^
    "\tpushl\t%ebp\n"^
    "\tpushl\t%ebx\n"^
    "\tpushl\t%esi\n"^
    "\tpushl\t%edi\n"^
    "\tmovl\t%esp, %ebp\n"^
    begin
      if numslots > 0 then
        (Printf.sprintf "\tsubl\t$%d, %%esp\n" (4*numslots))
      else ""
    end^
    prog_str^
    "\tmovl\t%ebp, %esp\n"^
    "\tpopl\t%edi\n"^
    "\tpopl\t%esi\n"^
    "\tpopl\t%ebx\n"^
    "\tpopl\t%ebp\n"^
    "\tret\n"^

    "_null_dereference:\n"^
    "\tpushl\t%ebp\n"^
    "\tmovl\t%esp, %ebp\n"^
    "\tsubl\t$24, %esp\n"^
    "\tmovl\t12(%ebp), %edx\n"^
    "\tmovl\t8(%ebp), %ecx\n"^
    "\tmovl\t(%edx), %eax\n"^
    "\ttestl\t%eax, %eax\n"^
    "\tjne\t.Lnd1\n"^
    "\tmovl\t$.Lnpd, 8(%esp)\n"^
    "\tjmp\t.Lnd3\n"^
    "\t.p2align 4,,7\n"^
    ".Lnd1:\tmovl\t8(%edx), %eax\n"^
    "\tcmpl\t%eax, 4(%edx)\n"^
    "\tjge\t.Lnd2\n"^
    "\tmovl\t$.Lbpb, 8(%esp)\n"^
    "\tjmp\t.Lnd3\n"^
    "\t.p2align 4,,7\n"^
    ".Lnd2:\tmovl\t$.Lbpa, 8(%esp)\n"^
    ".Lnd3:\tmovl\t%ecx, 4(%esp)\n"^
    "\tmovl\t$.Lfilename, (%esp)\n"^
    "\tcall\t_l2_error\n"^

    "#\tassembly output complete\n"
  end