3 * Copyright (C) 2007, 2008 Ecole des Mines de Nantes
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License (GPL)
7 * version 2 as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * file license.txt for more details.
17 module TH
= Token_helpers
18 module LP
= Lexer_parser
20 module Stat
= Parsing_stat
24 (*****************************************************************************)
25 (* Some debugging functions *)
26 (*****************************************************************************)
29 if !Flag_parsing_c.verbose_parsing
33 if !Flag_parsing_c.verbose_parsing
34 then Common.pr2_once s
37 if !Flag_parsing_c.debug_cpp
38 then Common.pr2_once ("CPP-" ^ s
)
41 let msg_gen cond is_known printer s
=
44 if not
(!Flag_parsing_c.filter_msg
)
51 (* In the following, there are some harcoded names of types or macros
52 * but they are not used by our heuristics! They are just here to
53 * enable to detect false positive by printing only the typedef/macros
54 * that we don't know yet. If we print everything, then we can easily
55 * get lost with too much verbose tracing information. So those
56 * functions "filter" some messages. So our heuristics are still good,
57 * there is no more (or not that much) hardcoded linux stuff.
63 | "u_char" | "u_short" | "u_int" | "u_long"
64 | "u8" | "u16" | "u32" | "u64"
65 | "s8" | "s16" | "s32" | "s64"
66 | "__u8" | "__u16" | "__u32" | "__u64"
77 | s
when s
=~
".*_t$" -> true
82 (* note: cant use partial application with let msg_typedef =
83 * because it would compute msg_typedef at compile time when
84 * the flag debug_typedef is always false
87 incr
Stat.nTypedefInfer
;
88 msg_gen (!Flag_parsing_c.debug_typedef
)
91 pr2_cpp ("TYPEDEF: promoting: " ^ s
)
95 let msg_maybe_dangereous_typedef s
=
96 if not
(is_known_typdef s
)
99 ("PB MAYBE: dangerous typedef inference, maybe not a typedef: " ^ s
)
103 let msg_declare_macro s
=
104 incr
Stat.nMacroDecl
;
105 msg_gen (!Flag_parsing_c.debug_cpp
)
108 | "DECLARE_MUTEX" | "DECLARE_COMPLETION" | "DECLARE_RWSEM"
109 | "DECLARE_WAITQUEUE" | "DECLARE_WAIT_QUEUE_HEAD"
110 | "DEFINE_SPINLOCK" | "DEFINE_TIMER"
111 | "DEVICE_ATTR" | "CLASS_DEVICE_ATTR" | "DRIVER_ATTR"
112 | "SENSOR_DEVICE_ATTR"
114 | "DECLARE_WORK" | "DECLARE_TASKLET"
115 | "PORT_ATTR_RO" | "PORT_PMA_ATTR"
120 | s when s =~ "^DECLARE_.*" -> true
121 | s when s =~ ".*_ATTR$" -> true
122 | s when s =~ "^DEFINE_.*" -> true
128 (fun s
-> pr2_cpp ("MACRO: found declare-macro: " ^ s
))
133 incr
Stat.nIteratorHeuristic
;
134 pr2_cpp ("MACRO: found foreach: " ^ s
)
138 let msg_debug_macro s =
139 pr2_cpp ("MACRO: found debug-macro: " ^ s)
143 let msg_macro_noptvirg s
=
144 incr
Stat.nMacroStmt
;
145 pr2_cpp ("MACRO: found macro with param noptvirg: " ^ s
)
147 let msg_macro_toplevel_noptvirg s
=
148 incr
Stat.nMacroStmt
;
149 pr2_cpp ("MACRO: found toplevel macro noptvirg: " ^ s
)
151 let msg_macro_noptvirg_single s
=
152 incr
Stat.nMacroStmt
;
153 pr2_cpp ("MACRO: found single-macro noptvirg: " ^ s
)
158 let msg_macro_higher_order s
=
159 incr
Stat.nMacroHigherOrder
;
160 msg_gen (!Flag_parsing_c.debug_cpp
)
170 (fun s
-> pr2_cpp ("MACRO: found higher ordre macro : " ^ s
))
174 let msg_stringification s
=
175 incr
Stat.nMacroString
;
176 msg_gen (!Flag_parsing_c.debug_cpp
)
184 (* s when s =~ ".*STR.*" -> true *)
188 (fun s
-> pr2_cpp ("MACRO: found string-macro " ^ s
))
191 let msg_stringification_params s
=
192 incr
Stat.nMacroString
;
193 pr2_cpp ("MACRO: string-macro with params : " ^ s
)
197 let msg_apply_known_macro s
=
198 incr
Stat.nMacroExpand
;
199 pr2_cpp ("MACRO: found known macro = " ^ s
)
201 let msg_apply_known_macro_hint s
=
202 incr
Stat.nMacroHint
;
203 pr2_cpp ("MACRO: found known macro hint = " ^ s
)
208 let msg_ifdef_bool_passing is_ifdef_positif
=
209 incr
Stat.nIfdefZero
; (* of Version ? *)
211 then pr2_cpp "commenting parts of a #if 1 or #if LINUX_VERSION"
212 else pr2_cpp "commenting a #if 0 or #if LINUX_VERSION or __cplusplus"
215 let msg_ifdef_mid_something () =
216 incr
Stat.nIfdefExprPassing
;
217 pr2_cpp "found ifdef-mid-something"
219 let msg_ifdef_funheaders () =
220 incr
Stat.nIfdefFunheader
;
224 let msg_attribute s
=
225 incr
Stat.nMacroAttribute
;
230 (*****************************************************************************)
231 (* The regexp and basic view definitions *)
232 (*****************************************************************************)
234 (* opti: better to built then once and for all, especially regexp_foreach *)
236 let regexp_macro = Str.regexp
240 let regexp_annot = Str.regexp
244 let regexp_declare = Str.regexp
248 let regexp_foreach = Str.regexp_case_fold
249 ".*\\(for_?each\\|for_?all\\|iterate\\|loop\\|walk\\|scan\\|each\\|for\\)"
251 let regexp_typedef = Str.regexp
254 let false_typedef = [
259 let ok_typedef s
= not
(List.mem s
false_typedef)
262 not
(s
==~
regexp_annot)
265 (* ------------------------------------------------------------------------- *)
266 (* cpp part 1 for standard.h *)
267 (* ------------------------------------------------------------------------- *)
269 type define_def
= string * define_param
* define_body
272 | Params
of string list
274 | DefineBody
of Parser_c.token list
275 | DefineHint
of parsinghack_hint
277 and parsinghack_hint
=
283 | HintMacroIdentBuilder
286 (* cf also data/test.h *)
287 let assoc_hint_string = [
288 "YACFE_ITERATOR" , HintIterator
;
289 "YACFE_DECLARATOR" , HintDeclarator
;
290 "YACFE_STRING" , HintMacroString
;
291 "YACFE_STATEMENT" , HintMacroStatement
;
292 "YACFE_ATTRIBUTE" , HintAttribute
;
293 "YACFE_IDENT_BUILDER" , HintMacroIdentBuilder
;
295 "MACROSTATEMENT" , HintMacroStatement
; (* backward compatibility *)
299 let (parsinghack_hint_of_string
: string -> parsinghack_hint
option) = fun s
->
300 Common.assoc_option s
assoc_hint_string
302 let (is_parsinghack_hint
: string -> bool) = fun s
->
303 parsinghack_hint_of_string s
<> None
305 let (token_from_parsinghack_hint
:
306 (string * Ast_c.info
) -> parsinghack_hint
-> Parser_c.token
) =
310 Parser_c.TMacroIterator
(s
, ii
)
312 Parser_c.TMacroDecl
(s
, ii
)
314 Parser_c.TMacroString
(s
, ii
)
315 | HintMacroStatement
->
316 Parser_c.TMacroStmt
(s
, ii
)
318 Parser_c.TMacroAttr
(s
, ii
)
319 | HintMacroIdentBuilder
->
320 Parser_c.TMacroIdentBuilder
(s
, ii
)
324 let (_defs
: (string, define_def
) Hashtbl.t
ref) =
325 ref (Hashtbl.create
101)
328 (* ------------------------------------------------------------------------- *)
329 (* fuzzy parsing, different "views" over the same program *)
330 (* ------------------------------------------------------------------------- *)
333 (* Normally I should not use ref/mutable in the token_extended type
334 * and I should have a set of functions taking a list of tokens and
335 * returning a list of tokens. The problem is that to make easier some
336 * functions, it is better to work on better representation, on "views"
337 * over this list of tokens. But then modifying those views and get
338 * back from those views to the original simple list of tokens is
339 * tedious. One way is to maintain next to the view a list of "actions"
340 * (I was using a hash storing the charpos of the token and associating
341 * the action) but it is tedious too. Simpler to use mutable/ref. We
342 * use the same idea that we use when working on the Ast_c. *)
344 (* old: when I was using the list of "actions" next to the views, the hash
345 * indexed by the charpos, there could have been some problems:
346 * how my fake_pos interact with the way I tag and adjust token ?
347 * because I base my tagging on the position of the token ! so sometimes
348 * could tag another fakeInfo that should not be tagged ?
349 * fortunately I don't use anymore this technique.
352 (* update: quite close to the Place_c.Inxxx *)
354 InFunction
| InEnum
| InStruct
| InInitializer
| NoContext
356 type token_extended
= {
357 mutable tok
: Parser_c.token
;
358 mutable where
: context
;
360 (* less: need also a after ? *)
361 mutable new_tokens_before
: Parser_c.token list
;
363 (* line x col cache, more easily accessible, of the info in the token *)
368 let set_as_comment cppkind x
=
370 then () (* otherwise parse_c will be lost if don't find a EOF token *)
372 x
.tok
<- TCommentCpp
(cppkind
, TH.info_of_tok x
.tok
)
374 let mk_token_extended x
=
375 let (line
, col
) = TH.linecol_of_tok x
in
377 line
= line
; col
= col
;
379 new_tokens_before
= [];
383 (* x list list, because x list separated by ',' *)
385 | Parenthised
of paren_grouped list list
* token_extended list
386 | PToken
of token_extended
390 brace_grouped list list
* token_extended
* token_extended
option
391 | BToken
of token_extended
393 (* Far better data structure than doing hacks in the lexer or parser
394 * because in lexer we don't know to which ifdef a endif is related
395 * and so when we want to comment a ifdef, we don't know which endif
396 * we must also comment. Especially true for the #if 0 which sometimes
399 * x list list, because x list separated by #else or #elif
402 | Ifdef
of ifdef_grouped list list
* token_extended list
403 | Ifdefbool
of bool * ifdef_grouped list list
* token_extended list
404 | NotIfdefLine
of token_extended list
407 type 'a line_grouped
=
411 type body_function_grouped
=
412 | BodyFunction
of token_extended list
413 | NotBodyLine
of token_extended list
416 (* ------------------------------------------------------------------------- *)
418 (* ------------------------------------------------------------------------- *)
420 (* todo: synchro ! use more indentation
421 * if paren not closed and same indentation level, certainly because
422 * part of a mid-ifdef-expression.
424 let rec mk_parenthised xs
=
429 | TOPar _
| TOParDefine _
->
430 let body, extras
, xs
= mk_parameters
[x
] [] xs
in
431 Parenthised
(body,extras
)::mk_parenthised xs
433 PToken x
::mk_parenthised xs
436 (* return the body of the parenthised expression and the rest of the tokens *)
437 and mk_parameters extras acc_before_sep xs
=
440 (* maybe because of #ifdef which "opens" '(' in 2 branches *)
441 pr2 "PB: not found closing paren in fuzzy parsing";
442 [List.rev acc_before_sep
], List.rev extras
, []
446 | TOBrace _
when x
.col
=|= 0 ->
447 pr2 "PB: found synchro point } in paren";
448 [List.rev acc_before_sep
], List.rev
(extras
), (x
::xs
)
450 | TCPar _
| TCParEOL _
->
451 [List.rev acc_before_sep
], List.rev
(x
::extras
), xs
452 | TOPar _
| TOParDefine _
->
453 let body, extrasnest
, xs
= mk_parameters
[x
] [] xs
in
455 (Parenthised
(body,extrasnest
)::acc_before_sep
)
458 let body, extras
, xs
= mk_parameters
(x
::extras
) [] xs
in
459 (List.rev acc_before_sep
)::body, extras
, xs
461 mk_parameters extras
(PToken x
::acc_before_sep
) xs
467 let rec mk_braceised xs
=
473 let body, endbrace
, xs
= mk_braceised_aux
[] xs
in
474 Braceised
(body, x
, endbrace
)::mk_braceised xs
476 pr2 "PB: found closing brace alone in fuzzy parsing";
477 BToken x
::mk_braceised xs
479 BToken x
::mk_braceised xs
482 (* return the body of the parenthised expression and the rest of the tokens *)
483 and mk_braceised_aux acc xs
=
486 (* maybe because of #ifdef which "opens" '(' in 2 branches *)
487 pr2 "PB: not found closing brace in fuzzy parsing";
488 [List.rev acc
], None
, []
491 | TCBrace _
-> [List.rev acc
], Some x
, xs
493 let body, endbrace
, xs
= mk_braceised_aux
[] xs
in
494 mk_braceised_aux
(Braceised
(body,x
, endbrace
)::acc
) xs
496 mk_braceised_aux
(BToken x
::acc
) xs
502 let rec mk_ifdef xs
=
508 let body, extra
, xs
= mk_ifdef_parameters
[x
] [] xs
in
509 Ifdef
(body, extra
)::mk_ifdef xs
510 | TIfdefBool
(b
,_
, _
) ->
511 let body, extra
, xs
= mk_ifdef_parameters
[x
] [] xs
in
513 (* if not passing, then consider a #if 0 as an ordinary #ifdef *)
514 if !Flag_parsing_c.if0_passing
515 then Ifdefbool
(b
, body, extra
)::mk_ifdef xs
516 else Ifdef
(body, extra
)::mk_ifdef xs
518 | TIfdefMisc
(b
,_
,_
) | TIfdefVersion
(b
,_
,_
) ->
519 let body, extra
, xs
= mk_ifdef_parameters
[x
] [] xs
in
520 Ifdefbool
(b
, body, extra
)::mk_ifdef xs
524 (* todo? can have some Ifdef in the line ? *)
525 let line, xs
= Common.span
(fun y
-> y
.line =|= x
.line) (x
::xs
) in
526 NotIfdefLine
line::mk_ifdef xs
529 and mk_ifdef_parameters extras acc_before_sep xs
=
532 (* Note that mk_ifdef is assuming that CPP instruction are alone
533 * on their line. Because I do a span (fun x -> is_same_line ...)
534 * I might take with me a #endif if this one is mixed on a line
535 * with some "normal" tokens.
537 pr2 "PB: not found closing ifdef in fuzzy parsing";
538 [List.rev acc_before_sep
], List.rev extras
, []
542 [List.rev acc_before_sep
], List.rev
(x
::extras
), xs
544 let body, extrasnest
, xs
= mk_ifdef_parameters
[x
] [] xs
in
546 extras
(Ifdef
(body, extrasnest
)::acc_before_sep
) xs
548 | TIfdefBool
(b
,_
,_
) ->
549 let body, extrasnest
, xs
= mk_ifdef_parameters
[x
] [] xs
in
551 if !Flag_parsing_c.if0_passing
554 extras
(Ifdefbool
(b
, body, extrasnest
)::acc_before_sep
) xs
557 extras
(Ifdef
(body, extrasnest
)::acc_before_sep
) xs
560 | TIfdefMisc
(b
,_
,_
) | TIfdefVersion
(b
,_
,_
) ->
561 let body, extrasnest
, xs
= mk_ifdef_parameters
[x
] [] xs
in
563 extras
(Ifdefbool
(b
, body, extrasnest
)::acc_before_sep
) xs
567 let body, extras
, xs
= mk_ifdef_parameters
(x
::extras
) [] xs
in
568 (List.rev acc_before_sep
)::body, extras
, xs
570 let line, xs
= Common.span
(fun y
-> y
.line =|= x
.line) (x
::xs
) in
571 mk_ifdef_parameters extras
(NotIfdefLine
line::acc_before_sep
) xs
574 (* --------------------------------------- *)
576 let line_of_paren = function
578 | Parenthised
(xxs
, info_parens
) ->
579 (match info_parens
with
580 | [] -> raise Impossible
585 let rec span_line_paren line = function
589 | PToken tok
when TH.is_eof tok
.tok
->
592 if line_of_paren x
=|= line
594 let (l1
, l2
) = span_line_paren line xs
in
600 let rec mk_line_parenthised xs
=
604 let line_no = line_of_paren x
in
605 let line, xs
= span_line_paren line_no xs
in
606 Line
(x
::line)::mk_line_parenthised xs
609 (* --------------------------------------- *)
610 let rec mk_body_function_grouped xs
=
615 | {tok
= TOBrace _
; col
= 0} ->
616 let is_closing_brace = function
617 | {tok
= TCBrace _
; col
= 0 } -> true
620 let body, xs
= Common.span
(fun x
-> not
(is_closing_brace x
)) xs
in
622 | ({tok
= TCBrace _
; col
= 0 })::xs
->
623 BodyFunction
body::mk_body_function_grouped xs
625 pr2 "PB:not found closing brace in fuzzy parsing";
627 | _
-> raise Impossible
631 let line, xs
= Common.span
(fun y
-> y
.line =|= x
.line) (x
::xs
) in
632 NotBodyLine
line::mk_body_function_grouped xs
636 (* ------------------------------------------------------------------------- *)
638 (* ------------------------------------------------------------------------- *)
640 let rec iter_token_paren f xs
=
641 xs
+> List.iter
(function
642 | PToken tok
-> f tok
;
643 | Parenthised
(xxs
, info_parens
) ->
644 info_parens
+> List.iter f
;
645 xxs
+> List.iter
(fun xs
-> iter_token_paren f xs
)
648 let rec iter_token_brace f xs
=
649 xs
+> List.iter
(function
650 | BToken tok
-> f tok
;
651 | Braceised
(xxs
, tok1
, tok2opt
) ->
652 f tok1
; do_option f tok2opt
;
653 xxs
+> List.iter
(fun xs
-> iter_token_brace f xs
)
656 let rec iter_token_ifdef f xs
=
657 xs
+> List.iter
(function
658 | NotIfdefLine xs
-> xs
+> List.iter f
;
659 | Ifdefbool
(_
, xxs
, info_ifdef
)
660 | Ifdef
(xxs
, info_ifdef
) ->
661 info_ifdef
+> List.iter f
;
662 xxs
+> List.iter
(iter_token_ifdef f
)
668 let tokens_of_paren xs
=
670 xs
+> iter_token_paren (fun tok
-> push2 tok
g);
674 let tokens_of_paren_ordered xs
=
677 let rec aux_tokens_ordered = function
678 | PToken tok
-> push2 tok
g;
679 | Parenthised
(xxs
, info_parens
) ->
680 let (opar
, cpar
, commas
) =
681 match info_parens
with
683 (match List.rev xs
with
685 opar
, cpar
, List.rev xs
686 | _
-> raise Impossible
688 | _
-> raise Impossible
691 aux_args
(xxs
,commas
);
694 and aux_args
(xxs
, commas
) =
695 match xxs
, commas
with
697 | [xs
], [] -> xs
+> List.iter
aux_tokens_ordered
698 | xs
::ys
::xxs
, comma
::commas
->
699 xs
+> List.iter
aux_tokens_ordered;
701 aux_args
(ys
::xxs
, commas
)
702 | _
-> raise Impossible
706 xs
+> List.iter
aux_tokens_ordered;
712 (* ------------------------------------------------------------------------- *)
713 (* set the context info in token *)
714 (* ------------------------------------------------------------------------- *)
717 let rec set_in_function_tag xs
=
718 (* could try: ) { } but it can be the ) of a if or while, so
719 * better to base the heuristic on the position in column zero.
720 * Note that some struct or enum or init put also their { in first column
721 * but set_in_other will overwrite the previous InFunction tag.
725 (* ) { and the closing } is in column zero, then certainly a function *)
726 | BToken
({tok
= TCPar _
})::(Braceised
(body, tok1
, Some tok2
))::xs
727 when tok1
.col
<> 0 && tok2
.col
=|= 0 ->
728 body +> List.iter
(iter_token_brace (fun tok
->
729 tok
.where
<- InFunction
731 set_in_function_tag xs
733 | (BToken x
)::xs
-> set_in_function_tag xs
735 | (Braceised
(body, tok1
, Some tok2
))::xs
736 when tok1
.col
=|= 0 && tok2
.col
=|= 0 ->
737 body +> List.iter
(iter_token_brace (fun tok
->
738 tok
.where
<- InFunction
740 set_in_function_tag xs
741 | Braceised
(body, tok1
, tok2
)::xs
->
742 set_in_function_tag xs
745 let rec set_in_other xs
=
749 | BToken
({tok
= Tenum _
})::BToken
({tok
= TIdent _
})
750 ::Braceised
(body, tok1
, tok2
)::xs
751 | BToken
({tok
= Tenum _
})
752 ::Braceised
(body, tok1
, tok2
)::xs
754 body +> List.iter
(iter_token_brace (fun tok
->
760 | BToken
({tok
= Tstruct _
})::BToken
({tok
= TIdent _
})
761 ::Braceised
(body, tok1
, tok2
)::xs
->
762 body +> List.iter
(iter_token_brace (fun tok
->
763 tok
.where
<- InStruct
;
767 | BToken
({tok
= TEq _
})
768 ::Braceised
(body, tok1
, tok2
)::xs
->
769 body +> List.iter
(iter_token_brace (fun tok
->
770 tok
.where
<- InInitializer
;
774 | BToken _
::xs
-> set_in_other xs
776 | Braceised
(body, tok1
, tok2
)::xs
->
777 body +> List.iter
set_in_other;
783 let set_context_tag xs
=
785 set_in_function_tag xs
;
790 (*****************************************************************************)
792 (*****************************************************************************)
794 (* To expand the parameter of the macro. The env corresponds to the actual
795 * code that is binded to the parameters of the macro.
796 * TODO? recurse ? fixpoint ? the expansion may also contain macro.
797 * Or to macro expansion in a strict manner, that is process first
798 * the parameters, expands macro in params, and then process enclosing
801 let rec (cpp_engine
: (string , Parser_c.token list
) assoc
->
802 Parser_c.token list
-> Parser_c.token list
) =
804 xs
+> List.map
(fun tok
->
806 | TIdent
(s
,i1
) when List.mem_assoc s env
-> Common.assoc s env
814 (* ------------------------------------------------------------------------- *)
815 (* the pair is the status of '()' and '{}', ex: (-1,0)
816 * if too much ')' and good '{}'
817 * could do for [] too ?
818 * could do for ',' if encounter ',' at "toplevel", not inside () or {}
819 * then if have ifdef, then certainly can lead to a problem.
821 let (count_open_close_stuff_ifdef_clause
: ifdef_grouped list
-> (int * int)) =
823 let cnt_paren, cnt_brace
= ref 0, ref 0 in
824 xs
+> iter_token_ifdef (fun x
->
826 | x
when TH.is_opar x
-> incr
cnt_paren
827 | TOBrace _
-> incr cnt_brace
828 | x
when TH.is_cpar x
-> decr
cnt_paren
829 | TCBrace _
-> decr cnt_brace
833 !cnt_paren, !cnt_brace
836 (* ------------------------------------------------------------------------- *)
837 let forLOOKAHEAD = 30
840 (* look if there is a '{' just after the closing ')', and handling the
841 * possibility to have nested expressions inside nested parenthesis
843 * todo: use indentation instead of premier(statement) ?
845 let rec is_really_foreach xs
=
846 let rec is_foreach_aux = function
848 | TCPar _
::TOBrace _
::xs
-> true, xs
849 (* the following attempts to handle the cases where there is a
850 single statement in the body of the loop. undoubtedly more
852 todo: premier(statement) - suivant(funcall)
854 | TCPar _
::TIdent _
::xs
-> true, xs
855 | TCPar _
::Tif _
::xs
-> true, xs
856 | TCPar _
::Twhile _
::xs
-> true, xs
857 | TCPar _
::Tfor _
::xs
-> true, xs
858 | TCPar _
::Tswitch _
::xs
-> true, xs
859 | TCPar _
::Treturn _
::xs
-> true, xs
862 | TCPar _
::xs
-> false, xs
864 let (_
, xs'
) = is_foreach_aux xs
in
866 | x
::xs
-> is_foreach_aux xs
868 is_foreach_aux xs
+> fst
871 (* ------------------------------------------------------------------------- *)
872 let set_ifdef_token_parenthize_info cnt x
=
875 | TIfdefelse
(tag
, _
)
876 | TIfdefelif
(tag
, _
)
879 | TIfdefBool
(_
, tag
, _
)
880 | TIfdefMisc
(_
, tag
, _
)
881 | TIfdefVersion
(_
, tag
, _
)
885 | _
-> raise Impossible
889 let ifdef_paren_cnt = ref 0
892 let rec set_ifdef_parenthize_info xs
=
893 xs
+> List.iter
(function
894 | NotIfdefLine xs
-> ()
895 | Ifdefbool
(_
, xxs
, info_ifdef
)
896 | Ifdef
(xxs
, info_ifdef
) ->
898 incr
ifdef_paren_cnt;
899 let total_directives = List.length info_ifdef
in
901 info_ifdef
+> List.iter
(fun x
->
902 set_ifdef_token_parenthize_info (!ifdef_paren_cnt, total_directives)
904 xxs
+> List.iter
set_ifdef_parenthize_info
908 (*****************************************************************************)
909 (* CPP handling: macros, ifdefs, macros defs *)
910 (*****************************************************************************)
912 (* ------------------------------------------------------------------------- *)
913 (* special skip_start skip_end handling *)
914 (* ------------------------------------------------------------------------- *)
916 (* note: after this normally the token list should not contain any more the
917 * TCommentSkipTagStart and End tokens.
919 let rec commentize_skip_start_to_end xs
=
924 | {tok
= TCommentSkipTagStart info
} ->
926 let (before
, x2
, after
) =
927 xs
+> Common.split_when
(function
928 | {tok
= TCommentSkipTagEnd _
} -> true
932 let topass = x
::x2
::before
in
933 topass +> List.iter
(fun tok
->
934 set_as_comment Token_c.CppPassingExplicit tok
936 commentize_skip_start_to_end after
938 failwith
"could not find end of skip_start special comment"
940 | {tok
= TCommentSkipTagEnd info
} ->
941 failwith
"found skip_end comment but no skip_start"
943 commentize_skip_start_to_end xs
949 (* ------------------------------------------------------------------------- *)
950 (* ifdef keeping/passing *)
951 (* ------------------------------------------------------------------------- *)
953 (* #if 0, #if 1, #if LINUX_VERSION handling *)
954 let rec find_ifdef_bool xs
=
955 xs
+> List.iter
(function
956 | NotIfdefLine _
-> ()
957 | Ifdefbool
(is_ifdef_positif
, xxs
, info_ifdef_stmt
) ->
959 msg_ifdef_bool_passing is_ifdef_positif
;
962 | [] -> raise Impossible
963 | firstclause
::xxs
->
964 info_ifdef_stmt
+> List.iter
(set_as_comment Token_c.CppDirective
);
967 then xxs
+> List.iter
968 (iter_token_ifdef (set_as_comment Token_c.CppPassingNormal
))
970 firstclause
+> iter_token_ifdef (set_as_comment Token_c.CppPassingNormal
);
971 (match List.rev xxs
with
975 (iter_token_ifdef (set_as_comment Token_c.CppPassingNormal
))
976 | [] -> (* not #else *) ()
981 | Ifdef
(xxs
, info_ifdef_stmt
) -> xxs
+> List.iter
find_ifdef_bool
986 let thresholdIfdefSizeMid = 6
988 (* infer ifdef involving not-closed expressions/statements *)
989 let rec find_ifdef_mid xs
=
990 xs
+> List.iter
(function
991 | NotIfdefLine _
-> ()
992 | Ifdef
(xxs
, info_ifdef_stmt
) ->
994 | [] -> raise Impossible
996 | first
::second
::rest
->
997 (* don't analyse big ifdef *)
998 if xxs
+> List.for_all
999 (fun xs
-> List.length xs
<= thresholdIfdefSizeMid) &&
1000 (* don't want nested ifdef *)
1001 xxs
+> List.for_all
(fun xs
->
1003 (function NotIfdefLine _
-> true | _
-> false)
1007 let counts = xxs
+> List.map count_open_close_stuff_ifdef_clause
in
1008 let cnt1, cnt2
= List.hd
counts in
1009 if cnt1 <> 0 || cnt2
<> 0 &&
1010 counts +> List.for_all
(fun x
-> x
=*= (cnt1, cnt2
))
1012 if counts +> List.exists (fun (cnt1, cnt2) ->
1013 cnt1 <> 0 || cnt2 <> 0
1017 msg_ifdef_mid_something();
1019 (* keep only first, treat the rest as comment *)
1020 info_ifdef_stmt
+> List.iter
(set_as_comment Token_c.CppDirective
);
1021 (second
::rest
) +> List.iter
1022 (iter_token_ifdef (set_as_comment Token_c.CppPassingCosWouldGetError
));
1026 List.iter
find_ifdef_mid xxs
1028 (* no need complex analysis for ifdefbool *)
1029 | Ifdefbool
(_
, xxs
, info_ifdef_stmt
) ->
1030 List.iter
find_ifdef_mid xxs
1036 let thresholdFunheaderLimit = 4
1038 (* ifdef defining alternate function header, type *)
1039 let rec find_ifdef_funheaders = function
1041 | NotIfdefLine _
::xs
-> find_ifdef_funheaders xs
1043 (* ifdef-funheader if ifdef with 2 lines and a '{' in next line *)
1045 ([(NotIfdefLine
(({col
= 0} as _xline1
)::line1
))::ifdefblock1
;
1046 (NotIfdefLine
(({col
= 0} as xline2
)::line2
))::ifdefblock2
1049 ::NotIfdefLine
(({tok
= TOBrace i
; col
= 0})::line3
)
1051 when List.length ifdefblock1
<= thresholdFunheaderLimit &&
1052 List.length ifdefblock2
<= thresholdFunheaderLimit
1054 find_ifdef_funheaders xs
;
1056 msg_ifdef_funheaders ();
1057 info_ifdef_stmt
+> List.iter
(set_as_comment Token_c.CppDirective
);
1058 let all_toks = [xline2
] @ line2
in
1059 all_toks +> List.iter
(set_as_comment Token_c.CppPassingCosWouldGetError
) ;
1060 ifdefblock2
+> iter_token_ifdef (set_as_comment Token_c.CppPassingCosWouldGetError
);
1062 (* ifdef with nested ifdef *)
1064 ([[NotIfdefLine
(({col
= 0} as _xline1
)::line1
)];
1066 ([[NotIfdefLine
(({col
= 0} as xline2
)::line2
)];
1067 [NotIfdefLine
(({col
= 0} as xline3
)::line3
)];
1073 ::NotIfdefLine
(({tok
= TOBrace i
; col
= 0})::line4
)
1076 find_ifdef_funheaders xs
;
1078 msg_ifdef_funheaders ();
1079 info_ifdef_stmt
+> List.iter
(set_as_comment Token_c.CppDirective
);
1080 info_ifdef_stmt2
+> List.iter
(set_as_comment Token_c.CppDirective
);
1081 let all_toks = [xline2
;xline3
] @ line2
@ line3
in
1082 all_toks +> List.iter
(set_as_comment Token_c.CppPassingCosWouldGetError
);
1084 (* ifdef with elseif *)
1086 ([[NotIfdefLine
(({col
= 0} as _xline1
)::line1
)];
1087 [NotIfdefLine
(({col
= 0} as xline2
)::line2
)];
1088 [NotIfdefLine
(({col
= 0} as xline3
)::line3
)];
1091 ::NotIfdefLine
(({tok
= TOBrace i
; col
= 0})::line4
)
1094 find_ifdef_funheaders xs
;
1096 msg_ifdef_funheaders ();
1097 info_ifdef_stmt
+> List.iter
(set_as_comment Token_c.CppDirective
);
1098 let all_toks = [xline2
;xline3
] @ line2
@ line3
in
1099 all_toks +> List.iter
(set_as_comment Token_c.CppPassingCosWouldGetError
)
1102 | Ifdef
(xxs
,info_ifdef_stmt
)::xs
1103 | Ifdefbool
(_
, xxs
,info_ifdef_stmt
)::xs
->
1104 List.iter
find_ifdef_funheaders xxs
;
1105 find_ifdef_funheaders xs
1110 let rec adjust_inifdef_include xs
=
1111 xs
+> List.iter
(function
1112 | NotIfdefLine _
-> ()
1113 | Ifdef
(xxs
, info_ifdef_stmt
) | Ifdefbool
(_
, xxs
, info_ifdef_stmt
) ->
1114 xxs
+> List.iter
(iter_token_ifdef (fun tokext
->
1115 match tokext
.tok
with
1116 | Parser_c.TInclude
(s1
, s2
, inifdef_ref
, ii
) ->
1117 inifdef_ref
:= true;
1124 (* ------------------------------------------------------------------------- *)
1125 (* cpp-builtin part2, macro, using standard.h or other defs *)
1126 (* ------------------------------------------------------------------------- *)
1128 (* Thanks to this function many stuff are not anymore hardcoded in ocaml code
1129 * (but they are now hardcoded in standard.h ...)
1133 * No need to take care to not substitute the macro name itself
1134 * that occurs in the macro definition because the macro name is
1135 * after fix_token_define a TDefineIdent, no more a TIdent.
1138 let rec apply_macro_defs xs
=
1142 (* old: "but could do more, could reuse same original token
1143 * so that have in the Ast a Dbg, not a MACROSTATEMENT"
1145 * | PToken ({tok = TIdent (s,i1)} as id)::xs
1146 * when s = "MACROSTATEMENT" ->
1148 * msg_macro_statement_hint s;
1149 * id.tok <- TMacroStmt(TH.info_of_tok id.tok);
1150 * find_macro_paren xs
1152 * let msg_macro_statement_hint s =
1153 * incr Stat.nMacroHint;
1158 (* recognized macro of standard.h (or other) *)
1159 | PToken
({tok
= TIdent
(s
,i1
)} as id
)::Parenthised
(xxs
,info_parens
)::xs
1160 when Hashtbl.mem
!_defs s
->
1162 msg_apply_known_macro s
;
1163 let (s
, params
, body) = Hashtbl.find
!_defs s
in
1167 pr2 ("WEIRD: macro without param used before parenthize: " ^ s
);
1168 (* ex: PRINTP("NCR53C400 card%s detected\n" ANDP(((struct ... *)
1171 | DefineBody bodymacro
->
1172 set_as_comment (Token_c.CppMacro
) id
;
1173 id
.new_tokens_before
<- bodymacro
;
1174 | DefineHint hint
->
1175 msg_apply_known_macro_hint s
;
1176 id
.tok
<- token_from_parsinghack_hint
(s
,i1
) hint
;
1180 | DefineBody bodymacro
->
1182 (* bugfix: better to put this that before the match body,
1183 * cos our macrostatement hint can have variable number of
1184 * arguments and so it's ok if it does not match exactly
1185 * the number of arguments. *)
1186 if List.length params
!= List.length xxs
1188 pr2_once ("WEIRD: macro with wrong number of arguments: " ^ s
);
1189 (* old: id.new_tokens_before <- bodymacro; *)
1194 let xxs'
= xxs +> List.map
(fun x
->
1195 (tokens_of_paren_ordered x
) +> List.map
(fun x
->
1196 TH.visitor_info_of_tok
Ast_c.make_expanded x
.tok
1199 id
.new_tokens_before
<-
1200 cpp_engine
(Common.zip params
xxs'
) bodymacro
;
1202 (* important to do that after have apply the macro, otherwise
1203 * will pass as argument to the macro some tokens that
1204 * are all TCommentCpp
1206 [Parenthised
(xxs, info_parens
)] +>
1207 iter_token_paren (set_as_comment Token_c.CppMacro
);
1208 set_as_comment Token_c.CppMacro id
;
1210 | DefineHint
(HintMacroStatement
as hint
) ->
1211 (* important to do that after have apply the macro, otherwise
1212 * will pass as argument to the macro some tokens that
1213 * are all TCommentCpp
1215 * note: such macrostatement can have a variable number of
1216 * arguments but here we don't care, we just pass all the
1221 | PToken
({tok
= TPtVirg _
} as id2
)::_
->
1223 ("macro stmt with trailing ';', passing also ';' for: "^
1225 (* sometimes still want pass its params ... as in
1226 * DEBUGPOLL(static unsigned int prev_mask = 0);
1229 msg_apply_known_macro_hint s
;
1230 id
.tok
<- token_from_parsinghack_hint
(s
,i1
) hint
;
1231 [Parenthised
(xxs, info_parens
)] +>
1232 iter_token_paren (set_as_comment Token_c.CppMacro
);
1233 set_as_comment Token_c.CppMacro id2
;
1236 msg_apply_known_macro_hint s
;
1237 id
.tok
<- token_from_parsinghack_hint
(s
,i1
) hint
;
1238 [Parenthised
(xxs, info_parens
)] +>
1239 iter_token_paren (set_as_comment Token_c.CppMacro
);
1243 | DefineHint hint
->
1244 msg_apply_known_macro_hint s
;
1245 id
.tok
<- token_from_parsinghack_hint
(s
,i1
) hint
;
1250 | PToken
({tok
= TIdent
(s
,i1
)} as id
)::xs
1251 when Hashtbl.mem
!_defs s
->
1253 msg_apply_known_macro s
;
1254 let (_s
, params
, body) = Hashtbl.find
!_defs s
in
1258 pr2 ("WEIRD: macro with params but no parens found: " ^ s
);
1259 (* dont apply the macro, perhaps a redefinition *)
1263 | DefineBody
[newtok
] ->
1264 (* special case when 1-1 substitution, we reuse the token *)
1265 id
.tok
<- (newtok
+> TH.visitor_info_of_tok
(fun _
->
1266 TH.info_of_tok id
.tok
))
1267 | DefineBody bodymacro
->
1268 set_as_comment Token_c.CppMacro id
;
1269 id
.new_tokens_before
<- bodymacro
;
1270 | DefineHint hint
->
1271 msg_apply_known_macro_hint s
;
1272 id
.tok
<- token_from_parsinghack_hint
(s
,i1
) hint
;
1281 | (PToken x
)::xs
-> apply_macro_defs xs
1282 | (Parenthised
(xxs, info_parens
))::xs
->
1283 xxs +> List.iter
apply_macro_defs;
1290 (* ------------------------------------------------------------------------- *)
1291 (* stringification *)
1292 (* ------------------------------------------------------------------------- *)
1294 let rec find_string_macro_paren xs
=
1297 | Parenthised
(xxs, info_parens
)::xs
->
1298 xxs +> List.iter
(fun xs
->
1299 if xs
+> List.exists
1300 (function PToken
({tok
= (TString _
| TMacroString _
)}) -> true | _
-> false) &&
1302 (function PToken
({tok
= (TString _
| TMacroString _
)}) | PToken
({tok
= TIdent _
}) ->
1305 xs
+> List.iter
(fun tok
->
1307 | PToken
({tok
= TIdent
(s
,_
)} as id
) ->
1308 msg_stringification s
;
1309 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
1313 find_string_macro_paren xs
1315 find_string_macro_paren xs
1316 | PToken
(tok
)::xs
->
1317 find_string_macro_paren xs
1320 (* ------------------------------------------------------------------------- *)
1322 (* ------------------------------------------------------------------------- *)
1324 (* don't forget to recurse in each case *)
1325 let rec find_macro_paren xs
=
1330 | PToken
({tok
= Tattribute _
} as id
)
1331 ::Parenthised
(xxs,info_parens
)
1334 pr2_cpp ("MACRO: __attribute detected ");
1335 [Parenthised
(xxs, info_parens
)] +>
1336 iter_token_paren (set_as_comment Token_c.CppAttr
);
1337 set_as_comment Token_c.CppAttr id
;
1341 (* attribute cpp, __xxx id() *)
1342 | PToken
({tok
= TIdent
(s
,i1
)} as id
)
1343 ::PToken
({tok
= TIdent
(s2
, i2
)})
1344 ::Parenthised
(xxs,info_parens
)
1345 ::xs
when s
==~
regexp_annot
1348 id
.tok
<- TMacroAttr
(s
, i1
);
1349 find_macro_paren (Parenthised
(xxs,info_parens
)::xs
)
1351 (* attribute cpp, id __xxx = *)
1352 | PToken
({tok
= TIdent
(s
,i1
)})
1353 ::PToken
({tok
= TIdent
(s2
, i2
)} as id
)
1354 ::xs
when s2
==~
regexp_annot
1357 id
.tok
<- TMacroAttr
(s2
, i2
);
1358 find_macro_paren (xs
)
1361 (* storage attribute *)
1362 | PToken
({tok
= (Tstatic _
| Textern _
)} as tok1
)
1363 ::PToken
({tok
= TMacroAttr
(s
,i1
)} as attr
)::xs
1365 pr2_cpp ("storage attribute: " ^ s
);
1366 attr
.tok
<- TMacroAttrStorage
(s
,i1
);
1367 (* recurse, may have other storage attributes *)
1368 find_macro_paren (PToken
(tok1
)::xs
)
1373 * the order of the matching clause is important
1377 (* string macro with params, before case *)
1378 | PToken
({tok
= (TString _
| TMacroString _
)})::PToken
({tok
= TIdent
(s
,_
)} as id
)
1379 ::Parenthised
(xxs, info_parens
)
1382 msg_stringification_params s
;
1383 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
1384 [Parenthised
(xxs, info_parens
)] +>
1385 iter_token_paren (set_as_comment Token_c.CppMacro
);
1389 | PToken
({tok
= TIdent
(s
,_
)} as id
)
1390 ::Parenthised
(xxs, info_parens
)
1391 ::PToken
({tok
= (TString _
| TMacroString _
)})
1394 msg_stringification_params s
;
1395 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
1396 [Parenthised
(xxs, info_parens
)] +>
1397 iter_token_paren (set_as_comment Token_c.CppMacro
);
1401 (* for the case where the string is not inside a funcall, but
1402 * for instance in an initializer.
1405 (* string macro variable, before case *)
1406 | PToken
({tok
= (TString _
| TMacroString _
)})::PToken
({tok
= TIdent
(s
,_
)} as id
)
1409 msg_stringification s
;
1410 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
1414 | PToken
({tok
= TIdent
(s
,_
)} as id
)
1415 ::PToken
({tok
= (TString _
| TMacroString _
)})
1418 msg_stringification s
;
1419 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
1427 | (PToken x
)::xs
-> find_macro_paren xs
1428 | (Parenthised
(xxs, info_parens
))::xs
->
1429 xxs +> List.iter
find_macro_paren;
1436 (* don't forget to recurse in each case *)
1437 let rec find_macro_lineparen xs
=
1441 (* linuxext: ex: static [const] DEVICE_ATTR(); *)
1444 [PToken
({tok
= Tstatic _
});
1445 PToken
({tok
= TIdent
(s
,_
)} as macro
);
1446 Parenthised
(xxs,info_parens
);
1447 PToken
({tok
= TPtVirg _
});
1451 when (s
==~
regexp_macro) ->
1453 msg_declare_macro s
;
1454 let info = TH.info_of_tok macro
.tok
in
1455 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1457 find_macro_lineparen (xs
)
1459 (* the static const case *)
1462 [PToken
({tok
= Tstatic _
});
1463 PToken
({tok
= Tconst _
} as const
);
1464 PToken
({tok
= TIdent
(s
,_
)} as macro
);
1465 Parenthised
(xxs,info_parens
);
1466 PToken
({tok
= TPtVirg _
});
1472 when (s
==~
regexp_macro) ->
1474 msg_declare_macro s
;
1475 let info = TH.info_of_tok macro
.tok
in
1476 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1478 (* need retag this const, otherwise ambiguity in grammar
1479 21: shift/reduce conflict (shift 121, reduce 137) on Tconst
1480 decl2 : Tstatic . TMacroDecl TOPar argument_list TCPar ...
1481 decl2 : Tstatic . Tconst TMacroDecl TOPar argument_list TCPar ...
1482 storage_class_spec : Tstatic . (137)
1484 const
.tok
<- TMacroDeclConst
(TH.info_of_tok const
.tok
);
1486 find_macro_lineparen (xs
)
1489 (* same but without trailing ';'
1491 * I do not put the final ';' because it can be on a multiline and
1492 * because of the way mk_line is coded, we will not have access to
1493 * this ';' on the next line, even if next to the ')' *)
1495 ([PToken
({tok
= Tstatic _
});
1496 PToken
({tok
= TIdent
(s
,_
)} as macro
);
1497 Parenthised
(xxs,info_parens
);
1501 when s
==~
regexp_macro ->
1503 msg_declare_macro s
;
1504 let info = TH.info_of_tok macro
.tok
in
1505 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1507 find_macro_lineparen (xs
)
1512 (* on multiple lines *)
1515 (PToken
({tok
= Tstatic _
})::[]
1519 [PToken
({tok
= TIdent
(s
,_
)} as macro
);
1520 Parenthised
(xxs,info_parens
);
1521 PToken
({tok
= TPtVirg _
});
1526 when (s
==~
regexp_macro) ->
1528 msg_declare_macro s
;
1529 let info = TH.info_of_tok macro
.tok
in
1530 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1532 find_macro_lineparen (xs
)
1535 (* linuxext: ex: DECLARE_BITMAP();
1537 * Here I use regexp_declare and not regexp_macro because
1538 * Sometimes it can be a FunCallMacro such as DEBUG(foo());
1539 * Here we don't have the preceding 'static' so only way to
1540 * not have positive is to restrict to .*DECLARE.* macros.
1542 * but there is a grammar rule for that, so don't need this case anymore
1543 * unless the parameter of the DECLARE_xxx are weird and can not be mapped
1544 * on a argument_list
1548 ([PToken
({tok
= TIdent
(s
,_
)} as macro
);
1549 Parenthised
(xxs,info_parens
);
1550 PToken
({tok
= TPtVirg _
});
1554 when (s
==~
regexp_declare) ->
1556 msg_declare_macro s
;
1557 let info = TH.info_of_tok macro
.tok
in
1558 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
1560 find_macro_lineparen (xs
)
1566 * Could also transform the TIdent in a TMacroTop but can have false
1567 * positive, so easier to just change the TCPar and so just solve
1568 * the end-of-stream pb of ocamlyacc
1571 ([PToken
({tok
= TIdent
(s
,ii
); col
= col1
; where
= ctx
} as _macro
);
1572 Parenthised
(xxs,info_parens
);
1575 ::xs
when col1
=|= 0
1578 (* to reduce number of false positive *)
1580 | (Line
(PToken
({col
= col2
} as other
)::restline2
))::_
->
1581 TH.is_eof other
.tok
|| (col2
=|= 0 &&
1582 (match other
.tok
with
1583 | TOBrace _
-> false (* otherwise would match funcdecl *)
1584 | TCBrace _
when ctx
<> InFunction
-> false
1588 | tok
when TH.is_binary_operator tok
-> false
1599 msg_macro_toplevel_noptvirg s
;
1600 (* just to avoid the end-of-stream pb of ocamlyacc *)
1601 let tcpar = Common.last info_parens
in
1602 tcpar.tok
<- TCParEOL
(TH.info_of_tok
tcpar.tok
);
1604 (*macro.tok <- TMacroTop (s, TH.info_of_tok macro.tok);*)
1608 find_macro_lineparen (xs
)
1612 (* macro with parameters
1617 ([PToken
({tok
= TIdent
(s
,ii
); col
= col1
; where
= ctx
} as macro
);
1618 Parenthised
(xxs,info_parens
);
1622 (PToken
({col
= col2
} as other
)::restline2
1625 (* when s ==~ regexp_macro *)
1629 (match other
.tok
with
1630 | TOBrace _
-> false (* otherwise would match funcdecl *)
1631 | TCBrace _
when ctx
<> InFunction
-> false
1635 | tok
when TH.is_binary_operator tok
-> false
1642 (match other
.tok
, restline2
with
1643 | TCBrace _
, _
when ctx
=*= InFunction
-> true
1644 | Treturn _
, _
-> true
1646 | Telse _
, _
-> true
1648 (* case of label, usually put in first line *)
1649 | TIdent _
, (PToken
({tok
= TDotDot _
}))::_
->
1661 if col1
=|= 0 then ()
1663 msg_macro_noptvirg s
;
1664 macro
.tok
<- TMacroStmt
(s
, TH.info_of_tok macro
.tok
);
1665 [Parenthised
(xxs, info_parens
)] +>
1666 iter_token_paren (set_as_comment Token_c.CppMacro
);
1669 find_macro_lineparen (line2
::xs
)
1671 (* linuxext:? single macro
1676 * todo: factorize code with previous rule ?
1679 ([PToken
({tok
= TIdent
(s
,ii
); col
= col1
; where
= ctx
} as macro
);
1683 (PToken
({col
= col2
} as other
)::restline2
1686 (* when s ==~ regexp_macro *)
1690 col1
<> 0 && (* otherwise can match typedef of fundecl*)
1691 (match other
.tok
with
1692 | TPtVirg _
-> false
1694 | TCBrace _
when ctx
<> InFunction
-> false
1695 | tok
when TH.is_binary_operator tok
-> false
1700 (match other
.tok
with
1701 | TCBrace _
when ctx
=*= InFunction
-> true
1711 msg_macro_noptvirg_single s
;
1712 macro
.tok
<- TMacroStmt
(s
, TH.info_of_tok macro
.tok
);
1714 find_macro_lineparen (line2
::xs
)
1717 find_macro_lineparen xs
1721 (* ------------------------------------------------------------------------- *)
1722 (* define tobrace init *)
1723 (* ------------------------------------------------------------------------- *)
1725 let rec find_define_init_brace_paren xs
=
1730 (* mainly for firefox *)
1731 | (PToken
{tok
= TDefine _
})
1732 ::(PToken
{tok
= TIdentDefine
(s
,_
)})
1733 ::(PToken
({tok
= TOBrace i1
} as tokbrace
))
1738 match tok2
.tok
, tok3
.tok
with
1739 | TInt _
, TComma _
-> true
1740 | TString _
, TComma _
-> true
1741 | TIdent _
, TComma _
-> true
1747 pr2_cpp("found define initializer: " ^s
);
1748 tokbrace
.tok
<- TOBraceDefineInit i1
;
1753 (* mainly for linux, especially in sound/ *)
1754 | (PToken
{tok
= TDefine _
})
1755 ::(PToken
{tok
= TIdentDefine
(s
,_
)})
1756 ::(Parenthised
(xxx
, info_parens
))
1757 ::(PToken
({tok
= TOBrace i1
} as tokbrace
))
1762 match tok2
.tok
, tok3
.tok
with
1763 | TInt _
, TComma _
-> true
1764 | TDot _
, TIdent _
-> true
1765 | TIdent _
, TComma _
-> true
1771 pr2_cpp("found define initializer with param: " ^ s
);
1772 tokbrace
.tok
<- TOBraceDefineInit i1
;
1780 | (PToken x
)::xs
-> aux xs
1781 | (Parenthised
(xxs, info_parens
))::xs
->
1782 (* not need for tobrace init:
1783 * xxs +> List.iter aux;
1790 (* ------------------------------------------------------------------------- *)
1792 (* ------------------------------------------------------------------------- *)
1794 let rec find_actions = function
1797 | PToken
({tok
= TIdent
(s
,ii
)})
1798 ::Parenthised
(xxs,info_parens
)
1801 xxs +> List.iter
find_actions;
1802 let modified = find_actions_params
xxs in
1804 then msg_macro_higher_order s
1809 and find_actions_params
xxs =
1810 xxs +> List.fold_left
(fun acc xs
->
1811 let toks = tokens_of_paren xs
in
1812 if toks +> List.exists
(fun x
-> TH.is_statement x
.tok
)
1814 xs
+> iter_token_paren (fun x
->
1817 (* certainly because paren detection had a pb because of
1820 pr2 "PB: weird, I try to tag an EOF token as action"
1822 x
.tok
<- TAction
(TH.info_of_tok x
.tok
);
1831 (* ------------------------------------------------------------------------- *)
1832 (* main fix cpp function *)
1833 (* ------------------------------------------------------------------------- *)
1835 let rebuild_tokens_extented toks_ext
=
1836 let _tokens = ref [] in
1837 toks_ext
+> List.iter
(fun tok
->
1838 tok
.new_tokens_before
+> List.iter
(fun x
-> push2 x
_tokens);
1839 push2 tok
.tok
_tokens
1841 let tokens = List.rev
!_tokens in
1842 (tokens +> acc_map
mk_token_extended)
1844 let filter_cpp_stuff xs
=
1850 | tok
when TH.is_comment tok
-> aux xs
1851 (* don't want drop the define, or if drop, have to drop
1852 * also its body otherwise the line heuristics may be lost
1853 * by not finding the TDefine in column 0 but by finding
1854 * a TDefineIdent in a column > 0
1856 | Parser_c.TDefine _
->
1858 | tok
when TH.is_cpp_instruction tok
-> aux xs
1864 let insert_virtual_positions l
=
1865 let strlen x
= String.length
(Ast_c.str_of_info x
) in
1866 let rec loop prev offset
= function
1869 let ii = TH.info_of_tok x
in
1871 TH.visitor_info_of_tok
(function ii -> Ast_c.rewrap_pinfo pi
ii) x
in
1872 match Ast_c.pinfo_of_info
ii with
1873 Ast_c.OriginTok pi
->
1874 let prev = Ast_c.parse_info_of_info
ii in
1875 x
::(loop prev (strlen ii) xs
)
1876 | Ast_c.ExpandedTok
(pi
,_
) ->
1877 inject (Ast_c.ExpandedTok
(pi
,(prev,offset
))) ::
1878 (loop prev (offset
+ (strlen ii)) xs
)
1879 | Ast_c.FakeTok
(s
,_
) ->
1880 inject (Ast_c.FakeTok
(s
,(prev,offset
))) ::
1881 (loop prev (offset
+ (strlen ii)) xs
)
1882 | Ast_c.AbstractLineTok _
-> failwith
"abstract not expected" in
1883 let rec skip_fake = function
1886 let ii = TH.info_of_tok x
in
1887 match Ast_c.pinfo_of_info
ii with
1888 Ast_c.OriginTok pi
->
1889 let prev = Ast_c.parse_info_of_info
ii in
1890 x
::(loop prev (strlen ii) xs
)
1891 | _
-> x
::skip_fake xs
in
1894 (* ------------------------------------------------------------------------- *)
1895 let fix_tokens_cpp2 tokens =
1896 let tokens2 = ref (tokens +> acc_map
mk_token_extended) in
1899 (* the order is important, if you put the action heuristic first,
1900 * then because of ifdef, can have not closed paren
1901 * and so may believe that higher order macro
1902 * and it will eat too much tokens. So important to do
1905 * I recompute multiple times cleaner cos the mutable
1906 * can have be changed and so may have more comments
1907 * in the token original list.
1911 commentize_skip_start_to_end !tokens2;
1914 let cleaner = !tokens2 +> List.filter
(fun x
->
1915 (* is_comment will also filter the TCommentCpp created in
1916 * commentize_skip_start_to_end *)
1917 not
(TH.is_comment x
.tok
) (* could filter also #define/#include *)
1919 let ifdef_grouped = mk_ifdef cleaner in
1920 set_ifdef_parenthize_info ifdef_grouped;
1922 find_ifdef_funheaders ifdef_grouped;
1923 find_ifdef_bool ifdef_grouped;
1924 find_ifdef_mid ifdef_grouped;
1925 adjust_inifdef_include ifdef_grouped;
1929 let cleaner = !tokens2 +> filter_cpp_stuff in
1931 let paren_grouped = mk_parenthised cleaner in
1932 apply_macro_defs paren_grouped;
1933 (* because the before field is used by apply_macro_defs *)
1934 tokens2 := rebuild_tokens_extented !tokens2;
1936 (* tagging contextual info (InFunc, InStruct, etc). Better to do
1937 * that after the "ifdef-simplification" phase.
1939 let cleaner = !tokens2 +> List.filter
(fun x
->
1940 not
(TH.is_comment x
.tok
) (* could filter also #define/#include *)
1943 let brace_grouped = mk_braceised cleaner in
1944 set_context_tag brace_grouped;
1949 let cleaner = !tokens2 +> filter_cpp_stuff in
1951 let paren_grouped = mk_parenthised cleaner in
1952 let line_paren_grouped = mk_line_parenthised paren_grouped in
1953 find_define_init_brace_paren paren_grouped;
1954 find_string_macro_paren paren_grouped;
1955 find_macro_lineparen line_paren_grouped;
1956 find_macro_paren paren_grouped;
1960 let cleaner = !tokens2 +> filter_cpp_stuff in
1961 let paren_grouped = mk_parenthised cleaner in
1962 find_actions paren_grouped;
1965 insert_virtual_positions (!tokens2 +> acc_map
(fun x
-> x
.tok
))
1969 Common.profile_code_exclusif
"HACK" (fun () -> fix_tokens_cpp2 a
)
1971 let fix_tokens_cpp a
=
1972 Common.profile_code
"C parsing.fix_cpp" (fun () -> time_hack1 a
)
1977 (*****************************************************************************)
1978 (* The #define tricks *)
1979 (*****************************************************************************)
1981 (* ugly hack, a better solution perhaps would be to erase TDefEOL
1982 * from the Ast and list of tokens in parse_c.
1984 * note: I do a +1 somewhere, it's for the unparsing to correctly sync.
1986 * note: can't replace mark_end_define by simply a fakeInfo(). The reason
1987 * is where is the \n TCommentSpace. Normally there is always a last token
1988 * to synchronize on, either EOF or the token of the next toplevel.
1989 * In the case of the #define we got in list of token
1990 * [TCommentSpace "\n"; TDefEOL] but if TDefEOL is a fakeinfo then we will
1991 * not synchronize on it and so we will not print the "\n".
1992 * A solution would be to put the TDefEOL before the "\n".
1994 * todo?: could put a ExpandedTok for that ?
1996 let mark_end_define ii =
1998 { Ast_c.pinfo
= Ast_c.OriginTok
{ (Ast_c.parse_info_of_info
ii) with
2000 Common.charpos
= Ast_c.pos_of_info
ii + 1
2002 cocci_tag
= ref Ast_c.emptyAnnot
;
2003 comments_tag
= ref Ast_c.emptyComments
;
2008 (* put the TDefEOL at the good place *)
2009 let rec define_line_1 acc xs
=
2011 | [] -> List.rev acc
2013 let line = Ast_c.line_of_info
ii in
2014 let acc = (TDefine
ii) :: acc in
2015 define_line_2
acc line ii xs
2016 | TCppEscapedNewline
ii::xs
->
2017 pr2 "WEIRD: a \\ outside a #define";
2018 let acc = (TCommentSpace
ii) :: acc in
2019 define_line_1 acc xs
2020 | x
::xs
-> define_line_1 (x
::acc) xs
2022 and define_line_2
acc line lastinfo xs
=
2025 (* should not happened, should meet EOF before *)
2027 List.rev
(mark_end_define lastinfo
::acc)
2029 let line'
= TH.line_of_tok x
in
2030 let info = TH.info_of_tok x
in
2034 let acc = (mark_end_define lastinfo
) :: acc in
2035 let acc = (EOF
ii) :: acc in
2036 define_line_1 acc xs
2037 | TCppEscapedNewline
ii ->
2038 if (line'
<> line) then pr2 "PB: WEIRD: not same line number";
2039 let acc = (TCommentSpace
ii) :: acc in
2040 define_line_2
acc (line+1) info xs
2043 then define_line_2
(x
::acc) line info xs
2044 else define_line_1 (mark_end_define lastinfo
::acc) (x
::xs
)
2047 let rec define_ident acc xs
=
2049 | [] -> List.rev
acc
2051 let acc = TDefine
ii :: acc in
2053 | TCommentSpace i1
::TIdent
(s
,i2
)::TOPar
(i3
)::xs
->
2054 (* Change also the kind of TIdent to avoid bad interaction
2055 * with other parsing_hack tricks. For instant if keep TIdent then
2056 * the stringication algo can believe the TIdent is a string-macro.
2057 * So simpler to change the kind of the ident too.
2059 (* if TOParDefine sticked to the ident, then
2060 * it's a macro-function. Change token to avoid ambiguity
2061 * between #define foo(x) and #define foo (x)
2063 let acc = (TCommentSpace i1
) :: acc in
2064 let acc = (TIdentDefine
(s
,i2
)) :: acc in
2065 let acc = (TOParDefine i3
) :: acc in
2067 | TCommentSpace i1
::TIdent
(s
,i2
)::xs
->
2068 let acc = (TCommentSpace i1
) :: acc in
2069 let acc = (TIdentDefine
(s
,i2
)) :: acc in
2072 pr2 "WEIRD: weird #define body";
2076 let acc = x
:: acc in
2081 let fix_tokens_define2 xs
=
2082 define_ident [] (define_line_1 [] xs
)
2084 let fix_tokens_define a
=
2085 Common.profile_code
"C parsing.fix_define" (fun () -> fix_tokens_define2 a
)
2088 (*****************************************************************************)
2089 (* for the cpp-builtin, standard.h, part 0 *)
2090 (*****************************************************************************)
2092 let macro_body_to_maybe_hint body =
2094 | [] -> DefineBody
body
2095 | [TIdent
(s
,i1
)] ->
2096 (match parsinghack_hint_of_string s
with
2097 | Some hint
-> DefineHint hint
2098 | None
-> DefineBody
body
2100 | xs
-> DefineBody
body
2103 let rec define_parse xs
=
2106 | TDefine i1
::TIdentDefine
(s
,i2
)::TOParDefine i3
::xs
->
2107 let (tokparams
, _
, xs
) =
2108 xs
+> Common.split_when
(function TCPar _
-> true | _
-> false) in
2110 xs
+> Common.split_when
(function TDefEOL _
-> true | _
-> false) in
2112 tokparams
+> Common.map_filter
(function
2114 | TIdent
(s
, _
) -> Some s
2115 | x
-> error_cant_have x
2117 let body = body +> List.map
2118 (TH.visitor_info_of_tok
Ast_c.make_expanded
) in
2119 let def = (s
, (s
, Params
params, macro_body_to_maybe_hint body)) in
2120 def::define_parse xs
2122 | TDefine i1
::TIdentDefine
(s
,i2
)::xs
->
2124 xs
+> Common.split_when
(function TDefEOL _
-> true | _
-> false) in
2125 let body = body +> List.map
2126 (TH.visitor_info_of_tok
Ast_c.make_expanded
) in
2127 let def = (s
, (s
, NoParam
, macro_body_to_maybe_hint body)) in
2128 def::define_parse xs
2133 | x
::xs
-> define_parse xs
2136 let extract_cpp_define xs
=
2137 let cleaner = xs
+> List.filter
(fun x
->
2138 not
(TH.is_comment x
)
2140 define_parse cleaner
2145 (*****************************************************************************)
2146 (* Lexing with lookahead *)
2147 (*****************************************************************************)
2149 (* Why using yet another parsing_hack technique ? The fix_xxx where do
2150 * some pre-processing on the full list of tokens is not enough ?
2151 * No cos sometimes we need more contextual info, and even if
2152 * set_context() tries to give some contextual info, it's not completely
2153 * accurate so the following code give yet another alternative, yet another
2154 * chance to transform some tokens.
2156 * todo?: maybe could try to get rid of this technique. Maybe a better
2157 * set_context() would make possible to move this code using a fix_xx
2160 * LALR(k) trick. We can do stuff by adding cases in lexer_c.mll, but
2161 * it is more general to do it via my LALR(k) tech. Because here we can
2162 * transform some token give some context information. So sometimes it
2163 * makes sense to transform a token in one context, sometimes not, and
2164 * lex can not provide us this context information. Note that the order
2165 * in the pattern matching in lookahead is important. Do not cut/paste.
2167 * Note that in next there is only "clean" tokens, there is no comment
2168 * or space tokens. This is done by the caller.
2172 open Lexer_parser
(* for the fields of lexer_hint type *)
2174 let not_struct_enum = function
2175 | (Parser_c.Tstruct _
| Parser_c.Tunion _
| Parser_c.Tenum _
)::_
-> false
2179 let lookahead2 ~pass next before
=
2181 match (next
, before
) with
2183 (*-------------------------------------------------------------*)
2184 (* typedef inference, parse_typedef_fix3 *)
2185 (*-------------------------------------------------------------*)
2187 | (TIdent
(s
,i1
)::TIdent
(s2
,i2
)::_
, _
) when not_struct_enum before
&& s
=$
= s2
2189 (* (take_safe 1 !passed_tok <> [TOPar]) -> *)
2191 (* parse_typedef_fix3:
2192 * acpi_object acpi_object;
2193 * etait mal parsé, car pas le temps d'appeler dt() dans le type_spec.
2194 * Le parser en interne a deja appelé le prochain token pour pouvoir
2195 * decider des choses.
2196 * => special case in lexer_heuristic, again
2198 if !Flag_parsing_c.debug_typedef
2199 then pr2 ("TYPEDEF: disable typedef cos special case: " ^ s
);
2201 LP.disable_typedef
();
2203 msg_typedef s
; LP.add_typedef_root s
;
2204 TypedefIdent
(s
, i1
)
2207 | (TIdent
(s
, i1
)::TIdent
(s2
, i2
)::_
, _
) when not_struct_enum before
2210 (* && not_annot s2 BUT lead to false positive*)
2212 msg_typedef s
; LP.add_typedef_root s
;
2213 TypedefIdent
(s
, i1
)
2217 | (TIdent
(s
, i1
)::Tinline i2
::_
, _
) when not_struct_enum before
2220 msg_typedef s
; LP.add_typedef_root s
;
2221 TypedefIdent
(s
, i1
)
2224 (* [,(] xx [,)] AND param decl *)
2225 | (TIdent
(s
, i1
)::(TComma _
|TCPar _
)::_
, (TComma _
|TOPar _
)::_
)
2226 when not_struct_enum before
&& (LP.current_context
() =*= LP.InParameter
)
2229 msg_typedef s
; LP.add_typedef_root s
;
2230 TypedefIdent
(s
, i1
)
2233 (* specialcase: [,(] xx* [,)] *)
2234 | (TIdent
(s
, i1
)::TMul _
::(TComma _
|TCPar _
)::_
, (*(TComma _|TOPar _)::*)_
)
2235 when not_struct_enum before
2236 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2239 msg_typedef s
; LP.add_typedef_root s
;
2240 TypedefIdent
(s
, i1
)
2244 (* specialcase: [,(] xx** [,)] *)
2245 | (TIdent
(s
, i1
)::TMul _
::TMul _
::(TComma _
|TCPar _
)::_
, (*(TComma _|TOPar _)::*)_
)
2246 when not_struct_enum before
2247 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2250 msg_typedef s
; LP.add_typedef_root s
;
2251 TypedefIdent
(s
, i1
)
2255 (* xx const * USELESS because of next rule ? *)
2256 | (TIdent
(s
, i1
)::(Tconst _
|Tvolatile _
|Trestrict _
)::TMul _
::_
, _
)
2257 when not_struct_enum before
2258 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2262 msg_typedef s
; LP.add_typedef_root s
;
2263 TypedefIdent
(s
, i1
)
2266 | (TIdent
(s
, i1
)::(Tconst _
|Tvolatile _
|Trestrict _
)::_
, _
)
2267 when not_struct_enum before
2269 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2272 msg_typedef s
; LP.add_typedef_root s
;
2273 TypedefIdent
(s
, i1
)
2277 | (TIdent
(s
, i1
)::TMul _
::(Tconst _
| Tvolatile _
|Trestrict _
)::_
, _
)
2278 when not_struct_enum before
2281 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2283 msg_typedef s
; LP.add_typedef_root s
;
2284 TypedefIdent
(s
, i1
)
2288 | (TIdent
(s
, i1
)::TCPar _
::_
, (Tconst _
| Tvolatile _
|Trestrict _
)::TOPar _
::_
) when
2290 msg_typedef s
; LP.add_typedef_root s
;
2291 TypedefIdent
(s
, i1
)
2295 (* ( xx ) [sizeof, ~] *)
2296 | (TIdent
(s
, i1
)::TCPar _
::(Tsizeof _
|TTilde _
)::_
, TOPar _
::_
)
2297 when not_struct_enum before
2300 msg_typedef s
; LP.add_typedef_root s
;
2301 TypedefIdent
(s
, i1
)
2303 (* [(,] xx [ AND parameterdeclaration *)
2304 | (TIdent
(s
, i1
)::TOCro _
::_
, (TComma _
|TOPar _
)::_
)
2305 when (LP.current_context
() =*= LP.InParameter
)
2308 msg_typedef s
; LP.add_typedef_root s
;
2309 TypedefIdent
(s
, i1
)
2311 (*------------------------------------------------------------*)
2312 (* if 'x*y' maybe an expr, maybe just a classic multiplication *)
2313 (* but if have a '=', or ',' I think not *)
2314 (*------------------------------------------------------------*)
2316 (* static xx * yy *)
2317 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::_
,
2318 (Tregister _
|Tstatic _
|Tvolatile _
|Tconst _
|Trestrict _
)::_
) when
2321 msg_typedef s
; LP.add_typedef_root s
;
2322 TypedefIdent
(s
, i1
)
2324 (* TODO xx * yy ; AND in start of compound element *)
2327 (* xx * yy, AND in paramdecl *)
2328 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TComma _
::_
, _
)
2329 when not_struct_enum before
&& (LP.current_context
() =*= LP.InParameter
)
2333 msg_typedef s
; LP.add_typedef_root s
;
2334 TypedefIdent
(s
, i1
)
2337 (* xx * yy ; AND in Toplevel, except when have = before *)
2338 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TPtVirg _
::_
, TEq _
::_
) ->
2340 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TPtVirg _
::_
, _
)
2341 when not_struct_enum before
&& (LP.is_top_or_struct
(LP.current_context
()))
2343 msg_typedef s
; LP.add_typedef_root s
;
2344 TypedefIdent
(s
, i1
)
2346 (* xx * yy , AND in Toplevel *)
2347 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TComma _
::_
, _
)
2348 when not_struct_enum before
&& (LP.current_context
() =*= LP.InTopLevel
)
2352 msg_typedef s
; LP.add_typedef_root s
;
2353 TypedefIdent
(s
, i1
)
2355 (* xx * yy ( AND in Toplevel *)
2356 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TOPar _
::_
, _
)
2357 when not_struct_enum before
2358 && (LP.is_top_or_struct
(LP.current_context
()))
2361 msg_typedef s
; LP.add_typedef_root s
;
2362 TypedefIdent
(s
, i1
)
2365 (* todo? enough ? cos in struct def we can have some expression ! *)
2366 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TOCro _
::_
, _
)
2367 when not_struct_enum before
&&
2368 (LP.is_top_or_struct
(LP.current_context
()))
2371 msg_typedef s
; LP.add_typedef_root s
;
2372 TypedefIdent
(s
, i1
)
2374 (* u16: 10; in struct *)
2375 | (TIdent
(s
, i1
)::TDotDot _
::_
, (TOBrace _
| TPtVirg _
)::_
)
2376 when (LP.is_top_or_struct
(LP.current_context
()))
2379 msg_typedef s
; LP.add_typedef_root s
;
2380 TypedefIdent
(s
, i1
)
2383 (* why need TOPar condition as stated in preceding rule ? really needed ? *)
2384 (* YES cos at toplevel can have some expression !! for instance when *)
2385 (* enter in the dimension of an array *)
2387 | (TIdent s::TMul::TIdent s2::_ , _)
2388 when (take_safe 1 !passed_tok <> [Tstruct] &&
2389 (take_safe 1 !passed_tok <> [Tenum]))
2391 !LP._lexer_hint = Some LP.Toplevel ->
2393 LP.add_typedef_root s;
2398 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TEq _
::_
, _
)
2399 when not_struct_enum before
2402 msg_typedef s
; LP.add_typedef_root s
;
2403 TypedefIdent
(s
, i1
)
2406 (* xx * yy) AND in paramdecl *)
2407 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TCPar _
::_
, _
)
2408 when not_struct_enum before
&& (LP.current_context
() =*= LP.InParameter
)
2411 msg_typedef s
; LP.add_typedef_root s
;
2412 TypedefIdent
(s
, i1
)
2415 (* xx * yy; *) (* wrong ? *)
2416 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TPtVirg _
::_
,
2417 (TOBrace _
| TPtVirg _
)::_
) when not_struct_enum before
2420 msg_typedef s
; LP.add_typedef_root s
;
2421 msg_maybe_dangereous_typedef s
;
2422 TypedefIdent
(s
, i1
)
2425 (* xx * yy, and ';' before xx *) (* wrong ? *)
2426 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TComma _
::_
,
2427 (TOBrace _
| TPtVirg _
)::_
) when
2430 msg_typedef s
; LP.add_typedef_root s
;
2431 TypedefIdent
(s
, i1
)
2435 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::_
, _
)
2436 when s
==~
regexp_typedef && not_struct_enum before
2437 (* struct user_info_t sometimes *)
2440 msg_typedef s
; LP.add_typedef_root s
;
2441 TypedefIdent
(s
, i1
)
2443 (* xx ** yy *) (* wrong ? *)
2444 | (TIdent
(s
, i1
)::TMul _
::TMul _
::TIdent
(s2
, i2
)::_
, _
)
2445 when not_struct_enum before
2446 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2449 msg_typedef s
; LP.add_typedef_root s
;
2450 TypedefIdent
(s
, i1
)
2453 | (TIdent
(s
, i1
)::TMul _
::TMul _
::TMul _
::TIdent
(s2
, i2
)::_
, _
)
2454 when not_struct_enum before
2456 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2458 msg_typedef s
; LP.add_typedef_root s
;
2459 TypedefIdent
(s
, i1
)
2462 | (TIdent
(s
, i1
)::TMul _
::TMul _
::TCPar _
::_
, _
)
2463 when not_struct_enum before
2464 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
2467 msg_typedef s
; LP.add_typedef_root s
;
2468 TypedefIdent
(s
, i1
)
2472 (* ----------------------------------- *)
2473 (* old: why not do like for other rules and start with TIdent ?
2474 * why do TOPar :: TIdent :: ..., _ and not TIdent :: ..., TOPAr::_ ?
2475 * new: prefer now start with TIdent because otherwise the add_typedef_root
2476 * may have no effect if in second pass or if have disable the add_typedef.
2480 | (TIdent
(s
, i1
)::TCPar i2
::(TIdent
(_
,i3
)|TInt
(_
,i3
))::_
,
2482 when not
(TH.is_stuff_taking_parenthized x
) &&
2483 Ast_c.line_of_info i2
=|= Ast_c.line_of_info i3
2487 msg_typedef s
; LP.add_typedef_root s
;
2489 TypedefIdent
(s
, i1
)
2493 * but false positif: typedef int (xxx_t)(...), so do specialisation below.
2496 | (TIdent (s, i1)::TCPar _::TOPar _::_ , (TOPar info)::x::_)
2497 when not (TH.is_stuff_taking_parenthized x)
2500 msg_typedef s; LP.add_typedef_root s;
2502 TypedefIdent
(s
, i1
)
2504 (* special case: = (xx) ( yy) *)
2505 | (TIdent
(s
, i1
)::TCPar _
::TOPar _
::_
,
2506 (TOPar
info)::(TEq _
|TEqEq _
)::_
)
2509 msg_typedef s
; LP.add_typedef_root s
;
2511 TypedefIdent
(s
, i1
)
2515 | (TIdent
(s
, i1
)::TMul _
::TCPar _
::TIdent
(s2
, i2
)::_
, (TOPar
info)::_
) when
2518 msg_typedef s
; LP.add_typedef_root s
;
2523 (* (xx){ ... } constructor *)
2524 | (TIdent
(s
, i1
)::TCPar _
::TOBrace _
::_
, TOPar _
::x
::_
)
2525 when (*s ==~ regexp_typedef && *) not
(TH.is_stuff_taking_parenthized x
)
2528 msg_typedef s
; LP.add_typedef_root s
;
2529 TypedefIdent
(s
, i1
)
2532 (* can have sizeof on expression
2533 | (Tsizeof::TOPar::TIdent s::TCPar::_, _) ->
2535 LP.add_typedef_root s;
2540 (* ----------------------------------- *)
2541 (* x ( *y )(params), function pointer *)
2542 | (TIdent
(s
, i1
)::TOPar _
::TMul _
::TIdent _
::TCPar _
::TOPar _
::_
, _
)
2543 when not_struct_enum before
2546 msg_typedef s
; LP.add_typedef_root s
;
2547 TypedefIdent
(s
, i1
)
2549 (* x* ( *y )(params), function pointer 2 *)
2550 | (TIdent
(s
, i1
)::TMul _
::TOPar _
::TMul _
::TIdent _
::TCPar _
::TOPar _
::_
, _
)
2551 when not_struct_enum before
2554 msg_typedef s
; LP.add_typedef_root s
;
2555 TypedefIdent
(s
, i1
)
2558 (*-------------------------------------------------------------*)
2560 (*-------------------------------------------------------------*)
2561 | ((TIfdef
(_
,ii) |TIfdefelse
(_
,ii) |TIfdefelif
(_
,ii) |TEndif
(_
,ii) |
2562 TIfdefBool
(_
,_
,ii)|TIfdefMisc
(_
,_
,ii)|TIfdefVersion
(_
,_
,ii))
2567 if not !Flag_parsing_c.ifdef_to_if
2568 then TCommentCpp (Ast_c.CppDirective, ii)
2571 (* not !LP._lexer_hint.toplevel *)
2572 if !Flag_parsing_c.ifdef_directive_passing
2576 if (LP.current_context
() =*= LP.InInitializer
)
2578 pr2_cpp "In Initializer passing"; (* cheat: dont count in stat *)
2579 incr
Stat.nIfdefInitializer
;
2581 pr2_cpp("IFDEF: or related insde function. I treat it as comment");
2582 incr
Stat.nIfdefPassing
;
2584 TCommentCpp
(Token_c.CppDirective
, ii)
2588 | (TUndef
(id
, ii) as x
)::_
, _
2592 pr2_cpp("UNDEF: I treat it as comment");
2593 TCommentCpp
(Token_c.CppDirective
, ii)
2597 | (TCppDirectiveOther
(ii) as x
)::_
, _
2601 pr2_cpp ("OTHER directive: I treat it as comment");
2602 TCommentCpp
(Token_c.CppDirective
, ii)
2606 (* If ident contain a for_each, then certainly a macro. But to be
2607 * sure should look if there is a '{' after the ')', but it requires
2608 * to count the '('. Because this can be expensive, we do that only
2609 * when the token contains "for_each".
2611 | (TIdent
(s
, i1
)::TOPar _
::rest
, _
)
2612 when not
(LP.current_context
() =*= LP.InTopLevel
)
2613 (* otherwise a function such as static void loopback_enable(int i) {
2614 * will be considered as a loop
2619 if s
==~
regexp_foreach &&
2620 is_really_foreach (Common.take_safe
forLOOKAHEAD rest
)
2624 TMacroIterator
(s
, i1
)
2630 (*-------------------------------------------------------------*)
2632 | _
-> raise Impossible
2634 let lookahead ~pass a b
=
2635 Common.profile_code
"C parsing.lookahead" (fun () -> lookahead2 ~pass a b
)