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 TV
= Token_views_c
19 module LP
= Lexer_parser
21 module Stat
= Parsing_stat
27 (*****************************************************************************)
28 (* Some debugging functions *)
29 (*****************************************************************************)
31 let pr2, pr2_once
= Common.mk_pr2_wrappers
Flag_parsing_c.verbose_parsing
34 if !Flag_parsing_c.debug_cpp
35 then Common.pr2_once
("CPP-" ^ s
)
38 let msg_gen cond is_known printer s
=
41 if not
(!Flag_parsing_c.filter_msg
)
48 (* In the following, there are some harcoded names of types or macros
49 * but they are not used by our heuristics! They are just here to
50 * enable to detect false positive by printing only the typedef/macros
51 * that we don't know yet. If we print everything, then we can easily
52 * get lost with too much verbose tracing information. So those
53 * functions "filter" some messages. So our heuristics are still good,
54 * there is no more (or not that much) hardcoded linux stuff.
60 | "u_char" | "u_short" | "u_int" | "u_long"
61 | "u8" | "u16" | "u32" | "u64"
62 | "s8" | "s16" | "s32" | "s64"
63 | "__u8" | "__u16" | "__u32" | "__u64"
74 | s
when s
=~
".*_t$" -> true
79 (* note: cant use partial application with let msg_typedef =
80 * because it would compute msg_typedef at compile time when
81 * the flag debug_typedef is always false
84 incr
Stat.nTypedefInfer
;
85 msg_gen (!Flag_parsing_c.debug_typedef
)
88 pr2_cpp ("TYPEDEF: promoting: " ^ s
)
92 let msg_maybe_dangereous_typedef s
=
93 if not
(is_known_typdef s
)
96 ("PB MAYBE: dangerous typedef inference, maybe not a typedef: " ^ s
)
100 let msg_declare_macro s
=
101 incr
Stat.nMacroDecl
;
102 msg_gen (!Flag_parsing_c.debug_cpp
)
105 | "DECLARE_MUTEX" | "DECLARE_COMPLETION" | "DECLARE_RWSEM"
106 | "DECLARE_WAITQUEUE" | "DECLARE_WAIT_QUEUE_HEAD"
107 | "DEFINE_SPINLOCK" | "DEFINE_TIMER"
108 | "DEVICE_ATTR" | "CLASS_DEVICE_ATTR" | "DRIVER_ATTR"
109 | "SENSOR_DEVICE_ATTR"
111 | "DECLARE_WORK" | "DECLARE_TASKLET"
112 | "PORT_ATTR_RO" | "PORT_PMA_ATTR"
117 | s when s =~ "^DECLARE_.*" -> true
118 | s when s =~ ".*_ATTR$" -> true
119 | s when s =~ "^DEFINE_.*" -> true
125 (fun s
-> pr2_cpp ("MACRO: found declare-macro: " ^ s
))
130 incr
Stat.nIteratorHeuristic
;
131 pr2_cpp ("MACRO: found foreach: " ^ s
)
135 let msg_debug_macro s =
136 pr2_cpp ("MACRO: found debug-macro: " ^ s)
140 let msg_macro_noptvirg s
=
141 incr
Stat.nMacroStmt
;
142 pr2_cpp ("MACRO: found macro with param noptvirg: " ^ s
)
144 let msg_macro_toplevel_noptvirg s
=
145 incr
Stat.nMacroStmt
;
146 pr2_cpp ("MACRO: found toplevel macro noptvirg: " ^ s
)
148 let msg_macro_noptvirg_single s
=
149 incr
Stat.nMacroStmt
;
150 pr2_cpp ("MACRO: found single-macro noptvirg: " ^ s
)
155 let msg_macro_higher_order s
=
156 incr
Stat.nMacroHigherOrder
;
157 msg_gen (!Flag_parsing_c.debug_cpp
)
167 (fun s
-> pr2_cpp ("MACRO: found higher ordre macro : " ^ s
))
171 let msg_stringification s
=
172 incr
Stat.nMacroString
;
173 msg_gen (!Flag_parsing_c.debug_cpp
)
181 (* s when s =~ ".*STR.*" -> true *)
185 (fun s
-> pr2_cpp ("MACRO: found string-macro " ^ s
))
188 let msg_stringification_params s
=
189 incr
Stat.nMacroString
;
190 pr2_cpp ("MACRO: string-macro with params : " ^ s
)
194 let msg_apply_known_macro s
=
195 incr
Stat.nMacroExpand
;
196 pr2_cpp ("MACRO: found known macro = " ^ s
)
198 let msg_apply_known_macro_hint s
=
199 incr
Stat.nMacroHint
;
200 pr2_cpp ("MACRO: found known macro hint = " ^ s
)
205 let msg_ifdef_bool_passing is_ifdef_positif
=
206 incr
Stat.nIfdefZero
; (* of Version ? *)
208 then pr2_cpp "commenting parts of a #if 1 or #if LINUX_VERSION"
209 else pr2_cpp "commenting a #if 0 or #if LINUX_VERSION or __cplusplus"
212 let msg_ifdef_mid_something () =
213 incr
Stat.nIfdefExprPassing
;
214 pr2_cpp "found ifdef-mid-something"
216 let msg_ifdef_funheaders () =
217 incr
Stat.nIfdefFunheader
;
220 let msg_ifdef_cparen_else () =
221 incr
Stat.nIfdefPassing
;
222 pr2_cpp("found ifdef-cparen-else")
225 let msg_attribute s
=
226 incr
Stat.nMacroAttribute
;
231 (*****************************************************************************)
232 (* The regexp and basic view definitions *)
233 (*****************************************************************************)
235 (* opti: better to built then once and for all, especially regexp_foreach *)
237 let regexp_macro = Str.regexp
241 let regexp_annot = Str.regexp
245 let regexp_declare = Str.regexp
249 let regexp_foreach = Str.regexp_case_fold
250 ".*\\(for_?each\\|for_?all\\|iterate\\|loop\\|walk\\|scan\\|each\\|for\\)"
252 let regexp_typedef = Str.regexp
255 let false_typedef = [
260 let ok_typedef s
= not
(List.mem s
false_typedef)
263 not
(s
==~
regexp_annot)
268 (*****************************************************************************)
270 (*****************************************************************************)
272 (* ------------------------------------------------------------------------- *)
273 (* the pair is the status of '()' and '{}', ex: (-1,0)
274 * if too much ')' and good '{}'
275 * could do for [] too ?
276 * could do for ',' if encounter ',' at "toplevel", not inside () or {}
277 * then if have ifdef, then certainly can lead to a problem.
279 let (count_open_close_stuff_ifdef_clause
: TV.ifdef_grouped list
-> (int * int))=
281 let cnt_paren, cnt_brace
= ref 0, ref 0 in
282 xs
+> TV.iter_token_ifdef
(fun x
->
284 | x
when TH.is_opar x
-> incr
cnt_paren
285 | TOBrace _
-> incr cnt_brace
286 | x
when TH.is_cpar x
-> decr
cnt_paren
287 | TCBrace _
-> decr cnt_brace
291 !cnt_paren, !cnt_brace
294 (* ------------------------------------------------------------------------- *)
295 let forLOOKAHEAD = 30
298 (* look if there is a '{' just after the closing ')', and handling the
299 * possibility to have nested expressions inside nested parenthesis
301 * todo: use indentation instead of premier(statement) ?
303 let rec is_really_foreach xs
=
304 let rec is_foreach_aux = function
306 | TCPar _
::TOBrace _
::xs
-> true, xs
307 (* the following attempts to handle the cases where there is a
308 single statement in the body of the loop. undoubtedly more
310 todo: premier(statement) - suivant(funcall)
312 | TCPar _
::TIdent _
::xs
-> true, xs
313 | TCPar _
::Tif _
::xs
-> true, xs
314 | TCPar _
::Twhile _
::xs
-> true, xs
315 | TCPar _
::Tfor _
::xs
-> true, xs
316 | TCPar _
::Tswitch _
::xs
-> true, xs
317 | TCPar _
::Treturn _
::xs
-> true, xs
320 | TCPar _
::xs
-> false, xs
322 let (_
, xs'
) = is_foreach_aux xs
in
324 | x
::xs
-> is_foreach_aux xs
326 is_foreach_aux xs
+> fst
329 (* ------------------------------------------------------------------------- *)
330 let set_ifdef_token_parenthize_info cnt x
=
333 | TIfdefelse
(tag
, _
)
334 | TIfdefelif
(tag
, _
)
337 | TIfdefBool
(_
, tag
, _
)
338 | TIfdefMisc
(_
, tag
, _
)
339 | TIfdefVersion
(_
, tag
, _
)
343 | _
-> raise Impossible
347 let ifdef_paren_cnt = ref 0
350 let rec set_ifdef_parenthize_info xs
=
351 xs
+> List.iter
(function
352 | NotIfdefLine xs
-> ()
353 | Ifdefbool
(_
, xxs
, info_ifdef
)
354 | Ifdef
(xxs
, info_ifdef
) ->
356 incr
ifdef_paren_cnt;
357 let total_directives = List.length info_ifdef
in
359 info_ifdef
+> List.iter
(fun x
->
360 set_ifdef_token_parenthize_info (!ifdef_paren_cnt, total_directives)
362 xxs
+> List.iter
set_ifdef_parenthize_info
366 (*****************************************************************************)
367 (* CPP handling: macros, ifdefs, macros defs *)
368 (*****************************************************************************)
370 (* ------------------------------------------------------------------------- *)
371 (* special skip_start skip_end handling *)
372 (* ------------------------------------------------------------------------- *)
374 (* note: after this normally the token list should not contain any more the
375 * TCommentSkipTagStart and End tokens.
377 let rec commentize_skip_start_to_end xs
=
382 | {tok
= TCommentSkipTagStart info
} ->
384 let (before
, x2
, after
) =
385 xs
+> Common.split_when
(function
386 | {tok
= TCommentSkipTagEnd _
} -> true
390 let topass = x
::x2
::before
in
391 topass +> List.iter
(fun tok
->
392 set_as_comment
Token_c.CppPassingExplicit tok
394 commentize_skip_start_to_end after
396 failwith
"could not find end of skip_start special comment"
398 | {tok
= TCommentSkipTagEnd info
} ->
399 failwith
"found skip_end comment but no skip_start"
401 commentize_skip_start_to_end xs
407 (* ------------------------------------------------------------------------- *)
408 (* ifdef keeping/passing *)
409 (* ------------------------------------------------------------------------- *)
411 (* #if 0, #if 1, #if LINUX_VERSION handling *)
412 let rec find_ifdef_bool xs
=
413 xs
+> List.iter
(function
414 | NotIfdefLine _
-> ()
415 | Ifdefbool
(is_ifdef_positif
, xxs
, info_ifdef_stmt
) ->
417 msg_ifdef_bool_passing is_ifdef_positif
;
420 | [] -> raise Impossible
421 | firstclause
::xxs
->
422 info_ifdef_stmt
+> List.iter
(set_as_comment
Token_c.CppDirective
);
425 then xxs
+> List.iter
426 (iter_token_ifdef
(set_as_comment
Token_c.CppPassingNormal
))
428 firstclause
+> iter_token_ifdef
(set_as_comment
Token_c.CppPassingNormal
);
429 (match List.rev xxs
with
433 (iter_token_ifdef
(set_as_comment
Token_c.CppPassingNormal
))
434 | [] -> (* not #else *) ()
439 | Ifdef
(xxs
, info_ifdef_stmt
) -> xxs
+> List.iter
find_ifdef_bool
444 let thresholdIfdefSizeMid = 6
446 (* infer ifdef involving not-closed expressions/statements *)
447 let rec find_ifdef_mid xs
=
448 xs
+> List.iter
(function
449 | NotIfdefLine _
-> ()
450 | Ifdef
(xxs
, info_ifdef_stmt
) ->
452 | [] -> raise Impossible
454 | first
::second
::rest
->
455 (* don't analyse big ifdef *)
456 if xxs
+> List.for_all
457 (fun xs
-> List.length xs
<= thresholdIfdefSizeMid) &&
458 (* don't want nested ifdef *)
459 xxs
+> List.for_all
(fun xs
->
461 (function NotIfdefLine _
-> true | _
-> false)
465 let counts = xxs
+> List.map count_open_close_stuff_ifdef_clause
in
466 let cnt1, cnt2
= List.hd
counts in
467 if cnt1 <> 0 || cnt2
<> 0 &&
468 counts +> List.for_all
(fun x
-> x
=*= (cnt1, cnt2
))
470 if counts +> List.exists (fun (cnt1, cnt2) ->
471 cnt1 <> 0 || cnt2 <> 0
475 msg_ifdef_mid_something();
477 (* keep only first, treat the rest as comment *)
478 info_ifdef_stmt
+> List.iter
(set_as_comment
Token_c.CppDirective
);
479 (second
::rest
) +> List.iter
480 (iter_token_ifdef
(set_as_comment
Token_c.CppPassingCosWouldGetError
));
484 List.iter
find_ifdef_mid xxs
486 (* no need complex analysis for ifdefbool *)
487 | Ifdefbool
(_
, xxs
, info_ifdef_stmt
) ->
488 List.iter
find_ifdef_mid xxs
494 let thresholdFunheaderLimit = 4
496 (* ifdef defining alternate function header, type *)
497 let rec find_ifdef_funheaders = function
499 | NotIfdefLine _
::xs
-> find_ifdef_funheaders xs
501 (* ifdef-funheader if ifdef with 2 lines and a '{' in next line *)
503 ([(NotIfdefLine
(({col
= 0} as _xline1
)::line1
))::ifdefblock1
;
504 (NotIfdefLine
(({col
= 0} as xline2
)::line2
))::ifdefblock2
507 ::NotIfdefLine
(({tok
= TOBrace i
; col
= 0})::line3
)
509 when List.length ifdefblock1
<= thresholdFunheaderLimit &&
510 List.length ifdefblock2
<= thresholdFunheaderLimit
512 find_ifdef_funheaders xs
;
514 msg_ifdef_funheaders ();
515 info_ifdef_stmt
+> List.iter
(set_as_comment
Token_c.CppDirective
);
516 let all_toks = [xline2
] @ line2
in
517 all_toks +> List.iter
(set_as_comment
Token_c.CppPassingCosWouldGetError
) ;
518 ifdefblock2
+> iter_token_ifdef
(set_as_comment
Token_c.CppPassingCosWouldGetError
);
520 (* ifdef with nested ifdef *)
522 ([[NotIfdefLine
(({col
= 0} as _xline1
)::line1
)];
524 ([[NotIfdefLine
(({col
= 0} as xline2
)::line2
)];
525 [NotIfdefLine
(({col
= 0} as xline3
)::line3
)];
531 ::NotIfdefLine
(({tok
= TOBrace i
; col
= 0})::line4
)
534 find_ifdef_funheaders xs
;
536 msg_ifdef_funheaders ();
537 info_ifdef_stmt
+> List.iter
(set_as_comment
Token_c.CppDirective
);
538 info_ifdef_stmt2
+> List.iter
(set_as_comment
Token_c.CppDirective
);
539 let all_toks = [xline2
;xline3
] @ line2
@ line3
in
540 all_toks +> List.iter
(set_as_comment
Token_c.CppPassingCosWouldGetError
);
542 (* ifdef with elseif *)
544 ([[NotIfdefLine
(({col
= 0} as _xline1
)::line1
)];
545 [NotIfdefLine
(({col
= 0} as xline2
)::line2
)];
546 [NotIfdefLine
(({col
= 0} as xline3
)::line3
)];
549 ::NotIfdefLine
(({tok
= TOBrace i
; col
= 0})::line4
)
552 find_ifdef_funheaders xs
;
554 msg_ifdef_funheaders ();
555 info_ifdef_stmt
+> List.iter
(set_as_comment
Token_c.CppDirective
);
556 let all_toks = [xline2
;xline3
] @ line2
@ line3
in
557 all_toks +> List.iter
(set_as_comment
Token_c.CppPassingCosWouldGetError
)
560 | Ifdef
(xxs
,info_ifdef_stmt
)::xs
561 | Ifdefbool
(_
, xxs
,info_ifdef_stmt
)::xs
->
562 List.iter
find_ifdef_funheaders xxs
;
563 find_ifdef_funheaders xs
568 let rec adjust_inifdef_include xs
=
569 xs
+> List.iter
(function
570 | NotIfdefLine _
-> ()
571 | Ifdef
(xxs
, info_ifdef_stmt
) | Ifdefbool
(_
, xxs
, info_ifdef_stmt
) ->
572 xxs
+> List.iter
(iter_token_ifdef
(fun tokext
->
573 match tokext
.tok
with
574 | Parser_c.TInclude
(s1
, s2
, inifdef_ref
, ii
) ->
586 let rec find_ifdef_cparen_else xs
=
588 xs
+> List.iter
(function
589 | NotIfdefLine _
-> ()
590 | Ifdef
(xxs
, info_ifdef_stmt
) ->
592 | [] -> raise Impossible
594 | first
::second
::rest
->
596 (* found a closing ')' just after the #else *)
598 (* Too bad ocaml does not support better list pattern matching
599 * a la Prolog-III where can match the end of lists.
602 if List.length first
= 0 then false
604 let last_line = Common.last first
in
607 if List.length xs
= 0 then false
609 let last_tok = Common.last xs
in
610 TH.is_cpar
last_tok.tok
611 | Ifdef _
| Ifdefbool _
-> false
613 if condition then begin
614 msg_ifdef_cparen_else();
616 (* keep only first, treat the rest as comment *)
617 info_ifdef_stmt
+> List.iter
(set_as_comment
Token_c.CppDirective
);
618 (second
::rest
) +> List.iter
619 (iter_token_ifdef
(set_as_comment
Token_c.CppPassingCosWouldGetError
));
625 (* no need complex analysis for ifdefbool *)
626 | Ifdefbool
(_
, xxs
, info_ifdef_stmt
) ->
632 (* ------------------------------------------------------------------------- *)
633 (* cpp-builtin part2, macro, using standard.h or other defs *)
634 (* ------------------------------------------------------------------------- *)
636 (* now in cpp_token_c.ml *)
638 (* ------------------------------------------------------------------------- *)
639 (* stringification *)
640 (* ------------------------------------------------------------------------- *)
642 let rec find_string_macro_paren xs
=
645 | Parenthised
(xxs
, info_parens
)::xs
->
646 xxs
+> List.iter
(fun xs
->
648 (function PToken
({tok
= (TString _
| TMacroString _
)}) -> true | _
-> false) &&
650 (function PToken
({tok
= (TString _
| TMacroString _
)}) | PToken
({tok
= TIdent _
}) ->
653 xs
+> List.iter
(fun tok
->
655 | PToken
({tok
= TIdent
(s
,_
)} as id
) ->
656 msg_stringification s
;
657 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
661 find_string_macro_paren xs
663 find_string_macro_paren xs
665 find_string_macro_paren xs
668 (* ------------------------------------------------------------------------- *)
670 (* ------------------------------------------------------------------------- *)
672 (* don't forget to recurse in each case *)
673 let rec find_macro_paren xs
=
678 | PToken
({tok
= Tattribute _
} as id
)
679 ::Parenthised
(xxs
,info_parens
)
682 pr2_cpp ("MACRO: __attribute detected ");
683 [Parenthised
(xxs
, info_parens
)] +>
684 iter_token_paren
(set_as_comment
Token_c.CppAttr
);
685 set_as_comment
Token_c.CppAttr id
;
689 (* attribute cpp, __xxx id *)
690 | PToken
({tok
= TIdent
(s
,i1
)} as id
)
691 ::PToken
({tok
= TIdent
(s2
, i2
)} as id2
)
692 ::xs
when s
==~
regexp_annot
695 id
.tok
<- TMacroAttr
(s
, i1
);
696 find_macro_paren ((PToken id2
)::xs
); (* recurse also on id2 ? *)
698 (* attribute cpp, id __xxx *)
699 | PToken
({tok
= TIdent
(s
,i1
)} as _id
)
700 ::PToken
({tok
= TIdent
(s2
, i2
)} as id2
)
701 ::xs
when s2
==~
regexp_annot && (not
(s
==~
regexp_typedef))
704 id2
.tok
<- TMacroAttr
(s2
, i2
);
707 | PToken
({tok
= (Tstatic _
| Textern _
)} as tok1
)
708 ::PToken
({tok
= TIdent
(s
,i1
)} as attr
)
709 ::xs
when s
==~
regexp_annot
711 pr2_cpp ("storage attribute: " ^ s
);
712 attr
.tok
<- TMacroAttrStorage
(s
,i1
);
713 (* recurse, may have other storage attributes *)
714 find_macro_paren (PToken
(tok1
)::xs
)
719 (* storage attribute *)
720 | PToken
({tok
= (Tstatic _
| Textern _
)} as tok1
)
721 ::PToken
({tok
= TMacroAttr
(s
,i1
)} as attr
)::xs
723 pr2_cpp ("storage attribute: " ^ s
);
724 attr
.tok
<- TMacroAttrStorage
(s
,i1
);
725 (* recurse, may have other storage attributes *)
726 find_macro_paren (PToken
(tok1
)::xs
)
731 * the order of the matching clause is important
735 (* string macro with params, before case *)
736 | PToken
({tok
= (TString _
| TMacroString _
)})::PToken
({tok
= TIdent
(s
,_
)} as id
)
737 ::Parenthised
(xxs
, info_parens
)
740 msg_stringification_params s
;
741 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
742 [Parenthised
(xxs
, info_parens
)] +>
743 iter_token_paren
(set_as_comment
Token_c.CppMacro
);
747 | PToken
({tok
= TIdent
(s
,_
)} as id
)
748 ::Parenthised
(xxs
, info_parens
)
749 ::PToken
({tok
= (TString _
| TMacroString _
)})
752 msg_stringification_params s
;
753 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
754 [Parenthised
(xxs
, info_parens
)] +>
755 iter_token_paren
(set_as_comment
Token_c.CppMacro
);
759 (* for the case where the string is not inside a funcall, but
760 * for instance in an initializer.
763 (* string macro variable, before case *)
764 | PToken
({tok
= (TString _
| TMacroString _
)})::PToken
({tok
= TIdent
(s
,_
)} as id
)
767 msg_stringification s
;
768 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
772 | PToken
({tok
= TIdent
(s
,_
)} as id
)
773 ::PToken
({tok
= (TString _
| TMacroString _
)})
776 msg_stringification s
;
777 id
.tok
<- TMacroString
(s
, TH.info_of_tok id
.tok
);
785 | (PToken x
)::xs
-> find_macro_paren xs
786 | (Parenthised
(xxs
, info_parens
))::xs
->
787 xxs
+> List.iter
find_macro_paren;
794 (* don't forget to recurse in each case *)
795 let rec find_macro_lineparen xs
=
799 (* linuxext: ex: static [const] DEVICE_ATTR(); *)
802 [PToken
({tok
= Tstatic _
});
803 PToken
({tok
= TIdent
(s
,_
)} as macro
);
804 Parenthised
(xxs
,info_parens
);
805 PToken
({tok
= TPtVirg _
});
809 when (s
==~
regexp_macro) ->
812 let info = TH.info_of_tok macro
.tok
in
813 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
815 find_macro_lineparen (xs
)
817 (* the static const case *)
820 [PToken
({tok
= Tstatic _
});
821 PToken
({tok
= Tconst _
} as const
);
822 PToken
({tok
= TIdent
(s
,_
)} as macro
);
823 Parenthised
(xxs
,info_parens
);
824 PToken
({tok
= TPtVirg _
});
830 when (s
==~
regexp_macro) ->
833 let info = TH.info_of_tok macro
.tok
in
834 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
836 (* need retag this const, otherwise ambiguity in grammar
837 21: shift/reduce conflict (shift 121, reduce 137) on Tconst
838 decl2 : Tstatic . TMacroDecl TOPar argument_list TCPar ...
839 decl2 : Tstatic . Tconst TMacroDecl TOPar argument_list TCPar ...
840 storage_class_spec : Tstatic . (137)
842 const
.tok
<- TMacroDeclConst
(TH.info_of_tok const
.tok
);
844 find_macro_lineparen (xs
)
847 (* same but without trailing ';'
849 * I do not put the final ';' because it can be on a multiline and
850 * because of the way mk_line is coded, we will not have access to
851 * this ';' on the next line, even if next to the ')' *)
853 ([PToken
({tok
= Tstatic _
});
854 PToken
({tok
= TIdent
(s
,_
)} as macro
);
855 Parenthised
(xxs
,info_parens
);
859 when s
==~
regexp_macro ->
862 let info = TH.info_of_tok macro
.tok
in
863 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
865 find_macro_lineparen (xs
)
870 (* on multiple lines *)
873 (PToken
({tok
= Tstatic _
})::[]
877 [PToken
({tok
= TIdent
(s
,_
)} as macro
);
878 Parenthised
(xxs
,info_parens
);
879 PToken
({tok
= TPtVirg _
});
884 when (s
==~
regexp_macro) ->
887 let info = TH.info_of_tok macro
.tok
in
888 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
890 find_macro_lineparen (xs
)
893 (* linuxext: ex: DECLARE_BITMAP();
895 * Here I use regexp_declare and not regexp_macro because
896 * Sometimes it can be a FunCallMacro such as DEBUG(foo());
897 * Here we don't have the preceding 'static' so only way to
898 * not have positive is to restrict to .*DECLARE.* macros.
900 * but there is a grammar rule for that, so don't need this case anymore
901 * unless the parameter of the DECLARE_xxx are weird and can not be mapped
906 ([PToken
({tok
= TIdent
(s
,_
)} as macro
);
907 Parenthised
(xxs
,info_parens
);
908 PToken
({tok
= TPtVirg _
});
912 when (s
==~
regexp_declare) ->
915 let info = TH.info_of_tok macro
.tok
in
916 macro
.tok
<- TMacroDecl
(Ast_c.str_of_info
info, info);
918 find_macro_lineparen (xs
)
924 * Could also transform the TIdent in a TMacroTop but can have false
925 * positive, so easier to just change the TCPar and so just solve
926 * the end-of-stream pb of ocamlyacc
929 ([PToken
({tok
= TIdent
(s
,ii
); col
= col1
; where
= ctx
} as _macro
);
930 Parenthised
(xxs
,info_parens
);
936 (* to reduce number of false positive *)
938 | (Line
(PToken
({col
= col2
} as other
)::restline2
))::_
->
939 TH.is_eof other
.tok
|| (col2
=|= 0 &&
940 (match other
.tok
with
941 | TOBrace _
-> false (* otherwise would match funcdecl *)
942 | TCBrace _
when ctx
<> InFunction
-> false
946 | tok
when TH.is_binary_operator tok
-> false
957 msg_macro_toplevel_noptvirg s
;
958 (* just to avoid the end-of-stream pb of ocamlyacc *)
959 let tcpar = Common.last info_parens
in
960 tcpar.tok
<- TCParEOL
(TH.info_of_tok
tcpar.tok
);
962 (*macro.tok <- TMacroTop (s, TH.info_of_tok macro.tok);*)
966 find_macro_lineparen (xs
)
970 (* macro with parameters
975 ([PToken
({tok
= TIdent
(s
,ii
); col
= col1
; where
= ctx
} as macro
);
976 Parenthised
(xxs
,info_parens
);
980 (PToken
({col
= col2
} as other
)::restline2
983 (* when s ==~ regexp_macro *)
987 (match other
.tok
with
988 | TOBrace _
-> false (* otherwise would match funcdecl *)
989 | TCBrace _
when ctx
<> InFunction
-> false
993 | tok
when TH.is_binary_operator tok
-> false
1000 (match other
.tok
, restline2
with
1001 | TCBrace _
, _
when ctx
=*= InFunction
-> true
1002 | Treturn _
, _
-> true
1004 | Telse _
, _
-> true
1006 (* case of label, usually put in first line *)
1007 | TIdent _
, (PToken
({tok
= TDotDot _
}))::_
->
1019 if col1
=|= 0 then ()
1021 msg_macro_noptvirg s
;
1022 macro
.tok
<- TMacroStmt
(s
, TH.info_of_tok macro
.tok
);
1023 [Parenthised
(xxs
, info_parens
)] +>
1024 iter_token_paren
(set_as_comment
Token_c.CppMacro
);
1027 find_macro_lineparen (line2
::xs
)
1029 (* linuxext:? single macro
1034 * todo: factorize code with previous rule ?
1037 ([PToken
({tok
= TIdent
(s
,ii
); col
= col1
; where
= ctx
} as macro
);
1041 (PToken
({col
= col2
} as other
)::restline2
1044 (* when s ==~ regexp_macro *)
1048 col1
<> 0 && (* otherwise can match typedef of fundecl*)
1049 (match other
.tok
with
1050 | TPtVirg _
-> false
1052 | TCBrace _
when ctx
<> InFunction
-> false
1053 | tok
when TH.is_binary_operator tok
-> false
1058 (match other
.tok
with
1059 | TCBrace _
when ctx
=*= InFunction
-> true
1069 msg_macro_noptvirg_single s
;
1070 macro
.tok
<- TMacroStmt
(s
, TH.info_of_tok macro
.tok
);
1072 find_macro_lineparen (line2
::xs
)
1075 find_macro_lineparen xs
1079 (* ------------------------------------------------------------------------- *)
1080 (* define tobrace init *)
1081 (* ------------------------------------------------------------------------- *)
1083 let rec find_define_init_brace_paren xs
=
1088 (* mainly for firefox *)
1089 | (PToken
{tok
= TDefine _
})
1090 ::(PToken
{tok
= TIdentDefine
(s
,_
)})
1091 ::(PToken
({tok
= TOBrace i1
} as tokbrace
))
1096 match tok2
.tok
, tok3
.tok
with
1097 | TInt _
, TComma _
-> true
1098 | TString _
, TComma _
-> true
1099 | TIdent _
, TComma _
-> true
1105 pr2_cpp("found define initializer: " ^s
);
1106 tokbrace
.tok
<- TOBraceDefineInit i1
;
1111 (* mainly for linux, especially in sound/ *)
1112 | (PToken
{tok
= TDefine _
})
1113 ::(PToken
{tok
= TIdentDefine
(s
,_
)})
1114 ::(Parenthised
(xxx
, info_parens
))
1115 ::(PToken
({tok
= TOBrace i1
} as tokbrace
))
1120 match tok2
.tok
, tok3
.tok
with
1121 | TInt _
, TComma _
-> true
1122 | TDot _
, TIdent _
-> true
1123 | TIdent _
, TComma _
-> true
1129 pr2_cpp("found define initializer with param: " ^ s
);
1130 tokbrace
.tok
<- TOBraceDefineInit i1
;
1138 | (PToken x
)::xs
-> aux xs
1139 | (Parenthised
(xxs
, info_parens
))::xs
->
1140 (* not need for tobrace init:
1141 * xxs +> List.iter aux;
1148 (* ------------------------------------------------------------------------- *)
1150 (* ------------------------------------------------------------------------- *)
1152 (* obsolete now with macro expansion ? get some regression if comment.
1153 * todo: if do bad decision here, then it can influence other phases
1154 * and make it hard to parse. So maybe when have a parse error, should
1155 * undo some of the guess those heuristics have done, and restore
1156 * the original token value.
1159 let rec find_actions = function
1162 | PToken
({tok
= TIdent
(s
,ii
)})
1163 ::Parenthised
(xxs
,info_parens
)
1166 xxs
+> List.iter
find_actions;
1167 let modified = find_actions_params xxs
in
1169 then msg_macro_higher_order s
1174 and find_actions_params xxs
=
1175 xxs
+> List.fold_left
(fun acc xs
->
1176 let toks = tokens_of_paren xs
in
1177 if toks +> List.exists
(fun x
-> TH.is_statement x
.tok
)
1178 (* undo: && List.length toks > 1
1179 * good for sparse, not good for linux
1182 xs
+> iter_token_paren
(fun x
->
1185 (* certainly because paren detection had a pb because of
1186 * some ifdef-exp. Do similar additional checking than
1187 * what is done in set_as_comment.
1189 pr2 "PB: weird, I try to tag an EOF token as an action"
1191 (* cf tests-bis/no_cpar_macro.c *)
1194 pr2 "PB: weird, I try to tag an EOM token as an action"
1196 x
.tok
<- TAction
(TH.info_of_tok x
.tok
);
1205 (* ------------------------------------------------------------------------- *)
1206 (* main fix cpp function *)
1207 (* ------------------------------------------------------------------------- *)
1209 let filter_cpp_stuff xs
=
1215 | tok
when TH.is_comment tok
-> aux xs
1216 (* don't want drop the define, or if drop, have to drop
1217 * also its body otherwise the line heuristics may be lost
1218 * by not finding the TDefine in column 0 but by finding
1219 * a TDefineIdent in a column > 0
1221 | Parser_c.TDefine _
->
1223 | tok
when TH.is_cpp_instruction tok
-> aux xs
1229 let insert_virtual_positions l
=
1230 let strlen x
= String.length
(Ast_c.str_of_info x
) in
1231 let rec loop prev offset acc
= function
1234 let ii = TH.info_of_tok x
in
1236 TH.visitor_info_of_tok
(function ii -> Ast_c.rewrap_pinfo pi
ii) x
in
1237 match Ast_c.pinfo_of_info
ii with
1238 Ast_c.OriginTok pi
->
1239 let prev = Ast_c.parse_info_of_info
ii in
1240 loop prev (strlen ii) (x
::acc
) xs
1241 | Ast_c.ExpandedTok
(pi
,_
) ->
1242 let x'
= inject (Ast_c.ExpandedTok
(pi
,(prev,offset
))) in
1243 loop prev (offset
+ (strlen ii)) (x'
::acc
) xs
1244 | Ast_c.FakeTok
(s
,_
) ->
1245 let x'
= inject (Ast_c.FakeTok
(s
,(prev,offset
))) in
1246 loop prev (offset
+ (strlen ii)) (x'
::acc
) xs
1247 | Ast_c.AbstractLineTok _
-> failwith
"abstract not expected" in
1248 let rec skip_fake = function
1251 let ii = TH.info_of_tok
x in
1252 match Ast_c.pinfo_of_info
ii with
1253 | Ast_c.OriginTok pi
->
1254 let prev = Ast_c.parse_info_of_info
ii in
1255 let res = loop prev (strlen ii) [] xs
in
1257 | _
-> x::skip_fake xs
in
1261 (* ------------------------------------------------------------------------- *)
1262 let fix_tokens_cpp2 ~macro_defs tokens
=
1263 let tokens2 = ref (tokens
+> Common.acc_map
TV.mk_token_extended
) in
1266 (* the order is important, if you put the action heuristic first,
1267 * then because of ifdef, can have not closed paren
1268 * and so may believe that higher order macro
1269 * and it will eat too much tokens. So important to do
1272 * I recompute multiple times cleaner cos the mutable
1273 * can have be changed and so may have more comments
1274 * in the token original list.
1278 commentize_skip_start_to_end !tokens2;
1281 let cleaner = !tokens2 +> List.filter
(fun x ->
1282 (* is_comment will also filter the TCommentCpp created in
1283 * commentize_skip_start_to_end *)
1284 not
(TH.is_comment
x.tok
) (* could filter also #define/#include *)
1286 let ifdef_grouped = TV.mk_ifdef
cleaner in
1287 set_ifdef_parenthize_info ifdef_grouped;
1289 find_ifdef_funheaders ifdef_grouped;
1290 find_ifdef_bool ifdef_grouped;
1291 find_ifdef_mid ifdef_grouped;
1292 (* change order ? maybe cparen_else heuristic make some of the funheaders
1293 * heuristics irrelevant ?
1295 find_ifdef_cparen_else ifdef_grouped;
1296 adjust_inifdef_include ifdef_grouped;
1300 let cleaner = !tokens2 +> filter_cpp_stuff in
1302 let paren_grouped = TV.mk_parenthised
cleaner in
1303 Cpp_token_c.apply_macro_defs
1304 ~
msg_apply_known_macro
1305 ~
msg_apply_known_macro_hint
1306 macro_defs
paren_grouped;
1307 (* because the before field is used by apply_macro_defs *)
1308 tokens2 := TV.rebuild_tokens_extented
!tokens2;
1310 (* tagging contextual info (InFunc, InStruct, etc). Better to do
1311 * that after the "ifdef-simplification" phase.
1313 let cleaner = !tokens2 +> List.filter
(fun x ->
1314 not
(TH.is_comment
x.tok
) (* could filter also #define/#include *)
1317 let brace_grouped = TV.mk_braceised
cleaner in
1318 set_context_tag
brace_grouped;
1323 let cleaner = !tokens2 +> filter_cpp_stuff in
1325 let paren_grouped = TV.mk_parenthised
cleaner in
1326 let line_paren_grouped = TV.mk_line_parenthised
paren_grouped in
1327 find_define_init_brace_paren paren_grouped;
1328 find_string_macro_paren paren_grouped;
1329 find_macro_lineparen line_paren_grouped;
1330 find_macro_paren paren_grouped;
1333 (* obsolete: actions ? not yet *)
1334 let cleaner = !tokens2 +> filter_cpp_stuff in
1335 let paren_grouped = TV.mk_parenthised
cleaner in
1336 find_actions paren_grouped;
1340 insert_virtual_positions (!tokens2 +> Common.acc_map
(fun x -> x.tok
))
1343 let time_hack1 ~macro_defs a
=
1344 Common.profile_code_exclusif
"HACK" (fun () -> fix_tokens_cpp2 ~macro_defs a
)
1346 let fix_tokens_cpp ~macro_defs a
=
1347 Common.profile_code
"C parsing.fix_cpp" (fun () -> time_hack1 ~macro_defs a
)
1351 (*****************************************************************************)
1352 (* for the cpp-builtin, standard.h, part 0 *)
1353 (*****************************************************************************)
1355 (* now in cpp_token_c.ml *)
1357 (*****************************************************************************)
1358 (* Lexing with lookahead *)
1359 (*****************************************************************************)
1361 (* Why using yet another parsing_hack technique ? The fix_xxx where do
1362 * some pre-processing on the full list of tokens is not enough ?
1363 * No cos sometimes we need more contextual info, and even if
1364 * set_context() tries to give some contextual info, it's not completely
1365 * accurate so the following code give yet another alternative, yet another
1366 * chance to transform some tokens.
1368 * todo?: maybe could try to get rid of this technique. Maybe a better
1369 * set_context() would make possible to move this code using a fix_xx
1372 * LALR(k) trick. We can do stuff by adding cases in lexer_c.mll, but
1373 * it is more general to do it via my LALR(k) tech. Because here we can
1374 * transform some token give some context information. So sometimes it
1375 * makes sense to transform a token in one context, sometimes not, and
1376 * lex can not provide us this context information. Note that the order
1377 * in the pattern matching in lookahead is important. Do not cut/paste.
1379 * Note that in next there is only "clean" tokens, there is no comment
1380 * or space tokens. This is done by the caller.
1384 open Lexer_parser
(* for the fields of lexer_hint type *)
1386 let not_struct_enum = function
1387 | (Parser_c.Tstruct _
| Parser_c.Tunion _
| Parser_c.Tenum _
)::_
-> false
1391 let lookahead2 ~pass next before
=
1393 match (next
, before
) with
1395 (*-------------------------------------------------------------*)
1396 (* typedef inference, parse_typedef_fix3 *)
1397 (*-------------------------------------------------------------*)
1399 | (TIdent
(s
,i1
)::TIdent
(s2
,i2
)::_
, _
) when not_struct_enum before
&& s
=$
= s2
1401 (* (take_safe 1 !passed_tok <> [TOPar]) -> *)
1403 (* parse_typedef_fix3:
1404 * acpi_object acpi_object;
1405 * etait mal parsé, car pas le temps d'appeler dt() dans le type_spec.
1406 * Le parser en interne a deja appelé le prochain token pour pouvoir
1407 * decider des choses.
1408 * => special case in lexer_heuristic, again
1410 if !Flag_parsing_c.debug_typedef
1411 then pr2 ("TYPEDEF: disable typedef cos special case: " ^ s
);
1413 LP.disable_typedef
();
1415 msg_typedef s
; LP.add_typedef_root s
;
1416 TypedefIdent
(s
, i1
)
1419 | (TIdent
(s
, i1
)::TIdent
(s2
, i2
)::_
, _
) when not_struct_enum before
1422 (* && not_annot s2 BUT lead to false positive*)
1424 msg_typedef s
; LP.add_typedef_root s
;
1425 TypedefIdent
(s
, i1
)
1429 | (TIdent
(s
, i1
)::Tinline i2
::_
, _
) when not_struct_enum before
1432 msg_typedef s
; LP.add_typedef_root s
;
1433 TypedefIdent
(s
, i1
)
1436 (* [,(] xx [,)] AND param decl *)
1437 | (TIdent
(s
, i1
)::(TComma _
|TCPar _
)::_
, (TComma _
|TOPar _
)::_
)
1438 when not_struct_enum before
&& (LP.current_context
() =*= LP.InParameter
)
1441 msg_typedef s
; LP.add_typedef_root s
;
1442 TypedefIdent
(s
, i1
)
1445 (* specialcase: [,(] xx* [,)] *)
1446 | (TIdent
(s
, i1
)::TMul _
::(TComma _
|TCPar _
)::_
, (*(TComma _|TOPar _)::*)_
)
1447 when not_struct_enum before
1448 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1451 msg_typedef s
; LP.add_typedef_root s
;
1452 TypedefIdent
(s
, i1
)
1456 (* specialcase: [,(] xx** [,)] *)
1457 | (TIdent
(s
, i1
)::TMul _
::TMul _
::(TComma _
|TCPar _
)::_
, (*(TComma _|TOPar _)::*)_
)
1458 when not_struct_enum before
1459 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1462 msg_typedef s
; LP.add_typedef_root s
;
1463 TypedefIdent
(s
, i1
)
1467 (* xx const * USELESS because of next rule ? *)
1468 | (TIdent
(s
, i1
)::(Tconst _
|Tvolatile _
|Trestrict _
)::TMul _
::_
, _
)
1469 when not_struct_enum before
1470 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1474 msg_typedef s
; LP.add_typedef_root s
;
1475 TypedefIdent
(s
, i1
)
1478 | (TIdent
(s
, i1
)::(Tconst _
|Tvolatile _
|Trestrict _
)::_
, _
)
1479 when not_struct_enum before
1481 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1484 msg_typedef s
; LP.add_typedef_root s
;
1485 TypedefIdent
(s
, i1
)
1489 | (TIdent
(s
, i1
)::TMul _
::(Tconst _
| Tvolatile _
|Trestrict _
)::_
, _
)
1490 when not_struct_enum before
1493 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1495 msg_typedef s
; LP.add_typedef_root s
;
1496 TypedefIdent
(s
, i1
)
1500 | (TIdent
(s
, i1
)::TCPar _
::_
, (Tconst _
| Tvolatile _
|Trestrict _
)::TOPar _
::_
) when
1502 msg_typedef s
; LP.add_typedef_root s
;
1503 TypedefIdent
(s
, i1
)
1507 (* ( xx ) [sizeof, ~] *)
1508 | (TIdent
(s
, i1
)::TCPar _
::(Tsizeof _
|TTilde _
)::_
, TOPar _
::_
)
1509 when not_struct_enum before
1512 msg_typedef s
; LP.add_typedef_root s
;
1513 TypedefIdent
(s
, i1
)
1515 (* [(,] xx [ AND parameterdeclaration *)
1516 | (TIdent
(s
, i1
)::TOCro _
::_
, (TComma _
|TOPar _
)::_
)
1517 when (LP.current_context
() =*= LP.InParameter
)
1520 msg_typedef s
; LP.add_typedef_root s
;
1521 TypedefIdent
(s
, i1
)
1523 (*------------------------------------------------------------*)
1524 (* if 'x*y' maybe an expr, maybe just a classic multiplication *)
1525 (* but if have a '=', or ',' I think not *)
1526 (*------------------------------------------------------------*)
1528 (* static xx * yy *)
1529 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::_
,
1530 (Tregister _
|Tstatic _
|Tvolatile _
|Tconst _
|Trestrict _
)::_
) when
1533 msg_typedef s
; LP.add_typedef_root s
;
1534 TypedefIdent
(s
, i1
)
1536 (* TODO xx * yy ; AND in start of compound element *)
1539 (* xx * yy, AND in paramdecl *)
1540 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TComma _
::_
, _
)
1541 when not_struct_enum before
&& (LP.current_context
() =*= LP.InParameter
)
1545 msg_typedef s
; LP.add_typedef_root s
;
1546 TypedefIdent
(s
, i1
)
1549 (* xx * yy ; AND in Toplevel, except when have = before *)
1550 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TPtVirg _
::_
, TEq _
::_
) ->
1552 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TPtVirg _
::_
, _
)
1553 when not_struct_enum before
&& (LP.is_top_or_struct
(LP.current_context
()))
1555 msg_typedef s
; LP.add_typedef_root s
;
1556 TypedefIdent
(s
, i1
)
1558 (* xx * yy , AND in Toplevel *)
1559 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TComma _
::_
, _
)
1560 when not_struct_enum before
&& (LP.current_context
() =*= LP.InTopLevel
)
1564 msg_typedef s
; LP.add_typedef_root s
;
1565 TypedefIdent
(s
, i1
)
1567 (* xx * yy ( AND in Toplevel *)
1568 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TOPar _
::_
, _
)
1569 when not_struct_enum before
1570 && (LP.is_top_or_struct
(LP.current_context
()))
1573 msg_typedef s
; LP.add_typedef_root s
;
1574 TypedefIdent
(s
, i1
)
1577 (* todo? enough ? cos in struct def we can have some expression ! *)
1578 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TOCro _
::_
, _
)
1579 when not_struct_enum before
&&
1580 (LP.is_top_or_struct
(LP.current_context
()))
1583 msg_typedef s
; LP.add_typedef_root s
;
1584 TypedefIdent
(s
, i1
)
1586 (* u16: 10; in struct *)
1587 | (TIdent
(s
, i1
)::TDotDot _
::_
, (TOBrace _
| TPtVirg _
)::_
)
1588 when (LP.is_top_or_struct
(LP.current_context
()))
1591 msg_typedef s
; LP.add_typedef_root s
;
1592 TypedefIdent
(s
, i1
)
1595 (* why need TOPar condition as stated in preceding rule ? really needed ? *)
1596 (* YES cos at toplevel can have some expression !! for instance when *)
1597 (* enter in the dimension of an array *)
1599 | (TIdent s::TMul::TIdent s2::_ , _)
1600 when (take_safe 1 !passed_tok <> [Tstruct] &&
1601 (take_safe 1 !passed_tok <> [Tenum]))
1603 !LP._lexer_hint = Some LP.Toplevel ->
1604 msg_typedef s; LP.add_typedef_root s;
1609 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TEq _
::_
, _
)
1610 when not_struct_enum before
1613 msg_typedef s
; LP.add_typedef_root s
;
1614 TypedefIdent
(s
, i1
)
1617 (* xx * yy) AND in paramdecl *)
1618 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TCPar _
::_
, _
)
1619 when not_struct_enum before
&& (LP.current_context
() =*= LP.InParameter
)
1622 msg_typedef s
; LP.add_typedef_root s
;
1623 TypedefIdent
(s
, i1
)
1626 (* xx * yy; *) (* wrong ? *)
1627 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TPtVirg _
::_
,
1628 (TOBrace _
| TPtVirg _
)::_
) when not_struct_enum before
1631 msg_typedef s
; LP.add_typedef_root s
;
1632 msg_maybe_dangereous_typedef s
;
1633 TypedefIdent
(s
, i1
)
1636 (* xx * yy, and ';' before xx *) (* wrong ? *)
1637 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::TComma _
::_
,
1638 (TOBrace _
| TPtVirg _
)::_
) when
1641 msg_typedef s
; LP.add_typedef_root s
;
1642 TypedefIdent
(s
, i1
)
1646 | (TIdent
(s
, i1
)::TMul _
::TIdent
(s2
, i2
)::_
, _
)
1647 when s
==~
regexp_typedef && not_struct_enum before
1648 (* struct user_info_t sometimes *)
1651 msg_typedef s
; LP.add_typedef_root s
;
1652 TypedefIdent
(s
, i1
)
1654 (* xx ** yy *) (* wrong ? *)
1655 | (TIdent
(s
, i1
)::TMul _
::TMul _
::TIdent
(s2
, i2
)::_
, _
)
1656 when not_struct_enum before
1657 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1660 msg_typedef s
; LP.add_typedef_root s
;
1661 TypedefIdent
(s
, i1
)
1664 | (TIdent
(s
, i1
)::TMul _
::TMul _
::TMul _
::TIdent
(s2
, i2
)::_
, _
)
1665 when not_struct_enum before
1667 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1669 msg_typedef s
; LP.add_typedef_root s
;
1670 TypedefIdent
(s
, i1
)
1673 | (TIdent
(s
, i1
)::TMul _
::TMul _
::TCPar _
::_
, _
)
1674 when not_struct_enum before
1675 (* && !LP._lexer_hint = Some LP.ParameterDeclaration *)
1678 msg_typedef s
; LP.add_typedef_root s
;
1679 TypedefIdent
(s
, i1
)
1683 (* ----------------------------------- *)
1684 (* old: why not do like for other rules and start with TIdent ?
1685 * why do TOPar :: TIdent :: ..., _ and not TIdent :: ..., TOPAr::_ ?
1686 * new: prefer now start with TIdent because otherwise the add_typedef_root
1687 * may have no effect if in second pass or if have disable the add_typedef.
1691 | (TIdent
(s
, i1
)::TCPar i2
::(TIdent
(_
,i3
)|TInt
(_
,i3
))::_
,
1693 when not
(TH.is_stuff_taking_parenthized
x) &&
1694 Ast_c.line_of_info i2
=|= Ast_c.line_of_info i3
1698 msg_typedef s
; LP.add_typedef_root s
;
1700 TypedefIdent
(s
, i1
)
1704 * but false positif: typedef int (xxx_t)(...), so do specialisation below.
1707 | (TIdent (s, i1)::TCPar _::TOPar _::_ , (TOPar info)::x::_)
1708 when not (TH.is_stuff_taking_parenthized x)
1711 msg_typedef s; LP.add_typedef_root s;
1713 TypedefIdent
(s
, i1
)
1715 (* special case: = (xx) ( yy) *)
1716 | (TIdent
(s
, i1
)::TCPar _
::TOPar _
::_
,
1717 (TOPar
info)::(TEq _
|TEqEq _
)::_
)
1720 msg_typedef s
; LP.add_typedef_root s
;
1722 TypedefIdent
(s
, i1
)
1726 | (TIdent
(s
, i1
)::TMul _
::TCPar _
::TIdent
(s2
, i2
)::_
, (TOPar
info)::_
) when
1729 msg_typedef s
; LP.add_typedef_root s
;
1734 (* (xx){ ... } constructor *)
1735 | (TIdent
(s
, i1
)::TCPar _
::TOBrace _
::_
, TOPar _
::x::_
)
1736 when (*s ==~ regexp_typedef && *) not
(TH.is_stuff_taking_parenthized
x)
1739 msg_typedef s
; LP.add_typedef_root s
;
1740 TypedefIdent
(s
, i1
)
1743 (* can have sizeof on expression
1744 | (Tsizeof::TOPar::TIdent s::TCPar::_, _) ->
1745 msg_typedef s; LP.add_typedef_root s;
1750 (* ----------------------------------- *)
1751 (* x ( *y )(params), function pointer *)
1752 | (TIdent
(s
, i1
)::TOPar _
::TMul _
::TIdent _
::TCPar _
::TOPar _
::_
, _
)
1753 when not_struct_enum before
1756 msg_typedef s
; LP.add_typedef_root s
;
1757 TypedefIdent
(s
, i1
)
1759 (* x* ( *y )(params), function pointer 2 *)
1760 | (TIdent
(s
, i1
)::TMul _
::TOPar _
::TMul _
::TIdent _
::TCPar _
::TOPar _
::_
, _
)
1761 when not_struct_enum before
1764 msg_typedef s
; LP.add_typedef_root s
;
1765 TypedefIdent
(s
, i1
)
1768 (*-------------------------------------------------------------*)
1770 (*-------------------------------------------------------------*)
1771 | ((TIfdef
(_
,ii) |TIfdefelse
(_
,ii) |TIfdefelif
(_
,ii) |TEndif
(_
,ii) |
1772 TIfdefBool
(_
,_
,ii)|TIfdefMisc
(_
,_
,ii)|TIfdefVersion
(_
,_
,ii))
1777 if not !Flag_parsing_c.ifdef_to_if
1778 then TCommentCpp (Ast_c.CppDirective, ii)
1781 (* not !LP._lexer_hint.toplevel *)
1782 if !Flag_parsing_c.ifdef_directive_passing
1786 if (LP.current_context
() =*= LP.InInitializer
)
1788 pr2_cpp "In Initializer passing"; (* cheat: dont count in stat *)
1789 incr
Stat.nIfdefInitializer
;
1791 pr2_cpp("IFDEF: or related inside function. I treat it as comment");
1792 incr
Stat.nIfdefPassing
;
1794 TCommentCpp
(Token_c.CppDirective
, ii)
1798 | (TUndef
(id
, ii) as x)::_
, _
1802 pr2_cpp("UNDEF: I treat it as comment");
1803 TCommentCpp
(Token_c.CppDirective
, ii)
1807 | (TCppDirectiveOther
(ii) as x)::_
, _
1811 pr2_cpp ("OTHER directive: I treat it as comment");
1812 TCommentCpp
(Token_c.CppDirective
, ii)
1816 (* If ident contain a for_each, then certainly a macro. But to be
1817 * sure should look if there is a '{' after the ')', but it requires
1818 * to count the '('. Because this can be expensive, we do that only
1819 * when the token contains "for_each".
1821 | (TIdent
(s
, i1
)::TOPar _
::rest
, _
)
1822 when not
(LP.current_context
() =*= LP.InTopLevel
)
1823 (* otherwise a function such as static void loopback_enable(int i) {
1824 * will be considered as a loop
1829 if s
==~
regexp_foreach &&
1830 is_really_foreach (Common.take_safe
forLOOKAHEAD rest
)
1834 TMacroIterator
(s
, i1
)
1840 (*-------------------------------------------------------------*)
1842 | _
-> raise Impossible
1844 let lookahead ~pass a b
=
1845 Common.profile_code
"C parsing.lookahead" (fun () -> lookahead2 ~pass a b
)