3 * Copyright (C) 2010, University of Copenhagen DIKU and INRIA.
4 * Copyright (C) 2007, 2008 Ecole des Mines de Nantes
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.
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.
18 module TH
= Token_helpers
19 module TV
= Token_views_c
20 module LP
= Lexer_parser
22 module Stat
= Parsing_stat
28 (*****************************************************************************)
29 (* Some debugging functions *)
30 (*****************************************************************************)
32 let pr2, pr2_once
= Common.mk_pr2_wrappers
Flag_parsing_c.verbose_parsing
35 if !Flag_parsing_c.debug_cpp
36 then Common.pr2_once
("CPP-" ^ s
)
39 let msg_gen cond is_known printer s
=
42 if not
(!Flag_parsing_c.filter_msg
)
48 (* In the following, there are some harcoded names of types or macros
49 * but they are not used by our heuristics! They are just here to
50 * enable to detect false positive by printing only the typedef/macros
51 * that we don't know yet. If we print everything, then we can easily
52 * get lost with too much verbose tracing information. So those
53 * functions "filter" some messages. So our heuristics are still good,
54 * there is no more (or not that much) hardcoded linux stuff.
60 | "u_char" | "u_short" | "u_int" | "u_long"
61 | "u8" | "u16" | "u32" | "u64"
62 | "s8" | "s16" | "s32" | "s64"
63 | "__u8" | "__u16" | "__u32" | "__u64"
74 | s
when s
=~
".*_t$" -> true
79 (* note: cant use partial application with let msg_typedef =
80 * because it would compute msg_typedef at compile time when
81 * the flag debug_typedef is always false
83 let msg_typedef s ii n
=
84 incr
Stat.nTypedefInfer
;
85 msg_gen (!Flag_parsing_c.debug_typedef
)
89 (Printf.sprintf
"TYPEDEF: promoting:(%d) %s on line %d" n s
90 (Ast_c.line_of_info ii
))
91 (*(Printf.sprintf "TYPEDEF: promoting: %s on line %d" s
92 (Ast_c.line_of_info ii))*)
96 let msg_maybe_dangereous_typedef s
=
97 if not
(is_known_typdef s
)
100 ("PB MAYBE: dangerous typedef inference, maybe not a typedef: " ^ s
)
104 let msg_declare_macro s
=
105 incr
Stat.nMacroDecl
;
106 msg_gen (!Flag_parsing_c.debug_cpp
)
109 | "DECLARE_MUTEX" | "DECLARE_COMPLETION" | "DECLARE_RWSEM"
110 | "DECLARE_WAITQUEUE" | "DECLARE_WAIT_QUEUE_HEAD"
111 | "DEFINE_SPINLOCK" | "DEFINE_TIMER"
112 | "DEVICE_ATTR" | "CLASS_DEVICE_ATTR" | "DRIVER_ATTR"
113 | "SENSOR_DEVICE_ATTR"
115 | "DECLARE_WORK" | "DECLARE_TASKLET"
116 | "PORT_ATTR_RO" | "PORT_PMA_ATTR"
121 | s when s =~ "^DECLARE_.*" -> true
122 | s when s =~ ".*_ATTR$" -> true
123 | s when s =~ "^DEFINE_.*" -> true
129 (fun s
-> pr2_cpp ("MACRO: found declare-macro: " ^ s
))
134 incr
Stat.nIteratorHeuristic
;
135 pr2_cpp ("MACRO: found foreach: " ^ s
)
139 let msg_debug_macro s =
140 pr2_cpp ("MACRO: found debug-macro: " ^ s)
144 let msg_macro_noptvirg s
=
145 incr
Stat.nMacroStmt
;
146 pr2_cpp ("MACRO: found macro with param noptvirg: " ^ s
)
148 let msg_macro_toplevel_noptvirg s
=
149 incr
Stat.nMacroStmt
;
150 pr2_cpp ("MACRO: found toplevel macro noptvirg: " ^ s
)
152 let msg_macro_noptvirg_single s
=
153 incr
Stat.nMacroStmt
;
154 pr2_cpp ("MACRO: found single-macro noptvirg: " ^ s
)
159 let msg_macro_higher_order s
=
160 incr
Stat.nMacroHigherOrder
;
161 msg_gen (!Flag_parsing_c.debug_cpp
)
171 (fun s
-> pr2_cpp ("MACRO: found higher ordre macro : " ^ s
))
175 let msg_stringification s
=
176 incr
Stat.nMacroString
;
177 msg_gen (!Flag_parsing_c.debug_cpp
)
185 (* s when s =~ ".*STR.*" -> true *)
189 (fun s
-> pr2_cpp ("MACRO: found string-macro " ^ s
))
192 let msg_stringification_params s
=
193 incr
Stat.nMacroString
;
194 pr2_cpp ("MACRO: string-macro with params : " ^ s
)
198 let msg_apply_known_macro s
=
199 incr
Stat.nMacroExpand
;
200 pr2_cpp ("MACRO: found known macro = " ^ s
)
202 let msg_apply_known_macro_hint s
=
203 incr
Stat.nMacroHint
;
204 pr2_cpp ("MACRO: found known macro hint = " ^ s
)
209 let msg_ifdef_bool_passing is_ifdef_positif
=
210 incr
Stat.nIfdefZero
; (* of Version ? *)
212 then pr2_cpp "commenting parts of a #if 1 or #if LINUX_VERSION"
213 else pr2_cpp "commenting a #if 0 or #if LINUX_VERSION or __cplusplus"
216 let msg_ifdef_mid_something () =
217 incr
Stat.nIfdefExprPassing
;
218 pr2_cpp "found ifdef-mid-something"
220 let msg_ifdef_funheaders () =
221 incr
Stat.nIfdefFunheader
;
224 let msg_ifdef_cparen_else () =
225 incr
Stat.nIfdefPassing
;
226 pr2_cpp("found ifdef-cparen-else")
229 let msg_attribute s
=
230 incr
Stat.nMacroAttribute
;
235 (*****************************************************************************)
236 (* The regexp and basic view definitions *)
237 (*****************************************************************************)
239 (* opti: better to built then once and for all, especially regexp_foreach *)
241 let regexp_macro = Str.regexp
245 let regexp_annot = Str.regexp
249 let regexp_declare = Str.regexp
253 let regexp_foreach = Str.regexp_case_fold
254 ".*\\(for_?each\\|for_?all\\|iterate\\|loop\\|walk\\|scan\\|each\\|for\\)"
256 let regexp_typedef = Str.regexp
259 let false_typedef = [
264 let ok_typedef s
= not
(List.mem s
false_typedef)
267 not
(s
==~
regexp_annot)
276 (*****************************************************************************)
278 (*****************************************************************************)
280 (* ------------------------------------------------------------------------- *)
281 (* the pair is the status of '()' and '{}', ex: (-1,0)
282 * if too much ')' and good '{}'
283 * could do for [] too ?
284 * could do for ',' if encounter ',' at "toplevel", not inside () or {}
285 * then if have ifdef, then certainly can lead to a problem.
287 let (count_open_close_stuff_ifdef_clause
: TV.ifdef_grouped list
-> (int * int))=
289 let cnt_paren, cnt_brace
= ref 0, ref 0 in
290 xs
+> TV.iter_token_ifdef
(fun x
->
292 | x
when TH.is_opar x
-> incr
cnt_paren
293 | TOBrace _
-> incr cnt_brace
294 | x
when TH.is_cpar x
-> decr
cnt_paren
295 | TCBrace _
-> decr cnt_brace
299 !cnt_paren, !cnt_brace
302 (* ------------------------------------------------------------------------- *)
303 let forLOOKAHEAD = 30
306 (* look if there is a '{' just after the closing ')', and handling the
307 * possibility to have nested expressions inside nested parenthesis
309 * todo: use indentation instead of premier(statement) ?
311 let rec is_really_foreach xs
=
312 let rec is_foreach_aux = function
314 | TCPar _
::TOBrace _
::xs
-> true, xs
315 (* the following attempts to handle the cases where there is a
316 single statement in the body of the loop. undoubtedly more
318 todo: premier(statement) - suivant(funcall)
320 | TCPar _
::TIdent _
::xs
-> true, xs
321 | TCPar _
::Tif _
::xs
-> true, xs
322 | TCPar _
::Twhile _
::xs
-> true, xs
323 | TCPar _
::Tfor _
::xs
-> true, xs
324 | TCPar _
::Tswitch _
::xs
-> true, xs
325 | TCPar _
::Treturn _
::xs
-> true, xs
328 | TCPar _
::xs
-> false, xs
330 let (_
, xs'
) = is_foreach_aux xs
in
332 | x
::xs
-> is_foreach_aux xs
334 is_foreach_aux xs
+> fst
337 (* ------------------------------------------------------------------------- *)
338 let set_ifdef_token_parenthize_info cnt x
=
341 | TIfdefelse
(tag
, _
)
342 | TIfdefelif
(tag
, _
)
345 | TIfdefBool
(_
, tag
, _
)
346 | TIfdefMisc
(_
, tag
, _
)
347 | TIfdefVersion
(_
, tag
, _
) ->
350 | _
-> raise
(Impossible
89)
354 let ifdef_paren_cnt = ref 0
357 let rec set_ifdef_parenthize_info xs
=
358 xs
+> List.iter
(function
359 | NotIfdefLine xs
-> ()
360 | Ifdefbool
(_
, xxs
, info_ifdef
)
361 | Ifdef
(xxs
, info_ifdef
) ->
363 incr
ifdef_paren_cnt;
364 let total_directives = List.length info_ifdef
in
366 info_ifdef
+> List.iter
(fun x
->
367 set_ifdef_token_parenthize_info (!ifdef_paren_cnt, total_directives)
369 xxs
+> List.iter
set_ifdef_parenthize_info
373 (*****************************************************************************)
374 (* The parsing hack for #define *)
375 (*****************************************************************************)
377 (* To parse macro definitions I need to do some tricks
378 * as some information can be get only at the lexing level. For instance
379 * the space after the name of the macro in '#define foo (x)' is meaningful
380 * but the grammar can not get this information. So define_ident below
381 * look at such space and generate a special TOpardefine. In a similar
382 * way macro definitions can contain some antislash and newlines
383 * and the grammar need to know where the macro ends (which is
384 * a line-level and so low token-level information). Hence the
385 * function 'define_line' below and the TDefEol.
387 * update: TDefEol is handled in a special way at different places,
388 * a little bit like EOF, especially for error recovery, so this
389 * is an important token that should not be retagged!
392 * ugly hack, a better solution perhaps would be to erase TDefEOL
393 * from the Ast and list of tokens in parse_c.
395 * note: I do a +1 somewhere, it's for the unparsing to correctly sync.
397 * note: can't replace mark_end_define by simply a fakeInfo(). The reason
398 * is where is the \n TCommentSpace. Normally there is always a last token
399 * to synchronize on, either EOF or the token of the next toplevel.
400 * In the case of the #define we got in list of token
401 * [TCommentSpace "\n"; TDefEOL] but if TDefEOL is a fakeinfo then we will
402 * not synchronize on it and so we will not print the "\n".
403 * A solution would be to put the TDefEOL before the "\n".
404 * (jll: tried to do this, see the comment "Put end of line..." below)
406 * todo?: could put a ExpandedTok for that ?
408 let mark_end_define ii
=
410 { Ast_c.pinfo
= Ast_c.OriginTok
{ (Ast_c.parse_info_of_info
ii) with
412 Common.charpos
= Ast_c.pos_of_info
ii + 1
414 cocci_tag
= ref Ast_c.emptyAnnot
;
415 annots_tag
= Token_annot.empty
;
416 comments_tag
= ref Ast_c.emptyComments
;
421 (* put the TDefEOL at the good place *)
422 let rec define_line_1 acc xs
=
426 let line = Ast_c.line_of_info
ii in
427 let acc = (TDefine
ii) :: acc in
428 define_line_2
acc ((=|=) line) ii xs
430 let line = Ast_c.line_of_info
ii in
431 let acc = (TUndef
ii) :: acc in
432 define_line_2
acc ((=|=) line) ii xs
433 | TCppEscapedNewline
ii::xs
->
434 pr2 ("SUSPICIOUS: a \\ character appears outside of a #define at");
435 pr2 (Ast_c.strloc_of_info
ii);
436 let acc = (TCommentSpace
ii) :: acc in
438 | x
::xs
-> define_line_1 (x
::acc) xs
440 and define_line_2
acc lineOk lastinfo xs
=
443 (* should not happened, should meet EOF before *)
445 List.rev
(mark_end_define lastinfo
::acc)
447 let line = TH.line_of_tok x
in
448 let info = TH.info_of_tok x
in
452 let acc = (mark_end_define lastinfo
) :: acc in
453 let acc = (EOF
ii) :: acc in
455 | TCppEscapedNewline
ii ->
456 if not
(lineOk
line) then pr2 "PB: WEIRD: not same line number";
457 let acc = (TCommentSpace
ii) :: acc in
458 define_line_2
acc ((=|=) (line + 1)) info xs
459 | TComment _
when lineOk
line ->
460 define_line_2
(x
::acc) (function x
-> true) info xs
461 | TString _
when lineOk
line ->
462 define_line_2
(x
::acc) (function x
-> true) info xs
465 then define_line_2
(x
::acc) ((=|=) line) info xs
467 (* Put end of line token before the newline. A newline at least
468 must be there because the line changed and because we saw a
469 #define previously to get to this function at all *)
471 ((List.hd
acc)::(mark_end_define lastinfo
::(List.tl
acc)))
475 let rec define_ident acc xs
=
479 let acc = TUndef
ii :: acc in
481 TCommentSpace i1
::TIdent
(s
,i2
)::xs
->
482 let acc = (TCommentSpace i1
) :: acc in
483 let acc = (TIdentDefine
(s
,i2
)) :: acc in
486 pr2 "WEIRD: weird #define body";
490 let acc = TDefine
ii :: acc in
492 | TCommentSpace i1
::TIdent
(s
,i2
)::TOPar
(i3
)::xs
->
493 (* Change also the kind of TIdent to avoid bad interaction
494 * with other parsing_hack tricks. For instant if keep TIdent then
495 * the stringication algo can believe the TIdent is a string-macro.
496 * So simpler to change the kind of the ident too.
498 (* if TOParDefine sticked to the ident, then
499 * it's a macro-function. Change token to avoid ambiguity
500 * between #define foo(x) and #define foo (x)
502 let acc = (TCommentSpace i1
) :: acc in
503 let acc = (TIdentDefine
(s
,i2
)) :: acc in
504 let acc = (TOParDefine i3
) :: acc in
507 | TCommentSpace i1
::TIdent
(s
,i2
)::xs
->
508 let acc = (TCommentSpace i1
) :: acc in
509 let acc = (TIdentDefine
(s
,i2
)) :: acc in
512 (* bugfix: ident of macro (as well as params, cf below) can be tricky
513 * note, do we need to subst in the body of the define ? no cos
514 * here the issue is the name of the macro, as in #define inline,
515 * so obviously the name of this macro will not be used in its
516 * body (it would be a recursive macro, which is forbidden).
519 | TCommentSpace i1
::t
::xs
520 when TH.str_of_tok t
==~
Common.regexp_alpha
522 let s = TH.str_of_tok t
in
523 let ii = TH.info_of_tok t
in
524 pr2 (spf
"remapping: %s to an ident in macro name" s);
525 let acc = (TCommentSpace i1
) :: acc in
526 let acc = (TIdentDefine
(s,ii)) :: acc in
529 | TCommentSpace _
::_
::xs
531 pr2 "WEIRD: weird #define body";
535 let acc = x
:: acc in
540 let fix_tokens_define2 xs
=
541 define_ident [] (define_line_1 [] xs
)
543 let fix_tokens_define a
=
544 Common.profile_code
"C parsing.fix_define" (fun () -> fix_tokens_define2 a
)
550 (* ------------------------------------------------------------------------- *)
551 (* Other parsing hacks related to cpp, Include/Define hacks *)
552 (* ------------------------------------------------------------------------- *)
554 (* Sometimes I prefer to generate a single token for a list of things in the
555 * lexer so that if I have to passed them, like for passing TInclude then
556 * it's easy. Also if I don't do a single token, then I need to
557 * parse the rest which may not need special stuff, like detecting
558 * end of line which the parser is not really ready for. So for instance
559 * could I parse a #include <a/b/c/xxx.h> as 2 or more tokens ? just
560 * lex #include ? so then need recognize <a/b/c/xxx.h> as one token ?
561 * but this kind of token is valid only after a #include and the
562 * lexing and parsing rules are different for such tokens so not that
563 * easy to parse such things in parser_c.mly. Hence the following hacks.
565 * less?: maybe could get rid of this like I get rid of some of fix_define.
570 (* used to generate new token from existing one *)
571 let new_info posadd str
ii =
573 Ast_c.OriginTok
{ (Ast_c.parse_info_of_info
ii) with
574 charpos
= Ast_c.pos_of_info
ii + posadd
;
576 column
= Ast_c.col_of_info
ii + posadd
;
578 (* must generate a new ref each time, otherwise share *)
579 cocci_tag
= ref Ast_c.emptyAnnot
;
580 annots_tag
= Token_annot.empty
;
581 comments_tag
= ref Ast_c.emptyComments
;
585 let rec comment_until_defeol xs
=
588 (* job not done in Cpp_token_c.define_parse ? *)
589 failwith
"cant find end of define token TDefEOL"
592 | Parser_c.TDefEOL i
->
593 Parser_c.TCommentCpp
(Token_c.CppDirective
, TH.info_of_tok x
)
597 (* bugfix: otherwise may lose a TComment token *)
598 if TH.is_real_comment
x
600 else Parser_c.TCommentCpp
(Token_c.CppPassingNormal
(*good?*), TH.info_of_tok
x)
602 x'
::comment_until_defeol xs
605 let drop_until_defeol xs
=
607 (Common.drop_until
(function Parser_c.TDefEOL _
-> true | _
-> false) xs
)
611 (* ------------------------------------------------------------------------- *)
612 (* returns a pair (replaced token, list of next tokens) *)
613 (* ------------------------------------------------------------------------- *)
615 let tokens_include (info, includes
, filename
, inifdef
) =
616 Parser_c.TIncludeStart
(Ast_c.rewrap_str includes
info, inifdef
),
617 [Parser_c.TIncludeFilename
618 (filename
, (new_info (String.length includes
) filename
info))
624 (*****************************************************************************)
625 (* CPP handling: macros, ifdefs, macros defs *)
626 (*****************************************************************************)
628 (* ------------------------------------------------------------------------- *)
629 (* special skip_start skip_end handling *)
630 (* ------------------------------------------------------------------------- *)
632 (* note: after this normally the token list should not contain any more the
633 * TCommentSkipTagStart and End tokens.
635 let rec commentize_skip_start_to_end xs
=
640 | {tok
= TCommentSkipTagStart
info} ->
642 let (before
, x2
, after
) =
643 xs
+> Common.split_when
(function
644 | {tok
= TCommentSkipTagEnd _
} -> true
648 let topass = x::x2
::before
in
649 topass +> List.iter
(fun tok
->
650 TV.set_as_comment
Token_c.CppPassingExplicit tok
652 commentize_skip_start_to_end after
654 failwith
"could not find end of skip_start special comment"
656 | {tok
= TCommentSkipTagEnd
info} ->
657 failwith
"found skip_end comment but no skip_start"
659 commentize_skip_start_to_end xs
665 (* ------------------------------------------------------------------------- *)
666 (* ifdef keeping/passing *)
667 (* ------------------------------------------------------------------------- *)
669 (* #if 0, #if 1, #if LINUX_VERSION handling *)
670 let rec find_ifdef_bool xs
=
671 xs
+> List.iter
(function
672 | NotIfdefLine _
-> ()
673 | Ifdefbool
(is_ifdef_positif
, xxs
, info_ifdef_stmt
) ->
675 msg_ifdef_bool_passing is_ifdef_positif
;
678 | [] -> raise
(Impossible
90)
679 | firstclause
::xxs
->
681 List.iter
(TV.save_as_comment
(fun x -> Token_c.CppIfDirective
x));
684 then xxs
+> List.iter
685 (iter_token_ifdef
(TV.set_as_comment
Token_c.CppPassingNormal
))
688 iter_token_ifdef
(TV.set_as_comment
Token_c.CppPassingNormal
);
689 (match List.rev xxs
with
693 (iter_token_ifdef
(TV.set_as_comment
Token_c.CppPassingNormal
))
694 | [] -> (* not #else *) ()
699 | Ifdef
(xxs
, info_ifdef_stmt
) -> xxs
+> List.iter
find_ifdef_bool
704 let thresholdIfdefSizeMid = 6
706 (* infer ifdef involving not-closed expressions/statements *)
707 let rec find_ifdef_mid xs
=
708 xs
+> List.iter
(function
709 | NotIfdefLine _
-> ()
710 | Ifdef
(xxs
, info_ifdef_stmt
) ->
712 | [] -> raise
(Impossible
91)
714 | first
::second
::rest
->
715 (* don't analyse big ifdef *)
716 if xxs
+> List.for_all
717 (fun xs
-> List.length xs
<= thresholdIfdefSizeMid) &&
718 (* don't want nested ifdef *)
719 xxs
+> List.for_all
(fun xs
->
721 (function NotIfdefLine _
-> true | _
-> false)
725 let counts = xxs
+> List.map count_open_close_stuff_ifdef_clause
in
726 let cnt1, cnt2
= List.hd
counts in
727 if cnt1 <> 0 || cnt2
<> 0 &&
728 counts +> List.for_all
(fun x -> x =*= (cnt1, cnt2
))
730 if counts +> List.exists (fun (cnt1, cnt2) ->
731 cnt1 <> 0 || cnt2 <> 0
735 msg_ifdef_mid_something();
737 (* keep only first, treat the rest as comment *)
740 (TV.save_as_comment
(function x -> Token_c.CppIfDirective
x));
741 (second
::rest
) +> List.iter
742 (iter_token_ifdef
(TV.set_as_comment
Token_c.CppPassingCosWouldGetError
));
746 List.iter
find_ifdef_mid xxs
748 (* no need complex analysis for ifdefbool *)
749 | Ifdefbool
(_
, xxs
, info_ifdef_stmt
) ->
750 List.iter
find_ifdef_mid xxs
756 let thresholdFunheaderLimit = 4
758 (* ifdef defining alternate function header, type *)
759 let rec find_ifdef_funheaders = function
761 | NotIfdefLine _
::xs
-> find_ifdef_funheaders xs
763 (* ifdef-funheader if ifdef with 2 lines and a '{' in next line *)
765 ([(NotIfdefLine
(({col
= 0} as _xline1
)::line1
))::ifdefblock1
;
766 (NotIfdefLine
(({col
= 0} as xline2
)::line2
))::ifdefblock2
769 ::NotIfdefLine
(({tok
= TOBrace i
; col
= 0})::line3
)
771 when List.length ifdefblock1
<= thresholdFunheaderLimit &&
772 List.length ifdefblock2
<= thresholdFunheaderLimit
774 find_ifdef_funheaders xs
;
776 msg_ifdef_funheaders ();
778 List.iter
(TV.save_as_comment
(fun x -> Token_c.CppIfDirective
x));
779 let all_toks = [xline2
] @ line2
in
780 all_toks +> List.iter
(TV.set_as_comment
Token_c.CppPassingCosWouldGetError
) ;
781 ifdefblock2
+> iter_token_ifdef
(TV.set_as_comment
Token_c.CppPassingCosWouldGetError
);
783 (* ifdef with nested ifdef *)
785 ([[NotIfdefLine
(({col
= 0} as _xline1
)::line1
)];
787 ([[NotIfdefLine
(({col
= 0} as xline2
)::line2
)];
788 [NotIfdefLine
(({col
= 0} as xline3
)::line3
)];
794 ::NotIfdefLine
(({tok
= TOBrace i
; col
= 0})::line4
)
797 find_ifdef_funheaders xs
;
799 msg_ifdef_funheaders ();
801 List.iter
(TV.save_as_comment
(fun x -> Token_c.CppIfDirective
x));
803 List.iter
(TV.save_as_comment
(fun x -> Token_c.CppIfDirective
x));
804 let all_toks = [xline2
;xline3
] @ line2
@ line3
in
805 all_toks +> List.iter
(TV.set_as_comment
Token_c.CppPassingCosWouldGetError
);
807 (* ifdef with elseif *)
809 ([[NotIfdefLine
(({col
= 0} as _xline1
)::line1
)];
810 [NotIfdefLine
(({col
= 0} as xline2
)::line2
)];
811 [NotIfdefLine
(({col
= 0} as xline3
)::line3
)];
814 ::NotIfdefLine
(({tok
= TOBrace i
; col
= 0})::line4
)
817 find_ifdef_funheaders xs
;
819 msg_ifdef_funheaders ();
821 List.iter
(TV.save_as_comment
(fun x -> Token_c.CppIfDirective
x));
822 let all_toks = [xline2
;xline3
] @ line2
@ line3
in
823 all_toks +> List.iter
(TV.set_as_comment
Token_c.CppPassingCosWouldGetError
)
826 | Ifdef
(xxs
,info_ifdef_stmt
)::xs
827 | Ifdefbool
(_
, xxs
,info_ifdef_stmt
)::xs
->
828 List.iter
find_ifdef_funheaders xxs
;
829 find_ifdef_funheaders xs
834 let rec adjust_inifdef_include xs
=
835 xs
+> List.iter
(function
836 | NotIfdefLine _
-> ()
837 | Ifdef
(xxs
, info_ifdef_stmt
) | Ifdefbool
(_
, xxs
, info_ifdef_stmt
) ->
838 xxs
+> List.iter
(iter_token_ifdef
(fun tokext
->
839 match tokext
.tok
with
840 | Parser_c.TInclude
(s1
, s2
, inifdef_ref
, ii) ->
852 let rec find_ifdef_cparen_else xs
=
854 xs
+> List.iter
(function
855 | NotIfdefLine _
-> ()
856 | Ifdef
(xxs
, info_ifdef_stmt
) ->
858 | [] -> raise
(Impossible
92)
860 | first
::second
::rest
->
862 (* found a closing ')' just after the #else *)
864 (* Too bad ocaml does not support better list pattern matching
865 * a la Prolog-III where can match the end of lists.
868 if List.length first
= 0 then false
870 let last_line = Common.last first
in
873 if List.length xs
= 0 then false
875 let last_tok = Common.last xs
in
876 TH.is_cpar
last_tok.tok
877 | Ifdef _
| Ifdefbool _
-> false
879 if condition then begin
880 msg_ifdef_cparen_else();
882 (* keep only first, treat the rest as comment *)
884 List.iter
(TV.save_as_comment
(fun x -> Token_c.CppIfDirective
x));
885 (second
::rest
) +> List.iter
886 (iter_token_ifdef
(TV.set_as_comment
Token_c.CppPassingCosWouldGetError
));
892 (* no need complex analysis for ifdefbool *)
893 | Ifdefbool
(_
, xxs
, info_ifdef_stmt
) ->
899 (* ------------------------------------------------------------------------- *)
900 (* cpp-builtin part2, macro, using standard.h or other defs *)
901 (* ------------------------------------------------------------------------- *)
903 (* now in cpp_token_c.ml *)
905 (* ------------------------------------------------------------------------- *)
906 (* stringification *)
907 (* ------------------------------------------------------------------------- *)
909 let rec find_string_macro_paren xs
=
912 | Parenthised
(xxs
, info_parens
)::xs
->
913 xxs
+> List.iter
(fun xs
->
915 (function PToken
({tok
= (TString _
| TMacroString _
)}) -> true | _
-> false) &&
917 (function PToken
({tok
= (TString _
| TMacroString _
)}) | PToken
({tok
= TIdent _
}) ->
920 xs
+> List.iter
(fun tok
->
922 | PToken
({tok
= TIdent
(s,_
)} as id
) ->
924 msg_stringification s;
925 id
.tok
<- TMacroString
(s, TH.info_of_tok id
.tok
);
929 find_string_macro_paren xs
931 find_string_macro_paren xs
933 find_string_macro_paren xs
936 (* ------------------------------------------------------------------------- *)
938 (* ------------------------------------------------------------------------- *)
940 (* don't forget to recurse in each case *)
941 let rec find_macro_paren xs
=
946 | PToken
({tok
= Tattribute _
} as id
)
947 ::Parenthised
(xxs
,info_parens
)
950 pr2_cpp ("MACRO: __attribute detected ");
951 [Parenthised
(xxs
, info_parens
)] +>
952 iter_token_paren
(TV.set_as_comment
Token_c.CppAttr
);
953 TV.set_as_comment
Token_c.CppAttr id
;
956 | PToken
({tok
= TattributeNoarg _
} as id
)
959 pr2_cpp ("MACRO: __attributenoarg detected ");
960 TV.set_as_comment
Token_c.CppAttr id
;
964 (* attribute cpp, __xxx id *)
965 | PToken
({tok
= TIdent
(s,i1
)} as id
)
966 ::PToken
({tok
= TIdent
(s2
, i2
)} as id2
)
967 ::xs
when s ==~
regexp_annot
970 id
.tok
<- TMacroAttr
(s, i1
);
971 find_macro_paren ((PToken id2
)::xs
); (* recurse also on id2 ? *)
973 (* attribute cpp, id __xxx *)
974 | PToken
({tok
= TIdent
(s,i1
)} as _id
)
975 ::PToken
({tok
= TIdent
(s2
, i2
)} as id2
)
976 ::xs
when s2
==~
regexp_annot && (not
(s ==~
regexp_typedef))
979 id2
.tok
<- TMacroAttr
(s2
, i2
);
982 | PToken
({tok
= (Tstatic _
| Textern _
)} as tok1
)
983 ::PToken
({tok
= TIdent
(s,i1
)} as attr
)
984 ::xs
when s ==~
regexp_annot
986 pr2_cpp ("storage attribute: " ^
s);
987 attr
.tok
<- TMacroAttrStorage
(s,i1
);
988 (* recurse, may have other storage attributes *)
989 find_macro_paren (PToken
(tok1
)::xs
)
993 (* storage attribute *)
994 | PToken
({tok
= (Tstatic _
| Textern _
)} as tok1
)
995 ::PToken
({tok
= TMacroAttr
(s,i1
)} as attr
)::xs
997 pr2_cpp ("storage attribute: " ^
s);
998 attr
.tok
<- TMacroAttrStorage
(s,i1
);
999 (* recurse, may have other storage attributes *)
1000 find_macro_paren (PToken
(tok1
)::xs
)
1005 * the order of the matching clause is important
1009 (* string macro with params, before case *)
1010 | PToken
({tok
= (TString _
| TMacroString _
)})::PToken
({tok
= TIdent
(s,_
)} as id
)
1011 ::Parenthised
(xxs
, info_parens
)
1014 msg_stringification_params s;
1015 id
.tok
<- TMacroString
(s, TH.info_of_tok id
.tok
);
1016 [Parenthised
(xxs
, info_parens
)] +>
1017 iter_token_paren
(TV.set_as_comment
Token_c.CppMacro
);
1021 | PToken
({tok
= TIdent
(s,_
)} as id
)
1022 ::Parenthised
(xxs
, info_parens
)
1023 ::PToken
({tok
= (TString _
| TMacroString _
)})
1026 msg_stringification_params s;
1027 id
.tok
<- TMacroString
(s, TH.info_of_tok id
.tok
);
1028 [Parenthised
(xxs
, info_parens
)] +>
1029 iter_token_paren
(TV.set_as_comment
Token_c.CppMacro
);
1033 (* for the case where the string is not inside a funcall, but
1034 * for instance in an initializer.
1037 (* string macro variable, before case *)
1038 | PToken
({tok
= (TString _
| TMacroString _
)})::PToken
({tok
= TIdent
(s,_
)} as id
)
1039 ::xs
when not
!Flag.c_plus_plus
->
1041 msg_stringification s;
1042 id
.tok
<- TMacroString
(s, TH.info_of_tok id
.tok
);
1046 | PToken
({tok
= TIdent
(s,_
)} as id
)
1047 ::PToken
({tok
= (TString _
| TMacroString _
)})
1050 msg_stringification s;
1051 id
.tok
<- TMacroString
(s, TH.info_of_tok id
.tok
);
1059 | (PToken
x)::xs
-> find_macro_paren xs
1060 | (Parenthised
(xxs
, info_parens
))::xs
->
1061 xxs
+> List.iter
find_macro_paren;
1068 (* don't forget to recurse in each case *)
1069 let rec find_macro_lineparen xs
=
1073 (* linuxext: ex: static [const] DEVICE_ATTR(); *)
1076 [PToken
({tok
= Tstatic _
});
1077 PToken
({tok
= TIdent
(s,_
)} as macro
);
1078 Parenthised
(xxs
,info_parens
);
1079 PToken
({tok
= TPtVirg _
});
1083 when (s ==~
regexp_macro) ->
1085 msg_declare_macro s;
1086 let info = TH.info_of_tok macro
.tok
in
1087 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1089 find_macro_lineparen (xs
)
1091 (* the static const case *)
1094 [PToken
({tok
= Tstatic _
});
1095 PToken
({tok
= Tconst _
} as const
);
1096 PToken
({tok
= TIdent
(s,_
)} as macro
);
1097 Parenthised
(xxs
,info_parens
);
1098 PToken
({tok
= TPtVirg _
});
1104 when (s ==~
regexp_macro) ->
1106 msg_declare_macro s;
1107 let info = TH.info_of_tok macro
.tok
in
1108 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1110 (* need retag this const, otherwise ambiguity in grammar
1111 21: shift/reduce conflict (shift 121, reduce 137) on Tconst
1112 decl2 : Tstatic . TMacroDecl TOPar argument_list TCPar ...
1113 decl2 : Tstatic . Tconst TMacroDecl TOPar argument_list TCPar ...
1114 storage_class_spec : Tstatic . (137)
1116 const
.tok
<- TMacroDeclConst
(TH.info_of_tok const
.tok
);
1118 find_macro_lineparen (xs
)
1121 (* same but without trailing ';'
1123 * I do not put the final ';' because it can be on a multiline and
1124 * because of the way mk_line is coded, we will not have access to
1125 * this ';' on the next line, even if next to the ')' *)
1127 ([PToken
({tok
= Tstatic _
});
1128 PToken
({tok
= TIdent
(s,_
)} as macro
);
1129 Parenthised
(xxs
,info_parens
);
1133 when s ==~
regexp_macro ->
1135 msg_declare_macro s;
1136 let info = TH.info_of_tok macro
.tok
in
1137 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1139 find_macro_lineparen (xs
)
1142 (* on multiple lines *)
1145 (PToken
({tok
= Tstatic _
})::[]
1149 [PToken
({tok
= TIdent
(s,_
)} as macro
);
1150 Parenthised
(xxs
,info_parens
);
1151 PToken
({tok
= TPtVirg _
});
1156 when (s ==~
regexp_macro) ->
1158 msg_declare_macro s;
1159 let info = TH.info_of_tok macro
.tok
in
1160 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1162 find_macro_lineparen (xs
)
1165 | (Line
(* initializer case *)
1167 PToken
({tok
= Tstatic _
}) ::
1168 PToken
({tok
= TIdent
(s,_
)} as macro
) ::
1169 Parenthised
(xxs
,info_parens
) ::
1170 PToken
({tok
= TEq _
}) :: rest
1173 when (s ==~
regexp_macro) ->
1175 msg_declare_macro s;
1176 let info = TH.info_of_tok macro
.tok
in
1177 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1179 (* continue with the rest of the line *)
1180 find_macro_lineparen ((Line
(rest
))::xs
)
1183 | (Line
(* multi-line initializer case *)
1185 (PToken
({tok
= Tstatic _
})::[]
1189 PToken
({tok
= Tstatic _
}) ::
1190 PToken
({tok
= TIdent
(s,_
)} as macro
) ::
1191 Parenthised
(xxs
,info_parens
) ::
1192 PToken
({tok
= TEq _
}) :: rest
1195 when (s ==~
regexp_macro) ->
1197 msg_declare_macro s;
1198 let info = TH.info_of_tok macro
.tok
in
1199 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1201 (* continue with the rest of the line *)
1202 find_macro_lineparen ((Line
(rest
))::xs
)
1205 (* linuxext: ex: DECLARE_BITMAP();
1207 * Here I use regexp_declare and not regexp_macro because
1208 * Sometimes it can be a FunCallMacro such as DEBUG(foo());
1209 * Here we don't have the preceding 'static' so only way to
1210 * not have positive is to restrict to .*DECLARE.* macros.
1212 * but there is a grammar rule for that, so don't need this case anymore
1213 * unless the parameter of the DECLARE_xxx are weird and can not be mapped
1214 * on a argument_list
1218 ([PToken
({tok
= TIdent
(s,_
)} as macro
);
1219 Parenthised
(xxs
,info_parens
);
1220 PToken
({tok
= TPtVirg _
});
1224 when (s ==~
regexp_declare) ->
1226 msg_declare_macro s;
1227 let info = TH.info_of_tok macro
.tok
in
1228 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1230 find_macro_lineparen (xs
)
1236 * Could also transform the TIdent in a TMacroTop but can have false
1237 * positive, so easier to just change the TCPar and so just solve
1238 * the end-of-stream pb of ocamlyacc
1241 ([PToken
({tok
= TIdent
(s,ii); col
= col1
; where
= ctx
} as _macro
);
1242 Parenthised
(xxs
,info_parens
);
1245 ::xs
when col1
=|= 0
1248 (* to reduce number of false positive *)
1250 | (Line
(PToken
({col
= col2
} as other
)::restline2
))::_
->
1251 TH.is_eof other
.tok
|| (col2
=|= 0 &&
1252 (match other
.tok
with
1253 | TOBrace _
-> false (* otherwise would match funcdecl *)
1254 | TCBrace _
when ctx
<> InFunction
-> false
1259 | tok
when TH.is_binary_operator tok
-> false
1270 msg_macro_toplevel_noptvirg s;
1271 (* just to avoid the end-of-stream pb of ocamlyacc *)
1272 let tcpar = Common.last info_parens
in
1273 tcpar.tok
<- TCParEOL
(TH.info_of_tok
tcpar.tok
);
1275 (*macro.tok <- TMacroTop (s, TH.info_of_tok macro.tok);*)
1279 find_macro_lineparen (xs
)
1283 (* macro with parameters
1288 ([PToken
({tok
= TIdent
(s,ii); col
= col1
; where
= ctx
} as macro
);
1289 Parenthised
(xxs
,info_parens
);
1293 (PToken
({col
= col2
} as other
)::restline2
1296 (* when s ==~ regexp_macro *)
1298 (* This can give a false positive for K&R functions if the function
1299 name is in the same column as the first parameter declaration. *)
1302 (match other
.tok
with
1303 | TOBrace _
-> false (* otherwise would match funcdecl *)
1304 | TCBrace _
when ctx
<> InFunction
-> false
1309 | tok
when TH.is_binary_operator tok
-> false
1316 (match other
.tok
, restline2
with
1317 | TCBrace _
, _
when ctx
=*= InFunction
-> true
1318 | Treturn _
, _
-> true
1320 | Telse _
, _
-> true
1322 (* case of label, usually put in first line *)
1323 | TIdent _
, (PToken
({tok
= TDotDot _
}))::_
->
1335 if col1
=|= 0 then ()
1337 msg_macro_noptvirg s;
1338 macro
.tok
<- TMacroStmt
(s, TH.info_of_tok macro
.tok
);
1339 [Parenthised
(xxs
, info_parens
)] +>
1340 iter_token_paren
(TV.set_as_comment
Token_c.CppMacro
);
1343 find_macro_lineparen (line2
::xs
)
1345 (* linuxext:? single macro
1350 * todo: factorize code with previous rule ?
1353 ([PToken
({tok
= TIdent
(s,ii); col
= col1
; where
= ctx
} as macro
);
1357 (PToken
({col
= col2
} as other
)::restline2
1360 (* when s ==~ regexp_macro *)
1364 col1
<> 0 && (* otherwise can match typedef of fundecl*)
1365 (match other
.tok
with
1366 | TPtVirg _
-> false
1368 | TCBrace _
when ctx
<> InFunction
-> false
1370 | tok
when TH.is_binary_operator tok
-> false
1375 (match other
.tok
with
1376 | TCBrace _
when ctx
=*= InFunction
-> true
1386 msg_macro_noptvirg_single s;
1387 macro
.tok
<- TMacroStmt
(s, TH.info_of_tok macro
.tok
);
1389 find_macro_lineparen (line2
::xs
)
1392 find_macro_lineparen xs
1396 (* ------------------------------------------------------------------------- *)
1397 (* define tobrace init *)
1398 (* ------------------------------------------------------------------------- *)
1400 let rec find_define_init_brace_paren xs
=
1405 (* mainly for firefox *)
1406 | (PToken
{tok
= TDefine _
})
1407 ::(PToken
{tok
= TIdentDefine
(s,_
)})
1408 ::(PToken
({tok
= TOBrace i1
} as tokbrace
))
1413 match tok2
.tok
, tok3
.tok
with
1414 | TInt _
, TComma _
-> true
1415 | TString _
, TComma _
-> true
1416 | TIdent _
, TComma _
-> true
1422 pr2_cpp("found define initializer: " ^
s);
1423 tokbrace
.tok
<- TOBraceDefineInit i1
;
1428 (* mainly for linux, especially in sound/ *)
1429 | (PToken
{tok
= TDefine _
})
1430 ::(PToken
{tok
= TIdentDefine
(s,_
)})
1431 ::(Parenthised
(xxx
, info_parens
))
1432 ::(PToken
({tok
= TOBrace i1
} as tokbrace
))
1437 match tok2
.tok
, tok3
.tok
with
1438 | TInt _
, TComma _
-> true
1439 | TDot _
, TIdent _
-> true
1440 | TIdent _
, TComma _
-> true
1446 pr2_cpp("found define initializer with param: " ^
s);
1447 tokbrace
.tok
<- TOBraceDefineInit i1
;
1455 | (PToken
x)::xs
-> aux xs
1456 | (Parenthised
(xxs
, info_parens
))::xs
->
1457 (* not need for tobrace init:
1458 * xxs +> List.iter aux;
1465 (* ------------------------------------------------------------------------- *)
1467 (* ------------------------------------------------------------------------- *)
1469 (* obsolete now with macro expansion ? get some regression if comment.
1470 * todo: if do bad decision here, then it can influence other phases
1471 * and make it hard to parse. So maybe when have a parse error, should
1472 * undo some of the guess those heuristics have done, and restore
1473 * the original token value.
1476 let rec find_actions = function
1479 | PToken
({tok
= TIdent
(s,ii)})
1480 ::Parenthised
(xxs
,info_parens
)
1483 xxs
+> List.iter
find_actions;
1484 let modified = find_actions_params xxs
in
1486 then msg_macro_higher_order s
1491 and find_actions_params xxs
=
1492 xxs
+> List.fold_left
(fun acc xs
->
1493 let toks = tokens_of_paren xs
in
1494 if toks +> List.exists
(fun x -> TH.is_statement
x.tok
)
1495 (* undo: && List.length toks > 1
1496 * good for sparse, not good for linux
1499 xs
+> iter_token_paren
(fun x ->
1502 (* certainly because paren detection had a pb because of
1503 * some ifdef-exp. Do similar additional checking than
1504 * what is done in TV.set_as_comment.
1506 pr2 "PB: weird, I try to tag an EOF token as an action"
1508 (* cf tests-bis/no_cpar_macro.c *)
1511 pr2 "PB: weird, I try to tag an EOM token as an action"
1513 x.tok
<- TAction
(TH.info_of_tok
x.tok
);
1522 (* ------------------------------------------------------------------------- *)
1523 (* main fix cpp function *)
1524 (* ------------------------------------------------------------------------- *)
1526 let filter_cpp_stuff xs
=
1530 | tok
when TH.is_comment tok
-> false
1531 (* don't want drop the define, or if drop, have to drop
1532 * also its body otherwise the line heuristics may be lost
1533 * by not finding the TDefine in column 0 but by finding
1534 * a TDefineIdent in a column > 0
1536 | Parser_c.TDefine _
-> true
1537 | tok
when TH.is_cpp_instruction tok
-> false
1542 let insert_virtual_positions l
=
1543 let strlen x = String.length
(Ast_c.str_of_info
x) in
1544 let rec loop prev offset
acc = function
1547 let ii = TH.info_of_tok
x in
1549 TH.visitor_info_of_tok
(function ii -> Ast_c.rewrap_pinfo pi
ii) x in
1550 match Ast_c.pinfo_of_info
ii with
1551 Ast_c.OriginTok pi
->
1552 let prev = Ast_c.parse_info_of_info
ii in
1553 loop prev (strlen ii) (x::acc) xs
1554 | Ast_c.ExpandedTok
(pi
,_
) ->
1555 let x'
= inject (Ast_c.ExpandedTok
(pi
,(prev,offset
))) in
1556 loop prev (offset
+ (strlen ii)) (x'
::acc) xs
1557 | Ast_c.FakeTok
(s,_
) ->
1558 let x'
= inject (Ast_c.FakeTok
(s,(prev,offset
))) in
1559 loop prev (offset
+ (strlen ii)) (x'
::acc) xs
1560 | Ast_c.AbstractLineTok _
-> failwith
"abstract not expected" in
1561 let rec skip_fake = function
1564 let ii = TH.info_of_tok
x in
1565 match Ast_c.pinfo_of_info
ii with
1566 | Ast_c.OriginTok pi
->
1567 let prev = Ast_c.parse_info_of_info
ii in
1568 let res = loop prev (strlen ii) [] xs
in
1570 | _
-> x::skip_fake xs
in
1573 (* ------------------------------------------------------------------------- *)
1575 let fix_tokens_cpp2 ~macro_defs tokens
=
1576 let tokens2 = ref (tokens
+> Common.acc_map
TV.mk_token_extended
) in
1579 (* the order is important, if you put the action heuristic first,
1580 * then because of ifdef, can have not closed paren
1581 * and so may believe that higher order macro
1582 * and it will eat too much tokens. So important to do
1585 * I recompute multiple times cleaner cos the mutable
1586 * can have be changed and so may have more comments
1587 * in the token original list.
1591 commentize_skip_start_to_end !tokens2;
1594 let cleaner = !tokens2 +> List.filter
(fun x ->
1595 (* is_comment will also filter the TCommentCpp created in
1596 * commentize_skip_start_to_end *)
1597 not
(TH.is_comment
x.tok
) (* could filter also #define/#include *)
1599 let ifdef_grouped = TV.mk_ifdef
cleaner in
1600 set_ifdef_parenthize_info ifdef_grouped;
1602 find_ifdef_funheaders ifdef_grouped;
1603 find_ifdef_bool ifdef_grouped;
1604 find_ifdef_mid ifdef_grouped;
1605 (* change order ? maybe cparen_else heuristic make some of the funheaders
1606 * heuristics irrelevant ?
1608 find_ifdef_cparen_else ifdef_grouped;
1609 adjust_inifdef_include ifdef_grouped;
1613 let cleaner = !tokens2 +> filter_cpp_stuff in
1615 let paren_grouped = TV.mk_parenthised
cleaner in
1616 Cpp_token_c.apply_macro_defs
1617 ~
msg_apply_known_macro
1618 ~
msg_apply_known_macro_hint
1619 macro_defs
paren_grouped;
1620 (* because the before field is used by apply_macro_defs *)
1621 tokens2 := TV.rebuild_tokens_extented
!tokens2;
1623 (* tagging contextual info (InFunc, InStruct, etc). Better to do
1624 * that after the "ifdef-simplification" phase.
1626 let cleaner = !tokens2 +> List.filter
(fun x ->
1627 not
(TH.is_comment
x.tok
) (* could filter also #define/#include *)
1630 let brace_grouped = TV.mk_braceised
cleaner in
1631 set_context_tag
brace_grouped;
1634 let cleaner = !tokens2 +> filter_cpp_stuff in
1636 let paren_grouped = TV.mk_parenthised
cleaner in
1637 let line_paren_grouped = TV.mk_line_parenthised
paren_grouped in
1638 find_define_init_brace_paren paren_grouped;
1639 find_string_macro_paren paren_grouped;
1640 find_macro_lineparen line_paren_grouped;
1641 find_macro_paren paren_grouped;
1644 (* obsolete: actions ? not yet *)
1645 let cleaner = !tokens2 +> filter_cpp_stuff in
1646 let paren_grouped = TV.mk_parenthised
cleaner in
1647 find_actions paren_grouped;
1651 insert_virtual_positions (!tokens2 +> Common.acc_map
(fun x -> x.tok
))
1654 let time_hack1 ~macro_defs a
=
1655 Common.profile_code_exclusif
"HACK" (fun () -> fix_tokens_cpp2 ~macro_defs a
)
1657 let fix_tokens_cpp ~macro_defs a
=
1658 Common.profile_code
"C parsing.fix_cpp" (fun () -> time_hack1 ~macro_defs a
)
1662 let can_be_on_top_level tl
=
1677 (*****************************************************************************)
1678 (* Lexing with lookahead *)
1679 (*****************************************************************************)
1681 (* Why using yet another parsing_hack technique ? The fix_xxx where do
1682 * some pre-processing on the full list of tokens is not enough ?
1683 * No cos sometimes we need more contextual info, and even if
1684 * set_context() tries to give some contextual info, it's not completely
1685 * accurate so the following code give yet another alternative, yet another
1686 * chance to transform some tokens.
1688 * todo?: maybe could try to get rid of this technique. Maybe a better
1689 * set_context() would make possible to move this code using a fix_xx
1692 * LALR(k) trick. We can do stuff by adding cases in lexer_c.mll, but
1693 * it is more general to do it via my LALR(k) tech. Because here we can
1694 * transform some token give some context information. So sometimes it
1695 * makes sense to transform a token in one context, sometimes not, and
1696 * lex can not provide us this context information. Note that the order
1697 * in the pattern matching in lookahead is important. Do not cut/paste.
1699 * Note that in next there is only "clean" tokens, there is no comment
1700 * or space tokens. This is done by the caller.
1704 open Lexer_parser
(* for the fields of lexer_hint type *)
1706 let not_struct_enum = function
1707 | (Parser_c.Tstruct _
| Parser_c.Tunion _
| Parser_c.Tenum _
)::_
-> false
1710 let pointer ?
(followed_by
=fun _
-> true)
1711 ?
(followed_by_more
=fun _
-> true) ts
=
1714 | TMul _
:: rest
-> loop rest
1715 | TAnd _
:: rest
when !Flag.c_plus_plus
-> loop rest
1716 | t
:: ts'
-> followed_by t
&& followed_by_more ts'
1717 | [] -> failwith
"unexpected end of token stream" in
1719 | TMul _
:: rest
-> loop rest
1720 | TAnd _
:: rest
when !Flag.c_plus_plus
-> loop rest
1723 let ident = function
1727 let is_type = function
1743 let is_cparen = function (TCPar _
) -> true | _
-> false
1744 let is_oparen = function (TOPar _
) -> true | _
-> false
1746 let rec not_has_type_before f xs
=
1748 | [] -> raise
(Impossible
666)
1752 else if is_type x then
1755 not_has_type_before f xs
1757 (* This function is inefficient, because it will look over a K&R header,
1758 or function prototype multiple times. At least when we see a , and are in a
1759 parameter list, we know we will eventually see a close paren, and it
1760 should come fairly soon. *)
1762 let l1 = drop_until
is_cparen l
in
1764 (TCPar _
) :: (TOCro _
) :: _
-> false
1765 | (TCPar _
) :: _
-> true
1768 (* (a)(b) is ambiguous, because (a) could be a function name or a cast.
1769 At this point, we just see an ident for a; we don't know if it is eg a local
1770 variable. This function sees at least if b is the only argument, ie there
1771 are no commas at top level *)
1772 let paren_before_comma l
=
1773 let rec loop level
= function
1775 | (TComma _
)::_
when level
= 1 -> false
1776 | (TCPar _
)::_
when level
= 1 -> true
1777 | (TCPar _
)::rest
-> loop (level
-1) rest
1778 | (TOPar _
)::rest
-> loop (level
+1) rest
1779 | x::rest
-> loop level rest
in
1782 let lookahead2 ~pass next before
=
1783 match (next
, before
) with
1786 (* yy xx( and in function *)
1787 | TOPar i1
::_
, TIdent
(s,i2
)::TypedefIdent _
::_
1788 when !Flag.c_plus_plus
&& (LP.current_context
() = (LP.InFunction
)) ->
1789 pr2_cpp("constructed_object: " ^
s);
1790 TOParCplusplusInit i1
1791 | TOPar i1
::_
, TIdent
(s,i2
)::ptr
1792 when !Flag.c_plus_plus
1793 && pointer ~followed_by
:(function TypedefIdent _
-> true | _
-> false) ptr
1794 && (LP.current_context
() = (LP.InFunction
)) ->
1795 pr2_cpp("constructed_object: " ^
s);
1796 TOParCplusplusInit i1
1797 | TypedefIdent
(s,i
)::TOPar i1
::_
,_
1798 when !Flag.c_plus_plus
&& (LP.current_context
() = (LP.InFunction
)) ->
1801 (*-------------------------------------------------------------*)
1802 (* typedef inference, parse_typedef_fix3 *)
1803 (*-------------------------------------------------------------*)
1805 | (TIdent
(s,i1
)::TIdent
(s2
,i2
)::_
, _
) when not_struct_enum before
&& s =$
= s2
1807 (* (take_safe 1 !passed_tok <> [TOPar]) -> *)
1809 (* parse_typedef_fix3:
1810 * acpi_object acpi_object;
1811 * etait mal parsé, car pas le temps d'appeler dt() dans le type_spec.
1812 * Le parser en interne a deja appelé le prochain token pour pouvoir
1813 * decider des choses.
1814 * => special case in lexer_heuristic, again
1816 if !Flag_parsing_c.debug_typedef
1817 then pr2 ("TYPEDEF: disable typedef cos special case: " ^
s);
1820 LP.disable_typedef
();
1821 msg_typedef s i1
1; LP.add_typedef_root
s;
1822 TypedefIdent
(s, i1
)
1827 | (TOCro i1
:: _
, Tdelete _
:: _
)
1828 when !Flag.c_plus_plus
->
1829 TCommentCpp
(Token_c.CppDirective
, i1
)
1831 | (TCCro i1
:: _
, Tdelete _
:: _
)
1832 when !Flag.c_plus_plus
->
1833 TCommentCpp
(Token_c.CppDirective
, i1
)
1836 | ((TString
((s, _
), i1
) | TMacroString
(s, i1
)) :: _
, Textern _
:: _
)
1837 when !Flag.c_plus_plus
->
1838 TCommentCpp
(Token_c.CppDirective
, i1
)
1841 | (Tconst i1
:: TOBrace _
:: _
, TCPar _
:: _
)
1842 when !Flag.c_plus_plus
->
1843 TCommentCpp
(Token_c.CppDirective
, i1
)
1846 | (TIdent
(s, i1
)::(Tconst _
|Tvolatile _
|Trestrict _
)::type_
::_
, _
)
1847 when not_struct_enum before
1849 TCommentCpp
(Token_c.CppDirective
, i1
)
1852 | (TIdent
(s, i1
)::Tstruct _
::_
, _
)
1853 when not_struct_enum before
->
1854 TCommentCpp
(Token_c.CppDirective
, i1
)
1857 | (TIdent
(s, i1
)::type_
::_
, _
)
1858 when not_struct_enum before
1860 TCommentCpp
(Token_c.CppDirective
, i1
)
1863 | (TIdent
(s, i1
)::TIdent
(s2
, i2
)::_
, seen
::_
)
1864 when not_struct_enum before
1869 TCommentCpp
(Token_c.CppDirective
, i1
)
1871 (* exception to next rule *)
1872 | (TIdent
(s2
, i2
)::TOPar _
::_
, TIdent
(s1
, i1
)::seen
::_
)
1873 when not_struct_enum before
1874 && is_macro s2
&& is_type seen
->
1877 | (TIdent
(s2
, i2
)::_
, TIdent
(s, i1
)::seen
::_
)
1878 when not_struct_enum before
1879 && is_macro s2
&& is_type seen
->
1880 TCommentCpp
(Token_c.CppDirective
, i2
)
1883 | (TIdent
(s, i1
)::ptr
, seen
::_
)
1884 when not_struct_enum before
1885 && pointer ptr
&& is_type seen
->
1886 TCommentCpp
(Token_c.CppDirective
, i1
)
1889 | (TIdent
(s, i1
)::TIdent
(s2
, i2
)::_
, ptr
)
1890 when not_struct_enum before
1895 TCommentCpp
(Token_c.CppDirective
, i1
)
1897 (* exception to next rule *)
1898 | (TIdent
(s2
, i2
)::TOPar _
::_
, TIdent
(s1
, i1
)::ptr
)
1899 when not_struct_enum before
1900 && is_macro s2
&& pointer ptr
->
1903 | (TIdent
(s2
, i2
)::_
, TIdent
(s, i1
)::ptr
)
1904 when not_struct_enum before
1905 && is_macro s2
&& pointer ptr
->
1906 TCommentCpp
(Token_c.CppDirective
, i2
)
1908 (* exception to next rule *)
1909 | (TIdent
(s2
, i2
)::TOPar _
:: _
, TIdent
(s, i1
)::seen
::_
)
1910 when not_struct_enum before
1911 && is_macro s2
&& is_type seen
->
1914 | (TIdent
(s2
, i2
)::_
, TIdent
(s, i1
)::seen
::_
)
1915 when not_struct_enum before
1916 && is_macro s2
&& is_type seen
->
1917 TCommentCpp
(Token_c.CppDirective
, i2
)
1919 (* xx * yy AND in paramdecl *)
1920 | (TIdent
(s, i1
)::ptr
, _
)
1921 when not_struct_enum before
&& (LP.current_context
() =*= LP.InParameter
)
1922 && pointer ~followed_by
:(function TIdent _
-> true | _
-> false) ptr
1924 msg_typedef s i1
14; LP.add_typedef_root
s;
1925 TypedefIdent
(s, i1
)
1928 (* exception to next rule *)
1929 | (TIdent
(s, i1
)::TIdent
(s2
, i2
)::TOPar _
::_
, _
) when not_struct_enum before
1930 && ok_typedef s && is_macro s2
1934 | (TIdent
(s, i1
)::TIdent
(s2
, i2
)::_
, _
) when not_struct_enum before
1937 (* && not_annot s2 BUT lead to false positive*)
1938 msg_typedef s i1
2; LP.add_typedef_root
s;
1939 TypedefIdent
(s, i1
)
1943 | (TIdent
(s, i1
)::Tinline i2
::_
, _
) when not_struct_enum before
1947 msg_typedef s i1
3; LP.add_typedef_root
s;
1948 TypedefIdent
(s, i1
)
1951 (* [,(] xx [,)] AND param decl *)
1952 | (TIdent
(s, i1
)::(((TComma _
|TCPar _
)::_
) as rest
) ,
1953 ((TComma _
|TOPar _
)::_
as bef
))
1954 when not_struct_enum before
&& (LP.current_context
() =*= LP.InParameter
)
1956 && not_has_type_before is_cparen rest
1957 && not_has_type_before is_oparen bef
1962 | (TIdent
(s, i1
)::((TComma _
|TCPar _
)::_
) , (TComma _
|TOPar _
)::_
)
1963 when not_struct_enum before
&& (LP.current_context
() =*= LP.InParameter
)
1967 msg_typedef s i1
4; LP.add_typedef_root
s;
1968 TypedefIdent
(s, i1
)
1971 (* specialcase: [,(] xx* [,)] *)
1972 | (TIdent
(s, i1
)::ptr
, (*(TComma _|TOPar _)::*)_
)
1973 when pointer ~followed_by
:(function TComma _
|TCPar _
-> true | _
-> false) ptr
1974 && not_struct_enum before
1975 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1979 msg_typedef s i1
5; LP.add_typedef_root
s;
1980 TypedefIdent
(s, i1
)
1984 (* specialcase: [,(] xx** [,)] *)
1985 | (TIdent
(s, i1
)::TMul _
::TMul _
::(TComma _
|TCPar _
)::_
, (*(TComma _|TOPar _)::*)_
)
1986 when not_struct_enum before
1987 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1991 msg_typedef s i1
6; LP.add_typedef_root
s;
1992 TypedefIdent
(s, i1
)
1996 (* xx const * USELESS because of next rule ? *)
1997 | (TIdent
(s, i1
)::(Tconst _
|Tvolatile _
|Trestrict _
)::TMul _
::_
, _
)
1998 when not_struct_enum before
1999 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2003 msg_typedef s i1
7; LP.add_typedef_root
s;
2004 TypedefIdent
(s, i1
)
2007 | (TIdent
(s, i1
)::(Tconst _
|Tvolatile _
|Trestrict _
)::_
, _
)
2008 when not_struct_enum before
2010 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2013 msg_typedef s i1
8; LP.add_typedef_root
s;
2014 TypedefIdent
(s, i1
)
2018 | (TIdent
(s, i1
)::ptr
, _
)
2019 when pointer ~followed_by
:(function Tconst _
| Tvolatile _
| Trestrict _
-> true | _
-> false) ptr
2020 && not_struct_enum before
2024 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2026 msg_typedef s i1
9; LP.add_typedef_root
s;
2027 TypedefIdent
(s, i1
)
2031 | (TIdent
(s, i1
)::TCPar _
::_
, (Tconst _
| Tvolatile _
|Trestrict _
)::TOPar _
::_
) when
2034 msg_typedef s i1
10; LP.add_typedef_root
s;
2035 TypedefIdent
(s, i1
)
2039 (* ( xx ) [sizeof, ~] *)
2040 | (TIdent
(s, i1
)::TCPar _
::(Tsizeof _
|TTilde _
)::_
, TOPar _
::_
)
2041 when not_struct_enum before
2045 msg_typedef s i1
11; LP.add_typedef_root
s;
2046 TypedefIdent
(s, i1
)
2048 (* [(,] xx [ AND parameterdeclaration *)
2049 | (TIdent
(s, i1
)::TOCro _
::_
, (TComma _
|TOPar _
)::_
)
2050 when (LP.current_context
() =*= LP.InParameter
)
2054 msg_typedef s i1
12; LP.add_typedef_root
s;
2055 TypedefIdent
(s, i1
)
2057 (*------------------------------------------------------------*)
2058 (* if 'x*y' maybe an expr, maybe just a classic multiplication *)
2059 (* but if have a '=', or ',' I think not *)
2060 (*------------------------------------------------------------*)
2062 (* static xx * yy *)
2063 | (TIdent
(s, i1
)::ptr
,
2064 (Tregister _
|Tstatic _
|Tvolatile _
|Tconst _
|Trestrict _
)::_
) when
2065 pointer ~followed_by
:(function TIdent _
-> true | _
-> false) ptr
2069 msg_typedef s i1
13; LP.add_typedef_root
s;
2070 TypedefIdent
(s, i1
)
2072 (* TODO xx * yy ; AND in start of compound element *)
2075 (* xx * yy, AND in paramdecl *)
2076 | (TIdent
(s, i1
)::ptr
, _
)
2077 when not_struct_enum before
&& (LP.current_context
() =*= LP.InParameter
)
2078 && pointer ~followed_by
:(function TIdent _
-> true | _
-> false)
2079 ~followed_by_more
:(function TComma _
:: _
-> true | _
-> false) ptr
2083 msg_typedef s i1
14; LP.add_typedef_root
s;
2084 TypedefIdent
(s, i1
)
2087 (* xx * yy ; AND in Toplevel, except when have = before *)
2088 | (TIdent
(s, i1
)::TMul _
::TIdent
(s2
, i2
)::TPtVirg _
::_
, TEq _
::_
) ->
2090 | (TIdent
(s, i1
)::ptr
, _
)
2091 when not_struct_enum before
2092 && pointer ~followed_by
:(function TIdent _
-> true | _
-> false)
2093 ~followed_by_more
:(function TPtVirg _
:: _
-> true | _
-> false) ptr
2094 && (LP.is_top_or_struct
(LP.current_context
()))
2097 msg_typedef s i1
15; LP.add_typedef_root
s;
2098 TypedefIdent
(s, i1
)
2100 (* xx * yy , AND in Toplevel *)
2101 | (TIdent
(s, i1
)::ptr
, _
)
2102 when not_struct_enum before
&& (LP.current_context
() =*= LP.InTopLevel
)
2104 && pointer ~followed_by
:(function TIdent _
-> true | _
-> false)
2105 ~followed_by_more
:(function TComma _
:: _
-> true | _
-> false) ptr
2108 msg_typedef s i1
16; LP.add_typedef_root
s;
2109 TypedefIdent
(s, i1
)
2111 (* xx * yy ( AND in Toplevel *)
2112 | (TIdent
(s, i1
)::ptr
, _
)
2113 when not_struct_enum before
2114 && (LP.is_top_or_struct
(LP.current_context
()))
2116 && pointer ~followed_by
:(function TIdent _
-> true | _
-> false)
2117 ~followed_by_more
:(function TOPar _
:: _
-> true | _
-> false) ptr
2120 msg_typedef s i1
17; LP.add_typedef_root
s;
2121 TypedefIdent
(s, i1
)
2124 (* todo? enough ? cos in struct def we can have some expression ! *)
2125 | (TIdent
(s, i1
)::ptr
, _
)
2126 when not_struct_enum before
2127 && (LP.is_top_or_struct
(LP.current_context
()))
2129 && pointer ~followed_by
:(function TIdent _
-> true | _
-> false)
2130 ~followed_by_more
:(function TOCro _
:: _
-> true | _
-> false) ptr
2133 msg_typedef s i1
18; LP.add_typedef_root
s;
2134 TypedefIdent
(s, i1
)
2136 (* u16: 10; in struct *)
2137 | (TIdent
(s, i1
)::TDotDot _
::_
, (TOBrace _
| TPtVirg _
)::_
)
2138 when (LP.is_top_or_struct
(LP.current_context
()))
2142 msg_typedef s i1
19; LP.add_typedef_root
s;
2143 TypedefIdent
(s, i1
)
2146 (* why need TOPar condition as stated in preceding rule ? really needed ? *)
2147 (* YES cos at toplevel can have some expression !! for instance when *)
2148 (* enter in the dimension of an array *)
2150 | (TIdent s::TMul::TIdent s2::_ , _)
2151 when (take_safe 1 !passed_tok <> [Tstruct] &&
2152 (take_safe 1 !passed_tok <> [Tenum]))
2154 !LP._lexer_hint = Some LP.Toplevel ->
2155 msg_typedef s 20; LP.add_typedef_root s;
2160 | (TIdent
(s, i1
)::ptr
, _
)
2161 when not_struct_enum before
2163 && pointer ~followed_by
:(function TIdent _
-> true | _
-> false)
2164 ~followed_by_more
:(function TEq _
:: _
-> true | _
-> false) ptr
2167 msg_typedef s i1
21; LP.add_typedef_root
s;
2168 TypedefIdent
(s, i1
)
2171 (* xx * yy) AND in paramdecl *)
2172 | (TIdent
(s, i1
)::ptr
, _
)
2173 when not_struct_enum before
&& (LP.current_context
() =*= LP.InParameter
)
2175 && pointer ~followed_by
:(function TIdent _
-> true | _
-> false)
2176 ~followed_by_more
:(function TCPar _
:: _
-> true | _
-> false) ptr
2179 msg_typedef s i1
22; LP.add_typedef_root
s;
2180 TypedefIdent
(s, i1
)
2183 (* xx * yy; *) (* wrong ? *)
2184 | (TIdent
(s, i1
)::ptr
,
2185 (TOBrace _
| TPtVirg _
)::_
) when not_struct_enum before
2187 && pointer ~followed_by
:(function TIdent _
-> true | _
-> false)
2188 ~followed_by_more
:(function TPtVirg _
:: _
-> true | _
-> false) ptr
2191 msg_typedef s i1
23; LP.add_typedef_root
s;
2192 msg_maybe_dangereous_typedef s;
2193 TypedefIdent
(s, i1
)
2196 (* xx * yy, and ';' before xx *) (* wrong ? *)
2197 | (TIdent
(s, i1
)::ptr
,
2198 (TOBrace _
| TPtVirg _
)::_
) when
2200 && pointer ~followed_by
:(function TIdent _
-> true | _
-> false)
2201 ~followed_by_more
:(function TComma _
:: _
-> true | _
-> false) ptr
2204 msg_typedef s i1
24; LP.add_typedef_root
s;
2205 TypedefIdent
(s, i1
)
2209 | (TIdent
(s, i1
)::ptr
, _
)
2210 when s ==~
regexp_typedef && not_struct_enum before
2211 (* struct user_info_t sometimes *)
2213 && pointer ~followed_by
:(function TIdent _
-> true | _
-> false) ptr
2216 msg_typedef s i1
25; LP.add_typedef_root
s;
2217 TypedefIdent
(s, i1
)
2219 (* xx ** yy *) (* wrong ? *)
2220 | (TIdent
(s, i1
)::TMul _
::TMul _
::TIdent
(s2
, i2
)::_
, _
)
2221 when not_struct_enum before
2222 && (LP.current_context
() =*= LP.InParameter
)
2226 msg_typedef s i1
26; LP.add_typedef_root
s;
2227 TypedefIdent
(s, i1
)
2229 (* xx ** yy *) (* wrong ? *)
2230 | (TIdent
(s, i1
)::TMul _
::TMul _
::TIdent
(s2
, i2
)::_
, (TOBrace _
| TPtVirg _
)::_
)
2231 when not_struct_enum before
2232 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2234 (* christia : this code catches 'a * *b' which is wrong
2238 msg_typedef s i1
26; LP.add_typedef_root
s;
2239 TypedefIdent
(s, i1
)
2242 | (TIdent
(s, i1
)::TMul _
::TMul _
::TMul _
::TIdent
(s2
, i2
)::_
, _
)
2243 when not_struct_enum before
2245 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2248 msg_typedef s i1
27; LP.add_typedef_root
s;
2249 TypedefIdent
(s, i1
)
2252 | (TIdent
(s, i1
)::TMul _
::TMul _
::TCPar _
::_
, _
)
2253 when not_struct_enum before
2254 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2258 msg_typedef s i1
28; LP.add_typedef_root
s;
2259 TypedefIdent
(s, i1
)
2263 (* ----------------------------------- *)
2264 (* old: why not do like for other rules and start with TIdent ?
2265 * why do TOPar :: TIdent :: ..., _ and not TIdent :: ..., TOPAr::_ ?
2266 * new: prefer now start with TIdent because otherwise the add_typedef_root
2267 * may have no effect if in second pass or if have disable the add_typedef.
2271 | (TIdent
(s, i1
)::TCPar i2
::(TIdent
(_
,i3
)|TInt
(_
,i3
))::_
,
2273 when not
(TH.is_stuff_taking_parenthized
x) (* &&
2274 Ast_c.line_of_info i2 =|= Ast_c.line_of_info i3 - why useful?
2277 && not
(ident x) (* possible K&R declaration *)
2280 msg_typedef s i1
29; LP.add_typedef_root
s;
2282 TypedefIdent
(s, i1
)
2286 * but false positif: typedef int (xxx_t)(...), so do specialisation below.
2289 | (TIdent (s, i1)::TCPar _::TOPar _::_ , (TOPar info)::x::_)
2290 when not (TH.is_stuff_taking_parenthized x)
2293 msg_typedef s 30; LP.add_typedef_root s;
2295 TypedefIdent
(s, i1
)
2297 (* special case: = (xx) ( yy) *)
2298 | (TIdent
(s, i1
)::TCPar _
::((TOPar _
::_
) as rest
) ,
2299 (TOPar
info)::(TEq _
|TEqEq _
)::_
)
2300 when ok_typedef s && paren_before_comma rest
2303 msg_typedef s i1
31; LP.add_typedef_root
s;
2305 TypedefIdent
(s, i1
)
2309 | (TIdent
(s, i1
)::ptr
, (TOPar
info)::_
)
2311 && pointer ~followed_by
:(function TCPar _
-> true | _
-> false)
2312 ~followed_by_more
:(function TIdent _
:: _
-> true | _
-> false) ptr
2315 msg_typedef s i1
32; LP.add_typedef_root
s;
2320 (* (xx){ ... } constructor *)
2321 | (TIdent
(s, i1
)::TCPar _
::TOBrace _
::_
, TOPar _
::x::_
)
2322 when (*s ==~ regexp_typedef && *) not
(TH.is_stuff_taking_parenthized
x)
2326 msg_typedef s i1
33; LP.add_typedef_root
s;
2327 TypedefIdent
(s, i1
)
2330 (* can have sizeof on expression
2331 | (Tsizeof::TOPar::TIdent s::TCPar::_, _) ->
2332 msg_typedef s; LP.add_typedef_root s;
2337 (* ----------------------------------- *)
2338 (* x ( *y )(params), function pointer *)
2339 | (TIdent
(s, i1
)::TOPar _
::TMul _
::TIdent _
::TCPar _
::TOPar _
::_
, _
)
2340 when not_struct_enum before
2344 msg_typedef s i1
34; LP.add_typedef_root
s;
2345 TypedefIdent
(s, i1
)
2347 (* x* ( *y )(params), function pointer 2 *)
2348 | (TIdent
(s, i1
)::TMul _
::TOPar _
::TMul _
::TIdent _
::TCPar _
::TOPar _
::_
, _
)
2349 when not_struct_enum before
2353 msg_typedef s i1
35; LP.add_typedef_root
s;
2354 TypedefIdent
(s, i1
)
2357 (*-------------------------------------------------------------*)
2359 (*-------------------------------------------------------------*)
2360 | ((TIfdef
(_
,ii) |TIfdefelse
(_
,ii) |TIfdefelif
(_
,ii) |TEndif
(_
,ii) |
2361 TIfdefBool
(_
,_
,ii)|TIfdefMisc
(_
,_
,ii)|TIfdefVersion
(_
,_
,ii))
2367 if not !Flag_parsing_c.ifdef_to_if
2368 then TCommentCpp (Ast_c.CppIfDirective, ii)
2371 (* not !LP._lexer_hint.toplevel *)
2372 if !Flag_parsing_c.ifdef_directive_passing
2376 if (LP.current_context
() =*= LP.InInitializer
)
2378 pr2_cpp "In Initializer passing"; (* cheat: dont count in stat *)
2379 incr
Stat.nIfdefInitializer
;
2381 pr2_cpp("IFDEF: or related inside function. I treat it as comment");
2382 incr
Stat.nIfdefPassing
;
2386 TIfdef _
| TIfdefMisc _
| TIfdefVersion _
-> Token_c.IfDef
2387 | TIfdefBool _
-> Token_c.IfDef0
2388 | TIfdefelse _
| TIfdefelif _
-> Token_c.Else
2389 | TEndif _
-> Token_c.Endif
2390 | _
-> Token_c.Other
in (* not possible here *)
2391 TCommentCpp
(Token_c.CppIfDirective
x, ii)
2395 | (TUndef
(ii) as x)::_
, _
2399 pr2_cpp("UNDEF: I treat it as comment");
2400 TCommentCpp
(Token_c.CppDirective
, ii)
2404 | (TCppDirectiveOther
(ii) as x)::_
, _
2408 pr2_cpp ("OTHER directive: I treat it as comment");
2409 TCommentCpp
(Token_c.CppDirective
, ii)
2413 (* If ident contain a for_each, then certainly a macro. But to be
2414 * sure should look if there is a '{' after the ')', but it requires
2415 * to count the '('. Because this can be expensive, we do that only
2416 * when the token contains "for_each".
2418 | (TIdent
(s, i1
)::TOPar _
::rest
, _
)
2419 when not
(LP.current_context
() =*= LP.InTopLevel
)
2420 (* otherwise a function such as static void loopback_enable(int i) {
2421 * will be considered as a loop
2425 if s ==~
regexp_foreach &&
2426 is_really_foreach (Common.take_safe
forLOOKAHEAD rest
)
2430 TMacroIterator
(s, i1
)
2434 (* (* christia: here insert support for macros on top level *)
2435 | TIdent
(s, ii) :: tl
:: _
, _
when
2436 can_be_on_top_level tl
&& LP.current_context
() = InTopLevel
->
2437 pr2_cpp ("'" ^
s ^
"' looks like a macro, I treat it as comment");
2438 TCommentCpp
(Token_c.CppDirective
, ii)
2441 (*-------------------------------------------------------------*)
2443 | _
-> raise
(Impossible
93)
2445 let lookahead ~pass a b
=
2446 Common.profile_code
"C parsing.lookahead" (fun () -> lookahead2 ~pass a b
)