
type arch_type = Intel | Sparc 

let limit = ref 1000
let trace = ref false 
let arch  = ref Intel (* default architecture *) 
(*let arch = ref Sparc*)

let set_arch = function 
    "x86" -> arch := Intel 
  | "intel" -> arch := Intel 
  | "Intel" -> arch := Intel 
  | "sparc" -> arch := Sparc
  | "Sparc" -> arch := Sparc
  | "mips" -> arch := Sparc
  | "Mips" -> arch := Sparc
  | _ -> arch := Intel 

let rec iter n e = (* 最適化処理をくりかえす (caml2html: main_iter) *)
  Format.eprintf "iteration %d@." n;
  if n = 0 then e else
  let e' = Elim.f (ConstFold.f (Inline.f (Assoc.f (Beta.f e)))) in
  if e = e' then e else
  iter (n - 1) e'

let lexbuf trace_outchan_opt outchan emitf l = (* バッファをコンパイルしてチャンネルへ出力する (caml2html: main_lexbuf) *)
 match trace_outchan_opt with 
 | None ->  Id.counter := 0;
            Typing.extenv := M.empty;
            let middle_end = 
                (Closure.f
                    (iter !limit
                        (Alpha.f
                            (KNormal.f
                                (Typing.f
                                    (Parser.exp Lexer.token l)))))) in
			(* back end *)
            (match !arch with
			| Sparc ->
                 EmitSparc.f outchan
                    (RegAlloc.f
                        (Simm13.f
                            (Virtual.f middle_end)))
			| Intel ->
			     IntelCode.emitCode outchan
				    (IntelVars.addIntelVariables middle_end))
 | Some toc -> 
   let _ = Id.counter := 0
   in let _ = Typing.extenv := M.empty
   in let t1 = Parser.exp Lexer.token l
   in let _ = output_string toc "\n\n===================== parser output ===============================\n" 
   in let _ = Spy.syntax toc t1 
   in let t2 = Typing.f t1 
   in let _ = output_string toc "\n\n===================== typing output ===============================\n" 
   in let _ = Spy.syntax toc t2 
   in let t3 = KNormal.f t2 
   in let _ = output_string toc "\n\n===================== knormal output ===============================\n" 
   in let _ = Spy.knormal toc t3 
   in let t4 = Alpha.f t3 
   in let _ = output_string toc "\n\n===================== alpha output ===============================\n" 
   in let _ = Spy.knormal toc t4
   in let t5 = iter !limit t4 
   in let _ = output_string toc "\n\n===================== simplify output ===============================\n" 
   in let _ = Spy.knormal toc t5 
   in let t6 = Closure.f t5 
   in let _ = output_string toc "\n\n===================== closure output ===============================\n" 
   in let _ = Spy.closure toc t6
   in match !arch with
   | Sparc ->
     let t7 = Virtual.f t6 
     in let _ = output_string toc "\n\n===================== virtual  output ===============================\n" 
     in let _ = Spy.abs_asm toc t7 
     in let t8 = Simm13.f t7 
     in let _ = output_string toc "\n\n=====================  simm13  output ===============================\n" 
     in let _ = Spy.abs_asm toc t8 
     in let t9 = RegAlloc.f t8 
     in let _ = output_string toc "\n\n===================== RegAlloc output ===============================\n" 
     in let _ = Spy.abs_asm toc t9 
     in let _ = output_string toc "\n\n===================== Emit output ===============================\n" 
     in let _ = EmitSparc.f toc t9 
     in let _ = EmitSparc.f outchan t9 
     in ()
   | Intel ->
     let iv = IntelVars.addIntelVariables t6 (* intel backend *)
     in let _ = IntelCode.emitCode outchan iv
	 in let _ = output_string toc "\n\n===================== Intel asm ===============================\n" 
	 in let _ = IntelCode.emitCode toc iv 
	 in ()

let file f = (* ファイルをコンパイルしてファイルに出力する (caml2html: main_file) *)
  let inchan = open_in (f ^ ".ml") in
  let outchan = match !arch with | Sparc -> open_out (f ^ ".s") | Intel -> open_out(f ^ ".asm") in
  (*let emitf = match !arch with Intel -> EmitIntel.f | Sparc -> EmitSparc.f in *)
  let trace_outchan_opt = if !trace then Some(open_out (f ^ ".v")) else None in 
  let clean_up () = (close_in inchan; close_out outchan; match trace_outchan_opt with None -> () | Some oc -> close_out oc) in 
  try
    lexbuf trace_outchan_opt outchan arch (Lexing.from_channel inchan);
    clean_up(); 
  with e -> (clean_up(); raise e)

let () = (* ここからコンパイラの実行が開始される (caml2html: main_entry) *)
  let files = ref [] in
  Arg.parse
    [("-inline", Arg.Int(fun i -> Inline.threshold := i), "maximum size of functions inlined");
     ("-iter", Arg.Int(fun i -> limit := i), "maximum number of optimizations iterated"); 
     ("-arch", Arg.String(set_arch), "set output to x86 or sparc assembler");
     ("-v", Arg.Unit(fun _ -> trace := true), "maximum number of optimizations iterated")]
    (fun s -> files := !files @ [s])
    ("Mitou Min-Caml Compiler (C) Eijiro Sumii\n" ^
     Printf.sprintf "usage: %s [-inline m] [-iter n] [-arch [ x86 | sparc]] [-v]...filenames without \".ml\"..." Sys.argv.(0));
  List.iter
    (fun f -> ignore (file f))
    !files
