1 (* *********************************************************************)
3 (* The Compcert verified compiler *)
5 (* Xavier Leroy, INRIA Paris-Rocquencourt *)
7 (* Copyright Institut National de Recherche en Informatique et en *)
8 (* Automatique. All rights reserved. This file is distributed *)
9 (* under the terms of the GNU General Public License as published by *)
10 (* the Free Software Foundation, either version 2 of the License, or *)
11 (* (at your option) any later version. This file is also distributed *)
12 (* under the terms of the INRIA Non-Commercial License Agreement. *)
14 (* *********************************************************************)
16 (* Typing environment *)
21 | Unbound_identifier of string
22 | Unbound_tag of string * string
23 | Tag_mismatch of string * string * string
24 | Unbound_typedef of string
25 | No_member of string * string * string
27 exception Error of error
29 (* Maps over ident, accessible both by name or by name + stamp *)
31 module StringMap = Map.Make(String)
33 module IdentMap = struct
34 type 'a t = (ident * 'a) list StringMap.t
35 let empty : 'a t = StringMap.empty
37 (* Search by name and return topmost binding *)
39 match StringMap.find s m with
40 | id_data :: _ -> id_data
43 (* Search by identifier and return associated binding *)
45 let rec lookup_in = function
46 | [] -> raise Not_found
47 | (id', data) :: rem ->
48 if id'.stamp = id.stamp then data else lookup_in rem in
49 lookup_in (StringMap.find id.name m)
51 (* Insert by identifier *)
53 let l = try StringMap.find id.name m with Not_found -> [] in
54 StringMap.add id.name ((id, data) :: l) m
59 let fresh_ident s = incr gensym; { name = s; stamp = !gensym }
61 (* Infos associated with structs or unions *)
63 type composite_info = {
64 ci_kind: struct_or_union;
65 ci_members: field list; (* members, in order *)
66 ci_alignof: int option; (* alignment; None if incomplete *)
67 ci_sizeof: int option; (* size; None if incomplete *)
70 (* Infos associated with an ordinary identifier *)
73 | II_ident of storage * typ
74 | II_enum of int64 (* value of the enum *)
76 (* Infos associated with a typedef *)
78 type typedef_info = typ
84 env_ident: ident_info IdentMap.t;
85 env_tag: composite_info IdentMap.t;
86 env_typedef: typedef_info IdentMap.t
91 env_ident = IdentMap.empty;
92 env_tag = IdentMap.empty;
93 env_typedef = IdentMap.empty
96 (* Enter a new scope. *)
99 { env with env_scope = !gensym + 1 }
101 let in_current_scope env id = id.stamp >= env.env_scope
103 (* Looking up things by source name *)
105 let lookup_ident env s =
107 IdentMap.lookup s env.env_ident
109 raise(Error(Unbound_identifier s))
111 let lookup_tag env s =
113 IdentMap.lookup s env.env_tag
115 raise(Error(Unbound_tag(s, "tag")))
117 let lookup_struct env s =
119 let (id, ci as res) = IdentMap.lookup s env.env_tag in
120 if ci.ci_kind <> Struct then
121 raise(Error(Tag_mismatch(s, "struct", "union")));
124 raise(Error(Unbound_tag(s, "struct")))
126 let lookup_union env s =
128 let (id, ci as res) = IdentMap.lookup s env.env_tag in
129 if ci.ci_kind <> Union then
130 raise(Error(Tag_mismatch(s, "union", "struct")));
133 raise(Error(Unbound_tag(s, "union")))
135 let lookup_composite env s =
136 try Some (IdentMap.lookup s env.env_tag)
137 with Not_found -> None
139 let lookup_typedef env s =
141 IdentMap.lookup s env.env_typedef
143 raise(Error(Unbound_typedef s))
145 (* Checking if a source name is bound *)
147 let ident_is_bound env s = StringMap.mem s env.env_ident
149 (* Finding things by translated identifier *)
151 let find_ident env id =
152 try IdentMap.find id env.env_ident
154 raise(Error(Unbound_identifier(id.name)))
156 let find_tag env id =
157 try IdentMap.find id env.env_tag
159 raise(Error(Unbound_tag(id.name, "tag")))
161 let find_struct env id =
163 let ci = IdentMap.find id env.env_tag in
164 if ci.ci_kind <> Struct then
165 raise(Error(Tag_mismatch(id.name, "struct", "union")));
168 raise(Error(Unbound_tag(id.name, "struct")))
170 let find_union env id =
172 let ci = IdentMap.find id env.env_tag in
173 if ci.ci_kind <> Union then
174 raise(Error(Tag_mismatch(id.name, "union", "struct")));
177 raise(Error(Unbound_tag(id.name, "union")))
179 let find_member ci m =
180 List.find (fun f -> f.fld_name = m) ci
182 let find_struct_member env (id, m) =
184 let ci = find_struct env id in
185 find_member ci.ci_members m
187 raise(Error(No_member(id.name, "struct", m)))
189 let find_union_member env (id, m) =
191 let ci = find_union env id in
192 find_member ci.ci_members m
194 raise(Error(No_member(id.name, "union", m)))
196 let find_typedef env id =
198 IdentMap.find id env.env_typedef
200 raise(Error(Unbound_typedef(id.name)))
202 (* Inserting things by source name, with generation of a translated name *)
204 let enter_ident env s sto ty =
205 let id = fresh_ident s in
207 { env with env_ident = IdentMap.add id (II_ident(sto, ty)) env.env_ident })
209 let enter_composite env s ci =
210 let id = fresh_ident s in
211 (id, { env with env_tag = IdentMap.add id ci env.env_tag })
213 let enter_enum_item env s v =
214 let id = fresh_ident s in
215 (id, { env with env_ident = IdentMap.add id (II_enum v) env.env_ident })
217 let enter_typedef env s info =
218 let id = fresh_ident s in
219 (id, { env with env_typedef = IdentMap.add id info env.env_typedef })
221 (* Inserting things by translated name *)
223 let add_ident env id sto ty =
224 { env with env_ident = IdentMap.add id (II_ident(sto, ty)) env.env_ident }
226 let add_composite env id ci =
227 { env with env_tag = IdentMap.add id ci env.env_tag }
229 let add_typedef env id info =
230 { env with env_typedef = IdentMap.add id info env.env_typedef }
232 (* Error reporting *)
236 let error_message = function
237 | Unbound_identifier name ->
238 sprintf "Unbound identifier '%s'" name
239 | Unbound_tag(name, kind) ->
240 sprintf "Unbound %s '%s'" kind name
241 | Tag_mismatch(name, expected, actual) ->
242 sprintf "'%s' was declared as a %s but is used as a %s"
244 | Unbound_typedef name ->
245 sprintf "Unbound typedef '%s'" name
246 | No_member(compname, compkind, memname) ->
247 sprintf "%s '%s' has no member named '%s'"
248 compkind compname memname