Commit | Line | Data |
---|---|---|
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 | ||
15 | open Common | |
16 | ||
17 | module TH = Token_helpers | |
18 | ||
19 | (*****************************************************************************) | |
20 | (* Wrappers *) | |
21 | (*****************************************************************************) | |
22 | let pr2_err, pr2_once = Common.mk_pr2_wrappers Flag_parsing_c.verbose_parsing | |
23 | ||
24 | (*****************************************************************************) | |
25 | (* Helpers *) | |
26 | (*****************************************************************************) | |
27 | ||
28 | let 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 ? *) | |
40 | let 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 | ||
79 | and 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 | ||
93 | and 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) |