File: parsing_recovery_c.ml

package info (click to toggle)
coccinelle 1.0.8.deb-5
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, sid
  • size: 26,148 kB
  • sloc: ml: 136,392; ansic: 23,594; sh: 2,189; makefile: 2,157; perl: 1,576; lisp: 840; python: 823; awk: 70; csh: 12
file content (147 lines) | stat: -rw-r--r-- 5,258 bytes parent folder | download
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
143
144
145
146
147
(* Yoann Padioleau
 *
 * Copyright (C) 2010, University of Copenhagen DIKU and INRIA.
 * 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 TH = Token_helpers

(*****************************************************************************)
(* Wrappers *)
(*****************************************************************************)
let pr2_err, pr2_once = Common.mk_pr2_wrappers Flag_parsing_c.verbose_parsing

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

let is_defined_passed_bis last_round =
  let xs = last_round +> List.filter TH.is_not_comment in
  match xs with
  | Parser_c.TDefine _::_ -> true
  | _ -> false


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

(* todo: do something if find Parser_c.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
  if is_defined_passed_bis last_round
  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
       *)
      | Parser_c.TOBrace _ -> false
      | Parser_c.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 "ERROR-RECOV: end of file while in recovery mode";
      already_passed, []
  | (Parser_c.TDefEOL i as v)::xs  ->
      pr2_err ("ERROR-RECOV: found sync end of #define, line "^
	       string_of_int(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 "ERROR-RECOV: end of file while in recovery mode";
      already_passed, []

  | (Parser_c.TCBrace i as v)::xs
    when TH.col_of_tok v = 0 && Ast_c.is_origintok i (*skip } in macro*) ->
      pr2_err ("ERROR-RECOV: found sync '}' at line "^
	       string_of_int (TH.line_of_tok v));

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

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

      | Parser_c.TIdent x::Parser_c.TPtVirg iptvirg::xs ->
          pr2_err "ERROR-RECOV: found sync bis, eating ident, }, and ;";
          (Parser_c.TPtVirg iptvirg)::(Parser_c.TIdent x)::v::already_passed,
          xs

      | Parser_c.TCommentSpace sp::Parser_c.TIdent x::Parser_c.TPtVirg iptvirg
        ::xs ->
          pr2_err "ERROR-RECOV: found sync bis, eating ident, }, and ;";
          (Parser_c.TPtVirg iptvirg)::
          (Parser_c.TIdent x)::
          (Parser_c.TCommentSpace sp)::
            v::
            already_passed,
          xs

      | Parser_c.TCommentNewline sp::Parser_c.TIdent x::Parser_c.TPtVirg iptvirg
        ::xs ->
          pr2_err "ERROR-RECOV: found sync bis, eating ident, }, and ;";
          (Parser_c.TPtVirg iptvirg)::
          (Parser_c.TIdent x)::
          (Parser_c.TCommentNewline sp)::
            v::
            already_passed,
          xs

      | _ ->
          v::already_passed, xs
      )
  | v::xs when TH.col_of_tok v = 0 && TH.is_start_of_something v  ->
      pr2_err ("ERROR-RECOV: found sync col 0 at line "^ string_of_int(TH.line_of_tok v));
      already_passed, v::xs

  | v::xs ->
      find_next_synchro_orig xs (v::already_passed)