6 (Printf.sprintf
"unparse_hrule: line: %d, %s" (Ast.get_line x
) s
)
8 let names = ref ([] : (string * int ref) list
)
10 let started_files = ref ([] : (string * bool) list
)
11 let typedefs = ref ([] : (string * string list
ref) list
)
12 let current_outfile = ref ""
14 let prefix = "_cocci_"
16 (* ----------------------------------------------------------------------- *)
17 (* Create rule to check for header include *)
19 let print_header_rule pr srcfile
=
20 match Str.split
(Str.regexp
"/") srcfile
with
22 pr
"@header@\n@@\n\n#include \"";
23 pr x
; pr
"\"\n\n"; true
25 let rec loop = function
28 pr
"@header@\n@@\n\n#include \"";
29 pr x
; pr
"\"\n\n"; true
30 | "include"::(x
::xs
) ->
31 pr
"@header@\n@@\n\n#include <";
33 if Str.string_match
(Str.regexp
"asm-") x 0 then "asm" else x in
34 pr
(String.concat
"/" (x::xs
));
39 (* ----------------------------------------------------------------------- *)
40 (* Print check that we are not in the defining function *)
42 let print_check_rule pr function_name function_name_count header_req
=
44 then pr
(Printf.sprintf
"@same_%s depends on header@\n" function_name_count
)
45 else pr
(Printf.sprintf
"@same_%s@\n" function_name_count
));
48 pr function_name
; pr
"@p(...) { ... }\n\n"
50 (* ----------------------------------------------------------------------- *)
51 (* get parameters of the matched function *)
53 let rec env_lookup fn
= function
54 [] -> failwith
"no binding"
55 | (nm
,vl
)::rest
when fn nm
-> vl
56 | _
::rest
-> env_lookup fn rest
59 let argname = ref ("","") in
60 let fn ((_
,nm
) as name
) =
62 then (argname := name
; true)
64 match env_lookup fn env
with
65 Ast_c.MetaParamListVal
(paramst
) -> (paramst
,!argname)
66 | _
-> failwith
"not possible"
68 let get_function_name rule env
=
69 let donothing r k e
= k e
in
70 let option_default = [] in
71 let bind = Common.union_set
in
72 let do_any_list_list r any_list_list
=
75 (function prev
-> function cur
->
76 bind (r
.V.combiner_anything cur
) prev
))
79 match Ast.get_mcodekind mc
with
80 Ast.MINUS
(_
,any_list_list
) -> do_any_list_list r any_list_list
81 | Ast.CONTEXT
(_
,any_befaft
) ->
82 (match any_befaft
with
83 Ast.BEFORE
(any_list_list
) | Ast.AFTER
(any_list_list
) ->
84 do_any_list_list r any_list_list
85 | Ast.BEFOREAFTER
(ba
,aa
) ->
86 bind (do_any_list_list r ba
) (do_any_list_list r aa
)
89 let expression r k e
=
91 (match Ast.unwrap e
with
92 Ast.FunCall
(fn,lp
,args
,rp
) ->
93 (match Ast.undots args
with
95 (match Ast.unwrap e
with
96 Ast.MetaExprList
(nm
,_
,_
,_
) ->
97 (match Ast.unwrap_mcode nm
with
98 (_
,"ARGS") when Ast.get_mcodekind nm
= Ast.PLUS
->
99 (match Ast.unwrap
fn with
101 (match Ast.unwrap id
with
103 | Ast.MetaFunc
(nm
,_
,_
,_
)
104 | Ast.MetaLocalFunc
(nm
,_
,_
,_
) ->
105 [Ast.unwrap_mcode nm
]
113 (V.combiner
bind option_default
114 mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
115 donothing donothing donothing donothing
116 donothing expression donothing donothing donothing donothing donothing
117 donothing donothing donothing donothing donothing).V.combiner_top_level
121 (match env_lookup (function nm
-> nm
= name
) env
with
122 Ast_c.MetaIdVal
(s
) | Ast_c.MetaFuncVal
(s
)
123 | Ast_c.MetaLocalFuncVal
(s
) -> s
124 | _
-> error rule
"not possible")
125 | _
-> error rule
"inconsistent rule generation"
127 (* ----------------------------------------------------------------------- *)
128 (* Print metavariable declarations *)
130 let rec print_typedef pr
= function
131 (Ast_c.TypeName
(s
,_
),_
) ->
133 try List.assoc
!current_outfile !typedefs
136 typedefs := (!current_outfile,td)::!typedefs;
138 if not
(List.mem s
!typedefs)
139 then (typedefs := s
::!typedefs; pr
"typedef "; pr s
; pr
";\n")
140 | (Ast_c.Pointer
(_
,ty
),_
) -> print_typedef pr ty
143 let rewrap_str s ii
=
144 {ii
with Ast_c.pinfo
=
145 (match ii
.Ast_c.pinfo
with
146 Ast_c.OriginTok pi
->
147 Ast_c.OriginTok
{ pi
with Common.str
= s
;}
148 | Ast_c.ExpandedTok
(pi
,vpi
) ->
149 Ast_c.ExpandedTok
({ pi
with Common.str
= s
;},vpi
)
150 | Ast_c.FakeTok
(_
,vpi
) -> Ast_c.FakeTok
(s
,vpi
)
151 | Ast_c.AbstractLineTok pi
->
152 Ast_c.AbstractLineTok
{ pi
with Common.str
= s
;})}
154 let print_metavar pr
= function
155 ((_
,Some param
,(_
,(Ast_c.Pointer
(_
,(Ast_c.BaseType
(Ast_c.Void
),_
)),_
))),_
)
157 pr
("expression "^
prefix); pr param
158 | (((_
,Some param
,(_
,ty
)),il
) : Ast_c.parameterType
) ->
160 match List.rev
il with
161 name
::rest
-> (rewrap_str (prefix^param
) name
) :: rest
162 | _
-> failwith
"no name" in
164 Pretty_print_c.pp_param_gen
166 let str = Ast_c.str_of_info
x in
167 if not
(List.mem
str ["const";"volatile"])
169 (function _
-> pr
" ")
171 (({Ast_c.const
= false; Ast_c.volatile
= false},[]),ty
)),
173 | _
-> failwith
"function must have named parameters"
175 let make_exp = function
176 (((_
,Some name
,ty
),param_ii
),comma_ii
) ->
177 let no_info = (None
,Ast_c.NotTest
) in
178 let nm = prefix^name
in
180 ((Ast_c.Ident
nm,ref no_info),
181 [rewrap_str nm (List.hd
(List.rev param_ii
))]) in
182 (name
,(Common.Left
exp,comma_ii
))
183 | _
-> failwith
"bad parameter"
185 let print_extra_typedefs pr env
=
187 { Visitor_c.default_visitor_c
with
188 Visitor_c.ktype
= (fun (k
, bigf) ty
->
190 (_
,((Ast_c.TypeName
(_
,_
),_
) as ty
)) -> print_typedef pr ty
195 Ast_c.MetaIdVal
(_
) | Ast_c.MetaFuncVal
(_
)
196 | Ast_c.MetaLocalFuncVal
(_
) -> ()
197 | Ast_c.MetaExprVal
(exp) -> Visitor_c.vk_expr
bigf exp
198 | Ast_c.MetaExprListVal
(args
) -> Visitor_c.vk_argument_list
bigf args
199 | Ast_c.MetaParamVal
(param
) -> Visitor_c.vk_param
bigf param
200 | Ast_c.MetaParamListVal
(params
) -> Visitor_c.vk_param_list
bigf params
202 | Ast_c.MetaTypeVal
(ty
) -> Visitor_c.vk_type
bigf ty
203 | Ast_c.MetaInitVal
(ty
) -> Visitor_c.vk_ini
bigf ty
204 | Ast_c.MetaStmtVal
(stm
) -> Visitor_c.vk_statement
bigf stm
205 | Ast_c.MetaPosVal _
| Ast_c.MetaPosValList _
206 | Ast_c.MetaListlenVal _
-> ())
209 let rename argids env
=
210 let argenv = List.map
(function arg
-> (arg
,prefix^arg
)) argids
in
211 let lookup x = try List.assoc
x argenv with Not_found
-> x in
213 { Visitor_c.default_visitor_c_s
with
214 Visitor_c.kexpr_s
= (fun (k
,bigf) e
->
216 ((Ast_c.Ident s
, info
), [ii
]) ->
217 let new_name = lookup s
in
218 ((Ast_c.Ident
new_name, info
), [rewrap_str new_name ii
])
224 Ast_c.MetaIdVal
(_
) | Ast_c.MetaFuncVal
(_
)
225 | Ast_c.MetaLocalFuncVal
(_
) -> vl
226 | Ast_c.MetaExprVal
(exp) ->
227 Ast_c.MetaExprVal
(Visitor_c.vk_expr_s
bigf exp)
228 | Ast_c.MetaExprListVal
(args
) ->
229 Ast_c.MetaExprListVal
(Visitor_c.vk_arguments_s
bigf args
)
230 | Ast_c.MetaParamVal
(param
) ->
231 Ast_c.MetaParamVal
(Visitor_c.vk_param_s
bigf param
)
232 | Ast_c.MetaParamListVal
(params
) ->
233 Ast_c.MetaParamListVal
(Visitor_c.vk_params_s
bigf params
)
235 | Ast_c.MetaTypeVal
(ty
) ->
236 Ast_c.MetaTypeVal
(Visitor_c.vk_type_s
bigf ty
)
237 | Ast_c.MetaInitVal
(ini
) ->
238 Ast_c.MetaInitVal
(Visitor_c.vk_ini_s
bigf ini
)
239 | Ast_c.MetaStmtVal
(stm
) ->
240 Ast_c.MetaStmtVal
(Visitor_c.vk_statement_s
bigf stm
)
241 | Ast_c.MetaPosVal _
| Ast_c.MetaPosValList _
242 | Ast_c.MetaListlenVal _
-> vl
))
245 let print_one_type pr env
= function
246 (Type_cocci.MetaType
(name
,keep
,inherited
)) as ty
->
248 match List.assoc name env
with
249 Ast_c.MetaTypeVal ty
->
250 Pretty_print_c.pp_type_gen
251 (function x -> pr
(Ast_c.str_of_info
x))
252 (function _
-> pr
" ")
254 | _
-> failwith
"impossible"
255 with Not_found
-> pr
(Type_cocci.type2c ty
))
256 | ty
-> pr
(Type_cocci.type2c ty
)
258 let print_types pr env
= function
260 | Some
[ty
] -> print_one_type pr env ty
263 Common.print_between
(function _
-> pr
", ") (print_one_type pr env
)
267 let pp_meta_decl pr env decl
=
268 let no_arity = function Ast.NONE
-> () | _
-> failwith
"no arity allowed" in
269 let pp_name (_
,n
) = pr n
in
271 Ast.MetaIdDecl
(ar
, name
) ->
272 no_arity ar
; pr
"identifier "; pp_name name
; pr
";\n"
273 | Ast.MetaFreshIdDecl
(ar
, name
) ->
274 no_arity ar
; pr
"fresh identifier "; pp_name name
; pr
";\n"
275 | Ast.MetaTypeDecl
(ar
, name
) ->
276 no_arity ar
; pr
"type "; pp_name name
; pr
";\n"
277 | Ast.MetaInitDecl
(ar
, name
) ->
278 no_arity ar
; pr
"initialiser "; pp_name name
; pr
";\n"
279 | Ast.MetaListlenDecl
(name
) -> ()
280 | Ast.MetaParamDecl
(ar
, name
) ->
281 no_arity ar
; pr
"parameter "; pp_name name
; pr
";\n"
282 | Ast.MetaParamListDecl
(ar
, name
, None
) ->
283 no_arity ar
; pr
"parameter list "; pp_name name
; pr
";\n"
284 | Ast.MetaParamListDecl
(ar
, name
, Some len
) ->
285 no_arity ar
; pr
"parameter list "; pp_name name
;
286 pr
"["; pp_name len
; pr
"]"; pr
";\n"
287 | Ast.MetaConstDecl
(ar
, name
, types
) ->
288 no_arity ar
; pr
"constant "; print_types pr env types
;
289 pp_name name
; pr
";\n"
290 | Ast.MetaErrDecl
(ar
, name
) ->
291 no_arity ar
; pr
"error "; pp_name name
; pr
";\n"
292 | Ast.MetaExpDecl
(ar
, name
, None
) ->
293 no_arity ar
; pr
"expression "; pp_name name
; pr
";\n"
294 | Ast.MetaExpDecl
(ar
, name
, types
) ->
295 no_arity ar
; print_types pr env types
; pp_name name
; pr
";\n"
296 | Ast.MetaIdExpDecl
(ar
, name
, types
) ->
297 no_arity ar
; pr
"idexpression ";
298 print_types pr env types
; pp_name name
; pr
";\n"
299 | Ast.MetaLocalIdExpDecl
(ar
, name
, types
) ->
300 no_arity ar
; pr
"local idexpression ";
301 print_types pr env types
; pp_name name
; pr
";\n"
302 | Ast.MetaExpListDecl
(ar
, name
, None
) ->
303 no_arity ar
; pr
"parameter list "; pp_name name
; pr
";\n"
304 | Ast.MetaExpListDecl
(ar
, name
, Some len
) ->
305 no_arity ar
; pr
"parameter list ";
306 pp_name name
; pr
"["; pp_name len
; pr
"]"; pr
";\n"
307 | Ast.MetaStmDecl
(ar
, name
) ->
308 no_arity ar
; pr
"statement "; pp_name name
; pr
";\n"
309 | Ast.MetaStmListDecl
(ar
, name
) ->
310 no_arity ar
; pr
"statement list "; pp_name name
; pr
";\n"
311 | Ast.MetaFuncDecl
(ar
, name
) ->
312 no_arity ar
; pr
"function "; pp_name name
; pr
";\n"
313 | Ast.MetaLocalFuncDecl
(ar
, name
) ->
314 no_arity ar
; pr
"local function "; pp_name name
; pr
";\n"
315 | Ast.MetaPosDecl
(ar
, name
) ->
316 no_arity ar
; pr
"position "; pp_name name
; pr
";\n"
317 | Ast.MetaDeclarerDecl
(ar
, name
) ->
318 no_arity ar
; pr
"declarer "; pp_name name
; pr
";\n"
319 | Ast.MetaIteratorDecl
(ar
, name
) ->
320 no_arity ar
; pr
"iterator "; pp_name name
; pr
";\n"
322 let print_metavariables pr local_metas paramst env header_req function_name
=
324 then pr
"@depends on header@\n"
326 pr
(Printf.sprintf
"position _p!=same_%s.p;\n" function_name
);
327 pr
"identifier _f;\n";
328 let rec loop = function
329 [] | [(((_
,_
,(_
,(Ast_c.BaseType
(Ast_c.Void
),_
))),_
),_
)] -> []
330 | ((first
,_
) as f
)::rest
->
331 print_metavar pr first
; pr
";\n";
332 (make_exp f
) :: loop rest
in
333 let args = loop paramst
in
334 print_extra_typedefs pr env
;
335 List.iter
(pp_meta_decl pr env
) local_metas
;
339 (* ----------------------------------------------------------------------- *)
340 (* print_start/end *)
343 pr
"_f@_p(...) { <+...\n"
348 (* ----------------------------------------------------------------------- *)
349 (* Print call to the defined function *)
351 let print_param_name pr
= function
352 ((_
,Some param
,_
),_
) -> pr param
353 | _
-> failwith
"function must have named parameters"
355 let pp_def_gen pr defn isexp
=
356 let {Ast_c.f_name
= s
; f_type
= (_
, (paramst
, (b
, iib
))); } = defn
in
358 (if b
then failwith
"not handling variable argument functions");
360 [] | [(((_
,_
,(_
,(Ast_c.BaseType
(Ast_c.Void
),_
))),_
),_
)] -> ()
362 print_param_name pr first
;
363 List.iter
(function (x,_
) -> pr
", "; print_param_name pr
x) rest
);
364 pr
")"; if not isexp
then pr
";"
366 (* ----------------------------------------------------------------------- *)
369 let pp_rule local_metas ast env srcfile
=
370 let (paramst
,args_name
) = get_paramst env
in
371 (* get rule information *)
372 let (rule
,printable
) =
374 Ast.CocciRule
(_
,_
,[body
],_
,_
) -> (* could extend to use attributes *)
376 match Ast.unwrap body
with
377 Ast.DECL
(s
) -> [[Ast.StatementTag s
]]
378 | Ast.CODE
(ss
) -> [[Ast.StmtDotsTag ss
]]
379 | _
-> error body
"bad rule body")
380 | _
-> failwith
"bad rule" in
381 (* create the output file *)
383 match !Flag.make_hrule
with
384 Some
outdir -> outdir
385 | None
-> error rule
"not possible" in
386 let function_name = get_function_name rule env
in
387 let function_name_count =
389 let cell = List.assoc
function_name !names in
392 function_name ^
(string_of_int
ct)
395 names := (function_name,cell) :: !names;
397 let outfile = outdir ^
"/" ^
398 (if !Flag.hrule_per_file
399 then Filename.chop_extension
(Filename.basename srcfile
)
400 else function_name_count) in
401 let escape_re = Str.regexp_string
"/" in
402 let dir = if !Flag.dir = "" then Filename.dirname srcfile
else !Flag.dir in
403 let outdirfile = Str.global_replace
escape_re "_"dir in
404 let outfile = outfile ^
outdirfile ^
".cocci" in
405 let saved_header_req =
406 try let res = List.assoc
outfile !started_files in Some
res
407 with Not_found
-> None
in
408 current_outfile := outfile;
409 Common.with_open_outfile_append
outfile (fun (pr
,chan
) ->
411 match saved_header_req with
414 let res = print_header_rule pr srcfile
in
415 started_files := (outfile,res)::!started_files;
417 print_check_rule pr
function_name function_name_count header_req;
419 print_metavariables pr local_metas paramst env
header_req
420 function_name_count in
421 let (argids
,args) = List.split
args in
422 let env = rename argids
env in
423 let env = (args_name
,Ast_c.MetaExprListVal
args)::env in
425 (* for printing C tokens *)
427 match Ast_c.pinfo_of_info info
with
428 Ast_c.AbstractLineTok _
-> pr
(Ast_c.str_of_info info
)
429 | Ast_c.FakeTok
(s
,_
) -> pr s
431 Printf.printf
"line: %s\n" (Common.dump info
);
432 error rule
"not an abstract line" in
433 Unparse_cocci.pp_list_list_any
434 (env, pr
, pr_c, (function _
-> pr
" "),
435 (function _
-> ()), (function _
-> ()))
436 true printable
Unparse_cocci.InPlace
;