| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- open Printf
- open Str
- open Lexing
- open Types
- (** Empty location, use when node location is unkown or irrelevant. *)
- let noloc = ("", 0, 0, 0, 0)
- let rec repeat s n = if n < 1 then "" else s ^ (repeat s (n - 1))
- let expand n text = text ^ repeat " " (n - String.length text)
- (* Logging functions *)
- let hline = "-----------------------------------------------------------------"
- let prt_node node = prerr_endline (Stringify.node2str node)
- let log_plain_line verbosity line =
- if Globals.args.verbose >= verbosity then prerr_endline line
- let log_line verbosity line =
- log_plain_line verbosity (repeat " " 13 ^ line)
- let log_node verbosity node =
- if Globals.args.verbose >= verbosity then prt_node node
- (* Variable generation *)
- let generate_id id num = "_" ^ id ^ "_" ^ string_of_int num
- let var_counter = ref 0
- let fresh_id base =
- (* For generated variables, just replace the counter *)
- let base =
- if string_match (regexp "^_\\(.+\\)_[0-9]+_?$") base 0 then
- matched_group 1 base
- else
- base
- in
- var_counter := !var_counter + 1;
- generate_id base !var_counter
- (* Constants are marked by a leading _ for recognition during constant
- * propagation *)
- let generate_const id num = generate_id id num ^ "_"
- let fresh_const id = fresh_id id ^ "_"
- let is_generated_id id = String.length id >= 1 & id.[0] = '_'
- let is_const_id id =
- String.length id >= 2
- & id.[0] = '_'
- & id.[String.length id - 1] = '_'
- let loc_from_lexpos pstart pend =
- 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 rec traverse u ( *: ) trav node =
- let trav_all nodes =
- let (nodes, res) = List.split (List.map trav nodes) in
- (nodes, List.fold_left ( *: ) u res)
- in
- match node with
- | Program (decls, ann) ->
- let (decls, res_decls) = trav_all decls in
- (Program (flatten_blocks decls, ann), res_decls)
- | FunDec (ret_type, name, params, ann) ->
- let (params, res_params) = trav_all params in
- (FunDec (ret_type, name, params, ann), res_params)
- | FunDef (export, ret_type, name, params, body, ann) ->
- let (params, resp) = trav_all params in
- let (body, resb) = trav body in
- (FunDef (export, ret_type, name, params, body, ann), resp *: resb)
- | GlobalDec (ctype, name, ann) ->
- (GlobalDec (ctype, name, ann), u)
- | GlobalDef (export, ctype, name, Some init, ann) ->
- let (init, res_init) = trav init in
- (GlobalDef (export, ctype, name, Some init, ann), res_init)
- | VarDecs decs ->
- let (decs, res_decs) = trav_all decs in
- (VarDecs decs, res_decs)
- | LocalFuns funs ->
- let (funs, res_funs) = trav_all funs in
- (LocalFuns funs, res_funs)
- | VarDec (ctype, name, Some init, ann) ->
- let (init, res_init) = trav init in
- (VarDec (ctype, name, Some init, ann), res_init)
- | Assign (name, None, value, ann) ->
- let (value, res_value) = trav value in
- (Assign (name, None, value, ann), res_value)
- | Assign (name, Some dims, value, ann) ->
- let (dims, res_dims) = trav_all dims in
- let (value, res_value) = trav value in
- (Assign (name, Some dims, value, ann), res_dims *: res_value)
- | VarLet (dec, None, value, ann) ->
- let (value, res_value) = trav value in
- (VarLet (dec, None, value, ann), res_value)
- | VarLet (dec, Some dims, value, ann) ->
- let (dims, res_dims) = trav_all dims in
- let (value, res_value) = trav value in
- (VarLet (dec, Some dims, value, ann), res_dims *: res_value)
- | Return (value, ann) ->
- let (value, res_value) = trav value in
- (Return (value, ann), res_value)
- | If (cond, body, ann) ->
- let (cond, res_cond) = trav cond in
- let (body, res_body) = trav body in
- (If (cond, body, ann), res_cond *: res_body)
- | IfElse (cond, tbody, fbody, ann) ->
- let (cond, resa) = trav cond in
- let (tbody, resb) = trav tbody in
- let (fbody, resc) = trav fbody in
- (IfElse (cond, tbody, fbody, ann), resa *: resb *: resc)
- | While (cond, body, ann) ->
- let (cond, resc) = trav cond in
- let (body, resb) = trav body in
- (While (cond, body, ann), resc *: resb)
- | DoWhile (cond, body, ann) ->
- let (cond, resc) = trav cond in
- let (body, resb) = trav body in
- (DoWhile (cond, body, ann), resc *: resb)
- | For (counter, start, stop, step, body, ann) ->
- let (start, resa) = trav start in
- let (stop, resb) = trav stop in
- let (step, resc) = trav step in
- let (body, resd) = trav body in
- let res = resa *: resb *: resc *: resd in
- (For (counter, start, stop, step, body, ann), res)
- | Allocate (dec, dims, ann) ->
- let (dims, res_dims) = trav_all dims in
- (Allocate (dec, dims, ann), res_dims)
- | Expr value ->
- let (value, res_value) = trav value in
- (Expr value, res_value)
- | Block (body) ->
- let (body, res_body) = trav_all body in
- (Block body, res_body)
- | Monop (op, value, ann) ->
- let (value, res_value) = trav value in
- (Monop (op, value, ann), res_value)
- | Binop (op, left, right, ann) ->
- let (left, res_left) = trav left in
- let (right, res_right) = trav right in
- (Binop (op, left, right, ann), res_left *: res_right)
- | Cond (cond, texpr, fexpr, ann) ->
- let (cond, resa) = trav cond in
- let (texpr, resb) = trav texpr in
- let (fexpr, resc) = trav fexpr in
- (Cond (cond, texpr, fexpr, ann), resa *: resb *: resc)
- | TypeCast (ctype, value, ann) ->
- let (value, res_value) = trav value in
- (TypeCast (ctype, value, ann), res_value)
- | FunCall (name, args, ann) ->
- let (args, res_args) = trav_all args in
- (FunCall (name, args, ann), res_args)
- | Arg value ->
- let (value, res_value) = trav value in
- (Arg value, res_value)
- | ArrayInit (value, dims) ->
- let (value, res_value) = trav value in
- (ArrayInit (value, dims), res_value)
- | Var (dec, Some dims, ann) ->
- let (dims, res_dims) = trav_all dims in
- (Var (dec, Some dims, ann), res_dims)
- | VarUse (dec, Some dims, ann) ->
- let (dims, res_dims) = trav_all dims in
- (VarUse (dec, Some dims, ann), res_dims)
- | FunUse (dec, params, ann) ->
- let (params, res_params) = trav_all params in
- (FunUse (dec, params, ann), res_params)
- | _ -> (node, u)
- let traverse_unit visit node =
- fst (traverse () (fun () () -> ()) (fun n -> (visit n, ())) node)
- let traverse_list visit = traverse [] (@) visit
- 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
- 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, _)
- | 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 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 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 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)
- 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 const_type = function
- | 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 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 tabwidth = 4
- 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 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 Globals.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 Globals.args.verbose >= 1 && loc != noloc then
- try prerr_loc loc
- with Sys_error _ -> ()
- end;
- ()
- let block_body = function
- | Block nodes -> nodes
- | _ -> raise InvalidNode
- let basetypeof node = match typeof node with
- | 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
- let optmap f = function
- | None -> None
- | Some lst -> Some (List.map f lst)
- let optmapl f = function
- | None -> []
- | Some lst -> List.map f lst
- let mapi f lst =
- let rec trav i = function
- | [] -> []
- | hd :: tl ->
- let hd = f i hd in
- hd :: (trav (i + 1) tl)
- in trav 0 lst
- (** Constants that are *)
- let immediate_consts = [
- BoolVal true;
- BoolVal false;
- IntVal (-1l);
- IntVal 0l;
- IntVal 1l;
- FloatVal 0.0;
- FloatVal 1.0;
- ]
- let is_immediate_const const =
- if Globals.args.optimize then List.mem const immediate_consts else false
- let is_array node = match typeof node with
- | ArrayDims _ | Array _ -> true
- | _ -> false
- let node_error node msg =
- prerr_loc_msg (locof node) ("Error: " ^ msg)
- let node_warning node msg =
- prerr_loc_msg (locof node) ("Warning: " ^ msg)
- let print_error = function
- | Msg msg ->
- eprintf "Error: %s\n" msg;
- | LocMsg (loc, msg) ->
- prerr_loc_msg loc ("Error: " ^ msg)
- | NodeMsg (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
- node_error node msg
- | NoMsg -> ()
- let quit_on_error node = function
- | [] -> node
- | errors ->
- List.iter print_error errors;
- raise (FatalError NoMsg)
|