context_analysis.ml 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. open Printf
  2. open Ast
  3. open Util
  4. type nametype = Varname of string | Funcname of string
  5. let type2str = function Funcname _ -> "function" | Varname _ -> "variable"
  6. let mapfind name tbl =
  7. if Hashtbl.mem tbl name then Some (Hashtbl.find tbl name) else None
  8. let check_in_scope name errnode scope =
  9. let (vars, funs) = scope in
  10. let (name, tbl, other_map, desired_type) = match name with
  11. | Varname name -> (name, vars, funs, "variable")
  12. | Funcname name -> (name, funs, vars, "function")
  13. in
  14. match mapfind name tbl with
  15. | Some (decl, dec_depth, _) ->
  16. (decl, dec_depth)
  17. | None ->
  18. let msg = match mapfind name other_map with
  19. | Some _ -> sprintf "\"%s\" is not a %s" name desired_type
  20. | None -> sprintf "undefined %s \"%s\"" desired_type name
  21. in
  22. raise (NodeError (errnode, msg))
  23. let rec analyse scope depth args node =
  24. (* add_to_scope uses args, so it needs to be defined here *)
  25. let add_to_scope name decl depth scope =
  26. let (vars, funs) = scope in
  27. let (name, tbl, name_type) = match name with
  28. | Varname name -> (name, vars, "variable")
  29. | Funcname name -> (name, funs, "function")
  30. in
  31. match mapfind name tbl with
  32. (* Identifiers of lower depth may be overwritten, but idenetifiers at
  33. * the same depth must be unique for consistency *)
  34. | Some (orig, orig_depth, _) when orig_depth >= depth ->
  35. let msg = sprintf "Error: cannot redeclare %s \"%s\"" name_type name in
  36. prerr_loc_msg (locof decl) msg args.verbose;
  37. prerr_loc_msg (locof orig) "Previously declared here:" args.verbose;
  38. raise EmptyError
  39. | Some _ ->
  40. Hashtbl.replace tbl name (decl, depth, name_type)
  41. | None ->
  42. Hashtbl.add tbl name (decl, depth, name_type)
  43. in
  44. let rec collect node = match node with
  45. (* Add node reference for this varname to vars map *)
  46. | VarDec (ctype, name, init, loc) ->
  47. let node = match init with
  48. | Some value -> VarDec (ctype, name, Some (collect value), loc)
  49. | None -> node
  50. in
  51. add_to_scope (Varname name) node depth scope;
  52. node
  53. (* For global vars, only the name and array dimensions *)
  54. | GlobalDec (Array (ctype, dims), name, loc) ->
  55. add_to_scope (Varname name) node depth scope;
  56. GlobalDec (Array (ctype, List.map collect dims), name, loc)
  57. | Dim (name, loc) ->
  58. add_to_scope (Varname name) (DimDec node) depth scope;
  59. node
  60. | GlobalDec (_, name, _)
  61. | GlobalDef (_, _, name, _, _) ->
  62. add_to_scope (Varname name) node depth scope;
  63. node
  64. (* Functions are traversed later on, for now only add the name *)
  65. | FunDec (_, name, _, _)
  66. | FunDef (_, _, name, _, _, _) ->
  67. add_to_scope (Funcname name) node depth scope;
  68. node
  69. (* For a variable or function call, look for its declaration in the
  70. * current scope and save a its type/depth information *)
  71. | Var (name, _) ->
  72. let (decl, dec_depth) = check_in_scope (Varname name) node scope in
  73. VarUse (node, ctypeof decl, depth - dec_depth)
  74. | Deref (name, dims, loc) ->
  75. let (decl, dec_depth) = check_in_scope (Varname name) node scope in
  76. let node = Deref (name, List.map collect dims, loc) in
  77. VarUse (node, ctypeof decl, depth - dec_depth)
  78. | FunCall (name, args, loc) ->
  79. let (decl, dec_depth) = check_in_scope (Funcname name) node scope in
  80. let node = FunCall (name, transform_all collect args, loc) in
  81. FunUse (node, decl, depth - dec_depth)
  82. (* Assign statements are wrapped in VarLet nodes, which stores the type
  83. * and depth of the assigned variable are *)
  84. | Assign (name, None, value, loc) ->
  85. let (decl, dec_depth) = check_in_scope (Varname name) node scope in
  86. let assign = Assign (name, None, collect value, loc) in
  87. VarLet (assign, ctypeof decl, depth - dec_depth)
  88. | Assign (name, Some dims, value, loc) ->
  89. let (decl, dec_depth) = check_in_scope (Varname name) node scope in
  90. let dims = Some (List.map collect dims) in
  91. let assign = Assign (name, dims, collect value, loc) in
  92. VarLet (assign, ctypeof decl, depth - dec_depth)
  93. | _ -> transform_children collect node
  94. in
  95. (*let print_scope () =
  96. let (vars, funs) = scope in
  97. let print_key key value = prerr_string (" " ^ key) in
  98. prerr_string "vars: ";
  99. Hashtbl.iter print_key vars;
  100. prerr_endline "";
  101. prerr_string "funs: ";
  102. Hashtbl.iter print_key funs;
  103. prerr_endline "";
  104. in*)
  105. let rec traverse scope depth node =
  106. match node with
  107. (* Increase nesting level when entering function *)
  108. | FunDef (export, ret_type, name, params, body, loc) ->
  109. let (vars, funs) = scope in
  110. let local_scope = (Hashtbl.copy vars, Hashtbl.copy funs) in
  111. let params = List.map (traverse local_scope (depth + 1)) params in
  112. let body = analyse local_scope (depth + 1) args body in
  113. FunDef (export, ret_type, name, params, body, loc)
  114. | Param (Array (ctype, dims), name, loc) as node ->
  115. let _ = List.map (traverse scope depth) dims in
  116. add_to_scope (Varname name) node depth scope;
  117. node
  118. | Dim (name, _) as dim ->
  119. add_to_scope (Varname name) (DimDec dim) depth scope;
  120. node
  121. | Param (_, name, _) ->
  122. add_to_scope (Varname name) node depth scope;
  123. node
  124. (* Do not traverse into external function declarations, since their
  125. * parameters must not be added to the namespace *)
  126. | FunDec _ -> node
  127. | _ -> transform_children (traverse scope depth) node
  128. in
  129. (*
  130. * First collect all definitions at the current depth. Then, traverse into
  131. * functions with a copy of the current scope. This is needed because
  132. * functions can access all identifiers in their surrounding scope.
  133. * E.g., the following is allowed:
  134. *
  135. * void foo() { glob = 1; }
  136. * int glob;
  137. *)
  138. (*prerr_endline "";
  139. prerr_endline ("node:----\n" ^ Stringify.node2str node);
  140. prerr_endline "----";*)
  141. let node = collect node in
  142. (*prerr_endline "collected";
  143. print_scope ();
  144. prerr_endline "\ntraversing";*)
  145. let node = traverse scope depth node in
  146. (*prerr_endline "traversed";
  147. print_scope ();
  148. prerr_endline "";*)
  149. node
  150. let analyse_context args program =
  151. let scope = (Hashtbl.create 20, Hashtbl.create 20) in
  152. analyse scope 0 args program
  153. let rec phase input =
  154. prerr_endline "- Context analysis";
  155. match input with
  156. | Ast node -> Ast (analyse_context args node)
  157. | _ -> raise (InvalidInput "context analysis")