package pfff

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file parsing_recovery_cpp.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
(* Yoann Padioleau
 * 
 * Copyright (C) 2011 Facebook
 * Copyright (C) 2006, 2007, 2008 Ecole des Mines de Nantes
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License (GPL)
 * version 2 as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * file license.txt for more details.
 *)
open Common

module Flag = Flag_parsing
module PI = Parse_info

module T = Parser_cpp
module TH = Token_helpers_cpp

(*****************************************************************************)
(* Wrappers *)
(*****************************************************************************)
let pr2_err, _pr2_once = Common2.mk_pr2_wrappers Flag.verbose_parsing 

let pr2_err s = pr2_err ("ERROR_RECOV: " ^s)

(*****************************************************************************)
(* Helpers *)
(*****************************************************************************)

(*****************************************************************************)
(* Skipping stuff, find next "synchronisation" point *)
(*****************************************************************************)

(* todo: do something if find T.Eof ? *)
let rec find_next_synchro ~next ~already_passed =

  (* Maybe because not enough }, because for example an ifdef contains
   * in both branch some opening {, we later eat too much, "on deborde
   * sur la fonction d'apres". So already_passed may be too big and
   * looking for next synchro point starting from next may not be the
   * best. So maybe we can find synchro point inside already_passed
   * instead of looking in next.
   * 
   * But take care! must progress. We must not stay in infinite loop!
   * For instance now I have as a error recovery to look for 
   * a "start of something", corresponding to start of function,
   * but must go beyond this start otherwise will loop.
   * So look at premier(external_declaration2) in parser.output and
   * pass at least those first tokens.
   * 
   * I have chosen to start search for next synchro point after the
   * first { I found, so quite sure we will not loop. *)

  let last_round = List.rev already_passed in
  let is_define = 
    let xs = last_round +> List.filter TH.is_not_comment in
    match xs with
    | T.TDefine _::_ -> true
    | _ -> false
  in
  if is_define 
  then find_next_synchro_define (last_round @ next) []
  else 

  let (before, after) = 
    last_round +> Common.span (fun tok -> 
      match tok with
      (* by looking at TOBrace we are sure that the "start of something"
       * will not arrive too early 
       *)
      | T.TOBrace _ -> false
      | T.TDefine _ -> false
      | _ -> true
    ) 
  in
  find_next_synchro_orig (after @ next)  (List.rev before)

    

and find_next_synchro_define next already_passed =
  match next with
  | [] ->  
      pr2_err "end of file while in recovery mode";
      already_passed, []
  | (T.TCommentNewline_DefineEndOfMacro _ as v)::xs  -> 
      pr2_err (spf "found sync end of #define  at line %d" (TH.line_of_tok v));
      v::already_passed, xs
  | v::xs -> 
      find_next_synchro_define xs (v::already_passed)


    

and find_next_synchro_orig next already_passed =
  match next with
  | [] ->  
      pr2_err "end of file while in recovery mode"; 
      already_passed, []

  | (T.TCBrace i as v)::xs when PI.col_of_info i = 0 -> 
      pr2_err (spf "found sync '}' at line %d" (PI.line_of_info i));

      (match xs with
      | [] -> raise Impossible (* there is a EOF token normally *)

      (* still useful: now parser.mly allow empty ';' so normally no pb *)
      | T.TPtVirg iptvirg::xs -> 
          pr2_err "found sync bis, eating } and ;";
          (T.TPtVirg iptvirg)::v::already_passed, xs

      | T.TIdent x::T.TPtVirg iptvirg::xs -> 
          pr2_err "found sync bis, eating ident, }, and ;";
          (T.TPtVirg iptvirg)::(T.TIdent x)::v::already_passed, 
          xs
            
      | T.TCommentSpace sp::T.TIdent x::T.TPtVirg iptvirg
        ::xs -> 
          pr2_err "found sync bis, eating ident, }, and ;";
          (T.TCommentSpace sp)::
            (T.TPtVirg iptvirg)::
            (T.TIdent x)::
            v::
            already_passed, 
          xs
            
      | _ -> 
          v::already_passed, xs
      )
  | v::xs ->
      let info = TH.info_of_tok v in
      if PI.col_of_info info = 0 && TH.is_start_of_something v 
      then begin
        pr2_err (spf "found sync col 0 at line %d " (PI.line_of_info info));
        already_passed, v::xs
      end
      else find_next_synchro_orig xs (v::already_passed)
      

OCaml

Innovation. Community. Security.