1 |
#header << |
2 |
#include "config.h" |
3 |
|
4 |
#include <cmath> |
5 |
#include <list> |
6 |
|
7 |
#include "lsys.h" |
8 |
#include "util.h" |
9 |
|
10 |
#define PURIFY(a,b) |
11 |
|
12 |
void parse_file (FILE *file, const string &path, lsys &l) t_err; |
13 |
void parse_file (const string &path, lsys &l) t_err; |
14 |
|
15 |
extern list<string> include_dirs; |
16 |
>> |
17 |
|
18 |
<< |
19 |
#include <sstream> |
20 |
#include <cstdio> |
21 |
|
22 |
#include "DLGLexer.h" |
23 |
|
24 |
list<string> include_dirs; |
25 |
|
26 |
void parse_file (FILE *file, const string &path, lsys &l) t_err |
27 |
{ |
28 |
DLGFileInput in (file); |
29 |
DLGLexer scanner (&in); |
30 |
ANTLRTokenBuffer pipe (&scanner); |
31 |
ANTLRCommonToken token; |
32 |
scanner.setToken (&token); |
33 |
Parser parser (&pipe); |
34 |
parser.init (); |
35 |
|
36 |
parser.current_file = path; |
37 |
parser.parse_file (l); |
38 |
} |
39 |
|
40 |
void parse_file (const string &path, lsys &l) t_err |
41 |
{ |
42 |
string ipath(path); |
43 |
list<string>::const_iterator i = include_dirs.begin (); |
44 |
FILE *f; |
45 |
|
46 |
while (!(f = fopen (ipath.c_str (), "r"))) |
47 |
{ |
48 |
ipath += ".l"; |
49 |
if ((f = fopen (ipath.c_str (), "r"))) |
50 |
break; |
51 |
|
52 |
if (i == include_dirs.end ()) |
53 |
throw error ("unable to find or open file '" + path + "'"); |
54 |
|
55 |
ipath = *i + "/" + path; |
56 |
i++; |
57 |
} |
58 |
|
59 |
struct filebuf |
60 |
{ |
61 |
FILE *f; |
62 |
filebuf (FILE * file) : f (file) {}; |
63 |
~filebuf () { fclose (f); }; |
64 |
} auto_close(f); |
65 |
|
66 |
parse_file (f, ipath, l); |
67 |
} |
68 |
>> |
69 |
|
70 |
#lexclass COMMENT |
71 |
|
72 |
#token "\n" << skip(); newline(); set_endcol(0); >> |
73 |
#token "\*/" << mode(START); skip(); >> |
74 |
#token "~[]" << skip(); >> |
75 |
|
76 |
#lexclass QW_STRING |
77 |
|
78 |
#token Name "\"" << replchar('\0'); mode(START); >> |
79 |
#token "\\\"" << replchar('\"'); more(); >> |
80 |
#token "~[]" << more(); >> |
81 |
|
82 |
#lexclass START |
83 |
|
84 |
#token "/\*" << mode(COMMENT); skip(); >> |
85 |
#token "\"" << skip(); mode(QW_STRING); >> |
86 |
|
87 |
#token "//~[\n]*" << skip(); >> |
88 |
#token "#~[\n]*" << skip(); >> |
89 |
#token "\n" << skip(); newline(); set_endcol(0); >> |
90 |
#token "[\ ]+" << skip(); >> |
91 |
#token "\t" << skip(); _endcol = ((_endcol-1) & ~7) + 8; >> |
92 |
|
93 |
#token Name "[a-zA-Z][a-z0-9_]*" |
94 |
#token Number "[0-9]+{\.[0-9]+}" |
95 |
|
96 |
class Parser { |
97 |
<< |
98 |
public: |
99 |
string current_file; |
100 |
protected: |
101 |
void syn(_ANTLRTokenPtr tok, ANTLRChar *egroup, SetWordType *eset, |
102 |
ANTLRTokenType etok, int k); |
103 |
|
104 |
bool istok (_ANTLRTokenPtr tok, const char *s) |
105 |
{ return strcmp (tok->getText(), s) == 0; }; |
106 |
|
107 |
file_pos here () |
108 |
{ return file_pos (current_file, LT(1)->getLine (), -1); }; |
109 |
>> |
110 |
|
111 |
#lexclass START |
112 |
|
113 |
parse_file[lsys &l] |
114 |
: parse_lsys[l] "@" |
115 |
; |
116 |
|
117 |
parse_lsys[lsys &l] |
118 |
: ( statement[$l] )+ | |
119 |
; |
120 |
|
121 |
statement[lsys &l] |
122 |
: << string s; lsys *m = 0; /* calm down gcc */ >> |
123 |
<< istok(LT(1), "include") >>? . |
124 |
( |
125 |
qw_str:Name |
126 |
<< |
127 |
::parse_file ($qw_str->getText(), l); |
128 |
>> |
129 |
| |
130 |
"\(" br_str:Name "\)" |
131 |
<< |
132 |
m = new lsys; |
133 |
::parse_file ($br_str->getText (), *m); |
134 |
l.add_lsys (m); |
135 |
>> |
136 |
) |
137 |
| << istok(LT(1), "ruleset") >>? . |
138 |
{ module_name>[s] } |
139 |
"\(" |
140 |
<< m = new lsys; >> |
141 |
parse_lsys[*m] |
142 |
<< l.add_lsys (m); >> |
143 |
"\)" |
144 |
| << istok(LT(1), "define") >>? . |
145 |
module_name>[s] expr_any[$l.defines[s]] ";" |
146 |
| << istok(LT(1), "ignore") >>? . |
147 |
( module_ref>[s] << $l.ignore_module.insert (s); >> )+ ";" |
148 |
| << !istok(LT(1), ")") >>? /* why is this predicate necessary? */ |
149 |
parse_rule[$l] |
150 |
; |
151 |
|
152 |
parse_rule[lsys &l] |
153 |
: << rule r; |
154 |
r.constraint = module (1); r.iterations.is_expr = 1; |
155 |
r.iterations = module (0); r.iterations.is_expr = 1; |
156 |
>> |
157 |
parse_modvec[r.pre] |
158 |
( "\<" parse_module[*(module *)&r] |
159 |
| << |
160 |
if (r.pre.size () == 0) |
161 |
throw error ("symbol to be replaced must be a single module, not an empty sequence", LT(1)->getLine ()); |
162 |
else if (r.pre.size () != 1) |
163 |
throw error ("symbol to be replaced must be a single module, not more", r.pre.first ()); |
164 |
else |
165 |
{ |
166 |
*(module *)&r = r.pre.first (); |
167 |
r.pre.erase (); |
168 |
} |
169 |
>> |
170 |
) |
171 |
{ "\>" parse_modvec[r.post] } |
172 |
{ ":" expr_numeric[r.constraint] } |
173 |
"=>" ( parse_modvec[r.repl] | /* empty */ ) |
174 |
{ "," expr_numeric[r.iterations] } |
175 |
";" |
176 |
<< $l.add_rule(r); >> |
177 |
; |
178 |
|
179 |
parse_modvec[module_vec &v] |
180 |
: << module m; >> |
181 |
( parse_module[m] << $v.push_back (m); >> )+ |
182 |
; |
183 |
|
184 |
parse_module[module &m] |
185 |
: << module v; |
186 |
m.erase (); |
187 |
>> |
188 |
module_head[$m] { |
189 |
"\(" |
190 |
expr_any[v] << $m.push_back (v); v.erase (); >> |
191 |
( "," expr_any[v] << $m.push_back (v); v.erase (); >> )* |
192 |
"\)" |
193 |
} |
194 |
; |
195 |
|
196 |
module_head[module &m] |
197 |
: n:Number << $m = module (atof ($n->getText ())); $m.where = here (); >> |
198 |
| module_ref>[$m.str] << $m.is_num = 0; $m.where = here (); >> |
199 |
; |
200 |
|
201 |
module_name>[string s] |
202 |
: a:Name << $s = $a->getText(); >> |
203 |
; |
204 |
|
205 |
module_ref>[string s] |
206 |
: module_name>[$s] |
207 |
| "\\" << $s = "\\"; >> |
208 |
| "\+" << $s = "+"; >> |
209 |
| "\-" << $s = "-"; >> |
210 |
| "\*" << $s = "*"; >> |
211 |
| "\/" << $s = "/"; >> |
212 |
| "\^" << $s = "^"; >> |
213 |
| "\{" << $s = "{"; >> |
214 |
| "\}" << $s = "}"; >> |
215 |
| "\." << $s = "."; >> |
216 |
| "\|" << $s = "|"; >> |
217 |
| "\~" << $s = "~"; >> |
218 |
| "\[" << $s = "["; >> |
219 |
| "\]" << $s = "]"; >> |
220 |
| "\!" << $s = "!"; >> |
221 |
| "\&" << $s = "&"; >> |
222 |
| "\%" << $s = "%"; >> |
223 |
; |
224 |
|
225 |
expr_any[module &v] |
226 |
: expr_numeric[$v] |
227 |
| expr_modvec[$v] |
228 |
; |
229 |
|
230 |
expr_modvec[module &v] |
231 |
: "\"" parse_modvec[$v] << $v.str.erase (); $v.is_expr = 0; >> "\"" |
232 |
| "\'" parse_modvec[$v] << $v.str.erase (); $v.is_expr = 0; >> |
233 |
; |
234 |
|
235 |
expr_numeric[module &v] |
236 |
: expr_0[$v] << $v.is_expr = 1; >> |
237 |
; |
238 |
|
239 |
expr_0[module &v] |
240 |
: << module r; >> |
241 |
expr_1[$v] ( "\&\&" expr_2[r] << $v = module ("&&", $v, r); >> |
242 |
| "\|\|" expr_2[r] << $v = module ("||", $v, r); >> |
243 |
)* |
244 |
| "\!" expr_1[r] << $v = module ("!", r); >> |
245 |
; |
246 |
|
247 |
expr_1[module &v] |
248 |
: << module r; >> |
249 |
expr_2[$v] { "\>" expr_2[r] << $v = module (">" , $v, r); >> |
250 |
| ">=" expr_2[r] << $v = module (">=", $v, r); >> |
251 |
| "==" expr_2[r] << $v = module ("==", $v, r); >> |
252 |
| "=" expr_2[r] << $v = module ("==", $v, r); >> |
253 |
| "!=" expr_2[r] << $v = module ("!=", $v, r); >> |
254 |
| "\<" expr_2[r] << $v = module ("<" , $v, r); >> |
255 |
| "<=" expr_2[r] << $v = module ("<=", $v, r); >> |
256 |
} |
257 |
; |
258 |
|
259 |
expr_2[module &v] |
260 |
: << module r; >> |
261 |
<< $v = module (0); >> |
262 |
{expr_3[$v]} ( "\+" expr_3[r] << $v = module ("+", $v, r); >> |
263 |
| "\-" expr_3[r] << $v = module ("-", $v, r); >> |
264 |
)* |
265 |
; |
266 |
|
267 |
expr_3[module &v] |
268 |
: << module r; >> |
269 |
expr_4[$v] ( "\*" expr_4[r] << $v = module ("*", $v, r); >> |
270 |
| "\/" expr_4[r] << $v = module ("/", $v, r); >> |
271 |
| "\%" expr_4[r] << $v = module ("%", $v ,r); >> |
272 |
)* |
273 |
; |
274 |
|
275 |
expr_4[module &v] |
276 |
: << module r; >> |
277 |
expr_5[$v] ( "\^" expr_5[r] << $v = module ("^", $v, r); >> |
278 |
)* |
279 |
; |
280 |
|
281 |
expr_5[module &v] |
282 |
: "\(" expr_0[$v] << $v.where = here (); >> "\)" |
283 |
| expr_atom[$v] |
284 |
; |
285 |
|
286 |
expr_atom[module &v] |
287 |
: num:Number << $v = module (atof ($num->getText ())); $v.where = here (); >> |
288 |
| expr_module[$v] |
289 |
; |
290 |
|
291 |
expr_module[module &m] |
292 |
: << module v; |
293 |
m.erase (); |
294 |
m.where = here (); |
295 |
>> |
296 |
module_name>[$m.str] { |
297 |
"\(" |
298 |
expr_any[v] << $m.push_back (v); v.erase (); >> |
299 |
( "," expr_any[v] << $m.push_back (v); v.erase (); >> )* |
300 |
"\)" |
301 |
} |
302 |
; |
303 |
|
304 |
} |
305 |
|
306 |
<< |
307 |
void Parser::syn (_ANTLRTokenPtr tok, ANTLRChar * egroup, SetWordType * eset, |
308 |
ANTLRTokenType etok, int k) |
309 |
{ |
310 |
ostringstream msg; |
311 |
|
312 |
syntaxErrCount++; |
313 |
|
314 |
msg << current_file << ":" << LT (1)->getLine () << ": syntax error at \"" << LT (1)->getText (); |
315 |
|
316 |
if (etok || eset) |
317 |
{ |
318 |
if (k == 1) |
319 |
msg << " missing"; |
320 |
else |
321 |
{ |
322 |
msg << "; \"" << LT (1)->getText () << "\" not"; |
323 |
if (set_deg (eset) > 1) |
324 |
msg << " in"; |
325 |
} |
326 |
|
327 |
if (set_deg (eset) > 0) |
328 |
{ |
329 |
SetWordType *p = eset; |
330 |
SetWordType *endp = &(p[bsetsize]); |
331 |
unsigned e = 0; |
332 |
|
333 |
if (set_deg (eset) > 1) |
334 |
msg << " {"; |
335 |
do |
336 |
{ |
337 |
register SetWordType t = *p; |
338 |
register SetWordType *b = &(bitmask[0]); |
339 |
do |
340 |
{ |
341 |
if (t & *b) |
342 |
msg << " " << token_tbl[e]; |
343 |
e++; |
344 |
} |
345 |
while (++b < &(bitmask[sizeof (SetWordType) * 8])); |
346 |
} |
347 |
while (++p < endp); |
348 |
if (set_deg (eset) > 1) |
349 |
msg << " }"; |
350 |
} |
351 |
else |
352 |
msg << " " << token_tbl[etok]; |
353 |
|
354 |
if (strlen (egroup) > 0) |
355 |
msg << " in " << egroup; |
356 |
|
357 |
msg << endl; |
358 |
throw error (msg.str ()); |
359 |
} |
360 |
} |
361 |
>> |
362 |
|
363 |
|
364 |
|
365 |
|
366 |
|