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