context.ml 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. open Printf
  2. open Types
  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 is_generated name = String.contains name '$'
  9. let check_in_scope name errnode scope =
  10. let (vars, funs) = scope in
  11. let (name, tbl, other_map, desired_type) = match name with
  12. | Varname name -> (name, vars, funs, "variable")
  13. | Funcname name -> (name, funs, vars, "function")
  14. in
  15. match mapfind name tbl with
  16. | Some (dec, dec_depth, _) ->
  17. (dec, dec_depth)
  18. | None ->
  19. let msg = match mapfind name other_map with
  20. | Some _ -> sprintf "\"%s\" is not a %s" name desired_type
  21. | None -> sprintf "undefined %s \"%s\"" desired_type name
  22. in
  23. raise (NodeError (errnode, msg))
  24. let add_to_scope name dec depth (vars, funs) =
  25. let (name, tbl, name_type) = match name with
  26. | Varname name -> (name, vars, "variable")
  27. | Funcname name -> (name, funs, "function")
  28. in
  29. match mapfind name tbl with
  30. (* Identifiers of lower depth may be overwritten, but idenetifiers at
  31. * the same depth must be unique for consistency *)
  32. | Some (orig, orig_depth, _) when orig_depth >= depth ->
  33. (* For generated variables, don't gove an error, since the error variable
  34. * is a derived array dimension of a redefined array, which will yield an
  35. * error later on *)
  36. if is_generated name then
  37. Hashtbl.replace tbl name (dec, depth, name_type)
  38. else
  39. let msg = sprintf "Error: cannot redeclare %s \"%s\"" name_type name in
  40. prerr_loc_msg (locof dec) msg;
  41. prerr_loc_msg (locof orig) "Previously declared here:";
  42. raise EmptyError
  43. | Some _ ->
  44. Hashtbl.replace tbl name (dec, depth, name_type)
  45. | None ->
  46. Hashtbl.add tbl name (dec, depth, name_type)
  47. let rec analyse scope depth node =
  48. let rec collect node = match node with
  49. (* For extern array declarations, add the dimension names as well *)
  50. | GlobalDec (ArrayDims (ctype, dims), name, ann) ->
  51. let rec add_dims = function
  52. | [] -> []
  53. | Dim (name, ann) :: tl ->
  54. let dim = Dim (name, Depth depth :: ann) in
  55. add_to_scope (Varname name) dim depth scope;
  56. dim :: (add_dims tl)
  57. | _ -> raise InvalidNode
  58. in
  59. let t = ArrayDims (ctype, add_dims dims) in
  60. let node = GlobalDec (t, name, Depth depth :: ann) in
  61. add_to_scope (Varname name) node depth scope;
  62. node
  63. (* For variables, add the name (array dimensions are added
  64. * implicitly, since they have separate VarDec nodes which were added
  65. * during the desugaring phase *)
  66. | VarDec (_, name, _, _)
  67. | GlobalDec (_, name, _)
  68. | GlobalDef (_, _, name, _, _) ->
  69. let node = annotate (Depth depth) node in
  70. add_to_scope (Varname name) node depth scope;
  71. node
  72. (* Functions are traversed later on, for now only add the name *)
  73. | FunDec (_, name, _, _)
  74. | FunDef (_, _, name, _, _, _) ->
  75. let node = annotate (Depth depth) node in
  76. add_to_scope (Funcname name) node depth scope;
  77. node
  78. (* For a variable or function call, look for its declaration in the
  79. * current scope and save a its type/depth information *)
  80. | Var (name, dims, ann) ->
  81. let (dec, dec_depth) = check_in_scope (Varname name) node scope in
  82. VarUse (dec, optmap collect dims, Depth depth :: ann)
  83. | FunCall (name, args, ann) ->
  84. let (dec, dec_depth) = check_in_scope (Funcname name) node scope in
  85. FunUse (dec, List.map collect args, Depth depth :: ann)
  86. (* Assign statements are replaced with VarLet nodes, which stores the
  87. * declaration of the assigned variable *)
  88. | Assign (name, dims, value, ann) ->
  89. let (dec, dec_depth) = check_in_scope (Varname name) node scope in
  90. VarLet (dec, optmap collect dims, collect value, Depth depth :: ann)
  91. | Allocate (dec, dims, ann) ->
  92. let (dec, dec_depth) = check_in_scope (Varname (nameof dec)) node scope in
  93. Allocate (dec, List.map collect dims, Depth depth :: ann)
  94. | _ -> transform_children collect node
  95. in
  96. let rec traverse scope depth node =
  97. match node with
  98. (* Increase nesting level when entering function *)
  99. | FunDef (export, ret_type, name, params, body, ann) ->
  100. let (vars, funs) = scope in
  101. let local_scope = (Hashtbl.copy vars, Hashtbl.copy funs) in
  102. let params = List.map (traverse local_scope (depth + 1)) params in
  103. let body = analyse local_scope (depth + 1) body in
  104. FunDef (export, ret_type, name, params, body, ann)
  105. | Param (ArrayDims (ctype, dims), name, ann) ->
  106. let rec add_dims = function
  107. | [] -> []
  108. | Dim (name, ann) :: tl ->
  109. let dim = Dim (name, Depth depth :: ann) in
  110. add_to_scope (Varname name) dim depth scope;
  111. dim :: (add_dims tl)
  112. | _ -> raise InvalidNode
  113. in
  114. let node = Param (ArrayDims (ctype, add_dims dims), name, ann) in
  115. add_to_scope (Varname name) node depth scope;
  116. node
  117. | VarDec _ -> node
  118. | Param (_, name, _) ->
  119. let node = annotate (Depth depth) node in
  120. add_to_scope (Varname name) node depth scope;
  121. node
  122. (* Do not traverse into external function declarations, since their
  123. * parameters must not be added to the namespace *)
  124. | FunDec _ -> node
  125. | _ -> transform_children (traverse scope depth) node
  126. in
  127. (*
  128. * First collect all definitions at the current depth. Then, traverse into
  129. * functions with a copy of the current scope. This is needed because
  130. * functions can access all identifiers in their surrounding scope.
  131. * E.g., the following is allowed:
  132. *
  133. * void foo() { glob = 1; }
  134. * int glob;
  135. *)
  136. let node = collect node in
  137. let node = traverse scope depth node in
  138. node
  139. let analyse_context program =
  140. let scope = (Hashtbl.create 20, Hashtbl.create 20) in
  141. analyse scope 0 program
  142. let phase = function
  143. | Ast node -> Ast (analyse_context node)
  144. | _ -> raise (InvalidInput "context analysis")