~ubuntu-branches/ubuntu/karmic/coccinelle/karmic

« back to all changes in this revision

Viewing changes to parsing_c/parsing_hacks.ml

  • Committer: Bazaar Package Importer
  • Author(s): Євгеній Мещеряков
  • Date: 2009-05-11 15:32:24 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20090511153224-1odv41d4dkr3y80v
Tags: 0.1.8.deb-2
Use common install Makefile target for both native and bytecode
build. This hopefully fixes FTBFS on bytecode archs 

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
open Common
16
16
 
17
17
module TH = Token_helpers 
 
18
module TV = Token_views_c
18
19
module LP = Lexer_parser
19
20
 
20
21
module Stat = Parsing_stat
21
22
 
22
23
open Parser_c 
23
24
 
 
25
open TV 
 
26
 
24
27
(*****************************************************************************)
25
28
(* Some debugging functions  *)
26
29
(*****************************************************************************)
27
30
 
28
 
let pr2 s = 
29
 
  if !Flag_parsing_c.verbose_parsing 
30
 
  then Common.pr2 s
31
 
 
32
 
let pr2_once s = 
33
 
  if !Flag_parsing_c.verbose_parsing 
34
 
  then Common.pr2_once s
 
31
let pr2, pr2_once = Common.mk_pr2_wrappers Flag_parsing_c.verbose_parsing
35
32
 
36
33
let pr2_cpp s = 
37
34
  if !Flag_parsing_c.debug_cpp
220
217
  incr Stat.nIfdefFunheader;
221
218
  ()
222
219
 
 
220
let msg_ifdef_cparen_else () = 
 
221
  incr Stat.nIfdefPassing;
 
222
  pr2_cpp("found ifdef-cparen-else")
 
223
 
223
224
 
224
225
let msg_attribute s = 
225
226
  incr Stat.nMacroAttribute;
262
263
  not (s ==~ regexp_annot)
263
264
 
264
265
 
265
 
(* ------------------------------------------------------------------------- *)
266
 
(* cpp part 1 for standard.h *)
267
 
(* ------------------------------------------------------------------------- *)
268
 
 
269
 
type define_def = string * define_param * define_body 
270
 
 and define_param = 
271
 
   | NoParam
272
 
   | Params of string list
273
 
 and define_body = 
274
 
   | DefineBody of Parser_c.token list
275
 
   | DefineHint of parsinghack_hint
276
 
 
277
 
   and parsinghack_hint = 
278
 
     | HintIterator
279
 
     | HintDeclarator
280
 
     | HintMacroString
281
 
     | HintMacroStatement
282
 
     | HintAttribute
283
 
     | HintMacroIdentBuilder
284
 
 
285
 
 
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;
294
 
 
295
 
  "MACROSTATEMENT"   , HintMacroStatement; (* backward compatibility *)
296
 
]
297
 
 
298
 
 
299
 
let (parsinghack_hint_of_string: string -> parsinghack_hint option) = fun s -> 
300
 
  Common.assoc_option s assoc_hint_string
301
 
 
302
 
let (is_parsinghack_hint: string -> bool) = fun s -> 
303
 
  parsinghack_hint_of_string s <> None
304
 
 
305
 
let (token_from_parsinghack_hint: 
306
 
     (string * Ast_c.info) -> parsinghack_hint -> Parser_c.token) = 
307
 
 fun (s,ii) hint ->
308
 
   match hint with
309
 
   | HintIterator -> 
310
 
       Parser_c.TMacroIterator (s, ii)
311
 
   | HintDeclarator -> 
312
 
       Parser_c.TMacroDecl (s, ii)
313
 
   | HintMacroString -> 
314
 
       Parser_c.TMacroString (s, ii)
315
 
   | HintMacroStatement -> 
316
 
       Parser_c.TMacroStmt (s, ii)
317
 
   | HintAttribute -> 
318
 
       Parser_c.TMacroAttr (s, ii)
319
 
   | HintMacroIdentBuilder -> 
320
 
       Parser_c.TMacroIdentBuilder (s, ii)
321
 
  
322
 
 
323
 
 
324
 
let (_defs : (string, define_def) Hashtbl.t ref)  = 
325
 
  ref (Hashtbl.create 101)
326
 
 
327
 
 
328
 
(* ------------------------------------------------------------------------- *)
329
 
(* fuzzy parsing, different "views" over the same program *)
330
 
(* ------------------------------------------------------------------------- *)
331
 
 
332
 
 
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. *)
343
 
 
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.
350
 
 *)
351
 
 
352
 
(* update: quite close to the Place_c.Inxxx *)
353
 
type context = 
354
 
  InFunction | InEnum | InStruct | InInitializer | NoContext
355
 
 
356
 
type token_extended = { 
357
 
  mutable tok: Parser_c.token;
358
 
  mutable where: context;
359
 
 
360
 
  (* less: need also a after ? *)
361
 
  mutable new_tokens_before : Parser_c.token list;
362
 
 
363
 
  (* line x col  cache, more easily accessible, of the info in the token *)
364
 
  line: int; 
365
 
  col : int;
366
 
}
367
 
 
368
 
let set_as_comment cppkind x = 
369
 
  if TH.is_eof x.tok 
370
 
  then () (* otherwise parse_c will be lost if don't find a EOF token *)
371
 
  else 
372
 
    x.tok <- TCommentCpp (cppkind, TH.info_of_tok x.tok)
373
 
 
374
 
let mk_token_extended x = 
375
 
  let (line, col) = TH.linecol_of_tok x in
376
 
  { tok = x; 
377
 
    line = line; col = col; 
378
 
    where = NoContext; 
379
 
    new_tokens_before = [];
380
 
  }
381
 
 
382
 
 
383
 
(* x list list, because x list separated by ',' *) 
384
 
type paren_grouped = 
385
 
  | Parenthised   of paren_grouped list list * token_extended list
386
 
  | PToken of token_extended
387
 
 
388
 
type brace_grouped = 
389
 
  | Braceised   of 
390
 
      brace_grouped list list * token_extended * token_extended option
391
 
  | BToken of token_extended
392
 
 
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
397
 
 * have a #else part.
398
 
 * 
399
 
 * x list list, because x list separated by #else or #elif 
400
 
 *) 
401
 
type ifdef_grouped = 
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
405
 
 
406
 
 
407
 
type 'a line_grouped = 
408
 
  Line of 'a list
409
 
 
410
 
 
411
 
type body_function_grouped = 
412
 
  | BodyFunction of token_extended list
413
 
  | NotBodyLine  of token_extended list
414
 
 
415
 
 
416
 
(* ------------------------------------------------------------------------- *)
417
 
(* view builders  *)
418
 
(* ------------------------------------------------------------------------- *)
419
 
 
420
 
(* todo: synchro ! use more indentation 
421
 
 * if paren not closed and same indentation level, certainly because
422
 
 * part of a mid-ifdef-expression.
423
 
*)
424
 
let rec mk_parenthised xs = 
425
 
  match xs with
426
 
  | [] -> []
427
 
  | x::xs -> 
428
 
      (match x.tok with 
429
 
      | TOPar _ | TOParDefine _ -> 
430
 
          let body, extras, xs = mk_parameters [x] [] xs in
431
 
          Parenthised (body,extras)::mk_parenthised xs
432
 
      | _ -> 
433
 
          PToken x::mk_parenthised xs
434
 
      )
435
 
 
436
 
(* return the body of the parenthised expression and the rest of the tokens *)
437
 
and mk_parameters extras acc_before_sep  xs = 
438
 
  match xs with
439
 
  | [] -> 
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, []
443
 
  | x::xs -> 
444
 
      (match x.tok with 
445
 
      (* synchro *)
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)
449
 
 
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
454
 
          mk_parameters extras 
455
 
            (Parenthised (body,extrasnest)::acc_before_sep) 
456
 
            xs
457
 
      | TComma _ -> 
458
 
          let body, extras, xs = mk_parameters (x::extras) [] xs in
459
 
          (List.rev acc_before_sep)::body, extras, xs 
460
 
      | _ -> 
461
 
          mk_parameters extras (PToken x::acc_before_sep) xs
462
 
      )
463
 
 
464
 
 
465
 
 
466
 
 
467
 
let rec mk_braceised xs = 
468
 
  match xs with
469
 
  | [] -> []
470
 
  | x::xs -> 
471
 
      (match x.tok with 
472
 
      | TOBrace _ -> 
473
 
          let body, endbrace, xs = mk_braceised_aux [] xs in
474
 
          Braceised (body, x, endbrace)::mk_braceised xs
475
 
      | TCBrace _ -> 
476
 
          pr2 "PB: found closing brace alone in fuzzy parsing";
477
 
          BToken x::mk_braceised xs
478
 
      | _ -> 
479
 
          BToken x::mk_braceised xs
480
 
      )
481
 
 
482
 
(* return the body of the parenthised expression and the rest of the tokens *)
483
 
and mk_braceised_aux acc xs = 
484
 
  match xs with
485
 
  | [] -> 
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, []
489
 
  | x::xs -> 
490
 
      (match x.tok with 
491
 
      | TCBrace _ -> [List.rev acc], Some x, xs
492
 
      | TOBrace _ -> 
493
 
          let body, endbrace, xs = mk_braceised_aux [] xs in
494
 
          mk_braceised_aux  (Braceised (body,x, endbrace)::acc) xs
495
 
      | _ -> 
496
 
          mk_braceised_aux (BToken x::acc) xs
497
 
      )
498
 
 
499
 
          
500
 
 
501
 
 
502
 
let rec mk_ifdef xs = 
503
 
  match xs with
504
 
  | [] -> []
505
 
  | x::xs -> 
506
 
      (match x.tok with 
507
 
      | TIfdef _ -> 
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
512
 
          
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
517
 
 
518
 
      | TIfdefMisc (b,_,_) | TIfdefVersion (b,_,_) -> 
519
 
          let body, extra, xs = mk_ifdef_parameters [x] [] xs in
520
 
          Ifdefbool (b, body, extra)::mk_ifdef xs
521
 
 
522
 
          
523
 
      | _ -> 
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 
527
 
      )
528
 
 
529
 
and mk_ifdef_parameters extras acc_before_sep xs = 
530
 
  match xs with
531
 
  | [] -> 
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.
536
 
       *)
537
 
      pr2 "PB: not found closing ifdef in fuzzy parsing";
538
 
      [List.rev acc_before_sep], List.rev extras, []
539
 
  | x::xs -> 
540
 
      (match x.tok with 
541
 
      | TEndif _ -> 
542
 
          [List.rev acc_before_sep], List.rev (x::extras), xs
543
 
      | TIfdef _ -> 
544
 
          let body, extrasnest, xs = mk_ifdef_parameters [x] [] xs in
545
 
          mk_ifdef_parameters 
546
 
            extras (Ifdef (body, extrasnest)::acc_before_sep) xs
547
 
 
548
 
      | TIfdefBool (b,_,_) -> 
549
 
          let body, extrasnest, xs = mk_ifdef_parameters [x] [] xs in
550
 
 
551
 
          if !Flag_parsing_c.if0_passing
552
 
          then
553
 
            mk_ifdef_parameters 
554
 
              extras (Ifdefbool (b, body, extrasnest)::acc_before_sep) xs
555
 
          else 
556
 
            mk_ifdef_parameters 
557
 
              extras (Ifdef (body, extrasnest)::acc_before_sep) xs
558
 
 
559
 
 
560
 
      | TIfdefMisc (b,_,_) | TIfdefVersion (b,_,_) -> 
561
 
          let body, extrasnest, xs = mk_ifdef_parameters [x] [] xs in
562
 
          mk_ifdef_parameters 
563
 
            extras (Ifdefbool (b, body, extrasnest)::acc_before_sep) xs
564
 
 
565
 
      | TIfdefelse _ 
566
 
      | TIfdefelif _ -> 
567
 
          let body, extras, xs = mk_ifdef_parameters (x::extras) [] xs in
568
 
          (List.rev acc_before_sep)::body, extras, xs 
569
 
      | _ -> 
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
572
 
      )
573
 
 
574
 
(* --------------------------------------- *)
575
 
 
576
 
let line_of_paren = function
577
 
  | PToken x -> x.line
578
 
  | Parenthised (xxs, info_parens) -> 
579
 
      (match info_parens with
580
 
      | [] -> raise Impossible
581
 
      | x::xs -> x.line
582
 
      )
583
 
 
584
 
 
585
 
let rec span_line_paren line = function
586
 
  | [] -> [],[]
587
 
  | x::xs -> 
588
 
      (match x with
589
 
      | PToken tok when TH.is_eof tok.tok -> 
590
 
          [], x::xs
591
 
      | _ -> 
592
 
        if line_of_paren x =|= line 
593
 
        then
594
 
          let (l1, l2) = span_line_paren line xs in
595
 
          (x::l1, l2)
596
 
        else ([], x::xs)
597
 
      )
598
 
        
599
 
 
600
 
let rec mk_line_parenthised xs = 
601
 
  match xs with
602
 
  | [] -> []
603
 
  | x::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
607
 
 
608
 
 
609
 
(* --------------------------------------- *)
610
 
let rec mk_body_function_grouped xs = 
611
 
  match xs with 
612
 
  | [] -> []
613
 
  | x::xs -> 
614
 
      (match x with
615
 
      | {tok = TOBrace _; col = 0} -> 
616
 
          let is_closing_brace = function 
617
 
            | {tok = TCBrace _; col = 0 } -> true 
618
 
            | _ -> false 
619
 
          in
620
 
          let body, xs = Common.span (fun x -> not (is_closing_brace x)) xs in
621
 
          (match xs with
622
 
          | ({tok = TCBrace _; col = 0 })::xs -> 
623
 
              BodyFunction body::mk_body_function_grouped xs
624
 
          | [] -> 
625
 
              pr2 "PB:not found closing brace in fuzzy parsing";
626
 
              [NotBodyLine body]
627
 
          | _ -> raise Impossible
628
 
          )
629
 
          
630
 
      | _ -> 
631
 
          let line, xs = Common.span (fun y -> y.line =|= x.line) (x::xs) in
632
 
          NotBodyLine line::mk_body_function_grouped xs 
633
 
      )
634
 
 
635
 
 
636
 
(* ------------------------------------------------------------------------- *)
637
 
(* view iterators  *)
638
 
(* ------------------------------------------------------------------------- *)
639
 
 
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)
646
 
  )
647
 
 
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)
654
 
  )
655
 
 
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)
663
 
  )
664
 
 
665
 
 
666
 
 
667
 
 
668
 
let tokens_of_paren xs = 
669
 
  let g = ref [] in
670
 
  xs +> iter_token_paren (fun tok -> push2 tok g);
671
 
  List.rev !g
672
 
 
673
 
 
674
 
let tokens_of_paren_ordered xs = 
675
 
  let g = ref [] in
676
 
 
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
682
 
          | opar::xs -> 
683
 
              (match List.rev xs with
684
 
              | cpar::xs -> 
685
 
                  opar, cpar, List.rev xs
686
 
              | _ -> raise Impossible
687
 
              )
688
 
          | _ -> raise Impossible
689
 
        in
690
 
        push2 opar g;
691
 
        aux_args (xxs,commas);
692
 
        push2 cpar g;
693
 
 
694
 
  and aux_args (xxs, commas) =
695
 
    match xxs, commas with
696
 
    | [], [] -> ()
697
 
    | [xs], [] -> xs +> List.iter aux_tokens_ordered
698
 
    | xs::ys::xxs, comma::commas -> 
699
 
        xs +> List.iter aux_tokens_ordered;
700
 
        push2 comma g;
701
 
        aux_args (ys::xxs, commas)
702
 
    | _ -> raise Impossible
703
 
 
704
 
  in
705
 
 
706
 
  xs +> List.iter aux_tokens_ordered;
707
 
  List.rev !g
708
 
 
709
 
 
710
 
 
711
 
 
712
 
(* ------------------------------------------------------------------------- *)
713
 
(* set the context info in token *)
714
 
(* ------------------------------------------------------------------------- *)
715
 
 
716
 
 
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.
722
 
  *)
723
 
  match xs with
724
 
  | [] -> ()
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
730
 
      ));
731
 
      set_in_function_tag xs
732
 
 
733
 
  | (BToken x)::xs -> set_in_function_tag xs
734
 
 
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
739
 
      ));
740
 
      set_in_function_tag xs
741
 
  | Braceised (body, tok1, tok2)::xs -> 
742
 
      set_in_function_tag xs
743
 
  
744
 
 
745
 
let rec set_in_other xs = 
746
 
  match xs with 
747
 
  | [] -> ()
748
 
  (* enum x { } *)
749
 
  | BToken ({tok = Tenum _})::BToken ({tok = TIdent _})
750
 
    ::Braceised(body, tok1, tok2)::xs 
751
 
  | BToken ({tok = Tenum _})
752
 
    ::Braceised(body, tok1, tok2)::xs 
753
 
    -> 
754
 
      body +> List.iter (iter_token_brace (fun tok -> 
755
 
        tok.where <- InEnum;
756
 
      ));
757
 
      set_in_other xs
758
 
 
759
 
  (* struct x { } *)
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;
764
 
      ));
765
 
      set_in_other xs
766
 
  (* = { } *)
767
 
  | BToken ({tok = TEq _})
768
 
    ::Braceised(body, tok1, tok2)::xs -> 
769
 
      body +> List.iter (iter_token_brace (fun tok -> 
770
 
        tok.where <- InInitializer;
771
 
      ));
772
 
      set_in_other xs
773
 
 
774
 
  | BToken _::xs -> set_in_other xs
775
 
 
776
 
  | Braceised(body, tok1, tok2)::xs -> 
777
 
      body +> List.iter set_in_other;
778
 
      set_in_other xs
779
 
 
780
 
      
781
 
      
782
 
 
783
 
let set_context_tag xs = 
784
 
  begin
785
 
    set_in_function_tag xs;
786
 
    set_in_other xs;
787
 
  end
788
 
  
 
266
 
789
267
 
790
268
(*****************************************************************************)
791
269
(* Helpers *)
792
270
(*****************************************************************************)
793
271
 
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
799
 
 * macro call.
800
 
 *)
801
 
let rec (cpp_engine: (string , Parser_c.token list) assoc -> 
802
 
          Parser_c.token list -> Parser_c.token list) = 
803
 
 fun env xs ->
804
 
  xs +> List.map (fun tok -> 
805
 
    match tok with
806
 
    | TIdent (s,i1) when List.mem_assoc s env -> Common.assoc s env
807
 
    | x -> [x]
808
 
  )
809
 
  +> List.flatten
810
 
 
811
 
 
812
 
 
813
 
 
814
272
(* ------------------------------------------------------------------------- *)
815
273
(* the pair is the status of '()' and '{}', ex: (-1,0) 
816
274
 * if too much ')' and good '{}' 
818
276
 * could do for ','   if encounter ',' at "toplevel", not inside () or {}
819
277
 * then if have ifdef, then certainly can lead to a problem.
820
278
 *)
821
 
let (count_open_close_stuff_ifdef_clause: ifdef_grouped list -> (int * int)) = 
 
279
let (count_open_close_stuff_ifdef_clause: TV.ifdef_grouped list -> (int * int))=
822
280
 fun xs -> 
823
281
   let cnt_paren, cnt_brace = ref 0, ref 0 in
824
 
   xs +> iter_token_ifdef (fun x -> 
 
282
   xs +> TV.iter_token_ifdef (fun x -> 
825
283
     (match x.tok with
826
284
     | x when TH.is_opar x  -> incr cnt_paren
827
285
     | TOBrace _ -> incr cnt_brace
1121
579
 
1122
580
 
1123
581
 
 
582
 
 
583
 
 
584
 
 
585
 
 
586
let rec find_ifdef_cparen_else xs = 
 
587
  let rec aux xs = 
 
588
  xs +> List.iter (function 
 
589
  | NotIfdefLine _ -> ()
 
590
  | Ifdef (xxs, info_ifdef_stmt) -> 
 
591
      (match xxs with 
 
592
      | [] -> raise Impossible
 
593
      | [first] -> ()
 
594
      | first::second::rest -> 
 
595
 
 
596
         (* found a closing ')' just after the #else *)
 
597
 
 
598
          (* Too bad ocaml does not support better list pattern matching
 
599
           * a la Prolog-III where can match the end of lists.
 
600
           *)
 
601
          let condition = 
 
602
            if List.length first = 0 then false 
 
603
            else 
 
604
              let last_line = Common.last first in
 
605
              match last_line with
 
606
              | NotIfdefLine xs -> 
 
607
                  if List.length xs = 0 then false 
 
608
                  else 
 
609
                    let last_tok = Common.last xs in
 
610
                    TH.is_cpar last_tok.tok
 
611
              | Ifdef _ | Ifdefbool _ -> false 
 
612
          in
 
613
          if condition then begin
 
614
            msg_ifdef_cparen_else();
 
615
 
 
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));
 
620
          end
 
621
              
 
622
      );
 
623
      List.iter aux xxs
 
624
        
 
625
  (* no need complex analysis for ifdefbool *)
 
626
  | Ifdefbool (_, xxs, info_ifdef_stmt) -> 
 
627
      List.iter aux xxs
 
628
  )
 
629
  in aux xs
 
630
 
 
631
 
1124
632
(* ------------------------------------------------------------------------- *)
1125
633
(* cpp-builtin part2, macro, using standard.h or other defs *)
1126
634
(* ------------------------------------------------------------------------- *)
1127
635
 
1128
 
(* Thanks to this function many stuff are not anymore hardcoded in ocaml code
1129
 
 * (but they are now hardcoded in standard.h ...)
1130
 
 *
1131
 
 * 
1132
 
 * 
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.
1136
 
 *)
1137
 
 
1138
 
let rec apply_macro_defs xs = 
1139
 
  match xs with
1140
 
  | [] -> ()
1141
 
 
1142
 
  (* old: "but could do more, could reuse same original token
1143
 
   * so that have in the Ast a Dbg, not a MACROSTATEMENT"
1144
 
   * 
1145
 
   *   | PToken ({tok = TIdent (s,i1)} as id)::xs 
1146
 
   *     when s = "MACROSTATEMENT" -> 
1147
 
   * 
1148
 
   *     msg_macro_statement_hint s;
1149
 
   *     id.tok <- TMacroStmt(TH.info_of_tok id.tok);
1150
 
   *     find_macro_paren xs
1151
 
   * 
1152
 
   *  let msg_macro_statement_hint s = 
1153
 
   *    incr Stat.nMacroHint;
1154
 
   *   ()
1155
 
   * 
1156
 
   *)
1157
 
 
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 -> 
1161
 
      
1162
 
      msg_apply_known_macro s;
1163
 
      let (s, params, body) = Hashtbl.find !_defs s in
1164
 
 
1165
 
      (match params with
1166
 
      | NoParam -> 
1167
 
          pr2 ("WEIRD: macro without param used before parenthize: " ^ s);
1168
 
          (* ex: PRINTP("NCR53C400 card%s detected\n" ANDP(((struct ... *)
1169
 
 
1170
 
          (match body with
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;
1177
 
          )
1178
 
      | Params params -> 
1179
 
          (match body with
1180
 
          | DefineBody bodymacro -> 
1181
 
 
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
1187
 
              then begin 
1188
 
                pr2_once ("WEIRD: macro with wrong number of arguments: " ^ s);
1189
 
                (* old: id.new_tokens_before <- bodymacro; *)
1190
 
                ()
1191
 
              end
1192
 
              else 
1193
 
 
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
1197
 
                  )
1198
 
                ) in
1199
 
                id.new_tokens_before <-
1200
 
                  cpp_engine (Common.zip params xxs') bodymacro;
1201
 
 
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
1205
 
                 *)
1206
 
                [Parenthised (xxs, info_parens)] +> 
1207
 
                  iter_token_paren (set_as_comment Token_c.CppMacro);
1208
 
                set_as_comment Token_c.CppMacro id;
1209
 
 
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
1214
 
                 * 
1215
 
                 * note: such macrostatement can have a variable number of
1216
 
                 * arguments but here we don't care, we just pass all the
1217
 
                 * parameters.
1218
 
                 *)
1219
 
 
1220
 
                (match xs with
1221
 
                | PToken ({tok = TPtVirg _} as id2)::_ -> 
1222
 
                    pr2_once 
1223
 
                      ("macro stmt with trailing ';', passing also ';' for: "^
1224
 
                       s);
1225
 
                    (* sometimes still want pass its params ... as in
1226
 
                     *  DEBUGPOLL(static unsigned int prev_mask = 0);
1227
 
                     *)
1228
 
 
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;
1234
 
 
1235
 
                | _ ->
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);
1240
 
                )
1241
 
                
1242
 
 
1243
 
            | DefineHint hint -> 
1244
 
                msg_apply_known_macro_hint s;
1245
 
                id.tok <- token_from_parsinghack_hint (s,i1) hint;
1246
 
            )
1247
 
      );
1248
 
      apply_macro_defs xs
1249
 
 
1250
 
  | PToken ({tok = TIdent (s,i1)} as id)::xs 
1251
 
      when Hashtbl.mem !_defs s -> 
1252
 
 
1253
 
      msg_apply_known_macro s;
1254
 
      let (_s, params, body) = Hashtbl.find !_defs s in
1255
 
 
1256
 
      (match params with
1257
 
      | Params params -> 
1258
 
          pr2 ("WEIRD: macro with params but no parens found: " ^ s);
1259
 
          (* dont apply the macro, perhaps a redefinition *)
1260
 
          ()
1261
 
      | NoParam -> 
1262
 
          (match body with
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;
1273
 
          )
1274
 
      );
1275
 
      apply_macro_defs xs
1276
 
 
1277
 
 
1278
 
 
1279
 
 
1280
 
  (* recurse *)
1281
 
  | (PToken x)::xs -> apply_macro_defs xs 
1282
 
  | (Parenthised (xxs, info_parens))::xs -> 
1283
 
      xxs +> List.iter apply_macro_defs;
1284
 
      apply_macro_defs xs
1285
 
 
1286
 
 
1287
 
 
1288
 
 
 
636
(* now in cpp_token_c.ml *) 
1289
637
 
1290
638
(* ------------------------------------------------------------------------- *)
1291
639
(* stringification *)
1338
686
      find_macro_paren xs
1339
687
 
1340
688
(*
1341
 
  (* attribute cpp, __xxx id() *)
 
689
  (* attribute cpp, __xxx id *)
1342
690
  | PToken ({tok = TIdent (s,i1)} as id)
1343
 
    ::PToken ({tok = TIdent (s2, i2)})
1344
 
    ::Parenthised(xxs,info_parens)
 
691
    ::PToken ({tok = TIdent (s2, i2)} as id2)
1345
692
    ::xs when s ==~ regexp_annot
1346
693
     -> 
1347
694
      msg_attribute s;
1348
695
      id.tok <- TMacroAttr (s, i1);
1349
 
      find_macro_paren (Parenthised(xxs,info_parens)::xs)
 
696
      find_macro_paren ((PToken id2)::xs); (* recurse also on id2 ? *)
1350
697
 
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
 
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))
1355
702
     -> 
1356
703
      msg_attribute s2;
1357
 
      id.tok <- TMacroAttr (s2, i2);
1358
 
      find_macro_paren (xs)
 
704
      id2.tok <- TMacroAttr (s2, i2);
 
705
      find_macro_paren xs
 
706
 
 
707
  | PToken ({tok = (Tstatic _ | Textern _)} as tok1)
 
708
    ::PToken ({tok = TIdent (s,i1)} as attr)
 
709
    ::xs when s ==~ regexp_annot
 
710
    -> 
 
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)
 
715
      
 
716
 
1359
717
*)
1360
718
 
1361
719
  (* storage attribute *)
1366
724
      attr.tok <- TMacroAttrStorage (s,i1);
1367
725
      (* recurse, may have other storage attributes *)
1368
726
      find_macro_paren (PToken (tok1)::xs)
1369
 
      
 
727
 
1370
728
 
1371
729
  (* stringification
1372
730
   * 
1791
1149
(* action *)
1792
1150
(* ------------------------------------------------------------------------- *)
1793
1151
 
 
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.
 
1157
 *)
 
1158
 
1794
1159
let rec find_actions = function
1795
1160
  | [] -> ()
1796
1161
 
1809
1174
and find_actions_params xxs = 
1810
1175
  xxs +> List.fold_left (fun acc xs -> 
1811
1176
    let toks = tokens_of_paren xs in
1812
 
    if toks +> List.exists (fun x -> TH.is_statement x.tok)
 
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
 
1180
       *)
1813
1181
    then begin
1814
1182
      xs +> iter_token_paren (fun x -> 
1815
1183
        if TH.is_eof x.tok
1816
1184
        then 
1817
1185
          (* certainly because paren detection had a pb because of
1818
 
           * some ifdef-exp
 
1186
           * some ifdef-exp. Do similar additional checking than
 
1187
           * what is done in set_as_comment.
1819
1188
           *)
1820
 
          pr2 "PB: weird, I try to tag an EOF token as action"
 
1189
          pr2 "PB: weird, I try to tag an EOF token as an action"
1821
1190
        else 
1822
 
          x.tok <- TAction (TH.info_of_tok x.tok);
 
1191
          (* cf tests-bis/no_cpar_macro.c *)
 
1192
          if TH.is_eom x.tok 
 
1193
          then 
 
1194
            pr2 "PB: weird, I try to tag an EOM token as an action"
 
1195
          else 
 
1196
            x.tok <- TAction (TH.info_of_tok x.tok);
1823
1197
      );
1824
1198
      true (* modified *)
1825
1199
    end
1832
1206
(* main fix cpp function *)
1833
1207
(* ------------------------------------------------------------------------- *)
1834
1208
 
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 
1840
 
  );
1841
 
  let tokens = List.rev !_tokens in
1842
 
  (tokens +> acc_map mk_token_extended)
1843
 
 
1844
1209
let filter_cpp_stuff xs = 
1845
1210
  let rec aux xs = 
1846
1211
    match xs with
1863
1228
 
1864
1229
let insert_virtual_positions l =
1865
1230
  let strlen x = String.length (Ast_c.str_of_info x) in
1866
 
  let rec loop prev offset = function
1867
 
      [] -> []
 
1231
  let rec loop prev offset acc = function
 
1232
      [] -> List.rev acc
1868
1233
    | x::xs ->
1869
1234
        let ii = TH.info_of_tok x in
1870
1235
        let inject pi =
1872
1237
        match Ast_c.pinfo_of_info ii with
1873
1238
          Ast_c.OriginTok pi ->
1874
1239
            let prev = Ast_c.parse_info_of_info ii in
1875
 
            x::(loop prev (strlen ii) xs)
 
1240
            loop prev (strlen ii) (x::acc) xs 
1876
1241
        | Ast_c.ExpandedTok (pi,_) ->
1877
 
            inject (Ast_c.ExpandedTok (pi,(prev,offset))) ::
1878
 
            (loop prev (offset + (strlen ii)) xs)
 
1242
            let x' = inject (Ast_c.ExpandedTok (pi,(prev,offset))) in
 
1243
            loop prev (offset + (strlen ii)) (x'::acc) xs 
1879
1244
        | Ast_c.FakeTok (s,_) ->
1880
 
            inject (Ast_c.FakeTok (s,(prev,offset))) ::
1881
 
            (loop prev (offset + (strlen ii)) xs)
 
1245
            let x' = inject (Ast_c.FakeTok (s,(prev,offset))) in
 
1246
            loop prev (offset + (strlen ii)) (x'::acc) xs 
1882
1247
        | Ast_c.AbstractLineTok _ -> failwith "abstract not expected" in
1883
1248
  let rec skip_fake = function
1884
 
      [] -> []
 
1249
    | [] -> []
1885
1250
    | x::xs ->
1886
1251
        let ii = TH.info_of_tok x in
1887
1252
        match Ast_c.pinfo_of_info ii with
1888
 
          Ast_c.OriginTok pi ->
 
1253
        | Ast_c.OriginTok pi ->
1889
1254
            let prev = Ast_c.parse_info_of_info ii in
1890
 
            x::(loop prev (strlen ii) xs)
 
1255
            let res = loop prev (strlen ii) [] xs  in
 
1256
            x::res
1891
1257
        | _ -> x::skip_fake xs in
1892
 
  skip_fake l
 
1258
  skip_fake l 
 
1259
 
1893
1260
 
1894
1261
(* ------------------------------------------------------------------------- *)
1895
 
let fix_tokens_cpp2 tokens = 
1896
 
  let tokens2 = ref (tokens +> acc_map mk_token_extended) in
 
1262
let fix_tokens_cpp2 ~macro_defs tokens = 
 
1263
  let tokens2 = ref (tokens +> Common.acc_map TV.mk_token_extended) in
1897
1264
  
1898
1265
  begin 
1899
1266
    (* the order is important, if you put the action heuristic first,
1916
1283
       * commentize_skip_start_to_end *)
1917
1284
      not (TH.is_comment x.tok) (* could filter also #define/#include *)
1918
1285
    ) in
1919
 
    let ifdef_grouped = mk_ifdef cleaner in
 
1286
    let ifdef_grouped = TV.mk_ifdef cleaner in
1920
1287
    set_ifdef_parenthize_info ifdef_grouped;
1921
1288
 
1922
1289
    find_ifdef_funheaders ifdef_grouped;
1923
1290
    find_ifdef_bool       ifdef_grouped;
1924
1291
    find_ifdef_mid        ifdef_grouped;
 
1292
    (* change order ? maybe cparen_else heuristic make some of the funheaders 
 
1293
     * heuristics irrelevant ?
 
1294
     *)
 
1295
    find_ifdef_cparen_else        ifdef_grouped; 
1925
1296
    adjust_inifdef_include ifdef_grouped;
1926
1297
 
1927
1298
 
1928
1299
    (* macro 1 *)
1929
1300
    let cleaner = !tokens2 +> filter_cpp_stuff in
1930
1301
 
1931
 
    let paren_grouped = mk_parenthised  cleaner in
1932
 
    apply_macro_defs paren_grouped;
 
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;
1933
1307
    (* because the before field is used by apply_macro_defs *)
1934
 
    tokens2 := rebuild_tokens_extented !tokens2; 
 
1308
    tokens2 := TV.rebuild_tokens_extented !tokens2; 
1935
1309
 
1936
1310
    (* tagging contextual info (InFunc, InStruct, etc). Better to do
1937
1311
     * that after the "ifdef-simplification" phase.
1940
1314
      not (TH.is_comment x.tok) (* could filter also #define/#include *)
1941
1315
    ) in
1942
1316
 
1943
 
    let brace_grouped = mk_braceised cleaner in
 
1317
    let brace_grouped = TV.mk_braceised cleaner in
1944
1318
    set_context_tag   brace_grouped;
1945
1319
 
1946
1320
 
1948
1322
    (* macro *)
1949
1323
    let cleaner = !tokens2 +> filter_cpp_stuff in
1950
1324
 
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;
1957
1331
 
1958
1332
 
1959
 
    (* actions *)
 
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;
1963
 
 
1964
 
 
1965
 
    insert_virtual_positions (!tokens2 +> acc_map (fun x -> x.tok))
 
1337
    
 
1338
 
 
1339
 
 
1340
    insert_virtual_positions (!tokens2 +> Common.acc_map (fun x -> x.tok))
1966
1341
  end
1967
1342
 
1968
 
let time_hack1 a = 
1969
 
  Common.profile_code_exclusif "HACK" (fun () -> fix_tokens_cpp2 a)
1970
 
 
1971
 
let fix_tokens_cpp a = 
1972
 
  Common.profile_code "C parsing.fix_cpp" (fun () -> time_hack1 a)
1973
 
 
1974
 
 
1975
 
 
1976
 
 
1977
 
(*****************************************************************************)
1978
 
(* The #define tricks *)
1979
 
(*****************************************************************************)
1980
 
 
1981
 
(* ugly hack, a better solution perhaps would be to erase TDefEOL 
1982
 
 * from the Ast and list of tokens in parse_c. 
1983
 
 * 
1984
 
 * note: I do a +1 somewhere, it's for the unparsing to correctly sync.
1985
 
 * 
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".
1993
 
 * 
1994
 
 * todo?: could put a ExpandedTok for that ? 
1995
 
 *)
1996
 
let mark_end_define ii = 
1997
 
  let ii' = 
1998
 
    { Ast_c.pinfo = Ast_c.OriginTok { (Ast_c.parse_info_of_info ii) with 
1999
 
        Common.str = ""; 
2000
 
        Common.charpos = Ast_c.pos_of_info ii + 1
2001
 
      };
2002
 
      cocci_tag = ref Ast_c.emptyAnnot;
2003
 
      comments_tag = ref Ast_c.emptyComments;
2004
 
    } 
2005
 
  in
2006
 
  TDefEOL (ii')
2007
 
 
2008
 
(* put the TDefEOL at the good place *)
2009
 
let rec define_line_1 acc xs = 
2010
 
  match xs with
2011
 
  | [] -> List.rev acc
2012
 
  | TDefine ii::xs ->
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
2021
 
 
2022
 
and define_line_2 acc line lastinfo xs = 
2023
 
  match xs with 
2024
 
  | [] -> 
2025
 
      (* should not happened, should meet EOF before *)
2026
 
      pr2 "PB: WEIRD";   
2027
 
      List.rev (mark_end_define lastinfo::acc)
2028
 
  | x::xs -> 
2029
 
      let line' = TH.line_of_tok x in
2030
 
      let info = TH.info_of_tok x in
2031
 
 
2032
 
      (match x with
2033
 
      | EOF ii -> 
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
2041
 
      | x -> 
2042
 
          if line' =|= line
2043
 
          then define_line_2 (x::acc) line info xs 
2044
 
          else define_line_1 (mark_end_define lastinfo::acc) (x::xs)
2045
 
      )
2046
 
 
2047
 
let rec define_ident acc xs = 
2048
 
  match xs with
2049
 
  | [] -> List.rev acc
2050
 
  | TDefine ii::xs -> 
2051
 
      let acc = TDefine ii :: acc in
2052
 
      (match xs with
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.
2058
 
           *)
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)
2062
 
           *)
2063
 
          let acc = (TCommentSpace i1) :: acc in
2064
 
          let acc = (TIdentDefine (s,i2)) :: acc in
2065
 
          let acc = (TOParDefine i3) :: acc in
2066
 
          define_ident acc xs
2067
 
      | TCommentSpace i1::TIdent (s,i2)::xs -> 
2068
 
          let acc = (TCommentSpace i1) :: acc in
2069
 
          let acc = (TIdentDefine (s,i2)) :: acc in
2070
 
          define_ident acc xs
2071
 
      | _ -> 
2072
 
          pr2 "WEIRD: weird #define body"; 
2073
 
          define_ident acc xs
2074
 
      )
2075
 
  | x::xs ->
2076
 
      let acc = x :: acc in
2077
 
      define_ident acc xs
2078
 
  
2079
 
 
2080
 
 
2081
 
let fix_tokens_define2 xs = 
2082
 
  define_ident [] (define_line_1 [] xs)
2083
 
 
2084
 
let fix_tokens_define a = 
2085
 
  Common.profile_code "C parsing.fix_define" (fun () -> fix_tokens_define2 a)
2086
 
      
 
1343
let time_hack1 ~macro_defs a = 
 
1344
  Common.profile_code_exclusif "HACK" (fun () -> fix_tokens_cpp2 ~macro_defs a)
 
1345
 
 
1346
let fix_tokens_cpp ~macro_defs a = 
 
1347
  Common.profile_code "C parsing.fix_cpp" (fun () -> time_hack1 ~macro_defs a)
 
1348
 
 
1349
 
2087
1350
 
2088
1351
(*****************************************************************************)
2089
1352
(* for the cpp-builtin, standard.h, part 0 *)
2090
1353
(*****************************************************************************)
2091
1354
 
2092
 
let macro_body_to_maybe_hint body = 
2093
 
  match body with
2094
 
  | [] -> DefineBody body
2095
 
  | [TIdent (s,i1)] -> 
2096
 
      (match parsinghack_hint_of_string s with
2097
 
      | Some hint -> DefineHint hint
2098
 
      | None -> DefineBody body
2099
 
      )
2100
 
  | xs -> DefineBody body
2101
 
 
2102
 
 
2103
 
let rec define_parse xs = 
2104
 
  match xs with
2105
 
  | [] -> []
2106
 
  | TDefine i1::TIdentDefine (s,i2)::TOParDefine i3::xs -> 
2107
 
      let (tokparams, _, xs) = 
2108
 
        xs +> Common.split_when (function TCPar _ -> true | _ -> false) in
2109
 
      let (body, _, xs) = 
2110
 
        xs +> Common.split_when (function TDefEOL _ -> true | _ -> false) in
2111
 
      let params = 
2112
 
        tokparams +> Common.map_filter (function
2113
 
        | TComma _ -> None
2114
 
        | TIdent (s, _) -> Some s
2115
 
        | x -> error_cant_have x
2116
 
        ) in
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
2121
 
 
2122
 
  | TDefine i1::TIdentDefine (s,i2)::xs -> 
2123
 
      let (body, _, 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
2129
 
 
2130
 
  | TDefine i1::_ -> 
2131
 
      pr2_gen i1;
2132
 
      raise Impossible
2133
 
  | x::xs -> define_parse xs 
2134
 
      
2135
 
 
2136
 
let extract_cpp_define xs = 
2137
 
  let cleaner = xs +> List.filter (fun x -> 
2138
 
    not (TH.is_comment x)
2139
 
  ) in
2140
 
  define_parse cleaner
2141
 
  
2142
 
 
2143
 
      
 
1355
(* now in cpp_token_c.ml *)
2144
1356
 
2145
1357
(*****************************************************************************)
2146
1358
(* Lexing with lookahead *)
2389
1601
      (take_safe 1 !passed_tok <> [Tenum]))
2390
1602
      &&
2391
1603
      !LP._lexer_hint = Some LP.Toplevel -> 
2392
 
      msg_typedef s; 
2393
 
      LP.add_typedef_root s;
 
1604
      msg_typedef s; LP.add_typedef_root s;
2394
1605
      TypedefIdent s
2395
1606
     *)
2396
1607
 
2531
1742
 
2532
1743
        (* can have sizeof on expression
2533
1744
           | (Tsizeof::TOPar::TIdent s::TCPar::_,   _) -> 
2534
 
           msg_typedef s; 
2535
 
           LP.add_typedef_root s;
 
1745
           msg_typedef s; LP.add_typedef_root s;
2536
1746
           Tsizeof
2537
1747
         *)
2538
1748
 
2570
1780
      *)
2571
1781
      (* not !LP._lexer_hint.toplevel *)
2572
1782
      if !Flag_parsing_c.ifdef_directive_passing
2573
 
        || (pass =|= 2)
 
1783
        || (pass >= 2)
2574
1784
      then begin
2575
1785
        
2576
1786
        if (LP.current_context () =*= LP.InInitializer)
2578
1788
          pr2_cpp "In Initializer passing"; (* cheat: dont count in stat *)
2579
1789
          incr Stat.nIfdefInitializer;
2580
1790
        end else begin 
2581
 
          pr2_cpp("IFDEF: or related insde function. I treat it as comment");
 
1791
          pr2_cpp("IFDEF: or related inside function. I treat it as comment");
2582
1792
          incr Stat.nIfdefPassing;
2583
1793
        end;
2584
1794
        TCommentCpp (Token_c.CppDirective, ii)
2587
1797
        
2588
1798
  | (TUndef (id, ii) as x)::_, _ 
2589
1799
      -> 
2590
 
        if (pass =|= 2)
 
1800
        if (pass >= 2)
2591
1801
        then begin
2592
1802
          pr2_cpp("UNDEF: I treat it as comment");
2593
1803
          TCommentCpp (Token_c.CppDirective, ii)
2596
1806
 
2597
1807
  | (TCppDirectiveOther (ii) as x)::_, _ 
2598
1808
      -> 
2599
 
        if (pass =|= 2)
 
1809
        if (pass >= 2)
2600
1810
        then begin
2601
1811
          pr2_cpp ("OTHER directive: I treat it as comment");
2602
1812
          TCommentCpp (Token_c.CppDirective, ii)