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

« back to all changes in this revision

Viewing changes to parsing_c/parse_c.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:
22
22
(*****************************************************************************)
23
23
(* Wrappers *)
24
24
(*****************************************************************************)
25
 
let pr2 s = 
26
 
  if !Flag_parsing_c.verbose_parsing 
27
 
  then Common.pr2 s
28
 
 
29
 
let pr2_once s = 
30
 
  if !Flag_parsing_c.verbose_parsing 
31
 
  then Common.pr2_once s
 
25
let pr2_err, pr2_once = Common.mk_pr2_wrappers Flag_parsing_c.verbose_parsing 
32
26
    
33
27
(*****************************************************************************)
34
28
(* Helpers *)
45
39
  let file = TH.file_of_tok tok in
46
40
  if !Flag_parsing_c.verbose_parsing
47
41
  then Common.error_message file (token_to_strpos tok) 
48
 
  else ("error in " ^ file  ^ "set verbose_parsing for more info")
 
42
  else ("error in " ^ file  ^ "; set verbose_parsing for more info")
49
43
 
50
44
 
51
45
let print_bad line_error (start_line, end_line) filelines  = 
204
198
 
205
199
(* called by parse_print_error_heuristic *)
206
200
let tokens2 file = 
207
 
 let table     = Common.full_charpos_to_pos file in
 
201
 let table     = Common.full_charpos_to_pos_large file in
208
202
 
209
203
 Common.with_open_infile file (fun chan -> 
210
204
  let lexbuf = Lexing.from_channel chan in
217
211
          (* could assert pinfo.filename = file ? *)
218
212
          match Ast_c.pinfo_of_info ii with
219
213
            Ast_c.OriginTok pi ->
220
 
              Ast_c.OriginTok (Common.complete_parse_info file table pi)
 
214
              Ast_c.OriginTok (Common.complete_parse_info_large file table pi)
221
215
          | Ast_c.ExpandedTok (pi,vpi) ->
222
 
              Ast_c.ExpandedTok((Common.complete_parse_info file table pi),vpi)
 
216
              Ast_c.ExpandedTok((Common.complete_parse_info_large file table pi),vpi)
223
217
          | Ast_c.FakeTok (s,vpi) -> Ast_c.FakeTok (s,vpi)
224
218
          | Ast_c.AbstractLineTok pi -> failwith "should not occur"
225
219
      })
329
323
  let lexer_function = 
330
324
    (fun _ -> 
331
325
      if TH.is_eof !cur_tok
332
 
      then (pr2 "LEXER: ALREADY AT END"; !cur_tok)
 
326
      then (pr2_err "LEXER: ALREADY AT END"; !cur_tok)
333
327
      else
334
328
        let v = Common.pop2 all_tokens in
335
329
        cur_tok := v;
397
391
  | CReservedKwd (type | decl | qualif | flow | misc | attr)
398
392
*)
399
393
 
400
 
let ident_to_typename ident =
401
 
  (Ast_c.nQ, (Ast_c.TypeName  (ident, Ast_c.noTypedefDef()), Ast_c.noii))
 
394
let ident_to_typename ident : Ast_c.fullType =
 
395
  Ast_c.mk_ty (Ast_c.TypeName  (ident, Ast_c.noTypedefDef())) Ast_c.noii
402
396
                  
403
397
 
404
398
(* parse_typedef_fix4 *)
446
440
    let xs = Common.hash_to_list v in
447
441
    if List.length xs >= 2
448
442
    then begin 
449
 
      pr2 ("CONFLICT:" ^ k);
 
443
      pr2_err ("CONFLICT:" ^ k);
450
444
      let sorted = xs +> List.sort (fun (ka,va) (kb,vb) -> 
451
445
        if !va =|= !vb then
452
446
          (match ka, kb with
459
453
      let sorted = List.rev sorted in
460
454
      match sorted with
461
455
      | [CTypedef, i1;CIdent, i2] -> 
462
 
          pr2 ("transforming some ident in typedef");
 
456
          pr2_err ("transforming some ident in typedef");
463
457
          push2 k ident_to_type;
464
458
      | _ -> 
465
 
          pr2 ("TODO:other transforming?");
 
459
          pr2_err ("TODO:other transforming?");
466
460
      
467
461
    end
468
462
  );
479
473
      Visitor_c.kdefineval_s = (fun (k,bigf) x -> 
480
474
        match x with
481
475
        | Ast_c.DefineExpr e -> 
482
 
            (match e with
483
 
            | (Ast_c.Ident (ident), _), _ii  -> 
 
476
            (match Ast_c.unwrap_expr e with
 
477
            | Ast_c.Ident (ident)  -> 
484
478
                let s = Ast_c.str_of_name ident in 
485
479
                if List.mem s !ident_to_type
486
480
                then
492
486
        | _ -> k x
493
487
      );
494
488
      Visitor_c.kexpr_s = (fun (k, bigf) x -> 
495
 
        match x with
 
489
        match Ast_c.get_e_and_ii x with
496
490
        | (Ast_c.SizeOfExpr e, tref), isizeof -> 
497
491
            let i1 = tuple_of_list1 isizeof in
498
 
            (match e with
 
492
            (match Ast_c.get_e_and_ii e with
499
493
            | (Ast_c.ParenExpr e, _), iiparen -> 
500
 
                (match e with
 
494
                let (i2, i3) = tuple_of_list2 iiparen in
 
495
                (match Ast_c.get_e_and_ii e with
501
496
                | (Ast_c.Ident (ident), _), _ii  -> 
502
497
 
503
498
                    let s = Ast_c.str_of_name ident in 
504
499
                    if List.mem s !ident_to_type
505
500
                    then
506
501
                      let t = ident_to_typename ident in
507
 
                      let (i2, i3) = tuple_of_list2 iiparen in
508
 
                      (Ast_c.SizeOfType t, tref), [i1;i2;i3]
 
502
                      (Ast_c.SizeOfType t, tref),[i1;i2;i3]
509
503
                    else  k x
510
504
                | _ -> k x
511
505
                )
528
522
(* Error recovery *)
529
523
(*****************************************************************************)
530
524
 
 
525
let is_define_passed passed =
 
526
  let xs = passed +> List.rev +> List.filter TH.is_not_comment in
 
527
  if List.length xs >= 2 
 
528
  then 
 
529
    (match Common.head_middle_tail xs with
 
530
    | Parser_c.TDefine _, _, Parser_c.TDefEOL _ -> 
 
531
        true
 
532
    | _ -> false
 
533
    )
 
534
  else begin
 
535
    pr2_err "WEIRD: length list of error recovery tokens < 2 ";
 
536
    false 
 
537
  end
 
538
 
 
539
let is_defined_passed_bis last_round = 
 
540
  let xs = last_round +> List.filter TH.is_not_comment in
 
541
  match xs with
 
542
  | Parser_c.TDefine _::_ -> true
 
543
  | _ -> false
 
544
 
 
545
(* ---------------------------------------------------------------------- *)
 
546
 
 
547
 
531
548
(* todo: do something if find Parser_c.Eof ? *)
532
549
let rec find_next_synchro next already_passed =
533
550
 
549
566
   * first { I found, so quite sure we will not loop. *)
550
567
 
551
568
  let last_round = List.rev already_passed in
552
 
  let is_define = 
553
 
    let xs = last_round +> List.filter TH.is_not_comment in
554
 
    match xs with
555
 
    | Parser_c.TDefine _::_ -> true
556
 
    | _ -> false
557
 
  in
558
 
  if is_define 
 
569
  if is_defined_passed_bis last_round 
559
570
  then find_next_synchro_define (last_round ++ next) []
560
571
  else 
561
572
 
577
588
and find_next_synchro_define next already_passed =
578
589
  match next with
579
590
  | [] ->  
580
 
      pr2 "ERROR-RECOV: end of file while in recovery mode"; 
 
591
      pr2_err "ERROR-RECOV: end of file while in recovery mode"; 
581
592
      already_passed, []
582
593
  | (Parser_c.TDefEOL i as v)::xs  -> 
583
 
      pr2 ("ERROR-RECOV: found sync end of #define, line "^i_to_s(TH.line_of_tok v));
 
594
      pr2_err ("ERROR-RECOV: found sync end of #define, line "^i_to_s(TH.line_of_tok v));
584
595
      v::already_passed, xs
585
596
  | v::xs -> 
586
597
      find_next_synchro_define xs (v::already_passed)
591
602
and find_next_synchro_orig next already_passed =
592
603
  match next with
593
604
  | [] ->  
594
 
      pr2 "ERROR-RECOV: end of file while in recovery mode"; 
 
605
      pr2_err "ERROR-RECOV: end of file while in recovery mode"; 
595
606
      already_passed, []
596
607
 
597
608
  | (Parser_c.TCBrace i as v)::xs when TH.col_of_tok v =|= 0 -> 
598
 
      pr2 ("ERROR-RECOV: found sync '}' at line "^i_to_s (TH.line_of_tok v));
 
609
      pr2_err ("ERROR-RECOV: found sync '}' at line "^i_to_s (TH.line_of_tok v));
599
610
 
600
611
      (match xs with
601
612
      | [] -> raise Impossible (* there is a EOF token normally *)
602
613
 
603
614
      (* still useful: now parser.mly allow empty ';' so normally no pb *)
604
615
      | Parser_c.TPtVirg iptvirg::xs -> 
605
 
          pr2 "ERROR-RECOV: found sync bis, eating } and ;";
 
616
          pr2_err "ERROR-RECOV: found sync bis, eating } and ;";
606
617
          (Parser_c.TPtVirg iptvirg)::v::already_passed, xs
607
618
 
608
619
      | Parser_c.TIdent x::Parser_c.TPtVirg iptvirg::xs -> 
609
 
          pr2 "ERROR-RECOV: found sync bis, eating ident, }, and ;";
 
620
          pr2_err "ERROR-RECOV: found sync bis, eating ident, }, and ;";
610
621
          (Parser_c.TPtVirg iptvirg)::(Parser_c.TIdent x)::v::already_passed, 
611
622
          xs
612
623
            
613
624
      | Parser_c.TCommentSpace sp::Parser_c.TIdent x::Parser_c.TPtVirg iptvirg
614
625
        ::xs -> 
615
 
          pr2 "ERROR-RECOV: found sync bis, eating ident, }, and ;";
 
626
          pr2_err "ERROR-RECOV: found sync bis, eating ident, }, and ;";
616
627
          (Parser_c.TCommentSpace sp)::
617
628
            (Parser_c.TPtVirg iptvirg)::
618
629
            (Parser_c.TIdent x)::
622
633
            
623
634
      | Parser_c.TCommentNewline sp::Parser_c.TIdent x::Parser_c.TPtVirg iptvirg
624
635
        ::xs -> 
625
 
          pr2 "ERROR-RECOV: found sync bis, eating ident, }, and ;";
 
636
          pr2_err "ERROR-RECOV: found sync bis, eating ident, }, and ;";
626
637
          (Parser_c.TCommentNewline sp)::
627
638
            (Parser_c.TPtVirg iptvirg)::
628
639
            (Parser_c.TIdent x)::
634
645
          v::already_passed, xs
635
646
      )
636
647
  | v::xs when TH.col_of_tok v =|= 0 && TH.is_start_of_something v  -> 
637
 
      pr2 ("ERROR-RECOV: found sync col 0 at line "^ i_to_s(TH.line_of_tok v));
 
648
      pr2_err ("ERROR-RECOV: found sync col 0 at line "^ i_to_s(TH.line_of_tok v));
638
649
      already_passed, v::xs
639
650
        
640
651
  | v::xs -> 
641
652
      find_next_synchro_orig xs (v::already_passed)
642
653
 
643
 
      
 
654
 
 
655
(*****************************************************************************)
 
656
(* Macro problem recovery *)
 
657
(*****************************************************************************)
 
658
module TV = Token_views_c
 
659
 
 
660
let candidate_macros_in_passed2 passed defs_optional = 
 
661
  let res = ref [] in
 
662
  let res2 = ref [] in
 
663
 
 
664
  passed +> List.iter (function
 
665
  | Parser_c.TIdent (s,_)
 
666
   (* bugfix: may have to undo some infered things *)
 
667
  | Parser_c.TMacroIterator (s,_)
 
668
  | Parser_c.TypedefIdent (s,_)
 
669
    -> 
 
670
      (match Common.hfind_option s defs_optional with
 
671
      | Some def -> 
 
672
          if s ==~ Parsing_hacks.regexp_macro 
 
673
          then
 
674
            (* pr2 (spf "candidate: %s" s); *)
 
675
            Common.push2 (s, def) res 
 
676
          else 
 
677
            Common.push2 (s, def) res2
 
678
        | None -> ()
 
679
        )
 
680
 
 
681
  | _ -> ()
 
682
  );
 
683
  if null !res 
 
684
  then !res2 
 
685
  else !res
 
686
 
 
687
let candidate_macros_in_passed a b = 
 
688
  Common.profile_code "MACRO managment" (fun () -> 
 
689
    candidate_macros_in_passed2 a b)
 
690
  
 
691
 
 
692
 
 
693
let find_optional_macro_to_expand2 ~defs toks =
 
694
 
 
695
  let defs = Common.hash_of_list defs in
 
696
 
 
697
  let toks = toks +> Common.map (function
 
698
 
 
699
    (* special cases to undo *)
 
700
    | Parser_c.TMacroIterator (s, ii) -> 
 
701
        if Hashtbl.mem defs s
 
702
        then Parser_c.TIdent (s, ii)
 
703
        else Parser_c.TMacroIterator (s, ii)
 
704
 
 
705
    | Parser_c.TypedefIdent (s, ii) -> 
 
706
        if Hashtbl.mem defs s
 
707
        then Parser_c.TIdent (s, ii)
 
708
        else Parser_c.TypedefIdent (s, ii)
 
709
 
 
710
    | x -> x
 
711
  ) in
 
712
 
 
713
  let tokens = toks in
 
714
  Parsing_hacks.fix_tokens_cpp ~macro_defs:defs tokens
 
715
 
 
716
  (* just calling apply_macro_defs and having a specialized version
 
717
   * of the code in fix_tokens_cpp is not enough as some work such 
 
718
   * as the passing of the body of attribute in Parsing_hacks.find_macro_paren
 
719
   * will not get the chance to be run on the new expanded tokens.
 
720
   * Hence even if it's expensive, it's currently better to 
 
721
   * just call directly fix_tokens_cpp again here.
 
722
 
 
723
  let tokens2 = ref (tokens +> Common.acc_map TV.mk_token_extended) in
 
724
  let cleaner = !tokens2 +> Parsing_hacks.filter_cpp_stuff in
 
725
  let paren_grouped = TV.mk_parenthised  cleaner in
 
726
  Cpp_token_c.apply_macro_defs
 
727
    ~msg_apply_known_macro:(fun s -> pr2 (spf "APPLYING: %s" s))
 
728
    ~msg_apply_known_macro_hint:(fun s -> pr2 "hint")
 
729
    defs paren_grouped;
 
730
  (* because the before field is used by apply_macro_defs *)
 
731
  tokens2 := TV.rebuild_tokens_extented !tokens2; 
 
732
  Parsing_hacks.insert_virtual_positions 
 
733
    (!tokens2 +> Common.acc_map (fun x -> x.TV.tok))
 
734
  *)
 
735
let find_optional_macro_to_expand ~defs a = 
 
736
    Common.profile_code "MACRO managment" (fun () -> 
 
737
      find_optional_macro_to_expand2 ~defs a)
 
738
  
 
739
 
 
740
 
644
741
(*****************************************************************************)
645
742
(* Include/Define hacks *)
646
743
(*****************************************************************************)
679
776
 
680
777
let rec comment_until_defeol xs = 
681
778
  match xs with
682
 
  | [] -> failwith "cant find end of define token TDefEOL"
 
779
  | [] -> 
 
780
      (* job not done in Cpp_token_c.define_parse ? *)
 
781
      failwith "cant find end of define token TDefEOL"
683
782
  | x::xs -> 
684
783
      (match x with
685
784
      | Parser_c.TDefEOL i -> 
716
815
(*****************************************************************************)
717
816
 
718
817
let parse_cpp_define_file2 file = 
719
 
  let toks = tokens ~profile:false file in
720
 
  let toks = Parsing_hacks.fix_tokens_define toks in
721
 
  Parsing_hacks.extract_cpp_define toks
 
818
  Common.save_excursion Flag_parsing_c.verbose_lexing (fun () -> 
 
819
    Flag_parsing_c.verbose_lexing := false;
 
820
    let toks = tokens ~profile:false file in
 
821
    let toks = Cpp_token_c.fix_tokens_define toks in
 
822
    Cpp_token_c.extract_cpp_define toks
 
823
  )
722
824
 
723
825
let parse_cpp_define_file a = 
724
826
  Common.profile_code_exclusif "HACK" (fun () -> parse_cpp_define_file2 a)
725
827
 
 
828
 
 
829
 
 
830
let (_defs : (string, Cpp_token_c.define_def) Hashtbl.t ref)  = 
 
831
  ref (Hashtbl.create 101)
 
832
 
 
833
let (_defs_builtins : (string, Cpp_token_c.define_def) Hashtbl.t ref)  = 
 
834
  ref (Hashtbl.create 101)
 
835
 
 
836
 
726
837
(* can not be put in parsing_hack, cos then mutually recursive problem as
727
838
 * we also want to parse the standard.h file.
728
839
 *)
729
 
let init_defs std_h =     
 
840
let init_defs_macros std_h =     
730
841
  if not (Common.lfile_exists std_h)
731
842
  then pr2 ("warning: Can't find default macro file: " ^ std_h)
732
843
  else begin
733
844
    pr2 ("init_defs: " ^ std_h);
734
 
    Parsing_hacks._defs := Common.hash_of_list (parse_cpp_define_file std_h);
 
845
    _defs := Common.hash_of_list (parse_cpp_define_file std_h);
 
846
  end
 
847
 
 
848
let init_defs_builtins file_h =     
 
849
  if not (Common.lfile_exists file_h)
 
850
  then pr2 ("warning: Can't find macro file: " ^ file_h)
 
851
  else begin
 
852
    pr2 ("init_defs_builtins: " ^ file_h);
 
853
    _defs_builtins := 
 
854
      Common.hash_of_list (parse_cpp_define_file file_h);
735
855
  end
736
856
 
737
857
 
804
924
  mutable passed :       Parser_c.token list;
805
925
  mutable passed_clean : Parser_c.token list;
806
926
}
807
 
let clone_tokens_stat tr = 
 
927
 
 
928
let mk_tokens_state toks = 
 
929
  { 
 
930
    rest       = toks;
 
931
    rest_clean = (toks +> List.filter TH.is_not_comment);
 
932
    current    = (List.hd toks);
 
933
    passed = []; 
 
934
    passed_clean = [];
 
935
  }
 
936
 
 
937
 
 
938
 
 
939
let clone_tokens_state tr = 
808
940
  { rest = tr.rest;
809
941
    rest_clean = tr.rest_clean;
810
942
    current = tr.current;
811
943
    passed = tr.passed;
812
944
    passed_clean = tr.passed_clean;
813
945
  }
814
 
let copy_tokens_stat ~src ~dst = 
 
946
let copy_tokens_state ~src ~dst = 
815
947
  dst.rest <- src.rest;
816
948
  dst.rest_clean <- src.rest_clean;
817
949
  dst.current <- src.current;
819
951
  dst.passed_clean <-  src.passed_clean;
820
952
  ()
821
953
 
 
954
(* todo? agglomerate the x##b ? *)
822
955
let rec filter_noise n xs =
823
956
  match n, xs with
824
957
  | _, [] -> []
845
978
 *)
846
979
let rec lexer_function ~pass tr = fun lexbuf -> 
847
980
  match tr.rest with
848
 
  | [] -> pr2 "ALREADY AT END"; tr.current
 
981
  | [] -> pr2_err "ALREADY AT END"; tr.current
849
982
  | v::xs -> 
850
983
    tr.rest <- xs;
851
984
    tr.current <- v;
873
1006
       *)
874
1007
      | Parser_c.TDefine (tok) -> 
875
1008
          if not (LP.current_context () =*= LP.InTopLevel) && 
876
 
            (!Flag_parsing_c.cpp_directive_passing || (pass =|= 2))
 
1009
            (!Flag_parsing_c.cpp_directive_passing || (pass >= 2))
877
1010
          then begin
878
1011
            incr Stat.nDefinePassing;
879
1012
            pr2_once ("CPP-DEFINE: inside function, I treat it as comment");
892
1025
            
893
1026
      | Parser_c.TInclude (includes, filename, inifdef, info) -> 
894
1027
          if not (LP.current_context () =*= LP.InTopLevel)  &&
895
 
            (!Flag_parsing_c.cpp_directive_passing || (pass =|= 2))
 
1028
            (!Flag_parsing_c.cpp_directive_passing || (pass >= 2))
896
1029
          then begin
897
1030
            incr Stat.nIncludePassing;
898
1031
            pr2_once ("CPP-INCLUDE: inside function, I treat it as comment");
945
1078
    end
946
1079
 
947
1080
 
 
1081
let max_pass = 4
 
1082
 
948
1083
 
949
1084
let get_one_elem ~pass tr (file, filelines) = 
950
1085
 
951
1086
  if not (LP.is_enabled_typedef()) && !Flag_parsing_c.debug_typedef
952
 
  then pr2 "TYPEDEF:_handle_typedef=false. Not normal if dont come from exn";
 
1087
  then pr2_err "TYPEDEF:_handle_typedef=false. Not normal if dont come from exn";
953
1088
 
954
1089
  (* normally have to do that only when come from an exception in which
955
1090
   * case the dt() may not have been done 
971
1106
      Common.profile_code_exclusif "YACC" (fun () -> 
972
1107
        Left (Parser_c.celem (lexer_function ~pass tr) lexbuf_fake)
973
1108
      )
974
 
    with e -> begin
975
 
      if (pass =|= 1 && !Flag_parsing_c.disable_two_pass)|| (pass =|= 2) 
976
 
      then begin 
977
 
        (match e with
978
 
        (* Lexical is not anymore launched I think *)
979
 
        | Lexer_c.Lexical s -> 
980
 
            pr2 ("lexical error " ^s^ "\n =" ^ error_msg_tok tr.current)
981
 
        | Parsing.Parse_error -> 
982
 
            pr2 ("parse error \n = " ^ error_msg_tok tr.current)
983
 
        | Semantic_c.Semantic (s, i) -> 
984
 
            pr2 ("semantic error " ^s^ "\n ="^ error_msg_tok tr.current)
985
 
        | e -> raise e
986
 
        )
987
 
      end;
 
1109
    with e -> 
988
1110
      LP.restore_typedef_state();
989
1111
 
990
1112
      (* must keep here, before the code that adjusts the tr fields *)
991
1113
      let line_error = TH.line_of_tok tr.current in
992
 
        
 
1114
 
 
1115
      let passed_before_error = tr.passed in
 
1116
      let current = tr.current in
993
1117
        
994
1118
      (*  error recovery, go to next synchro point *)
995
1119
      let (passed', rest') = find_next_synchro tr.rest tr.passed in
1003
1127
      
1004
1128
      
1005
1129
      let info_of_bads = Common.map_eff_rev TH.info_of_tok tr.passed in 
1006
 
      Right (info_of_bads,  line_error, tr.passed)
1007
 
    end
 
1130
      Right (info_of_bads,  line_error, 
 
1131
            tr.passed, passed_before_error, 
 
1132
            current, e)
1008
1133
  )
1009
1134
 
1010
1135
 
1032
1157
  (* -------------------------------------------------- *)
1033
1158
  LP.lexer_reset_typedef(); 
1034
1159
  Parsing_hacks.ifdef_paren_cnt := 0;
 
1160
 
1035
1161
  let toks_orig = tokens file in
1036
1162
 
1037
 
  let toks = Parsing_hacks.fix_tokens_define toks_orig in
1038
 
  let toks = Parsing_hacks.fix_tokens_cpp toks in
1039
 
 
1040
 
  let tr = { 
1041
 
    rest       = toks;
1042
 
    rest_clean = (toks +> List.filter TH.is_not_comment);
1043
 
    current    = (List.hd toks);
1044
 
    passed = []; 
1045
 
    passed_clean = [];
1046
 
  } in
1047
 
 
1048
 
 
1049
 
 
 
1163
  let toks = Cpp_token_c.fix_tokens_define toks_orig in
 
1164
 
 
1165
  let toks = Parsing_hacks.fix_tokens_cpp ~macro_defs:!_defs_builtins toks in
 
1166
 
 
1167
  (* expand macros on demand trick, preparation phase *)
 
1168
  let macros = 
 
1169
    Common.profile_code "MACRO mgmt prep 1" (fun () -> 
 
1170
      let macros = Hashtbl.copy !_defs in
 
1171
      (* include also builtins as some macros may generate some builtins too
 
1172
       * like __decl_spec or __stdcall
 
1173
       *)
 
1174
      !_defs_builtins +> Hashtbl.iter (fun s def -> 
 
1175
        Hashtbl.replace macros   s def;
 
1176
      );
 
1177
      macros
 
1178
    )
 
1179
  in
 
1180
  Common.profile_code "MACRO mgmt prep 2" (fun () -> 
 
1181
    let local_macros = parse_cpp_define_file file in
 
1182
    local_macros +> List.iter (fun (s, def) -> 
 
1183
      Hashtbl.replace macros   s def;
 
1184
    );
 
1185
  );
 
1186
 
 
1187
  let tr = mk_tokens_state toks in
1050
1188
 
1051
1189
  let rec loop tr =
1052
1190
 
1063
1201
    let checkpoint = TH.line_of_tok tr.current in
1064
1202
    let checkpoint_file = TH.file_of_tok tr.current in
1065
1203
 
1066
 
    let tr_save = clone_tokens_stat tr in
1067
 
    
1068
1204
    (* call the parser *)
1069
1205
    let elem = 
1070
 
      let pass1 = get_one_elem ~pass:1 tr (file, filelines) in
 
1206
      let pass1 = 
 
1207
        Common.profile_code "Parsing: 1st pass" (fun () -> 
 
1208
          get_one_elem ~pass:1 tr (file, filelines)
 
1209
        ) in
1071
1210
      match pass1 with
1072
1211
      | Left e -> Left e
1073
 
      | Right res -> 
1074
 
          if !Flag_parsing_c.disable_two_pass
1075
 
          then Right res
 
1212
      | Right (info,line_err, passed, passed_before_error, cur, exn) -> 
 
1213
          if !Flag_parsing_c.disable_multi_pass
 
1214
          then pass1
1076
1215
          else begin
1077
 
            pr2 "parsing pass2: try again";
1078
 
            copy_tokens_stat ~src:tr_save ~dst: tr;
1079
 
            let pass2 = get_one_elem ~pass:2 tr (file, filelines) in
1080
 
            pass2
 
1216
            Common.profile_code "Parsing: multi pass" (fun () -> 
 
1217
 
 
1218
            pr2_err "parsing pass2: try again";
 
1219
            let toks = List.rev passed ++ tr.rest in
 
1220
            let new_tr = mk_tokens_state toks in
 
1221
            copy_tokens_state ~src:new_tr ~dst:tr;
 
1222
            let passx = get_one_elem ~pass:2 tr (file, filelines) in
 
1223
 
 
1224
            (match passx with
 
1225
            | Left e -> passx
 
1226
            | Right (info,line_err,passed,passed_before_error,cur,exn) -> 
 
1227
                let candidates = 
 
1228
                  candidate_macros_in_passed passed macros 
 
1229
                in
 
1230
                if is_define_passed passed || null candidates
 
1231
                then passx
 
1232
                else begin
 
1233
                  (* todo factorize code *)
 
1234
 
 
1235
                  pr2_err "parsing pass3: try again";
 
1236
                  let toks = List.rev passed ++ tr.rest in
 
1237
                  let toks' = 
 
1238
                    find_optional_macro_to_expand ~defs:candidates toks in
 
1239
                  let new_tr = mk_tokens_state toks' in
 
1240
                  copy_tokens_state ~src:new_tr ~dst:tr;
 
1241
                  let passx = get_one_elem ~pass:3 tr (file, filelines) in
 
1242
 
 
1243
                  (match passx with
 
1244
                  | Left e -> passx
 
1245
                  | Right (info,line_err,passed,passed_before_error,cur,exn) -> 
 
1246
                      pr2_err "parsing pass4: try again";
 
1247
 
 
1248
                      let candidates = 
 
1249
                        candidate_macros_in_passed passed macros in
 
1250
 
 
1251
                      let toks = List.rev passed ++ tr.rest in
 
1252
                      let toks' = 
 
1253
                      find_optional_macro_to_expand ~defs:candidates toks in
 
1254
                      let new_tr = mk_tokens_state toks' in
 
1255
                      copy_tokens_state ~src:new_tr ~dst:tr;
 
1256
                      let passx = get_one_elem ~pass:4 tr (file, filelines) in
 
1257
                      passx
 
1258
                  )
 
1259
                 end
 
1260
            )
 
1261
            )
1081
1262
          end
1082
1263
    in
1083
1264
 
1086
1267
    let checkpoint2 = TH.line_of_tok tr.current in (* <> line_error *)
1087
1268
    let checkpoint2_file = TH.file_of_tok tr.current in
1088
1269
 
1089
 
    let was_define = 
1090
 
      (match elem with
1091
 
      | Left _ -> false
1092
 
      | Right (_, line_error, _) -> 
1093
 
          let was_define = 
1094
 
            let xs = tr.passed +> List.rev +> List.filter TH.is_not_comment in
1095
 
            if List.length xs >= 2 
1096
 
            then 
1097
 
              (match Common.head_middle_tail xs with
1098
 
              | Parser_c.TDefine _, _, Parser_c.TDefEOL _ -> 
1099
 
                  true
1100
 
              | _ -> false
1101
 
              )
1102
 
            else begin
1103
 
              pr2 "WEIRD: length list of error recovery tokens < 2 ";
1104
 
              false 
1105
 
            end
1106
 
          in
1107
 
          (if was_define && !Flag_parsing_c.filter_msg_define_error
1108
 
          then ()
1109
 
          else 
1110
 
            (* bugfix: *)
1111
 
            if (checkpoint_file =$= checkpoint2_file) && 
1112
 
                checkpoint_file =$= file
1113
 
            then print_bad line_error (checkpoint, checkpoint2) filelines
1114
 
            else pr2 "PB: bad: but on tokens not from original file"
1115
 
          );
1116
 
          was_define
1117
 
      ) in
1118
 
    
1119
 
 
1120
1270
    let diffline = 
1121
1271
      if (checkpoint_file =$= checkpoint2_file) && (checkpoint_file =$= file)
1122
1272
      then (checkpoint2 - checkpoint) 
1139
1289
      | Left e -> 
1140
1290
          stat.Stat.correct <- stat.Stat.correct + diffline;
1141
1291
          e
1142
 
      | Right (info_of_bads, line_error, toks_of_bads) -> 
 
1292
      | Right (info_of_bads, line_error, toks_of_bads, 
 
1293
              _passed_before_error, cur, exn) -> 
 
1294
 
 
1295
          let was_define = is_define_passed tr.passed in
 
1296
          
 
1297
          if was_define && !Flag_parsing_c.filter_msg_define_error
 
1298
          then ()
 
1299
          else begin
 
1300
 
 
1301
            (match exn with
 
1302
            | Lexer_c.Lexical _ 
 
1303
            | Parsing.Parse_error
 
1304
            | Semantic_c.Semantic _ -> ()
 
1305
            | e -> raise e
 
1306
            );
 
1307
 
 
1308
            if !Flag_parsing_c.show_parsing_error
 
1309
            then begin 
 
1310
              (match exn with
 
1311
              (* Lexical is not anymore launched I think *)
 
1312
              | Lexer_c.Lexical s -> 
 
1313
                  pr2 ("lexical error " ^s^ "\n =" ^ error_msg_tok cur)
 
1314
              | Parsing.Parse_error -> 
 
1315
                  pr2 ("parse error \n = " ^ error_msg_tok cur)
 
1316
              | Semantic_c.Semantic (s, i) -> 
 
1317
                  pr2 ("semantic error " ^s^ "\n ="^ error_msg_tok cur)
 
1318
              | e -> raise Impossible
 
1319
              );
 
1320
              (* bugfix: *)
 
1321
              if (checkpoint_file =$= checkpoint2_file) && 
 
1322
                checkpoint_file =$= file
 
1323
              then print_bad line_error (checkpoint, checkpoint2) filelines
 
1324
              else pr2 "PB: bad: but on tokens not from original file"
 
1325
            end;
 
1326
 
 
1327
            
 
1328
            let pbline = 
 
1329
              toks_of_bads 
 
1330
              +> Common.filter (TH.is_same_line_or_close line_error)
 
1331
              +> Common.filter TH.is_ident_like 
 
1332
            in
 
1333
            let error_info = 
 
1334
              (pbline +> List.map TH.str_of_tok), line_error
 
1335
            in
 
1336
            stat.Stat.problematic_lines <- 
 
1337
              error_info::stat.Stat.problematic_lines;
 
1338
 
 
1339
          end;
 
1340
 
1143
1341
          if was_define && !Flag_parsing_c.filter_define_error
1144
1342
          then stat.Stat.correct <- stat.Stat.correct + diffline
1145
1343
          else stat.Stat.bad     <- stat.Stat.bad     + diffline;
1146
1344
 
1147
 
          let pbline = 
1148
 
            toks_of_bads 
1149
 
            +> Common.filter (TH.is_same_line_or_close line_error)
1150
 
            +> Common.filter TH.is_ident_like 
1151
 
          in
1152
 
          let error_info = 
1153
 
            (pbline +> List.map TH.str_of_tok), line_error
1154
 
          in
1155
 
          stat.Stat.problematic_lines <- 
1156
 
            error_info::stat.Stat.problematic_lines;
1157
 
 
1158
1345
          Ast_c.NotParsedCorrectly info_of_bads
1159
1346
    in
1160
1347
 
1215
1402
(*****************************************************************************)
1216
1403
 
1217
1404
let (cstatement_of_string: string -> Ast_c.statement) = fun s ->
1218
 
  Common.write_file ("/tmp/__cocci.c") ("void main() { \n" ^ s ^ "\n}");
1219
 
  let program = parse_c_and_cpp ("/tmp/__cocci.c") +> fst in
 
1405
  let tmpfile = Common.new_temp_file "cocci_stmt_of_s" "c" in
 
1406
  Common.write_file tmpfile ("void main() { \n" ^ s ^ "\n}");
 
1407
  let program = parse_c_and_cpp tmpfile +> fst in
1220
1408
  program +> Common.find_some (fun (e,_) -> 
1221
1409
    match e with
1222
1410
    | Ast_c.Definition ({Ast_c.f_body = [Ast_c.StmtElem st]},_) -> Some st
1224
1412
  )
1225
1413
 
1226
1414
let (cexpression_of_string: string -> Ast_c.expression) = fun s ->
1227
 
  Common.write_file ("/tmp/__cocci.c") ("void main() { \n" ^ s ^ ";\n}");
1228
 
  let program = parse_c_and_cpp ("/tmp/__cocci.c") +> fst in
 
1415
  let tmpfile = Common.new_temp_file "cocci_expr_of_s" "c" in
 
1416
  Common.write_file tmpfile ("void main() { \n" ^ s ^ ";\n}");
 
1417
  let program = parse_c_and_cpp tmpfile +> fst in
1229
1418
  program +> Common.find_some (fun (e,_) -> 
1230
1419
    match e with
1231
1420
    | Ast_c.Definition ({Ast_c.f_body = compound},_) -> 
1232
1421
        (match compound with
1233
 
        | [Ast_c.StmtElem (Ast_c.ExprStatement (Some e),ii)] -> Some e
 
1422
        | [Ast_c.StmtElem st] -> 
 
1423
            (match Ast_c.unwrap_st st with
 
1424
            | Ast_c.ExprStatement (Some e) -> Some e
 
1425
            | _ -> None
 
1426
            )
1234
1427
        | _ -> None
1235
1428
        )
1236
1429
    | _ -> None