context_analysis.ml 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  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 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 (dec, dec_depth, _) ->
  16. (dec, 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 add_to_scope name dec depth (vars, funs) =
  24. let (name, tbl, name_type) = match name with
  25. | Varname name -> (name, vars, "variable")
  26. | Funcname name -> (name, funs, "function")
  27. in
  28. match mapfind name tbl with
  29. (* Identifiers of lower depth may be overwritten, but idenetifiers at
  30. * the same depth must be unique for consistency *)
  31. | Some (orig, orig_depth, _) when orig_depth >= depth ->
  32. let msg = sprintf "Error: cannot redeclare %s \"%s\"" name_type name in
  33. prerr_loc_msg (locof dec) msg;
  34. prerr_loc_msg (locof orig) "Previously declared here:";
  35. raise EmptyError
  36. | Some _ ->
  37. Hashtbl.replace tbl name (dec, depth, name_type)
  38. | None ->
  39. Hashtbl.add tbl name (dec, depth, name_type)
  40. let rec analyse scope depth node =
  41. let rec collect node = match node with
  42. (* Add node reference for this varname to vars map *)
  43. | VarDec (ctype, name, init, ann) ->
  44. let node = match init with
  45. | Some value -> VarDec (ctype, name, Some (collect value),
  46. Depth depth :: ann)
  47. | None -> VarDec (ctype, name, init, Depth depth :: ann)
  48. in
  49. add_to_scope (Varname name) node depth scope;
  50. node
  51. (* For global vars, only the name and array dimensions *)
  52. | GlobalDec (ctype, name, ann) ->
  53. let ctype = match ctype with
  54. | Array (ctype, dims) -> Array (ctype, List.map collect dims)
  55. | _ -> ctype
  56. in
  57. let node = GlobalDec (ctype, name, Depth depth :: ann) in
  58. add_to_scope (Varname name) node depth scope;
  59. node
  60. | Dim (name, ann) ->
  61. let node = Dim (name, Depth depth :: ann) in
  62. add_to_scope (Varname name) node depth scope;
  63. node
  64. | GlobalDef (export, ctype, name, init, ann) ->
  65. let ctype = match ctype with
  66. | Array (ctype, dims) -> Array (ctype, List.map collect dims)
  67. | _ -> ctype
  68. in
  69. let node = GlobalDef (export, ctype, name, init, Depth depth :: ann) 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 (ret_type, name, params, ann) ->
  74. let node = FunDec (ret_type, name, params, Depth depth :: ann) in
  75. add_to_scope (Funcname name) node depth scope;
  76. node
  77. | FunDef (export, ret_type, name, params, body, ann) ->
  78. let node = FunDef (export, ret_type, name, params, body, Depth depth :: ann) in
  79. add_to_scope (Funcname name) node depth scope;
  80. node
  81. (* For a variable or function call, look for its declaration in the
  82. * current scope and save a its type/depth information *)
  83. | Var (name, dims, ann) ->
  84. let (dec, dec_depth) = check_in_scope (Varname name) node scope in
  85. VarUse (dec, optmap collect dims, Depth depth :: ann)
  86. | FunCall (name, args, ann) ->
  87. let (dec, dec_depth) = check_in_scope (Funcname name) node scope in
  88. FunUse (dec, List.map collect args, Depth depth :: ann)
  89. (* Assign statements are replaced with VarLet nodes, which stores the type
  90. * and depth of the assigned variable are *)
  91. | Assign (name, dims, value, ann) ->
  92. let (dec, dec_depth) = check_in_scope (Varname name) node scope in
  93. VarLet (dec, optmap collect dims, collect value, Depth depth :: ann)
  94. | Allocate (dec, dims, ann) ->
  95. let (dec, dec_depth) = check_in_scope (Varname (nameof dec)) node scope in
  96. Allocate (dec, List.map collect dims, Depth depth :: ann)
  97. | _ -> transform_children collect node
  98. in
  99. let rec traverse scope depth node =
  100. match node with
  101. (* Increase nesting level when entering function *)
  102. | FunDef (export, ret_type, name, params, body, ann) ->
  103. let (vars, funs) = scope in
  104. let local_scope = (Hashtbl.copy vars, Hashtbl.copy funs) in
  105. let params = List.map (traverse local_scope (depth + 1)) params in
  106. let body = analyse local_scope (depth + 1) body in
  107. FunDef (export, ret_type, name, params, body, ann)
  108. | Param (Array (ctype, dims), name, ann) as node ->
  109. let _ = List.map (traverse scope depth) dims in
  110. add_to_scope (Varname name) node depth scope;
  111. node
  112. | Dim (name, _) as dim ->
  113. add_to_scope (Varname name) dim depth scope;
  114. node
  115. | Param (_, name, _) ->
  116. add_to_scope (Varname name) node depth scope;
  117. node
  118. (* Do not traverse into external function declarations, since their
  119. * parameters must not be added to the namespace *)
  120. | FunDec _ -> node
  121. | _ -> transform_children (traverse scope depth) node
  122. in
  123. (*
  124. * First collect all definitions at the current depth. Then, traverse into
  125. * functions with a copy of the current scope. This is needed because
  126. * functions can access all identifiers in their surrounding scope.
  127. * E.g., the following is allowed:
  128. *
  129. * void foo() { glob = 1; }
  130. * int glob;
  131. *)
  132. let node = collect node in
  133. let node = traverse scope depth node in
  134. node
  135. let analyse_context program =
  136. let scope = (Hashtbl.create 20, Hashtbl.create 20) in
  137. analyse scope 0 program
  138. let phase = function
  139. | Ast node -> Ast (analyse_context node)
  140. | _ -> raise (InvalidInput "context analysis")