|
|
@@ -2,63 +2,158 @@ open Printf
|
|
|
open Ast
|
|
|
open Util
|
|
|
|
|
|
-module StrMap = Map.Make (String)
|
|
|
+type nametype = Varname of string | Funcname of string
|
|
|
|
|
|
-let analyse_context args node =
|
|
|
- let scope = ref StrMap.empty in
|
|
|
- let add_to_scope name decl depth desc =
|
|
|
- if StrMap.mem name !scope then (
|
|
|
- let msg = sprintf "Error: cannot redeclare %s \"%s\"" desc name in
|
|
|
- prerr_loc_msg (locof !decl) msg args.verbose;
|
|
|
+let type2str = function Funcname _ -> "function" | Varname _ -> "variable"
|
|
|
|
|
|
- let (orig, _) = StrMap.find name !scope in
|
|
|
- prerr_loc_msg (locof !orig) "Previously declared here:" args.verbose;
|
|
|
+let mapfind name tbl =
|
|
|
+ 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")
|
|
|
+ in
|
|
|
+ match mapfind name tbl with
|
|
|
+ | Some (decl, decl_depth, _) ->
|
|
|
+ (decl, decl_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))
|
|
|
+
|
|
|
+let rec analyse scope depth args node =
|
|
|
+ (* add_to_scope uses args, so it needs to be defined here *)
|
|
|
+ let add_to_scope name decl depth scope =
|
|
|
+ let (vars, funs) = scope in
|
|
|
+ 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 decl) msg args.verbose;
|
|
|
+ prerr_loc_msg (locof orig) "Previously declared here:" args.verbose;
|
|
|
raise EmptyError
|
|
|
- ) else
|
|
|
- scope := StrMap.add name (decl, depth) !scope
|
|
|
+ | Some _ ->
|
|
|
+ Hashtbl.replace tbl name (decl, depth, name_type)
|
|
|
+ | None ->
|
|
|
+ Hashtbl.add tbl name (decl, depth, name_type)
|
|
|
in
|
|
|
- let rec analyse depth node = match node with
|
|
|
+
|
|
|
+ let rec collect node = match node with
|
|
|
(* Add node reference for this varname to vars map *)
|
|
|
| VarDec (ctype, name, init, loc) ->
|
|
|
let node = match init with
|
|
|
- | Some value ->
|
|
|
- let value = analyse depth value in
|
|
|
- VarDec (ctype, name, Some value, loc)
|
|
|
+ | Some value -> VarDec (ctype, name, Some (collect value), loc)
|
|
|
| None -> node
|
|
|
in
|
|
|
- add_to_scope name (ref node) depth "variable";
|
|
|
+ add_to_scope (Varname name) node depth scope;
|
|
|
+ node
|
|
|
+
|
|
|
+ (* For global vars, only add the name *)
|
|
|
+ | GlobalDec (_, name, _)
|
|
|
+ | GlobalDef (_, _, name, _, _) ->
|
|
|
+ add_to_scope (Varname name) node depth scope;
|
|
|
node
|
|
|
|
|
|
- (* For a variable, look for its declaration in the current scope and
|
|
|
- * save a reference with the relative nesting depth *)
|
|
|
+ (* Functions are traversed later on, for now only add the name *)
|
|
|
+ | FunDec (_, name, _, _)
|
|
|
+ | FunDef (_, _, name, _, _, _) ->
|
|
|
+ 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, _) ->
|
|
|
- if StrMap.mem name !scope then
|
|
|
- let (decl, decl_depth) = StrMap.find name !scope in
|
|
|
- VarUse (node, decl, depth - decl_depth)
|
|
|
- else
|
|
|
- raise (NodeError (node, (sprintf "undefined variable \"%s\"" name)))
|
|
|
+ let (decl, decl_depth) = check_in_scope (Varname name) node scope in
|
|
|
+ VarUse (node, ctypeof decl, depth - decl_depth)
|
|
|
|
|
|
+ | FunCall (name, args, loc) ->
|
|
|
+ let (decl, decl_depth) = check_in_scope (Funcname name) node scope in
|
|
|
+ let node = FunCall (name, transform_all collect args, loc) in
|
|
|
+ FunUse (node, ctypeof decl, depth - decl_depth)
|
|
|
+
|
|
|
+ | _ -> transform_children collect node
|
|
|
+ in
|
|
|
+
|
|
|
+ (*let print_scope () =
|
|
|
+ let (vars, funs) = scope in
|
|
|
+ let print_key key value = prerr_string (" " ^ key) in
|
|
|
+ prerr_string "vars: ";
|
|
|
+ Hashtbl.iter print_key vars;
|
|
|
+ prerr_endline "";
|
|
|
+ prerr_string "funs: ";
|
|
|
+ Hashtbl.iter print_key funs;
|
|
|
+ prerr_endline "";
|
|
|
+ in*)
|
|
|
+
|
|
|
+ let rec traverse scope depth node =
|
|
|
+ match node with
|
|
|
(* Increase nesting level when entering function *)
|
|
|
| FunDef (export, ret_type, name, params, body, loc) ->
|
|
|
- add_to_scope name (ref node) depth "function";
|
|
|
- let params = List.map (analyse (depth + 1)) params in
|
|
|
- let body = analyse (depth + 1) body in
|
|
|
+ let params = List.map (traverse scope depth) params in
|
|
|
+ let body = analyse scope depth args body in
|
|
|
FunDef (export, ret_type, name, params, body, loc)
|
|
|
|
|
|
| Param (ArrayDec (_, dims) as atype, name, _) as node ->
|
|
|
- let add dim = add_to_scope dim (ref (Type atype)) depth "variable" in
|
|
|
- List.iter add dims;
|
|
|
- add_to_scope name (ref node) depth "variable";
|
|
|
+ let rec add_dims = function
|
|
|
+ | [] -> ()
|
|
|
+ | Dim (name, _) as dim :: tail ->
|
|
|
+ add_to_scope (Varname name) (DimDec dim) depth scope;
|
|
|
+ add_dims tail
|
|
|
+ | _ -> raise InvalidNode
|
|
|
+ in
|
|
|
+ add_dims dims;
|
|
|
+ add_to_scope (Varname name) node depth scope;
|
|
|
node
|
|
|
|
|
|
| Param (_, name, _) ->
|
|
|
- add_to_scope name (ref node) depth "variable";
|
|
|
+ add_to_scope (Varname name) node depth scope;
|
|
|
node
|
|
|
|
|
|
- | node -> transform_children (analyse depth) 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
|
|
|
- analyse 0 node
|
|
|
+
|
|
|
+ (*
|
|
|
+ * 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;
|
|
|
+ *)
|
|
|
+ (*prerr_endline "";
|
|
|
+ prerr_endline ("node:----\n" ^ Stringify.node2str node);
|
|
|
+ prerr_endline "----";*)
|
|
|
+ let node = collect node in
|
|
|
+ (*prerr_endline "collected";
|
|
|
+ print_scope ();
|
|
|
+ prerr_endline "\ntraversing";*)
|
|
|
+
|
|
|
+ let (vars, funs) = scope in
|
|
|
+ let local_scope = (Hashtbl.copy vars, Hashtbl.copy funs) in
|
|
|
+
|
|
|
+ let node = traverse local_scope (depth + 1) node in
|
|
|
+ (*prerr_endline "traversed";
|
|
|
+ print_scope ();
|
|
|
+ prerr_endline "";*)
|
|
|
+ node
|
|
|
+
|
|
|
+let analyse_context args program =
|
|
|
+ let scope = (Hashtbl.create 20, Hashtbl.create 20) in
|
|
|
+ analyse scope 0 args program
|
|
|
|
|
|
let rec phase input =
|
|
|
prerr_endline "- Context analysis";
|