permit multiline comments and strings in macros
[bpt/coccinelle.git] / parsing_c / parsing_consistency_c.ml
CommitLineData
978fd7e5 1(* Yoann Padioleau
ae4735db
C
2 *
3 * Copyright (C) 2010, University of Copenhagen DIKU and INRIA.
978fd7e5
C
4 * Copyright (C) 2006, 2007, 2008 Ecole des Mines de Nantes
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License (GPL)
8 * version 2 as published by the Free Software Foundation.
ae4735db 9 *
978fd7e5
C
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * file license.txt for more details.
14 *)
15
16open Common
17
18
19(*****************************************************************************)
20(* Wrappers *)
21(*****************************************************************************)
ae4735db 22let pr2_err, pr2_once = Common.mk_pr2_wrappers Flag_parsing_c.verbose_parsing
978fd7e5
C
23
24(*****************************************************************************)
25(* Consistency checking *)
26(*****************************************************************************)
27
28(* todo:
29 * could check that an ident has always the same class, be it a typedef
ae4735db 30 * (but sometimes do 'acpi_val acpi_val;'), an ident, a TMacroStatement,
978fd7e5
C
31 * etc.
32 *)
33
ae4735db 34type class_ident =
978fd7e5
C
35 | CIdent (* can be var, func, field, tag, enum constant *)
36 | CTypedef
37
38let str_of_class_ident = function
39 | CIdent -> "Ident"
40 | CTypedef -> "Typedef"
41
42(*
43 | CMacro
44 | CMacroString
45 | CMacroStmt
46 | CMacroDecl
47 | CMacroIterator
48 | CAttr
49
50(* but take care that must still be able to use '=' *)
51type context = InFunction | InEnum | InStruct | InInitializer | InParams
ae4735db 52type class_token =
978fd7e5
C
53 | CIdent of class_ident
54
ae4735db 55 | CComment
978fd7e5
C
56 | CSpace
57 | CCommentCpp of cppkind
58 | CCommentMisc
59 | CCppDirective
60
61 | COPar
62 | CCPar
63 | COBrace
64 | CCBrace
65
66 | CSymbol
67 | CReservedKwd (type | decl | qualif | flow | misc | attr)
68*)
69
70let ident_to_typename ident : Ast_c.fullType =
71 Ast_c.mk_ty (Ast_c.TypeName (ident, Ast_c.noTypedefDef())) Ast_c.noii
ae4735db 72
978fd7e5
C
73
74(* parse_typedef_fix4 *)
ae4735db 75let consistency_checking2 xs =
978fd7e5
C
76
77 (* first phase, gather data *)
ae4735db 78 let stat = Hashtbl.create 101 in
978fd7e5
C
79
80 (* default value for hash *)
81 let v1 () = Hashtbl.create 101 in
82 let v2 () = ref 0 in
83
84 let bigf = { Visitor_c.default_visitor_c with
85
ae4735db 86 Visitor_c.kexpr = (fun (k,bigf) x ->
978fd7e5 87 match Ast_c.unwrap_expr x with
ae4735db 88 | Ast_c.Ident (id) ->
978fd7e5 89 let s = Ast_c.str_of_name id in
ae4735db
C
90 stat +>
91 Common.hfind_default s v1 +> Common.hfind_default CIdent v2 +>
978fd7e5
C
92 (fun aref -> incr aref)
93
94 | _ -> k x
95 );
ae4735db 96 Visitor_c.ktype = (fun (k,bigf) t ->
978fd7e5 97 match Ast_c.unwrap_typeC t with
ae4735db 98 | Ast_c.TypeName (name,_typ) ->
978fd7e5 99 let s = Ast_c.str_of_name name in
ae4735db
C
100 stat +>
101 Common.hfind_default s v1 +> Common.hfind_default CTypedef v2 +>
978fd7e5
C
102 (fun aref -> incr aref)
103
104 | _ -> k t
105 );
ae4735db 106 }
978fd7e5
C
107 in
108 xs +> List.iter (fun (p) -> Visitor_c.vk_toplevel bigf p);
109
110
111 let ident_to_type = ref [] in
ae4735db 112
978fd7e5
C
113
114 (* second phase, analyze data *)
ae4735db 115 stat +> Hashtbl.iter (fun k v ->
978fd7e5
C
116 let xs = Common.hash_to_list v in
117 if List.length xs >= 2
951c7801
C
118 then begin
119 pr2_err ("TYPEDEF CONFLICT:" ^ k);
ae4735db 120 let sorted = xs +> List.sort (fun (ka,va) (kb,vb) ->
978fd7e5
C
121 if !va =|= !vb then
122 (match ka, kb with
123 | CTypedef, _ -> 1 (* first is smaller *)
124 | _, CTypedef -> -1
125 | _ -> 0
126 )
127 else compare !va !vb
128 ) in
129 let sorted = List.rev sorted in
130 match sorted with
ae4735db 131 | [CTypedef, i1;CIdent, i2] ->
978fd7e5
C
132 pr2_err ("transforming some ident in typedef");
133 push2 k ident_to_type;
951c7801
C
134 | [CIdent, i1;CTypedef, i2] ->
135 pr2_err ("TODO:typedef now used as an identifier");
ae4735db 136 | _ ->
978fd7e5 137 pr2_err ("TODO:other transforming?");
ae4735db 138
978fd7e5
C
139 end
140 );
141
ae4735db 142 (* third phase, update ast.
978fd7e5 143 * todo? but normally should try to handle correctly scope ? maybe sometime
ae4735db 144 * sizeof(id) and even if id was for a long time an identifier, maybe
978fd7e5
C
145 * a few time, because of the scope it's actually really a type.
146 *)
147 if (null !ident_to_type)
ae4735db
C
148 then xs
149 else
978fd7e5 150 let bigf = { Visitor_c.default_visitor_c_s with
ae4735db 151 Visitor_c.kdefineval_s = (fun (k,bigf) x ->
978fd7e5 152 match x with
ae4735db 153 | Ast_c.DefineExpr e ->
978fd7e5 154 (match Ast_c.unwrap_expr e with
ae4735db
C
155 | Ast_c.Ident (ident) ->
156 let s = Ast_c.str_of_name ident in
978fd7e5
C
157 if List.mem s !ident_to_type
158 then
159 let t = ident_to_typename ident in
160 Ast_c.DefineType t
161 else k x
162 | _ -> k x
163 )
164 | _ -> k x
165 );
ae4735db 166 Visitor_c.kexpr_s = (fun (k, bigf) x ->
978fd7e5 167 match Ast_c.get_e_and_ii x with
ae4735db 168 | (Ast_c.SizeOfExpr e, tref), isizeof ->
978fd7e5
C
169 let i1 = tuple_of_list1 isizeof in
170 (match Ast_c.get_e_and_ii e with
ae4735db 171 | (Ast_c.ParenExpr e, _), iiparen ->
978fd7e5
C
172 let (i2, i3) = tuple_of_list2 iiparen in
173 (match Ast_c.get_e_and_ii e with
ae4735db 174 | (Ast_c.Ident (ident), _), _ii ->
978fd7e5 175
ae4735db 176 let s = Ast_c.str_of_name ident in
978fd7e5
C
177 if List.mem s !ident_to_type
178 then
179 let t = ident_to_typename ident in
180 (Ast_c.SizeOfType t, tref),[i1;i2;i3]
181 else k x
182 | _ -> k x
183 )
184 | _ -> k x
185 )
186 | _ -> k x
187 );
188 } in
ae4735db 189 xs +> List.map (fun (p) ->
978fd7e5
C
190 Visitor_c.vk_toplevel_s bigf p
191 )
192
193
ae4735db 194let consistency_checking a =
978fd7e5
C
195 Common.profile_code "C consistencycheck" (fun () -> consistency_checking2 a)
196
197
198