490783d88379b5b1086e7d98c036689a1a563219
[bpt/coccinelle.git] / parsing_c / parsing_hacks.ml
1 (* Yoann Padioleau
2 *
3 * Copyright (C) 2010, University of Copenhagen DIKU and INRIA.
4 * Copyright (C) 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.
9 *
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
16 open Common
17
18 module TH = Token_helpers
19 module TV = Token_views_c
20 module LP = Lexer_parser
21
22 module Stat = Parsing_stat
23
24 open Parser_c
25
26 open TV
27
28 (*****************************************************************************)
29 (* Some debugging functions *)
30 (*****************************************************************************)
31
32 let pr2, pr2_once = Common.mk_pr2_wrappers Flag_parsing_c.verbose_parsing
33
34 let pr2_cpp s =
35 if !Flag_parsing_c.debug_cpp
36 then Common.pr2_once ("CPP-" ^ s)
37
38
39 let msg_gen cond is_known printer s =
40 if cond
41 then
42 if not (!Flag_parsing_c.filter_msg)
43 then printer s
44 else
45 if not (is_known s)
46 then printer s
47
48
49 (* In the following, there are some harcoded names of types or macros
50 * but they are not used by our heuristics! They are just here to
51 * enable to detect false positive by printing only the typedef/macros
52 * that we don't know yet. If we print everything, then we can easily
53 * get lost with too much verbose tracing information. So those
54 * functions "filter" some messages. So our heuristics are still good,
55 * there is no more (or not that much) hardcoded linux stuff.
56 *)
57
58 let is_known_typdef =
59 (fun s ->
60 (match s with
61 | "u_char" | "u_short" | "u_int" | "u_long"
62 | "u8" | "u16" | "u32" | "u64"
63 | "s8" | "s16" | "s32" | "s64"
64 | "__u8" | "__u16" | "__u32" | "__u64"
65 -> true
66
67 | "acpi_handle"
68 | "acpi_status"
69 -> true
70
71 | "FILE"
72 | "DIR"
73 -> true
74
75 | s when s =~ ".*_t$" -> true
76 | _ -> false
77 )
78 )
79
80 (* note: cant use partial application with let msg_typedef =
81 * because it would compute msg_typedef at compile time when
82 * the flag debug_typedef is always false
83 *)
84 let msg_typedef s =
85 incr Stat.nTypedefInfer;
86 msg_gen (!Flag_parsing_c.debug_typedef)
87 is_known_typdef
88 (fun s ->
89 pr2_cpp ("TYPEDEF: promoting: " ^ s)
90 )
91 s
92
93 let msg_maybe_dangereous_typedef s =
94 if not (is_known_typdef s)
95 then
96 pr2
97 ("PB MAYBE: dangerous typedef inference, maybe not a typedef: " ^ s)
98
99
100
101 let msg_declare_macro s =
102 incr Stat.nMacroDecl;
103 msg_gen (!Flag_parsing_c.debug_cpp)
104 (fun s ->
105 (match s with
106 | "DECLARE_MUTEX" | "DECLARE_COMPLETION" | "DECLARE_RWSEM"
107 | "DECLARE_WAITQUEUE" | "DECLARE_WAIT_QUEUE_HEAD"
108 | "DEFINE_SPINLOCK" | "DEFINE_TIMER"
109 | "DEVICE_ATTR" | "CLASS_DEVICE_ATTR" | "DRIVER_ATTR"
110 | "SENSOR_DEVICE_ATTR"
111 | "LIST_HEAD"
112 | "DECLARE_WORK" | "DECLARE_TASKLET"
113 | "PORT_ATTR_RO" | "PORT_PMA_ATTR"
114 | "DECLARE_BITMAP"
115
116 -> true
117 (*
118 | s when s =~ "^DECLARE_.*" -> true
119 | s when s =~ ".*_ATTR$" -> true
120 | s when s =~ "^DEFINE_.*" -> true
121 *)
122
123 | _ -> false
124 )
125 )
126 (fun s -> pr2_cpp ("MACRO: found declare-macro: " ^ s))
127 s
128
129
130 let msg_foreach s =
131 incr Stat.nIteratorHeuristic;
132 pr2_cpp ("MACRO: found foreach: " ^ s)
133
134
135 (* ??
136 let msg_debug_macro s =
137 pr2_cpp ("MACRO: found debug-macro: " ^ s)
138 *)
139
140
141 let msg_macro_noptvirg s =
142 incr Stat.nMacroStmt;
143 pr2_cpp ("MACRO: found macro with param noptvirg: " ^ s)
144
145 let msg_macro_toplevel_noptvirg s =
146 incr Stat.nMacroStmt;
147 pr2_cpp ("MACRO: found toplevel macro noptvirg: " ^ s)
148
149 let msg_macro_noptvirg_single s =
150 incr Stat.nMacroStmt;
151 pr2_cpp ("MACRO: found single-macro noptvirg: " ^ s)
152
153
154
155
156 let msg_macro_higher_order s =
157 incr Stat.nMacroHigherOrder;
158 msg_gen (!Flag_parsing_c.debug_cpp)
159 (fun s ->
160 (match s with
161 | "DBGINFO"
162 | "DBGPX"
163 | "DFLOW"
164 -> true
165 | _ -> false
166 )
167 )
168 (fun s -> pr2_cpp ("MACRO: found higher ordre macro : " ^ s))
169 s
170
171
172 let msg_stringification s =
173 incr Stat.nMacroString;
174 msg_gen (!Flag_parsing_c.debug_cpp)
175 (fun s ->
176 (match s with
177 | "REVISION"
178 | "UTS_RELEASE"
179 | "SIZE_STR"
180 | "DMA_STR"
181 -> true
182 (* s when s =~ ".*STR.*" -> true *)
183 | _ -> false
184 )
185 )
186 (fun s -> pr2_cpp ("MACRO: found string-macro " ^ s))
187 s
188
189 let msg_stringification_params s =
190 incr Stat.nMacroString;
191 pr2_cpp ("MACRO: string-macro with params : " ^ s)
192
193
194
195 let msg_apply_known_macro s =
196 incr Stat.nMacroExpand;
197 pr2_cpp ("MACRO: found known macro = " ^ s)
198
199 let msg_apply_known_macro_hint s =
200 incr Stat.nMacroHint;
201 pr2_cpp ("MACRO: found known macro hint = " ^ s)
202
203
204
205
206 let msg_ifdef_bool_passing is_ifdef_positif =
207 incr Stat.nIfdefZero; (* of Version ? *)
208 if is_ifdef_positif
209 then pr2_cpp "commenting parts of a #if 1 or #if LINUX_VERSION"
210 else pr2_cpp "commenting a #if 0 or #if LINUX_VERSION or __cplusplus"
211
212
213 let msg_ifdef_mid_something () =
214 incr Stat.nIfdefExprPassing;
215 pr2_cpp "found ifdef-mid-something"
216
217 let msg_ifdef_funheaders () =
218 incr Stat.nIfdefFunheader;
219 ()
220
221 let msg_ifdef_cparen_else () =
222 incr Stat.nIfdefPassing;
223 pr2_cpp("found ifdef-cparen-else")
224
225
226 let msg_attribute s =
227 incr Stat.nMacroAttribute;
228 pr2_cpp("ATTR:" ^ s)
229
230
231
232 (*****************************************************************************)
233 (* The regexp and basic view definitions *)
234 (*****************************************************************************)
235
236 (* opti: better to built then once and for all, especially regexp_foreach *)
237
238 let regexp_macro = Str.regexp
239 "^[A-Z_][A-Z_0-9]*$"
240
241 (* linuxext: *)
242 let regexp_annot = Str.regexp
243 "^__.*$"
244
245 (* linuxext: *)
246 let regexp_declare = Str.regexp
247 ".*DECLARE.*"
248
249 (* linuxext: *)
250 let regexp_foreach = Str.regexp_case_fold
251 ".*\\(for_?each\\|for_?all\\|iterate\\|loop\\|walk\\|scan\\|each\\|for\\)"
252
253 let regexp_typedef = Str.regexp
254 ".*_t$"
255
256 let false_typedef = [
257 "printk";
258 ]
259
260
261 let ok_typedef s = not (List.mem s false_typedef)
262
263 let not_annot s =
264 not (s ==~ regexp_annot)
265
266
267
268
269 (*****************************************************************************)
270 (* Helpers *)
271 (*****************************************************************************)
272
273 (* ------------------------------------------------------------------------- *)
274 (* the pair is the status of '()' and '{}', ex: (-1,0)
275 * if too much ')' and good '{}'
276 * could do for [] too ?
277 * could do for ',' if encounter ',' at "toplevel", not inside () or {}
278 * then if have ifdef, then certainly can lead to a problem.
279 *)
280 let (count_open_close_stuff_ifdef_clause: TV.ifdef_grouped list -> (int * int))=
281 fun xs ->
282 let cnt_paren, cnt_brace = ref 0, ref 0 in
283 xs +> TV.iter_token_ifdef (fun x ->
284 (match x.tok with
285 | x when TH.is_opar x -> incr cnt_paren
286 | TOBrace _ -> incr cnt_brace
287 | x when TH.is_cpar x -> decr cnt_paren
288 | TCBrace _ -> decr cnt_brace
289 | _ -> ()
290 )
291 );
292 !cnt_paren, !cnt_brace
293
294
295 (* ------------------------------------------------------------------------- *)
296 let forLOOKAHEAD = 30
297
298
299 (* look if there is a '{' just after the closing ')', and handling the
300 * possibility to have nested expressions inside nested parenthesis
301 *
302 * todo: use indentation instead of premier(statement) ?
303 *)
304 let rec is_really_foreach xs =
305 let rec is_foreach_aux = function
306 | [] -> false, []
307 | TCPar _::TOBrace _::xs -> true, xs
308 (* the following attempts to handle the cases where there is a
309 single statement in the body of the loop. undoubtedly more
310 cases are needed.
311 todo: premier(statement) - suivant(funcall)
312 *)
313 | TCPar _::TIdent _::xs -> true, xs
314 | TCPar _::Tif _::xs -> true, xs
315 | TCPar _::Twhile _::xs -> true, xs
316 | TCPar _::Tfor _::xs -> true, xs
317 | TCPar _::Tswitch _::xs -> true, xs
318 | TCPar _::Treturn _::xs -> true, xs
319
320
321 | TCPar _::xs -> false, xs
322 | TOPar _::xs ->
323 let (_, xs') = is_foreach_aux xs in
324 is_foreach_aux xs'
325 | x::xs -> is_foreach_aux xs
326 in
327 is_foreach_aux xs +> fst
328
329
330 (* ------------------------------------------------------------------------- *)
331 let set_ifdef_token_parenthize_info cnt x =
332 match x with
333 | TIfdef (tag, _)
334 | TIfdefelse (tag, _)
335 | TIfdefelif (tag, _)
336 | TEndif (tag, _)
337
338 | TIfdefBool (_, tag, _)
339 | TIfdefMisc (_, tag, _)
340 | TIfdefVersion (_, tag, _)
341 ->
342 tag := Some cnt;
343
344 | _ -> raise Impossible
345
346
347
348 let ifdef_paren_cnt = ref 0
349
350
351 let rec set_ifdef_parenthize_info xs =
352 xs +> List.iter (function
353 | NotIfdefLine xs -> ()
354 | Ifdefbool (_, xxs, info_ifdef)
355 | Ifdef (xxs, info_ifdef) ->
356
357 incr ifdef_paren_cnt;
358 let total_directives = List.length info_ifdef in
359
360 info_ifdef +> List.iter (fun x ->
361 set_ifdef_token_parenthize_info (!ifdef_paren_cnt, total_directives)
362 x.tok);
363 xxs +> List.iter set_ifdef_parenthize_info
364 )
365
366
367 (*****************************************************************************)
368 (* The parsing hack for #define *)
369 (*****************************************************************************)
370
371 (* To parse macro definitions I need to do some tricks
372 * as some information can be get only at the lexing level. For instance
373 * the space after the name of the macro in '#define foo (x)' is meaningful
374 * but the grammar can not get this information. So define_ident below
375 * look at such space and generate a special TOpardefine. In a similar
376 * way macro definitions can contain some antislash and newlines
377 * and the grammar need to know where the macro ends (which is
378 * a line-level and so low token-level information). Hence the
379 * function 'define_line' below and the TDefEol.
380 *
381 * update: TDefEol is handled in a special way at different places,
382 * a little bit like EOF, especially for error recovery, so this
383 * is an important token that should not be retagged!
384 *
385 *
386 * ugly hack, a better solution perhaps would be to erase TDefEOL
387 * from the Ast and list of tokens in parse_c.
388 *
389 * note: I do a +1 somewhere, it's for the unparsing to correctly sync.
390 *
391 * note: can't replace mark_end_define by simply a fakeInfo(). The reason
392 * is where is the \n TCommentSpace. Normally there is always a last token
393 * to synchronize on, either EOF or the token of the next toplevel.
394 * In the case of the #define we got in list of token
395 * [TCommentSpace "\n"; TDefEOL] but if TDefEOL is a fakeinfo then we will
396 * not synchronize on it and so we will not print the "\n".
397 * A solution would be to put the TDefEOL before the "\n".
398 *
399 * todo?: could put a ExpandedTok for that ?
400 *)
401 let mark_end_define ii =
402 let ii' =
403 { Ast_c.pinfo = Ast_c.OriginTok { (Ast_c.parse_info_of_info ii) with
404 Common.str = "";
405 Common.charpos = Ast_c.pos_of_info ii + 1
406 };
407 cocci_tag = ref Ast_c.emptyAnnot;
408 comments_tag = ref Ast_c.emptyComments;
409 }
410 in
411 TDefEOL (ii')
412
413 (* put the TDefEOL at the good place *)
414 let rec define_line_1 acc xs =
415 match xs with
416 | [] -> List.rev acc
417 | TDefine ii::xs ->
418 let line = Ast_c.line_of_info ii in
419 let acc = (TDefine ii) :: acc in
420 define_line_2 acc line ii xs
421 | TCppEscapedNewline ii::xs ->
422 pr2 ("SUSPICIOUS: a \\ character appears outside of a #define at");
423 pr2 (Ast_c.strloc_of_info ii);
424 let acc = (TCommentSpace ii) :: acc in
425 define_line_1 acc xs
426 | x::xs -> define_line_1 (x::acc) xs
427
428 and define_line_2 acc line lastinfo xs =
429 match xs with
430 | [] ->
431 (* should not happened, should meet EOF before *)
432 pr2 "PB: WEIRD";
433 List.rev (mark_end_define lastinfo::acc)
434 | x::xs ->
435 let line' = TH.line_of_tok x in
436 let info = TH.info_of_tok x in
437
438 (match x with
439 | EOF ii ->
440 let acc = (mark_end_define lastinfo) :: acc in
441 let acc = (EOF ii) :: acc in
442 define_line_1 acc xs
443 | TCppEscapedNewline ii ->
444 if (line' <> line) then pr2 "PB: WEIRD: not same line number";
445 let acc = (TCommentSpace ii) :: acc in
446 define_line_2 acc (line+1) info xs
447 | x ->
448 if line' =|= line
449 then define_line_2 (x::acc) line info xs
450 else define_line_1 (mark_end_define lastinfo::acc) (x::xs)
451 )
452
453 let rec define_ident acc xs =
454 match xs with
455 | [] -> List.rev acc
456 | TDefine ii::xs ->
457 let acc = TDefine ii :: acc in
458 (match xs with
459 | TCommentSpace i1::TIdent (s,i2)::TOPar (i3)::xs ->
460 (* Change also the kind of TIdent to avoid bad interaction
461 * with other parsing_hack tricks. For instant if keep TIdent then
462 * the stringication algo can believe the TIdent is a string-macro.
463 * So simpler to change the kind of the ident too.
464 *)
465 (* if TOParDefine sticked to the ident, then
466 * it's a macro-function. Change token to avoid ambiguity
467 * between #define foo(x) and #define foo (x)
468 *)
469 let acc = (TCommentSpace i1) :: acc in
470 let acc = (TIdentDefine (s,i2)) :: acc in
471 let acc = (TOParDefine i3) :: acc in
472 define_ident acc xs
473
474 | TCommentSpace i1::TIdent (s,i2)::xs ->
475 let acc = (TCommentSpace i1) :: acc in
476 let acc = (TIdentDefine (s,i2)) :: acc in
477 define_ident acc xs
478
479 (* bugfix: ident of macro (as well as params, cf below) can be tricky
480 * note, do we need to subst in the body of the define ? no cos
481 * here the issue is the name of the macro, as in #define inline,
482 * so obviously the name of this macro will not be used in its
483 * body (it would be a recursive macro, which is forbidden).
484 *)
485
486 | TCommentSpace i1::t::xs ->
487
488 let s = TH.str_of_tok t in
489 let ii = TH.info_of_tok t in
490 if s ==~ Common.regexp_alpha
491 then begin
492 pr2 (spf "remapping: %s to an ident in macro name" s);
493 let acc = (TCommentSpace i1) :: acc in
494 let acc = (TIdentDefine (s,ii)) :: acc in
495 define_ident acc xs
496 end
497 else begin
498 pr2 "WEIRD: weird #define body";
499 define_ident acc xs
500 end
501
502 | _ ->
503 pr2 "WEIRD: weird #define body";
504 define_ident acc xs
505 )
506 | x::xs ->
507 let acc = x :: acc in
508 define_ident acc xs
509
510
511
512 let fix_tokens_define2 xs =
513 define_ident [] (define_line_1 [] xs)
514
515 let fix_tokens_define a =
516 Common.profile_code "C parsing.fix_define" (fun () -> fix_tokens_define2 a)
517
518
519
520
521
522 (* ------------------------------------------------------------------------- *)
523 (* Other parsing hacks related to cpp, Include/Define hacks *)
524 (* ------------------------------------------------------------------------- *)
525
526 (* Sometimes I prefer to generate a single token for a list of things in the
527 * lexer so that if I have to passed them, like for passing TInclude then
528 * it's easy. Also if I don't do a single token, then I need to
529 * parse the rest which may not need special stuff, like detecting
530 * end of line which the parser is not really ready for. So for instance
531 * could I parse a #include <a/b/c/xxx.h> as 2 or more tokens ? just
532 * lex #include ? so then need recognize <a/b/c/xxx.h> as one token ?
533 * but this kind of token is valid only after a #include and the
534 * lexing and parsing rules are different for such tokens so not that
535 * easy to parse such things in parser_c.mly. Hence the following hacks.
536 *
537 * less?: maybe could get rid of this like I get rid of some of fix_define.
538 *)
539
540 (* helpers *)
541
542 (* used to generate new token from existing one *)
543 let new_info posadd str ii =
544 { Ast_c.pinfo =
545 Ast_c.OriginTok { (Ast_c.parse_info_of_info ii) with
546 charpos = Ast_c.pos_of_info ii + posadd;
547 str = str;
548 column = Ast_c.col_of_info ii + posadd;
549 };
550 (* must generate a new ref each time, otherwise share *)
551 cocci_tag = ref Ast_c.emptyAnnot;
552 comments_tag = ref Ast_c.emptyComments;
553 }
554
555
556 let rec comment_until_defeol xs =
557 match xs with
558 | [] ->
559 (* job not done in Cpp_token_c.define_parse ? *)
560 failwith "cant find end of define token TDefEOL"
561 | x::xs ->
562 (match x with
563 | Parser_c.TDefEOL i ->
564 Parser_c.TCommentCpp (Token_c.CppDirective, TH.info_of_tok x)
565 ::xs
566 | _ ->
567 let x' =
568 (* bugfix: otherwise may lose a TComment token *)
569 if TH.is_real_comment x
570 then x
571 else Parser_c.TCommentCpp (Token_c.CppPassingNormal (*good?*), TH.info_of_tok x)
572 in
573 x'::comment_until_defeol xs
574 )
575
576 let drop_until_defeol xs =
577 List.tl
578 (Common.drop_until (function Parser_c.TDefEOL _ -> true | _ -> false) xs)
579
580
581
582 (* ------------------------------------------------------------------------- *)
583 (* returns a pair (replaced token, list of next tokens) *)
584 (* ------------------------------------------------------------------------- *)
585
586 let tokens_include (info, includes, filename, inifdef) =
587 Parser_c.TIncludeStart (Ast_c.rewrap_str includes info, inifdef),
588 [Parser_c.TIncludeFilename
589 (filename, (new_info (String.length includes) filename info))
590 ]
591
592
593
594
595 (*****************************************************************************)
596 (* CPP handling: macros, ifdefs, macros defs *)
597 (*****************************************************************************)
598
599 (* ------------------------------------------------------------------------- *)
600 (* special skip_start skip_end handling *)
601 (* ------------------------------------------------------------------------- *)
602
603 (* note: after this normally the token list should not contain any more the
604 * TCommentSkipTagStart and End tokens.
605 *)
606 let rec commentize_skip_start_to_end xs =
607 match xs with
608 | [] -> ()
609 | x::xs ->
610 (match x with
611 | {tok = TCommentSkipTagStart info} ->
612 (try
613 let (before, x2, after) =
614 xs +> Common.split_when (function
615 | {tok = TCommentSkipTagEnd _ } -> true
616 | _ -> false
617 )
618 in
619 let topass = x::x2::before in
620 topass +> List.iter (fun tok ->
621 set_as_comment Token_c.CppPassingExplicit tok
622 );
623 commentize_skip_start_to_end after
624 with Not_found ->
625 failwith "could not find end of skip_start special comment"
626 )
627 | {tok = TCommentSkipTagEnd info} ->
628 failwith "found skip_end comment but no skip_start"
629 | _ ->
630 commentize_skip_start_to_end xs
631 )
632
633
634
635
636 (* ------------------------------------------------------------------------- *)
637 (* ifdef keeping/passing *)
638 (* ------------------------------------------------------------------------- *)
639
640 (* #if 0, #if 1, #if LINUX_VERSION handling *)
641 let rec find_ifdef_bool xs =
642 xs +> List.iter (function
643 | NotIfdefLine _ -> ()
644 | Ifdefbool (is_ifdef_positif, xxs, info_ifdef_stmt) ->
645
646 msg_ifdef_bool_passing is_ifdef_positif;
647
648 (match xxs with
649 | [] -> raise Impossible
650 | firstclause::xxs ->
651 info_ifdef_stmt +> List.iter (set_as_comment Token_c.CppDirective);
652
653 if is_ifdef_positif
654 then xxs +> List.iter
655 (iter_token_ifdef (set_as_comment Token_c.CppPassingNormal))
656 else begin
657 firstclause +> iter_token_ifdef (set_as_comment Token_c.CppPassingNormal);
658 (match List.rev xxs with
659 (* keep only last *)
660 | last::startxs ->
661 startxs +> List.iter
662 (iter_token_ifdef (set_as_comment Token_c.CppPassingNormal))
663 | [] -> (* not #else *) ()
664 );
665 end
666 );
667
668 | Ifdef (xxs, info_ifdef_stmt) -> xxs +> List.iter find_ifdef_bool
669 )
670
671
672
673 let thresholdIfdefSizeMid = 6
674
675 (* infer ifdef involving not-closed expressions/statements *)
676 let rec find_ifdef_mid xs =
677 xs +> List.iter (function
678 | NotIfdefLine _ -> ()
679 | Ifdef (xxs, info_ifdef_stmt) ->
680 (match xxs with
681 | [] -> raise Impossible
682 | [first] -> ()
683 | first::second::rest ->
684 (* don't analyse big ifdef *)
685 if xxs +> List.for_all
686 (fun xs -> List.length xs <= thresholdIfdefSizeMid) &&
687 (* don't want nested ifdef *)
688 xxs +> List.for_all (fun xs ->
689 xs +> List.for_all
690 (function NotIfdefLine _ -> true | _ -> false)
691 )
692
693 then
694 let counts = xxs +> List.map count_open_close_stuff_ifdef_clause in
695 let cnt1, cnt2 = List.hd counts in
696 if cnt1 <> 0 || cnt2 <> 0 &&
697 counts +> List.for_all (fun x -> x =*= (cnt1, cnt2))
698 (*
699 if counts +> List.exists (fun (cnt1, cnt2) ->
700 cnt1 <> 0 || cnt2 <> 0
701 )
702 *)
703 then begin
704 msg_ifdef_mid_something();
705
706 (* keep only first, treat the rest as comment *)
707 info_ifdef_stmt +> List.iter (set_as_comment Token_c.CppDirective);
708 (second::rest) +> List.iter
709 (iter_token_ifdef (set_as_comment Token_c.CppPassingCosWouldGetError));
710 end
711
712 );
713 List.iter find_ifdef_mid xxs
714
715 (* no need complex analysis for ifdefbool *)
716 | Ifdefbool (_, xxs, info_ifdef_stmt) ->
717 List.iter find_ifdef_mid xxs
718
719
720 )
721
722
723 let thresholdFunheaderLimit = 4
724
725 (* ifdef defining alternate function header, type *)
726 let rec find_ifdef_funheaders = function
727 | [] -> ()
728 | NotIfdefLine _::xs -> find_ifdef_funheaders xs
729
730 (* ifdef-funheader if ifdef with 2 lines and a '{' in next line *)
731 | Ifdef
732 ([(NotIfdefLine (({col = 0} as _xline1)::line1))::ifdefblock1;
733 (NotIfdefLine (({col = 0} as xline2)::line2))::ifdefblock2
734 ], info_ifdef_stmt
735 )
736 ::NotIfdefLine (({tok = TOBrace i; col = 0})::line3)
737 ::xs
738 when List.length ifdefblock1 <= thresholdFunheaderLimit &&
739 List.length ifdefblock2 <= thresholdFunheaderLimit
740 ->
741 find_ifdef_funheaders xs;
742
743 msg_ifdef_funheaders ();
744 info_ifdef_stmt +> List.iter (set_as_comment Token_c.CppDirective);
745 let all_toks = [xline2] @ line2 in
746 all_toks +> List.iter (set_as_comment Token_c.CppPassingCosWouldGetError) ;
747 ifdefblock2 +> iter_token_ifdef (set_as_comment Token_c.CppPassingCosWouldGetError);
748
749 (* ifdef with nested ifdef *)
750 | Ifdef
751 ([[NotIfdefLine (({col = 0} as _xline1)::line1)];
752 [Ifdef
753 ([[NotIfdefLine (({col = 0} as xline2)::line2)];
754 [NotIfdefLine (({col = 0} as xline3)::line3)];
755 ], info_ifdef_stmt2
756 )
757 ]
758 ], info_ifdef_stmt
759 )
760 ::NotIfdefLine (({tok = TOBrace i; col = 0})::line4)
761 ::xs
762 ->
763 find_ifdef_funheaders xs;
764
765 msg_ifdef_funheaders ();
766 info_ifdef_stmt +> List.iter (set_as_comment Token_c.CppDirective);
767 info_ifdef_stmt2 +> List.iter (set_as_comment Token_c.CppDirective);
768 let all_toks = [xline2;xline3] @ line2 @ line3 in
769 all_toks +> List.iter (set_as_comment Token_c.CppPassingCosWouldGetError);
770
771 (* ifdef with elseif *)
772 | Ifdef
773 ([[NotIfdefLine (({col = 0} as _xline1)::line1)];
774 [NotIfdefLine (({col = 0} as xline2)::line2)];
775 [NotIfdefLine (({col = 0} as xline3)::line3)];
776 ], info_ifdef_stmt
777 )
778 ::NotIfdefLine (({tok = TOBrace i; col = 0})::line4)
779 ::xs
780 ->
781 find_ifdef_funheaders xs;
782
783 msg_ifdef_funheaders ();
784 info_ifdef_stmt +> List.iter (set_as_comment Token_c.CppDirective);
785 let all_toks = [xline2;xline3] @ line2 @ line3 in
786 all_toks +> List.iter (set_as_comment Token_c.CppPassingCosWouldGetError)
787
788 (* recurse *)
789 | Ifdef (xxs,info_ifdef_stmt)::xs
790 | Ifdefbool (_, xxs,info_ifdef_stmt)::xs ->
791 List.iter find_ifdef_funheaders xxs;
792 find_ifdef_funheaders xs
793
794
795
796 (* ?? *)
797 let rec adjust_inifdef_include xs =
798 xs +> List.iter (function
799 | NotIfdefLine _ -> ()
800 | Ifdef (xxs, info_ifdef_stmt) | Ifdefbool (_, xxs, info_ifdef_stmt) ->
801 xxs +> List.iter (iter_token_ifdef (fun tokext ->
802 match tokext.tok with
803 | Parser_c.TInclude (s1, s2, inifdef_ref, ii) ->
804 inifdef_ref := true;
805 | _ -> ()
806 ));
807 )
808
809
810
811
812
813
814
815 let rec find_ifdef_cparen_else xs =
816 let rec aux xs =
817 xs +> List.iter (function
818 | NotIfdefLine _ -> ()
819 | Ifdef (xxs, info_ifdef_stmt) ->
820 (match xxs with
821 | [] -> raise Impossible
822 | [first] -> ()
823 | first::second::rest ->
824
825 (* found a closing ')' just after the #else *)
826
827 (* Too bad ocaml does not support better list pattern matching
828 * a la Prolog-III where can match the end of lists.
829 *)
830 let condition =
831 if List.length first = 0 then false
832 else
833 let last_line = Common.last first in
834 match last_line with
835 | NotIfdefLine xs ->
836 if List.length xs = 0 then false
837 else
838 let last_tok = Common.last xs in
839 TH.is_cpar last_tok.tok
840 | Ifdef _ | Ifdefbool _ -> false
841 in
842 if condition then begin
843 msg_ifdef_cparen_else();
844
845 (* keep only first, treat the rest as comment *)
846 info_ifdef_stmt +> List.iter (set_as_comment Token_c.CppDirective);
847 (second::rest) +> List.iter
848 (iter_token_ifdef (set_as_comment Token_c.CppPassingCosWouldGetError));
849 end
850
851 );
852 List.iter aux xxs
853
854 (* no need complex analysis for ifdefbool *)
855 | Ifdefbool (_, xxs, info_ifdef_stmt) ->
856 List.iter aux xxs
857 )
858 in aux xs
859
860
861 (* ------------------------------------------------------------------------- *)
862 (* cpp-builtin part2, macro, using standard.h or other defs *)
863 (* ------------------------------------------------------------------------- *)
864
865 (* now in cpp_token_c.ml *)
866
867 (* ------------------------------------------------------------------------- *)
868 (* stringification *)
869 (* ------------------------------------------------------------------------- *)
870
871 let rec find_string_macro_paren xs =
872 match xs with
873 | [] -> ()
874 | Parenthised(xxs, info_parens)::xs ->
875 xxs +> List.iter (fun xs ->
876 if xs +> List.exists
877 (function PToken({tok = (TString _| TMacroString _)}) -> true | _ -> false) &&
878 xs +> List.for_all
879 (function PToken({tok = (TString _| TMacroString _)}) | PToken({tok = TIdent _}) ->
880 true | _ -> false)
881 then
882 xs +> List.iter (fun tok ->
883 match tok with
884 | PToken({tok = TIdent (s,_)} as id) ->
885 msg_stringification s;
886 id.tok <- TMacroString (s, TH.info_of_tok id.tok);
887 | _ -> ()
888 )
889 else
890 find_string_macro_paren xs
891 );
892 find_string_macro_paren xs
893 | PToken(tok)::xs ->
894 find_string_macro_paren xs
895
896
897 (* ------------------------------------------------------------------------- *)
898 (* macro2 *)
899 (* ------------------------------------------------------------------------- *)
900
901 (* don't forget to recurse in each case *)
902 let rec find_macro_paren xs =
903 match xs with
904 | [] -> ()
905
906 (* attribute *)
907 | PToken ({tok = Tattribute _} as id)
908 ::Parenthised (xxs,info_parens)
909 ::xs
910 ->
911 pr2_cpp ("MACRO: __attribute detected ");
912 [Parenthised (xxs, info_parens)] +>
913 iter_token_paren (set_as_comment Token_c.CppAttr);
914 set_as_comment Token_c.CppAttr id;
915 find_macro_paren xs
916
917 | PToken ({tok = TattributeNoarg _} as id)
918 ::xs
919 ->
920 pr2_cpp ("MACRO: __attributenoarg detected ");
921 set_as_comment Token_c.CppAttr id;
922 find_macro_paren xs
923
924 (*
925 (* attribute cpp, __xxx id *)
926 | PToken ({tok = TIdent (s,i1)} as id)
927 ::PToken ({tok = TIdent (s2, i2)} as id2)
928 ::xs when s ==~ regexp_annot
929 ->
930 msg_attribute s;
931 id.tok <- TMacroAttr (s, i1);
932 find_macro_paren ((PToken id2)::xs); (* recurse also on id2 ? *)
933
934 (* attribute cpp, id __xxx *)
935 | PToken ({tok = TIdent (s,i1)} as _id)
936 ::PToken ({tok = TIdent (s2, i2)} as id2)
937 ::xs when s2 ==~ regexp_annot && (not (s ==~ regexp_typedef))
938 ->
939 msg_attribute s2;
940 id2.tok <- TMacroAttr (s2, i2);
941 find_macro_paren xs
942
943 | PToken ({tok = (Tstatic _ | Textern _)} as tok1)
944 ::PToken ({tok = TIdent (s,i1)} as attr)
945 ::xs when s ==~ regexp_annot
946 ->
947 pr2_cpp ("storage attribute: " ^ s);
948 attr.tok <- TMacroAttrStorage (s,i1);
949 (* recurse, may have other storage attributes *)
950 find_macro_paren (PToken (tok1)::xs)
951
952
953 *)
954
955 (* storage attribute *)
956 | PToken ({tok = (Tstatic _ | Textern _)} as tok1)
957 ::PToken ({tok = TMacroAttr (s,i1)} as attr)::xs
958 ->
959 pr2_cpp ("storage attribute: " ^ s);
960 attr.tok <- TMacroAttrStorage (s,i1);
961 (* recurse, may have other storage attributes *)
962 find_macro_paren (PToken (tok1)::xs)
963
964
965 (* stringification
966 *
967 * the order of the matching clause is important
968 *
969 *)
970
971 (* string macro with params, before case *)
972 | PToken ({tok = (TString _| TMacroString _)})::PToken ({tok = TIdent (s,_)} as id)
973 ::Parenthised (xxs, info_parens)
974 ::xs ->
975
976 msg_stringification_params s;
977 id.tok <- TMacroString (s, TH.info_of_tok id.tok);
978 [Parenthised (xxs, info_parens)] +>
979 iter_token_paren (set_as_comment Token_c.CppMacro);
980 find_macro_paren xs
981
982 (* after case *)
983 | PToken ({tok = TIdent (s,_)} as id)
984 ::Parenthised (xxs, info_parens)
985 ::PToken ({tok = (TString _ | TMacroString _)})
986 ::xs ->
987
988 msg_stringification_params s;
989 id.tok <- TMacroString (s, TH.info_of_tok id.tok);
990 [Parenthised (xxs, info_parens)] +>
991 iter_token_paren (set_as_comment Token_c.CppMacro);
992 find_macro_paren xs
993
994
995 (* for the case where the string is not inside a funcall, but
996 * for instance in an initializer.
997 *)
998
999 (* string macro variable, before case *)
1000 | PToken ({tok = (TString _ | TMacroString _)})::PToken ({tok = TIdent (s,_)} as id)
1001 ::xs ->
1002
1003 msg_stringification s;
1004 id.tok <- TMacroString (s, TH.info_of_tok id.tok);
1005 find_macro_paren xs
1006
1007 (* after case *)
1008 | PToken ({tok = TIdent (s,_)} as id)
1009 ::PToken ({tok = (TString _ | TMacroString _)})
1010 ::xs ->
1011
1012 msg_stringification s;
1013 id.tok <- TMacroString (s, TH.info_of_tok id.tok);
1014 find_macro_paren xs
1015
1016
1017
1018
1019
1020 (* recurse *)
1021 | (PToken x)::xs -> find_macro_paren xs
1022 | (Parenthised (xxs, info_parens))::xs ->
1023 xxs +> List.iter find_macro_paren;
1024 find_macro_paren xs
1025
1026
1027
1028
1029
1030 (* don't forget to recurse in each case *)
1031 let rec find_macro_lineparen xs =
1032 match xs with
1033 | [] -> ()
1034
1035 (* linuxext: ex: static [const] DEVICE_ATTR(); *)
1036 | (Line
1037 (
1038 [PToken ({tok = Tstatic _});
1039 PToken ({tok = TIdent (s,_)} as macro);
1040 Parenthised (xxs,info_parens);
1041 PToken ({tok = TPtVirg _});
1042 ]
1043 ))
1044 ::xs
1045 when (s ==~ regexp_macro) ->
1046
1047 msg_declare_macro s;
1048 let info = TH.info_of_tok macro.tok in
1049 macro.tok <- TMacroDecl (Ast_c.str_of_info info, info);
1050
1051 find_macro_lineparen (xs)
1052
1053 (* the static const case *)
1054 | (Line
1055 (
1056 [PToken ({tok = Tstatic _});
1057 PToken ({tok = Tconst _} as const);
1058 PToken ({tok = TIdent (s,_)} as macro);
1059 Parenthised (xxs,info_parens);
1060 PToken ({tok = TPtVirg _});
1061 ]
1062 (*as line1*)
1063
1064 ))
1065 ::xs
1066 when (s ==~ regexp_macro) ->
1067
1068 msg_declare_macro s;
1069 let info = TH.info_of_tok macro.tok in
1070 macro.tok <- TMacroDecl (Ast_c.str_of_info info, info);
1071
1072 (* need retag this const, otherwise ambiguity in grammar
1073 21: shift/reduce conflict (shift 121, reduce 137) on Tconst
1074 decl2 : Tstatic . TMacroDecl TOPar argument_list TCPar ...
1075 decl2 : Tstatic . Tconst TMacroDecl TOPar argument_list TCPar ...
1076 storage_class_spec : Tstatic . (137)
1077 *)
1078 const.tok <- TMacroDeclConst (TH.info_of_tok const.tok);
1079
1080 find_macro_lineparen (xs)
1081
1082
1083 (* same but without trailing ';'
1084 *
1085 * I do not put the final ';' because it can be on a multiline and
1086 * because of the way mk_line is coded, we will not have access to
1087 * this ';' on the next line, even if next to the ')' *)
1088 | (Line
1089 ([PToken ({tok = Tstatic _});
1090 PToken ({tok = TIdent (s,_)} as macro);
1091 Parenthised (xxs,info_parens);
1092 ]
1093 ))
1094 ::xs
1095 when s ==~ regexp_macro ->
1096
1097 msg_declare_macro s;
1098 let info = TH.info_of_tok macro.tok in
1099 macro.tok <- TMacroDecl (Ast_c.str_of_info info, info);
1100
1101 find_macro_lineparen (xs)
1102
1103
1104
1105
1106 (* on multiple lines *)
1107 | (Line
1108 (
1109 (PToken ({tok = Tstatic _})::[]
1110 )))
1111 ::(Line
1112 (
1113 [PToken ({tok = TIdent (s,_)} as macro);
1114 Parenthised (xxs,info_parens);
1115 PToken ({tok = TPtVirg _});
1116 ]
1117 )
1118 )
1119 ::xs
1120 when (s ==~ regexp_macro) ->
1121
1122 msg_declare_macro s;
1123 let info = TH.info_of_tok macro.tok in
1124 macro.tok <- TMacroDecl (Ast_c.str_of_info info, info);
1125
1126 find_macro_lineparen (xs)
1127
1128
1129 (* linuxext: ex: DECLARE_BITMAP();
1130 *
1131 * Here I use regexp_declare and not regexp_macro because
1132 * Sometimes it can be a FunCallMacro such as DEBUG(foo());
1133 * Here we don't have the preceding 'static' so only way to
1134 * not have positive is to restrict to .*DECLARE.* macros.
1135 *
1136 * but there is a grammar rule for that, so don't need this case anymore
1137 * unless the parameter of the DECLARE_xxx are weird and can not be mapped
1138 * on a argument_list
1139 *)
1140
1141 | (Line
1142 ([PToken ({tok = TIdent (s,_)} as macro);
1143 Parenthised (xxs,info_parens);
1144 PToken ({tok = TPtVirg _});
1145 ]
1146 ))
1147 ::xs
1148 when (s ==~ regexp_declare) ->
1149
1150 msg_declare_macro s;
1151 let info = TH.info_of_tok macro.tok in
1152 macro.tok <- TMacroDecl (Ast_c.str_of_info info, info);
1153
1154 find_macro_lineparen (xs)
1155
1156
1157 (* toplevel macros.
1158 * module_init(xxx)
1159 *
1160 * Could also transform the TIdent in a TMacroTop but can have false
1161 * positive, so easier to just change the TCPar and so just solve
1162 * the end-of-stream pb of ocamlyacc
1163 *)
1164 | (Line
1165 ([PToken ({tok = TIdent (s,ii); col = col1; where = ctx} as _macro);
1166 Parenthised (xxs,info_parens);
1167 ] as _line1
1168 ))
1169 ::xs when col1 =|= 0
1170 ->
1171 let condition =
1172 (* to reduce number of false positive *)
1173 (match xs with
1174 | (Line (PToken ({col = col2 } as other)::restline2))::_ ->
1175 TH.is_eof other.tok || (col2 =|= 0 &&
1176 (match other.tok with
1177 | TOBrace _ -> false (* otherwise would match funcdecl *)
1178 | TCBrace _ when ctx <> InFunction -> false
1179 | TPtVirg _
1180 | TDotDot _
1181 -> false
1182 | tok when TH.is_binary_operator tok -> false
1183
1184 | _ -> true
1185 )
1186 )
1187 | _ -> false
1188 )
1189 in
1190 if condition
1191 then begin
1192
1193 msg_macro_toplevel_noptvirg s;
1194 (* just to avoid the end-of-stream pb of ocamlyacc *)
1195 let tcpar = Common.last info_parens in
1196 tcpar.tok <- TCParEOL (TH.info_of_tok tcpar.tok);
1197
1198 (*macro.tok <- TMacroTop (s, TH.info_of_tok macro.tok);*)
1199
1200 end;
1201
1202 find_macro_lineparen (xs)
1203
1204
1205
1206 (* macro with parameters
1207 * ex: DEBUG()
1208 * return x;
1209 *)
1210 | (Line
1211 ([PToken ({tok = TIdent (s,ii); col = col1; where = ctx} as macro);
1212 Parenthised (xxs,info_parens);
1213 ] as _line1
1214 ))
1215 ::(Line
1216 (PToken ({col = col2 } as other)::restline2
1217 ) as line2)
1218 ::xs
1219 (* when s ==~ regexp_macro *)
1220 ->
1221 let condition =
1222 (col1 =|= col2 &&
1223 (match other.tok with
1224 | TOBrace _ -> false (* otherwise would match funcdecl *)
1225 | TCBrace _ when ctx <> InFunction -> false
1226 | TPtVirg _
1227 | TDotDot _
1228 -> false
1229 | tok when TH.is_binary_operator tok -> false
1230
1231 | _ -> true
1232 )
1233 )
1234 ||
1235 (col2 <= col1 &&
1236 (match other.tok, restline2 with
1237 | TCBrace _, _ when ctx =*= InFunction -> true
1238 | Treturn _, _ -> true
1239 | Tif _, _ -> true
1240 | Telse _, _ -> true
1241
1242 (* case of label, usually put in first line *)
1243 | TIdent _, (PToken ({tok = TDotDot _}))::_ ->
1244 true
1245
1246
1247 | _ -> false
1248 )
1249 )
1250
1251 in
1252
1253 if condition
1254 then
1255 if col1 =|= 0 then ()
1256 else begin
1257 msg_macro_noptvirg s;
1258 macro.tok <- TMacroStmt (s, TH.info_of_tok macro.tok);
1259 [Parenthised (xxs, info_parens)] +>
1260 iter_token_paren (set_as_comment Token_c.CppMacro);
1261 end;
1262
1263 find_macro_lineparen (line2::xs)
1264
1265 (* linuxext:? single macro
1266 * ex: LOCK
1267 * foo();
1268 * UNLOCK
1269 *
1270 * todo: factorize code with previous rule ?
1271 *)
1272 | (Line
1273 ([PToken ({tok = TIdent (s,ii); col = col1; where = ctx} as macro);
1274 ] as _line1
1275 ))
1276 ::(Line
1277 (PToken ({col = col2 } as other)::restline2
1278 ) as line2)
1279 ::xs ->
1280 (* when s ==~ regexp_macro *)
1281
1282 let condition =
1283 (col1 =|= col2 &&
1284 col1 <> 0 && (* otherwise can match typedef of fundecl*)
1285 (match other.tok with
1286 | TPtVirg _ -> false
1287 | TOr _ -> false
1288 | TCBrace _ when ctx <> InFunction -> false
1289 | tok when TH.is_binary_operator tok -> false
1290
1291 | _ -> true
1292 )) ||
1293 (col2 <= col1 &&
1294 (match other.tok with
1295 | TCBrace _ when ctx =*= InFunction -> true
1296 | Treturn _ -> true
1297 | Tif _ -> true
1298 | Telse _ -> true
1299 | _ -> false
1300 ))
1301 in
1302
1303 if condition
1304 then begin
1305 msg_macro_noptvirg_single s;
1306 macro.tok <- TMacroStmt (s, TH.info_of_tok macro.tok);
1307 end;
1308 find_macro_lineparen (line2::xs)
1309
1310 | x::xs ->
1311 find_macro_lineparen xs
1312
1313
1314
1315 (* ------------------------------------------------------------------------- *)
1316 (* define tobrace init *)
1317 (* ------------------------------------------------------------------------- *)
1318
1319 let rec find_define_init_brace_paren xs =
1320 let rec aux xs =
1321 match xs with
1322 | [] -> ()
1323
1324 (* mainly for firefox *)
1325 | (PToken {tok = TDefine _})
1326 ::(PToken {tok = TIdentDefine (s,_)})
1327 ::(PToken ({tok = TOBrace i1} as tokbrace))
1328 ::(PToken tok2)
1329 ::(PToken tok3)
1330 ::xs ->
1331 let is_init =
1332 match tok2.tok, tok3.tok with
1333 | TInt _, TComma _ -> true
1334 | TString _, TComma _ -> true
1335 | TIdent _, TComma _ -> true
1336 | _ -> false
1337
1338 in
1339 if is_init
1340 then begin
1341 pr2_cpp("found define initializer: " ^s);
1342 tokbrace.tok <- TOBraceDefineInit i1;
1343 end;
1344
1345 aux xs
1346
1347 (* mainly for linux, especially in sound/ *)
1348 | (PToken {tok = TDefine _})
1349 ::(PToken {tok = TIdentDefine (s,_)})
1350 ::(Parenthised(xxx, info_parens))
1351 ::(PToken ({tok = TOBrace i1} as tokbrace))
1352 ::(PToken tok2)
1353 ::(PToken tok3)
1354 ::xs ->
1355 let is_init =
1356 match tok2.tok, tok3.tok with
1357 | TInt _, TComma _ -> true
1358 | TDot _, TIdent _ -> true
1359 | TIdent _, TComma _ -> true
1360 | _ -> false
1361
1362 in
1363 if is_init
1364 then begin
1365 pr2_cpp("found define initializer with param: " ^ s);
1366 tokbrace.tok <- TOBraceDefineInit i1;
1367 end;
1368
1369 aux xs
1370
1371
1372
1373 (* recurse *)
1374 | (PToken x)::xs -> aux xs
1375 | (Parenthised (xxs, info_parens))::xs ->
1376 (* not need for tobrace init:
1377 * xxs +> List.iter aux;
1378 *)
1379 aux xs
1380 in
1381 aux xs
1382
1383
1384 (* ------------------------------------------------------------------------- *)
1385 (* action *)
1386 (* ------------------------------------------------------------------------- *)
1387
1388 (* obsolete now with macro expansion ? get some regression if comment.
1389 * todo: if do bad decision here, then it can influence other phases
1390 * and make it hard to parse. So maybe when have a parse error, should
1391 * undo some of the guess those heuristics have done, and restore
1392 * the original token value.
1393 *)
1394
1395 let rec find_actions = function
1396 | [] -> ()
1397
1398 | PToken ({tok = TIdent (s,ii)})
1399 ::Parenthised (xxs,info_parens)
1400 ::xs ->
1401 find_actions xs;
1402 xxs +> List.iter find_actions;
1403 let modified = find_actions_params xxs in
1404 if modified
1405 then msg_macro_higher_order s
1406
1407 | x::xs ->
1408 find_actions xs
1409
1410 and find_actions_params xxs =
1411 xxs +> List.fold_left (fun acc xs ->
1412 let toks = tokens_of_paren xs in
1413 if toks +> List.exists (fun x -> TH.is_statement x.tok)
1414 (* undo: && List.length toks > 1
1415 * good for sparse, not good for linux
1416 *)
1417 then begin
1418 xs +> iter_token_paren (fun x ->
1419 if TH.is_eof x.tok
1420 then
1421 (* certainly because paren detection had a pb because of
1422 * some ifdef-exp. Do similar additional checking than
1423 * what is done in set_as_comment.
1424 *)
1425 pr2 "PB: weird, I try to tag an EOF token as an action"
1426 else
1427 (* cf tests-bis/no_cpar_macro.c *)
1428 if TH.is_eom x.tok
1429 then
1430 pr2 "PB: weird, I try to tag an EOM token as an action"
1431 else
1432 x.tok <- TAction (TH.info_of_tok x.tok);
1433 );
1434 true (* modified *)
1435 end
1436 else acc
1437 ) false
1438
1439
1440
1441 (* ------------------------------------------------------------------------- *)
1442 (* main fix cpp function *)
1443 (* ------------------------------------------------------------------------- *)
1444
1445 let filter_cpp_stuff xs =
1446 List.filter
1447 (function x ->
1448 (match x.tok with
1449 | tok when TH.is_comment tok -> false
1450 (* don't want drop the define, or if drop, have to drop
1451 * also its body otherwise the line heuristics may be lost
1452 * by not finding the TDefine in column 0 but by finding
1453 * a TDefineIdent in a column > 0
1454 *)
1455 | Parser_c.TDefine _ -> true
1456 | tok when TH.is_cpp_instruction tok -> false
1457 | _ -> true
1458 ))
1459 xs
1460
1461 let insert_virtual_positions l =
1462 let strlen x = String.length (Ast_c.str_of_info x) in
1463 let rec loop prev offset acc = function
1464 [] -> List.rev acc
1465 | x::xs ->
1466 let ii = TH.info_of_tok x in
1467 let inject pi =
1468 TH.visitor_info_of_tok (function ii -> Ast_c.rewrap_pinfo pi ii) x in
1469 match Ast_c.pinfo_of_info ii with
1470 Ast_c.OriginTok pi ->
1471 let prev = Ast_c.parse_info_of_info ii in
1472 loop prev (strlen ii) (x::acc) xs
1473 | Ast_c.ExpandedTok (pi,_) ->
1474 let x' = inject (Ast_c.ExpandedTok (pi,(prev,offset))) in
1475 loop prev (offset + (strlen ii)) (x'::acc) xs
1476 | Ast_c.FakeTok (s,_) ->
1477 let x' = inject (Ast_c.FakeTok (s,(prev,offset))) in
1478 loop prev (offset + (strlen ii)) (x'::acc) xs
1479 | Ast_c.AbstractLineTok _ -> failwith "abstract not expected" in
1480 let rec skip_fake = function
1481 | [] -> []
1482 | x::xs ->
1483 let ii = TH.info_of_tok x in
1484 match Ast_c.pinfo_of_info ii with
1485 | Ast_c.OriginTok pi ->
1486 let prev = Ast_c.parse_info_of_info ii in
1487 let res = loop prev (strlen ii) [] xs in
1488 x::res
1489 | _ -> x::skip_fake xs in
1490 skip_fake l
1491
1492
1493 (* ------------------------------------------------------------------------- *)
1494 let fix_tokens_cpp2 ~macro_defs tokens =
1495 let tokens2 = ref (tokens +> Common.acc_map TV.mk_token_extended) in
1496
1497 begin
1498 (* the order is important, if you put the action heuristic first,
1499 * then because of ifdef, can have not closed paren
1500 * and so may believe that higher order macro
1501 * and it will eat too much tokens. So important to do
1502 * first the ifdef.
1503 *
1504 * I recompute multiple times cleaner cos the mutable
1505 * can have be changed and so may have more comments
1506 * in the token original list.
1507 *
1508 *)
1509
1510 commentize_skip_start_to_end !tokens2;
1511
1512 (* ifdef *)
1513 let cleaner = !tokens2 +> List.filter (fun x ->
1514 (* is_comment will also filter the TCommentCpp created in
1515 * commentize_skip_start_to_end *)
1516 not (TH.is_comment x.tok) (* could filter also #define/#include *)
1517 ) in
1518 let ifdef_grouped = TV.mk_ifdef cleaner in
1519 set_ifdef_parenthize_info ifdef_grouped;
1520
1521 find_ifdef_funheaders ifdef_grouped;
1522 find_ifdef_bool ifdef_grouped;
1523 find_ifdef_mid ifdef_grouped;
1524 (* change order ? maybe cparen_else heuristic make some of the funheaders
1525 * heuristics irrelevant ?
1526 *)
1527 find_ifdef_cparen_else ifdef_grouped;
1528 adjust_inifdef_include ifdef_grouped;
1529
1530
1531 (* macro 1 *)
1532 let cleaner = !tokens2 +> filter_cpp_stuff in
1533
1534 let paren_grouped = TV.mk_parenthised cleaner in
1535 Cpp_token_c.apply_macro_defs
1536 ~msg_apply_known_macro
1537 ~msg_apply_known_macro_hint
1538 macro_defs paren_grouped;
1539 (* because the before field is used by apply_macro_defs *)
1540 tokens2 := TV.rebuild_tokens_extented !tokens2;
1541
1542 (* tagging contextual info (InFunc, InStruct, etc). Better to do
1543 * that after the "ifdef-simplification" phase.
1544 *)
1545 let cleaner = !tokens2 +> List.filter (fun x ->
1546 not (TH.is_comment x.tok) (* could filter also #define/#include *)
1547 ) in
1548
1549 let brace_grouped = TV.mk_braceised cleaner in
1550 set_context_tag brace_grouped;
1551
1552 (* macro *)
1553 let cleaner = !tokens2 +> filter_cpp_stuff in
1554
1555 let paren_grouped = TV.mk_parenthised cleaner in
1556 let line_paren_grouped = TV.mk_line_parenthised paren_grouped in
1557 find_define_init_brace_paren paren_grouped;
1558 find_string_macro_paren paren_grouped;
1559 find_macro_lineparen line_paren_grouped;
1560 find_macro_paren paren_grouped;
1561
1562
1563 (* obsolete: actions ? not yet *)
1564 let cleaner = !tokens2 +> filter_cpp_stuff in
1565 let paren_grouped = TV.mk_parenthised cleaner in
1566 find_actions paren_grouped;
1567
1568
1569
1570 insert_virtual_positions (!tokens2 +> Common.acc_map (fun x -> x.tok))
1571 end
1572
1573 let time_hack1 ~macro_defs a =
1574 Common.profile_code_exclusif "HACK" (fun () -> fix_tokens_cpp2 ~macro_defs a)
1575
1576 let fix_tokens_cpp ~macro_defs a =
1577 Common.profile_code "C parsing.fix_cpp" (fun () -> time_hack1 ~macro_defs a)
1578
1579
1580
1581
1582 (*****************************************************************************)
1583 (* Lexing with lookahead *)
1584 (*****************************************************************************)
1585
1586 (* Why using yet another parsing_hack technique ? The fix_xxx where do
1587 * some pre-processing on the full list of tokens is not enough ?
1588 * No cos sometimes we need more contextual info, and even if
1589 * set_context() tries to give some contextual info, it's not completely
1590 * accurate so the following code give yet another alternative, yet another
1591 * chance to transform some tokens.
1592 *
1593 * todo?: maybe could try to get rid of this technique. Maybe a better
1594 * set_context() would make possible to move this code using a fix_xx
1595 * technique.
1596 *
1597 * LALR(k) trick. We can do stuff by adding cases in lexer_c.mll, but
1598 * it is more general to do it via my LALR(k) tech. Because here we can
1599 * transform some token give some context information. So sometimes it
1600 * makes sense to transform a token in one context, sometimes not, and
1601 * lex can not provide us this context information. Note that the order
1602 * in the pattern matching in lookahead is important. Do not cut/paste.
1603 *
1604 * Note that in next there is only "clean" tokens, there is no comment
1605 * or space tokens. This is done by the caller.
1606 *
1607 *)
1608
1609 open Lexer_parser (* for the fields of lexer_hint type *)
1610
1611 let not_struct_enum = function
1612 | (Parser_c.Tstruct _ | Parser_c.Tunion _ | Parser_c.Tenum _)::_ -> false
1613 | _ -> true
1614
1615
1616 let lookahead2 ~pass next before =
1617
1618 match (next, before) with
1619
1620 (*-------------------------------------------------------------*)
1621 (* typedef inference, parse_typedef_fix3 *)
1622 (*-------------------------------------------------------------*)
1623 (* xx xx *)
1624 | (TIdent(s,i1)::TIdent(s2,i2)::_ , _) when not_struct_enum before && s =$= s2
1625 && ok_typedef s
1626 (* (take_safe 1 !passed_tok <> [TOPar]) -> *)
1627 ->
1628 (* parse_typedef_fix3:
1629 * acpi_object acpi_object;
1630 * etait mal parsé, car pas le temps d'appeler dt() dans le type_spec.
1631 * Le parser en interne a deja appelé le prochain token pour pouvoir
1632 * decider des choses.
1633 * => special case in lexer_heuristic, again
1634 *)
1635 if !Flag_parsing_c.debug_typedef
1636 then pr2 ("TYPEDEF: disable typedef cos special case: " ^ s);
1637
1638 LP.disable_typedef();
1639
1640 msg_typedef s; LP.add_typedef_root s;
1641 TypedefIdent (s, i1)
1642
1643 (* xx yy *)
1644 | (TIdent (s, i1)::TIdent (s2, i2)::_ , _) when not_struct_enum before
1645 && ok_typedef s
1646 ->
1647 (* && not_annot s2 BUT lead to false positive*)
1648
1649 msg_typedef s; LP.add_typedef_root s;
1650 TypedefIdent (s, i1)
1651
1652
1653 (* xx inline *)
1654 | (TIdent (s, i1)::Tinline i2::_ , _) when not_struct_enum before
1655 && ok_typedef s
1656 ->
1657 msg_typedef s; LP.add_typedef_root s;
1658 TypedefIdent (s, i1)
1659
1660
1661 (* [,(] xx [,)] AND param decl *)
1662 | (TIdent (s, i1)::(TComma _|TCPar _)::_ , (TComma _ |TOPar _)::_ )
1663 when not_struct_enum before && (LP.current_context() =*= LP.InParameter)
1664 && ok_typedef s
1665 ->
1666 msg_typedef s; LP.add_typedef_root s;
1667 TypedefIdent (s, i1)
1668
1669 (* xx* [,)] *)
1670 (* specialcase: [,(] xx* [,)] *)
1671 | (TIdent (s, i1)::TMul _::(TComma _|TCPar _)::_ , (*(TComma _|TOPar _)::*)_ )
1672 when not_struct_enum before
1673 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1674 && ok_typedef s
1675 ->
1676 msg_typedef s; LP.add_typedef_root s;
1677 TypedefIdent (s, i1)
1678
1679
1680 (* xx** [,)] *)
1681 (* specialcase: [,(] xx** [,)] *)
1682 | (TIdent (s, i1)::TMul _::TMul _::(TComma _|TCPar _)::_ , (*(TComma _|TOPar _)::*)_ )
1683 when not_struct_enum before
1684 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1685 && ok_typedef s
1686 ->
1687 msg_typedef s; LP.add_typedef_root s;
1688 TypedefIdent (s, i1)
1689
1690
1691
1692 (* xx const * USELESS because of next rule ? *)
1693 | (TIdent (s, i1)::(Tconst _|Tvolatile _|Trestrict _)::TMul _::_ , _ )
1694 when not_struct_enum before
1695 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1696 && ok_typedef s
1697 ->
1698
1699 msg_typedef s; LP.add_typedef_root s;
1700 TypedefIdent (s, i1)
1701
1702 (* xx const *)
1703 | (TIdent (s, i1)::(Tconst _|Tvolatile _|Trestrict _)::_ , _ )
1704 when not_struct_enum before
1705 && ok_typedef s
1706 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1707 ->
1708
1709 msg_typedef s; LP.add_typedef_root s;
1710 TypedefIdent (s, i1)
1711
1712
1713 (* xx * const *)
1714 | (TIdent (s, i1)::TMul _::(Tconst _ | Tvolatile _|Trestrict _)::_ , _ )
1715 when not_struct_enum before
1716 && ok_typedef s
1717 ->
1718 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1719
1720 msg_typedef s; LP.add_typedef_root s;
1721 TypedefIdent (s, i1)
1722
1723
1724 (* ( const xx) *)
1725 | (TIdent (s, i1)::TCPar _::_, (Tconst _ | Tvolatile _|Trestrict _)::TOPar _::_) when
1726 ok_typedef s ->
1727 msg_typedef s; LP.add_typedef_root s;
1728 TypedefIdent (s, i1)
1729
1730
1731
1732 (* ( xx ) [sizeof, ~] *)
1733 | (TIdent (s, i1)::TCPar _::(Tsizeof _|TTilde _)::_ , TOPar _::_ )
1734 when not_struct_enum before
1735 && ok_typedef s
1736 ->
1737 msg_typedef s; LP.add_typedef_root s;
1738 TypedefIdent (s, i1)
1739
1740 (* [(,] xx [ AND parameterdeclaration *)
1741 | (TIdent (s, i1)::TOCro _::_, (TComma _ |TOPar _)::_)
1742 when (LP.current_context() =*= LP.InParameter)
1743 && ok_typedef s
1744 ->
1745 msg_typedef s; LP.add_typedef_root s;
1746 TypedefIdent (s, i1)
1747
1748 (*------------------------------------------------------------*)
1749 (* if 'x*y' maybe an expr, maybe just a classic multiplication *)
1750 (* but if have a '=', or ',' I think not *)
1751 (*------------------------------------------------------------*)
1752
1753 (* static xx * yy *)
1754 | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::_ ,
1755 (Tregister _|Tstatic _ |Tvolatile _|Tconst _|Trestrict _)::_) when
1756 ok_typedef s
1757 ->
1758 msg_typedef s; LP.add_typedef_root s;
1759 TypedefIdent (s, i1)
1760
1761 (* TODO xx * yy ; AND in start of compound element *)
1762
1763
1764 (* xx * yy, AND in paramdecl *)
1765 | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TComma _::_ , _)
1766 when not_struct_enum before && (LP.current_context() =*= LP.InParameter)
1767 && ok_typedef s
1768 ->
1769
1770 msg_typedef s; LP.add_typedef_root s;
1771 TypedefIdent (s, i1)
1772
1773
1774 (* xx * yy ; AND in Toplevel, except when have = before *)
1775 | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TPtVirg _::_ , TEq _::_) ->
1776 TIdent (s, i1)
1777 | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TPtVirg _::_ , _)
1778 when not_struct_enum before && (LP.is_top_or_struct (LP.current_context ()))
1779 ->
1780 msg_typedef s; LP.add_typedef_root s;
1781 TypedefIdent (s, i1)
1782
1783 (* xx * yy , AND in Toplevel *)
1784 | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TComma _::_ , _)
1785 when not_struct_enum before && (LP.current_context () =*= LP.InTopLevel)
1786 && ok_typedef s
1787 ->
1788
1789 msg_typedef s; LP.add_typedef_root s;
1790 TypedefIdent (s, i1)
1791
1792 (* xx * yy ( AND in Toplevel *)
1793 | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TOPar _::_ , _)
1794 when not_struct_enum before
1795 && (LP.is_top_or_struct (LP.current_context ()))
1796 && ok_typedef s
1797 ->
1798 msg_typedef s; LP.add_typedef_root s;
1799 TypedefIdent (s, i1)
1800
1801 (* xx * yy [ *)
1802 (* todo? enough ? cos in struct def we can have some expression ! *)
1803 | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TOCro _::_ , _)
1804 when not_struct_enum before &&
1805 (LP.is_top_or_struct (LP.current_context ()))
1806 && ok_typedef s
1807 ->
1808 msg_typedef s; LP.add_typedef_root s;
1809 TypedefIdent (s, i1)
1810
1811 (* u16: 10; in struct *)
1812 | (TIdent (s, i1)::TDotDot _::_ , (TOBrace _ | TPtVirg _)::_)
1813 when (LP.is_top_or_struct (LP.current_context ()))
1814 && ok_typedef s
1815 ->
1816 msg_typedef s; LP.add_typedef_root s;
1817 TypedefIdent (s, i1)
1818
1819
1820 (* why need TOPar condition as stated in preceding rule ? really needed ? *)
1821 (* YES cos at toplevel can have some expression !! for instance when *)
1822 (* enter in the dimension of an array *)
1823 (*
1824 | (TIdent s::TMul::TIdent s2::_ , _)
1825 when (take_safe 1 !passed_tok <> [Tstruct] &&
1826 (take_safe 1 !passed_tok <> [Tenum]))
1827 &&
1828 !LP._lexer_hint = Some LP.Toplevel ->
1829 msg_typedef s; LP.add_typedef_root s;
1830 TypedefIdent s
1831 *)
1832
1833 (* xx * yy = *)
1834 | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TEq _::_ , _)
1835 when not_struct_enum before
1836 && ok_typedef s
1837 ->
1838 msg_typedef s; LP.add_typedef_root s;
1839 TypedefIdent (s, i1)
1840
1841
1842 (* xx * yy) AND in paramdecl *)
1843 | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TCPar _::_ , _)
1844 when not_struct_enum before && (LP.current_context () =*= LP.InParameter)
1845 && ok_typedef s
1846 ->
1847 msg_typedef s; LP.add_typedef_root s;
1848 TypedefIdent (s, i1)
1849
1850
1851 (* xx * yy; *) (* wrong ? *)
1852 | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TPtVirg _::_ ,
1853 (TOBrace _| TPtVirg _)::_) when not_struct_enum before
1854 && ok_typedef s
1855 ->
1856 msg_typedef s; LP.add_typedef_root s;
1857 msg_maybe_dangereous_typedef s;
1858 TypedefIdent (s, i1)
1859
1860
1861 (* xx * yy, and ';' before xx *) (* wrong ? *)
1862 | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::TComma _::_ ,
1863 (TOBrace _| TPtVirg _)::_) when
1864 ok_typedef s
1865 ->
1866 msg_typedef s; LP.add_typedef_root s;
1867 TypedefIdent (s, i1)
1868
1869
1870 (* xx_t * yy *)
1871 | (TIdent (s, i1)::TMul _::TIdent (s2, i2)::_ , _)
1872 when s ==~ regexp_typedef && not_struct_enum before
1873 (* struct user_info_t sometimes *)
1874 && ok_typedef s
1875 ->
1876 msg_typedef s; LP.add_typedef_root s;
1877 TypedefIdent (s, i1)
1878
1879 (* xx ** yy *) (* wrong ? *)
1880 | (TIdent (s, i1)::TMul _::TMul _::TIdent (s2, i2)::_ , _)
1881 when not_struct_enum before
1882 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1883 && ok_typedef s
1884 ->
1885 msg_typedef s; LP.add_typedef_root s;
1886 TypedefIdent (s, i1)
1887
1888 (* xx *** yy *)
1889 | (TIdent (s, i1)::TMul _::TMul _::TMul _::TIdent (s2, i2)::_ , _)
1890 when not_struct_enum before
1891 && ok_typedef s
1892 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1893 ->
1894 msg_typedef s; LP.add_typedef_root s;
1895 TypedefIdent (s, i1)
1896
1897 (* xx ** ) *)
1898 | (TIdent (s, i1)::TMul _::TMul _::TCPar _::_ , _)
1899 when not_struct_enum before
1900 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1901 && ok_typedef s
1902 ->
1903 msg_typedef s; LP.add_typedef_root s;
1904 TypedefIdent (s, i1)
1905
1906
1907
1908 (* ----------------------------------- *)
1909 (* old: why not do like for other rules and start with TIdent ?
1910 * why do TOPar :: TIdent :: ..., _ and not TIdent :: ..., TOPAr::_ ?
1911 * new: prefer now start with TIdent because otherwise the add_typedef_root
1912 * may have no effect if in second pass or if have disable the add_typedef.
1913 *)
1914
1915 (* (xx) yy *)
1916 | (TIdent (s, i1)::TCPar i2::(TIdent (_,i3)|TInt (_,i3))::_ ,
1917 (TOPar info)::x::_)
1918 when not (TH.is_stuff_taking_parenthized x) &&
1919 Ast_c.line_of_info i2 =|= Ast_c.line_of_info i3
1920 && ok_typedef s
1921 ->
1922
1923 msg_typedef s; LP.add_typedef_root s;
1924 (*TOPar info*)
1925 TypedefIdent (s, i1)
1926
1927
1928 (* (xx) ( yy)
1929 * but false positif: typedef int (xxx_t)(...), so do specialisation below.
1930 *)
1931 (*
1932 | (TIdent (s, i1)::TCPar _::TOPar _::_ , (TOPar info)::x::_)
1933 when not (TH.is_stuff_taking_parenthized x)
1934 && ok_typedef s
1935 ->
1936 msg_typedef s; LP.add_typedef_root s;
1937 (* TOPar info *)
1938 TypedefIdent (s, i1)
1939 *)
1940 (* special case: = (xx) ( yy) *)
1941 | (TIdent (s, i1)::TCPar _::TOPar _::_ ,
1942 (TOPar info)::(TEq _ |TEqEq _)::_)
1943 when ok_typedef s
1944 ->
1945 msg_typedef s; LP.add_typedef_root s;
1946 (* TOPar info *)
1947 TypedefIdent (s, i1)
1948
1949
1950 (* (xx * ) yy *)
1951 | (TIdent (s, i1)::TMul _::TCPar _::TIdent (s2, i2)::_ , (TOPar info)::_) when
1952 ok_typedef s
1953 ->
1954 msg_typedef s; LP.add_typedef_root s;
1955 (*TOPar info*)
1956 TypedefIdent (s,i1)
1957
1958
1959 (* (xx){ ... } constructor *)
1960 | (TIdent (s, i1)::TCPar _::TOBrace _::_ , TOPar _::x::_)
1961 when (*s ==~ regexp_typedef && *) not (TH.is_stuff_taking_parenthized x)
1962 && ok_typedef s
1963 ->
1964 msg_typedef s; LP.add_typedef_root s;
1965 TypedefIdent (s, i1)
1966
1967
1968 (* can have sizeof on expression
1969 | (Tsizeof::TOPar::TIdent s::TCPar::_, _) ->
1970 msg_typedef s; LP.add_typedef_root s;
1971 Tsizeof
1972 *)
1973
1974
1975 (* ----------------------------------- *)
1976 (* x ( *y )(params), function pointer *)
1977 | (TIdent (s, i1)::TOPar _::TMul _::TIdent _::TCPar _::TOPar _::_, _)
1978 when not_struct_enum before
1979 && ok_typedef s
1980 ->
1981 msg_typedef s; LP.add_typedef_root s;
1982 TypedefIdent (s, i1)
1983
1984 (* x* ( *y )(params), function pointer 2 *)
1985 | (TIdent (s, i1)::TMul _::TOPar _::TMul _::TIdent _::TCPar _::TOPar _::_, _)
1986 when not_struct_enum before
1987 && ok_typedef s
1988 ->
1989 msg_typedef s; LP.add_typedef_root s;
1990 TypedefIdent (s, i1)
1991
1992
1993 (*-------------------------------------------------------------*)
1994 (* CPP *)
1995 (*-------------------------------------------------------------*)
1996 | ((TIfdef (_,ii) |TIfdefelse (_,ii) |TIfdefelif (_,ii) |TEndif (_,ii) |
1997 TIfdefBool (_,_,ii)|TIfdefMisc(_,_,ii)|TIfdefVersion(_,_,ii))
1998 as x)
1999 ::_, _
2000 ->
2001 (*
2002 if not !Flag_parsing_c.ifdef_to_if
2003 then TCommentCpp (Ast_c.CppDirective, ii)
2004 else
2005 *)
2006 (* not !LP._lexer_hint.toplevel *)
2007 if !Flag_parsing_c.ifdef_directive_passing
2008 || (pass >= 2)
2009 then begin
2010
2011 if (LP.current_context () =*= LP.InInitializer)
2012 then begin
2013 pr2_cpp "In Initializer passing"; (* cheat: dont count in stat *)
2014 incr Stat.nIfdefInitializer;
2015 end else begin
2016 pr2_cpp("IFDEF: or related inside function. I treat it as comment");
2017 incr Stat.nIfdefPassing;
2018 end;
2019 TCommentCpp (Token_c.CppDirective, ii)
2020 end
2021 else x
2022
2023 | (TUndef (id, ii) as x)::_, _
2024 ->
2025 if (pass >= 2)
2026 then begin
2027 pr2_cpp("UNDEF: I treat it as comment");
2028 TCommentCpp (Token_c.CppDirective, ii)
2029 end
2030 else x
2031
2032 | (TCppDirectiveOther (ii) as x)::_, _
2033 ->
2034 if (pass >= 2)
2035 then begin
2036 pr2_cpp ("OTHER directive: I treat it as comment");
2037 TCommentCpp (Token_c.CppDirective, ii)
2038 end
2039 else x
2040
2041 (* If ident contain a for_each, then certainly a macro. But to be
2042 * sure should look if there is a '{' after the ')', but it requires
2043 * to count the '('. Because this can be expensive, we do that only
2044 * when the token contains "for_each".
2045 *)
2046 | (TIdent (s, i1)::TOPar _::rest, _)
2047 when not (LP.current_context () =*= LP.InTopLevel)
2048 (* otherwise a function such as static void loopback_enable(int i) {
2049 * will be considered as a loop
2050 *)
2051 ->
2052
2053
2054 if s ==~ regexp_foreach &&
2055 is_really_foreach (Common.take_safe forLOOKAHEAD rest)
2056
2057 then begin
2058 msg_foreach s;
2059 TMacroIterator (s, i1)
2060 end
2061 else TIdent (s, i1)
2062
2063
2064
2065 (*-------------------------------------------------------------*)
2066 | v::xs, _ -> v
2067 | _ -> raise Impossible
2068
2069 let lookahead ~pass a b =
2070 Common.profile_code "C parsing.lookahead" (fun () -> lookahead2 ~pass a b)
2071
2072