5 let score_path = "/home/pad/c-yacfe/tmp"
7 let tmpfile = "/tmp/output.c"
9 module Ast_to_flow
= Control_flow_c_build
11 (*****************************************************************************)
12 (* Subsystem testing *)
13 (*****************************************************************************)
15 let test_tokens_c file
=
16 if not
(file
=~
".*\\.c")
17 then pr2
"warning: seems not a .c file";
19 Flag_parsing_c.debug_lexer
:= true;
20 Flag_parsing_c.verbose_lexing
:= true;
21 Flag_parsing_c.verbose_parsing
:= true;
23 Parse_c.tokens file
+> List.iter
(fun x
-> pr2_gen x
);
27 (* ---------------------------------------------------------------------- *)
29 (* Was in main, but using it in test_parsing_c *)
32 cmd_to_list
(* same as "true, "", _" case *)
33 (if !Flag.include_headers
34 (* FIXME : Could we remove xs ?
35 -use_glimpse requires a singleton.
36 This is checked some lines before.
37 then ("find "^(join " " (x::xs))^" -name \"*.[ch]\"")
38 else ("find "^(join " " (x::xs))^" -name \"*.c\"")
40 then ("find "^ path ^
" -name \"*.[ch]\"")
41 else ("find "^ path ^
" -name \"*.c\"")) in
44 then cmd_to_list
("find "^ path ^
" -name \"*.cpp\"")
48 let new_test_parse_gen xs
=
50 Flag_parsing_c.debug_typedef
:= true;
51 Flag_parsing_c.debug_cpp
:= true;
52 Flag_parsing_c.debug_etdt
:= false;
53 Flag_parsing_c.filter_msg
:= true;
57 | [x] when is_directory x -> Some x
62 let xs = if !Flag.dir then
63 process_output_to_list ("find " ^ x ^" -name \"*.c\"") else x::xs in
65 let fullxs = xs +> List.map
get_files +> List.concat
in
67 let stat_list = ref [] in
68 let newscore = Common.empty_score
() in
70 Common.check_stack_nbfiles
(List.length
fullxs);
72 fullxs +> List.iter
(fun file
->
75 pr2
("PARSING: " ^ file
);
77 let (xs, stat
) = Parse_c.parse_c_and_cpp file
in
78 xs +> List.iter
(fun (ast
, (s
, toks
)) ->
79 Parse_c.print_commentized toks
82 Common.push2 stat
stat_list;
84 sprintf
"bad = %d, timeout = %B"
85 stat
.Parsing_stat.bad stat
.Parsing_stat.have_timeout
87 if stat
.Parsing_stat.bad
=|= 0 && not stat
.Parsing_stat.have_timeout
88 then Hashtbl.add
newscore file
(Common.Ok
)
89 else Hashtbl.add
newscore file
(Common.Pb
s)
92 (* uses an explicit path; to fix
93 dirname_opt +> Common.do_option (fun dirname ->
94 pr2_xxxxxxxxxxxxxxxxx();
95 pr2 "regression testing information";
96 pr2_xxxxxxxxxxxxxxxxx();
97 let str = Str.global_replace (Str.regexp "/") "__" dirname in
98 let def = if !Flag_parsing_c.filter_define_error then "_def_" else "" in
99 let ext = if ext =$= "c" then "" else ext in
100 let filename = "score_parsing__" ^str ^ def ^ ext ^ ".marshalled" in
101 if Sys.file_exists filename
103 Common.regression_testing newscore
104 (Filename.concat score_path
105 ("score_parsing__" ^str ^ def ^ ext ^ ".marshalled"))
109 if not
(null
!stat_list)
111 Parsing_stat.print_recurring_problematic_tokens
!stat_list;
112 Parsing_stat.print_parsing_stat_list
!stat_list;
116 (* ---------------------------------------------------------------------- *)
117 let test_parse_gen xs ext =
119 Flag_parsing_c.debug_typedef
:= true;
120 Flag_parsing_c.debug_cpp
:= true;
121 Flag_parsing_c.debug_etdt
:= false;
122 Flag_parsing_c.filter_msg
:= true;
126 | [x] when is_directory x -> Some x
131 let xs = if !Flag.dir then
132 process_output_to_list ("find " ^ x ^" -name \"*.c\"") else x::xs in
134 let fullxs = Common.files_of_dir_or_files_no_vcs
ext xs in
136 let stat_list = ref [] in
137 let newscore = Common.empty_score
() in
139 Common.check_stack_nbfiles
(List.length
fullxs);
141 fullxs +> List.iter
(fun file
->
142 if not
(file
=~
(".*\\."^
ext))
143 then pr2
("warning: seems not a ."^
ext^
" file");
147 pr2
("PARSING: " ^ file
);
149 let (xs, stat
) = Parse_c.parse_c_and_cpp file
in
150 xs +> List.iter
(fun (ast
, (s, toks
)) ->
151 Parse_c.print_commentized toks
154 Common.push2 stat
stat_list;
156 sprintf
"bad = %d, timeout = %B"
157 stat
.Parsing_stat.bad stat
.Parsing_stat.have_timeout
159 if stat
.Parsing_stat.bad
=|= 0 && not stat
.Parsing_stat.have_timeout
160 then Hashtbl.add
newscore file
(Common.Ok
)
161 else Hashtbl.add
newscore file
(Common.Pb
s)
164 (* uses an explicit path; to fix
165 dirname_opt +> Common.do_option (fun dirname ->
166 pr2_xxxxxxxxxxxxxxxxx();
167 pr2 "regression testing information";
168 pr2_xxxxxxxxxxxxxxxxx();
169 let str = Str.global_replace (Str.regexp "/") "__" dirname in
170 let def = if !Flag_parsing_c.filter_define_error then "_def_" else "" in
171 let ext = if ext =$= "c" then "" else ext in
172 let filename = "score_parsing__" ^str ^ def ^ ext ^ ".marshalled" in
173 if Sys.file_exists filename
175 Common.regression_testing newscore
176 (Filename.concat score_path
177 ("score_parsing__" ^str ^ def ^ ext ^ ".marshalled"))
181 if not
(null
!stat_list)
183 Parsing_stat.print_recurring_problematic_tokens
!stat_list;
184 Parsing_stat.print_parsing_stat_list
!stat_list;
189 let test_parse_c xs =
190 test_parse_gen xs "c"
191 let test_parse_h xs =
192 test_parse_gen xs "h"
193 let test_parse_ch xs =
194 test_parse_gen xs "[ch]"
196 (* could use a simpler parser than heavy parse_c_and_cpp here as there
197 * is no more cpp stuff in the .i files
199 let test_parse_i xs =
200 test_parse_gen xs "i"
208 (* ---------------------------------------------------------------------- *)
209 (* file can be "foo.c" or "foo.c:main" *)
210 (* local function that is parameterized by whether to launch gv *)
211 let local_test_cfg launchgv file
=
212 let (file
, specific_func
) =
213 if file
=~
"\\(.*\\.c\\):\\(.*\\)"
215 let (a
,b
) = matched2 file
in
221 if not
(file
=~
".*\\.c")
222 then pr2
"warning: seems not a .c file";
224 let (program
, _stat
) = Parse_c.parse_c_and_cpp file
in
226 program
+> List.iter
(fun (e
,_
) ->
228 match specific_func
, e
with
229 | None
, Ast_c.Definition
(defbis
,_
) ->
230 Some
(Ast_c.str_of_name
(defbis
.Ast_c.f_name
))
231 | Some
s, Ast_c.Definition
(defbis
,_
) ->
232 let nm = Ast_c.str_of_name
(defbis
.Ast_c.f_name
) in
233 if s =$
= nm then Some
nm else None
239 | Some fn
-> (* old: Flow_to_ast.test !Flag.show_flow def *)
241 let flow = Ast_to_flow.ast_to_control_flow e
in
242 flow +> do_option
(fun flow ->
243 Ast_to_flow.deadcode_detection
flow;
244 let flow = Ast_to_flow.annotate_loop_nodes
flow in
248 if !Flag_cocci.show_before_fixed_flow
250 else Ctlcocci_integration.fix_flow_ctl flow
256 then Filename.temp_file
"output" ".dot"
258 let fl = Filename.chop_extension
(Filename.basename file
) in
260 Ograph_extended.print_ograph_mutable
flow'
(filename) launchgv
262 with Ast_to_flow.Error
(x
) -> Ast_to_flow.report_error x
265 let test_cfg = local_test_cfg true
269 let test_cfg_ifdef file
=
270 let (ast2
, _stat
) = Parse_c.parse_c_and_cpp file
in
271 let ast = Parse_c.program_of_program2 ast2
in
273 let ast = Cpp_ast_c.cpp_ifdef_statementize
ast in
275 ast +> List.iter
(fun e
->
277 let flow = Ast_to_flow.ast_to_control_flow e
in
278 flow +> do_option
(fun flow ->
279 Ast_to_flow.deadcode_detection
flow;
280 let flow = Ast_to_flow.annotate_loop_nodes
flow in
281 Ograph_extended.print_ograph_mutable
flow ("/tmp/output.dot") true
283 with Ast_to_flow.Error
(x
) -> Ast_to_flow.report_error x
287 (* ---------------------------------------------------------------------- *)
288 let test_parse_unparse infile
=
289 if not
(infile
=~
".*\\.c")
290 then pr2
"warning: seems not a .c file";
292 let (program2
, _stat
) = Parse_c.parse_c_and_cpp infile
in
293 let program2_with_ppmethod =
294 program2
+> List.map
(fun x
-> x
, Unparse_c.PPnormal
)
296 Unparse_c.pp_program
program2_with_ppmethod tmpfile;
297 Common.command2
("cat " ^
tmpfile);
298 (* if want see diff of space => no -b -B *)
299 Common.command2
(spf
"diff -u -p %s %s" infile
tmpfile);
300 (* +> Transformation.test_simple_trans1;*)
305 let parse_and_print_sexp file =
306 let (ast2,_stat) = Parse_c.parse_c_and_cpp file in
307 let ast = Parse_c.program_of_program2 ast2 in
309 Type_annoter_c.annotate_program !Type_annoter_c.initial_env ast
313 let sexp = Sexp_ast_c.sexp_of_program ast in
314 let s = Sexp.to_string_hum sexp in
316 Sexp_ast_c.show_info
:= false;
317 let s = Sexp_ast_c.string_of_program
ast in
323 let test_type_c infile
=
324 if not
(infile
=~
".*\\.c")
325 then pr2
"warning: seems not a .c file";
327 Flag_parsing_c.pretty_print_type_info
:= true;
329 let (program2
, _stat
) = Parse_c.parse_c_and_cpp infile
in
333 +> (fun (program
, infos
) ->
334 Type_annoter_c.annotate_program
!Type_annoter_c.initial_env
335 program
+> List.map fst
,
338 +> Common.uncurry
Common.zip
340 let program2_with_ppmethod =
341 program2
+> List.map
(fun x
-> x
, Unparse_c.PPnormal
)
343 Unparse_c.pp_program
program2_with_ppmethod tmpfile;
344 Common.command2
("cat " ^
tmpfile);
348 (* ---------------------------------------------------------------------- *)
349 (* ex: demos/platform_ifdef.c *)
350 let test_comment_annotater infile
=
351 let (program2
, _stat
) = Parse_c.parse_c_and_cpp infile
in
352 let asts = program2
+> List.map
(fun (ast,_
) -> ast) in
353 let toks = program2
+> List.map
(fun (ast, (s, toks)) -> toks) +>
356 Flag_parsing_c.pretty_print_comment_info
:= true;
358 pr2
"pretty print, before comment annotation: --->";
359 Common.adjust_pp_with_indent
(fun () ->
360 asts +> List.iter
(fun ast ->
361 Pretty_print_c.pp_toplevel_simple
ast;
365 let _ = Comment_annotater_c.annotate_program
toks asts in
367 Common.adjust_pp_with_indent
(fun () ->
368 pr2
"pretty print, after comment annotation: --->";
369 asts +> List.iter
(fun ast ->
370 Pretty_print_c.pp_toplevel_simple
ast;
378 (* ---------------------------------------------------------------------- *)
379 (* used by generic_makefile now *)
380 let test_compare_c file1 file2
=
381 let (correct
, diffxs
) = Compare_c.compare_default file1 file2
in
382 let res = Compare_c.compare_result_to_bool correct
in
384 then raise
(Common.UnixExit
0)
385 else raise
(Common.UnixExit
(-1))
388 let test_compare_c_hardcoded () =
389 Compare_c.compare_default
393 "tests/equal_modulo1.c"
394 "tests/equal_modulo2.c"
396 +> Compare_c.compare_result_to_string
401 (* ---------------------------------------------------------------------- *)
402 let test_attributes file
=
403 let (ast2
, _stat
) = Parse_c.parse_c_and_cpp file
in
404 let ast = Parse_c.program_of_program2 ast2
in
406 Visitor_c.vk_program
{ Visitor_c.default_visitor_c
with
407 Visitor_c.kdef
= (fun (k
, bigf
) (defbis
, ii
) ->
408 let sattr = Ast_c.s_of_attr defbis
.f_attr
in
409 pr2
(spf
"%-30s: %s" (Ast_c.str_of_name
(defbis
.f_name
)) sattr);
411 Visitor_c.kdecl
= (fun (k
, bigf
) decl
->
413 | DeclList
(xs, ii
) ->
414 xs +> List.iter
(fun (onedecl
, iicomma
) ->
416 let sattr = Ast_c.s_of_attr onedecl
.v_attr
in
418 match onedecl
.v_namei
with
419 | Some
(name
, ini
) -> Ast_c.str_of_name name
422 pr2
(spf
"%-30s: %s" idname sattr);
431 let cpp_options () = [
432 Cpp_ast_c.I
"/home/yyzhou/pad/linux/include";
434 Cpp_ast_c.cpp_option_of_cmdline
435 (!Flag_parsing_c.cpp_i_opts
,!Flag_parsing_c.cpp_d_opts
)
438 let (ast2
, _stat
) = Parse_c.parse_c_and_cpp file
in
439 let dirname = Filename.dirname file
in
440 let ast = Parse_c.program_of_program2 ast2
in
441 let ast = Cpp_ast_c.cpp_expand_include
(cpp_options()) dirname ast in
442 let _ast = Cpp_ast_c.cpp_ifdef_statementize
ast in
449 (* CONFIG [ch] ? also do for .c ? maybe less needed now that I
452 let extract_macros ~selection dir
=
454 let fullxs = Common.files_of_dir_or_files_no_vcs
ext [dir
] in
455 let macros_and_filename =
456 fullxs +> List.map
(fun file
->
457 pr2
(spf
"processing: %s" file
);
458 let xs = Parse_c.extract_macros file
in
465 then Cpp_analysis_c.extract_dangerous_macros
macros_and_filename
466 else macros_and_filename
468 macros +> List.iter
(fun (file
, defs
) ->
469 pr
("/* PARSING: " ^ file ^
" */");
470 defs
+> List.iter
(fun (s, def) ->
471 let str = Cpp_token_c.string_of_define_def
def in
480 Flag_parsing_c.filter_msg_define_error
:= true;
481 Flag_parsing_c.filter_define_error
:= true;
482 Flag_parsing_c.verbose_lexing
:= false;
483 Flag_parsing_c.verbose_parsing
:= false;
487 | [x
] when is_directory x
-> Some x
490 dirname_opt +> Common.do_option
(fun dir
->
493 let fullxs = Common.files_of_dir_or_files_no_vcs
ext [dir
] in
495 let macros_and_filename =
496 fullxs +> List.map
(fun file
->
497 pr2
(spf
"processing: %s" file
);
498 let xs = Parse_c.extract_macros file
in
503 Cpp_analysis_c.extract_dangerous_macros
macros_and_filename
505 macros +> List.iter
(fun (file
, xs) ->
506 xs +> List.iter
(fun (x
, def) ->
507 let (s, params
, body
) = def in
508 let str = Cpp_token_c.string_of_define_def
def in
511 Hashtbl.replace
!Parse_c._defs_builtins
s (s, params
, body
);
518 let fullxs = Common.files_of_dir_or_files_no_vcs
ext xs in
520 let stat_list = ref [] in
521 Common.check_stack_nbfiles
(List.length
fullxs);
523 fullxs +> List.iter
(fun file
->
524 if not
(file
=~
(".*\\."^
ext))
525 then pr2
("warning: seems not a ."^
ext^
" file");
528 pr2
("PARSING: " ^ file
);
530 let (xs, stat
) = Parse_c.parse_c_and_cpp file
in
531 xs +> List.iter
(fun (ast, (s, toks)) ->
532 Parse_c.print_commentized
toks
535 Common.push2 stat
stat_list;
538 if not
(null
!stat_list)
540 Parsing_stat.print_recurring_problematic_tokens
!stat_list;
541 Parsing_stat.print_parsing_stat_list
!stat_list;
552 (* ---------------------------------------------------------------------- *)
557 ignore(Parse_c.parse_cpp_define_file "standard.h")
561 Format.print_newline();
562 Format.printf "@[<v 5>--@,--@,@[<v 5>--@,--@,@]--@,--@,@]";
563 Format.print_newline();
564 Format.printf "@[<v>(---@[<v>(---@[<v>(---@,)@]@,)@]@,)@]"
569 (*****************************************************************************)
570 (* Main entry for Arg *)
571 (*****************************************************************************)
574 "--tokens-c", " <file>",
575 Common.mk_action_1_arg
test_tokens_c;
576 "--parse-c", " <file or dir>",
577 Common.mk_action_n_arg
test_parse_c;
578 "--parse-h", " <file or dir>",
579 Common.mk_action_n_arg
test_parse_h;
580 "--parse-ch", " <file or dir>",
581 Common.mk_action_n_arg
test_parse_ch;
582 "--parse-i", " <file or dir>",
583 Common.mk_action_n_arg
test_parse_i;
584 "--parse-c++", " <file or dir>",
585 Common.mk_action_n_arg
new_test_parse_gen;
587 "--parse", " <file or dir>",
588 Common.mk_action_n_arg
test_parse;
590 "--show-flow", " <file or file:function>",
591 Common.mk_action_1_arg
(local_test_cfg true);
592 "--control-flow", " <file or file:function>",
593 Common.mk_action_1_arg
(local_test_cfg true);
594 "--control-flow-to-file", " <file or file:function>",
595 Common.mk_action_1_arg
(local_test_cfg false);
596 "--test-cfg-ifdef", " <file>",
597 Common.mk_action_1_arg
test_cfg_ifdef;
598 "--parse-unparse", " <file>",
599 Common.mk_action_1_arg
test_parse_unparse;
600 (* "--parse-and-print-sexp", " <file>",
601 Common.mk_action_1_arg parse_and_print_sexp;*)
602 "--type-c", " <file>",
603 Common.mk_action_1_arg
test_type_c;
604 "--compare-c", " <file1> <file2>",
605 Common.mk_action_2_arg
test_compare_c (* result is in unix code *);
606 "--comment-annotater-c", " <file>",
607 Common.mk_action_1_arg
test_comment_annotater;
609 "--compare-c-hardcoded", " ",
610 Common.mk_action_0_arg
test_compare_c_hardcoded;
612 "--test-attributes", " <file>",
613 Common.mk_action_1_arg
test_attributes;
614 "--test-cpp", " <file>",
615 Common.mk_action_1_arg
test_cpp;
617 "--extract-macros", " <file or dir>",
618 Common.mk_action_1_arg
(extract_macros ~selection
:false) ;
620 "--extract-macros-select", " <file or dir>",
621 Common.mk_action_1_arg
(extract_macros ~selection
:true);
624 "--xxx", " <file1> <>",
625 Common.mk_action_n_arg
test_xxx;