1 (* Copyright (C) 2007, 2008 Yoann Padioleau
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License (GPL)
5 * version 2 as published by the Free Software Foundation.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * file license.txt for more details.
15 module TH
= Token_helpers
16 module LP
= Lexer_parser
18 module Stat
= Parsing_stat
22 (*****************************************************************************)
23 (* Some debugging functions *)
24 (*****************************************************************************)
27 if !Flag_parsing_c.verbose_parsing
31 if !Flag_parsing_c.debug_cpp
32 then Common.pr2_once
("CPP-" ^ s
)
35 let msg_gen cond is_known printer s
=
38 if not
(!Flag_parsing_c.filter_msg
)
45 (* In the following, there are some harcoded names of types or macros
46 * but they are not used by our heuristics! They are just here to
47 * enable to detect false positive by printing only the typedef/macros
48 * that we don't know yet. If we print everything, then we can easily
49 * get lost with too much verbose tracing information. So those
50 * functions "filter" some messages. So our heuristics are still good,
51 * there is no more (or not that much) hardcoded linux stuff.
57 | "u_char" | "u_short" | "u_int" | "u_long"
58 | "u8" | "u16" | "u32" | "u64"
59 | "s8" | "s16" | "s32" | "s64"
60 | "__u8" | "__u16" | "__u32" | "__u64"
71 | s
when s
=~
".*_t$" -> true
76 (* note: cant use partial application with let msg_typedef =
77 * because it would compute msg_typedef at compile time when
78 * the flag debug_typedef is always false
81 incr
Stat.nTypedefInfer
;
82 msg_gen (!Flag_parsing_c.debug_typedef
)
85 pr2_cpp ("TYPEDEF: promoting: " ^ s
)
89 let msg_maybe_dangereous_typedef s
=
90 if not
(is_known_typdef s
)
92 pr2 ("PB MAYBE: dangerous typedef inference, maybe not a typedef: " ^ s
)
96 let msg_declare_macro s
=
98 msg_gen (!Flag_parsing_c.debug_cpp
)
101 | "DECLARE_MUTEX" | "DECLARE_COMPLETION" | "DECLARE_RWSEM"
102 | "DECLARE_WAITQUEUE" | "DECLARE_WAIT_QUEUE_HEAD"
103 | "DEFINE_SPINLOCK" | "DEFINE_TIMER"
104 | "DEVICE_ATTR" | "CLASS_DEVICE_ATTR" | "DRIVER_ATTR"
105 | "SENSOR_DEVICE_ATTR"
107 | "DECLARE_WORK" | "DECLARE_TASKLET"
108 | "PORT_ATTR_RO" | "PORT_PMA_ATTR"
113 | s when s =~ "^DECLARE_.*" -> true
114 | s when s =~ ".*_ATTR$" -> true
115 | s when s =~ "^DEFINE_.*" -> true
121 (fun s
-> pr2_cpp ("MACRO: found declare-macro: " ^ s
))
126 incr
Stat.nIteratorHeuristic
;
127 pr2_cpp ("MACRO: found foreach: " ^ s
)
131 let msg_debug_macro s =
132 pr2_cpp ("MACRO: found debug-macro: " ^ s)
136 let msg_macro_noptvirg s
=
137 incr
Stat.nMacroStmt
;
138 pr2_cpp ("MACRO: found macro with param noptvirg: " ^ s
)
140 let msg_macro_toplevel_noptvirg s
=
141 incr
Stat.nMacroStmt
;
142 pr2_cpp ("MACRO: found toplevel macro noptvirg: " ^ s
)
144 let msg_macro_noptvirg_single s
=
145 incr
Stat.nMacroStmt
;
146 pr2_cpp ("MACRO: found single-macro noptvirg: " ^ s
)
151 let msg_macro_higher_order s
=
152 incr
Stat.nMacroHigherOrder
;
153 msg_gen (!Flag_parsing_c.debug_cpp
)
163 (fun s
-> pr2_cpp ("MACRO: found higher ordre macro : " ^ s
))
167 let msg_stringification s
=
168 incr
Stat.nMacroString
;
169 msg_gen (!Flag_parsing_c.debug_cpp
)
177 (* s when s =~ ".*STR.*" -> true *)
181 (fun s
-> pr2_cpp ("MACRO: found string-macro " ^ s
))
184 let msg_stringification_params s
=
185 incr
Stat.nMacroString
;
186 pr2_cpp ("MACRO: string-macro with params : " ^ s
)
190 let msg_apply_known_macro s
=
191 incr
Stat.nMacroExpand
;
192 pr2_cpp ("MACRO: found known macro = " ^ s
)
194 let msg_apply_known_macro_hint s
=
195 incr
Stat.nMacroHint
;
196 pr2_cpp ("MACRO: found known macro hint = " ^ s
)
201 let msg_ifdef_bool_passing is_ifdef_positif
=
202 incr
Stat.nIfdefZero
; (* of Version ? *)
204 then pr2_cpp "commenting parts of a #if 1 or #if LINUX_VERSION"
205 else pr2_cpp "commenting a #if 0 or #if LINUX_VERSION or __cplusplus"
208 let msg_ifdef_mid_something () =
209 incr
Stat.nIfdefExprPassing
;
210 pr2_cpp "found ifdef-mid-something"
212 let msg_ifdef_funheaders () =
213 incr
Stat.nIfdefFunheader
;
216 let msg_ifdef_passing () =
217 pr2_cpp("IFDEF: or related outside function. I treat it as comment");
218 incr
Stat.nIfdefPassing
;
221 let msg_attribute s
=
222 incr
Stat.nMacroAttribute
;
227 (*****************************************************************************)
228 (* The regexp and basic view definitions *)
229 (*****************************************************************************)
231 (* opti: better to built then once and for all, especially regexp_foreach *)
233 let regexp_macro = Str.regexp
237 let regexp_annot = Str.regexp
241 let regexp_declare = Str.regexp
245 let regexp_foreach = Str.regexp_case_fold
246 ".*\\(for_?each\\|for_?all\\|iterate\\|loop\\|walk\\|scan\\|each\\|for\\)"
248 let regexp_typedef = Str.regexp
251 let false_typedef = [
256 let ok_typedef s
= not
(List.mem s
false_typedef)
259 not
(s
==~
regexp_annot)
262 (* ------------------------------------------------------------------------- *)
263 (* cpp part 1 for standard.h *)
264 (* ------------------------------------------------------------------------- *)
266 type define_def
= string * define_param
* define_body
269 | Params
of string list
271 | DefineBody
of Parser_c.token list
272 | DefineHint
of parsinghack_hint
274 and parsinghack_hint
=
282 (* cf also data/test.h *)
283 let assoc_hint_string = [
284 "YACFE_ITERATOR" , HintIterator
;
285 "YACFE_DECLARATOR" , HintDeclarator
;
286 "YACFE_STRING" , HintMacroString
;
287 "YACFE_STATEMENT" , HintMacroStatement
;
288 "YACFE_ATTRIBUTE" , HintAttribute
;
289 "MACROSTATEMENT" , HintMacroStatement
; (* backward compatibility *)
293 let (parsinghack_hint_of_string
: string -> parsinghack_hint
option) = fun s
->
294 Common.assoc_option s
assoc_hint_string
296 let (is_parsinghack_hint
: string -> bool) = fun s
->
297 parsinghack_hint_of_string s
<> None
299 let (token_from_parsinghack_hint
:
300 (string * Ast_c.info
) -> parsinghack_hint
-> Parser_c.token
) =
304 Parser_c.TMacroIterator
(s
, ii
)
306 Parser_c.TMacroDecl
(s
, ii
)
308 Parser_c.TMacroString
(s
, ii
)
309 | HintMacroStatement
->
310 Parser_c.TMacroStmt
(s
, ii
)
312 Parser_c.TMacroAttr
(s
, ii
)
316 let (_defs
: (string, define_def
) Hashtbl.t
ref) =
317 ref (Hashtbl.create
101)
320 (* ------------------------------------------------------------------------- *)
321 (* fuzzy parsing, different "views" over the same program *)
322 (* ------------------------------------------------------------------------- *)
325 (* Normally I should not use ref/mutable in the token_extended type
326 * and I should have a set of functions taking a list of tokens and
327 * returning a list of tokens. The problem is that to make easier some
328 * functions, it is better to work on better representation, on "views"
329 * over this list of tokens. But then modifying those views and get
330 * back from those views to the original simple list of tokens is
331 * tedious. One way is to maintain next to the view a list of "actions"
332 * (I was using a hash storing the charpos of the token and associating
333 * the action) but it is tedious too. Simpler to use mutable/ref. We
334 * use the same idea that we use when working on the Ast_c. *)
336 (* old: when I was using the list of "actions" next to the views, the hash
337 * indexed by the charpos, there could have been some problems:
338 * how my fake_pos interact with the way I tag and adjust token ?
339 * because I base my tagging on the position of the token ! so sometimes
340 * could tag another fakeInfo that should not be tagged ?
341 * fortunately I don't use anymore this technique.
344 (* update: quite close to the Place_c.Inxxx *)
346 InFunction
| InEnum
| InStruct
| InInitializer
| NoContext
348 type token_extended
= {
349 mutable tok
: Parser_c.token
;
350 mutable where
: context
;
352 (* less: need also a after ? *)
353 mutable new_tokens_before
: Parser_c.token list
;
355 (* line x col cache, more easily accessible, of the info in the token *)
360 let set_as_comment cppkind x
=
362 then () (* otherwise parse_c will be lost if don't find a EOF token *)
364 x
.tok
<- TCommentCpp
(cppkind
, TH.info_of_tok x
.tok
)
366 let mk_token_extended x
=
367 let (line
, col
) = TH.linecol_of_tok x
in
369 line
= line
; col
= col
;
371 new_tokens_before
= [];
375 (* x list list, because x list separated by ',' *)
377 | Parenthised
of paren_grouped list list
* token_extended list
378 | PToken
of token_extended
382 brace_grouped list list
* token_extended
* token_extended
option
383 | BToken
of token_extended
385 (* Far better data structure than doing hacks in the lexer or parser
386 * because in lexer we don't know to which ifdef a endif is related
387 * and so when we want to comment a ifdef, we don't know which endif
388 * we must also comment. Especially true for the #if 0 which sometimes
391 * x list list, because x list separated by #else or #elif
394 | Ifdef
of ifdef_grouped list list
* token_extended list
395 | Ifdefbool
of bool * ifdef_grouped list list
* token_extended list
396 | NotIfdefLine
of token_extended list
399 type 'a line_grouped
=
403 type body_function_grouped
=
404 | BodyFunction
of token_extended list
405 | NotBodyLine
of token_extended list
408 (* ------------------------------------------------------------------------- *)
410 (* ------------------------------------------------------------------------- *)
412 (* todo: synchro ! use more indentation
413 * if paren not closed and same indentation level, certainly because
414 * part of a mid-ifdef-expression.
416 let rec mk_parenthised xs
=
421 | TOPar _
| TOParDefine _
->
422 let body, extras
, xs
= mk_parameters
[x
] [] xs
in
423 Parenthised
(body,extras
)::mk_parenthised xs
425 PToken x
::mk_parenthised xs
428 (* return the body of the parenthised expression and the rest of the tokens *)
429 and mk_parameters extras acc_before_sep xs
=
432 (* maybe because of #ifdef which "opens" '(' in 2 branches *)
433 pr2 "PB: not found closing paren in fuzzy parsing";
434 [List.rev acc_before_sep
], List.rev extras
, []
438 | TOBrace _
when x
.col
= 0 ->
439 pr2 "PB: found synchro point } in paren";
440 [List.rev acc_before_sep
], List.rev
(extras
), (x
::xs
)
442 | TCPar _
| TCParEOL _
->
443 [List.rev acc_before_sep
], List.rev
(x
::extras
), xs
444 | TOPar _
| TOParDefine _
->
445 let body, extrasnest
, xs
= mk_parameters
[x
] [] xs
in
447 (Parenthised
(body,extrasnest
)::acc_before_sep
)
450 let body, extras
, xs
= mk_parameters
(x
::extras
) [] xs
in
451 (List.rev acc_before_sep
)::body, extras
, xs
453 mk_parameters extras
(PToken x
::acc_before_sep
) xs
459 let rec mk_braceised xs
=
465 let body, endbrace
, xs
= mk_braceised_aux
[] xs
in
466 Braceised
(body, x
, endbrace
)::mk_braceised xs
468 pr2 "PB: found closing brace alone in fuzzy parsing";
469 BToken x
::mk_braceised xs
471 BToken x
::mk_braceised xs
474 (* return the body of the parenthised expression and the rest of the tokens *)
475 and mk_braceised_aux acc xs
=
478 (* maybe because of #ifdef which "opens" '(' in 2 branches *)
479 pr2 "PB: not found closing brace in fuzzy parsing";
480 [List.rev acc
], None
, []
483 | TCBrace _
-> [List.rev acc
], Some x
, xs
485 let body, endbrace
, xs
= mk_braceised_aux
[] xs
in
486 mk_braceised_aux
(Braceised
(body,x
, endbrace
)::acc
) xs
488 mk_braceised_aux
(BToken x
::acc
) xs
494 let rec mk_ifdef xs
=
500 let body, extra
, xs
= mk_ifdef_parameters
[x
] [] xs
in
501 Ifdef
(body, extra
)::mk_ifdef xs
502 | TIfdefBool
(b
,_
, _
) ->
503 let body, extra
, xs
= mk_ifdef_parameters
[x
] [] xs
in
505 (* if not passing, then consider a #if 0 as an ordinary #ifdef *)
506 if !Flag_parsing_c.if0_passing
507 then Ifdefbool
(b
, body, extra
)::mk_ifdef xs
508 else Ifdef
(body, extra
)::mk_ifdef xs
510 | TIfdefMisc
(b
,_
,_
) | TIfdefVersion
(b
,_
,_
) ->
511 let body, extra
, xs
= mk_ifdef_parameters
[x
] [] xs
in
512 Ifdefbool
(b
, body, extra
)::mk_ifdef xs
516 (* todo? can have some Ifdef in the line ? *)
517 let line, xs
= Common.span
(fun y
-> y
.line = x
.line) (x
::xs
) in
518 NotIfdefLine
line::mk_ifdef xs
521 and mk_ifdef_parameters extras acc_before_sep xs
=
524 (* Note that mk_ifdef is assuming that CPP instruction are alone
525 * on their line. Because I do a span (fun x -> is_same_line ...)
526 * I might take with me a #endif if this one is mixed on a line
527 * with some "normal" tokens.
529 pr2 "PB: not found closing ifdef in fuzzy parsing";
530 [List.rev acc_before_sep
], List.rev extras
, []
534 [List.rev acc_before_sep
], List.rev
(x
::extras
), xs
536 let body, extrasnest
, xs
= mk_ifdef_parameters
[x
] [] xs
in
538 extras
(Ifdef
(body, extrasnest
)::acc_before_sep
) xs
540 | TIfdefBool
(b
,_
,_
) ->
541 let body, extrasnest
, xs
= mk_ifdef_parameters
[x
] [] xs
in
543 if !Flag_parsing_c.if0_passing
546 extras
(Ifdefbool
(b
, body, extrasnest
)::acc_before_sep
) xs
549 extras
(Ifdef
(body, extrasnest
)::acc_before_sep
) xs
552 | TIfdefMisc
(b
,_
,_
) | TIfdefVersion
(b
,_
,_
) ->
553 let body, extrasnest
, xs
= mk_ifdef_parameters
[x
] [] xs
in
555 extras
(Ifdefbool
(b
, body, extrasnest
)::acc_before_sep
) xs
559 let body, extras
, xs
= mk_ifdef_parameters
(x
::extras
) [] xs
in
560 (List.rev acc_before_sep
)::body, extras
, xs
562 let line, xs
= Common.span
(fun y
-> y
.line = x
.line) (x
::xs
) in
563 mk_ifdef_parameters extras
(NotIfdefLine
line::acc_before_sep
) xs
566 (* --------------------------------------- *)
568 let line_of_paren = function
570 | Parenthised
(xxs
, info_parens
) ->
571 (match info_parens
with
572 | [] -> raise Impossible
577 let rec span_line_paren line = function
581 | PToken tok
when TH.is_eof tok
.tok
->
584 if line_of_paren x
= line
586 let (l1
, l2
) = span_line_paren line xs
in
592 let rec mk_line_parenthised xs
=
596 let line_no = line_of_paren x
in
597 let line, xs
= span_line_paren line_no xs
in
598 Line
(x
::line)::mk_line_parenthised xs
601 (* --------------------------------------- *)
602 let rec mk_body_function_grouped xs
=
607 | {tok
= TOBrace _
; col
= 0} ->
608 let is_closing_brace = function
609 | {tok
= TCBrace _
; col
= 0 } -> true
612 let body, xs
= Common.span
(fun x
-> not
(is_closing_brace x
)) xs
in
614 | ({tok
= TCBrace _
; col
= 0 })::xs
->
615 BodyFunction
body::mk_body_function_grouped xs
617 pr2 "PB:not found closing brace in fuzzy parsing";
619 | _
-> raise Impossible
623 let line, xs
= Common.span
(fun y
-> y
.line = x
.line) (x
::xs
) in
624 NotBodyLine
line::mk_body_function_grouped xs
628 (* ------------------------------------------------------------------------- *)
630 (* ------------------------------------------------------------------------- *)
632 let rec iter_token_paren f xs
=
633 xs
+> List.iter
(function
634 | PToken tok
-> f tok
;
635 | Parenthised
(xxs
, info_parens
) ->
636 info_parens
+> List.iter f
;
637 xxs
+> List.iter
(fun xs
-> iter_token_paren f xs
)
640 let rec iter_token_brace f xs
=
641 xs
+> List.iter
(function
642 | BToken tok
-> f tok
;
643 | Braceised
(xxs
, tok1
, tok2opt
) ->
644 f tok1
; do_option f tok2opt
;
645 xxs
+> List.iter
(fun xs
-> iter_token_brace f xs
)
648 let rec iter_token_ifdef f xs
=
649 xs
+> List.iter
(function
650 | NotIfdefLine xs
-> xs
+> List.iter f
;
651 | Ifdefbool
(_
, xxs
, info_ifdef
)
652 | Ifdef
(xxs
, info_ifdef
) ->
653 info_ifdef
+> List.iter f
;
654 xxs
+> List.iter
(iter_token_ifdef f
)
660 let tokens_of_paren xs
=
662 xs
+> iter_token_paren (fun tok
-> push2 tok
g);
666 let tokens_of_paren_ordered xs
=
669 let rec aux_tokens_ordered = function
670 | PToken tok
-> push2 tok
g;
671 | Parenthised
(xxs
, info_parens
) ->
672 let (opar
, cpar
, commas
) =
673 match info_parens
with
675 (match List.rev xs
with
677 opar
, cpar
, List.rev xs
678 | _
-> raise Impossible
680 | _
-> raise Impossible
683 aux_args
(xxs
,commas
);
686 and aux_args
(xxs
, commas
) =
687 match xxs
, commas
with
689 | [xs
], [] -> xs
+> List.iter
aux_tokens_ordered
690 | xs
::ys
::xxs
, comma
::commas
->
691 xs
+> List.iter
aux_tokens_ordered;
693 aux_args
(ys
::xxs
, commas
)
694 | _
-> raise Impossible
698 xs
+> List.iter
aux_tokens_ordered;
704 (* ------------------------------------------------------------------------- *)
705 (* set the context info in token *)
706 (* ------------------------------------------------------------------------- *)
709 let rec set_in_function_tag xs
=
710 (* could try: ) { } but it can be the ) of a if or while, so
711 * better to base the heuristic on the position in column zero.
712 * Note that some struct or enum or init put also their { in first column
713 * but set_in_other will overwrite the previous InFunction tag.
717 (* ) { and the closing } is in column zero, then certainly a function *)
718 | BToken
({tok
= TCPar _
})::(Braceised
(body, tok1
, Some tok2
))::xs
719 when tok1
.col
<> 0 && tok2
.col
= 0 ->
720 body +> List.iter
(iter_token_brace (fun tok
->
721 tok
.where
<- InFunction
723 set_in_function_tag xs
725 | (BToken x
)::xs
-> set_in_function_tag xs
727 | (Braceised
(body, tok1
, Some tok2
))::xs
728 when tok1
.col
= 0 && tok2
.col
= 0 ->
729 body +> List.iter
(iter_token_brace (fun tok
->
730 tok
.where
<- InFunction
732 set_in_function_tag xs
733 | Braceised
(body, tok1
, tok2
)::xs
->
734 set_in_function_tag xs
737 let rec set_in_other xs
=
741 | BToken
({tok
= Tenum _
})::BToken
({tok
= TIdent _
})
742 ::Braceised
(body, tok1
, tok2
)::xs
743 | BToken
({tok
= Tenum _
})
744 ::Braceised
(body, tok1
, tok2
)::xs
746 body +> List.iter
(iter_token_brace (fun tok
->
752 | BToken
({tok
= Tstruct _
})::BToken
({tok
= TIdent _
})
753 ::Braceised
(body, tok1
, tok2
)::xs
->
754 body +> List.iter
(iter_token_brace (fun tok
->
755 tok
.where
<- InStruct
;
759 | BToken
({tok
= TEq _
})
760 ::Braceised
(body, tok1
, tok2
)::xs
->
761 body +> List.iter
(iter_token_brace (fun tok
->
762 tok
.where
<- InInitializer
;
766 | BToken _
::xs
-> set_in_other xs
768 | Braceised
(body, tok1
, tok2
)::xs
->
769 body +> List.iter
set_in_other;
775 let set_context_tag xs
=
777 set_in_function_tag xs
;
782 (*****************************************************************************)
784 (*****************************************************************************)
786 (* To expand the parameter of the macro. The env corresponds to the actual
787 * code that is binded to the parameters of the macro.
788 * TODO? recurse ? fixpoint ? the expansion may also contain macro.
789 * Or to macro expansion in a strict manner, that is process first
790 * the parameters, expands macro in params, and then process enclosing
793 let rec (cpp_engine
: (string , Parser_c.token list
) assoc
->
794 Parser_c.token list
-> Parser_c.token list
) =
796 xs
+> List.map
(fun tok
->
798 | TIdent
(s
,i1
) when List.mem_assoc s env
-> Common.assoc s env
806 (* ------------------------------------------------------------------------- *)
807 (* the pair is the status of '()' and '{}', ex: (-1,0)
808 * if too much ')' and good '{}'
809 * could do for [] too ?
810 * could do for ',' if encounter ',' at "toplevel", not inside () or {}
811 * then if have ifdef, then certainly can lead to a problem.
813 let (count_open_close_stuff_ifdef_clause
: ifdef_grouped list
-> (int * int)) =
815 let cnt_paren, cnt_brace
= ref 0, ref 0 in
816 xs
+> iter_token_ifdef (fun x
->
818 | x
when TH.is_opar x
-> incr
cnt_paren
819 | TOBrace _
-> incr cnt_brace
820 | x
when TH.is_cpar x
-> decr
cnt_paren
821 | TCBrace _
-> decr cnt_brace
825 !cnt_paren, !cnt_brace
828 (* ------------------------------------------------------------------------- *)
829 let forLOOKAHEAD = 30
832 (* look if there is a '{' just after the closing ')', and handling the
833 * possibility to have nested expressions inside nested parenthesis
835 * todo: use indentation instead of premier(statement) ?
837 let rec is_really_foreach xs
=
838 let rec is_foreach_aux = function
840 | TCPar _
::TOBrace _
::xs
-> true, xs
841 (* the following attempts to handle the cases where there is a
842 single statement in the body of the loop. undoubtedly more
844 todo: premier(statement) - suivant(funcall)
846 | TCPar _
::TIdent _
::xs
-> true, xs
847 | TCPar _
::Tif _
::xs
-> true, xs
848 | TCPar _
::Twhile _
::xs
-> true, xs
849 | TCPar _
::Tfor _
::xs
-> true, xs
850 | TCPar _
::Tswitch _
::xs
-> true, xs
851 | TCPar _
::Treturn _
::xs
-> true, xs
854 | TCPar _
::xs
-> false, xs
856 let (_
, xs'
) = is_foreach_aux xs
in
858 | x
::xs
-> is_foreach_aux xs
860 is_foreach_aux xs
+> fst
863 (* ------------------------------------------------------------------------- *)
864 let set_ifdef_token_parenthize_info cnt x
=
867 | TIfdefelse
(tag
, _
)
868 | TIfdefelif
(tag
, _
)
871 | TIfdefBool
(_
, tag
, _
)
872 | TIfdefMisc
(_
, tag
, _
)
873 | TIfdefVersion
(_
, tag
, _
)
877 | _
-> raise Impossible
881 let ifdef_paren_cnt = ref 0
884 let rec set_ifdef_parenthize_info xs
=
885 xs
+> List.iter
(function
886 | NotIfdefLine xs
-> ()
887 | Ifdefbool
(_
, xxs
, info_ifdef
)
888 | Ifdef
(xxs
, info_ifdef
) ->
890 incr
ifdef_paren_cnt;
891 let total_directives = List.length info_ifdef
in
893 info_ifdef
+> List.iter
(fun x
->
894 set_ifdef_token_parenthize_info (!ifdef_paren_cnt, total_directives)
896 xxs
+> List.iter
set_ifdef_parenthize_info
900 (*****************************************************************************)
901 (* CPP handling: macros, ifdefs, macros defs *)
902 (*****************************************************************************)
904 (* ------------------------------------------------------------------------- *)
905 (* ifdef keeping/passing *)
906 (* ------------------------------------------------------------------------- *)
908 (* #if 0, #if 1, #if LINUX_VERSION handling *)
909 let rec find_ifdef_bool xs
=
910 xs
+> List.iter
(function
911 | NotIfdefLine _
-> ()
912 | Ifdefbool
(is_ifdef_positif
, xxs
, info_ifdef_stmt
) ->
914 msg_ifdef_bool_passing is_ifdef_positif
;
917 | [] -> raise Impossible
918 | firstclause
::xxs
->
919 info_ifdef_stmt
+> List.iter
(set_as_comment Ast_c.CppDirective
);
922 then xxs
+> List.iter
923 (iter_token_ifdef (set_as_comment Ast_c.CppPassingNormal
))
925 firstclause
+> iter_token_ifdef (set_as_comment Ast_c.CppPassingNormal
);
926 (match List.rev xxs
with
930 (iter_token_ifdef (set_as_comment Ast_c.CppPassingNormal
))
931 | [] -> (* not #else *) ()
936 | Ifdef
(xxs
, info_ifdef_stmt
) -> xxs
+> List.iter
find_ifdef_bool
941 let thresholdIfdefSizeMid = 6
943 (* infer ifdef involving not-closed expressions/statements *)
944 let rec find_ifdef_mid xs
=
945 xs
+> List.iter
(function
946 | NotIfdefLine _
-> ()
947 | Ifdef
(xxs
, info_ifdef_stmt
) ->
949 | [] -> raise Impossible
951 | first
::second
::rest
->
952 (* don't analyse big ifdef *)
953 if xxs
+> List.for_all
954 (fun xs
-> List.length xs
<= thresholdIfdefSizeMid) &&
955 (* don't want nested ifdef *)
956 xxs
+> List.for_all
(fun xs
->
958 (function NotIfdefLine _
-> true | _
-> false)
962 let counts = xxs
+> List.map count_open_close_stuff_ifdef_clause
in
963 let cnt1, cnt2
= List.hd
counts in
964 if cnt1 <> 0 || cnt2
<> 0 &&
965 counts +> List.for_all
(fun x
-> x
= (cnt1, cnt2
))
967 if counts +> List.exists (fun (cnt1, cnt2) ->
968 cnt1 <> 0 || cnt2 <> 0
972 msg_ifdef_mid_something();
974 (* keep only first, treat the rest as comment *)
975 info_ifdef_stmt
+> List.iter
(set_as_comment Ast_c.CppDirective
);
976 (second
::rest
) +> List.iter
977 (iter_token_ifdef (set_as_comment Ast_c.CppPassingCosWouldGetError
));
981 List.iter
find_ifdef_mid xxs
983 (* no need complex analysis for ifdefbool *)
984 | Ifdefbool
(_
, xxs
, info_ifdef_stmt
) ->
985 List.iter
find_ifdef_mid xxs
991 let thresholdFunheaderLimit = 4
993 (* ifdef defining alternate function header, type *)
994 let rec find_ifdef_funheaders = function
996 | NotIfdefLine _
::xs
-> find_ifdef_funheaders xs
998 (* ifdef-funheader if ifdef with 2 lines and a '{' in next line *)
1000 ([(NotIfdefLine
(({col
= 0} as _xline1
)::line1
))::ifdefblock1
;
1001 (NotIfdefLine
(({col
= 0} as xline2
)::line2
))::ifdefblock2
1004 ::NotIfdefLine
(({tok
= TOBrace i
; col
= 0})::line3
)
1006 when List.length ifdefblock1
<= thresholdFunheaderLimit &&
1007 List.length ifdefblock2
<= thresholdFunheaderLimit
1009 find_ifdef_funheaders xs
;
1011 msg_ifdef_funheaders ();
1012 info_ifdef_stmt
+> List.iter
(set_as_comment Ast_c.CppDirective
);
1013 let all_toks = [xline2
] @ line2
in
1014 all_toks +> List.iter
(set_as_comment Ast_c.CppPassingCosWouldGetError
) ;
1015 ifdefblock2
+> iter_token_ifdef (set_as_comment Ast_c.CppPassingCosWouldGetError
);
1017 (* ifdef with nested ifdef *)
1019 ([[NotIfdefLine
(({col
= 0} as _xline1
)::line1
)];
1021 ([[NotIfdefLine
(({col
= 0} as xline2
)::line2
)];
1022 [NotIfdefLine
(({col
= 0} as xline3
)::line3
)];
1028 ::NotIfdefLine
(({tok
= TOBrace i
; col
= 0})::line4
)
1031 find_ifdef_funheaders xs
;
1033 msg_ifdef_funheaders ();
1034 info_ifdef_stmt
+> List.iter
(set_as_comment Ast_c.CppDirective
);
1035 info_ifdef_stmt2
+> List.iter
(set_as_comment Ast_c.CppDirective
);
1036 let all_toks = [xline2
;xline3
] @ line2
@ line3
in
1037 all_toks +> List.iter
(set_as_comment Ast_c.CppPassingCosWouldGetError
);
1039 (* ifdef with elseif *)
1041 ([[NotIfdefLine
(({col
= 0} as _xline1
)::line1
)];
1042 [NotIfdefLine
(({col
= 0} as xline2
)::line2
)];
1043 [NotIfdefLine
(({col
= 0} as xline3
)::line3
)];
1046 ::NotIfdefLine
(({tok
= TOBrace i
; col
= 0})::line4
)
1049 find_ifdef_funheaders xs
;
1051 msg_ifdef_funheaders ();
1052 info_ifdef_stmt
+> List.iter
(set_as_comment Ast_c.CppDirective
);
1053 let all_toks = [xline2
;xline3
] @ line2
@ line3
in
1054 all_toks +> List.iter
(set_as_comment Ast_c.CppPassingCosWouldGetError
)
1057 | Ifdef
(xxs
,info_ifdef_stmt
)::xs
1058 | Ifdefbool
(_
, xxs
,info_ifdef_stmt
)::xs
->
1059 List.iter
find_ifdef_funheaders xxs
;
1060 find_ifdef_funheaders xs
1065 let rec adjust_inifdef_include xs
=
1066 xs
+> List.iter
(function
1067 | NotIfdefLine _
-> ()
1068 | Ifdef
(xxs
, info_ifdef_stmt
) | Ifdefbool
(_
, xxs
, info_ifdef_stmt
) ->
1069 xxs
+> List.iter
(iter_token_ifdef (fun tokext
->
1070 match tokext
.tok
with
1071 | Parser_c.TInclude
(s1
, s2
, inifdef_ref
, ii
) ->
1072 inifdef_ref
:= true;
1079 (* ------------------------------------------------------------------------- *)
1080 (* cpp-builtin part2, macro, using standard.h or other defs *)
1081 (* ------------------------------------------------------------------------- *)
1083 (* Thanks to this function many stuff are not anymore hardcoded in ocaml code
1084 * (but they are now hardcoded in standard.h ...)
1088 * No need to take care to not substitute the macro name itself
1089 * that occurs in the macro definition because the macro name is
1090 * after fix_token_define a TDefineIdent, no more a TIdent.
1093 let rec apply_macro_defs xs
=
1097 (* old: "but could do more, could reuse same original token
1098 * so that have in the Ast a Dbg, not a MACROSTATEMENT"
1100 * | PToken ({tok = TIdent (s,i1)} as id)::xs
1101 * when s = "MACROSTATEMENT" ->
1103 * msg_macro_statement_hint s;
1104 * id.tok <- TMacroStmt(TH.info_of_tok id.tok);
1105 * find_macro_paren xs
1107 * let msg_macro_statement_hint s =
1108 * incr Stat.nMacroHint;
1113 (* recognized macro of standard.h (or other) *)
1114 | PToken
({tok
= TIdent
(s
,i1
)} as id
)::Parenthised
(xxs
,info_parens
)::xs
1115 when Hashtbl.mem
!_defs s
->
1117 msg_apply_known_macro s
;
1118 let (s
, params
, body) = Hashtbl.find
!_defs s
in
1122 pr2 ("WIERD: macro without param used before parenthize: " ^ s
);
1123 (* ex: PRINTP("NCR53C400 card%s detected\n" ANDP(((struct ... *)
1126 | DefineBody bodymacro
->
1127 set_as_comment (Ast_c.CppMacro
) id
;
1128 id
.new_tokens_before
<- bodymacro
;
1129 | DefineHint hint
->
1130 msg_apply_known_macro_hint s
;
1131 id
.tok
<- token_from_parsinghack_hint
(s
,i1
) hint
;
1134 if List.length params
!= List.length xxs
1136 pr2 ("WIERD: macro with wrong number of arguments: " ^ s
);
1137 (* old: id.new_tokens_before <- bodymacro; *)
1142 | DefineBody bodymacro
->
1143 let xxs'
= xxs +> List.map
(fun x
->
1144 (tokens_of_paren_ordered x
) +> List.map
(fun x
->
1145 TH.visitor_info_of_tok
Ast_c.make_expanded x
.tok
1148 id
.new_tokens_before
<-
1149 cpp_engine
(Common.zip params
xxs'
) bodymacro
;
1151 (* important to do that after have apply the macro, otherwise
1152 * will pass as argument to the macro some tokens that
1153 * are all TCommentCpp
1155 [Parenthised
(xxs, info_parens
)] +>
1156 iter_token_paren (set_as_comment Ast_c.CppMacro
);
1157 set_as_comment Ast_c.CppMacro id
;
1159 | DefineHint
(HintMacroStatement
as hint
) ->
1160 (* important to do that after have apply the macro, otherwise
1161 * will pass as argument to the macro some tokens that
1162 * are all TCommentCpp
1164 msg_apply_known_macro_hint s
;
1165 id
.tok
<- token_from_parsinghack_hint
(s
,i1
) hint
;
1166 [Parenthised
(xxs, info_parens
)] +>
1167 iter_token_paren (set_as_comment Ast_c.CppMacro
);
1170 | DefineHint hint
->
1171 msg_apply_known_macro_hint s
;
1172 id
.tok
<- token_from_parsinghack_hint
(s
,i1
) hint
;
1177 | PToken
({tok
= TIdent
(s
,i1
)} as id
)::xs
1178 when Hashtbl.mem
!_defs s
->
1180 msg_apply_known_macro s
;
1181 let (_s
, params
, body) = Hashtbl.find
!_defs s
in
1185 pr2 ("WIERD: macro with params but no parens found: " ^ s
);
1186 (* dont apply the macro, perhaps a redefinition *)
1190 | DefineBody
[newtok
] ->
1191 (* special case when 1-1 substitution, we reuse the token *)
1192 id
.tok
<- (newtok
+> TH.visitor_info_of_tok
(fun _
->
1193 TH.info_of_tok id
.tok
))
1194 | DefineBody bodymacro
->
1195 set_as_comment Ast_c.CppMacro id
;
1196 id
.new_tokens_before
<- bodymacro
;
1197 | DefineHint hint
->
1198 msg_apply_known_macro_hint s
;
1199 id
.tok
<- token_from_parsinghack_hint
(s
,i1
) hint
;
1208 | (PToken x
)::xs
-> apply_macro_defs xs
1209 | (Parenthised
(xxs, info_parens
))::xs
->
1210 xxs +> List.iter
apply_macro_defs;
1217 (* ------------------------------------------------------------------------- *)
1218 (* stringification *)
1219 (* ------------------------------------------------------------------------- *)
1221 let rec find_string_macro_paren xs
=
1224 | Parenthised
(xxs, info_parens
)::xs
->
1225 xxs +> List.iter
(fun xs
->
1226 if xs
+> List.exists
1227 (function PToken
({tok
= (TString _
| TMacroString _
)}) -> true | _
-> false) &&
1229 (function PToken
({tok
= (TString _
| TMacroString _
)}) | PToken
({tok
= TIdent _
}) ->
1232 xs
+> List.iter
(fun tok
->
1234 | PToken
({tok
= TIdent
(s
,_
)} as id
) ->
1235 msg_stringification s
;
1236 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
1240 find_string_macro_paren xs
1242 find_string_macro_paren xs
1243 | PToken
(tok
)::xs
->
1244 find_string_macro_paren xs
1247 (* ------------------------------------------------------------------------- *)
1249 (* ------------------------------------------------------------------------- *)
1251 (* don't forget to recurse in each case *)
1252 let rec find_macro_paren xs
=
1257 | PToken
({tok
= Tattribute _
} as id
)
1258 ::Parenthised
(xxs,info_parens
)
1261 pr2_cpp ("MACRO: __attribute detected ");
1262 [Parenthised
(xxs, info_parens
)] +>
1263 iter_token_paren (set_as_comment Ast_c.CppAttr
);
1264 set_as_comment Ast_c.CppAttr id
;
1268 (* attribute cpp, __xxx id() *)
1269 | PToken
({tok
= TIdent
(s
,i1
)} as id
)
1270 ::PToken
({tok
= TIdent
(s2
, i2
)})
1271 ::Parenthised
(xxs,info_parens
)
1272 ::xs
when s
==~
regexp_annot
1275 id
.tok
<- TMacroAttr
(s
, i1
);
1276 find_macro_paren (Parenthised
(xxs,info_parens
)::xs
)
1278 (* attribute cpp, id __xxx = *)
1279 | PToken
({tok
= TIdent
(s
,i1
)})
1280 ::PToken
({tok
= TIdent
(s2
, i2
)} as id
)
1281 ::xs
when s2
==~
regexp_annot
1284 id
.tok
<- TMacroAttr
(s2
, i2
);
1285 find_macro_paren (xs
)
1288 (* storage attribute *)
1289 | PToken
({tok
= (Tstatic _
| Textern _
)} as tok1
)
1290 ::PToken
({tok
= TMacroAttr
(s
,i1
)} as attr
)::xs
1292 pr2_cpp ("storage attribute: " ^ s
);
1293 attr
.tok
<- TMacroAttrStorage
(s
,i1
);
1294 (* recurse, may have other storage attributes *)
1295 find_macro_paren (PToken
(tok1
)::xs
)
1300 * the order of the matching clause is important
1304 (* string macro with params, before case *)
1305 | PToken
({tok
= (TString _
| TMacroString _
)})::PToken
({tok
= TIdent
(s
,_
)} as id
)
1306 ::Parenthised
(xxs, info_parens
)
1309 msg_stringification_params s
;
1310 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
1311 [Parenthised
(xxs, info_parens
)] +>
1312 iter_token_paren (set_as_comment Ast_c.CppMacro
);
1316 | PToken
({tok
= TIdent
(s
,_
)} as id
)
1317 ::Parenthised
(xxs, info_parens
)
1318 ::PToken
({tok
= (TString _
| TMacroString _
)})
1321 msg_stringification_params s
;
1322 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
1323 [Parenthised
(xxs, info_parens
)] +>
1324 iter_token_paren (set_as_comment Ast_c.CppMacro
);
1328 (* for the case where the string is not inside a funcall, but
1329 * for instance in an initializer.
1332 (* string macro variable, before case *)
1333 | PToken
({tok
= (TString _
| TMacroString _
)})::PToken
({tok
= TIdent
(s
,_
)} as id
)
1336 msg_stringification s
;
1337 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
1341 | PToken
({tok
= TIdent
(s
,_
)} as id
)
1342 ::PToken
({tok
= (TString _
| TMacroString _
)})
1345 msg_stringification s
;
1346 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
1354 | (PToken x
)::xs
-> find_macro_paren xs
1355 | (Parenthised
(xxs, info_parens
))::xs
->
1356 xxs +> List.iter
find_macro_paren;
1363 (* don't forget to recurse in each case *)
1364 let rec find_macro_lineparen xs
=
1368 (* linuxext: ex: static [const] DEVICE_ATTR(); *)
1371 [PToken
({tok
= Tstatic _
});
1372 PToken
({tok
= TIdent
(s
,_
)} as macro
);
1373 Parenthised
(xxs,info_parens
);
1374 PToken
({tok
= TPtVirg _
});
1378 when (s
==~
regexp_macro) ->
1380 msg_declare_macro s
;
1381 let info = TH.info_of_tok macro
.tok
in
1382 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1384 find_macro_lineparen (xs
)
1386 (* the static const case *)
1389 [PToken
({tok
= Tstatic _
});
1390 PToken
({tok
= Tconst _
} as const
);
1391 PToken
({tok
= TIdent
(s
,_
)} as macro
);
1392 Parenthised
(xxs,info_parens
);
1393 PToken
({tok
= TPtVirg _
});
1399 when (s
==~
regexp_macro) ->
1401 msg_declare_macro s
;
1402 let info = TH.info_of_tok macro
.tok
in
1403 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1405 (* need retag this const, otherwise ambiguity in grammar
1406 21: shift/reduce conflict (shift 121, reduce 137) on Tconst
1407 decl2 : Tstatic . TMacroDecl TOPar argument_list TCPar ...
1408 decl2 : Tstatic . Tconst TMacroDecl TOPar argument_list TCPar ...
1409 storage_class_spec : Tstatic . (137)
1411 const
.tok
<- TMacroDeclConst
(TH.info_of_tok const
.tok
);
1413 find_macro_lineparen (xs
)
1416 (* same but without trailing ';'
1418 * I do not put the final ';' because it can be on a multiline and
1419 * because of the way mk_line is coded, we will not have access to
1420 * this ';' on the next line, even if next to the ')' *)
1422 ([PToken
({tok
= Tstatic _
});
1423 PToken
({tok
= TIdent
(s
,_
)} as macro
);
1424 Parenthised
(xxs,info_parens
);
1428 when s
==~
regexp_macro ->
1430 msg_declare_macro s
;
1431 let info = TH.info_of_tok macro
.tok
in
1432 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1434 find_macro_lineparen (xs
)
1439 (* on multiple lines *)
1442 (PToken
({tok
= Tstatic _
})::[]
1446 [PToken
({tok
= TIdent
(s
,_
)} as macro
);
1447 Parenthised
(xxs,info_parens
);
1448 PToken
({tok
= TPtVirg _
});
1453 when (s
==~
regexp_macro) ->
1455 msg_declare_macro s
;
1456 let info = TH.info_of_tok macro
.tok
in
1457 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1459 find_macro_lineparen (xs
)
1462 (* linuxext: ex: DECLARE_BITMAP();
1464 * Here I use regexp_declare and not regexp_macro because
1465 * Sometimes it can be a FunCallMacro such as DEBUG(foo());
1466 * Here we don't have the preceding 'static' so only way to
1467 * not have positive is to restrict to .*DECLARE.* macros.
1469 * but there is a grammar rule for that, so don't need this case anymore
1470 * unless the parameter of the DECLARE_xxx are wierd and can not be mapped
1471 * on a argument_list
1475 ([PToken
({tok
= TIdent
(s
,_
)} as macro
);
1476 Parenthised
(xxs,info_parens
);
1477 PToken
({tok
= TPtVirg _
});
1481 when (s
==~
regexp_declare) ->
1483 msg_declare_macro s
;
1484 let info = TH.info_of_tok macro
.tok
in
1485 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1487 find_macro_lineparen (xs
)
1493 * Could also transform the TIdent in a TMacroTop but can have false
1494 * positive, so easier to just change the TCPar and so just solve
1495 * the end-of-stream pb of ocamlyacc
1498 ([PToken
({tok
= TIdent
(s
,ii
); col
= col1
; where
= ctx
} as _macro
);
1499 Parenthised
(xxs,info_parens
);
1505 (* to reduce number of false positive *)
1507 | (Line
(PToken
({col
= col2
} as other
)::restline2
))::_
->
1508 TH.is_eof other
.tok
|| (col2
= 0 &&
1509 (match other
.tok
with
1510 | TOBrace _
-> false (* otherwise would match funcdecl *)
1511 | TCBrace _
when ctx
<> InFunction
-> false
1515 | tok
when TH.is_binary_operator tok
-> false
1526 msg_macro_toplevel_noptvirg s
;
1527 (* just to avoid the end-of-stream pb of ocamlyacc *)
1528 let tcpar = Common.last info_parens
in
1529 tcpar.tok
<- TCParEOL
(TH.info_of_tok
tcpar.tok
);
1531 (*macro.tok <- TMacroTop (s, TH.info_of_tok macro.tok);*)
1535 find_macro_lineparen (xs
)
1539 (* macro with parameters
1544 ([PToken
({tok
= TIdent
(s
,ii
); col
= col1
; where
= ctx
} as macro
);
1545 Parenthised
(xxs,info_parens
);
1549 (PToken
({col
= col2
} as other
)::restline2
1552 (* when s ==~ regexp_macro *)
1556 (match other
.tok
with
1557 | TOBrace _
-> false (* otherwise would match funcdecl *)
1558 | TCBrace _
when ctx
<> InFunction
-> false
1562 | tok
when TH.is_binary_operator tok
-> false
1569 (match other
.tok
with
1570 | TCBrace _
when ctx
= InFunction
-> true
1585 msg_macro_noptvirg s
;
1586 macro
.tok
<- TMacroStmt
(s
, TH.info_of_tok macro
.tok
);
1587 [Parenthised
(xxs, info_parens
)] +>
1588 iter_token_paren (set_as_comment Ast_c.CppMacro
);
1591 find_macro_lineparen (line2
::xs
)
1593 (* linuxext:? single macro
1599 ([PToken
({tok
= TIdent
(s
,ii
); col
= col1
; where
= ctx
} as macro
);
1603 (PToken
({col
= col2
} as other
)::restline2
1606 (* when s ==~ regexp_macro *)
1610 col1
<> 0 && (* otherwise can match typedef of fundecl*)
1611 (match other
.tok
with
1612 | TPtVirg _
-> false
1614 | TCBrace _
when ctx
<> InFunction
-> false
1615 | tok
when TH.is_binary_operator tok
-> false
1620 (match other
.tok
with
1621 | TCBrace _
when ctx
= InFunction
-> true
1631 msg_macro_noptvirg_single s
;
1632 macro
.tok
<- TMacroStmt
(s
, TH.info_of_tok macro
.tok
);
1634 find_macro_lineparen (line2
::xs
)
1637 find_macro_lineparen xs
1641 (* ------------------------------------------------------------------------- *)
1642 (* define tobrace init *)
1643 (* ------------------------------------------------------------------------- *)
1645 let rec find_define_init_brace_paren xs
=
1650 (* mainly for firefox *)
1651 | (PToken
{tok
= TDefine _
})
1652 ::(PToken
{tok
= TIdentDefine
(s
,_
)})
1653 ::(PToken
({tok
= TOBrace i1
} as tokbrace
))
1658 match tok2
.tok
, tok3
.tok
with
1659 | TInt _
, TComma _
-> true
1660 | TString _
, TComma _
-> true
1661 | TIdent _
, TComma _
-> true
1667 pr2_cpp("found define initializer: " ^s
);
1668 tokbrace
.tok
<- TOBraceDefineInit i1
;
1673 (* mainly for linux, especially in sound/ *)
1674 | (PToken
{tok
= TDefine _
})
1675 ::(PToken
{tok
= TIdentDefine
(s
,_
)})
1676 ::(Parenthised
(xxx
, info_parens
))
1677 ::(PToken
({tok
= TOBrace i1
} as tokbrace
))
1682 match tok2
.tok
, tok3
.tok
with
1683 | TInt _
, TComma _
-> true
1684 | TDot _
, TIdent _
-> true
1685 | TIdent _
, TComma _
-> true
1691 pr2_cpp("found define initializer with param: " ^ s
);
1692 tokbrace
.tok
<- TOBraceDefineInit i1
;
1700 | (PToken x
)::xs
-> aux xs
1701 | (Parenthised
(xxs, info_parens
))::xs
->
1702 (* not need for tobrace init:
1703 * xxs +> List.iter aux;
1710 (* ------------------------------------------------------------------------- *)
1712 (* ------------------------------------------------------------------------- *)
1714 let rec find_actions = function
1717 | PToken
({tok
= TIdent
(s
,ii
)})
1718 ::Parenthised
(xxs,info_parens
)
1721 xxs +> List.iter
find_actions;
1722 let modified = find_actions_params
xxs in
1724 then msg_macro_higher_order s
1729 and find_actions_params
xxs =
1730 xxs +> List.fold_left
(fun acc xs
->
1731 let toks = tokens_of_paren xs
in
1732 if toks +> List.exists
(fun x
-> TH.is_statement x
.tok
)
1734 xs
+> iter_token_paren (fun x
->
1737 (* certainly because paren detection had a pb because of
1740 pr2 "PB: wierd, I try to tag an EOF token as action"
1742 x
.tok
<- TAction
(TH.info_of_tok x
.tok
);
1751 (* ------------------------------------------------------------------------- *)
1752 (* main fix cpp function *)
1753 (* ------------------------------------------------------------------------- *)
1755 let rebuild_tokens_extented toks_ext
=
1756 let _tokens = ref [] in
1757 toks_ext
+> List.iter
(fun tok
->
1758 tok
.new_tokens_before
+> List.iter
(fun x
-> push2 x
_tokens);
1759 push2 tok
.tok
_tokens
1761 let tokens = List.rev
!_tokens in
1762 (tokens +> acc_map
mk_token_extended)
1764 let filter_cpp_stuff xs
=
1770 | tok
when TH.is_comment tok
-> aux xs
1771 (* don't want drop the define, or if drop, have to drop
1772 * also its body otherwise the line heuristics may be lost
1773 * by not finding the TDefine in column 0 but by finding
1774 * a TDefineIdent in a column > 0
1776 | Parser_c.TDefine _
->
1778 | tok
when TH.is_cpp_instruction tok
-> aux xs
1784 let insert_virtual_positions l
=
1785 let strlen x
= String.length
(Ast_c.str_of_info x
) in
1786 let rec loop prev offset
= function
1789 let ii = TH.info_of_tok x
in
1791 TH.visitor_info_of_tok
(function ii -> Ast_c.rewrap_pinfo pi
ii) x
in
1792 match Ast_c.pinfo_of_info
ii with
1793 Ast_c.OriginTok pi
->
1794 let prev = Ast_c.parse_info_of_info
ii in
1795 x
::(loop prev (strlen ii) xs
)
1796 | Ast_c.ExpandedTok
(pi
,_
) ->
1797 inject (Ast_c.ExpandedTok
(pi
,(prev,offset
))) ::
1798 (loop prev (offset
+ (strlen ii)) xs
)
1799 | Ast_c.FakeTok
(s
,_
) ->
1800 inject (Ast_c.FakeTok
(s
,(prev,offset
))) ::
1801 (loop prev (offset
+ (strlen ii)) xs
)
1802 | Ast_c.AbstractLineTok _
-> failwith
"abstract not expected" in
1803 let rec skip_fake = function
1806 let ii = TH.info_of_tok x
in
1807 match Ast_c.pinfo_of_info
ii with
1808 Ast_c.OriginTok pi
->
1809 let prev = Ast_c.parse_info_of_info
ii in
1810 x
::(loop prev (strlen ii) xs
)
1811 | _
-> x
::skip_fake xs
in
1814 (* ------------------------------------------------------------------------- *)
1815 let fix_tokens_cpp2 tokens =
1816 let tokens2 = ref (tokens +> acc_map
mk_token_extended) in
1819 (* the order is important, if you put the action heuristic first,
1820 * then because of ifdef, can have not closed paren
1821 * and so may believe that higher order macro
1822 * and it will eat too much tokens. So important to do
1825 * I recompute multiple times cleaner cos the mutable
1826 * can have be changed and so may have more comments
1827 * in the token original list.
1832 let cleaner = !tokens2 +> List.filter
(fun x
->
1833 not
(TH.is_comment x
.tok
) (* could filter also #define/#include *)
1835 let ifdef_grouped = mk_ifdef cleaner in
1836 set_ifdef_parenthize_info ifdef_grouped;
1838 find_ifdef_funheaders ifdef_grouped;
1839 find_ifdef_bool ifdef_grouped;
1840 find_ifdef_mid ifdef_grouped;
1841 adjust_inifdef_include ifdef_grouped;
1845 let cleaner = !tokens2 +> filter_cpp_stuff in
1847 let paren_grouped = mk_parenthised cleaner in
1848 apply_macro_defs paren_grouped;
1849 (* because the before field is used by apply_macro_defs *)
1850 tokens2 := rebuild_tokens_extented !tokens2;
1852 (* tagging contextual info (InFunc, InStruct, etc). Better to do
1853 * that after the "ifdef-simplification" phase.
1855 let cleaner = !tokens2 +> List.filter
(fun x
->
1856 not
(TH.is_comment x
.tok
) (* could filter also #define/#include *)
1859 let brace_grouped = mk_braceised cleaner in
1860 set_context_tag brace_grouped;
1865 let cleaner = !tokens2 +> filter_cpp_stuff in
1867 let paren_grouped = mk_parenthised cleaner in
1868 let line_paren_grouped = mk_line_parenthised paren_grouped in
1869 find_define_init_brace_paren paren_grouped;
1870 find_string_macro_paren paren_grouped;
1871 find_macro_lineparen line_paren_grouped;
1872 find_macro_paren paren_grouped;
1876 let cleaner = !tokens2 +> filter_cpp_stuff in
1877 let paren_grouped = mk_parenthised cleaner in
1878 find_actions paren_grouped;
1881 insert_virtual_positions (!tokens2 +> acc_map
(fun x
-> x
.tok
))
1885 Common.profile_code_exclusif
"HACK" (fun () -> fix_tokens_cpp2 a
)
1887 let fix_tokens_cpp a
=
1888 Common.profile_code
"C parsing.fix_cpp" (fun () -> time_hack1 a
)
1893 (*****************************************************************************)
1894 (* The #define tricks *)
1895 (*****************************************************************************)
1897 (* ugly hack, a better solution perhaps would be to erase TDefEOL
1898 * from the Ast and list of tokens in parse_c.
1900 * note: I do a +1 somewhere, it's for the unparsing to correctly sync.
1902 * note: can't replace mark_end_define by simply a fakeInfo(). The reason
1903 * is where is the \n TCommentSpace. Normally there is always a last token
1904 * to synchronize on, either EOF or the token of the next toplevel.
1905 * In the case of the #define we got in list of token
1906 * [TCommentSpace "\n"; TDefEOL] but if TDefEOL is a fakeinfo then we will
1907 * not synchronize on it and so we will not print the "\n".
1908 * A solution would be to put the TDefEOL before the "\n".
1910 * todo?: could put a ExpandedTok for that ?
1912 let mark_end_define ii =
1914 { Ast_c.pinfo
= Ast_c.OriginTok
{ (Ast_c.parse_info_of_info
ii) with
1916 Common.charpos
= Ast_c.pos_of_info
ii + 1
1918 cocci_tag
= ref Ast_c.emptyAnnot
;
1919 comments_tag
= ref Ast_c.emptyComments
;
1924 (* put the TDefEOL at the good place *)
1925 let rec define_line_1 acc xs
=
1927 | [] -> List.rev acc
1929 let line = Ast_c.line_of_info
ii in
1930 let acc = (TDefine
ii) :: acc in
1931 define_line_2
acc line ii xs
1932 | TCppEscapedNewline
ii::xs
->
1933 pr2 "WIERD: a \\ outside a #define";
1934 let acc = (TCommentSpace
ii) :: acc in
1935 define_line_1 acc xs
1936 | x
::xs
-> define_line_1 (x
::acc) xs
1938 and define_line_2
acc line lastinfo xs
=
1941 (* should not happened, should meet EOF before *)
1943 List.rev
(mark_end_define lastinfo
::acc)
1945 let line'
= TH.line_of_tok x
in
1946 let info = TH.info_of_tok x
in
1950 let acc = (mark_end_define lastinfo
) :: acc in
1951 let acc = (EOF
ii) :: acc in
1952 define_line_1 acc xs
1953 | TCppEscapedNewline
ii ->
1954 if (line'
<> line) then pr2 "PB: WIERD: not same line number";
1955 let acc = (TCommentSpace
ii) :: acc in
1956 define_line_2
acc (line+1) info xs
1959 then define_line_2
(x
::acc) line info xs
1960 else define_line_1 (mark_end_define lastinfo
::acc) (x
::xs
)
1963 let rec define_ident acc xs
=
1965 | [] -> List.rev
acc
1967 let acc = TDefine
ii :: acc in
1969 | TCommentSpace i1
::TIdent
(s
,i2
)::TOPar
(i3
)::xs
->
1970 (* Change also the kind of TIdent to avoid bad interaction
1971 * with other parsing_hack tricks. For instant if keep TIdent then
1972 * the stringication algo can believe the TIdent is a string-macro.
1973 * So simpler to change the kind of the ident too.
1975 (* if TOParDefine sticked to the ident, then
1976 * it's a macro-function. Change token to avoid ambiguity
1977 * between #define foo(x) and #define foo (x)
1979 let acc = (TCommentSpace i1
) :: acc in
1980 let acc = (TIdentDefine
(s
,i2
)) :: acc in
1981 let acc = (TOParDefine i3
) :: acc in
1983 | TCommentSpace i1
::TIdent
(s
,i2
)::xs
->
1984 let acc = (TCommentSpace i1
) :: acc in
1985 let acc = (TIdentDefine
(s
,i2
)) :: acc in
1988 pr2 "WIERD: wierd #define body";
1992 let acc = x
:: acc in
1997 let fix_tokens_define2 xs
=
1998 define_ident [] (define_line_1 [] xs
)
2000 let fix_tokens_define a
=
2001 Common.profile_code
"C parsing.fix_define" (fun () -> fix_tokens_define2 a
)
2004 (*****************************************************************************)
2005 (* for the cpp-builtin, standard.h, part 0 *)
2006 (*****************************************************************************)
2008 let macro_body_to_maybe_hint body =
2010 | [] -> DefineBody
body
2011 | [TIdent
(s
,i1
)] ->
2012 (match parsinghack_hint_of_string s
with
2013 | Some hint
-> DefineHint hint
2014 | None
-> DefineBody
body
2016 | xs
-> DefineBody
body
2019 let rec define_parse xs
=
2022 | TDefine i1
::TIdentDefine
(s
,i2
)::TOParDefine i3
::xs
->
2023 let (tokparams
, _
, xs
) =
2024 xs
+> Common.split_when
(function TCPar _
-> true | _
-> false) in
2026 xs
+> Common.split_when
(function TDefEOL _
-> true | _
-> false) in
2028 tokparams
+> Common.map_filter
(function
2030 | TIdent
(s
, _
) -> Some s
2031 | x
-> error_cant_have x
2033 let body = body +> List.map
2034 (TH.visitor_info_of_tok
Ast_c.make_expanded
) in
2035 let def = (s
, (s
, Params
params, macro_body_to_maybe_hint body)) in
2036 def::define_parse xs
2038 | TDefine i1
::TIdentDefine
(s
,i2
)::xs
->
2040 xs
+> Common.split_when
(function TDefEOL _
-> true | _
-> false) in
2041 let body = body +> List.map
2042 (TH.visitor_info_of_tok
Ast_c.make_expanded
) in
2043 let def = (s
, (s
, NoParam
, macro_body_to_maybe_hint body)) in
2044 def::define_parse xs
2049 | x
::xs
-> define_parse xs
2052 let extract_cpp_define xs
=
2053 let cleaner = xs
+> List.filter
(fun x
->
2054 not
(TH.is_comment x
)
2056 define_parse cleaner
2061 (*****************************************************************************)
2062 (* Lexing with lookahead *)
2063 (*****************************************************************************)
2065 (* Why using yet another parsing_hack technique ? The fix_xxx where do
2066 * some pre-processing on the full list of tokens is not enough ?
2067 * No cos sometimes we need more contextual info, and even if
2068 * set_context() tries to give some contextual info, it's not completely
2069 * accurate so the following code give yet another alternative, yet another
2070 * chance to transform some tokens.
2072 * todo?: maybe could try to get rid of this technique. Maybe a better
2073 * set_context() would make possible to move this code using a fix_xx
2076 * LALR(k) trick. We can do stuff by adding cases in lexer_c.mll, but
2077 * it is more general to do it via my LALR(k) tech. Because here we can
2078 * transform some token give some context information. So sometimes it
2079 * makes sense to transform a token in one context, sometimes not, and
2080 * lex can not provide us this context information. Note that the order
2081 * in the pattern matching in lookahead is important. Do not cut/paste.
2083 * Note that in next there is only "clean" tokens, there is no comment
2084 * or space tokens. This is done by the caller.
2088 open Lexer_parser
(* for the fields of lexer_hint type *)
2090 let not_struct_enum = function
2091 | (Parser_c.Tstruct _
| Parser_c.Tunion _
| Parser_c.Tenum _
)::_
-> false
2095 let lookahead2 ~pass next before
=
2097 match (next
, before
) with
2099 (*-------------------------------------------------------------*)
2100 (* typedef inference, parse_typedef_fix3 *)
2101 (*-------------------------------------------------------------*)
2103 | (TIdent
(s
,i1
)::TIdent
(s2
,i2
)::_
, _
) when not_struct_enum before
&& s
= s2
2105 (* (take_safe 1 !passed_tok <> [TOPar]) -> *)
2107 (* parse_typedef_fix3:
2108 * acpi_object acpi_object;
2109 * etait mal parsé, car pas le temps d'appeler dt() dans le type_spec.
2110 * Le parser en interne a deja appelé le prochain token pour pouvoir
2111 * decider des choses.
2112 * => special case in lexer_heuristic, again
2114 if !Flag_parsing_c.debug_typedef
2115 then pr2 ("TYPEDEF: disable typedef cos special case: " ^ s
);
2117 LP.disable_typedef
();
2119 msg_typedef s
; LP.add_typedef_root s
;
2120 TypedefIdent
(s
, i1
)
2123 | (TIdent
(s
, i1
)::TIdent
(s2
, i2
)::_
, _
) when not_struct_enum before
2126 (* && not_annot s2 BUT lead to false positive*)
2128 msg_typedef s
; LP.add_typedef_root s
;
2129 TypedefIdent
(s
, i1
)
2133 | (TIdent
(s
, i1
)::Tinline i2
::_
, _
) when not_struct_enum before
2136 msg_typedef s
; LP.add_typedef_root s
;
2137 TypedefIdent
(s
, i1
)
2140 (* [,(] xx [,)] AND param decl *)
2141 | (TIdent
(s
, i1
)::(TComma _
|TCPar _
)::_
, (TComma _
|TOPar _
)::_
)
2142 when not_struct_enum before
&& (LP.current_context
() = LP.InParameter
)
2145 msg_typedef s
; LP.add_typedef_root s
;
2146 TypedefIdent
(s
, i1
)
2149 (* specialcase: [,(] xx* [,)] *)
2150 | (TIdent
(s
, i1
)::TMul _
::(TComma _
|TCPar _
)::_
, (*(TComma _|TOPar _)::*)_
)
2151 when not_struct_enum before
2152 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2155 msg_typedef s
; LP.add_typedef_root s
;
2156 TypedefIdent
(s
, i1
)
2160 (* specialcase: [,(] xx** [,)] *)
2161 | (TIdent
(s
, i1
)::TMul _
::TMul _
::(TComma _
|TCPar _
)::_
, (*(TComma _|TOPar _)::*)_
)
2162 when not_struct_enum before
2163 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2166 msg_typedef s
; LP.add_typedef_root s
;
2167 TypedefIdent
(s
, i1
)
2171 (* xx const * USELESS because of next rule ? *)
2172 | (TIdent
(s
, i1
)::(Tconst _
|Tvolatile _
|Trestrict _
)::TMul _
::_
, _
)
2173 when not_struct_enum before
2174 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2178 msg_typedef s
; LP.add_typedef_root s
;
2179 TypedefIdent
(s
, i1
)
2182 | (TIdent
(s
, i1
)::(Tconst _
|Tvolatile _
|Trestrict _
)::_
, _
)
2183 when not_struct_enum before
2185 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2188 msg_typedef s
; LP.add_typedef_root s
;
2189 TypedefIdent
(s
, i1
)
2193 | (TIdent
(s
, i1
)::TMul _
::(Tconst _
| Tvolatile _
|Trestrict _
)::_
, _
)
2194 when not_struct_enum before
2197 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2199 msg_typedef s
; LP.add_typedef_root s
;
2200 TypedefIdent
(s
, i1
)
2204 | (TIdent
(s
, i1
)::TCPar _
::_
, (Tconst _
| Tvolatile _
|Trestrict _
)::TOPar _
::_
) when
2206 msg_typedef s
; LP.add_typedef_root s
;
2207 TypedefIdent
(s
, i1
)
2211 (* ( xx ) [sizeof, ~] *)
2212 | (TIdent
(s
, i1
)::TCPar _
::(Tsizeof _
|TTilde _
)::_
, TOPar _
::_
)
2213 when not_struct_enum before
2216 msg_typedef s
; LP.add_typedef_root s
;
2217 TypedefIdent
(s
, i1
)
2219 (* [(,] xx [ AND parameterdeclaration *)
2220 | (TIdent
(s
, i1
)::TOCro _
::_
, (TComma _
|TOPar _
)::_
)
2221 when (LP.current_context
() = LP.InParameter
)
2224 msg_typedef s
; LP.add_typedef_root s
;
2225 TypedefIdent
(s
, i1
)
2227 (*------------------------------------------------------------*)
2228 (* if 'x*y' maybe an expr, maybe just a classic multiplication *)
2229 (* but if have a '=', or ',' I think not *)
2230 (*------------------------------------------------------------*)
2232 (* static xx * yy *)
2233 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::_
,
2234 (Tregister _
|Tstatic _
|Tvolatile _
|Tconst _
|Trestrict _
)::_
) when
2237 msg_typedef s
; LP.add_typedef_root s
;
2238 TypedefIdent
(s
, i1
)
2240 (* TODO xx * yy ; AND in start of compound element *)
2243 (* xx * yy, AND in paramdecl *)
2244 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TComma _
::_
, _
)
2245 when not_struct_enum before
&& (LP.current_context
() = LP.InParameter
)
2249 msg_typedef s
; LP.add_typedef_root s
;
2250 TypedefIdent
(s
, i1
)
2253 (* xx * yy ; AND in Toplevel, except when have = before *)
2254 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TPtVirg _
::_
, TEq _
::_
) ->
2256 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TPtVirg _
::_
, _
)
2257 when not_struct_enum before
&& (LP.is_top_or_struct
(LP.current_context
()))
2259 msg_typedef s
; LP.add_typedef_root s
;
2260 TypedefIdent
(s
, i1
)
2262 (* xx * yy , AND in Toplevel *)
2263 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TComma _
::_
, _
)
2264 when not_struct_enum before
&& (LP.current_context
() = LP.InTopLevel
)
2268 msg_typedef s
; LP.add_typedef_root s
;
2269 TypedefIdent
(s
, i1
)
2271 (* xx * yy ( AND in Toplevel *)
2272 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TOPar _
::_
, _
)
2273 when not_struct_enum before
2274 && (LP.is_top_or_struct
(LP.current_context
()))
2277 msg_typedef s
; LP.add_typedef_root s
;
2278 TypedefIdent
(s
, i1
)
2281 (* todo? enough ? cos in struct def we can have some expression ! *)
2282 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TOCro _
::_
, _
)
2283 when not_struct_enum before
&&
2284 (LP.is_top_or_struct
(LP.current_context
()))
2287 msg_typedef s
; LP.add_typedef_root s
;
2288 TypedefIdent
(s
, i1
)
2290 (* u16: 10; in struct *)
2291 | (TIdent
(s
, i1
)::TDotDot _
::_
, (TOBrace _
| TPtVirg _
)::_
)
2292 when (LP.is_top_or_struct
(LP.current_context
()))
2295 msg_typedef s
; LP.add_typedef_root s
;
2296 TypedefIdent
(s
, i1
)
2299 (* why need TOPar condition as stated in preceding rule ? really needed ? *)
2300 (* YES cos at toplevel can have some expression !! for instance when *)
2301 (* enter in the dimension of an array *)
2303 | (TIdent s::TMul::TIdent s2::_ , _)
2304 when (take_safe 1 !passed_tok <> [Tstruct] &&
2305 (take_safe 1 !passed_tok <> [Tenum]))
2307 !LP._lexer_hint = Some LP.Toplevel ->
2309 LP.add_typedef_root s;
2314 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TEq _
::_
, _
)
2315 when not_struct_enum before
2318 msg_typedef s
; LP.add_typedef_root s
;
2319 TypedefIdent
(s
, i1
)
2322 (* xx * yy) AND in paramdecl *)
2323 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TCPar _
::_
, _
)
2324 when not_struct_enum before
&& (LP.current_context
() = LP.InParameter
)
2327 msg_typedef s
; LP.add_typedef_root s
;
2328 TypedefIdent
(s
, i1
)
2331 (* xx * yy; *) (* wrong ? *)
2332 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TPtVirg _
::_
,
2333 (TOBrace _
| TPtVirg _
)::_
) when not_struct_enum before
2336 msg_typedef s
; LP.add_typedef_root s
;
2337 msg_maybe_dangereous_typedef s
;
2338 TypedefIdent
(s
, i1
)
2341 (* xx * yy, and ';' before xx *) (* wrong ? *)
2342 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TComma _
::_
,
2343 (TOBrace _
| TPtVirg _
)::_
) when
2346 msg_typedef s
; LP.add_typedef_root s
;
2347 TypedefIdent
(s
, i1
)
2351 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::_
, _
)
2352 when s
==~
regexp_typedef && not_struct_enum before
2353 (* struct user_info_t sometimes *)
2356 msg_typedef s
; LP.add_typedef_root s
;
2357 TypedefIdent
(s
, i1
)
2359 (* xx ** yy *) (* wrong ? *)
2360 | (TIdent
(s
, i1
)::TMul _
::TMul _
::TIdent
(s2
, i2
)::_
, _
)
2361 when not_struct_enum before
2362 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2365 msg_typedef s
; LP.add_typedef_root s
;
2366 TypedefIdent
(s
, i1
)
2369 | (TIdent
(s
, i1
)::TMul _
::TMul _
::TMul _
::TIdent
(s2
, i2
)::_
, _
)
2370 when not_struct_enum before
2372 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2374 msg_typedef s
; LP.add_typedef_root s
;
2375 TypedefIdent
(s
, i1
)
2378 | (TIdent
(s
, i1
)::TMul _
::TMul _
::TCPar _
::_
, _
)
2379 when not_struct_enum before
2380 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2383 msg_typedef s
; LP.add_typedef_root s
;
2384 TypedefIdent
(s
, i1
)
2388 (* ----------------------------------- *)
2389 (* old: why not do like for other rules and start with TIdent ?
2390 * why do TOPar :: TIdent :: ..., _ and not TIdent :: ..., TOPAr::_ ?
2391 * new: prefer now start with TIdent because otherwise the add_typedef_root
2392 * may have no effect if in second pass or if have disable the add_typedef.
2396 | (TIdent
(s
, i1
)::TCPar i2
::(TIdent
(_
,i3
)|TInt
(_
,i3
))::_
,
2398 when not
(TH.is_stuff_taking_parenthized x
) &&
2399 Ast_c.line_of_info i2
= Ast_c.line_of_info i3
2403 msg_typedef s
; LP.add_typedef_root s
;
2405 TypedefIdent
(s
, i1
)
2409 | (TIdent
(s
, i1
)::TCPar _
::TOPar _
::_
, (TOPar
info)::x
::_
)
2410 when not
(TH.is_stuff_taking_parenthized x
)
2413 msg_typedef s
; LP.add_typedef_root s
;
2415 TypedefIdent
(s
, i1
)
2418 | (TIdent
(s
, i1
)::TMul _
::TCPar _
::TIdent
(s2
, i2
)::_
, (TOPar
info)::_
) when
2421 msg_typedef s
; LP.add_typedef_root s
;
2426 (* (xx){ ... } constructor *)
2427 | (TIdent
(s
, i1
)::TCPar _
::TOBrace _
::_
, TOPar _
::x
::_
)
2428 when (*s ==~ regexp_typedef && *) not
(TH.is_stuff_taking_parenthized x
)
2431 msg_typedef s
; LP.add_typedef_root s
;
2432 TypedefIdent
(s
, i1
)
2435 (* can have sizeof on expression
2436 | (Tsizeof::TOPar::TIdent s::TCPar::_, _) ->
2438 LP.add_typedef_root s;
2441 (* x ( *y )(params), function pointer *)
2442 | (TIdent
(s
, i1
)::TOPar _
::TMul _
::TIdent _
::TCPar _
::TOPar _
::_
, _
)
2443 when not_struct_enum before
2446 msg_typedef s
; LP.add_typedef_root s
;
2447 TypedefIdent
(s
, i1
)
2450 (*-------------------------------------------------------------*)
2452 (*-------------------------------------------------------------*)
2453 | ((TIfdef
(_
,ii) |TIfdefelse
(_
,ii) |TIfdefelif
(_
,ii) |TEndif
(_
,ii) |
2454 TIfdefBool
(_
,_
,ii)|TIfdefMisc
(_
,_
,ii)|TIfdefVersion
(_
,_
,ii))
2459 if not !Flag_parsing_c.ifdef_to_if
2460 then TCommentCpp (Ast_c.CppDirective, ii)
2463 (* not !LP._lexer_hint.toplevel *)
2464 if !Flag_parsing_c.ifdef_directive_passing
2468 if (LP.current_context
() = LP.InInitializer
)
2470 pr2 "In Initializer passing"; (* cheat: dont count in stat *)
2471 incr
Stat.nIfdefInitializer
;
2474 else msg_ifdef_passing ()
2477 TCommentCpp
(Ast_c.CppDirective
, ii)
2481 | (TUndef
(id
, ii) as x
)::_
, _
2485 pr2_once
("CPP-UNDEF: I treat it as comment");
2486 TCommentCpp
(Ast_c.CppDirective
, ii)
2490 (* If ident contain a for_each, then certainly a macro. But to be
2491 * sure should look if there is a '{' after the ')', but it requires
2492 * to count the '('. Because this can be expensive, we do that only
2493 * when the token contains "for_each".
2495 | (TIdent
(s
, i1
)::TOPar _
::rest
, _
) when not
(LP.current_context
() = LP.InTopLevel
)
2496 (* otherwise a function such as static void loopback_enable(int i) {
2497 * will be considered as a loop
2502 if s
==~
regexp_foreach &&
2503 is_really_foreach (Common.take_safe
forLOOKAHEAD rest
)
2507 TMacroIterator
(s
, i1
)
2513 (*-------------------------------------------------------------*)
2515 | _
-> raise Impossible
2517 let lookahead ~pass a b
=
2518 Common.profile_code
"C parsing.lookahead" (fun () -> lookahead2 ~pass a b
)