Quellcode durchsuchen

Formatted all source code to 2 spaces as tab, and some more prettifications

Taddeus Kroes vor 12 Jahren
Ursprung
Commit
3403c4a3fc
19 geänderte Dateien mit 2272 neuen und 2240 gelöschten Zeilen
  1. 6 6
      globals.ml
  2. 96 93
      main.ml
  3. 246 248
      phases/assemble.ml
  4. 30 30
      phases/boolop.ml
  5. 151 151
      phases/constprop.ml
  6. 125 125
      phases/context.ml
  7. 246 246
      phases/desug.ml
  8. 89 89
      phases/dimreduce.ml
  9. 89 90
      phases/extern.ml
  10. 69 68
      phases/index.ml
  11. 20 15
      phases/load.ml
  12. 12 12
      phases/output.ml
  13. 16 15
      phases/parse.ml
  14. 77 59
      phases/peephole.ml
  15. 157 156
      phases/print.ml
  16. 210 205
      phases/typecheck.ml
  17. 151 150
      stringify.ml
  18. 126 126
      types.mli
  19. 356 356
      util.ml

+ 6 - 6
globals.ml

@@ -4,10 +4,10 @@ open Types
  * (yes, it is a bit dirty, but I don't know how to do this without passing
  * [args] to every function). *)
 let args = {
-    infile   = None;
-    outfile  = None;
-    verbose  = 1;
-    cpp      = true;
-    optimize = true;
-    endphase = "";
+  infile   = None;
+  outfile  = None;
+  verbose  = 1;
+  cpp      = true;
+  optimize = true;
+  endphase = "";
 }

+ 96 - 93
main.ml

@@ -8,117 +8,120 @@ let always _ = true
 let when_optimize _ = args.optimize
 
 let phases = [
-    ("load", Load.phase, always,
-     "Load input file");
-    ("parse", Parse.phase, always,
-     "Parse input");
-    ("desug", Desug.phase, always,
-     "Desugaring");
-    ("context", Context.phase, always,
-     "Context analysis");
-    ("typecheck", Typecheck.phase, always,
-     "Type checking");
-    ("dimreduce", Dimreduce.phase, always,
-     "Array dimension reduction");
-    ("boolop", Boolop.phase, always,
-     "Convert bool operations");
-    ("extern", Extern.phase, always,
-     "Create getters and setters for extern variables");
-    ("constprop", Constprop.phase, when_optimize,
-     "Constant propagation");
-    ("index", Index.phase, always,
-     "Index analysis");
-    ("assemble", Assemble.phase, always,
-     "Assembly");
-    ("peephole", Peephole.phase, when_optimize,
-     "Peephole optimization");
-    ("output", Output.phase, always,
-     "Output assembly");
+  ("load", Load.phase, always,
+   "Load input file");
+  ("parse", Parse.phase, always,
+   "Parse input");
+  ("desug", Desug.phase, always,
+   "Desugaring");
+  ("context", Context.phase, always,
+   "Context analysis");
+  ("typecheck", Typecheck.phase, always,
+   "Type checking");
+  ("dimreduce", Dimreduce.phase, always,
+   "Array dimension reduction");
+  ("boolop", Boolop.phase, always,
+   "Convert bool operations");
+  ("extern", Extern.phase, always,
+   "Create getters and setters for extern variables");
+  ("constprop", Constprop.phase, when_optimize,
+   "Constant propagation");
+  ("index", Index.phase, always,
+   "Index analysis");
+  ("assemble", Assemble.phase, always,
+   "Assembly");
+  ("peephole", Peephole.phase, when_optimize,
+   "Peephole optimization");
+  ("output", Output.phase, always,
+   "Output assembly");
 ]
 
 (* Compile CVC file to assembly code
  * in_channel -> int -> repr *)
 let compile () =
-    let rec run_phases input = function
-        | [] -> ()
-        | (id, phase, cond, msg) :: tl ->
-            let output = if cond () then (
-                log_plain_line 2 (expand 13 ("- " ^ id ^ ":") ^ msg);
-                let output = phase input in
-                if id = args.endphase || args.verbose >= 2 then (
-                    let _ = Print.phase output in ()
-                );
-                output
-            ) else input in
-            if id = args.endphase then () else run_phases output tl
-    in
-    run_phases Empty phases
+  let rec run_phases input = function
+    | [] -> ()
+    | (id, phase, cond, msg) :: tl ->
+      let output =
+        if cond () then begin
+          log_plain_line 2 (expand 13 ("- " ^ id ^ ":") ^ msg);
+          let output = phase input in
+          if id = args.endphase || args.verbose >= 2 then begin
+            ignore (Print.phase output)
+          end;
+          output
+        end else
+          input
+      in
+      if id = args.endphase then () else run_phases output tl
+  in
+  run_phases Empty phases
 
 (* Main function, returns exit status
  * Command-line arguments are stored in Util.args
  * () -> int *)
 let main () =
-    let rec upto_usage = function
-        | [] -> ""
-        | (id, _, _, msg) :: tl ->
-            "\n" ^ repeat " " 12 ^ expand 10 id ^ ": " ^ msg ^ (upto_usage tl)
-    in
-    let args_spec = [
-        ("<file>", Arg.Rest (fun s -> ()),
-                 "   Optional input file (default is to read from stdin)");
+  let rec upto_usage = function
+    | [] -> ""
+    | (id, _, _, msg) :: tl ->
+      "\n" ^ repeat " " 12 ^ expand 10 id ^ ": " ^ msg ^ (upto_usage tl)
+  in
+  let args_spec = [
+    ("<file>", Arg.Rest (fun s -> ()),
+             "   Optional input file (default is to read from stdin)");
 
-        ("-o", Arg.String (fun s -> args.outfile <- Some s),
-             "<file> Output file (defaults to foo.s for foo.cvc)");
+    ("-o", Arg.String (fun s -> args.outfile <- Some s),
+         "<file> Output file (defaults to foo.s for foo.cvc)");
 
-        ("-v", Arg.Int (fun i -> args.verbose <- i),
-             "<num>  Set verbosity (0: nothing, 1: errors, 2: intermediate, 3: debug)");
+    ("-v", Arg.Int (fun i -> args.verbose <- i),
+         "<num>  Set verbosity (0: nothing, 1: errors, 2: intermediate, 3: debug)");
 
-        ("-nocpp", Arg.Unit (fun _ -> args.cpp <- false),
-                 "   Disable C preprocessor");
-        ("-cpp", Arg.Unit (fun _ -> args.cpp <- true),
-               "     Enable C preprocessor (overwrite earlier -nocpp)");
+    ("-nocpp", Arg.Unit (fun _ -> args.cpp <- false),
+             "   Disable C preprocessor");
+    ("-cpp", Arg.Unit (fun _ -> args.cpp <- true),
+           "     Enable C preprocessor (overwrite earlier -nocpp)");
 
-        ("-noopt", Arg.Unit (fun _ -> args.optimize <- false),
-                 "   Disable optimization");
-        ("-opt", Arg.Unit (fun _ -> args.optimize <- true),
-               "     Enable optimization (overwrite earlier -nocpp)");
+    ("-noopt", Arg.Unit (fun _ -> args.optimize <- false),
+             "   Disable optimization");
+    ("-opt", Arg.Unit (fun _ -> args.optimize <- true),
+           "     Enable optimization (overwrite earlier -nocpp)");
 
-        ("-upto", Arg.String (fun s -> args.endphase <- s),
-                "<phase> Stop after the specified phase, and print the intermediate " ^
-                "representation to stderr.\n        " ^
-                "    Possible options are (in order of execution):" ^ upto_usage phases);
-    ] in
+    ("-upto", Arg.String (fun s -> args.endphase <- s),
+            "<phase> Stop after the specified phase, and print the intermediate \
+             representation to stderr.\n        \
+             Possible options are (in order of execution):" ^ upto_usage phases);
+  ] in
 
-    let usage =
-        "Usage: " ^ Sys.argv.(0) ^ " [-o <file>] [-nocpp] [-noopt] " ^
-        " [-v <verbosity>] [-upto <phase>] [<file>]"
-    in
+  let usage =
+    "Usage: " ^ Sys.argv.(0) ^ " [-o <file>] [-nocpp] [-noopt] \
+     [-v <verbosity>] [-upto <phase>] [<file>]"
+  in
 
+  try
     try
-        try
-            Arg.parse args_spec (fun s -> args.infile <- Some s) usage;
-            compile ();
-            0
-        with
-        (*| InvalidNode ->
-            raise (CompileError "invalid node")*)
-        | InvalidInput name ->
-            raise (CompileError ("invalid input for phase \"" ^ name ^ "\""))
-        | NodeError (node, msg) ->
-            (* If no location is given, just stringify the node to at least give
-             * some information *)
-            let msg = if locof node = noloc then
-                msg ^ "\nnode: " ^ Stringify.node2str node
-            else msg in
-            raise (LocError (locof node, msg))
+      Arg.parse args_spec (fun s -> args.infile <- Some s) usage;
+      compile ();
+      0
     with
-    | CompileError msg ->
-        eprintf "Error: %s\n" msg;
-        1
-    | LocError (loc, msg) ->
-        prerr_loc_msg loc ("Error: " ^ msg);
-        1
-    | EmptyError ->
-        1
+    (*| InvalidNode ->
+      raise (CompileError "invalid node")*)
+    | InvalidInput name ->
+      raise (CompileError ("invalid input for phase \"" ^ name ^ "\""))
+    | NodeError (node, msg) ->
+      (* If no location is given, just stringify the node to at least give
+       * some information *)
+      let msg = if locof node = noloc then
+        msg ^ "\nnode: " ^ Stringify.node2str node
+      else msg in
+      raise (LocError (locof node, msg))
+  with
+  | CompileError msg ->
+    eprintf "Error: %s\n" msg;
+    1
+  | LocError (loc, msg) ->
+    prerr_loc_msg loc ("Error: " ^ msg);
+    1
+  | EmptyError ->
+    1
 
 let _ = exit (main ())

+ 246 - 248
phases/assemble.ml

@@ -7,256 +7,254 @@ open Globals
 let comline comment = InlineComment (EmptyLine, comment)
 
 let assemble program =
-    let labcounter = ref 0 in
-    let genlabel suffix =
-        labcounter := !labcounter + 1;
-        string_of_int !labcounter ^ "_" ^ suffix
+  let labcounter = ref 0 in
+  let genlabel suffix =
+  labcounter := !labcounter + 1;
+  string_of_int !labcounter ^ "_" ^ suffix
+  in
+
+  let consts = Hashtbl.create 20 in
+
+  let rec trav node =
+  let rec trav_all = function
+    | [] -> []
+    | hd :: tl -> trav hd @ (trav_all tl)
+  in
+  let rec traverse_localfuns = function
+    | LocalFuns body -> List.concat (List.map trav body)
+    | Block body -> List.concat (List.map traverse_localfuns body)
+    | _ -> []
+  in
+  match node with
+  (* Global *)
+  | Program (decls, _) ->
+    trav_all decls
+
+  | GlobalDef (_, ctype, name, _, _) ->
+    [Comment (sprintf "global var \"%s\" at index %d" name (indexof node));
+     Global ctype]
+
+  | FunDec (ret_type, name, params, _) ->
+    [Comment (sprintf "extern fun \"%s\" at index %d" name (indexof node));
+     Import (name, ret_type, List.map typeof params)]
+
+  | FunDef (export, ret_type, name, params, body, _) ->
+    let label = labelof node in
+    (if export then
+        let param_types = List.map typeof params in
+        [Export (name, ret_type, param_types, label)]
+    else []) @
+    [Comment (sprintf "fun \"%s\" with %d local vars" label (indexof node));
+     Label label;
+     RtnEnter (indexof node)] @
+    (trav body) @
+    (match ret_type with Void -> [Ret Void] | _ -> []) @
+    [EmptyLine] @
+    (traverse_localfuns body)
+
+  | VarDec (_, name, _, _) ->
+    [comline (sprintf "local var \"%s\" at index %d" name (indexof node))]
+
+  | LocalFuns _ -> []
+
+  | Block body | VarDecs body -> trav_all body
+
+  (* Statements *)
+  | VarLet (dec, None, value, _) ->
+    let store = match (depthof dec, depthof node) with
+    | (0, _)            -> Store (typeof dec, Glob,        indexof dec)
+    | (a, b) when a = b -> Store (typeof dec, Current,     indexof dec)
+    | (a, b)            -> Store (typeof dec, Rel (b - a), indexof dec)
     in
-
-    let consts = Hashtbl.create 20 in
-
-    let rec trav node =
-        let rec trav_all = function
-            | [] -> []
-            | hd :: tl -> trav hd @ (trav_all tl)
-        in
-        let rec traverse_localfuns = function
-            | LocalFuns body -> List.concat (List.map trav body)
-            | Block body -> List.concat (List.map traverse_localfuns body)
-            | _ -> []
-        in
-        match node with
-        (* Global *)
-        | Program (decls, _) ->
-            trav_all decls
-
-        | GlobalDef (_, ctype, name, _, _) ->
-            [Comment (sprintf "global var \"%s\" at index %d" name (indexof node));
-             Global ctype]
-
-        | FunDec (ret_type, name, params, _) ->
-            [Comment (sprintf "extern fun \"%s\" at index %d" name (indexof node));
-             Import (name, ret_type, List.map typeof params)]
-
-        | FunDef (export, ret_type, name, params, body, _) ->
-            let label = labelof node in
-            (if export then
-                let param_types = List.map typeof params in
-                [Export (name, ret_type, param_types, label)]
-            else []) @
-            [
-                Comment (sprintf "fun \"%s\" with %d local vars" label (indexof node));
-                Label label;
-                RtnEnter (indexof node);
-            ] @
-            (trav body) @
-            (match ret_type with Void -> [Ret Void] | _ -> []) @
-            [EmptyLine] @
-            (traverse_localfuns body)
-
-        | VarDec (_, name, _, _) ->
-            [comline (sprintf "local var \"%s\" at index %d" name (indexof node))]
-
-        | LocalFuns _ -> []
-
-        | Block body | VarDecs body -> trav_all body
-
-        (* Statements *)
-        | VarLet (dec, None, value, _) ->
-            let store = match (depthof dec, depthof node) with
-                | (0, _)            -> Store (typeof dec, Glob,        indexof dec)
-                | (a, b) when a = b -> Store (typeof dec, Current,     indexof dec)
-                | (a, b)            -> Store (typeof dec, Rel (b - a), indexof dec)
-            in
-            trav value @ [InlineComment (store, node2str node)]
-
-        | Return (value, _) ->
-            trav value @ [InlineComment (Ret (typeof value), node2str node)]
-
-        | If (cond, body, _) ->
-            let endlabel = genlabel "end" in
-            (trav cond) @
-            [Branch (false, endlabel);
-             comline ("if (" ^ (node2str cond) ^ ") {")] @
-            (trav body) @
-            [comline "}";
-             Label endlabel]
-
-        | IfElse (cond, true_body, false_body, _) ->
-            let elselabel = genlabel "else" in
-            let endlabel = genlabel "end" in
-            (trav cond) @
-            [Branch (false, elselabel);
-             comline ("if (" ^ (node2str cond) ^ ") {")] @
-            (trav true_body) @
-            [Jump endlabel;
-             comline "} else {";
-             Label elselabel] @
-            (trav false_body) @
-            [comline "}";
-             Label endlabel]
-
-        | While (cond, body, _) ->
-            let startlabel = genlabel "while" in
-            let endlabel = genlabel "end" in
-            let com = ("while (" ^ (node2str cond) ^ ") {") in
-            [Label startlabel] @
-            (trav cond) @
-            [InlineComment (Branch (false, endlabel), com)] @
-            (trav body) @
-            [Jump startlabel;
-             Label endlabel;
-             comline "}"]
-
-        | DoWhile (cond, body, _) ->
-            let startlabel = genlabel "dowhile" in
-            let com = ("} while (" ^ (node2str cond) ^ ");") in
-            [comline "do {";
-             Label startlabel] @
-            (trav body) @
-            (trav cond) @
-            [InlineComment (Branch (true, startlabel), com)]
-
-        (* Expression statement pops the disregarded expression value from the
-         * stack, if any *)
-        | Expr value ->
-            let pop = match typeof value with
-                | Void -> [comline (node2str node)]
-                | ctype -> [InlineComment (Pop ctype, node2str node)]
-            in
-            (trav value) @ pop
-
-        (* Expressions *)
-        (* Immediate values are handled here, and not in the peephole optimizer,
-         * for convenience: the indices in the constant table would be altered,
-         * so entries cannot be removed. By this early detection (also during
-         * index analysis), they are not added in the first place *)
-        | Const (value, _) when is_immediate_const value ->
-            [InlineComment (LoadImm value, node2str node)]
-
-        | Const (value, _) ->
-            Hashtbl.replace consts value (indexof node);
-            let load = LoadConst (typeof node, indexof node) in
-            [InlineComment (load, node2str node)]
-
-        | VarUse (dec, None, _) ->
-            let load = match (depthof dec, depthof node) with
-                | (0, _)            -> Load (typeof dec, Glob,        indexof dec)
-                | (a, b) when a = b -> Load (typeof dec, Current,     indexof dec)
-                | (a, b)            -> Load (typeof dec, Rel (b - a), indexof dec)
-            in
-            [InlineComment (load, node2str node)]
-
-        | Monop (op, value, _) ->
-            (trav value) @
-            [InlineComment (Op (op, typeof value), op2str op)]
-
-        | Binop (op, left, right, _) ->
-            (trav left) @
-            (trav right) @
-            [InlineComment (Op (op, typeof left), op2str op)]
-
-        | TypeCast (ctype, value, _) ->
-            let vtype = typeof value in
-            (match (ctype, vtype) with
-            | (Float, Int) | (Int, Float) -> ()
-            | _ ->
-                let msg = sprintf
-                    "invalid typecast: %s -> %s"
-                    (type2str vtype) (type2str ctype)
-                in raise (NodeError (node, msg))
-            );
-            trav value @ [Convert (vtype, ctype)]
-
-        (* Function calls *)
-        | FunUse (dec, args, _) ->
-            let init = match (depthof dec, depthof node) with
-                | (0, _)                -> RtnInit Glob
-                | (a, b) when a = b - 1 -> RtnInit Current
-                | (a, b) when a = b     -> RtnInit Local
-                | (a, b)                -> RtnInit (Rel (b - a - 1))
-            in
-            let jmp = match dec with
-                | FunDec _ -> RtnJmp (ExternFun (indexof dec))
-                | FunDef _ -> RtnJmp (LocalFun (List.length args, labelof dec))
-                | _ -> raise InvalidNode
-            in
-            init :: (trav_all args) @ [jmp]
-
-        | Arg value -> trav value
-
-        (* Conditional expression (short-circuit evaluation) *)
-        (*     <cond>
-         *     branch_f else
-         *     <true_expr>
-         *     jump end
-         * else:
-         *     <false_expr>
-         * end:
-         *)
-        | Cond (cond, texp, fexp, _) ->
-            let elselabel = genlabel "false_expr" in
-            let endlabel = genlabel "end" in
-            (trav cond) @
-            [Branch (false, elselabel)] @
-            (trav texp) @
-            [Jump (endlabel);
-             Label (elselabel)] @
-            (trav fexp) @
-            [InlineComment (Label (endlabel), node2str node)]
-
-        (* Arrays *)
-        | Allocate (dec, dims, _) ->
-            let store = match (depthof dec, depthof node) with
-                | (0, _)            -> Store (typeof dec, Glob,    indexof dec)
-                | (a, b) when a = b -> Store (typeof dec, Current, indexof dec)
-                | _                 -> raise InvalidNode
-            in
-            trav_all dims @
-            [NewArray (basetypeof dec, List.length dims);
-             InlineComment (store, node2str node)]
-
-        | VarUse (dec, Some dims, _) ->
-            let load = match (depthof dec, depthof node) with
-                | (0, _)            -> Load (typeof dec, Glob,        indexof dec)
-                | (a, b) when a = b -> Load (typeof dec, Current,     indexof dec)
-                | (a, b)            -> Load (typeof dec, Rel (b - a), indexof dec)
-            in
-            (trav_all (List.rev dims)) @          (* push dimensions *)
-            [InlineComment (load, nameof dec)] @  (* push array reference *)
-            [InlineComment (LoadArray (basetypeof dec), node2str node)]
-
-        | VarLet (dec, Some dims, value, _) ->
-            let load = match (depthof dec, depthof node) with
-                | (0, _)            -> Load (typeof dec, Glob,        indexof dec)
-                | (a, b) when a = b -> Load (typeof dec, Current,     indexof dec)
-                | (a, b)            -> Load (typeof dec, Rel (b - a), indexof dec)
-            in
-            (trav value) @                        (* push value *)
-            (trav_all dims) @                     (* push dimensions *)
-            [InlineComment (load, nameof dec)] @  (* push array reference *)
-            [InlineComment (StoreArray (basetypeof dec), node2str node)]
-
-        | _ -> [Comment ("FIXME: " ^ Stringify.node2str node)]
-        (*| _ -> raise InvalidNode*)
+    trav value @ [InlineComment (store, node2str node)]
+
+  | Return (value, _) ->
+    trav value @ [InlineComment (Ret (typeof value), node2str node)]
+
+  | If (cond, body, _) ->
+    let endlabel = genlabel "end" in
+    (trav cond) @
+    [Branch (false, endlabel);
+     comline ("if (" ^ (node2str cond) ^ ") {")] @
+    (trav body) @
+    [comline "}";
+     Label endlabel]
+
+  | IfElse (cond, true_body, false_body, _) ->
+    let elselabel = genlabel "else" in
+    let endlabel = genlabel "end" in
+    (trav cond) @
+    [Branch (false, elselabel);
+     comline ("if (" ^ (node2str cond) ^ ") {")] @
+    (trav true_body) @
+    [Jump endlabel;
+     comline "} else {";
+     Label elselabel] @
+    (trav false_body) @
+    [comline "}";
+     Label endlabel]
+
+  | While (cond, body, _) ->
+    let startlabel = genlabel "while" in
+    let endlabel = genlabel "end" in
+    let com = ("while (" ^ (node2str cond) ^ ") {") in
+    [Label startlabel] @
+    (trav cond) @
+    [InlineComment (Branch (false, endlabel), com)] @
+    (trav body) @
+    [Jump startlabel;
+     Label endlabel;
+     comline "}"]
+
+  | DoWhile (cond, body, _) ->
+    let startlabel = genlabel "dowhile" in
+    let com = ("} while (" ^ (node2str cond) ^ ");") in
+    [comline "do {";
+     Label startlabel] @
+    (trav body) @
+    (trav cond) @
+    [InlineComment (Branch (true, startlabel), com)]
+
+  (* Expression statement pops the disregarded expression value from the
+   * stack, if any *)
+  | Expr value ->
+    let pop = match typeof value with
+        | Void -> [comline (node2str node)]
+        | ctype -> [InlineComment (Pop ctype, node2str node)]
     in
-    let instrs = trav program in
-
-    (* Sort aggregated constants and add definitions
-     * If possible, this should be rewritten in the future because it's a little
-     * cumbersome right now... *)
-    let pairs = ref [] in
-    let add_pair value index =
-        let com = sprintf "index %d" index in
-        pairs := (InlineComment (ConstDef value, com), index) :: !pairs;
+    (trav value) @ pop
+
+  (* Expressions *)
+  (* Immediate values are handled here, and not in the peephole optimizer,
+   * for convenience: the indices in the constant table would be altered,
+   * so entries cannot be removed. By this early detection (also during
+   * index analysis), they are not added in the first place *)
+  | Const (value, _) when is_immediate_const value ->
+    [InlineComment (LoadImm value, node2str node)]
+
+  | Const (value, _) ->
+    Hashtbl.replace consts value (indexof node);
+    let load = LoadConst (typeof node, indexof node) in
+    [InlineComment (load, node2str node)]
+
+  | VarUse (dec, None, _) ->
+    let load = match (depthof dec, depthof node) with
+    | (0, _)            -> Load (typeof dec, Glob,        indexof dec)
+    | (a, b) when a = b -> Load (typeof dec, Current,     indexof dec)
+    | (a, b)            -> Load (typeof dec, Rel (b - a), indexof dec)
     in
-    Hashtbl.iter add_pair consts;
-    let cmp (_, i) (_, j) = compare i j in
-    let sorted_pairs = List.sort cmp !pairs in
-    let const_defs = List.map (fun (d, _) -> d) sorted_pairs in
-
-    instrs @ const_defs
+    [InlineComment (load, node2str node)]
+
+  | Monop (op, value, _) ->
+    (trav value) @
+    [InlineComment (Op (op, typeof value), op2str op)]
+
+  | Binop (op, left, right, _) ->
+    (trav left) @
+    (trav right) @
+    [InlineComment (Op (op, typeof left), op2str op)]
+
+  | TypeCast (ctype, value, _) ->
+    let vtype = typeof value in
+    (match (ctype, vtype) with
+    | (Float, Int) | (Int, Float) -> ()
+    | _ ->
+      let msg = sprintf
+        "invalid typecast: %s -> %s"
+        (type2str vtype) (type2str ctype)
+      in raise (NodeError (node, msg))
+    );
+    trav value @ [Convert (vtype, ctype)]
+
+  (* Function calls *)
+  | FunUse (dec, args, _) ->
+    let init = match (depthof dec, depthof node) with
+    | (0, _)                -> RtnInit Glob
+    | (a, b) when a = b - 1 -> RtnInit Current
+    | (a, b) when a = b     -> RtnInit Local
+    | (a, b)                -> RtnInit (Rel (b - a - 1))
+    in
+    let jmp = match dec with
+    | FunDec _ -> RtnJmp (ExternFun (indexof dec))
+    | FunDef _ -> RtnJmp (LocalFun (List.length args, labelof dec))
+    | _ -> raise InvalidNode
+    in
+    init :: (trav_all args) @ [jmp]
+
+  | Arg value -> trav value
+
+  (* Conditional expression (short-circuit evaluation) *)
+  (*     <cond>
+   *     branch_f else
+   *     <true_expr>
+   *     jump end
+   * else:
+   *     <false_expr>
+   * end:
+   *)
+  | Cond (cond, texp, fexp, _) ->
+    let elselabel = genlabel "false_expr" in
+    let endlabel = genlabel "end" in
+    (trav cond) @
+    [Branch (false, elselabel)] @
+    (trav texp) @
+    [Jump (endlabel);
+     Label (elselabel)] @
+    (trav fexp) @
+    [InlineComment (Label (endlabel), node2str node)]
+
+  (* Arrays *)
+  | Allocate (dec, dims, _) ->
+    let store = match (depthof dec, depthof node) with
+    | (0, _)            -> Store (typeof dec, Glob,    indexof dec)
+    | (a, b) when a = b -> Store (typeof dec, Current, indexof dec)
+    | _                 -> raise InvalidNode
+    in
+    trav_all dims @
+    [NewArray (basetypeof dec, List.length dims);
+     InlineComment (store, node2str node)]
+
+  | VarUse (dec, Some dims, _) ->
+    let load = match (depthof dec, depthof node) with
+    | (0, _)            -> Load (typeof dec, Glob,        indexof dec)
+    | (a, b) when a = b -> Load (typeof dec, Current,     indexof dec)
+    | (a, b)            -> Load (typeof dec, Rel (b - a), indexof dec)
+    in
+    (trav_all (List.rev dims)) @          (* push dimensions *)
+    [InlineComment (load, nameof dec)] @  (* push array reference *)
+    [InlineComment (LoadArray (basetypeof dec), node2str node)]
+
+  | VarLet (dec, Some dims, value, _) ->
+    let load = match (depthof dec, depthof node) with
+    | (0, _)            -> Load (typeof dec, Glob,        indexof dec)
+    | (a, b) when a = b -> Load (typeof dec, Current,     indexof dec)
+    | (a, b)            -> Load (typeof dec, Rel (b - a), indexof dec)
+    in
+    (trav value) @                        (* push value *)
+    (trav_all dims) @                     (* push dimensions *)
+    [InlineComment (load, nameof dec)] @  (* push array reference *)
+    [InlineComment (StoreArray (basetypeof dec), node2str node)]
+
+  | _ -> [Comment ("FIXME: " ^ Stringify.node2str node)]
+  (*| _ -> raise InvalidNode*)
+  in
+  let instrs = trav program in
+
+  (* Sort aggregated constants and add definitions
+   * If possible, this should be rewritten in the future because it's a little
+   * cumbersome right now... *)
+  let pairs = ref [] in
+  let add_pair value index =
+  let com = sprintf "index %d" index in
+  pairs := (InlineComment (ConstDef value, com), index) :: !pairs;
+  in
+  Hashtbl.iter add_pair consts;
+  let cmp (_, i) (_, j) = compare i j in
+  let sorted_pairs = List.sort cmp !pairs in
+  let const_defs = List.map (fun (d, _) -> d) sorted_pairs in
+
+  instrs @ const_defs
 
 let phase = function
-    | Ast node -> Assembly (assemble node)
-    | _ -> raise (InvalidInput "assembly")
+  | Ast node -> Assembly (assemble node)
+  | _ -> raise (InvalidInput "assembly")

+ 30 - 30
phases/boolop.ml

@@ -9,11 +9,11 @@
  * > b1 != b2   ==>   (int)b1 != (int)b2
  * > b1 && b2   ==>   b1 ? b2 : false
  * > b1 || b2   ==>   b1 ? true : b2
- * > b1 + b2    ==>   (bool)((int)b1 + (int)b2)
- * > b1 * b2    ==>   (bool)((int)b1 * (int)b2)
- * > (bool)i    ==>   i != 0
- * > (bool)f    ==>   f != 0.0
- * > (int)b1    ==>   b1 ? 1 : 0
+ * > b1 + b2  ==>   (bool)((int)b1 + (int)b2)
+ * > b1 * b2  ==>   (bool)((int)b1 * (int)b2)
+ * > (bool)i  ==>   i != 0
+ * > (bool)f  ==>   f != 0.0
+ * > (int)b1  ==>   b1 ? 1 : 0
  * > (float)b1  ==>   b1 ? 1.0 : 0.0
  *)
 open Types
@@ -27,42 +27,42 @@ let intconst   value = Const (IntVal   value, [Type Int])
 let floatconst value = Const (FloatVal value, [Type Float])
 
 let rec trav_binop = function
-    | ((Eq | Ne) as op, left, right, ann) ->
-        bool_op (Binop (op, cast Int left, cast Int right, ann))
+  | ((Eq | Ne) as op, left, right, ann) ->
+    bool_op (Binop (op, cast Int left, cast Int right, ann))
 
-    | (And, left, right, ann) ->
-        bool_op (Cond (left, right, boolconst false, ann))
+  | (And, left, right, ann) ->
+    bool_op (Cond (left, right, boolconst false, ann))
 
-    | (Or, left, right, ann) ->
-        bool_op (Cond (left, boolconst true, right, ann))
+  | (Or, left, right, ann) ->
+    bool_op (Cond (left, boolconst true, right, ann))
 
-    | ((Add | Mul) as op, left, right, ann) ->
-        bool_op (cast Bool (Binop (op, cast Int left, cast Int right, Type Int :: ann)))
+  | ((Add | Mul) as op, left, right, ann) ->
+    bool_op (cast Bool (Binop (op, cast Int left, cast Int right, Type Int :: ann)))
 
-    | (op, left, right, ann) ->
-        Binop (op, left, right, ann)
+  | (op, left, right, ann) ->
+    Binop (op, left, right, ann)
 
 and bool_op = function
-    | Binop (op, left, right, ann) when typeof left = Bool && typeof right = Bool ->
-        trav_binop (op, bool_op left, bool_op right, ann)
+  | Binop (op, left, right, ann) when typeof left = Bool && typeof right = Bool ->
+    trav_binop (op, bool_op left, bool_op right, ann)
 
-    | TypeCast (Bool, value, ann) when typeof value = Int ->
-        Binop (Ne, bool_op value, intconst 0, ann)
+  | TypeCast (Bool, value, ann) when typeof value = Int ->
+    Binop (Ne, bool_op value, intconst 0, ann)
 
-    | TypeCast (Bool, value, ann) when typeof value = Float ->
-        Binop (Ne, bool_op value, floatconst 0.0, ann)
+  | TypeCast (Bool, value, ann) when typeof value = Float ->
+    Binop (Ne, bool_op value, floatconst 0.0, ann)
 
-    | TypeCast (Int, value, ann) when typeof value = Bool ->
-        Cond (bool_op value, intconst 1, intconst 0, ann)
+  | TypeCast (Int, value, ann) when typeof value = Bool ->
+    Cond (bool_op value, intconst 1, intconst 0, ann)
 
-    | TypeCast (Float, value, ann) when typeof value = Bool ->
-        Cond (bool_op value, floatconst 1.0, floatconst 0.0, ann)
+  | TypeCast (Float, value, ann) when typeof value = Bool ->
+    Cond (bool_op value, floatconst 1.0, floatconst 0.0, ann)
 
-    | TypeCast (ctype, value, ann) when typeof value = ctype ->
-        bool_op value
+  | TypeCast (ctype, value, ann) when typeof value = ctype ->
+    bool_op value
 
-    | node -> transform_children bool_op node
+  | node -> transform_children bool_op node
 
 let phase = function
-    | Ast node -> Ast (bool_op node)
-    | _ -> raise (InvalidInput "bool operations")
+  | Ast node -> Ast (bool_op node)
+  | _ -> raise (InvalidInput "bool operations")

+ 151 - 151
phases/constprop.ml

@@ -20,7 +20,7 @@ open Util
 open Globals
 
 let is_const_name name =
-    Str.string_match (Str.regexp "^.+\\$\\$[0-9]+$") name 0
+  Str.string_match (Str.regexp "^.+\\$\\$[0-9]+$") name 0
 
 let is_const = function Const _ -> true | _ -> false
 
@@ -29,162 +29,162 @@ let is_const = function Const _ -> true | _ -> false
  * particular targeting array indices that can be simplified after array
  * dimension reduction). *)
 let no_side_effect = function
-    | VarUse _ | Const _ | Var _ -> true
-    | _ -> false
+  | VarUse _ | Const _ | Var _ -> true
+  | _ -> false
 
 (* Constand folding *)
 let eval = function
-    (* Binop - arithmetic *)
-    | Binop (Add, Const (IntVal left, _), Const (IntVal right, _), ann) ->
-        Const (IntVal (left + right), ann)
-    | Binop (Add, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
-        Const (FloatVal (left +. right), ann)
-
-    | Binop (Sub, Const (IntVal left, _), Const (IntVal right, _), ann) ->
-        Const (IntVal (left - right), ann)
-    | Binop (Sub, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
-        Const (FloatVal (left -. right), ann)
-
-    | Binop (Mul, Const (IntVal left, _), Const (IntVal right, _), ann) ->
-        Const (IntVal (left * right), ann)
-    | Binop (Mul, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
-        Const (FloatVal (left *. right), ann)
-
-    | Binop (Div, Const (IntVal left, _), Const (IntVal right, _), ann) when right != 0 ->
-        Const (IntVal (left / right), ann)
-    | Binop (Div, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
-        Const (FloatVal (left /. right), ann)
-
-    | Binop (Mod, Const (IntVal left, _), Const (IntVal right, _), ann) ->
-        Const (IntVal (left mod right), ann)
-
-    (* Binop - relational *)
-    | Binop (Eq, Const (IntVal left, _), Const (IntVal right, _), ann) ->
-        Const (BoolVal (left = right), ann)
-    | Binop (Eq, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
-        Const (BoolVal (left = right), ann)
-
-    | Binop (Ne, Const (IntVal left, _), Const (IntVal right, _), ann) ->
-        Const (BoolVal (left <> right), ann)
-    | Binop (Ne, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
-        Const (BoolVal (left <> right), ann)
-
-    | Binop (Gt, Const (IntVal left, _), Const (IntVal right, _), ann) ->
-        Const (BoolVal (left > right), ann)
-    | Binop (Gt, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
-        Const (BoolVal (left > right), ann)
-
-    | Binop (Lt, Const (IntVal left, _), Const (IntVal right, _), ann) ->
-        Const (BoolVal (left < right), ann)
-    | Binop (Lt, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
-        Const (BoolVal (left < right), ann)
-
-    | Binop (Ge, Const (IntVal left, _), Const (IntVal right, _), ann) ->
-        Const (BoolVal (left >= right), ann)
-    | Binop (Ge, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
-        Const (BoolVal (left >= right), ann)
-
-    | Binop (Le, Const (IntVal left, _), Const (IntVal right, _), ann) ->
-        Const (BoolVal (left <= right), ann)
-    | Binop (Le, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
-        Const (BoolVal (left <= right), ann)
-
-    (* Binop - logical *)
-    | Binop (And, Const (BoolVal left, _), Const (BoolVal right, _), ann) ->
-        Const (BoolVal (left && right), ann)
-    | Binop (Or, Const (BoolVal left, _), Const (BoolVal right, _), ann) ->
-        Const (BoolVal (left || right), ann)
-
-    (* Monary operations *)
-    | Monop (Not, Const (BoolVal  value, _), ann) -> Const (BoolVal  (not value), ann)
-    | Monop (Neg, Const (IntVal   value, _), ann) -> Const (IntVal   (-value), ann)
-    | Monop (Neg, Const (FloatVal value, _), ann) -> Const (FloatVal (-.value), ann)
-
-    (* 0 * a --> 0 *)
-    | Binop (Mul, Const (IntVal 0, _), other, ann)
-    | Binop (Mul, other, Const (IntVal 0, _), ann) when no_side_effect other ->
-        Const (IntVal 0, ann)
-
-    (* 0 + a --> a *)
-    | Binop (Add, Const (IntVal 0, _), other, _)
-    | Binop (Add, other, Const (IntVal 0, _), _) ->
-        other
-
-    (* 1 * a --> a *)
-    | Binop (Mul, Const (IntVal 1, _), other, _)
-    | Binop (Mul, other, Const (IntVal 1, _), _) ->
-        other
-
-    (* true|false ? texp : fexp --> texp|fexp*)
-    | Cond (Const (BoolVal value, _), texp, fexp, _) ->
-        if value then texp else fexp
-
-    | node -> node
+  (* Binop - arithmetic *)
+  | Binop (Add, Const (IntVal left, _), Const (IntVal right, _), ann) ->
+    Const (IntVal (left + right), ann)
+  | Binop (Add, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
+    Const (FloatVal (left +. right), ann)
+
+  | Binop (Sub, Const (IntVal left, _), Const (IntVal right, _), ann) ->
+    Const (IntVal (left - right), ann)
+  | Binop (Sub, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
+    Const (FloatVal (left -. right), ann)
+
+  | Binop (Mul, Const (IntVal left, _), Const (IntVal right, _), ann) ->
+    Const (IntVal (left * right), ann)
+  | Binop (Mul, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
+    Const (FloatVal (left *. right), ann)
+
+  | Binop (Div, Const (IntVal left, _), Const (IntVal right, _), ann) when right != 0 ->
+    Const (IntVal (left / right), ann)
+  | Binop (Div, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
+    Const (FloatVal (left /. right), ann)
+
+  | Binop (Mod, Const (IntVal left, _), Const (IntVal right, _), ann) ->
+    Const (IntVal (left mod right), ann)
+
+  (* Binop - relational *)
+  | Binop (Eq, Const (IntVal left, _), Const (IntVal right, _), ann) ->
+    Const (BoolVal (left = right), ann)
+  | Binop (Eq, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
+    Const (BoolVal (left = right), ann)
+
+  | Binop (Ne, Const (IntVal left, _), Const (IntVal right, _), ann) ->
+    Const (BoolVal (left <> right), ann)
+  | Binop (Ne, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
+    Const (BoolVal (left <> right), ann)
+
+  | Binop (Gt, Const (IntVal left, _), Const (IntVal right, _), ann) ->
+    Const (BoolVal (left > right), ann)
+  | Binop (Gt, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
+    Const (BoolVal (left > right), ann)
+
+  | Binop (Lt, Const (IntVal left, _), Const (IntVal right, _), ann) ->
+    Const (BoolVal (left < right), ann)
+  | Binop (Lt, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
+    Const (BoolVal (left < right), ann)
+
+  | Binop (Ge, Const (IntVal left, _), Const (IntVal right, _), ann) ->
+    Const (BoolVal (left >= right), ann)
+  | Binop (Ge, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
+    Const (BoolVal (left >= right), ann)
+
+  | Binop (Le, Const (IntVal left, _), Const (IntVal right, _), ann) ->
+    Const (BoolVal (left <= right), ann)
+  | Binop (Le, Const (FloatVal left, _), Const (FloatVal right, _), ann) ->
+    Const (BoolVal (left <= right), ann)
+
+  (* Binop - logical *)
+  | Binop (And, Const (BoolVal left, _), Const (BoolVal right, _), ann) ->
+    Const (BoolVal (left && right), ann)
+  | Binop (Or, Const (BoolVal left, _), Const (BoolVal right, _), ann) ->
+    Const (BoolVal (left || right), ann)
+
+  (* Monary operations *)
+  | Monop (Not, Const (BoolVal  value, _), ann) -> Const (BoolVal  (not value), ann)
+  | Monop (Neg, Const (IntVal   value, _), ann) -> Const (IntVal   (-value), ann)
+  | Monop (Neg, Const (FloatVal value, _), ann) -> Const (FloatVal (-.value), ann)
+
+  (* 0 * a --> 0 *)
+  | Binop (Mul, Const (IntVal 0, _), other, ann)
+  | Binop (Mul, other, Const (IntVal 0, _), ann) when no_side_effect other ->
+    Const (IntVal 0, ann)
+
+  (* 0 + a --> a *)
+  | Binop (Add, Const (IntVal 0, _), other, _)
+  | Binop (Add, other, Const (IntVal 0, _), _) ->
+    other
+
+  (* 1 * a --> a *)
+  | Binop (Mul, Const (IntVal 1, _), other, _)
+  | Binop (Mul, other, Const (IntVal 1, _), _) ->
+    other
+
+  (* true|false ? texp : fexp --> texp|fexp*)
+  | Cond (Const (BoolVal value, _), texp, fexp, _) ->
+    if value then texp else fexp
+
+  | node -> node
 
 let rec propagate consts node =
-    let propagate = propagate consts in
-    match node with
-
-    (* Constant assignments are added to constants table *)
-    | Assign (name, None, value, ann) when is_const_name name ->
-        let value = propagate value in
-        if is_const value then (
-            Hashtbl.add consts name value;
-            DummyNode
-        ) else
-            Assign (name, None, value, ann)
-
-    | VarLet (dec, None, value, ann) when is_const_name (nameof dec) ->
-        let value = propagate value in
-        if is_const value then (
-            Hashtbl.add consts (nameof dec) value;
-            DummyNode
-        ) else
-            VarLet (dec, None, value, ann)
-
-    (* Variables that are in the constant table are replaced with their constant
-     * value *)
-    | Var (name, None, ann) when Hashtbl.mem consts name ->
-        Hashtbl.find consts name
-    | VarUse (dec, None, ann) when Hashtbl.mem consts (nameof dec) ->
-        Hashtbl.find consts (nameof dec)
-    | Dim (name, ann) when Hashtbl.mem consts name ->
-        Hashtbl.find consts name
-
-    (* Apply arithmetic simplification to constant operands *)
-    | Monop (op, opnd, ann) ->
-        eval (Monop (op, propagate opnd, ann))
-
-    | Binop (op, left, right, ann) ->
-        eval (Binop (op, propagate left, propagate right, ann))
-
-    | Cond (cond, texp, fexp, ann) ->
-        eval (Cond (propagate cond, propagate texp, propagate fexp, ann))
-
-    | TypeCast (ctype, value, ann) ->
-        let value = propagate value in
-        (match (ctype, value) with
-        | (Bool,  Const (BoolVal  value, _)) -> Const (BoolVal value, ann)
-        | (Bool,  Const (IntVal   value, _)) -> Const (BoolVal (value != 1), ann)
-        | (Bool,  Const (FloatVal value, _)) -> Const (BoolVal (value != 1.0), ann)
-        | (Int,   Const (BoolVal  value, _)) -> Const (IntVal (if value then 1 else 0), ann)
-        | (Int,   Const (IntVal   value, _)) -> Const (IntVal value, ann)
-        | (Int,   Const (FloatVal value, _)) -> Const (IntVal (int_of_float value), ann)
-        | (Float, Const (BoolVal  value, _)) -> Const (FloatVal (if value then 1. else 0.), ann)
-        | (Float, Const (IntVal   value, _)) -> Const (FloatVal (float_of_int value), ann)
-        | (Float, Const (FloatVal value, _)) -> Const (FloatVal value, ann)
-        | _ -> TypeCast (ctype, value, ann)
-        )
-
-    | _ -> transform_children propagate node
+  let propagate = propagate consts in
+  match node with
+
+  (* Constant assignments are added to constants table *)
+  | Assign (name, None, value, ann) when is_const_name name ->
+    let value = propagate value in
+    if is_const value then begin
+      Hashtbl.add consts name value;
+      DummyNode
+    end else
+      Assign (name, None, value, ann)
+
+  | VarLet (dec, None, value, ann) when is_const_name (nameof dec) ->
+    let value = propagate value in
+    if is_const value then begin
+      Hashtbl.add consts (nameof dec) value;
+      DummyNode
+    end else
+      VarLet (dec, None, value, ann)
+
+  (* Variables that are in the constant table are replaced with their constant
+   * value *)
+  | Var (name, None, ann) when Hashtbl.mem consts name ->
+    Hashtbl.find consts name
+  | VarUse (dec, None, ann) when Hashtbl.mem consts (nameof dec) ->
+    Hashtbl.find consts (nameof dec)
+  | Dim (name, ann) when Hashtbl.mem consts name ->
+    Hashtbl.find consts name
+
+  (* Apply arithmetic simplification to constant operands *)
+  | Monop (op, opnd, ann) ->
+    eval (Monop (op, propagate opnd, ann))
+
+  | Binop (op, left, right, ann) ->
+    eval (Binop (op, propagate left, propagate right, ann))
+
+  | Cond (cond, texp, fexp, ann) ->
+    eval (Cond (propagate cond, propagate texp, propagate fexp, ann))
+
+  | TypeCast (ctype, value, ann) ->
+    let value = propagate value in
+    begin match (ctype, value) with
+    | (Bool,  Const (BoolVal  value, _)) -> Const (BoolVal value, ann)
+    | (Bool,  Const (IntVal   value, _)) -> Const (BoolVal (value != 1), ann)
+    | (Bool,  Const (FloatVal value, _)) -> Const (BoolVal (value != 1.0), ann)
+    | (Int,   Const (BoolVal  value, _)) -> Const (IntVal (if value then 1 else 0), ann)
+    | (Int,   Const (IntVal   value, _)) -> Const (IntVal value, ann)
+    | (Int,   Const (FloatVal value, _)) -> Const (IntVal (int_of_float value), ann)
+    | (Float, Const (BoolVal  value, _)) -> Const (FloatVal (if value then 1. else 0.), ann)
+    | (Float, Const (IntVal   value, _)) -> Const (FloatVal (float_of_int value), ann)
+    | (Float, Const (FloatVal value, _)) -> Const (FloatVal value, ann)
+    | _ -> TypeCast (ctype, value, ann)
+    end
+
+  | _ -> transform_children propagate node
 
 let rec prune_vardecs consts = function
-    | VarDec (_, name, _, _) when Hashtbl.mem consts name -> DummyNode
-    | node -> transform_children (prune_vardecs consts) node
+  | VarDec (_, name, _, _) when Hashtbl.mem consts name -> DummyNode
+  | node -> transform_children (prune_vardecs consts) node
 
 let phase = function
-    | Ast node ->
-        let consts = Hashtbl.create 32 in
-        let node = propagate consts node in
-        Ast (prune_vardecs consts node)
-    | _ -> raise (InvalidInput "constant propagation")
+  | Ast node ->
+    let consts = Hashtbl.create 32 in
+    let node = propagate consts node in
+    Ast (prune_vardecs consts node)
+  | _ -> raise (InvalidInput "constant propagation")

+ 125 - 125
phases/context.ml

@@ -8,139 +8,139 @@ type nametype = Varname of string | Funcname of string
 let type2str = function Funcname _ -> "function" | Varname _ -> "variable"
 
 let mapfind name tbl =
-    if Hashtbl.mem tbl name then Some (Hashtbl.find tbl name) else None
+  if Hashtbl.mem tbl name then Some (Hashtbl.find tbl name) else None
 
 let check_in_scope name errnode scope =
-    let (vars, funs) = scope in
-    let (name, tbl, other_map, desired_type) = match name with
-        | Varname  name -> (name, vars, funs, "variable")
-        | Funcname name -> (name, funs, vars, "function")
+  let (vars, funs) = scope in
+  let (name, tbl, other_map, desired_type) = match name with
+  | Varname  name -> (name, vars, funs, "variable")
+  | Funcname name -> (name, funs, vars, "function")
+  in
+  match mapfind name tbl with
+  | Some (dec, dec_depth, _) ->
+    (dec, dec_depth)
+  | None ->
+    let msg = match mapfind name other_map with
+    | Some _ -> sprintf "\"%s\" is not a %s" name desired_type
+    | None   -> sprintf "undefined %s \"%s\"" desired_type name
     in
-    match mapfind name tbl with
-    | Some (dec, dec_depth, _) ->
-        (dec, dec_depth)
-    | None ->
-        let msg = match mapfind name other_map with
-            | Some _ -> sprintf "\"%s\" is not a %s" name desired_type
-            | None   -> sprintf "undefined %s \"%s\"" desired_type name
-        in
-        raise (NodeError (errnode, msg))
+    raise (NodeError (errnode, msg))
 
 let add_to_scope name dec depth (vars, funs) =
-    let (name, tbl, name_type) = match name with
-        | Varname name  -> (name, vars, "variable")
-        | Funcname name -> (name, funs, "function")
-    in
-    match mapfind name tbl with
-    (* Identifiers of lower depth may be overwritten, but idenetifiers at
-        * the same depth must be unique for consistency *)
-    | Some (orig, orig_depth, _) when orig_depth >= depth ->
-        let msg = sprintf "Error: cannot redeclare %s \"%s\"" name_type name in
-        prerr_loc_msg (locof dec) msg;
-        prerr_loc_msg (locof orig) "Previously declared here:";
-        raise EmptyError
-    | Some _ ->
-        Hashtbl.replace tbl name (dec, depth, name_type)
-    | None ->
-        Hashtbl.add tbl name (dec, depth, name_type)
+  let (name, tbl, name_type) = match name with
+  | Varname name  -> (name, vars, "variable")
+  | Funcname name -> (name, funs, "function")
+  in
+  match mapfind name tbl with
+  (* Identifiers of lower depth may be overwritten, but idenetifiers at
+    * the same depth must be unique for consistency *)
+  | Some (orig, orig_depth, _) when orig_depth >= depth ->
+    let msg = sprintf "Error: cannot redeclare %s \"%s\"" name_type name in
+    prerr_loc_msg (locof dec) msg;
+    prerr_loc_msg (locof orig) "Previously declared here:";
+    raise EmptyError
+  | Some _ ->
+    Hashtbl.replace tbl name (dec, depth, name_type)
+  | None ->
+    Hashtbl.add tbl name (dec, depth, name_type)
 
 let rec analyse scope depth node =
-    let rec collect node = match node with
-        (* For variables, add the name (array dimensions are added
-         * implicitly, since they have separate VarDec nodes which were added
-         * during the desugaring phase *)
-        | VarDec (_, name, _, _)
-        | GlobalDec (_, name, _)
-        | GlobalDef (_, _, name, _, _) ->
-            let node = annotate (Depth depth) node in
-            add_to_scope (Varname name) node depth scope;
-            node
-
-        (* Functions are traversed later on, for now only add the name *)
-        | FunDec (_, name, _, _)
-        | FunDef (_, _, name, _, _, _) ->
-            let node = annotate (Depth depth) node in
-            add_to_scope (Funcname name) node depth scope;
-            node
-
-        (* For a variable or function call, look for its declaration in the
-         * current scope and save a its type/depth information  *)
-        | Var (name, dims, ann) ->
-            let (dec, dec_depth) = check_in_scope (Varname name) node scope in
-            VarUse (dec, optmap collect dims, Depth depth :: ann)
-
-        | FunCall (name, args, ann) ->
-            let (dec, dec_depth) = check_in_scope (Funcname name) node scope in
-            FunUse (dec, List.map collect args, Depth depth :: ann)
-
-        (* Assign statements are replaced with VarLet nodes, which stores the
-         * declaration of the assigned variable *)
-        | Assign (name, dims, value, ann) ->
-            let (dec, dec_depth) = check_in_scope (Varname name) node scope in
-            VarLet (dec, optmap collect dims, collect value, Depth depth :: ann)
-
-        | Allocate (dec, dims, ann) ->
-            let (dec, dec_depth) = check_in_scope (Varname (nameof dec)) node scope in
-            Allocate (dec, List.map collect dims, Depth depth :: ann)
-
-        | _ -> transform_children collect node
-    in
-
-    let rec traverse scope depth node =
-        match node with
-        (* Increase nesting level when entering function *)
-        | FunDef (export, ret_type, name, params, body, ann) ->
-            let (vars, funs) = scope in
-            let local_scope = (Hashtbl.copy vars, Hashtbl.copy funs) in
-            let params = List.map (traverse local_scope (depth + 1)) params in
-            let body = analyse local_scope (depth + 1) body in
-            FunDef (export, ret_type, name, params, body, ann)
-
-        | Param (ArrayDims (ctype, dims), name, ann) ->
-            let rec add_dims = function
-                | [] -> []
-                | Dim (name, ann) :: tl ->
-                    let dim = Dim (name, Depth depth :: ann) in
-                    add_to_scope (Varname name) dim depth scope;
-                    dim :: (add_dims tl)
-                | _ -> raise InvalidNode
-            in
-            let node = Param (ArrayDims (ctype, add_dims dims), name, ann) in
-            add_to_scope (Varname name) node depth scope;
-            node
-
-        | VarDec _ -> node
-
-        | Param (_, name, _) ->
-            let node = annotate (Depth depth) node in
-            add_to_scope (Varname name) node depth scope;
-            node
-
-        (* Do not traverse into external function declarations, since their
-         * parameters must not be added to the namespace *)
-        | FunDec _ -> node
-
-        | _ -> transform_children (traverse scope depth) node
-    in
-
-    (*
-     * First collect all definitions at the current depth. Then, traverse into
-     * functions with a copy of the current scope. This is needed because
-     * functions can access all identifiers in their surrounding scope.
-     * E.g., the following is allowed:
-     *
-     * void foo() { glob = 1; }
-     * int glob;
-     *)
-    let node = collect node in
-
-    let node = traverse scope depth node in
-    node
+  let rec collect node = match node with
+    (* For variables, add the name (array dimensions are added
+     * implicitly, since they have separate VarDec nodes which were added
+     * during the desugaring phase *)
+    | VarDec (_, name, _, _)
+    | GlobalDec (_, name, _)
+    | GlobalDef (_, _, name, _, _) ->
+      let node = annotate (Depth depth) node in
+      add_to_scope (Varname name) node depth scope;
+      node
+
+    (* Functions are traversed later on, for now only add the name *)
+    | FunDec (_, name, _, _)
+    | FunDef (_, _, name, _, _, _) ->
+      let node = annotate (Depth depth) node in
+      add_to_scope (Funcname name) node depth scope;
+      node
+
+    (* For a variable or function call, look for its declaration in the
+     * current scope and save a its type/depth information  *)
+    | Var (name, dims, ann) ->
+      let (dec, dec_depth) = check_in_scope (Varname name) node scope in
+      VarUse (dec, optmap collect dims, Depth depth :: ann)
+
+    | FunCall (name, args, ann) ->
+      let (dec, dec_depth) = check_in_scope (Funcname name) node scope in
+      FunUse (dec, List.map collect args, Depth depth :: ann)
+
+    (* Assign statements are replaced with VarLet nodes, which stores the
+     * declaration of the assigned variable *)
+    | Assign (name, dims, value, ann) ->
+      let (dec, dec_depth) = check_in_scope (Varname name) node scope in
+      VarLet (dec, optmap collect dims, collect value, Depth depth :: ann)
+
+    | Allocate (dec, dims, ann) ->
+      let (dec, dec_depth) = check_in_scope (Varname (nameof dec)) node scope in
+      Allocate (dec, List.map collect dims, Depth depth :: ann)
+
+    | _ -> transform_children collect node
+  in
+
+  let rec traverse scope depth node =
+    match node with
+    (* Increase nesting level when entering function *)
+    | FunDef (export, ret_type, name, params, body, ann) ->
+      let (vars, funs) = scope in
+      let local_scope = (Hashtbl.copy vars, Hashtbl.copy funs) in
+      let params = List.map (traverse local_scope (depth + 1)) params in
+      let body = analyse local_scope (depth + 1) body in
+      FunDef (export, ret_type, name, params, body, ann)
+
+    | Param (ArrayDims (ctype, dims), name, ann) ->
+      let rec add_dims = function
+        | [] -> []
+        | Dim (name, ann) :: tl ->
+          let dim = Dim (name, Depth depth :: ann) in
+          add_to_scope (Varname name) dim depth scope;
+          dim :: (add_dims tl)
+        | _ -> raise InvalidNode
+      in
+      let node = Param (ArrayDims (ctype, add_dims dims), name, ann) in
+      add_to_scope (Varname name) node depth scope;
+      node
+
+    | VarDec _ -> node
+
+    | Param (_, name, _) ->
+      let node = annotate (Depth depth) node in
+      add_to_scope (Varname name) node depth scope;
+      node
+
+    (* Do not traverse into external function declarations, since their
+     * parameters must not be added to the namespace *)
+    | FunDec _ -> node
+
+    | _ -> transform_children (traverse scope depth) node
+  in
+
+  (*
+   * First collect all definitions at the current depth. Then, traverse into
+   * functions with a copy of the current scope. This is needed because
+   * functions can access all identifiers in their surrounding scope.
+   * E.g., the following is allowed:
+   *
+   * void foo() { glob = 1; }
+   * int glob;
+   *)
+  let node = collect node in
+
+  let node = traverse scope depth node in
+  node
 
 let analyse_context program =
-    let scope = (Hashtbl.create 20, Hashtbl.create 20) in
-    analyse scope 0 program
+  let scope = (Hashtbl.create 20, Hashtbl.create 20) in
+  analyse scope 0 program
 
 let phase = function
-    | Ast node -> Ast (analyse_context node)
-    | _ -> raise (InvalidInput "context analysis")
+  | Ast node -> Ast (analyse_context node)
+  | _ -> raise (InvalidInput "context analysis")

+ 246 - 246
phases/desug.ml

@@ -6,282 +6,282 @@ open Globals
 (* Create new constant variables for all assigned array values so that they are
  * only evaluated once *)
 let rec consts_to_vars node =
-    let rec create_vars new_vars values = function
-        | [] -> (new_vars, values)
-        | hd :: tl ->
-            let (new_vars, value) = match hd with
-                | ArrayConst (values, ann) ->
-                    let (new_vars, values) = create_vars new_vars [] values in
-                    (new_vars, ArrayConst (values, ann))
-                | value ->
-                    let index = fresh_const "const" in
-                    (new_vars @ [(index, value)], Var (index, None, annof value))
-            in
-            create_vars new_vars (values @ [value]) tl
+  let rec create_vars new_vars values = function
+    | [] -> (new_vars, values)
+    | hd :: tl ->
+      let (new_vars, value) = match hd with
+        | ArrayConst (values, ann) ->
+          let (new_vars, values) = create_vars new_vars [] values in
+          (new_vars, ArrayConst (values, ann))
+        | value ->
+          let index = fresh_const "const" in
+          (new_vars @ [(index, value)], Var (index, None, annof value))
+      in
+      create_vars new_vars (values @ [value]) tl
+  in
+  match node with
+  (* Add vardecs for values in arrayconst *)
+  | VarDec (ArrayDims _ as ctype, name, Some (ArrayConst (values, vann)), ann) ->
+    let (new_vars, values) = create_vars [] [] values in
+    let value = ArrayConst (values, vann) in
+    let create_vardec (name, value) =
+      VarDec (basetypeof node, name, Some value, annof value)
     in
-    match node with
-    (* Add vardecs for values in arrayconst *)
-    | VarDec (ArrayDims _ as ctype, name, Some (ArrayConst (values, vann)), ann) ->
-        let (new_vars, values) = create_vars [] [] values in
-        let value = ArrayConst (values, vann) in
-        let create_vardec (name, value) =
-            VarDec (basetypeof node, name, Some value, annof value)
-        in
-        let new_vardecs = List.map create_vardec new_vars in
-        Block (new_vardecs @ [VarDec (ctype, name, Some value, ann)])
+    let new_vardecs = List.map create_vardec new_vars in
+    Block (new_vardecs @ [VarDec (ctype, name, Some value, ann)])
 
-    (* Add vardec for scalar value *)
-    | VarDec (ArrayDims _ as ctype, name, Some value, ann) as node ->
-        let scalar_name = fresh_const "scalar" in
-        Block [
-            VarDec (basetypeof node, scalar_name, Some value, ann);
-            VarDec (ctype, name, Some (Var (scalar_name, None, annof value)), ann);
-        ]
+  (* Add vardec for scalar value *)
+  | VarDec (ArrayDims _ as ctype, name, Some value, ann) as node ->
+    let scalar_name = fresh_const "scalar" in
+    Block [
+      VarDec (basetypeof node, scalar_name, Some value, ann);
+      VarDec (ctype, name, Some (Var (scalar_name, None, annof value)), ann);
+    ]
 
-    | node -> transform_children consts_to_vars node
+  | node -> transform_children consts_to_vars node
 
 (* Generate new variables for array dimensions, to avoid re-evalutation when
  * array dimensions are used (e.g., after array dimension reduction). *)
 let rec array_dims node =
-    let make_dims basename values make_dec =
-        let make_name i _ = fresh_const (basename ^ "$dim$" ^ string_of_int (i + 1)) in
-        let names = mapi make_name values in
-
-        let decs = List.map2 make_dec values names in
-
-        let make_dim value name = Dim (name, annof value) in
-        let dims = List.map2 make_dim values names in
-
-        (decs, dims)
+  let make_dims basename values make_dec =
+    let make_name i _ = fresh_const (basename ^ "$dim$" ^ string_of_int (i + 1)) in
+    let names = mapi make_name values in
+
+    let decs = List.map2 make_dec values names in
+
+    let make_dim value name = Dim (name, annof value) in
+    let dims = List.map2 make_dim values names in
+
+    (decs, dims)
+  in
+  match node with
+  | VarDec (ArrayDims (ctype, values), name, init, ann) ->
+    let make_dec value name = VarDec (Int, name, Some value, []) in
+    let (decs, dims) = make_dims name values make_dec in
+    Block (decs @ [VarDec (ArrayDims (ctype, dims), name, init, ann)])
+
+  | GlobalDef (export, ArrayDims (ctype, values), name, None, ann) ->
+    let make_dec value name = GlobalDef (export, Int, name, Some value, []) in
+    let (decs, dims) = make_dims name values make_dec in
+    Block (decs @ [GlobalDef (export, ArrayDims (ctype, dims), name, None, ann)])
+
+  | GlobalDec (ArrayDims (ctype, dims), name, ann) ->
+    let rec make_decs = function
+      | [] -> []
+      | Dim (name, ann) :: tl -> GlobalDec (Int, name, ann) :: (make_decs tl)
+      | _ -> raise InvalidNode
     in
-    match node with
-    | VarDec (ArrayDims (ctype, values), name, init, ann) ->
-        let make_dec value name = VarDec (Int, name, Some value, []) in
-        let (decs, dims) = make_dims name values make_dec in
-        Block (decs @ [VarDec (ArrayDims (ctype, dims), name, init, ann)])
-
-    | GlobalDef (export, ArrayDims (ctype, values), name, None, ann) ->
-        let make_dec value name = GlobalDef (export, Int, name, Some value, []) in
-        let (decs, dims) = make_dims name values make_dec in
-        Block (decs @ [GlobalDef (export, ArrayDims (ctype, dims), name, None, ann)])
-
-    | GlobalDec (ArrayDims (ctype, dims), name, ann) ->
-        let rec make_decs = function
-            | [] -> []
-            | Dim (name, ann) :: tl -> GlobalDec (Int, name, ann) :: (make_decs tl)
-            | _ -> raise InvalidNode
-        in
-        let decs = make_decs dims in
-        Block (decs @ [GlobalDec (ArrayDims (ctype, dims), name, ann)])
+    let decs = make_decs dims in
+    Block (decs @ [GlobalDec (ArrayDims (ctype, dims), name, ann)])
 
-    | node -> transform_children array_dims node
+  | node -> transform_children array_dims node
 
 (* Split variable initialisation into declaration and assignment *)
 let rec split_inits = function
-    (* Wrap array initialisation in ArrayInit to pass dimensions *)
-    | VarDec (ArrayDims (_, dims) as ctype, name, Some value, ann) ->
-        Block [
-            VarDec (ctype, name, None, ann);
-            Assign (name, None, ArrayInit (value, dims), ann);
-        ]
-
-    | VarDec (ctype, name, Some init, ann) ->
-        Block [
-            VarDec (ctype, name, None, ann);
-            Assign (name, None, init, ann);
-        ]
-
-    | GlobalDef (export, ctype, name, Some init, ann) ->
-        Block [
-            GlobalDef (export, ctype, name, None, ann);
-            Assign (name, None, init, ann);
-        ]
-
-    | node -> transform_children split_inits node
+  (* Wrap array initialisation in ArrayInit to pass dimensions *)
+  | VarDec (ArrayDims (_, dims) as ctype, name, Some value, ann) ->
+    Block [
+      VarDec (ctype, name, None, ann);
+      Assign (name, None, ArrayInit (value, dims), ann);
+    ]
+
+  | VarDec (ctype, name, Some init, ann) ->
+    Block [
+      VarDec (ctype, name, None, ann);
+      Assign (name, None, init, ann);
+    ]
+
+  | GlobalDef (export, ctype, name, Some init, ann) ->
+    Block [
+      GlobalDef (export, ctype, name, None, ann);
+      Assign (name, None, init, ann);
+    ]
+
+  | node -> transform_children split_inits node
 
 (* Add <allocate> statements after array declarations *)
 let rec add_allocs node =
-    let create_dimvar = function
-        | Dim (name, _) -> Var (name, None, [])
-        | _ -> raise InvalidNode
-    in
-    match node with
-    | VarDec (ArrayDims (_, dims), _, _, ann) ->
-        Block [node; Allocate (node, List.map create_dimvar dims, ann)]
+  let create_dimvar = function
+    | Dim (name, _) -> Var (name, None, [])
+    | _ -> raise InvalidNode
+  in
+  match node with
+  | VarDec (ArrayDims (_, dims), _, _, ann) ->
+    Block [node; Allocate (node, List.map create_dimvar dims, ann)]
 
-    | GlobalDef (_, ArrayDims (_, dims), _, _, ann) ->
-        Block [node; Allocate (node, List.map create_dimvar dims, ann)]
+  | GlobalDef (_, ArrayDims (_, dims), _, _, ann) ->
+    Block [node; Allocate (node, List.map create_dimvar dims, ann)]
 
-    | node -> transform_children add_allocs node
+  | node -> transform_children add_allocs node
 
 let extract_inits lst =
-    let rec trav inits = function
-        | [] ->
-            (List.rev inits, [])
-        | (Assign _ as hd) :: tl
-        | (Allocate _ as hd) :: tl ->
-            trav (hd :: inits) tl
-        | hd :: tl ->
-            let (inits, tl) = trav inits tl in
-            (inits, (hd :: tl))
-    in trav [] lst
+  let rec trav inits = function
+    | [] ->
+      (List.rev inits, [])
+    | (Assign _ as hd) :: tl
+    | (Allocate _ as hd) :: tl ->
+      trav (hd :: inits) tl
+    | hd :: tl ->
+      let (inits, tl) = trav inits tl in
+      (inits, (hd :: tl))
+  in trav [] lst
 
 let rec move_inits = function
-    (* Move global initialisations to __init function *)
-    | Program (decls, ann) ->
-        let decls = List.map move_inits decls in
-        (match extract_inits decls with
-        | ([], _) -> Program (decls, ann)
-        | (inits, decls) ->
-            let init_func = FunDef (true, Void, "__init", [], Block inits, []) in
-            Program (init_func :: decls, ann)
-        )
-
-    (* Split local variable initialisations in declaration and assignment *)
-    | FunDef (export, ret_type, name, params, Block body, ann) ->
-        let rec place_inits inits = function
-            | VarDecs lst :: tl ->
-                let (inits, decs) = extract_inits lst in
-                VarDecs decs :: (place_inits inits tl)
-            | LocalFuns _ as hd :: tl ->
-                hd :: inits @ tl
-            | _ -> raise InvalidNode
-        in
-        let body = Block (place_inits [] body) in
-        FunDef (export, ret_type, name, params, body, ann)
+  (* Move global initialisations to __init function *)
+  | Program (decls, ann) ->
+    let decls = List.map move_inits decls in
+    begin match extract_inits decls with
+    | ([], _) -> Program (decls, ann)
+    | (inits, decls) ->
+      let init_func = FunDef (true, Void, "__init", [], Block inits, []) in
+      Program (init_func :: decls, ann)
+    end
+
+  (* Split local variable initialisations in declaration and assignment *)
+  | FunDef (export, ret_type, name, params, Block body, ann) ->
+    let rec place_inits inits = function
+      | VarDecs lst :: tl ->
+        let (inits, decs) = extract_inits lst in
+        VarDecs decs :: (place_inits inits tl)
+      | LocalFuns _ as hd :: tl ->
+        hd :: inits @ tl
+      | _ -> raise InvalidNode
+    in
+    let body = Block (place_inits [] body) in
+    FunDef (export, ret_type, name, params, body, ann)
 
-    | node -> transform_children move_inits node
+  | node -> transform_children move_inits node
 
 let for_to_while node =
-    let rec replace_var var replacement node =
-        let trav = (replace_var var replacement) in
-        match node with
-        | Var (name, None, ann) when name = var ->
-            Var (replacement, None, ann)
-        | For (counter, start, stop, step, body, ann) when counter = var ->
-            For (replacement, trav start, trav stop, trav step, trav body, ann)
-        | node ->
-            transform_children trav node
-    in
-    let rec traverse new_vars = function
-        | FunDef (export, ret_type, name, params, body, ann) ->
-            let new_vars = ref [] in
-            let body = traverse new_vars body in
-            let create_vardec name = VarDec (Int, name, None, []) in
-            let new_vardecs = List.map create_vardec !new_vars in
-            let _body = new_vardecs @ (flatten_blocks (block_body body)) in
-            FunDef (export, ret_type, name, params, Block _body, ann)
-
-        (* Transform for-loops to while-loops *)
-        | For (counter, start, stop, step, body, ann) ->
-            let _i = fresh_var counter in
-            let _stop = fresh_const "stop" in
-            let _step = fresh_const "step" in
-            new_vars := !new_vars @ [_i; _stop; _step];
-
-            let vi = Var (_i, None, []) in
-            let vstop = Var (_stop, None, annof stop) in
-            let vstep = Var (_step, None, annof step) in
-            let cond = Cond (
-                Binop (Gt, vstep, Const (IntVal 0, []), []),
-                Binop (Lt, vi, vstop, []),
-                Binop (Gt, vi, vstop, []),
-                []
-            ) in
-            Block [
-                Assign (_i, None, start, annof start);
-                Assign (_stop, None, stop, annof stop);
-                Assign (_step, None, step, annof step);
-                traverse new_vars (While (cond, (Block (
-                    block_body (replace_var counter _i body) @
-                    [Assign (_i, None, Binop (Add, vi, vstep, []), [])]
-                )), ann));
-            ]
-
-        (* DISABLED, while-loops are explicitly supported by the assembly phase
-        (* Transform while-loops to do-while loops in if-statements *)
-        | While (cond, body, ann) ->
-            let cond = traverse new_vars cond in
-            let body = traverse new_vars body in
-            Block [If (cond, Block [DoWhile (cond, body, ann)], ann)]
-        *)
-
-        | node -> transform_children (traverse new_vars) node
-    in
-    traverse (ref []) node
+  let rec replace_var var replacement node =
+    let trav = (replace_var var replacement) in
+    match node with
+    | Var (name, None, ann) when name = var ->
+      Var (replacement, None, ann)
+    | For (counter, start, stop, step, body, ann) when counter = var ->
+      For (replacement, trav start, trav stop, trav step, trav body, ann)
+    | node ->
+      transform_children trav node
+  in
+  let rec traverse new_vars = function
+    | FunDef (export, ret_type, name, params, body, ann) ->
+      let new_vars = ref [] in
+      let body = traverse new_vars body in
+      let create_vardec name = VarDec (Int, name, None, []) in
+      let new_vardecs = List.map create_vardec !new_vars in
+      let _body = new_vardecs @ (flatten_blocks (block_body body)) in
+      FunDef (export, ret_type, name, params, Block _body, ann)
+
+    (* Transform for-loops to while-loops *)
+    | For (counter, start, stop, step, body, ann) ->
+      let _i = fresh_var counter in
+      let _stop = fresh_const "stop" in
+      let _step = fresh_const "step" in
+      new_vars := !new_vars @ [_i; _stop; _step];
+
+      let vi = Var (_i, None, []) in
+      let vstop = Var (_stop, None, annof stop) in
+      let vstep = Var (_step, None, annof step) in
+      let cond = Cond (
+        Binop (Gt, vstep, Const (IntVal 0, []), []),
+        Binop (Lt, vi, vstop, []),
+        Binop (Gt, vi, vstop, []),
+        []
+      ) in
+      Block [
+        Assign (_i, None, start, annof start);
+        Assign (_stop, None, stop, annof stop);
+        Assign (_step, None, step, annof step);
+        traverse new_vars (While (cond, (Block (
+          block_body (replace_var counter _i body) @
+          [Assign (_i, None, Binop (Add, vi, vstep, []), [])]
+        )), ann));
+      ]
+
+    (* DISABLED, while-loops are explicitly supported by the assembly phase
+    (* Transform while-loops to do-while loops in if-statements *)
+    | While (cond, body, ann) ->
+      let cond = traverse new_vars cond in
+      let body = traverse new_vars body in
+      Block [If (cond, Block [DoWhile (cond, body, ann)], ann)]
+    *)
+
+    | node -> transform_children (traverse new_vars) node
+  in
+  traverse (ref []) node
 
 let rec sublist n = function
-    | [] when n > 0  -> raise (Invalid_argument "n")
-    | []             -> []
-    | lst when n = 0 -> lst
-    | _ :: tl        -> sublist (n - 1) tl
+  | [] when n > 0  -> raise (Invalid_argument "n")
+  | []       -> []
+  | lst when n = 0 -> lst
+  | _ :: tl    -> sublist (n - 1) tl
 
 let rec array_init = function
-    (* Transform array constant inisialisation into separate assign statements
-     * for all entries in the constant array *)
-    (* TODO: only allow when array dimensions are constant? *)
-    | Assign (name, None, ArrayInit (ArrayConst _ as value, dims), ann) ->
-        let ndims = List.length dims in
-        let rec make_assigns depth i indices = function
-            | [] -> []
-            | hd :: tl ->
-                let assigns = traverse depth (i :: indices) hd in
-                make_assigns depth (i + 1) indices tl @ assigns
-        and traverse depth indices = function
-            | ArrayConst (values, _) ->
-                make_assigns (depth + 1) 0 indices values
-            | value when depth = ndims ->
-                let indices = List.map (fun i -> Const (IntVal i, [])) indices in
-                [Assign (name, Some (List.rev indices), value, ann)]
-            | value when depth < ndims ->
-                (* Use the for-loops constructed for scalar assignment *)
-                let value = ArrayInit (value, dims) in
-                let indices = List.map (fun i -> Const (IntVal i, [])) indices in
-                [array_init (Assign (name, Some (List.rev indices), value, ann))]
-            | node ->
-                let msg = sprintf
-                    "dimension mismatch: expected %d nesting levels, got %d"
-                    ndims depth
-                in
-                raise (NodeError (node, msg))
+  (* Transform array constant inisialisation into separate assign statements
+   * for all entries in the constant array *)
+  (* TODO: only allow when array dimensions are constant? *)
+  | Assign (name, None, ArrayInit (ArrayConst _ as value, dims), ann) ->
+    let ndims = List.length dims in
+    let rec make_assigns depth i indices = function
+      | [] -> []
+      | hd :: tl ->
+        let assigns = traverse depth (i :: indices) hd in
+        make_assigns depth (i + 1) indices tl @ assigns
+    and traverse depth indices = function
+      | ArrayConst (values, _) ->
+        make_assigns (depth + 1) 0 indices values
+      | value when depth = ndims ->
+        let indices = List.map (fun i -> Const (IntVal i, [])) indices in
+        [Assign (name, Some (List.rev indices), value, ann)]
+      | value when depth < ndims ->
+        (* Use the for-loops constructed for scalar assignment *)
+        let value = ArrayInit (value, dims) in
+        let indices = List.map (fun i -> Const (IntVal i, [])) indices in
+        [array_init (Assign (name, Some (List.rev indices), value, ann))]
+      | node ->
+        let msg = sprintf
+          "dimension mismatch: expected %d nesting levels, got %d"
+          ndims depth
         in
-        Block (List.rev (traverse 0 [] value))
-
-    (* Replace no indices with empty indices to have a list below *)
-    | Assign (name, None, (ArrayInit _ as value), ann) ->
-        array_init (Assign (name, Some [], value, ann))
-
-    | Assign (name, Some indices, ArrayInit (value, dims), ann) as node ->
-        let rec add_loop indices = function
-            | [] ->
-                array_init (Assign (name, Some indices, value, ann))
-            | dim :: rest ->
-                let counter = fresh_var "i" in
-                let start = Const (IntVal 0, []) in
-                let step = Const (IntVal 1, []) in
-                let body = Block [add_loop (indices @ [Var (counter, None, [])]) rest] in
-                let stop = match dim with
-                    | Dim (name, ann) -> Var (name, None, ann)
-                    | _ -> dim
-                in
-                For (counter, start, stop, step, body, [])
+        raise (NodeError (node, msg))
+    in
+    Block (List.rev (traverse 0 [] value))
+
+  (* Replace no indices with empty indices to have a list below *)
+  | Assign (name, None, (ArrayInit _ as value), ann) ->
+    array_init (Assign (name, Some [], value, ann))
+
+  | Assign (name, Some indices, ArrayInit (value, dims), ann) as node ->
+    let rec add_loop indices = function
+      | [] ->
+        array_init (Assign (name, Some indices, value, ann))
+      | dim :: rest ->
+        let counter = fresh_var "i" in
+        let start = Const (IntVal 0, []) in
+        let step = Const (IntVal 1, []) in
+        let body = Block [add_loop (indices @ [Var (counter, None, [])]) rest] in
+        let stop = match dim with
+        | Dim (name, ann) -> Var (name, None, ann)
+        | _ -> dim
         in
-        let dims_left = sublist (List.length indices) dims in
-        add_loop indices dims_left
+        For (counter, start, stop, step, body, [])
+    in
+    let dims_left = sublist (List.length indices) dims in
+    add_loop indices dims_left
 
-    | node -> transform_children array_init node
+  | node -> transform_children array_init node
 
 let phase = function
-    | Ast node ->
-        (* Generate variable declarations for expressions that must be evaluated
-         * once and used multiple times *)
-        let node = consts_to_vars (array_dims node) in
-
-        (* Split variable initialisations into declarations and assignments, and
-         * move the assignments to the function body *)
-        let node = move_inits (add_allocs (split_inits node)) in
-
-        (* Transform ArrayConst assignment to assignments in for-loops, and
-         * transform all for-loops to while-loops afterwards *)
-        Ast (for_to_while (array_init (node)))
-    | _ -> raise (InvalidInput "desugar")
+  | Ast node ->
+    (* Generate variable declarations for expressions that must be evaluated
+     * once and used multiple times *)
+    let node = consts_to_vars (array_dims node) in
+
+    (* Split variable initialisations into declarations and assignments, and
+     * move the assignments to the function body *)
+    let node = move_inits (add_allocs (split_inits node)) in
+
+    (* Transform ArrayConst assignment to assignments in for-loops, and
+     * transform all for-loops to while-loops afterwards *)
+    Ast (for_to_while (array_init (node)))
+  | _ -> raise (InvalidInput "desugar")

+ 89 - 89
phases/dimreduce.ml

@@ -3,102 +3,102 @@ open Util
 open Globals
 
 let rec expand_dims = function
-    (* Flatten Block nodes returned by transformations below *)
-    | FunDef (export, ret_type, name, params, body, ann) ->
-        let params = flatten_blocks (List.map expand_dims params) in
-        FunDef (export, ret_type, name, params, expand_dims body, ann)
-
-    | FunDec (ret_type, name, params, ann) ->
-        let params = flatten_blocks (List.map expand_dims params) in
-        FunDec (ret_type, name, params, ann)
-
-    | FunUse (dec, params, ann) ->
-        FunUse (dec, flatten_blocks (List.map expand_dims params), ann)
-
-    (* Add additional parameters for array dimensions *)
-    | Param (ArrayDims (ctype, dims), name, ann) ->
-        let rec do_expand = function
-            | [] -> [Param (Array ctype, name, ann)]
-            | Dim (name, ann) :: tail ->
-                Param (Int, name, ann) :: (do_expand tail)
-            | _ -> raise InvalidNode
-        in
-        Block (do_expand dims)
-
-    (* Add additional function arguments for array dimensions *)
-    | Arg (VarUse (VarDec (ArrayDims (ctype, dims), name, None, decann), None, ann)) ->
-        let rec do_expand = function
-            | [] ->
-                (* Remove the (now obsolete dimensions fromt the type) *)
-                let dec = VarDec (Array ctype, name, None, decann) in
-                [VarUse (dec, None, ann)]
-            | hd :: tl ->
-                (* A VarDec node has been added for each dimension during
-                 * desugaring, so we can safely reconstruct it here (we need no
-                 * refrence because the type is immutable, yay!) *)
-                let dimdec = VarDec (Int, nameof hd, None, annof hd) in
-                Arg (VarUse (dimdec, None, [])) :: (do_expand tl)
-        in
-        Block (do_expand dims)
-
-    (* Simplify array types in declarations *)
-    | VarDec (ArrayDims (ctype, _), name, None, ann) ->
-        VarDec (Array ctype, name, None, ann)
-
-    | node -> transform_children expand_dims node
+  (* Flatten Block nodes returned by transformations below *)
+  | FunDef (export, ret_type, name, params, body, ann) ->
+    let params = flatten_blocks (List.map expand_dims params) in
+    FunDef (export, ret_type, name, params, expand_dims body, ann)
+
+  | FunDec (ret_type, name, params, ann) ->
+    let params = flatten_blocks (List.map expand_dims params) in
+    FunDec (ret_type, name, params, ann)
+
+  | FunUse (dec, params, ann) ->
+    FunUse (dec, flatten_blocks (List.map expand_dims params), ann)
+
+  (* Add additional parameters for array dimensions *)
+  | Param (ArrayDims (ctype, dims), name, ann) ->
+    let rec do_expand = function
+      | [] -> [Param (Array ctype, name, ann)]
+      | Dim (name, ann) :: tail ->
+        Param (Int, name, ann) :: (do_expand tail)
+      | _ -> raise InvalidNode
+    in
+    Block (do_expand dims)
+
+  (* Add additional function arguments for array dimensions *)
+  | Arg (VarUse (VarDec (ArrayDims (ctype, dims), name, None, decann), None, ann)) ->
+    let rec do_expand = function
+      | [] ->
+        (* Remove the (now obsolete dimensions fromt the type) *)
+        let dec = VarDec (Array ctype, name, None, decann) in
+        [VarUse (dec, None, ann)]
+      | hd :: tl ->
+        (* A VarDec node has been added for each dimension during
+         * desugaring, so we can safely reconstruct it here (we need no
+         * refrence because the type is immutable, yay!) *)
+        let dimdec = VarDec (Int, nameof hd, None, annof hd) in
+        Arg (VarUse (dimdec, None, [])) :: (do_expand tl)
+    in
+    Block (do_expand dims)
+
+  (* Simplify array types in declarations *)
+  | VarDec (ArrayDims (ctype, _), name, None, ann) ->
+    VarDec (Array ctype, name, None, ann)
+
+  | node -> transform_children expand_dims node
 
 let rec multiply = function
-    | []       -> raise InvalidNode
-    | [node]   -> node
-    | hd :: tl -> Binop (Mul, hd, multiply tl, [Type Int])
+  | []       -> raise InvalidNode
+  | [node]   -> node
+  | hd :: tl -> Binop (Mul, hd, multiply tl, [Type Int])
 
 let rec multiply_all = function
-    | []       -> raise InvalidNode
-    | [node]   -> node
-    | hd :: tl -> Binop (Mul, hd, multiply_all tl, [])
+  | []       -> raise InvalidNode
+  | [node]   -> node
+  | hd :: tl -> Binop (Mul, hd, multiply_all tl, [])
 
 let rec expand depth dims =
-    let rec do_expand dims = function
-        | []       -> raise InvalidNode
-        | [node]   -> dim_reduce depth node
-        | i :: j :: tl ->
-            let parent_width = List.hd dims in
-            let mul = Binop (Mul, dim_reduce depth i, parent_width, [Type Int]) in
-            do_expand (List.tl dims) (Binop (Add, mul, j, [Type Int]) :: tl)
-    in
-    let use_dim = function
-        | Dim _ as dim -> VarUse (dim, None, [Type Int; Depth depth])
-        | node -> node
-    in
-    do_expand (List.map use_dim (List.tl dims))
+  let rec do_expand dims = function
+    | []       -> raise InvalidNode
+    | [node]   -> dim_reduce depth node
+    | i :: j :: tl ->
+      let parent_width = List.hd dims in
+      let mul = Binop (Mul, dim_reduce depth i, parent_width, [Type Int]) in
+      do_expand (List.tl dims) (Binop (Add, mul, j, [Type Int]) :: tl)
+  in
+  let use_dim = function
+    | Dim _ as dim -> VarUse (dim, None, [Type Int; Depth depth])
+    | node -> node
+  in
+  do_expand (List.map use_dim (List.tl dims))
 
 and dim_reduce depth = function
-    | Allocate (dec, dims, ann) ->
-        Allocate (dec, [multiply dims], ann)
-
-    (* Increase nesting depth when goiing into function *)
-    | FunDef (export, ret_type, name, params, body, ann) ->
-        let trav = dim_reduce (depth + 1) in
-        FunDef (export, ret_type, name, List.map trav params, trav body, ann)
-
-    (* Expand indices when dereferencing *)
-    | VarUse (dec, Some values, ann) as node ->
-        (match typeof dec with
-        | ArrayDims (_, dims) ->
-            VarUse (dec, Some [expand depth dims values], ann)
-        | _ -> node
-        )
-
-    (* Expand indices when assigning to array index *)
-    | VarLet (dec, Some values, value, ann) as node ->
-        (match typeof dec with
-        | ArrayDims (_, dims) ->
-            VarLet (dec, Some [expand depth dims values], value, ann)
-        | _ -> node
-        )
-
-    | node -> transform_children (dim_reduce depth) node
+  | Allocate (dec, dims, ann) ->
+    Allocate (dec, [multiply dims], ann)
+
+  (* Increase nesting depth when goiing into function *)
+  | FunDef (export, ret_type, name, params, body, ann) ->
+    let trav = dim_reduce (depth + 1) in
+    FunDef (export, ret_type, name, List.map trav params, trav body, ann)
+
+  (* Expand indices when dereferencing *)
+  | VarUse (dec, Some values, ann) as node ->
+    begin match typeof dec with
+    | ArrayDims (_, dims) ->
+      VarUse (dec, Some [expand depth dims values], ann)
+    | _ -> node
+    end
+
+  (* Expand indices when assigning to array index *)
+  | VarLet (dec, Some values, value, ann) as node ->
+    begin match typeof dec with
+    | ArrayDims (_, dims) ->
+      VarLet (dec, Some [expand depth dims values], value, ann)
+    | _ -> node
+    end
+
+  | node -> transform_children (dim_reduce depth) node
 
 let phase = function
-    | Ast node -> Ast (dim_reduce 0 (expand_dims node))
-    | _ -> raise (InvalidInput "dimension reduction")
+  | Ast node -> Ast (dim_reduce 0 (expand_dims node))
+  | _ -> raise (InvalidInput "dimension reduction")

+ 89 - 90
phases/extern.ml

@@ -3,113 +3,112 @@ open Util
 open Globals
 
 let create_param ctype name =
-    let param = Param (ctype, name, [Depth 1]) in
-    let value = VarUse (param, None, [Type ctype; Depth 1]) in
-    (param, value)
+  let param = Param (ctype, name, [Depth 1]) in
+  let value = VarUse (param, None, [Type ctype; Depth 1]) in
+  (param, value)
 
-let call node args depth = match node with
-    | FunDec (ctype, name, _, _) as dec ->
-        FunUse (dec, args, [Type ctype; Depth depth])
-    | _ -> raise InvalidNode
+let call node args depth =
+  match node with
+  | FunDec (ctype, name, _, _) as dec ->
+    FunUse (dec, args, [Type ctype; Depth depth])
+  | _ -> raise InvalidNode
 
 let process globals = function
-    | GlobalDef (true, Array ctype, name, None, ann) as dec ->
-        (* Getters for array variable: crate getter for given index Note that
-         * getters and setters for dimensions are automatically generated,
-         * because they have been put into new global variables during the
-         * desugarin phase *)
-        let (param, index) = create_param Int (fresh_var "index") in
-        let var = VarUse (dec, Some [index], [Type ctype; Depth 1]) in
-        let body = Block [Return (var, [])] in
-        let getter = FunDef (true, ctype, name ^ "$get", [param], body, []) in
-
-        (* Setters for array variable: create setter for given index *)
-        let (param1, index) = create_param Int (fresh_var "index") in
-        let (param2, value) = create_param ctype (fresh_var "value") in
-        let body = Block [VarLet (dec, Some [index], value, [])] in
-        let setter = FunDef (true, Void, name ^ "$set", [param1; param2], body, []) in
-
-        [getter; setter]
-
-    | GlobalDef (true, ctype, name, None, ann) as dec ->
-        (* Getter for basic variable type: return the variable *)
-        let var = VarUse (dec, None, [Type ctype; Depth 1]) in
-        let body = [Return (var, [])] in
-        let getter = FunDef (true, ctype, name ^ "$get", [], Block body, []) in
-
-        (* Setter for basic variable type: assign the variable *)
-        let (param, value) = create_param ctype (fresh_var "value") in
-        let body = [VarLet (dec, None, value, [])] in
-        let setter = FunDef (true, Void, name ^ "$set", [param], Block body, []) in
-
-        [getter; setter]
-
-    | GlobalDec (Array ctype, name, ann) ->
-        (* Getters for external array variable: create getter and setter for a
-         * given index *)
-        let (param, _) = create_param Int "index" in
-        let getter = FunDec (ctype, name ^ "$get", [param], []) in
-
-        let (param1, index) = create_param Int "index" in
-        let (param2, value) = create_param ctype "value" in
-        let setter = FunDec (Void, name ^ "$set", [param1; param2], []) in
-
-        Hashtbl.add globals name (call getter, call setter);
-        [getter; setter]
-
+  | GlobalDef (true, Array ctype, name, None, ann) as dec ->
+    (* Getters for array variable: crate getter for given index Note that
+     * getters and setters for dimensions are automatically generated,
+     * because they have been put into new global variables during the
+     * desugarin phase *)
+    let (param, index) = create_param Int (fresh_var "index") in
+    let var = VarUse (dec, Some [index], [Type ctype; Depth 1]) in
+    let body = Block [Return (var, [])] in
+    let getter = FunDef (true, ctype, name ^ "$get", [param], body, []) in
+
+    (* Setters for array variable: create setter for given index *)
+    let (param1, index) = create_param Int (fresh_var "index") in
+    let (param2, value) = create_param ctype (fresh_var "value") in
+    let body = Block [VarLet (dec, Some [index], value, [])] in
+    let setter = FunDef (true, Void, name ^ "$set", [param1; param2], body, []) in
+
+    [getter; setter]
+
+  | GlobalDef (true, ctype, name, None, ann) as dec ->
     (* Getter for basic variable type: return the variable *)
-    | GlobalDec (ctype, name, ann) ->
-        let getter = FunDec (ctype, name ^ "$get", [], []) in
+    let var = VarUse (dec, None, [Type ctype; Depth 1]) in
+    let body = [Return (var, [])] in
+    let getter = FunDef (true, ctype, name ^ "$get", [], Block body, []) in
+
+    (* Setter for basic variable type: assign the variable *)
+    let (param, value) = create_param ctype (fresh_var "value") in
+    let body = [VarLet (dec, None, value, [])] in
+    let setter = FunDef (true, Void, name ^ "$set", [param], Block body, []) in
+
+    [getter; setter]
+
+  | GlobalDec (Array ctype, name, ann) ->
+    (* Getters for external array variable: create getter and setter for a
+     * given index *)
+    let (param, _) = create_param Int "index" in
+    let getter = FunDec (ctype, name ^ "$get", [param], []) in
+
+    let (param1, index) = create_param Int "index" in
+    let (param2, value) = create_param ctype "value" in
+    let setter = FunDec (Void, name ^ "$set", [param1; param2], []) in
+
+    Hashtbl.add globals name (call getter, call setter);
+    [getter; setter]
+
+  (* Getter for basic variable type: return the variable *)
+  | GlobalDec (ctype, name, ann) ->
+    let getter = FunDec (ctype, name ^ "$get", [], []) in
 
-        let (param, _) = create_param ctype "value" in
-        let setter = FunDec (Void, name ^ "$set", [param], []) in
+    let (param, _) = create_param ctype "value" in
+    let setter = FunDec (Void, name ^ "$set", [param], []) in
 
-        Hashtbl.add globals name (call getter, call setter);
-        [getter; setter]
+    Hashtbl.add globals name (call getter, call setter);
+    [getter; setter]
 
-    | _ -> raise InvalidNode
+  | _ -> raise InvalidNode
 
 let rec create_funcs globals = function
-    | Program (decls, ann) ->
-        let decls = List.map (create_funcs globals) decls in
-        Program (flatten_blocks (List.map (create_funcs globals) decls), ann)
+  | Program (decls, ann) ->
+    let decls = List.map (create_funcs globals) decls in
+    Program (flatten_blocks (List.map (create_funcs globals) decls), ann)
 
-    | GlobalDef (true, ctype, name, None, ann) as node ->
-        Block (GlobalDef (false, ctype, name, None, ann) ::
-               (process globals node))
+  | GlobalDef (true, ctype, name, None, ann) as node ->
+    Block (GlobalDef (false, ctype, name, None, ann) :: (process globals node))
 
-    | GlobalDec (ctype, name, ann) as node ->
-        Block (process globals node)
+  | GlobalDec (ctype, name, ann) as node ->
+    Block (process globals node)
 
-    | node -> transform_children (create_funcs globals) node
+  | node -> transform_children (create_funcs globals) node
 
 let rec replace_vars scope depth = function
-    | (VarDec (_, name, _, _) as node)
-    | (Param (_, name, _) as node)
-            when Hashtbl.mem scope name ->
-        Hashtbl.remove scope name;
-        node
+  | (VarDec (_, name, _, _) as node)
+  | (Param (_, name, _) as node) when Hashtbl.mem scope name ->
+    Hashtbl.remove scope name;
+    node
 
-    | FunDef (export, ret_type, name, params, body, ann) ->
-        let local_scope = Hashtbl.copy scope in
-        let trav = replace_vars local_scope (depth + 1) in
-        let params = List.map trav params in
-        FunDef (export, ret_type, name, params, trav body, ann)
+  | FunDef (export, ret_type, name, params, body, ann) ->
+    let local_scope = Hashtbl.copy scope in
+    let trav = replace_vars local_scope (depth + 1) in
+    let params = List.map trav params in
+    FunDef (export, ret_type, name, params, trav body, ann)
 
-    | VarUse (dec, None, _) when Hashtbl.mem scope (nameof dec) ->
-        let (get, _) = Hashtbl.find scope (nameof dec) in
-        get [] depth
+  | VarUse (dec, None, _) when Hashtbl.mem scope (nameof dec) ->
+    let (get, _) = Hashtbl.find scope (nameof dec) in
+    get [] depth
 
-    | VarLet (dec, dims, value, _) when Hashtbl.mem scope (nameof dec) ->
-        let dims = optmapl (replace_vars scope depth) dims in
-        let (_, set) = Hashtbl.find scope (nameof dec) in
-        Expr (set (dims @ [replace_vars scope depth value]) depth)
+  | VarLet (dec, dims, value, _) when Hashtbl.mem scope (nameof dec) ->
+    let dims = optmapl (replace_vars scope depth) dims in
+    let (_, set) = Hashtbl.find scope (nameof dec) in
+    Expr (set (dims @ [replace_vars scope depth value]) depth)
 
-    | node -> transform_children (replace_vars scope depth) node
+  | node -> transform_children (replace_vars scope depth) node
 
 let phase = function
-    | Ast node ->
-        let globals = Hashtbl.create 20 in
-        let node = create_funcs globals node in
-        Ast (replace_vars globals 0 node)
-    | _ -> raise (InvalidInput "extern vars")
+  | Ast node ->
+    let globals = Hashtbl.create 20 in
+    let node = create_funcs globals node in
+    Ast (replace_vars globals 0 node)
+  | _ -> raise (InvalidInput "extern vars")

+ 69 - 68
phases/index.ml

@@ -3,78 +3,79 @@ open Util
 open Globals
 
 let tag_index program =
-    let nglobs = ref 0 in
-    let nimport = ref 0 in
-    let consts = Hashtbl.create 32 in
-    let rec trav_localfuns trav = function
-        | LocalFuns body -> LocalFuns (List.map trav body)
-        | node -> transform_children (trav_localfuns trav) node
-    in
-    let rec tag stacklen callstack node =
-        let trav = tag stacklen callstack in
-        match node with
-        | GlobalDef _ ->
-            let index = !nglobs in
-            nglobs := !nglobs + 1;
-            annotate (Index index) (transform_children trav node)
-
-        | FunDef (export, rtype, name, params, body, ann) ->
-            (* label name for local function is "<parent_label>$<name>" *)
-            let callstack = name :: callstack in
-            let label = String.concat "$" (List.rev callstack) in
-
-            let stacklen = ref 0 in
-            let trav = tag stacklen callstack in
-
-            (* Traverse own function body first *)
-            let params = List.map trav params in
-            let body = trav body in
-            let ann = Index (!stacklen - List.length params) :: ann in
-
-            (* Traverse local functions after the function body *)
-            let body = trav_localfuns trav body in
-
-            FunDef (export, rtype, name, params, body, LabelName label :: ann)
-
-        | LocalFuns _ -> node
-
-        | VarDec _ | Param _ | Dim _ ->
-            let index = !stacklen in
-            stacklen := !stacklen + 1;
-            annotate (Index index) (transform_children trav node)
-
-        | FunDec (_, name, _, _) ->
-            let index = !nimport in
-            nimport := !nimport + 1;
-            annotate (LabelName name) (annotate (Index index) node)
-
-        | Const (value, _) when not (is_immediate_const value) ->
-            let index = if Hashtbl.mem consts value then (
-                Hashtbl.find consts value
-            ) else (
-                let index = Hashtbl.length consts in
-                Hashtbl.add consts value index;
-                index
-            ) in
-            annotate (Index index) node
-
-        | _ -> transform_children trav node
-    in tag (ref 0) [] program
+  let nglobs = ref 0 in
+  let nimport = ref 0 in
+  let consts = Hashtbl.create 32 in
+  let rec trav_localfuns trav = function
+    | LocalFuns body -> LocalFuns (List.map trav body)
+    | node -> transform_children (trav_localfuns trav) node
+  in
+  let rec tag stacklen callstack node =
+    let trav = tag stacklen callstack in
+    match node with
+    | GlobalDef _ ->
+      let index = !nglobs in
+      nglobs := !nglobs + 1;
+      annotate (Index index) (transform_children trav node)
+
+    | FunDef (export, rtype, name, params, body, ann) ->
+      (* label name for local function is "<parent_label>$<name>" *)
+      let callstack = name :: callstack in
+      let label = String.concat "$" (List.rev callstack) in
+
+      let stacklen = ref 0 in
+      let trav = tag stacklen callstack in
+
+      (* Traverse own function body first *)
+      let params = List.map trav params in
+      let body = trav body in
+      let ann = Index (!stacklen - List.length params) :: ann in
+
+      (* Traverse local functions after the function body *)
+      let body = trav_localfuns trav body in
+
+      FunDef (export, rtype, name, params, body, LabelName label :: ann)
+
+    | LocalFuns _ -> node
+
+    | VarDec _ | Param _ | Dim _ ->
+      let index = !stacklen in
+      stacklen := !stacklen + 1;
+      annotate (Index index) (transform_children trav node)
+
+    | FunDec (_, name, _, _) ->
+      let index = !nimport in
+      nimport := !nimport + 1;
+      annotate (LabelName name) (annotate (Index index) node)
+
+    | Const (value, _) when not (is_immediate_const value) ->
+      let index =
+        if Hashtbl.mem consts value then
+          Hashtbl.find consts value
+        else
+          let index = Hashtbl.length consts in
+          Hashtbl.add consts value index;
+          index
+      in
+      annotate (Index index) node
+
+    | _ -> transform_children trav node
+  in tag (ref 0) [] program
 
 let rec strip_context = function
-    | VarUse (dec, dims, ann) ->
-        Var (nameof dec, optmap strip_context dims, ann)
+  | VarUse (dec, dims, ann) ->
+    Var (nameof dec, optmap strip_context dims, ann)
 
-    | VarLet (dec, dims, value, ann) ->
-        Assign (nameof dec, optmap strip_context dims, strip_context value, ann)
+  | VarLet (dec, dims, value, ann) ->
+    Assign (nameof dec, optmap strip_context dims, strip_context value, ann)
 
-    | FunUse (dec, args, ann) ->
-        FunCall (nameof dec, List.map strip_context args, ann)
+  | FunUse (dec, args, ann) ->
+    FunCall (nameof dec, List.map strip_context args, ann)
 
-    | node -> transform_children strip_context node
+  | node -> transform_children strip_context node
 
 let phase = function
-    | Ast node ->
-        let tagged = tag_index (strip_context node) in
-        Ast (Context.analyse_context tagged)
-    | _ -> raise (InvalidInput "index analysis")
+  | Ast node ->
+    let tagged = tag_index (strip_context node) in
+    Ast (Context.analyse_context tagged)
+  | _ -> raise (InvalidInput "index analysis")

+ 20 - 15
phases/load.ml

@@ -31,32 +31,37 @@ let input_buffered ic chunksize =
 
 let phase = function
   | Empty ->
-    let display_name = match args.infile with
-    | Some filename -> filename
-    | None -> "<stdin>"
+    let display_name =
+      match args.infile with
+      | Some filename -> filename
+      | None -> "<stdin>"
     in
     let bufsize = 512 in
 
     if args.cpp then
-      let cpp_out = match args.infile with
-      | Some filename ->
-        Unix.open_process_in (cpp_cmd ^ " " ^ filename)
-      | None ->
-        let content = input_buffered stdin bufsize in
-        let (cpp_out, cpp_in) = Unix.open_process cpp_cmd in
-        output_string cpp_in content;
-        close_out cpp_in;
-        cpp_out
+      let cpp_out =
+        match args.infile with
+        | Some filename ->
+          Unix.open_process_in (cpp_cmd ^ " " ^ filename)
+        | None ->
+          let content = input_buffered stdin bufsize in
+          let (cpp_out, cpp_in) = Unix.open_process cpp_cmd in
+          output_string cpp_in content;
+          close_out cpp_in;
+          cpp_out
       in
       log_line 2 "Run C preprocessor";
 
       (* Read preprocessed code from cpp's stdout *)
       let preprocessed = input_buffered cpp_out bufsize in
       FileContent (display_name, preprocessed)
+
     else
-      let content = match args.infile with
-      | Some filename -> input_all (open_in filename)
-      | None -> input_buffered stdin bufsize
+      let content =
+        match args.infile with
+        | Some filename -> input_all (open_in filename)
+        | None -> input_buffered stdin bufsize
       in
       FileContent (display_name, content)
+
   | _ -> raise (InvalidInput "load")

+ 12 - 12
phases/output.ml

@@ -3,15 +3,15 @@ open Util
 open Globals
 
 let phase = function
-    | Assembly instrs ->
-        (match args.outfile with
-        | Some filename ->
-            let oc = open_out filename in
-            Print.print_assembly oc instrs;
-            close_out oc
-        | None ->
-            if args.verbose >= 1 then (prerr_endline hline);
-            Print.print_assembly stdout instrs
-        );
-        Empty
-    | _ -> raise (InvalidInput "output")
+  | Assembly instrs ->
+    begin match args.outfile with
+    | Some filename ->
+      let oc = open_out filename in
+      Print.print_assembly oc instrs;
+      close_out oc
+    | None ->
+      if args.verbose >= 1 then prerr_endline hline;
+      Print.print_assembly stdout instrs
+    end;
+    Empty
+  | _ -> raise (InvalidInput "output")

+ 16 - 15
phases/parse.ml

@@ -4,26 +4,27 @@ open Util
 open Globals
 
 let get_loc lexbuf =
-    Util.loc_from_lexpos lexbuf.lex_curr_p lexbuf.lex_curr_p
+  Util.loc_from_lexpos lexbuf.lex_curr_p lexbuf.lex_curr_p
 
 let shift_loc (fname, ystart, yend, xstart, xend) yshift xshift =
-    (fname, ystart + yshift, yend + yshift, xstart + xshift, xend + xshift)
+  (fname, ystart + yshift, yend + yshift, xstart + xshift, xend + xshift)
 
 let shift_back lexbuf = shift_loc (get_loc lexbuf) 0 (-1)
 
 let parse_with_error lexbuf =
-    try Some (Parser.program Lexer.token lexbuf) with
-    | Lexer.SyntaxError msg ->
-        raise (LocError ((shift_back lexbuf), msg))
-    | Parser.Error ->
-        raise (LocError ((shift_back lexbuf), "syntax error"))
+  try Some (Parser.program Lexer.token lexbuf) with
+  | Lexer.SyntaxError msg ->
+    raise (LocError ((shift_back lexbuf), msg))
+  | Parser.Error ->
+    raise (LocError ((shift_back lexbuf), "syntax error"))
 
 let phase = function
-    | FileContent (display_name, content) ->
-        let lexbuf = Lexing.from_string content in
-        lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = display_name };
-        let ast = parse_with_error lexbuf in
-        (match ast with
-            | None -> raise (CompileError "no syntax tree was constructed")
-            | Some node -> Ast node)
-    | _ -> raise (InvalidInput "parse")
+  | FileContent (display_name, content) ->
+    let lexbuf = Lexing.from_string content in
+    lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = display_name };
+    let ast = parse_with_error lexbuf in
+    begin match ast with
+      | None -> raise (CompileError "no syntax tree was constructed")
+      | Some node -> Ast node
+    end
+  | _ -> raise (InvalidInput "parse")

+ 77 - 59
phases/peephole.ml

@@ -4,75 +4,93 @@ open Util
 open Globals
 
 let rec strip_comments = function
-    | Comment _ :: tl -> strip_comments tl
-    | InlineComment (EmptyLine, _) :: tl -> strip_comments tl
-    | InlineComment (instr, _) :: tl -> strip_comments (instr :: tl)
-    | hd :: tl -> hd :: (strip_comments tl)
-    | [] -> []
+  | Comment _ :: tl -> strip_comments tl
+  | InlineComment (EmptyLine, _) :: tl -> strip_comments tl
+  | InlineComment (instr, _) :: tl -> strip_comments (instr :: tl)
+  | hd :: tl -> hd :: (strip_comments tl)
+  | [] -> []
 
 let rec peephole = function
-    (* Constant load before branch becomes a jump when the branch condition
-     * matches the loaded value ... *)
-    | LoadImm (BoolVal b) :: Branch (cond, tgt) :: tl when cond = b ->
-        InlineComment (Jump tgt, "branch -> jump") :: (peephole tl)
+  (* Constant load before branch becomes a jump when the branch condition
+   * matches the loaded value ... *)
+  | LoadImm (BoolVal b) :: Branch (cond, tgt) :: tl when cond = b ->
+    InlineComment (Jump tgt, "branch -> jump") :: (peephole tl)
 
-    (* ... otherwise, both instructions can be removed *)
-    | LoadImm (BoolVal _) :: Branch (_, tgt) :: tl ->
-        InlineComment (EmptyLine, "load + branch removed") :: peephole tl
+  (* ... otherwise, both instructions can be removed *)
+  | LoadImm (BoolVal _) :: Branch (_, tgt) :: tl ->
+    InlineComment (EmptyLine, "load + branch removed") :: peephole tl
 
-    (* Transform addition/subtraction by constant to increment/decrement:
-     * iload L          |   iload L
-     * iloadc[_ ]C      |   iloadc_1
-     * i{add,sub}       |   i{add,sub}
-     * istore L         |   istore L
-     *     |                  |
-     *     v                  v
-     * i{inc,dec} L C   |   i{inc,dec}_1 L
-     *)
-    | (Load (Int, Current, index) :: LoadConst (_, i) :: Op (Add, Int) ::
-            Store (Int, Current, store) :: tl
-    |  LoadConst (_, i) :: Load (Int, Current, index) :: Op (Add, Int) ::
-            Store (Int, Current, store) :: tl) when store = index ->
-        InlineComment (Inc (index, i), "add -> inc") :: (peephole tl)
+  (* Transform addition/subtraction by constant to increment/decrement:
+   * iload L          |   iload L
+   * iloadc[_ ]C      |   iloadc_1
+   * i{add,sub}       |   i{add,sub}
+   * istore L         |   istore L
+   *     |                    |
+   *     v                    v
+   * i{inc,dec} L C   |   i{inc,dec}_1 L
+   *)
+  | Load (Int, Current, index) ::
+    LoadConst (_, i) ::
+    Op (Add, Int) ::
+    Store (Int, Current, store) :: tl
+  | LoadConst (_, i) ::
+    Load (Int, Current, index) ::
+    Op (Add, Int) ::
+    Store (Int, Current, store) :: tl
+    when store = index ->
+      InlineComment (Inc (index, i), "add -> inc") :: (peephole tl)
 
-    | (Load (Int, Current, index) :: LoadConst (_, i) :: Op (Sub, Int) ::
-            Store (Int, Current, store) :: tl
-    |  LoadConst (_, i) :: Load (Int, Current, index) :: Op (Sub, Int) ::
-            Store (Int, Current, store) :: tl) when store = index ->
-        InlineComment (Dec (index, i), "sub -> dec") :: (peephole tl)
+  | Load (Int, Current, index) ::
+    LoadConst (_, i) ::
+    Op (Sub, Int) ::
+    Store (Int, Current, store) :: tl
+  | LoadConst (_, i) ::
+    Load (Int, Current, index) ::
+    Op (Sub, Int) ::
+    Store (Int, Current, store) :: tl
+    when store = index ->
+      InlineComment (Dec (index, i), "sub -> dec") :: (peephole tl)
 
-    | (Load (Int, Current, index) :: LoadImm (IntVal 1) :: Op (Add, Int) ::
-            Store (Int, Current, store) :: tl
-    |  LoadImm (IntVal 1) :: Load (Int, Current, index) :: Op (Add, Int) ::
-            Store (Int, Current, store) :: tl) when store = index ->
-        InlineComment (IncOne index, "add -> inc") :: (peephole tl)
+  | Load (Int, Current, index) ::
+    LoadImm (IntVal 1) ::
+    Op (Add, Int) ::
+    Store (Int, Current, store) :: tl
+  | LoadImm (IntVal 1) ::
+    Load (Int, Current, index) ::
+    Op (Add, Int) ::
+    Store (Int, Current, store) :: tl
+    when store = index ->
+      InlineComment (IncOne index, "add -> inc") :: (peephole tl)
 
-    | (Load (Int, Current, index) :: LoadImm (IntVal 1) :: Op (Sub, Int) ::
-            Store (Int, Current, store) :: tl
-    |  LoadImm (IntVal 1) :: Load (Int, Current, index) :: Op (Sub, Int) ::
-            Store (Int, Current, store) :: tl) when store = index ->
-        InlineComment (DecOne index, "sub -> dec") :: (peephole tl)
+  | Load (Int, Current, index) :: LoadImm (IntVal 1) :: Op (Sub, Int) ::
+    Store (Int, Current, store) :: tl
+  | LoadImm (IntVal 1) ::
+    Load (Int, Current, index) ::
+    Op (Sub, Int) ::
+    Store (Int, Current, store) :: tl
+    when store = index ->
+      InlineComment (DecOne index, "sub -> dec") :: (peephole tl)
 
-    | hd :: tl -> hd :: (peephole tl)
-    | [] -> []
+  | hd :: tl -> hd :: (peephole tl)
+  | [] -> []
 
 (* Count actual instructions, ignoring comments and labels *)
 let count_instrs instrs =
-    let rec trav n = function
-    | [] -> n
-    | (Comment _ | Label _ | EmptyLine) :: tl -> trav n tl
-    | InlineComment (hd, _) :: tl -> trav (trav n [hd]) tl
-    | hd :: tl -> trav (n + 1) tl
-    in trav 0 instrs
+  let rec trav n = function
+  | [] -> n
+  | (Comment _ | Label _ | EmptyLine) :: tl -> trav n tl
+  | InlineComment (hd, _) :: tl -> trav (trav n [hd]) tl
+  | hd :: tl -> trav (n + 1) tl
+  in trav 0 instrs
 
 let phase = function
-    | Assembly instrs as input ->
-        let oldcount = count_instrs instrs in
-        let instrs = peephole (strip_comments instrs) in
-        let newcount = count_instrs instrs in
-        log_line 2 (sprintf
-            "Optimized %d to %d instructions (%d fewer)"
-            oldcount newcount (oldcount - newcount)
-        );
-        Assembly instrs
-    | _ -> raise (InvalidInput "peephole")
+  | Assembly instrs as input ->
+    let oldcount = count_instrs instrs in
+    let instrs = peephole (strip_comments instrs) in
+    let newcount = count_instrs instrs in
+    log_line 2 (sprintf
+      "Optimized %d to %d instructions (%d fewer)"
+      oldcount newcount (oldcount - newcount)
+    );
+    Assembly instrs
+  | _ -> raise (InvalidInput "peephole")

+ 157 - 156
phases/print.ml

@@ -3,179 +3,180 @@ open Util
 open Globals
 open Stringify
 
-let tab = "    "
+let tab = "  "
 let max_instr_width = 26
 
 let si = string_of_int
 
 let ctype2str = Stringify.type2str
 let type2str = function
-    | ArrayDims (t, dims) -> ctype2str t ^ repeat "," (List.length dims - 1)
-    | t -> ctype2str t
+  | ArrayDims (t, dims) -> ctype2str t ^ repeat "," (List.length dims - 1)
+  | t -> ctype2str t
 
 let op2str = function
-    | Neg -> "neg"
-    | Not -> "not"
-    | Add -> "add"
-    | Sub -> "sub"
-    | Mul -> "mul"
-    | Div -> "div"
-    | Mod -> "rem"
-    | Eq  -> "eq"
-    | Ne  -> "ne"
-    | Lt  -> "lt"
-    | Le  -> "le"
-    | Gt  -> "gt"
-    | Ge  -> "ge"
-    | _ -> raise (CompileError ("operator unsupported by VM"))
+  | Neg -> "neg"
+  | Not -> "not"
+  | Add -> "add"
+  | Sub -> "sub"
+  | Mul -> "mul"
+  | Div -> "div"
+  | Mod -> "rem"
+  | Eq  -> "eq"
+  | Ne  -> "ne"
+  | Lt  -> "lt"
+  | Le  -> "le"
+  | Gt  -> "gt"
+  | Ge  -> "ge"
+  | _ -> raise (CompileError ("operator unsupported by VM"))
 
 let prefix = function
-    | Bool _  -> "b"
-    | Int _   -> "i"
-    | Float _ -> "f"
-    | Void    -> ""
-    | _       -> "a"
+  | Bool _  -> "b"
+  | Int _   -> "i"
+  | Float _ -> "f"
+  | Void  -> ""
+  | _     -> "a"
 
 let suffix = function
-    | Glob        -> "g"
-    | Current     -> ""
-    | Local       -> "l"
-    | Rel nesting -> "n " ^ si nesting
+  | Glob    -> "g"
+  | Current   -> ""
+  | Local     -> "l"
+  | Rel nesting -> "n " ^ si nesting
 
 let rtn_suffix = function
-    | ExternFun index        -> "e " ^ si index
-    | LocalFun (size, label) -> " " ^ si size ^ " " ^ label
+  | ExternFun index    -> "e " ^ si index
+  | LocalFun (size, label) -> " " ^ si size ^ " " ^ label
 
 let rec instr2str = function
-    (* Global / directives *)
-    | Comment comment ->
-        if args.verbose >= 2 then "; " ^ comment else ""
-    | InlineComment (instr, comment) ->
-        if args.verbose >= 2 then
-            expand max_instr_width (instr2str instr) ^ " ; " ^ comment
-        else
-            instr2str instr
-    | Label name ->
-        name ^ ":"
-    | Export (name, ret_type, arg_types, label) ->
-        let types = List.map type2str (ret_type :: arg_types) in
-        ".export \"" ^ name ^ "\" " ^ (String.concat " " types) ^ " " ^ label
-    | Import (name, ret_type, arg_types) ->
-        let types = List.map type2str (ret_type :: arg_types) in
-        ".import \"" ^ name ^ "\" " ^ (String.concat " " types)
-    | Global ctype ->
-        ".global " ^ (type2str ctype)
-    | ConstDef value ->
-        ".const " ^ type2str (const_type value) ^ " " ^ const2str value
-
-    (* Store *)
-    | Store (ctype, scope, index) ->
-        tab ^ prefix ctype ^ "store" ^ suffix scope ^ " " ^ si index
-
-    (* Load *)
-    | Load (ctype, Current, index) when index >= 0 & index <= 3 ->
-        tab ^ prefix ctype ^ "load_" ^ si index
-    | Load (ctype, scope, index) ->
-        tab ^ prefix ctype ^ "load" ^ suffix scope ^ " " ^ si index
-    | LoadConst (ctype, index) ->
-        tab ^ prefix ctype ^ "loadc " ^ si index
-    | LoadImm (BoolVal b) ->
-        tab ^ "bloadc_" ^ (if b then "t" else "f")
-    | LoadImm (IntVal i) when i < 0 ->
-        tab ^ "iloadc_m" ^ si (-i)
-    | LoadImm (IntVal i) ->
-        tab ^ "iloadc_" ^ si i
-    | LoadImm (FloatVal i) ->
-        tab ^ "floadc_" ^ si (int_of_float i)
-
-    (* Operators *)
-    | Op (op, ctype) ->
-        tab ^ prefix ctype ^ op2str op
-    | Convert (src, tgt) ->
-        tab ^ prefix src ^ "2" ^ prefix tgt
-    | Inc (index, const) ->
-        tab ^ "iinc " ^ si index ^ " " ^ si const
-    | Dec (index, const) ->
-        tab ^ "idec " ^ si index ^ " " ^ si const
-    | IncOne index ->
-        tab ^ "iinc_1 " ^ si index
-    | DecOne index ->
-        tab ^ "idec_1 " ^ si index
-
-    (* Control flow *)
-    | RtnInit scope ->
-        tab ^ "isr" ^ suffix scope
-    | RtnJmp scope ->
-        tab ^ "jsr" ^ rtn_suffix scope
-    | RtnEnter stack_len ->
-        tab ^ "esr " ^ si stack_len
-    | Ret ctype ->
-        tab ^ prefix ctype ^ "return"
-    | Branch (true, target) ->
-        tab ^ "branch_t " ^ target
-    | Branch (false, target) ->
-        tab ^ "branch_f " ^ target
-    | Jump target ->
-        tab ^ "jump " ^ target
-
-    (* Stack management *)
-    | Pop ctype ->
-        tab ^ prefix ctype ^ "pop"
-
-    (* Arrays *)
-    | NewArray (basetype, ndims) ->
-        tab ^ prefix basetype ^ "newa " ^ si ndims
-    | LoadArray basetype ->
-        tab ^ prefix basetype ^ "loada"
-    | StoreArray basetype ->
-        tab ^ prefix basetype ^ "storea"
-
-    | EmptyLine -> ""
-    | DummyInstr -> tab ^ "<dummy>"
+  (* Global / directives *)
+  | Comment comment ->
+    if args.verbose >= 2 then "; " ^ comment else ""
+  | InlineComment (instr, comment) ->
+    if args.verbose >= 2 then
+      expand max_instr_width (instr2str instr) ^ " ; " ^ comment
+    else
+      instr2str instr
+  | Label name ->
+    name ^ ":"
+  | Export (name, ret_type, arg_types, label) ->
+    let types = List.map type2str (ret_type :: arg_types) in
+    ".export \"" ^ name ^ "\" " ^ (String.concat " " types) ^ " " ^ label
+  | Import (name, ret_type, arg_types) ->
+    let types = List.map type2str (ret_type :: arg_types) in
+    ".import \"" ^ name ^ "\" " ^ (String.concat " " types)
+  | Global ctype ->
+    ".global " ^ (type2str ctype)
+  | ConstDef value ->
+    ".const " ^ type2str (const_type value) ^ " " ^ const2str value
+
+  (* Store *)
+  | Store (ctype, scope, index) ->
+    tab ^ prefix ctype ^ "store" ^ suffix scope ^ " " ^ si index
+
+  (* Load *)
+  | Load (ctype, Current, index) when index >= 0 & index <= 3 ->
+    tab ^ prefix ctype ^ "load_" ^ si index
+  | Load (ctype, scope, index) ->
+    tab ^ prefix ctype ^ "load" ^ suffix scope ^ " " ^ si index
+  | LoadConst (ctype, index) ->
+    tab ^ prefix ctype ^ "loadc " ^ si index
+  | LoadImm (BoolVal b) ->
+    tab ^ "bloadc_" ^ (if b then "t" else "f")
+  | LoadImm (IntVal i) when i < 0 ->
+    tab ^ "iloadc_m" ^ si (-i)
+  | LoadImm (IntVal i) ->
+    tab ^ "iloadc_" ^ si i
+  | LoadImm (FloatVal i) ->
+    tab ^ "floadc_" ^ si (int_of_float i)
+
+  (* Operators *)
+  | Op (op, ctype) ->
+    tab ^ prefix ctype ^ op2str op
+  | Convert (src, tgt) ->
+    tab ^ prefix src ^ "2" ^ prefix tgt
+  | Inc (index, const) ->
+    tab ^ "iinc " ^ si index ^ " " ^ si const
+  | Dec (index, const) ->
+    tab ^ "idec " ^ si index ^ " " ^ si const
+  | IncOne index ->
+    tab ^ "iinc_1 " ^ si index
+  | DecOne index ->
+    tab ^ "idec_1 " ^ si index
+
+  (* Control flow *)
+  | RtnInit scope ->
+    tab ^ "isr" ^ suffix scope
+  | RtnJmp scope ->
+    tab ^ "jsr" ^ rtn_suffix scope
+  | RtnEnter stack_len ->
+    tab ^ "esr " ^ si stack_len
+  | Ret ctype ->
+    tab ^ prefix ctype ^ "return"
+  | Branch (true, target) ->
+    tab ^ "branch_t " ^ target
+  | Branch (false, target) ->
+    tab ^ "branch_f " ^ target
+  | Jump target ->
+    tab ^ "jump " ^ target
+
+  (* Stack management *)
+  | Pop ctype ->
+    tab ^ prefix ctype ^ "pop"
+
+  (* Arrays *)
+  | NewArray (basetype, ndims) ->
+    tab ^ prefix basetype ^ "newa " ^ si ndims
+  | LoadArray basetype ->
+    tab ^ prefix basetype ^ "loada"
+  | StoreArray basetype ->
+    tab ^ prefix basetype ^ "storea"
+
+  | EmptyLine -> ""
+  | DummyInstr -> tab ^ "<dummy>"
 
 let rec print_assembly oc instrs =
-    let output_line line =
-        output_string oc line;
-        output_char oc '\n';
-    in
-    let endbuf = ref [] in
-    let rec trav = function
-        | [] -> ()
-        | EmptyLine :: tl -> output_line ""; trav tl
-        | hd :: tl ->
-            let line = instr2str hd in
-            (if String.length line > 0 && line.[0] = '.' then
-                endbuf := line :: !endbuf
-            else (if String.length line > 0 then
-                output_line line
-            ));
-            trav tl
-    in
-    trav instrs;
-    if List.length !endbuf > 1 then (
-        output_line (instr2str (Comment ("globals:")));
-        let cmp a b = compare (String.sub b 0 7) (String.sub a 0 7) in
-        List.iter output_line (List.sort cmp (List.rev !endbuf))
-    ); ()
+  let output_line line =
+    output_string oc line;
+    output_char oc '\n';
+  in
+  let endbuf = ref [] in
+  let rec trav = function
+    | [] -> ()
+    | EmptyLine :: tl -> output_line ""; trav tl
+    | hd :: tl ->
+      let line = instr2str hd in
+      begin
+        if String.length line > 0 && line.[0] = '.' then
+          endbuf := line :: !endbuf
+        else if String.length line > 0 then
+          output_line line
+      end;
+      trav tl
+  in
+  trav instrs;
+  if List.length !endbuf > 1 then begin
+    output_line (instr2str (Comment ("globals:")));
+    let cmp a b = compare (String.sub b 0 7) (String.sub a 0 7) in
+    List.iter output_line (List.sort cmp (List.rev !endbuf))
+  end
 
 let phase = function
-    | Ast node as input ->
-        prerr_endline hline;
-        prerr_endline (node2str node);
-        prerr_endline hline;
-        input
-
-    | FileContent (display_name, content) as input ->
-        prerr_endline hline;
-        prerr_endline (display_name ^ ":\n");
-        prerr_endline content;
-        prerr_endline hline;
-        input
-
-    | Assembly instrs as input ->
-        prerr_endline hline;
-        print_assembly stderr instrs;
-        prerr_endline hline;
-        input
-
-    | Empty -> Empty
+  | Ast node as input ->
+    prerr_endline hline;
+    prerr_endline (node2str node);
+    prerr_endline hline;
+    input
+
+  | FileContent (display_name, content) as input ->
+    prerr_endline hline;
+    prerr_endline (display_name ^ ":\n");
+    prerr_endline content;
+    prerr_endline hline;
+    input
+
+  | Assembly instrs as input ->
+    prerr_endline hline;
+    print_assembly stderr instrs;
+    prerr_endline hline;
+    input
+
+  | Empty -> Empty

+ 210 - 205
phases/typecheck.ml

@@ -21,229 +21,234 @@ open Globals
 open Stringify
 
 let array_depth = function
-    | ArrayDims (_, dims) -> List.length dims
-    | _                   -> raise InvalidNode
+  | ArrayDims (_, dims) -> List.length dims
+  | _                   -> raise InvalidNode
 
 let spec = function
-    | ArrayDims (ctype, dims) -> (ctype, List.length dims)
-    | ctype                   -> (ctype, 0)
+  | ArrayDims (ctype, dims) -> (ctype, List.length dims)
+  | ctype                   -> (ctype, 0)
 
 let check_type ?(msg="") expected node =
-    let got = typeof node in
-    if (spec got) <> (spec expected) then (
-        let msg = match msg with
-            | "" -> sprintf "type mismatch: expected type %s, got %s"
-                            (type2str expected) (type2str got)
-                            (*(type2str (spec expected)) (type2str (spec got))*)
-            | _ -> msg
-        in raise (NodeError (node, msg))
-    ); ()
+  let got = typeof node in
+  if (spec got) <> (spec expected) then begin
+    let msg = match msg with
+      | "" -> sprintf "type mismatch: expected type %s, got %s"
+              (type2str expected) (type2str got)
+              (*(type2str (spec expected)) (type2str (spec got))*)
+      | _ -> msg
+    in raise (NodeError (node, msg))
+  end
 
 let op_types = function
-    | Not | And | Or                      -> [Bool]
-    | Mod                                 -> [Int]
-    | Neg | Sub | Div | Lt | Le | Gt | Ge -> [Int; Float]
-    | Add | Mul | Eq | Ne                 -> [Bool; Int; Float]
+  | Not | And | Or                      -> [Bool]
+  | Mod                                 -> [Int]
+  | Neg | Sub | Div | Lt | Le | Gt | Ge -> [Int; Float]
+  | Add | Mul | Eq | Ne                 -> [Bool; Int; Float]
 
 let op_result_type opnd_type = function
-    | Not | And | Or | Eq | Ne | Lt | Le | Gt | Ge -> Bool
-    | Neg | Add | Sub | Mul | Div | Mod            -> opnd_type
+  | Not | And | Or | Eq | Ne | Lt | Le | Gt | Ge -> Bool
+  | Neg | Add | Sub | Mul | Div | Mod      -> opnd_type
 
 (* Check if the given operator can be applied to the given type *)
 let check_type_op allowed_types desc node =
-    let got = typeof node in
-    if not (List.mem got allowed_types) then (
+  let got = typeof node in
+  if not (List.mem got allowed_types) then (
+    let msg = sprintf
+      "%s cannot be applied to type %s, only to %s"
+      desc (type2str got) (types2str allowed_types)
+    in
+    raise (NodeError (node, msg))
+  ); ()
+
+let check_dims_match dims dec_type errnode =
+  match (List.length dims, array_depth dec_type) with
+  | (got, expected) when got != expected ->
+    let msg = sprintf
+      "dimension mismatch: expected %d indices, got %d" expected got
+    in
+    raise (NodeError (errnode, msg))
+  | _ -> ()
+
+let rec typecheck node =
+  let check_trav ctype node =
+    let node = typecheck node in
+    check_type ctype node;
+    node
+  in
+  match node with
+  | FunUse ((FunDec (ret_type, name, params, _) as dec), args, ann)
+  | FunUse ((FunDef (_, ret_type, name, params, _, _) as dec), args, ann) ->
+    begin
+      match (List.length args, List.length params) with
+      | (nargs, nparams) when nargs != nparams ->
         let msg = sprintf
-            "%s cannot be applied to type %s, only to %s"
-            desc (type2str got) (types2str allowed_types)
+          "function \"%s\" expects %d arguments, got %d"
+          name nparams nargs
         in
         raise (NodeError (node, msg))
-    ); ()
+      | _ ->
+        let args = List.map typecheck args in
+        let check_arg_type arg param =
+          check_type (typeof param) arg;
+        in
+        List.iter2 check_arg_type args params;
+        FunUse (dec, args, Type ret_type :: ann)
+    end
+
+  (* Operators match operand types and get a new type based on the operator *)
+  | Monop (op, opnd, ann) ->
+    let opnd = typecheck opnd in
+    let desc = sprintf "unary operator \"%s\"" (op2str op) in
+    check_type_op (op_types op) desc opnd;
+    Monop (op, opnd, Type (op_result_type (typeof opnd) op) :: ann)
+
+  | Binop (op, left, right, ann) ->
+    let left = typecheck left in
+    let right = typecheck right in
+    let desc = sprintf "binary operator \"%s\"" (op2str op) in
+    check_type_op (op_types op) desc left;
+    check_type (typeof left) right;
+
+    (* Check for division by zero *)
+    begin
+      match (op, right) with
+      | (Div, Const (IntVal 0, _)) -> node_warning right "division by zero"
+      | _ -> ()
+    end;
+
+    Binop (op, left, right, Type (op_result_type (typeof left) op) :: ann)
+
+  (* Conditions must be bool, and right-hand type must match left-hand type *)
+  | Cond (cond, texpr, fexpr, ann) ->
+    let cond = check_trav Bool cond in
+    let texpr = typecheck texpr in
+    let fexpr = check_trav (typeof texpr) fexpr in
+    Cond (cond, texpr, fexpr, Type (typeof texpr) :: ann)
+
+  (* Only basic types can be typecasted *)
+  | TypeCast (ctype, value, ann) ->
+    let value = typecheck value in
+    check_type_op [Bool; Int; Float] "typecast" value;
+    TypeCast (ctype, value, Type (ctype) :: ann)
+
+  (* Array allocation dimensions must have type int *)
+  | Allocate (dec, dims, ann) ->
+    Allocate (dec, List.map (check_trav Int) dims, ann)
+
+  (* Array dimensions are always integers *)
+  | Dim (name, ann) ->
+    Dim (name, Type Int :: ann)
+
+  (* Functions and parameters must be traversed to give types to Dim nodes *)
+  (*
+  | FunDec (ret_type, name, params, ann) ->
+    FunDec (ret_type, name, List.map typecheck params, ann)
+
+  | Param (ArrayDims (ctype, dims), name, ann) ->
+    Param (ArrayDims (ctype, List.map typecheck dims), name, ann)
+    *)
+
+  (* Void functions may have no return statement, other functions must have a
+   * return statement of valid type *)
+  | FunDef (export, ret_type, name, params, body, ann) ->
+    let params = List.map typecheck params in
+    let body = typecheck body in
+    let rec find_return = function
+      | []                         -> None
+      | [Return (value, _) as ret] -> Some (ret, typeof value)
+      | hd :: tl                   -> find_return tl
+    in
+    begin
+      match (ret_type, find_return (block_body body)) with
+      | (Void, Some (ret, _)) ->
+        raise (NodeError (ret, "void function should not have a return value"))
 
-let check_dims_match dims dec_type errnode =
-    match (List.length dims, array_depth dec_type) with
-    | (got, expected) when got != expected ->
+      | ((Bool | Int | Float), None) ->
         let msg = sprintf
-            "dimension mismatch: expected %d indices, got %d" expected got
+          "expected return value of type %s for function \"%s\""
+          (type2str ret_type) name
         in
-        raise (NodeError (errnode, msg))
-    | _ -> ()
+        raise (NodeError (node, msg))
 
-let rec typecheck node =
-    let check_trav ctype node =
-        let node = typecheck node in
-        check_type ctype node;
-        node
-    in
-    match node with
-    | FunUse ((FunDec (ret_type, name, params, _) as dec), args, ann)
-    | FunUse ((FunDef (_, ret_type, name, params, _, _) as dec), args, ann) ->
-        (match (List.length args, List.length params) with
-        | (nargs, nparams) when nargs != nparams ->
-            let msg = sprintf
-                "function \"%s\" expects %d arguments, got %d"
-                name nparams nargs
-            in
-            raise (NodeError (node, msg))
-        | _ ->
-            let args = List.map typecheck args in
-            let check_arg_type arg param =
-                check_type (typeof param) arg;
-            in
-            List.iter2 check_arg_type args params;
-            FunUse (dec, args, Type ret_type :: ann)
-        )
-
-    (* Operators match operand types and get a new type based on the operator *)
-    | Monop (op, opnd, ann) ->
-        let opnd = typecheck opnd in
-        let desc = sprintf "unary operator \"%s\"" (op2str op) in
-        check_type_op (op_types op) desc opnd;
-        Monop (op, opnd, Type (op_result_type (typeof opnd) op) :: ann)
-
-    | Binop (op, left, right, ann) ->
-        let left = typecheck left in
-        let right = typecheck right in
-        let desc = sprintf "binary operator \"%s\"" (op2str op) in
-        check_type_op (op_types op) desc left;
-        check_type (typeof left) right;
-
-        let _ = match (op, right) with
-            | (Div, Const (IntVal 0, _)) -> node_warning right "division by zero"
-            | _ -> ()
+      | ((Bool | Int | Float), Some (ret, t)) when t != ret_type ->
+        let msg = sprintf
+          "function \"%s\" has return type %s, got %s"
+          name (type2str ret_type) (type2str t)
         in
-        Binop (op, left, right, Type (op_result_type (typeof left) op) :: ann)
-
-    (* Conditions must be bool, and right-hand type must match left-hand type *)
-    | Cond (cond, texpr, fexpr, ann) ->
-        let cond = check_trav Bool cond in
-        let texpr = typecheck texpr in
-        let fexpr = check_trav (typeof texpr) fexpr in
-        Cond (cond, texpr, fexpr, Type (typeof texpr) :: ann)
-
-    (* Only basic types can be typecasted *)
-    | TypeCast (ctype, value, ann) ->
-        let value = typecheck value in
-        check_type_op [Bool; Int; Float] "typecast" value;
-        TypeCast (ctype, value, Type (ctype) :: ann)
-
-    (* Array allocation dimensions must have type int *)
-    | Allocate (dec, dims, ann) ->
-        Allocate (dec, List.map (check_trav Int) dims, ann)
-
-    (* Array dimensions are always integers *)
-    | Dim (name, ann) ->
-        Dim (name, Type Int :: ann)
-
-    (* Functions and parameters must be traversed to give types to Dim nodes *)
-    (*
-    | FunDec (ret_type, name, params, ann) ->
-        FunDec (ret_type, name, List.map typecheck params, ann)
-
-    | Param (ArrayDims (ctype, dims), name, ann) ->
-        Param (ArrayDims (ctype, List.map typecheck dims), name, ann)
-        *)
-
-    (* Void functions may have no return statement, other functions must have a
-     * return statement of valid type *)
-    | FunDef (export, ret_type, name, params, body, ann) ->
-        let params = List.map typecheck params in
-        let body = typecheck body in
-        let rec find_return = function
-            | []                         -> None
-            | [Return (value, _) as ret] -> Some (ret, typeof value)
-            | hd :: tl                   -> find_return tl
-        in (
-        match (ret_type, find_return (block_body body)) with
-            | (Void, Some (ret, _)) ->
-                raise (NodeError (ret, "void function should not have a return value"))
-
-            | ((Bool | Int | Float), None) ->
-                let msg = sprintf
-                    "expected return value of type %s for function \"%s\""
-                    (type2str ret_type) name
-                in
-                raise (NodeError (node, msg))
-
-            | ((Bool | Int | Float), Some (ret, t)) when t != ret_type ->
-                let msg = sprintf
-                    "function \"%s\" has return type %s, got %s"
-                    name (type2str ret_type) (type2str t)
-                in
-                raise (NodeError (ret, msg))
-
-            | _ -> FunDef (export, ret_type, name, params, body, ann)
-        )
-
-    (* Conditions in must have type bool *)
-    | If (cond, body, ann) ->
-        If (check_trav Bool cond, typecheck body, ann)
-    | IfElse (cond, tbody, fbody, ann) ->
-        IfElse (check_trav Bool cond, typecheck tbody, typecheck fbody, ann)
-    | While (cond, body, ann) ->
-        While (check_trav Bool cond, typecheck body, ann)
-    | DoWhile (cond, body, ann) ->
-        DoWhile (check_trav Bool cond, typecheck body, ann)
-
-    (* Constants *)
-    | Const (BoolVal value, ann) ->
-        Const (BoolVal value, Type Bool :: ann)
-    | Const (IntVal value, ann) ->
-        (* Do a bound check on integers (use Int32 because default ints in ocaml
-         * are 31- or 63-bit *)
-        let cmpval = Nativeint.of_int value in
-        let min = Nativeint.of_int32 Int32.min_int in
-        let max = Nativeint.of_int32 Int32.max_int in
-        if cmpval < min || cmpval > max then (
-            raise (NodeError (node, "integer value out of range (signed 32-bit)"))
-        );
-        Const (IntVal value, Type Int :: ann)
-    | Const (FloatVal value, ann) ->
-        Const (FloatVal value, Type Float :: ann)
-
-    (* Variables inherit the type of their declaration *)
-    | VarUse (dec, None, ann) ->
-        VarUse (dec, None, Type (typeof dec) :: ann)
-
-    | VarUse (dec, Some dims, ann) ->
-        let dims = List.map typecheck dims in
-        List.iter (check_type Int) dims;
-
-        check_dims_match dims (typeof dec) node;
-        VarUse (dec, Some dims, Type (basetypeof dec) :: ann)
-
-    (* Array pointers cannot be re-assigned, because array dimension reduction
-     * makes assumptions about dimensions of an array *)
-    | VarLet (dec, None, _, _) when is_array dec ->
-        raise (NodeError (node, "cannot assign value to array pointer " ^
-                                "after initialisation"))
-
-    (* Assigned values must match variable declaration *)
-    | VarLet (dec, None, value, ann) ->
-        VarLet (dec, None, check_trav (typeof dec) value, ann)
-
-    | VarLet (dec, Some dims, value, ann) ->
-        (* Number of assigned indices must match array definition *)
-        check_dims_match dims (typeof dec) node;
-
-        (* Array indices must be ints *)
-        let dims = List.map typecheck dims in
-        List.iter (check_type Int) dims;
-
-        (* Assigned value must match array base type *)
-        let value = typecheck value in
-        check_type (basetypeof dec) value;
-
-        VarLet (dec, Some dims, value, ann)
-
-    (* ArrayConst initialisations are transformed during desugaring, so any
-     * occurrences that are left are illegal *)
-    | ArrayConst _ ->
-        raise (NodeError (node, "array constants can only be used in array " ^
-                                "initialisation"))
-
-    | _ -> transform_children typecheck node
+        raise (NodeError (ret, msg))
+
+      | _ -> FunDef (export, ret_type, name, params, body, ann)
+    end
+
+  (* Conditions in must have type bool *)
+  | If (cond, body, ann) ->
+    If (check_trav Bool cond, typecheck body, ann)
+  | IfElse (cond, tbody, fbody, ann) ->
+    IfElse (check_trav Bool cond, typecheck tbody, typecheck fbody, ann)
+  | While (cond, body, ann) ->
+    While (check_trav Bool cond, typecheck body, ann)
+  | DoWhile (cond, body, ann) ->
+    DoWhile (check_trav Bool cond, typecheck body, ann)
+
+  (* Constants *)
+  | Const (BoolVal value, ann) ->
+    Const (BoolVal value, Type Bool :: ann)
+  | Const (IntVal value, ann) ->
+    (* Do a bound check on integers (use Int32 because default ints in ocaml
+     * are 31- or 63-bit *)
+    let cmpval = Nativeint.of_int value in
+    let min = Nativeint.of_int32 Int32.min_int in
+    let max = Nativeint.of_int32 Int32.max_int in
+    if cmpval < min || cmpval > max then (
+      raise (NodeError (node, "integer value out of range (signed 32-bit)"))
+    );
+    Const (IntVal value, Type Int :: ann)
+  | Const (FloatVal value, ann) ->
+    Const (FloatVal value, Type Float :: ann)
+
+  (* Variables inherit the type of their declaration *)
+  | VarUse (dec, None, ann) ->
+    VarUse (dec, None, Type (typeof dec) :: ann)
+
+  | VarUse (dec, Some dims, ann) ->
+    let dims = List.map typecheck dims in
+    List.iter (check_type Int) dims;
+
+    check_dims_match dims (typeof dec) node;
+    VarUse (dec, Some dims, Type (basetypeof dec) :: ann)
+
+  (* Array pointers cannot be re-assigned, because array dimension reduction
+   * makes assumptions about dimensions of an array *)
+  | VarLet (dec, None, _, _) when is_array dec ->
+    raise (NodeError (node, "cannot assign value to array pointer after \
+                             initialisation"))
+
+  (* Assigned values must match variable declaration *)
+  | VarLet (dec, None, value, ann) ->
+    VarLet (dec, None, check_trav (typeof dec) value, ann)
+
+  | VarLet (dec, Some dims, value, ann) ->
+    (* Number of assigned indices must match array definition *)
+    check_dims_match dims (typeof dec) node;
+
+    (* Array indices must be ints *)
+    let dims = List.map typecheck dims in
+    List.iter (check_type Int) dims;
+
+    (* Assigned value must match array base type *)
+    let value = typecheck value in
+    check_type (basetypeof dec) value;
+
+    VarLet (dec, Some dims, value, ann)
+
+  (* ArrayConst initialisations are transformed during desugaring, so any
+   * occurrences that are left are illegal *)
+  | ArrayConst _ ->
+    raise (NodeError (node, "array constants can only be used in array \
+                             initialisation"))
+
+  | _ -> transform_children typecheck node
 
 let phase = function
-    | Ast node -> Ast (typecheck node)
-    | _ -> raise (InvalidInput "typecheck")
+  | Ast node -> Ast (typecheck node)
+  | _ -> raise (InvalidInput "typecheck")

+ 151 - 150
stringify.ml

@@ -8,170 +8,171 @@ let indent = Str.global_replace (Str.regexp "^\\(.\\)") (tab ^ "\\1")
 
 (* const -> string *)
 let const2str = function
-    | BoolVal  b -> string_of_bool b
-    | IntVal   i -> string_of_int i
-    | FloatVal f ->
-        (* Add a trailing zero to a float stringification *)
-        (match string_of_float f with
-        | s when s.[String.length s - 1] = '.' -> s ^ "0"
-        | s -> s
-        )
+  | BoolVal  b -> string_of_bool b
+  | IntVal   i -> string_of_int i
+  | FloatVal f ->
+    (* Add a trailing zero to a float stringification *)
+    begin
+      match string_of_float f with
+      | s when s.[String.length s - 1] = '.' -> s ^ "0"
+      | s -> s
+    end
 
 (* Copied from util.ml to avoid circular dependency *)
 let nameof = function
-    | GlobalDec (_, name, _)
-    | GlobalDef (_, _, name, _, _)
-    | FunDec (_, name, _, _)
-    | FunDef (_, _, name, _, _, _)
-    | VarDec (_, name, _, _)
-    | Param (_, name, _)
-    | Dim (name, _) -> name
-    | _ -> raise InvalidNode
+  | GlobalDec (_, name, _)
+  | GlobalDef (_, _, name, _, _)
+  | FunDec (_, name, _, _)
+  | FunDef (_, _, name, _, _, _)
+  | VarDec (_, name, _, _)
+  | Param (_, name, _)
+  | Dim (name, _) -> name
+  | _ -> raise InvalidNode
 
 (* operator -> string *)
 let op2str = function
-    | Neg -> "-"
-    | Not -> "!"
-    | Add -> "+"
-    | Sub -> "-"
-    | Mul -> "*"
-    | Div -> "/"
-    | Mod -> "%"
-    | Eq  -> "=="
-    | Ne  -> "!="
-    | Lt  -> "<"
-    | Le  -> "<="
-    | Gt  -> ">"
-    | Ge  -> ">="
-    | And -> "&&"
-    | Or  -> "||"
+  | Neg -> "-"
+  | Not -> "!"
+  | Add -> "+"
+  | Sub -> "-"
+  | Mul -> "*"
+  | Div -> "/"
+  | Mod -> "%"
+  | Eq  -> "=="
+  | Ne  -> "!="
+  | Lt  -> "<"
+  | Le  -> "<="
+  | Gt  -> ">"
+  | Ge  -> ">="
+  | And -> "&&"
+  | Or  -> "||"
 
 (* ctype -> string *)
 let rec type2str = function
-    | Void  -> "void"
-    | Bool  -> "bool"
-    | Int   -> "int"
-    | Float -> "float"
-    | ArrayDims (t, dims) -> (type2str t) ^ "[" ^ (concat ", " dims) ^ "]"
-    | Array t             -> (type2str t) ^ "[]"
+  | Void  -> "void"
+  | Bool  -> "bool"
+  | Int   -> "int"
+  | Float -> "float"
+  | ArrayDims (t, dims) -> (type2str t) ^ "[" ^ (concat ", " dims) ^ "]"
+  | Array t             -> (type2str t) ^ "[]"
 
 and concat sep nodes = String.concat sep (List.map node2str nodes)
 
 (* node -> string *)
 and node2str node =
-    let str = node2str in
-    match node with
-
-    (* Global *)
-    | Program (decls, _) ->
-        concat "\n\n" decls
-    | Param (param_type, name, _) ->
-        (type2str param_type) ^ " " ^ name
-    | FunDec (ret_type, name, params, _) ->
-        let params = concat ", " params in
-        "extern " ^ type2str ret_type ^ " " ^ name ^ "(" ^ params ^ ");"
-    | FunDef (export, ret_type, name, params, body, _) ->
-        let export = if export then "export " else "" in
-        let params = "(" ^ (concat ", " params) ^ ")" in
-        export ^ type2str ret_type ^ " " ^ name ^ params ^ " " ^ str body
-    | GlobalDec (var_type, name, _) ->
-        "extern " ^ type2str var_type ^ " " ^ name ^ ";"
-    | GlobalDef (export, ret_type, name, init, _) ->
-        let export = if export then "export " else "" in
-        let init = match init with
-            | Some value -> " = " ^ str value
-            | None -> ""
-        in
-        export ^ (type2str ret_type) ^ " " ^ name ^ init ^ ";"
-
-    (* Statements *)
-    | VarDec (var_type, name, None, _) ->
-        (type2str var_type) ^ " " ^ name ^ ";"
-    | VarDec (var_type, name, Some init, _) ->
-        (type2str var_type) ^ " " ^ name ^ " = " ^ str init ^ ";"
-    | Assign (name, None, value, _) ->
-        name ^ " = " ^ (str value) ^ ";"
-    | Assign (name, Some dims, value, _) ->
-        name ^ "[" ^ (concat ", " dims) ^ "] = " ^ (str value) ^ ";"
-    | Expr expr ->
-        str expr ^ ";"
-    | Return (value, _) ->
-        "return " ^ (str value) ^ ";"
-    | If (cond, body, _) ->
-        "if (" ^ str cond ^ ") " ^ str body
-    | IfElse (cond, true_body, false_body, _) ->
-        "if (" ^ str cond ^ ") " ^ str true_body ^ " else " ^ str false_body
-    | While (cond, body, _) ->
-        "while (" ^ str cond ^ ") " ^ str body
-    | DoWhile (cond, body, _) ->
-        "do " ^ str body ^ " while (" ^ str cond ^ ");"
-    | For (counter, start, stop, step, body, _) ->
-        let step = match step with
-            | Const (IntVal 1, _) -> ""
-            | value -> ", " ^ str value
-        in
-        let range = str start ^ ", " ^ str stop ^ step in
-        "for (int " ^ counter ^ " = " ^ range ^ ") " ^ str body
-    | Allocate (dec, dims, _) ->
-        nameof dec ^ " := <allocate>(" ^ concat ", " dims ^ ");"
-    | Block body ->
-        let rec append = function
-            | [] -> ""
-            | [last] -> last
-            | "" :: tl -> append tl
-            | hd :: tl -> hd ^ "\n" ^ append tl
-        in
-        "{\n" ^ indent (append (List.map str body)) ^ "\n}"
-
-    (* Expressions *)
-    | Const (c, _) -> const2str c
-    | ArrayConst (dims, _) -> "[" ^ concat ", " dims ^ "]"
-    | Var (v, None, _) -> v
-    | Var (name, Some dims, _) -> name ^ (str (ArrayConst (dims, [])))
-    | Monop (op, opnd, _) -> op2str op ^ str opnd
-    | Binop (op, left, right, _) ->
-        "(" ^ str left ^ " " ^ op2str op ^ " " ^ str right ^ ")"
-    | TypeCast (ctype, value, _) -> "(" ^ type2str ctype ^ ")" ^ str value
-    | FunCall (name, args, _) -> name ^ "(" ^ (concat ", " args) ^ ")"
-    | Cond (cond, t, f, _) -> "(" ^ (str cond) ^ " ? " ^ str t ^ " : " ^ str f ^ ")"
-
-    (* Annotation nodes print more information at higher verbosity, for
-     * debugging purposes *)
-    | VarLet (dec, dims, value, _) when args.verbose >= 3 ->
-        "<let:" ^ node2str (Assign (nameof dec, dims, value, [])) ^ ">"
-    | VarUse (dec, dims, _)        when args.verbose >= 3 ->
-        "<use:" ^ node2str (Var (nameof dec, dims, [])) ^ ">"
-    | FunUse (dec, params, _)      when args.verbose >= 3 ->
-        "<use:" ^ node2str (FunCall (nameof dec, params, [])) ^ ">"
-    | Dim (name, _)                when args.verbose >= 3 ->
-        "<dim:" ^ name ^ ">"
-    | ArrayScalar value            when args.verbose >= 3 ->
-        "<scalar:" ^ str value ^ ">"
-    | Arg node                     when args.verbose >= 3 ->
-        "<arg:" ^ str node ^ ">"
-    | VarDecs nodes                when args.verbose >= 3 ->
-        String.concat "\n" ("// vardecs" :: List.map str nodes)
-    | LocalFuns nodes              when args.verbose >= 3 ->
-        String.concat "\n" ("// localfuns" :: List.map str nodes)
-
-    | VarLet (dec, dims, value, _) ->
-        node2str (Assign (nameof dec, dims, value, []))
-    | VarUse (dec, dims, _) ->
-        node2str (Var (nameof dec, dims, []))
-    | FunUse (dec, args, _) ->
-        node2str (FunCall (nameof dec, args, []))
-    | Dim (name, _) -> name
-    | ArrayScalar node
-    | ArrayInit (node, _)
-    | Arg node -> str node
-
-    | VarDecs nodes
-    | LocalFuns nodes -> concat "\n" nodes
-
-    | DummyNode -> "<dummy>"
+  let str = node2str in
+  match node with
+
+  (* Global *)
+  | Program (decls, _) ->
+    concat "\n\n" decls
+  | Param (param_type, name, _) ->
+    (type2str param_type) ^ " " ^ name
+  | FunDec (ret_type, name, params, _) ->
+    let params = concat ", " params in
+    "extern " ^ type2str ret_type ^ " " ^ name ^ "(" ^ params ^ ");"
+  | FunDef (export, ret_type, name, params, body, _) ->
+    let export = if export then "export " else "" in
+    let params = "(" ^ (concat ", " params) ^ ")" in
+    export ^ type2str ret_type ^ " " ^ name ^ params ^ " " ^ str body
+  | GlobalDec (var_type, name, _) ->
+    "extern " ^ type2str var_type ^ " " ^ name ^ ";"
+  | GlobalDef (export, ret_type, name, init, _) ->
+    let export = if export then "export " else "" in
+    let init = match init with
+      | Some value -> " = " ^ str value
+      | None -> ""
+    in
+    export ^ (type2str ret_type) ^ " " ^ name ^ init ^ ";"
+
+  (* Statements *)
+  | VarDec (var_type, name, None, _) ->
+    (type2str var_type) ^ " " ^ name ^ ";"
+  | VarDec (var_type, name, Some init, _) ->
+    (type2str var_type) ^ " " ^ name ^ " = " ^ str init ^ ";"
+  | Assign (name, None, value, _) ->
+    name ^ " = " ^ (str value) ^ ";"
+  | Assign (name, Some dims, value, _) ->
+    name ^ "[" ^ (concat ", " dims) ^ "] = " ^ (str value) ^ ";"
+  | Expr expr ->
+    str expr ^ ";"
+  | Return (value, _) ->
+    "return " ^ (str value) ^ ";"
+  | If (cond, body, _) ->
+    "if (" ^ str cond ^ ") " ^ str body
+  | IfElse (cond, true_body, false_body, _) ->
+    "if (" ^ str cond ^ ") " ^ str true_body ^ " else " ^ str false_body
+  | While (cond, body, _) ->
+    "while (" ^ str cond ^ ") " ^ str body
+  | DoWhile (cond, body, _) ->
+    "do " ^ str body ^ " while (" ^ str cond ^ ");"
+  | For (counter, start, stop, step, body, _) ->
+    let step = match step with
+      | Const (IntVal 1, _) -> ""
+      | value -> ", " ^ str value
+    in
+    let range = str start ^ ", " ^ str stop ^ step in
+    "for (int " ^ counter ^ " = " ^ range ^ ") " ^ str body
+  | Allocate (dec, dims, _) ->
+    nameof dec ^ " := <allocate>(" ^ concat ", " dims ^ ");"
+  | Block body ->
+    let rec append = function
+      | [] -> ""
+      | [last] -> last
+      | "" :: tl -> append tl
+      | hd :: tl -> hd ^ "\n" ^ append tl
+    in
+    "{\n" ^ indent (append (List.map str body)) ^ "\n}"
+
+  (* Expressions *)
+  | Const (c, _) -> const2str c
+  | ArrayConst (dims, _) -> "[" ^ concat ", " dims ^ "]"
+  | Var (v, None, _) -> v
+  | Var (name, Some dims, _) -> name ^ (str (ArrayConst (dims, [])))
+  | Monop (op, opnd, _) -> op2str op ^ str opnd
+  | Binop (op, left, right, _) ->
+    "(" ^ str left ^ " " ^ op2str op ^ " " ^ str right ^ ")"
+  | TypeCast (ctype, value, _) -> "(" ^ type2str ctype ^ ")" ^ str value
+  | FunCall (name, args, _) -> name ^ "(" ^ (concat ", " args) ^ ")"
+  | Cond (cond, t, f, _) -> "(" ^ (str cond) ^ " ? " ^ str t ^ " : " ^ str f ^ ")"
+
+  (* Annotation nodes print more information at higher verbosity, for
+   * debugging purposes *)
+  | VarLet (dec, dims, value, _) when args.verbose >= 3 ->
+    "<let:" ^ node2str (Assign (nameof dec, dims, value, [])) ^ ">"
+  | VarUse (dec, dims, _)        when args.verbose >= 3 ->
+    "<use:" ^ node2str (Var (nameof dec, dims, [])) ^ ">"
+  | FunUse (dec, params, _)      when args.verbose >= 3 ->
+    "<use:" ^ node2str (FunCall (nameof dec, params, [])) ^ ">"
+  | Dim (name, _)                when args.verbose >= 3 ->
+    "<dim:" ^ name ^ ">"
+  | ArrayScalar value            when args.verbose >= 3 ->
+    "<scalar:" ^ str value ^ ">"
+  | Arg node                     when args.verbose >= 3 ->
+    "<arg:" ^ str node ^ ">"
+  | VarDecs nodes                when args.verbose >= 3 ->
+    String.concat "\n" ("// vardecs" :: List.map str nodes)
+  | LocalFuns nodes              when args.verbose >= 3 ->
+    String.concat "\n" ("// localfuns" :: List.map str nodes)
+
+  | VarLet (dec, dims, value, _) ->
+    node2str (Assign (nameof dec, dims, value, []))
+  | VarUse (dec, dims, _) ->
+    node2str (Var (nameof dec, dims, []))
+  | FunUse (dec, args, _) ->
+    node2str (FunCall (nameof dec, args, []))
+  | Dim (name, _) -> name
+  | ArrayScalar node
+  | ArrayInit (node, _)
+  | Arg node -> str node
+
+  | VarDecs nodes
+  | LocalFuns nodes -> concat "\n" nodes
+
+  | DummyNode -> "<dummy>"
 
 (* ctype list -> string *)
 let rec types2str = function
-    | [] -> ""
-    | [ctype] -> type2str ctype
-    | ctype :: tail -> type2str ctype ^ " or " ^ (types2str tail)
+  | [] -> ""
+  | [ctype] -> type2str ctype
+  | ctype :: tail -> type2str ctype ^ " or " ^ (types2str tail)

+ 126 - 126
types.mli

@@ -5,157 +5,157 @@ type location = string * int * int * int * int
 
 (**  *)
 type operator =
-    | Neg | Not
-    | Add | Sub | Mul | Div | Mod
-    | Eq | Ne | Lt | Le | Gt | Ge
-    | And | Or
+  | Neg | Not
+  | Add | Sub | Mul | Div | Mod
+  | Eq | Ne | Lt | Le | Gt | Ge
+  | And | Or
 
 (**  *)
 type const =
-    | BoolVal of bool
-    | IntVal of int
-    | FloatVal of float
+  | BoolVal of bool
+  | IntVal of int
+  | FloatVal of float
 
 (**  *)
 type ctype =
-    | Void | Bool | Int | Float | Array of ctype
-    | ArrayDims of ctype * node list
+  | Void | Bool | Int | Float | Array of ctype
+  | ArrayDims of ctype * node list
 
 (**  *)
 and annotation =
-    | Loc of location
-    | Depth of int
-    | Index of int
-    | Type of ctype
-    | LabelName of string
+  | Loc of location
+  | Depth of int
+  | Index of int
+  | Type of ctype
+  | LabelName of string
 
 (** Shorthand for annotation list, only to be used by {! Types.node} definitions
-    below. *)
+  below. *)
 and ann = annotation list
 
 (**  *)
 and node =
-    (* Global *)
-    | Program of node list * ann
-      (* list of declarations *)
-    | FunDec of ctype * string * node list * ann
-      (* ret_type, name, params *)
-    | FunDef of bool * ctype * string * node list * node * ann
-      (* export, ret_type, name, params, body *)
-    | GlobalDec of ctype * string * ann
-      (* type, name *)
-    | GlobalDef of bool * ctype * string * node option * ann
-      (* export, type, name, initialisation? *)
-    | Param of ctype * string * ann
-      (* type, name *)
-    | Dim of string * ann
-      (* name *)
-
-    | VarDecs of node list
-    | LocalFuns of node list
-
-    (* Statements *)
-    | VarDec of ctype * string * node option * ann
-      (* type, name, initialisation? *)
-    | Assign of string * node list option * node * ann
-      (* name, indices?, value *)
-    | For of string * node * node * node * node * ann
-      (* counter, start, stop, step, body *)
-    | Allocate of node * node list * ann
-      (* dec, dims  # name = __allocate(dims) *)
-    | Return of node * ann                   (* return <value>; *)
-    | Expr of node                           (* <expr>; *)
-    | Block of node list                     (* { <body> } *)
-    | If of node * node * ann                (* cond, body *)
-    | IfElse of node * node * node * ann     (* cond, true_body, false_body *)
-    | While of node * node * ann             (* cond, body *)
-    | DoWhile of node * node * ann           (* cond, body *)
-
-    (* Expressions *)
-    | Const of const * ann                     (* bool|int|float value *)
-    | ArrayConst of node list * ann            (* [<exprs>] *)
-    | Var of string * node list option * ann   (* <name> [<indices>]? *)
-    | Monop of operator * node * ann           (* op, operand *)
-    | Binop of operator * node * node * ann    (* op, left, right *)
-    | TypeCast of ctype * node * ann           (* (type) operand *)
-    | FunCall of string * node list * ann      (* name(args) *)
-    | Arg of node                              (* function argument *)
-
-    (* Additional types for convenience in traversals
-     * Mostly used to annotate existing nodes with information from declarations *)
-    | VarUse of node * node list option * ann  (* Same as Var, but with decl. *)
-    | FunUse of node * node list * ann         (* Same as FunCall, but with decl. *)
-    | VarLet of node * node list option * node * ann (* replacement for Assign *)
-    | ArrayScalar of node                      (* (Bool|Int|Float)Const *)
-    | ArrayInit of node * node list            (* Array(Scalar|Const), dimensions *)
-    | Cond of node * node * node * ann         (* cond, true_expr, false_expr *)
-    | DummyNode                                (* null node, pruned by traversals *)
+  (* Global *)
+  | Program of node list * ann
+    (* list of declarations *)
+  | FunDec of ctype * string * node list * ann
+    (* ret_type, name, params *)
+  | FunDef of bool * ctype * string * node list * node * ann
+    (* export, ret_type, name, params, body *)
+  | GlobalDec of ctype * string * ann
+    (* type, name *)
+  | GlobalDef of bool * ctype * string * node option * ann
+    (* export, type, name, initialisation? *)
+  | Param of ctype * string * ann
+    (* type, name *)
+  | Dim of string * ann
+    (* name *)
+
+  | VarDecs of node list
+  | LocalFuns of node list
+
+  (* Statements *)
+  | VarDec of ctype * string * node option * ann
+    (* type, name, initialisation? *)
+  | Assign of string * node list option * node * ann
+    (* name, indices?, value *)
+  | For of string * node * node * node * node * ann
+    (* counter, start, stop, step, body *)
+  | Allocate of node * node list * ann
+    (* dec, dims  # name = __allocate(dims) *)
+  | Return of node * ann                   (* return <value>; *)
+  | Expr of node                           (* <expr>; *)
+  | Block of node list                     (* { <body> } *)
+  | If of node * node * ann                (* cond, body *)
+  | IfElse of node * node * node * ann     (* cond, true_body, false_body *)
+  | While of node * node * ann             (* cond, body *)
+  | DoWhile of node * node * ann           (* cond, body *)
+
+  (* Expressions *)
+  | Const of const * ann                     (* bool|int|float value *)
+  | ArrayConst of node list * ann            (* [<exprs>] *)
+  | Var of string * node list option * ann   (* <name> [<indices>]? *)
+  | Monop of operator * node * ann           (* op, operand *)
+  | Binop of operator * node * node * ann    (* op, left, right *)
+  | TypeCast of ctype * node * ann           (* (type) operand *)
+  | FunCall of string * node list * ann      (* name(args) *)
+  | Arg of node                              (* function argument *)
+
+  (* Additional types for convenience in traversals
+   * Mostly used to annotate existing nodes with information from declarations *)
+  | VarUse of node * node list option * ann  (* Same as Var, but with decl. *)
+  | FunUse of node * node list * ann         (* Same as FunCall, but with decl. *)
+  | VarLet of node * node list option * node * ann (* replacement for Assign *)
+  | ArrayScalar of node                      (* (Bool|Int|Float)Const *)
+  | ArrayInit of node * node list            (* Array(Scalar|Const), dimensions *)
+  | Cond of node * node * node * ann         (* cond, true_expr, false_expr *)
+  | DummyNode                                (* null node, pruned by traversals *)
 
 type stack_scope = Glob | Local | Rel of int | Current
 type rtn_scope = ExternFun of int | LocalFun of int * string
 type instr =
-    | Comment of string                 (* # <comment> *)
-    | InlineComment of instr * string   (* <instr>  # <comment> *)
-    | Label of string                   (* <label>: *)
-
-    (* Directives *)
-    (* .export "<name>" <ret_type> [ <arg_type>; ... ] <label> *)
-    | Export of string * ctype * ctype list * string
-    (* .import "<name>" <ret_type> [ <arg_type>; ... ] *)
-    | Import of string * ctype * ctype list
-    (* .const <value> *)
-    | ConstDef of const
-    (* .global <type> *)
-    | Global of ctype
-
-    | Store of ctype * stack_scope * int (* [ifba]store[ gn] *)
-
-    | Load of ctype * stack_scope * int  (* [ifb]load[ gn] G *)
-    | LoadConst of ctype * int           (* [ifb]loadc C *)
-    | LoadImm of const                   (* [ifb]load_[01tf] <value> *)
-
-    (* Operators *)
-    | Op of operator * ctype             (* [ifb]() *)
-    | Convert of ctype * ctype           (* i2f|f2i *)
-    | Inc of int * int                   (* iinc L C *)
-    | Dec of int * int                   (* idec L C *)
-    | IncOne of int                      (* iinc_1 L *)
-    | DecOne of int                      (* idec_1 L *)
-
-    (* Control flow *)
-    | RtnInit of stack_scope
-    | RtnJmp of rtn_scope
-    | RtnEnter of int
-    | Ret of ctype
-    | Branch of bool * string
-    | Jump of string
-
-    (* Stack management *)
-    | Pop of ctype                       (* [ifb]pop *)
-
-    (* Arrays *)
-    | NewArray of ctype * int
-    | LoadArray of ctype
-    | StoreArray of ctype
-
-    | EmptyLine
-    | DummyInstr
+  | Comment of string                 (* # <comment> *)
+  | InlineComment of instr * string   (* <instr>  # <comment> *)
+  | Label of string                   (* <label>: *)
+
+  (* Directives *)
+  (* .export "<name>" <ret_type> [ <arg_type>; ... ] <label> *)
+  | Export of string * ctype * ctype list * string
+  (* .import "<name>" <ret_type> [ <arg_type>; ... ] *)
+  | Import of string * ctype * ctype list
+  (* .const <value> *)
+  | ConstDef of const
+  (* .global <type> *)
+  | Global of ctype
+
+  | Store of ctype * stack_scope * int (* [ifba]store[ gn] *)
+
+  | Load of ctype * stack_scope * int  (* [ifb]load[ gn] G *)
+  | LoadConst of ctype * int           (* [ifb]loadc C *)
+  | LoadImm of const                   (* [ifb]load_[01tf] <value> *)
+
+  (* Operators *)
+  | Op of operator * ctype             (* [ifb]() *)
+  | Convert of ctype * ctype           (* i2f|f2i *)
+  | Inc of int * int                   (* iinc L C *)
+  | Dec of int * int                   (* idec L C *)
+  | IncOne of int                      (* iinc_1 L *)
+  | DecOne of int                      (* idec_1 L *)
+
+  (* Control flow *)
+  | RtnInit of stack_scope
+  | RtnJmp of rtn_scope
+  | RtnEnter of int
+  | Ret of ctype
+  | Branch of bool * string
+  | Jump of string
+
+  (* Stack management *)
+  | Pop of ctype                       (* [ifb]pop *)
+
+  (* Arrays *)
+  | NewArray of ctype * int
+  | LoadArray of ctype
+  | StoreArray of ctype
+
+  | EmptyLine
+  | DummyInstr
 
 (* Intermediate representations between phases *)
 type intermediate =
-    | Empty
-    | FileContent of string * string
-    | Ast of node
-    | Assembly of instr list
+  | Empty
+  | FileContent of string * string
+  | Ast of node
+  | Assembly of instr list
 
 (** Container for command-line arguments. *)
 type args_record = {
-    mutable infile   : string option;
-    mutable outfile  : string option;
-    mutable verbose  : int;
-    mutable cpp      : bool;
-    mutable optimize : bool;
-    mutable endphase : string;
+  mutable infile   : string option;
+  mutable outfile  : string option;
+  mutable verbose  : int;
+  mutable cpp      : bool;
+  mutable optimize : bool;
+  mutable endphase : string;
 }
 
 (* Exceptions *)

+ 356 - 356
util.ml

@@ -19,333 +19,333 @@ let prt_line = prerr_endline
 let prt_node node = prt_line (Stringify.node2str node)
 
 let log_plain_line verbosity line =
-    if args.verbose >= verbosity then prt_line line
+  if args.verbose >= verbosity then prt_line line
 
 let log_line verbosity line =
-    log_plain_line verbosity (repeat " " 13 ^ line)
+  log_plain_line verbosity (repeat " " 13 ^ line)
 
 let log_node verbosity node =
-    if args.verbose >= verbosity then prt_node node
+  if args.verbose >= verbosity then prt_node node
 
 (* Variable generation *)
 let var_counter = ref 0
 let fresh_var prefix =
-    var_counter := !var_counter + 1;
-    prefix ^ "$" ^ string_of_int !var_counter
+  var_counter := !var_counter + 1;
+  prefix ^ "$" ^ string_of_int !var_counter
 
 (* Constants are marked by a double $$ for recognition during constant
  * propagation *)
 let fresh_const prefix = fresh_var (prefix ^ "$")
 
 let loc_from_lexpos pstart pend =
-    let (fname, ystart, yend, xstart, xend) = (
-        pstart.pos_fname,
-        pstart.pos_lnum,
-        pend.pos_lnum,
-        (pstart.pos_cnum - pstart.pos_bol + 1),
-        (pend.pos_cnum - pend.pos_bol)
-    ) in
-    if ystart = yend && xend < xstart then
-        (fname, ystart, yend, xstart, xstart)
-    else
-        (fname, ystart, yend, xstart, xend)
+  let (fname, ystart, yend, xstart, xend) = begin
+    pstart.pos_fname,
+    pstart.pos_lnum,
+    pend.pos_lnum,
+    (pstart.pos_cnum - pstart.pos_bol + 1),
+    (pend.pos_cnum - pend.pos_bol)
+  end in
+  if ystart = yend && xend < xstart then
+    (fname, ystart, yend, xstart, xstart)
+  else
+    (fname, ystart, yend, xstart, xend)
 
 let rec flatten_blocks lst =
-    let flatten = flatten_blocks in
-    let rec trav = function
-        | Block body ->
-            Block (flatten body)
-        | FunDef (export, ret_type, name, params, body, ann) ->
-            FunDef (export, ret_type, name, flatten params, trav body, ann)
-        | If (cond, body, ann) ->
-            If (cond, trav body, ann)
-        | IfElse (cond, tbody, fbody, ann) ->
-            IfElse (cond, trav tbody, trav fbody, ann)
-        | While (cond, body, ann) ->
-            While (cond, trav body, ann)
-        | DoWhile (cond, body, ann) ->
-            DoWhile (cond, trav body, ann)
-        | For (counter, start, stop, step, body, ann) ->
-            For (counter, start, stop, step, trav body, ann)
-        | VarDecs decs ->
-            VarDecs (flatten decs)
-        | LocalFuns decs ->
-            LocalFuns (flatten decs)
-        | node -> node
-    in
-    match lst with
-    | []                -> []
-    | Block nodes :: tl -> flatten nodes @ (flatten tl)
-    | DummyNode :: tl   -> flatten tl
-    | hd :: tl          -> trav hd :: (flatten tl)
-
-(* Default tree transformation
- * (node -> node) -> node -> node *)
-let transform_children trav node =
-    let trav_all nodes = List.map trav nodes in
-    match node with
-    | Program (decls, ann) ->
-        Program (flatten_blocks (trav_all decls), ann)
-    | FunDec (ret_type, name, params, ann) ->
-        FunDec (ret_type, name, trav_all params, ann)
+  let flatten = flatten_blocks in
+  let rec trav = function
+    | Block body ->
+      Block (flatten body)
     | FunDef (export, ret_type, name, params, body, ann) ->
-        FunDef (export, ret_type, name, trav_all params, trav body, ann)
-    | GlobalDec (ctype, name, ann) ->
-        GlobalDec (ctype, name, ann)
-    | GlobalDef (export, ctype, name, Some init, ann) ->
-        GlobalDef (export, ctype, name, Some (trav init), ann)
-
-    | VarDecs decs ->
-        VarDecs (trav_all decs)
-    | LocalFuns funs ->
-        LocalFuns (trav_all funs)
-
-    | VarDec (ctype, name, Some init, ann) ->
-        VarDec (ctype, name, Some (trav init), ann)
-    | Assign (name, None, value, ann) ->
-        Assign (name, None, trav value, ann)
-    | Assign (name, Some dims, value, ann) ->
-        Assign (name, Some (trav_all dims), trav value, ann)
-    | VarLet (dec, None, value, ann) ->
-        VarLet (dec, None, trav value, ann)
-    | VarLet (dec, Some dims, value, ann) ->
-        VarLet (dec, Some (trav_all dims), trav value, ann)
-    | Return (value, ann) ->
-        Return (trav value, ann)
+      FunDef (export, ret_type, name, flatten params, trav body, ann)
     | If (cond, body, ann) ->
-        If (trav cond, trav body, ann)
-    | IfElse (cond, true_body, false_body, ann) ->
-        IfElse (trav cond, trav true_body, trav false_body, ann)
+      If (cond, trav body, ann)
+    | IfElse (cond, tbody, fbody, ann) ->
+      IfElse (cond, trav tbody, trav fbody, ann)
     | While (cond, body, ann) ->
-        While (trav cond, trav body, ann)
+      While (cond, trav body, ann)
     | DoWhile (cond, body, ann) ->
-        DoWhile (trav cond, trav body, ann)
+      DoWhile (cond, trav body, ann)
     | For (counter, start, stop, step, body, ann) ->
-        For (counter, trav start, trav stop, trav step, trav body, ann)
-    | Allocate (dec, dims, ann) ->
-        Allocate (dec, trav_all dims, ann)
-    | Expr value ->
-        Expr (trav value)
-    | Block (body) ->
-        Block (trav_all body)
-
-    | Monop (op, value, ann) ->
-        Monop (op, trav value, ann)
-    | Binop (op, left, right, ann) ->
-        Binop (op, trav left, trav right, ann)
-    | Cond (cond, true_expr, false_expr, ann) ->
-        Cond (trav cond, trav true_expr, trav false_expr, ann)
-    | TypeCast (ctype, value, ann) ->
-        TypeCast (ctype, trav value, ann)
-    | FunCall (name, args, ann) ->
-        FunCall (name, trav_all args, ann)
-    | Arg value ->
-        Arg (trav value)
-
-    | ArrayInit (value, dims) ->
-        ArrayInit (trav value, dims)
-    | ArrayScalar value ->
-        ArrayScalar (trav value)
-    | Var (dec, Some dims, ann) ->
-        Var (dec, Some (trav_all dims), ann)
-    | VarUse (dec, Some dims, ann) ->
-        VarUse (dec, Some (trav_all dims), ann)
-    | FunUse (dec, params, ann) ->
-        FunUse (dec, trav_all params, ann)
-
-    | _ -> node
+      For (counter, start, stop, step, trav body, ann)
+    | VarDecs decs ->
+      VarDecs (flatten decs)
+    | LocalFuns decs ->
+      LocalFuns (flatten decs)
+    | node -> node
+  in
+  match lst with
+  | []                -> []
+  | Block nodes :: tl -> flatten nodes @ (flatten tl)
+  | DummyNode :: tl   -> flatten tl
+  | hd :: tl          -> trav hd :: (flatten tl)
+
+(* Default tree transformation
+ * (node -> node) -> node -> node *)
+let transform_children trav node =
+  let trav_all nodes = List.map trav nodes in
+  match node with
+  | Program (decls, ann) ->
+    Program (flatten_blocks (trav_all decls), ann)
+  | FunDec (ret_type, name, params, ann) ->
+    FunDec (ret_type, name, trav_all params, ann)
+  | FunDef (export, ret_type, name, params, body, ann) ->
+    FunDef (export, ret_type, name, trav_all params, trav body, ann)
+  | GlobalDec (ctype, name, ann) ->
+    GlobalDec (ctype, name, ann)
+  | GlobalDef (export, ctype, name, Some init, ann) ->
+    GlobalDef (export, ctype, name, Some (trav init), ann)
+
+  | VarDecs decs ->
+    VarDecs (trav_all decs)
+  | LocalFuns funs ->
+    LocalFuns (trav_all funs)
+
+  | VarDec (ctype, name, Some init, ann) ->
+    VarDec (ctype, name, Some (trav init), ann)
+  | Assign (name, None, value, ann) ->
+    Assign (name, None, trav value, ann)
+  | Assign (name, Some dims, value, ann) ->
+    Assign (name, Some (trav_all dims), trav value, ann)
+  | VarLet (dec, None, value, ann) ->
+    VarLet (dec, None, trav value, ann)
+  | VarLet (dec, Some dims, value, ann) ->
+    VarLet (dec, Some (trav_all dims), trav value, ann)
+  | Return (value, ann) ->
+    Return (trav value, ann)
+  | If (cond, body, ann) ->
+    If (trav cond, trav body, ann)
+  | IfElse (cond, true_body, false_body, ann) ->
+    IfElse (trav cond, trav true_body, trav false_body, ann)
+  | While (cond, body, ann) ->
+    While (trav cond, trav body, ann)
+  | DoWhile (cond, body, ann) ->
+    DoWhile (trav cond, trav body, ann)
+  | For (counter, start, stop, step, body, ann) ->
+    For (counter, trav start, trav stop, trav step, trav body, ann)
+  | Allocate (dec, dims, ann) ->
+    Allocate (dec, trav_all dims, ann)
+  | Expr value ->
+    Expr (trav value)
+  | Block (body) ->
+    Block (trav_all body)
+
+  | Monop (op, value, ann) ->
+    Monop (op, trav value, ann)
+  | Binop (op, left, right, ann) ->
+    Binop (op, trav left, trav right, ann)
+  | Cond (cond, true_expr, false_expr, ann) ->
+    Cond (trav cond, trav true_expr, trav false_expr, ann)
+  | TypeCast (ctype, value, ann) ->
+    TypeCast (ctype, trav value, ann)
+  | FunCall (name, args, ann) ->
+    FunCall (name, trav_all args, ann)
+  | Arg value ->
+    Arg (trav value)
+
+  | ArrayInit (value, dims) ->
+    ArrayInit (trav value, dims)
+  | ArrayScalar value ->
+    ArrayScalar (trav value)
+  | Var (dec, Some dims, ann) ->
+    Var (dec, Some (trav_all dims), ann)
+  | VarUse (dec, Some dims, ann) ->
+    VarUse (dec, Some (trav_all dims), ann)
+  | FunUse (dec, params, ann) ->
+    FunUse (dec, trav_all params, ann)
+
+  | _ -> node
 
 let annotate a = function
-    | Program (decls, ann) ->
-        Program (decls, a :: ann)
-    | FunDec (ret_type, name, params, ann) ->
-        FunDec (ret_type, name, params, a :: ann)
-    | FunDef (export, ret_type, name, params, body, ann) ->
-        FunDef (export, ret_type, name, params, body, a :: ann)
-    | GlobalDec (ctype, name, ann) ->
-        GlobalDec (ctype, name, a :: ann)
-    | GlobalDef (export, ctype, name, init, ann) ->
-        GlobalDef (export, ctype, name, init, a :: ann)
-    | VarDec (ctype, name, init, ann) ->
-        VarDec (ctype, name, init, a :: ann)
-    | Assign (name, dims, value, ann) ->
-        Assign (name, dims, value, a :: ann)
-    | VarLet (dec, dims, value, ann) ->
-        VarLet (dec, dims, value, a :: ann)
-    | Return (value, ann) ->
-        Return (value, a :: ann)
-    | If (cond, body, ann) ->
-        If (cond, body, a :: ann)
-    | IfElse (cond, true_body, false_body, ann) ->
-        IfElse (cond, true_body, false_body, a :: ann)
-    | While (cond, body, ann) ->
-        While (cond, body, a :: ann)
-    | DoWhile (cond, body, ann) ->
-        DoWhile (cond, body, a :: ann)
-    | For (counter, start, stop, step, body, ann) ->
-        For (counter, start, stop, step, body, a :: ann)
-    | Allocate (dec, dims, ann) ->
-        Allocate (dec, dims, a :: ann)
-    | Monop (op, value, ann) ->
-        Monop (op, value, a :: ann)
-    | Binop (op, left, right, ann) ->
-        Binop (op, left, right, a :: ann)
-    | Cond (cond, true_expr, false_expr, ann) ->
-        Cond (cond, true_expr, false_expr, a :: ann)
-    | TypeCast (ctype, value, ann) ->
-        TypeCast (ctype, value, a :: ann)
-    | FunCall (name, args, ann) ->
-        FunCall (name, args, a :: ann)
-    | Arg value ->
-        Arg (value)
-    | Var (dec, dims, ann) ->
-        Var (dec, dims, a :: ann)
-    | VarUse (dec, dims, ann) ->
-        VarUse (dec, dims, a :: ann)
-    | FunUse (dec, params, ann) ->
-        FunUse (dec, params, a :: ann)
-    | Const (BoolVal value, ann) ->
-        Const (BoolVal value, a :: ann)
-    | Const (IntVal value, ann) ->
-        Const (IntVal value, a :: ann)
-    | Const (FloatVal value, ann) ->
-        Const (FloatVal value, a :: ann)
-    | ArrayConst (value, ann) ->
-        ArrayConst (value, a :: ann)
-    | Param (ctype, name, ann) ->
-        Param (ctype, name, a :: ann)
-    | Dim (name, ann) ->
-        Dim (name, a :: ann)
-
-    | _ -> raise InvalidNode
+  | Program (decls, ann) ->
+    Program (decls, a :: ann)
+  | FunDec (ret_type, name, params, ann) ->
+    FunDec (ret_type, name, params, a :: ann)
+  | FunDef (export, ret_type, name, params, body, ann) ->
+    FunDef (export, ret_type, name, params, body, a :: ann)
+  | GlobalDec (ctype, name, ann) ->
+    GlobalDec (ctype, name, a :: ann)
+  | GlobalDef (export, ctype, name, init, ann) ->
+    GlobalDef (export, ctype, name, init, a :: ann)
+  | VarDec (ctype, name, init, ann) ->
+    VarDec (ctype, name, init, a :: ann)
+  | Assign (name, dims, value, ann) ->
+    Assign (name, dims, value, a :: ann)
+  | VarLet (dec, dims, value, ann) ->
+    VarLet (dec, dims, value, a :: ann)
+  | Return (value, ann) ->
+    Return (value, a :: ann)
+  | If (cond, body, ann) ->
+    If (cond, body, a :: ann)
+  | IfElse (cond, true_body, false_body, ann) ->
+    IfElse (cond, true_body, false_body, a :: ann)
+  | While (cond, body, ann) ->
+    While (cond, body, a :: ann)
+  | DoWhile (cond, body, ann) ->
+    DoWhile (cond, body, a :: ann)
+  | For (counter, start, stop, step, body, ann) ->
+    For (counter, start, stop, step, body, a :: ann)
+  | Allocate (dec, dims, ann) ->
+    Allocate (dec, dims, a :: ann)
+  | Monop (op, value, ann) ->
+    Monop (op, value, a :: ann)
+  | Binop (op, left, right, ann) ->
+    Binop (op, left, right, a :: ann)
+  | Cond (cond, true_expr, false_expr, ann) ->
+    Cond (cond, true_expr, false_expr, a :: ann)
+  | TypeCast (ctype, value, ann) ->
+    TypeCast (ctype, value, a :: ann)
+  | FunCall (name, args, ann) ->
+    FunCall (name, args, a :: ann)
+  | Arg value ->
+    Arg (value)
+  | Var (dec, dims, ann) ->
+    Var (dec, dims, a :: ann)
+  | VarUse (dec, dims, ann) ->
+    VarUse (dec, dims, a :: ann)
+  | FunUse (dec, params, ann) ->
+    FunUse (dec, params, a :: ann)
+  | Const (BoolVal value, ann) ->
+    Const (BoolVal value, a :: ann)
+  | Const (IntVal value, ann) ->
+    Const (IntVal value, a :: ann)
+  | Const (FloatVal value, ann) ->
+    Const (FloatVal value, a :: ann)
+  | ArrayConst (value, ann) ->
+    ArrayConst (value, a :: ann)
+  | Param (ctype, name, ann) ->
+    Param (ctype, name, a :: ann)
+  | Dim (name, ann) ->
+    Dim (name, a :: ann)
+
+  | _ -> raise InvalidNode
 
 let rec annof = function
-    | Program (_, ann)
-    | Param (_, _, ann)
-    | Dim (_, ann)
-    | FunDec (_, _, _, ann)
-    | FunDef (_, _, _, _, _, ann)
-    | GlobalDec (_, _, ann)
-    | GlobalDef (_, _, _, _, ann)
-    | VarDec (_, _, _, ann)
-    | Assign (_, _, _, ann)
-    | VarLet (_, _, _, ann)
-    | Return (_, ann)
-    | If (_, _, ann)
-    | IfElse (_, _, _, ann)
-    | While (_, _, ann)
-    | DoWhile (_, _, ann)
-    | For (_, _, _, _, _, ann)
-    | Allocate (_, _, ann)
-    | Const (BoolVal _, ann)
-    | Const (IntVal _, ann)
-    | Const (FloatVal _, ann)
-    | ArrayConst (_, ann)
-    | Var (_, _, ann)
-    | Monop (_, _, ann)
-    | Binop (_, _, _, ann)
-    | Cond (_, _, _, ann)
-    | TypeCast (_, _, ann)
-    | VarUse (_, _, ann)
-    | FunUse (_, _, ann)
-    | FunCall (_, _, ann) -> ann
-
-    | ArrayInit (value, _)
-    | ArrayScalar value
-    | Expr value
-    | Arg value -> annof value
-
-    | _ -> raise InvalidNode
+  | Program (_, ann)
+  | Param (_, _, ann)
+  | Dim (_, ann)
+  | FunDec (_, _, _, ann)
+  | FunDef (_, _, _, _, _, ann)
+  | GlobalDec (_, _, ann)
+  | GlobalDef (_, _, _, _, ann)
+  | VarDec (_, _, _, ann)
+  | Assign (_, _, _, ann)
+  | VarLet (_, _, _, ann)
+  | Return (_, ann)
+  | If (_, _, ann)
+  | IfElse (_, _, _, ann)
+  | While (_, _, ann)
+  | DoWhile (_, _, ann)
+  | For (_, _, _, _, _, ann)
+  | Allocate (_, _, ann)
+  | Const (BoolVal _, ann)
+  | Const (IntVal _, ann)
+  | Const (FloatVal _, ann)
+  | ArrayConst (_, ann)
+  | Var (_, _, ann)
+  | Monop (_, _, ann)
+  | Binop (_, _, _, ann)
+  | Cond (_, _, _, ann)
+  | TypeCast (_, _, ann)
+  | VarUse (_, _, ann)
+  | FunUse (_, _, ann)
+  | FunCall (_, _, ann) -> ann
+
+  | ArrayInit (value, _)
+  | ArrayScalar value
+  | Expr value
+  | Arg value -> annof value
+
+  | _ -> raise InvalidNode
 
 let locof node =
-     let rec trav = function
-         | []           -> noloc
-         | Loc loc :: _ -> loc
-         | _ :: tl      -> trav tl
-     in trav (annof node)
+  let rec trav = function
+    | []           -> noloc
+    | Loc loc :: _ -> loc
+    | _ :: tl      -> trav tl
+  in trav (annof node)
 
 let depthof node =
-     let rec trav = function
-         | [] ->
-            prerr_string "cannot get depth for: ";
-            prt_node node;
-            raise InvalidNode
-         | Depth depth :: _ -> depth
-         | _ :: tl          -> trav tl
-     in trav (annof node)
+  let rec trav = function
+    | [] ->
+      prerr_string "cannot get depth for: ";
+      prt_node node;
+      raise InvalidNode
+    | Depth depth :: _ -> depth
+    | _ :: tl          -> trav tl
+  in trav (annof node)
 
 let indexof node =
-     let rec trav = function
-         | [] ->
-            prerr_string "cannot get index for: ";
-            prt_node node;
-            raise InvalidNode
-         | Index index :: _ -> index
-         | _ :: tl          -> trav tl
-     in trav (annof node)
+  let rec trav = function
+    | [] ->
+      prerr_string "cannot get index for: ";
+      prt_node node;
+      raise InvalidNode
+    | Index index :: _ -> index
+    | _ :: tl          -> trav tl
+  in trav (annof node)
 
 let typeof = function
-    (* Some nodes have their type as property *)
-    | VarDec (ctype, _, _, _)
-    | Param (ctype, _, _)
-    | FunDec (ctype, _, _, _)
-    | FunDef (_, ctype, _, _, _, _)
-    | GlobalDec (ctype, _, _)
-    | GlobalDef (_, ctype, _, _, _)
-    | TypeCast (ctype, _, _)
-        -> ctype
-
-    (* Dim nodes are always type Int, and are copied by context analysis before
-     * they are annotated with Type Int, so this match is necessary *)
-    | Dim _ -> Int
-
-    (* Other nodes must be annotated during typechecking *)
-    | node ->
-        let rec trav = function
-         | [] ->
-            prerr_string "cannot get type for: ";
-            prt_node node;
-            raise InvalidNode
-            | Type t :: _ -> t
-            | _ :: tl     -> trav tl
-        in trav (annof node)
+  (* Some nodes have their type as property *)
+  | VarDec (ctype, _, _, _)
+  | Param (ctype, _, _)
+  | FunDec (ctype, _, _, _)
+  | FunDef (_, ctype, _, _, _, _)
+  | GlobalDec (ctype, _, _)
+  | GlobalDef (_, ctype, _, _, _)
+  | TypeCast (ctype, _, _)
+    -> ctype
+
+  (* Dim nodes are always type Int, and are copied by context analysis before
+   * they are annotated with Type Int, so this match is necessary *)
+  | Dim _ -> Int
+
+  (* Other nodes must be annotated during typechecking *)
+  | node ->
+    let rec trav = function
+      | [] ->
+        prerr_string "cannot get type for: ";
+        prt_node node;
+        raise InvalidNode
+      | Type t :: _ -> t
+      | _ :: tl     -> trav tl
+    in trav (annof node)
 
 let labelof node =
-     let rec trav = function
-         | [] ->
-            prerr_string "cannot get label for: ";
-            prt_node node;
-            raise InvalidNode
-         | LabelName label :: _ -> label
-         | _ :: tl              -> trav tl
-     in trav (annof node)
+  let rec trav = function
+    | [] ->
+      prerr_string "cannot get label for: ";
+      prt_node node;
+      raise InvalidNode
+    | LabelName label :: _ -> label
+    | _ :: tl              -> trav tl
+  in trav (annof node)
 
 let const_type = function
-    | BoolVal _  -> Bool
-    | IntVal _   -> Int
-    | FloatVal _ -> Float
+  | BoolVal _  -> Bool
+  | IntVal _   -> Int
+  | FloatVal _ -> Float
 
 (*
 let get_line str n =
-    let rec find_start from = function
-        | n when n < 1 -> raise (Invalid_argument "n")
-        | 1 -> from
-        | n -> find_start ((String.index_from str from '\n') + 1) (n - 1)
-    in
-    let linestart = find_start 0 n in
-    let len = String.length str in
-    let lineend =
-        try String.index_from str linestart '\n'
-        with Not_found -> len
-    in
-    String.sub str linestart (lineend - linestart)
+  let rec find_start from = function
+    | n when n < 1 -> raise (Invalid_argument "n")
+    | 1 -> from
+    | n -> find_start ((String.index_from str from '\n') + 1) (n - 1)
+  in
+  let linestart = find_start 0 n in
+  let len = String.length str in
+  let lineend =
+    try String.index_from str linestart '\n'
+    with Not_found -> len
+  in
+  String.sub str linestart (lineend - linestart)
 *)
 
 let count_tabs str upto =
-    let rec count n = function
-        | 0 -> n
-        | i -> count (if String.get str (i - 1) = '\t' then n + 1 else n) (i - 1)
-    in count 0 upto
+  let rec count n = function
+    | 0 -> n
+    | i -> count (if String.get str (i - 1) = '\t' then n + 1 else n) (i - 1)
+  in count 0 upto
 
 let tabwidth = 4
 
@@ -354,99 +354,99 @@ let retab str = global_replace (regexp "\t") (repeat " " tabwidth) str
 let indent n = repeat (repeat " " (tabwidth - 1)) n
 
 let prerr_loc (fname, ystart, yend, xstart, xend) =
-    let file = open_in fname in
-
-    (* skip lines until the first matched line *)
-    for i = 1 to ystart - 1 do let _ = input_line file in () done;
-
-    (* for each line in `loc`, print the source line with an underline *)
-    for l = ystart to yend do
-        let line = input_line file in
-        let linewidth = String.length line in
-        let left = if l = ystart then xstart else 1 in
-        let right = if l = yend then xend else linewidth in
-        if linewidth > 0 then (
-            prerr_endline (retab line);
-            prerr_string (indent (count_tabs line right));
-            for i = 1 to left - 1 do prerr_char ' ' done;
-            for i = left to right do prerr_char '^' done;
-            prerr_endline "";
-        )
-    done;
-    ()
+  let file = open_in fname in
+
+  (* skip lines until the first matched line *)
+  for i = 1 to ystart - 1 do let _ = input_line file in () done;
+
+  (* for each line in `loc`, print the source line with an underline *)
+  for l = ystart to yend do
+    let line = input_line file in
+    let linewidth = String.length line in
+    let left = if l = ystart then xstart else 1 in
+    let right = if l = yend then xend else linewidth in
+    if linewidth > 0 then begin
+      prerr_endline (retab line);
+      prerr_string (indent (count_tabs line right));
+      for i = 1 to left - 1 do prerr_char ' ' done;
+      for i = left to right do prerr_char '^' done;
+      prerr_endline "";
+    end
+  done;
+  ()
 
 let prerr_loc_msg loc msg =
-    if args.verbose >= 1 then (
-        let (fname, ystart, yend, xstart, xend) = loc in
-        if loc != noloc then (
-            let line_s = if yend != ystart
-                then sprintf "lines %d-%d" ystart yend
-                else sprintf "line %d" ystart
-            in
-            let char_s = if xend != xstart || yend != ystart
-                then sprintf "characters %d-%d" xstart xend
-                else sprintf "character %d" xstart
-            in
-            eprintf "File \"%s\", %s, %s:\n" fname line_s char_s;
-        );
-        eprintf "%s\n" msg;
-
-        if args.verbose >= 1 && loc != noloc then
-            try prerr_loc loc
-            with Sys_error _ -> ()
-    );
-    ()
+  if args.verbose >= 1 then begin
+    let (fname, ystart, yend, xstart, xend) = loc in
+    if loc != noloc then begin
+      let line_s = if yend != ystart
+        then sprintf "lines %d-%d" ystart yend
+        else sprintf "line %d" ystart
+      in
+      let char_s = if xend != xstart || yend != ystart
+        then sprintf "characters %d-%d" xstart xend
+        else sprintf "character %d" xstart
+      in
+      eprintf "File \"%s\", %s, %s:\n" fname line_s char_s;
+    end;
+    eprintf "%s\n" msg;
+
+    if args.verbose >= 1 && loc != noloc then
+        try prerr_loc loc
+        with Sys_error _ -> ()
+  end;
+  ()
 
 let block_body = function
-    | Block nodes -> nodes
-    | _ -> raise InvalidNode
+  | Block nodes -> nodes
+  | _ -> raise InvalidNode
 
 let basetypeof node = match typeof node with
-    | ArrayDims (ctype, _)
-    | Array ctype
-    | ctype -> ctype
+  | ArrayDims (ctype, _)
+  | Array ctype
+  | ctype -> ctype
 
 let nameof = function
-    | GlobalDec (_, name, _)
-    | GlobalDef (_, _, name, _, _)
-    | FunDec (_, name, _, _)
-    | FunDef (_, _, name, _, _, _)
-    | VarDec (_, name, _, _)
-    | Param (_, name, _)
-    | Dim (name, _) -> name
-    | _ -> raise InvalidNode
+  | GlobalDec (_, name, _)
+  | GlobalDef (_, _, name, _, _)
+  | FunDec (_, name, _, _)
+  | FunDef (_, _, name, _, _, _)
+  | VarDec (_, name, _, _)
+  | Param (_, name, _)
+  | Dim (name, _) -> name
+  | _ -> raise InvalidNode
 
 let optmap f = function
-    | None -> None
-    | Some lst -> Some (List.map f lst)
+  | None -> None
+  | Some lst -> Some (List.map f lst)
 
 let optmapl f = function
-    | None -> []
-    | Some lst -> List.map f lst
+  | None -> []
+  | Some lst -> List.map f lst
 
 let mapi f lst =
-    let rec trav i = function
-        | [] -> []
-        | hd :: tl -> f i hd :: (trav (i + 1) tl)
-    in trav 0 lst
+  let rec trav i = function
+    | [] -> []
+    | hd :: tl -> f i hd :: (trav (i + 1) tl)
+  in trav 0 lst
 
 (** Constants that are *)
 let immediate_consts = [
-    BoolVal true;
-    BoolVal false;
-    IntVal (-1);
-    IntVal 0;
-    IntVal 1;
-    FloatVal 0.0;
-    FloatVal 1.0;
+  BoolVal true;
+  BoolVal false;
+  IntVal (-1);
+  IntVal 0;
+  IntVal 1;
+  FloatVal 0.0;
+  FloatVal 1.0;
 ]
 
 let is_immediate_const const =
-    if args.optimize then List.mem const immediate_consts else false
+  if args.optimize then List.mem const immediate_consts else false
 
 let is_array node = match typeof node with
-    | ArrayDims _ | Array _ -> true
-    | _ -> false
+  | ArrayDims _ | Array _ -> true
+  | _ -> false
 
 let node_warning node msg =
-    prerr_loc_msg (locof node) ("Warning: " ^ msg)
+  prerr_loc_msg (locof node) ("Warning: " ^ msg)