Release coccinelle-0.2.4rc5
[bpt/coccinelle.git] / parsing_c / parsing_recovery_c.ml
CommitLineData
978fd7e5 1(* Yoann Padioleau
ae4735db
C
2 *
3 * Copyright (C) 2010, University of Copenhagen DIKU and INRIA.
978fd7e5
C
4 * Copyright (C) 2006, 2007, 2008 Ecole des Mines de Nantes
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License (GPL)
8 * version 2 as published by the Free Software Foundation.
ae4735db 9 *
978fd7e5
C
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * file license.txt for more details.
14 *)
15
16open Common
17
ae4735db 18module TH = Token_helpers
978fd7e5
C
19
20(*****************************************************************************)
21(* Wrappers *)
22(*****************************************************************************)
ae4735db 23let pr2_err, pr2_once = Common.mk_pr2_wrappers Flag_parsing_c.verbose_parsing
978fd7e5
C
24
25(*****************************************************************************)
26(* Helpers *)
27(*****************************************************************************)
28
ae4735db 29let is_defined_passed_bis last_round =
978fd7e5
C
30 let xs = last_round +> List.filter TH.is_not_comment in
31 match xs with
32 | Parser_c.TDefine _::_ -> true
33 | _ -> false
34
35
36(*****************************************************************************)
37(* Skipping stuff, find next "synchronisation" point *)
38(*****************************************************************************)
39
40(* todo: do something if find Parser_c.Eof ? *)
41let rec find_next_synchro ~next ~already_passed =
42
43 (* Maybe because not enough }, because for example an ifdef contains
44 * in both branch some opening {, we later eat too much, "on deborde
45 * sur la fonction d'apres". So already_passed may be too big and
46 * looking for next synchro point starting from next may not be the
47 * best. So maybe we can find synchro point inside already_passed
48 * instead of looking in next.
ae4735db 49 *
978fd7e5 50 * But take care! must progress. We must not stay in infinite loop!
ae4735db 51 * For instance now I have as a error recovery to look for
978fd7e5
C
52 * a "start of something", corresponding to start of function,
53 * but must go beyond this start otherwise will loop.
54 * So look at premier(external_declaration2) in parser.output and
55 * pass at least those first tokens.
ae4735db 56 *
978fd7e5
C
57 * I have chosen to start search for next synchro point after the
58 * first { I found, so quite sure we will not loop. *)
59
60 let last_round = List.rev already_passed in
ae4735db 61 if is_defined_passed_bis last_round
978fd7e5 62 then find_next_synchro_define (last_round ++ next) []
ae4735db 63 else
978fd7e5 64
ae4735db
C
65 let (before, after) =
66 last_round +> Common.span (fun tok ->
978fd7e5
C
67 match tok with
68 (* by looking at TOBrace we are sure that the "start of something"
ae4735db 69 * will not arrive too early
978fd7e5
C
70 *)
71 | Parser_c.TOBrace _ -> false
72 | Parser_c.TDefine _ -> false
73 | _ -> true
ae4735db 74 )
978fd7e5
C
75 in
76 find_next_synchro_orig (after ++ next) (List.rev before)
77
ae4735db 78
978fd7e5
C
79
80and find_next_synchro_define next already_passed =
81 match next with
ae4735db
C
82 | [] ->
83 pr2_err "ERROR-RECOV: end of file while in recovery mode";
978fd7e5 84 already_passed, []
ae4735db 85 | (Parser_c.TDefEOL i as v)::xs ->
978fd7e5
C
86 pr2_err ("ERROR-RECOV: found sync end of #define, line "^i_to_s(TH.line_of_tok v));
87 v::already_passed, xs
ae4735db 88 | v::xs ->
978fd7e5
C
89 find_next_synchro_define xs (v::already_passed)
90
91
ae4735db 92
978fd7e5
C
93
94and find_next_synchro_orig next already_passed =
95 match next with
ae4735db
C
96 | [] ->
97 pr2_err "ERROR-RECOV: end of file while in recovery mode";
978fd7e5
C
98 already_passed, []
99
ae4735db 100 | (Parser_c.TCBrace i as v)::xs when TH.col_of_tok v =|= 0 ->
978fd7e5
C
101 pr2_err ("ERROR-RECOV: found sync '}' at line "^i_to_s (TH.line_of_tok v));
102
103 (match xs with
104 | [] -> raise Impossible (* there is a EOF token normally *)
105
106 (* still useful: now parser.mly allow empty ';' so normally no pb *)
ae4735db 107 | Parser_c.TPtVirg iptvirg::xs ->
978fd7e5
C
108 pr2_err "ERROR-RECOV: found sync bis, eating } and ;";
109 (Parser_c.TPtVirg iptvirg)::v::already_passed, xs
110
ae4735db 111 | Parser_c.TIdent x::Parser_c.TPtVirg iptvirg::xs ->
978fd7e5 112 pr2_err "ERROR-RECOV: found sync bis, eating ident, }, and ;";
ae4735db 113 (Parser_c.TPtVirg iptvirg)::(Parser_c.TIdent x)::v::already_passed,
978fd7e5 114 xs
ae4735db 115
978fd7e5 116 | Parser_c.TCommentSpace sp::Parser_c.TIdent x::Parser_c.TPtVirg iptvirg
ae4735db 117 ::xs ->
978fd7e5 118 pr2_err "ERROR-RECOV: found sync bis, eating ident, }, and ;";
5626f154
C
119 (Parser_c.TPtVirg iptvirg)::
120 (Parser_c.TIdent x)::
978fd7e5 121 (Parser_c.TCommentSpace sp)::
978fd7e5 122 v::
ae4735db 123 already_passed,
978fd7e5 124 xs
ae4735db 125
978fd7e5 126 | Parser_c.TCommentNewline sp::Parser_c.TIdent x::Parser_c.TPtVirg iptvirg
ae4735db 127 ::xs ->
978fd7e5 128 pr2_err "ERROR-RECOV: found sync bis, eating ident, }, and ;";
5626f154
C
129 (Parser_c.TPtVirg iptvirg)::
130 (Parser_c.TIdent x)::
978fd7e5 131 (Parser_c.TCommentNewline sp)::
978fd7e5 132 v::
ae4735db 133 already_passed,
978fd7e5 134 xs
ae4735db
C
135
136 | _ ->
978fd7e5
C
137 v::already_passed, xs
138 )
ae4735db 139 | v::xs when TH.col_of_tok v =|= 0 && TH.is_start_of_something v ->
978fd7e5
C
140 pr2_err ("ERROR-RECOV: found sync col 0 at line "^ i_to_s(TH.line_of_tok v));
141 already_passed, v::xs
ae4735db
C
142
143 | v::xs ->
978fd7e5 144 find_next_synchro_orig xs (v::already_passed)