262
263
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
268
(*****************************************************************************)
792
270
(*****************************************************************************)
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
272
(* ------------------------------------------------------------------------- *)
815
273
(* the pair is the status of '()' and '{}', ex: (-1,0)
816
274
* if too much ')' and good '{}'
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) ->
1124
632
(* ------------------------------------------------------------------------- *)
1125
633
(* cpp-builtin part2, macro, using standard.h or other defs *)
1126
634
(* ------------------------------------------------------------------------- *)
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;
636
(* now in cpp_token_c.ml *)
1290
638
(* ------------------------------------------------------------------------- *)
1291
639
(* stringification *)
1949
1323
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
1325
let paren_grouped = TV.mk_parenthised cleaner in
1326
let line_paren_grouped = TV.mk_line_parenthised paren_grouped in
1953
1327
find_define_init_brace_paren paren_grouped;
1954
1328
find_string_macro_paren paren_grouped;
1955
1329
find_macro_lineparen line_paren_grouped;
1956
1330
find_macro_paren paren_grouped;
1333
(* obsolete: actions ? not yet *)
1960
1334
let cleaner = !tokens2 +> filter_cpp_stuff in
1961
let paren_grouped = mk_parenthised cleaner in
1335
let paren_grouped = TV.mk_parenthised cleaner in
1962
1336
find_actions paren_grouped;
1965
insert_virtual_positions (!tokens2 +> acc_map (fun x -> x.tok))
1340
insert_virtual_positions (!tokens2 +> Common.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)
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)
2088
1351
(*****************************************************************************)
2089
1352
(* for the cpp-builtin, standard.h, part 0 *)
2090
1353
(*****************************************************************************)
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
1355
(* now in cpp_token_c.ml *)
2145
1357
(*****************************************************************************)
2146
1358
(* Lexing with lookahead *)