Mercurial > ~dholland > hg > tradcpp > index.cgi
annotate directive.c @ 58:0cd5a1d55ed6
rename joerg's tests to not conflict.
author | David A. Holland |
---|---|
date | Sun, 31 Mar 2013 01:13:03 -0400 |
parents | 337110e7240a |
children | 8a204d153398 |
rev | line source |
---|---|
30 | 1 /*- |
2 * Copyright (c) 2010 The NetBSD Foundation, Inc. | |
3 * All rights reserved. | |
4 * | |
5 * This code is derived from software contributed to The NetBSD Foundation | |
6 * by David A. Holland. | |
7 * | |
8 * Redistribution and use in source and binary forms, with or without | |
9 * modification, are permitted provided that the following conditions | |
10 * are met: | |
11 * 1. Redistributions of source code must retain the above copyright | |
12 * notice, this list of conditions and the following disclaimer. | |
13 * 2. Redistributions in binary form must reproduce the above copyright | |
14 * notice, this list of conditions and the following disclaimer in the | |
15 * documentation and/or other materials provided with the distribution. | |
16 * | |
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
27 * POSSIBILITY OF SUCH DAMAGE. | |
28 */ | |
29 | |
15 | 30 #include <assert.h> |
31 #include <stdbool.h> | |
32 #include <stdlib.h> | |
33 #include <string.h> | |
34 | |
35 #include "utils.h" | |
36 #include "mode.h" | |
37 #include "place.h" | |
38 #include "files.h" | |
39 #include "directive.h" | |
40 #include "macro.h" | |
41 #include "eval.h" | |
42 | |
43 struct ifstate { | |
44 struct ifstate *prev; | |
45 struct place startplace; | |
46 bool curtrue; | |
47 bool evertrue; | |
48 bool seenelse; | |
49 }; | |
50 | |
51 static struct ifstate *ifstate; | |
52 | |
53 //////////////////////////////////////////////////////////// | |
54 // common parsing bits | |
55 | |
56 static | |
57 void | |
58 oneword(const char *what, struct place *p2, char *line) | |
59 { | |
60 size_t pos; | |
61 | |
62 pos = strcspn(line, ws); | |
63 if (line[pos] != '\0') { | |
64 p2->column += pos; | |
65 complain(p2, "Garbage after %s argument", what); | |
66 complain_fail(); | |
67 line[pos] = '\0'; | |
68 } | |
69 } | |
70 | |
71 //////////////////////////////////////////////////////////// | |
72 // if handling | |
73 | |
74 static | |
75 struct ifstate * | |
76 ifstate_create(struct ifstate *prev, struct place *p, bool startstate) | |
77 { | |
78 struct ifstate *is; | |
79 | |
80 is = domalloc(sizeof(*is)); | |
81 is->prev = prev; | |
82 if (p != NULL) { | |
83 is->startplace = *p; | |
84 } else { | |
85 place_setbuiltin(&is->startplace, 1); | |
86 } | |
87 is->curtrue = startstate; | |
88 is->evertrue = is->curtrue; | |
89 is->seenelse = false; | |
90 return is; | |
91 } | |
92 | |
93 static | |
94 void | |
95 ifstate_destroy(struct ifstate *is) | |
96 { | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
97 dofree(is, sizeof(*is)); |
15 | 98 } |
99 | |
100 static | |
101 void | |
102 ifstate_push(struct place *p, bool startstate) | |
103 { | |
104 ifstate = ifstate_create(ifstate, p, startstate); | |
105 } | |
106 | |
107 static | |
108 void | |
109 ifstate_pop(void) | |
110 { | |
111 struct ifstate *is; | |
112 | |
113 is = ifstate; | |
114 ifstate = ifstate->prev; | |
115 ifstate_destroy(is); | |
116 } | |
117 | |
118 static | |
119 void | |
120 d_if(struct place *p, struct place *p2, char *line, size_t len) | |
121 { | |
122 char *expr; | |
123 bool val; | |
16 | 124 struct place p3 = *p2; |
15 | 125 |
126 expr = macroexpand(p2, line, len, true); | |
16 | 127 val = eval(&p3, expr); |
15 | 128 ifstate_push(p, val); |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
129 dostrfree(expr); |
15 | 130 } |
131 | |
132 static | |
133 void | |
134 d_ifdef(struct place *p, struct place *p2, char *line, size_t len) | |
135 { | |
136 oneword("#ifdef", p2, line); | |
137 ifstate_push(p, macro_isdefined(line)); | |
138 } | |
139 | |
140 static | |
141 void | |
142 d_ifndef(struct place *p, struct place *p2, char *line, size_t len) | |
143 { | |
144 oneword("#ifndef", p2, line); | |
145 ifstate_push(p, !macro_isdefined(line)); | |
146 } | |
147 | |
148 static | |
149 void | |
150 d_elif(struct place *p, struct place *p2, char *line, size_t len) | |
151 { | |
152 char *expr; | |
16 | 153 struct place p3 = *p2; |
15 | 154 |
155 if (ifstate->seenelse) { | |
156 complain(p, "#elif after #else"); | |
157 complain_fail(); | |
158 } | |
159 | |
160 if (ifstate->evertrue) { | |
161 ifstate->curtrue = false; | |
162 } else { | |
163 expr = macroexpand(p2, line, len, true); | |
16 | 164 ifstate->curtrue = eval(&p3, expr); |
15 | 165 ifstate->evertrue = ifstate->curtrue; |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
166 dostrfree(expr); |
15 | 167 } |
168 } | |
169 | |
170 static | |
171 void | |
172 d_else(struct place *p, struct place *p2, char *line, size_t len) | |
173 { | |
174 if (ifstate->seenelse) { | |
175 complain(p, "Multiple #else directives in one conditional"); | |
176 complain_fail(); | |
177 } | |
178 | |
179 ifstate->curtrue = !ifstate->evertrue; | |
180 ifstate->evertrue = true; | |
181 ifstate->seenelse = true; | |
182 } | |
183 | |
184 static | |
185 void | |
186 d_endif(struct place *p, struct place *p2, char *line, size_t len) | |
187 { | |
188 if (ifstate->prev == NULL) { | |
189 complain(p, "Unmatched #endif"); | |
190 complain_fail(); | |
191 } else { | |
192 ifstate_pop(); | |
193 } | |
194 } | |
195 | |
196 //////////////////////////////////////////////////////////// | |
197 // macros | |
198 | |
199 static | |
200 void | |
201 d_define(struct place *p, struct place *p2, char *line, size_t len) | |
202 { | |
18 | 203 size_t pos, argpos; |
204 struct place p3, p4; | |
15 | 205 |
206 /* | |
207 * line may be: | |
208 * macro expansion | |
209 * macro(arg, arg, ...) expansion | |
210 */ | |
211 | |
212 pos = strcspn(line, " \t\f\v("); | |
213 if (line[pos] == '(') { | |
18 | 214 line[pos++] = '\0'; |
215 argpos = pos; | |
15 | 216 pos = pos + strcspn(line+pos, "()"); |
217 if (line[pos] == '(') { | |
218 p2->column += pos; | |
219 complain(p2, "Left parenthesis in macro parameters"); | |
220 complain_fail(); | |
221 return; | |
222 } | |
223 if (line[pos] != ')') { | |
224 p2->column += pos; | |
225 complain(p2, "Unclosed macro parameter list"); | |
226 complain_fail(); | |
227 return; | |
228 } | |
18 | 229 line[pos++] = '\0'; |
36
a489cc223483
Don't demand space after the macro argument parenthesis.
David A. Holland
parents:
30
diff
changeset
|
230 #if 0 |
15 | 231 if (!strchr(ws, line[pos])) { |
232 p2->column += pos; | |
233 complain(p2, "Trash after macro parameter list"); | |
234 complain_fail(); | |
235 return; | |
236 } | |
36
a489cc223483
Don't demand space after the macro argument parenthesis.
David A. Holland
parents:
30
diff
changeset
|
237 #endif |
15 | 238 } else if (line[pos] == '\0') { |
18 | 239 argpos = 0; |
15 | 240 } else { |
241 line[pos++] = '\0'; | |
18 | 242 argpos = 0; |
15 | 243 } |
244 | |
245 pos += strspn(line+pos, ws); | |
246 | |
247 p3 = *p2; | |
18 | 248 p3.column += argpos; |
249 | |
250 p4 = *p2; | |
251 p4.column += pos; | |
252 | |
253 if (argpos) { | |
254 macro_define_params(p2, line, &p3, | |
255 line + argpos, &p4, | |
256 line + pos); | |
257 } else { | |
258 macro_define_plain(p2, line, &p4, line + pos); | |
259 } | |
15 | 260 } |
261 | |
262 static | |
263 void | |
264 d_undef(struct place *p, struct place *p2, char *line, size_t len) | |
265 { | |
266 oneword("#undef", p2, line); | |
267 macro_undef(line); | |
268 } | |
269 | |
270 //////////////////////////////////////////////////////////// | |
271 // includes | |
272 | |
273 static | |
274 bool | |
275 tryinclude(struct place *p, char *line, size_t len) | |
276 { | |
277 if (len > 2 && line[0] == '"' && line[len-1] == '"') { | |
278 line[len-1] = '\0'; | |
279 file_readquote(p, line+1); | |
280 return true; | |
281 } | |
282 if (len > 2 && line[0] == '<' && line[len-1] == '>') { | |
283 line[len-1] = '\0'; | |
284 file_readbracket(p, line+1); | |
285 return true; | |
286 } | |
287 return false; | |
288 } | |
289 | |
290 static | |
291 void | |
292 d_include(struct place *p, struct place *p2, char *line, size_t len) | |
293 { | |
294 char *text; | |
295 | |
296 if (tryinclude(p, line, len)) { | |
297 return; | |
298 } | |
299 text = macroexpand(p2, line, len, false); | |
300 if (tryinclude(p, text, strlen(text))) { | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
301 dostrfree(text); |
15 | 302 return; |
303 } | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
304 dostrfree(text); |
15 | 305 complain(p, "Illegal #include directive"); |
306 complain_fail(); | |
307 } | |
308 | |
309 static | |
310 void | |
311 d_line(struct place *p, struct place *p2, char *line, size_t len) | |
312 { | |
313 /* XXX */ | |
314 complain(p, "Sorry, no #line yet"); | |
315 } | |
316 | |
317 //////////////////////////////////////////////////////////// | |
318 // messages | |
319 | |
320 static | |
321 void | |
322 d_warning(struct place *p, struct place *p2, char *line, size_t len) | |
323 { | |
324 char *msg; | |
325 | |
326 msg = macroexpand(p2, line, len, false); | |
327 complain(p, "#warning: %s", msg); | |
328 if (mode.werror) { | |
329 complain_fail(); | |
330 } | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
331 dostrfree(msg); |
15 | 332 } |
333 | |
334 static | |
335 void | |
336 d_error(struct place *p, struct place *p2, char *line, size_t len) | |
337 { | |
338 char *msg; | |
339 | |
340 msg = macroexpand(p2, line, len, false); | |
341 complain(p, "#error: %s", msg); | |
342 complain_fail(); | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
343 dostrfree(msg); |
15 | 344 } |
345 | |
346 //////////////////////////////////////////////////////////// | |
347 // other | |
348 | |
349 static | |
350 void | |
351 d_pragma(struct place *p, struct place *p2, char *line, size_t len) | |
352 { | |
353 complain(p, "#pragma %s", line); | |
354 complain_fail(); | |
355 } | |
356 | |
357 //////////////////////////////////////////////////////////// | |
358 // directive table | |
359 | |
360 static const struct { | |
361 const char *name; | |
362 bool ifskip; | |
363 void (*func)(struct place *, struct place *, char *line, size_t len); | |
364 } directives[] = { | |
365 { "define", true, d_define }, | |
366 { "elif", false, d_elif }, | |
367 { "else", false, d_else }, | |
368 { "endif", false, d_endif }, | |
369 { "error", true, d_error }, | |
370 { "if", false, d_if }, | |
371 { "ifdef", false, d_ifdef }, | |
372 { "ifndef", false, d_ifndef }, | |
373 { "include", true, d_include }, | |
374 { "line", true, d_line }, | |
375 { "pragma", true, d_pragma }, | |
376 { "undef", true, d_undef }, | |
377 { "warning", true, d_warning }, | |
378 }; | |
379 static const unsigned numdirectives = HOWMANY(directives); | |
380 | |
381 static | |
382 void | |
383 directive_gotdirective(struct place *p, char *line, size_t linelen) | |
384 { | |
385 struct place p2; | |
386 size_t len, skip; | |
387 unsigned i; | |
388 | |
389 p2 = *p; | |
390 for (i=0; i<numdirectives; i++) { | |
391 len = strlen(directives[i].name); | |
392 if (!strncmp(line, directives[i].name, len) && | |
393 strchr(ws, line[len])) { | |
394 if (directives[i].ifskip && !ifstate->curtrue) { | |
395 return; | |
396 } | |
397 skip = len + strspn(line+len, ws); | |
398 p2.column += skip; | |
399 line += skip; | |
400 linelen -= skip; | |
401 linelen = notrailingws(line, linelen); | |
402 directives[i].func(p, &p2, line, linelen); | |
403 return; | |
404 } | |
405 } | |
406 skip = strcspn(line, ws); | |
407 complain(p, "Unknown directive #%.*s", (int)skip, line); | |
408 complain_fail(); | |
409 } | |
410 | |
411 void | |
412 directive_gotline(struct place *p, char *line, size_t len) | |
413 { | |
414 size_t skip; | |
415 | |
416 /* check if we have a directive line */ | |
417 skip = strspn(line, ws); | |
418 if (line[skip] == '#') { | |
419 skip = skip + 1 + strspn(line + skip + 1, ws); | |
420 p->column += skip; | |
421 directive_gotdirective(p, line+skip, len-skip); | |
422 } else if (ifstate->curtrue) { | |
423 macro_sendline(p, line, len); | |
424 } | |
425 } | |
426 | |
427 | |
428 void | |
429 directive_goteof(struct place *p) | |
430 { | |
431 while (ifstate->prev != NULL) { | |
432 complain(p, "Missing #endif"); | |
433 complain(&ifstate->startplace, "...opened at this point"); | |
434 complain_failed(); | |
435 ifstate_pop(); | |
436 } | |
437 macro_sendeof(p); | |
438 } | |
439 | |
440 //////////////////////////////////////////////////////////// | |
441 // module initialization | |
442 | |
443 void | |
444 directive_init(void) | |
445 { | |
446 ifstate = ifstate_create(NULL, NULL, true); | |
447 } | |
448 | |
449 void | |
450 directive_cleanup(void) | |
451 { | |
452 assert(ifstate->prev == NULL); | |
453 ifstate_destroy(ifstate); | |
454 ifstate = NULL; | |
455 } |