Mercurial > hg > index.cgi
annotate lwcc/preproc.c @ 297:310df72c641d ccdev
Handle () surrounding macro args on invocation
author | William Astle <lost@l-w.ca> |
---|---|
date | Sat, 14 Sep 2013 21:27:03 -0600 |
parents | 83fcc1ed6ad6 |
children | 6112c67728ba |
rev | line source |
---|---|
296 | 1 /* |
2 lwcc/preproc.c | |
3 | |
4 Copyright © 2013 William Astle | |
5 | |
6 This file is part of LWTOOLS. | |
7 | |
8 LWTOOLS is free software: you can redistribute it and/or modify it under the | |
9 terms of the GNU General Public License as published by the Free Software | |
10 Foundation, either version 3 of the License, or (at your option) any later | |
11 version. | |
12 | |
13 This program is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
16 more details. | |
17 | |
18 You should have received a copy of the GNU General Public License along with | |
19 this program. If not, see <http://www.gnu.org/licenses/>. | |
20 */ | |
21 | |
22 #include <string.h> | |
23 | |
24 #include <lw_alloc.h> | |
25 #include <lw_string.h> | |
26 | |
27 #include "cpp.h" | |
28 #include "strbuf.h" | |
29 #include "symbol.h" | |
30 #include "token.h" | |
31 | |
32 static int expand_macro(struct preproc_info *, char *); | |
33 static void process_directive(struct preproc_info *); | |
34 static long eval_expr(struct preproc_info *); | |
35 | |
36 struct token *preproc_next_processed_token(struct preproc_info *pp) | |
37 { | |
38 struct token *ct; | |
39 | |
40 again: | |
41 ct = preproc_next_token(pp); | |
42 if (ct -> ttype == TOK_EOF) | |
43 return ct; | |
44 if (ct -> ttype == TOK_EOL) | |
45 pp -> ppeolseen = 1; | |
46 | |
47 if (ct -> ttype == TOK_HASH && pp -> eolseen == 1) | |
48 { | |
49 // preprocessor directive | |
50 process_directive(pp); | |
51 } | |
52 // if we're in a false section, don't return the token; keep scanning | |
53 if (pp -> skip_level) | |
54 goto again; | |
55 | |
56 if (ct -> ttype != TOK_WSPACE) | |
57 pp -> ppeolseen = 0; | |
58 | |
59 if (ct -> ttype == TOK_IDENT) | |
60 { | |
61 // possible macro expansion | |
62 if (expand_macro(pp, ct -> strval)) | |
63 goto again; | |
64 } | |
65 | |
66 return ct; | |
67 } | |
68 | |
69 static struct token *preproc_next_processed_token_nws(struct preproc_info *pp) | |
70 { | |
71 struct token *t; | |
72 | |
73 do | |
74 { | |
75 t = preproc_next_processed_token(pp); | |
76 } while (t -> ttype == TOK_WSPACE); | |
77 return t; | |
78 } | |
79 | |
80 static struct token *preproc_next_token_nws(struct preproc_info *pp) | |
81 { | |
82 struct token *t; | |
83 | |
84 do | |
85 { | |
86 t = preproc_next_token(pp); | |
87 } while (t -> ttype == TOK_WSPACE); | |
88 return t; | |
89 } | |
90 | |
91 static void skip_eol(struct preproc_info *pp) | |
92 { | |
93 struct token *t; | |
94 | |
95 if (pp -> curtok && pp -> curtok -> ttype == TOK_EOL) | |
96 return; | |
97 do | |
98 { | |
99 t = preproc_next_token(pp); | |
100 } while (t -> ttype != TOK_EOL); | |
101 } | |
102 | |
103 static void check_eol(struct preproc_info *pp) | |
104 { | |
105 struct token *t; | |
106 | |
107 t = preproc_next_token(pp); | |
108 if (t -> ttype != TOK_EOL) | |
109 preproc_throw_warning(pp, "Extra text after preprocessor directive"); | |
110 skip_eol(pp); | |
111 } | |
112 | |
113 static void dir_ifdef(struct preproc_info *pp) | |
114 { | |
115 struct token *ct; | |
116 | |
117 if (pp -> skip_level) | |
118 { | |
119 pp -> skip_level++; | |
120 skip_eol(pp); | |
121 return; | |
122 } | |
123 | |
124 do | |
125 { | |
126 ct = preproc_next_token(pp); | |
127 } while (ct -> ttype == TOK_WSPACE); | |
128 | |
129 if (ct -> ttype != TOK_IDENT) | |
130 { | |
131 preproc_throw_error(pp, "Bad #ifdef"); | |
132 skip_eol(pp); | |
133 } | |
134 | |
135 if (symtab_find(pp, ct -> strval) == NULL) | |
136 { | |
137 pp -> skip_level++; | |
138 } | |
139 else | |
140 { | |
141 pp -> found_level++; | |
142 } | |
143 check_eol(pp); | |
144 } | |
145 | |
146 static void dir_ifndef(struct preproc_info *pp) | |
147 { | |
148 struct token *ct; | |
149 | |
150 if (pp -> skip_level) | |
151 { | |
152 pp -> skip_level++; | |
153 skip_eol(pp); | |
154 return; | |
155 } | |
156 | |
157 do | |
158 { | |
159 ct = preproc_next_token(pp); | |
160 } while (ct -> ttype == TOK_WSPACE); | |
161 | |
162 if (ct -> ttype != TOK_IDENT) | |
163 { | |
164 preproc_throw_error(pp, "Bad #ifdef"); | |
165 skip_eol(pp); | |
166 } | |
167 | |
168 if (symtab_find(pp, ct -> strval) != NULL) | |
169 { | |
170 pp -> skip_level++; | |
171 } | |
172 else | |
173 { | |
174 pp -> found_level++; | |
175 } | |
176 check_eol(pp); | |
177 } | |
178 | |
179 static void dir_if(struct preproc_info *pp) | |
180 { | |
181 if (pp -> skip_level || !eval_expr(pp)) | |
182 pp -> skip_level++; | |
183 else | |
184 pp -> found_level++; | |
185 } | |
186 | |
187 static void dir_elif(struct preproc_info *pp) | |
188 { | |
189 if (pp -> skip_level == 0) | |
190 pp -> else_skip_level = pp -> found_level; | |
191 if (pp -> skip_level) | |
192 { | |
193 if (pp -> else_skip_level > pp -> found_level) | |
194 ; | |
195 else if (--(pp -> skip_level) != 0) | |
196 pp -> skip_level++; | |
197 else if (eval_expr(pp)) | |
198 pp -> found_level++; | |
199 else | |
200 pp -> skip_level++; | |
201 } | |
202 else if (pp -> found_level) | |
203 { | |
204 pp -> skip_level++; | |
205 pp -> found_level--; | |
206 } | |
207 else | |
208 preproc_throw_error(pp, "#elif in non-conditional section"); | |
209 } | |
210 | |
211 static void dir_else(struct preproc_info *pp) | |
212 { | |
213 if (pp -> skip_level) | |
214 { | |
215 if (pp -> else_skip_level > pp -> found_level) | |
216 ; | |
217 else if (--(pp -> skip_level) != 0) | |
218 pp -> skip_level++; | |
219 else | |
220 pp -> found_level++; | |
221 } | |
222 else if (pp -> found_level) | |
223 { | |
224 pp -> skip_level++; | |
225 pp -> found_level--; | |
226 } | |
227 else | |
228 { | |
229 preproc_throw_error(pp, "#else in non-conditional section"); | |
230 } | |
231 if (pp -> else_level == pp -> found_level + pp -> skip_level) | |
232 { | |
233 preproc_throw_error(pp, "Too many #else"); | |
234 } | |
235 pp -> else_level = pp -> found_level + pp -> skip_level; | |
236 check_eol(pp); | |
237 } | |
238 | |
239 static void dir_endif(struct preproc_info *pp) | |
240 { | |
241 if (pp -> skip_level) | |
242 pp -> skip_level--; | |
243 else if (pp -> found_level) | |
244 pp -> found_level--; | |
245 else | |
246 preproc_throw_error(pp, "#endif in non-conditional section"); | |
247 if (pp -> skip_level == 0) | |
248 pp -> else_skip_level = 0; | |
249 pp -> else_level = 0; | |
250 check_eol(pp); | |
251 } | |
252 | |
253 static void dir_define(struct preproc_info *pp) | |
254 { | |
255 struct token *tl = NULL; | |
256 struct token *ttl; | |
257 struct token *ct; | |
258 int nargs = -1; | |
259 int vargs = 0; | |
260 char *mname = NULL; | |
261 | |
262 char **arglist = NULL; | |
263 | |
264 if (pp -> skip_level) | |
265 { | |
266 skip_eol(pp); | |
267 return; | |
268 } | |
269 | |
270 ct = preproc_next_token_nws(pp); | |
271 if (ct -> ttype != TOK_IDENT) | |
272 goto baddefine; | |
273 | |
274 mname = lw_strdup(ct -> strval); | |
275 ct = preproc_next_token(pp); | |
276 | |
277 if (ct -> ttype == TOK_WSPACE) | |
278 { | |
279 /* object like macro */ | |
280 } | |
281 else if (ct -> ttype == TOK_EOL) | |
282 { | |
283 /* object like macro - empty value */ | |
284 goto out; | |
285 } | |
286 else if (ct -> ttype == TOK_OPAREN) | |
287 { | |
288 /* function like macro - parse args */ | |
289 nargs = 0; | |
290 vargs = 0; | |
291 for (;;) | |
292 { | |
293 ct = preproc_next_token_nws(pp); | |
294 if (ct -> ttype == TOK_EOL) | |
295 { | |
296 goto baddefine; | |
297 } | |
298 if (ct -> ttype == TOK_CPAREN) | |
299 break; | |
300 | |
301 if (ct -> ttype == TOK_IDENT) | |
302 { | |
303 /* parameter name */ | |
304 nargs++; | |
305 /* record argument name */ | |
306 arglist = lw_realloc(arglist, sizeof(char *) * nargs); | |
307 arglist[nargs - 1] = lw_strdup(ct -> strval); | |
308 | |
309 /* check for end of args or comma */ | |
310 ct = preproc_next_token_nws(pp); | |
311 if (ct -> ttype == TOK_CPAREN) | |
312 break; | |
313 else if (ct -> ttype == TOK_COMMA) | |
314 continue; | |
315 else | |
316 goto baddefine; | |
317 } | |
318 else if (ct -> ttype == TOK_ELLIPSIS) | |
319 { | |
320 /* variadic macro */ | |
321 vargs = 1; | |
322 ct = preproc_next_token_nws(pp); | |
323 if (ct -> ttype != TOK_CPAREN) | |
324 goto baddefine; | |
325 break; | |
326 } | |
327 else | |
328 goto baddefine; | |
329 } | |
330 } | |
331 else | |
332 { | |
333 baddefine: | |
334 preproc_throw_error(pp, "bad #define"); | |
335 baddefine2: | |
336 skip_eol(pp); | |
337 lw_free(mname); | |
338 while (nargs > 0) | |
339 lw_free(arglist[--nargs]); | |
340 lw_free(arglist); | |
341 return; | |
342 } | |
343 | |
344 for (;;) | |
345 { | |
346 ct = preproc_next_token(pp); | |
347 if (ct -> ttype == TOK_EOL) | |
348 break; | |
349 if (!tl) | |
350 tl = ct; | |
351 else | |
352 ttl -> next = ct; | |
353 ttl = ct; | |
354 pp -> curtok = NULL; // tell *_next_token* not to clobber token | |
355 } | |
356 out: | |
357 if (strcmp(mname, "defined") == 0) | |
358 { | |
359 preproc_throw_warning(pp, "attempt to define 'defined' as a macro not allowed"); | |
360 goto baddefine2; | |
361 } | |
362 else if (symtab_find(pp, mname) != NULL) | |
363 { | |
364 /* need to do a token compare between the old value and the new value | |
365 to decide whether to complain */ | |
366 preproc_throw_warning(pp, "%s previous defined", mname); | |
367 symtab_undef(pp, mname); | |
368 } | |
369 symtab_define(pp, mname, tl, nargs, arglist, vargs); | |
370 lw_free(mname); | |
371 while (nargs > 0) | |
372 lw_free(arglist[--nargs]); | |
373 lw_free(arglist); | |
374 /* no need to check for EOL here */ | |
375 } | |
376 | |
377 static void dir_undef(struct preproc_info *pp) | |
378 { | |
379 struct token *ct; | |
380 if (pp -> skip_level) | |
381 { | |
382 skip_eol(pp); | |
383 return; | |
384 } | |
385 | |
386 do | |
387 { | |
388 ct = preproc_next_token(pp); | |
389 } while (ct -> ttype == TOK_WSPACE); | |
390 | |
391 if (ct -> ttype != TOK_IDENT) | |
392 { | |
393 preproc_throw_error(pp, "Bad #undef"); | |
394 skip_eol(pp); | |
395 } | |
396 | |
397 symtab_undef(pp, ct -> strval); | |
398 check_eol(pp); | |
399 } | |
400 | |
401 char *streol(struct preproc_info *pp) | |
402 { | |
403 struct strbuf *s; | |
404 struct token *ct; | |
405 int i; | |
406 | |
407 s = strbuf_new(); | |
408 do | |
409 { | |
410 ct = preproc_next_token(pp); | |
411 } while (ct -> ttype == TOK_WSPACE); | |
412 | |
413 while (ct -> ttype != TOK_EOL) | |
414 { | |
415 for (i = 0; ct -> strval[i]; i++) | |
416 strbuf_add(s, ct -> strval[i]); | |
417 ct = preproc_next_token(pp); | |
418 } | |
419 return strbuf_end(s); | |
420 } | |
421 | |
422 static void dir_error(struct preproc_info *pp) | |
423 { | |
424 char *s; | |
425 | |
426 if (pp -> skip_level) | |
427 { | |
428 skip_eol(pp); | |
429 return; | |
430 } | |
431 | |
432 s = streol(pp); | |
433 preproc_throw_error(pp, "%s", s); | |
434 lw_free(s); | |
435 } | |
436 | |
437 static void dir_warning(struct preproc_info *pp) | |
438 { | |
439 char *s; | |
440 | |
441 if (pp -> skip_level) | |
442 { | |
443 skip_eol(pp); | |
444 return; | |
445 } | |
446 | |
447 s = streol(pp); | |
448 preproc_throw_warning(pp, "%s", s); | |
449 lw_free(s); | |
450 } | |
451 | |
452 static void dir_include(struct preproc_info *pp) | |
453 { | |
454 } | |
455 | |
456 static void dir_line(struct preproc_info *pp) | |
457 { | |
458 } | |
459 | |
460 static void dir_pragma(struct preproc_info *pp) | |
461 { | |
462 if (pp -> skip_level) | |
463 { | |
464 skip_eol(pp); | |
465 return; | |
466 } | |
467 | |
468 preproc_throw_warning(pp, "Unsupported #pragma"); | |
469 skip_eol(pp); | |
470 } | |
471 | |
472 struct { char *name; void (*fn)(struct preproc_info *); } dirlist[] = | |
473 { | |
474 { "ifdef", dir_ifdef }, | |
475 { "ifndef", dir_ifndef }, | |
476 { "if", dir_if }, | |
477 { "else", dir_else }, | |
478 { "elif", dir_elif }, | |
479 { "endif", dir_endif }, | |
480 { "define", dir_define }, | |
481 { "undef", dir_undef }, | |
482 { "include", dir_include }, | |
483 { "error", dir_error }, | |
484 { "warning", dir_warning }, | |
485 { "line", dir_line }, | |
486 { "pragma", dir_pragma }, | |
487 { NULL, NULL } | |
488 }; | |
489 | |
490 static void process_directive(struct preproc_info *pp) | |
491 { | |
492 struct token *ct; | |
493 int i; | |
494 | |
495 do | |
496 { | |
497 ct = preproc_next_token(pp); | |
498 } while (ct -> ttype == TOK_WSPACE); | |
499 | |
500 // NULL directive | |
501 if (ct -> ttype == TOK_EOL) | |
502 return; | |
503 | |
504 if (ct -> ttype != TOK_IDENT) | |
505 goto baddir; | |
506 | |
507 for (i = 0; dirlist[i].name; i++) | |
508 { | |
509 if (strcmp(dirlist[i].name, ct -> strval) == 0) | |
510 { | |
511 (*(dirlist[i].fn))(pp); | |
512 return; | |
513 } | |
514 } | |
515 baddir: | |
516 preproc_throw_error(pp, "Bad preprocessor directive"); | |
517 while (ct -> ttype != TOK_EOL) | |
518 ct = preproc_next_token(pp); | |
519 return; | |
520 } | |
521 | |
522 /* | |
523 Evaluate a preprocessor expression | |
524 */ | |
525 | |
526 /* same as skip_eol() but the EOL token is not consumed */ | |
527 static void skip_eoe(struct preproc_info *pp) | |
528 { | |
529 skip_eol(pp); | |
530 preproc_unget_token(pp, pp -> curtok); | |
531 } | |
532 | |
533 static long eval_expr_real(struct preproc_info *, int); | |
534 static long preproc_numval(struct token *); | |
535 | |
536 static long eval_term_real(struct preproc_info *pp) | |
537 { | |
538 long tval = 0; | |
539 struct token *ct; | |
540 | |
541 eval_next: | |
542 ct = preproc_next_processed_token_nws(pp); | |
543 if (ct -> ttype == TOK_EOL) | |
544 { | |
545 preproc_throw_error(pp, "Bad expression"); | |
546 return 0; | |
547 } | |
548 | |
549 switch (ct -> ttype) | |
550 { | |
551 case TOK_OPAREN: | |
552 tval = eval_expr_real(pp, 0); | |
553 ct = preproc_next_processed_token_nws(pp); | |
554 if (ct -> ttype != ')') | |
555 { | |
556 preproc_throw_error(pp, "Unbalanced () in expression"); | |
557 skip_eoe(pp); | |
558 return 0; | |
559 } | |
560 return tval; | |
561 | |
562 case TOK_ADD: // unary + | |
563 goto eval_next; | |
564 | |
565 case TOK_SUB: // unary - | |
566 tval = eval_expr_real(pp, 200); | |
567 return -tval; | |
568 | |
569 /* NOTE: we should only get "TOK_IDENT" from an undefined macro */ | |
570 case TOK_IDENT: // some sort of function, symbol, etc. | |
571 if (strcmp(ct -> strval, "defined")) | |
572 { | |
573 /* the defined operator */ | |
574 /* any number in the "defined" bit will be | |
575 treated as a defined symbol, even zero */ | |
576 ct = preproc_next_token_nws(pp); | |
577 if (ct -> ttype == TOK_OPAREN) | |
578 { | |
579 ct = preproc_next_token_nws(pp); | |
580 if (ct -> ttype != TOK_IDENT) | |
581 { | |
582 preproc_throw_error(pp, "Bad expression"); | |
583 skip_eoe(pp); | |
584 return 0; | |
585 } | |
586 if (symtab_find(pp, ct -> strval) == NULL) | |
587 tval = 0; | |
588 else | |
589 tval = 1; | |
590 ct = preproc_next_token_nws(pp); | |
591 if (ct -> ttype != TOK_CPAREN) | |
592 { | |
593 preproc_throw_error(pp, "Bad expression"); | |
594 skip_eoe(pp); | |
595 return 0; | |
596 } | |
597 return tval; | |
598 } | |
599 else if (ct -> ttype == TOK_IDENT) | |
600 { | |
601 return (symtab_find(pp, ct -> strval) != NULL) ? 1 : 0; | |
602 } | |
603 preproc_throw_error(pp, "Bad expression"); | |
604 skip_eoe(pp); | |
605 return 0; | |
606 } | |
607 /* unknown identifier - it's zero */ | |
608 return 0; | |
609 | |
610 /* numbers */ | |
611 case TOK_NUMBER: | |
612 return preproc_numval(ct); | |
613 | |
614 default: | |
615 preproc_throw_error(pp, "Bad expression"); | |
616 skip_eoe(pp); | |
617 return 0; | |
618 } | |
619 return 0; | |
620 } | |
621 | |
622 static long eval_expr_real(struct preproc_info *pp, int p) | |
623 { | |
624 static const struct operinfo | |
625 { | |
626 int tok; | |
627 int prec; | |
628 } operators[] = | |
629 { | |
630 { TOK_ADD, 100 }, | |
631 { TOK_SUB, 100 }, | |
632 { TOK_STAR, 150 }, | |
633 { TOK_DIV, 150 }, | |
634 { TOK_MOD, 150 }, | |
635 { TOK_LT, 75 }, | |
636 { TOK_LE, 75 }, | |
637 { TOK_GT, 75 }, | |
638 { TOK_GE, 75 }, | |
639 { TOK_EQ, 70 }, | |
640 { TOK_NE, 70 }, | |
641 { TOK_BAND, 30 }, | |
642 { TOK_BOR, 25 }, | |
643 { TOK_NONE, 0 } | |
644 }; | |
645 | |
646 int op; | |
647 long term1, term2, term3; | |
648 struct token *ct; | |
649 | |
650 term1 = eval_term_real(pp); | |
651 eval_next: | |
652 ct = preproc_next_processed_token_nws(pp); | |
653 for (op = 0; operators[op].tok != TOK_NONE; op++) | |
654 { | |
655 if (operators[op].tok == ct -> ttype) | |
656 break; | |
657 } | |
658 /* if it isn't a recognized operator, assume end of expression */ | |
659 if (operators[op].tok == TOK_NONE) | |
660 { | |
661 preproc_unget_token(pp, ct); | |
662 return term1; | |
663 } | |
664 | |
665 /* if new operation is not higher than the current precedence, let the previous op finish */ | |
666 if (operators[op].prec <= p) | |
667 return term1; | |
668 | |
669 /* get the second term */ | |
670 term2 = eval_expr_real(pp, operators[op].prec); | |
671 | |
672 switch (operators[op].tok) | |
673 { | |
674 case TOK_ADD: | |
675 term3 = term1 + term2; | |
676 break; | |
677 | |
678 case TOK_SUB: | |
679 term3 = term1 - term2; | |
680 break; | |
681 | |
682 case TOK_STAR: | |
683 term3 = term1 * term2; | |
684 break; | |
685 | |
686 case TOK_DIV: | |
687 if (!term2) | |
688 { | |
689 preproc_throw_warning(pp, "Division by zero"); | |
690 term3 = 0; | |
691 break; | |
692 } | |
693 term3 = term1 / term2; | |
694 break; | |
695 | |
696 case TOK_MOD: | |
697 if (!term2) | |
698 { | |
699 preproc_throw_warning(pp, "Division by zero"); | |
700 term3 = 0; | |
701 break; | |
702 } | |
703 term3 = term1 % term2; | |
704 break; | |
705 | |
706 case TOK_BAND: | |
707 term3 = (term1 && term2); | |
708 break; | |
709 | |
710 case TOK_BOR: | |
711 term3 = (term1 || term2); | |
712 break; | |
713 | |
714 case TOK_EQ: | |
715 term3 = (term1 == term2); | |
716 break; | |
717 | |
718 case TOK_NE: | |
719 term3 = (term1 != term2); | |
720 break; | |
721 | |
722 case TOK_GT: | |
723 term3 = (term1 > term2); | |
724 break; | |
725 | |
726 case TOK_GE: | |
727 term3 = (term1 >= term2); | |
728 break; | |
729 | |
730 case TOK_LT: | |
731 term3 = (term1 < term2); | |
732 break; | |
733 | |
734 case TOK_LE: | |
735 term3 = (term1 <= term2); | |
736 break; | |
737 | |
738 default: | |
739 term3 = 0; | |
740 break; | |
741 } | |
742 term1 = term3; | |
743 goto eval_next; | |
744 } | |
745 | |
746 static long eval_expr(struct preproc_info *pp) | |
747 { | |
748 long rv; | |
749 | |
750 rv = eval_expr_real(pp, 0); | |
751 if (pp -> curtok -> ttype != TOK_EOL) | |
752 { | |
753 preproc_throw_error(pp, "Bad expression"); | |
754 skip_eol(pp); | |
755 } | |
756 return rv; | |
757 } | |
758 | |
759 /* convert a numeric string to a number */ | |
760 long preproc_numval(struct token *t) | |
761 { | |
762 return 0; | |
763 } | |
764 | |
765 /* | |
766 Below here is the logic for expanding a macro | |
767 */ | |
768 static int expand_macro(struct preproc_info *pp, char *mname) | |
769 { | |
770 struct symtab_e *s; | |
771 struct token *t, *t2, *t3; | |
772 struct token **arglist = NULL; | |
773 int nargs = 0; | |
774 struct expand_e *e; | |
775 struct token **exparglist = NULL; | |
776 int i; | |
297
310df72c641d
Handle () surrounding macro args on invocation
William Astle <lost@l-w.ca>
parents:
296
diff
changeset
|
777 int pcount; |
310df72c641d
Handle () surrounding macro args on invocation
William Astle <lost@l-w.ca>
parents:
296
diff
changeset
|
778 |
296 | 779 s = symtab_find(pp, mname); |
780 if (!s) | |
781 return 0; | |
782 | |
783 for (e = pp -> expand_list; e; e = e -> next) | |
784 { | |
785 /* don't expand if we're already expanding the same macro */ | |
786 if (e -> s == s) | |
787 return 0; | |
788 } | |
789 | |
790 if (s -> nargs == -1) | |
791 { | |
792 /* short circuit NULL expansion */ | |
793 if (s -> tl == NULL) | |
794 return 1; | |
795 | |
796 goto expandmacro; | |
797 } | |
798 | |
799 // look for opening paren after optional whitespace | |
800 t2 = NULL; | |
801 t = NULL; | |
802 for (;;) | |
803 { | |
804 t = preproc_next_token(pp); | |
805 if (t -> ttype != TOK_WSPACE && t -> ttype != TOK_EOL) | |
806 break; | |
807 t -> next = t2; | |
808 t2 = t2; | |
809 } | |
810 if (t -> ttype != TOK_OPAREN) | |
811 { | |
812 // not a function-like invocation | |
813 while (t2) | |
814 { | |
815 t = t2 -> next; | |
816 preproc_unget_token(pp, t2); | |
817 t2 = t; | |
818 } | |
819 return 0; | |
820 } | |
821 | |
822 // parse parameters here | |
823 t = preproc_next_token_nws(pp); | |
824 nargs = 1; | |
825 arglist = lw_alloc(sizeof(struct token *)); | |
826 arglist[0] = NULL; | |
827 t2 = NULL; | |
828 | |
829 while (t -> ttype != TOK_CPAREN) | |
830 { | |
297
310df72c641d
Handle () surrounding macro args on invocation
William Astle <lost@l-w.ca>
parents:
296
diff
changeset
|
831 pcount = 0; |
296 | 832 if (t -> ttype == TOK_EOF) |
833 { | |
834 preproc_throw_error(pp, "Unexpected EOF in macro call"); | |
835 break; | |
836 } | |
837 if (t -> ttype == TOK_EOL) | |
838 continue; | |
297
310df72c641d
Handle () surrounding macro args on invocation
William Astle <lost@l-w.ca>
parents:
296
diff
changeset
|
839 if (t -> ttype == TOK_OPAREN) |
310df72c641d
Handle () surrounding macro args on invocation
William Astle <lost@l-w.ca>
parents:
296
diff
changeset
|
840 pcount++; |
310df72c641d
Handle () surrounding macro args on invocation
William Astle <lost@l-w.ca>
parents:
296
diff
changeset
|
841 else if (t -> ttype == TOK_CPAREN && pcount) |
310df72c641d
Handle () surrounding macro args on invocation
William Astle <lost@l-w.ca>
parents:
296
diff
changeset
|
842 pcount--; |
310df72c641d
Handle () surrounding macro args on invocation
William Astle <lost@l-w.ca>
parents:
296
diff
changeset
|
843 if (t -> ttype == TOK_COMMA && pcount == 0) |
296 | 844 { |
845 if (!(s -> vargs) || (nargs > s -> nargs)) | |
846 { | |
847 nargs++; | |
848 arglist = lw_realloc(arglist, sizeof(struct token *) * nargs); | |
849 arglist[nargs - 1] = NULL; | |
850 t2 = NULL; | |
851 continue; | |
852 } | |
853 } | |
854 if (t2) | |
855 { | |
856 t2 -> next = token_dup(t); | |
857 t2 = t2 -> next; | |
858 } | |
859 else | |
860 { | |
861 t2 = token_dup(t); | |
862 arglist[nargs - 1] = t2; | |
863 } | |
864 } | |
865 | |
866 if (s -> vargs) | |
867 { | |
868 if (nargs <= s -> nargs) | |
869 { | |
870 preproc_throw_error(pp, "Wrong number of arguments (%d) for variadic macro %s which takes %d arguments", nargs, mname, s -> nargs); | |
871 } | |
872 } | |
873 else | |
874 { | |
875 if (s -> nargs != nargs && !(s -> nargs == 0 && nargs == 1 && arglist[nargs - 1])) | |
876 { | |
877 preproc_throw_error(pp, "Wrong number of arguments (%d) for macro %s which takes %d arguments", nargs, mname, s -> nargs); | |
878 } | |
879 } | |
880 | |
881 /* now calculate the pre-expansions of the arguments */ | |
882 exparglist = lw_alloc(nargs); | |
883 for (i = 0; i < nargs; i++) | |
884 { | |
885 t2 = NULL; | |
886 exparglist[i] = NULL; | |
887 // NOTE: do nothing if empty argument | |
888 if (arglist[i] == NULL) | |
889 continue; | |
890 pp -> sourcelist = arglist[i]; | |
891 for (;;) | |
892 { | |
893 t = preproc_next_processed_token(pp); | |
894 if (t -> ttype == TOK_EOF) | |
895 break; | |
896 if (t2) | |
897 { | |
898 t2 -> next = token_dup(t); | |
899 t2 = t2 -> next; | |
900 } | |
901 else | |
902 { | |
903 t2 = token_dup(t); | |
904 exparglist[i] = t2; | |
905 } | |
906 } | |
907 } | |
908 | |
909 expandmacro: | |
910 t2 = NULL; | |
911 t3 = NULL; | |
912 | |
913 for (t = s -> tl; t; t = t -> next) | |
914 { | |
915 if (t -> ttype == TOK_IDENT) | |
916 { | |
917 /* identifiers might need expansion to arguments */ | |
918 if (strcmp(t -> strval, "__VA_ARGS__") == 0) | |
919 { | |
920 i = s -> nargs; | |
921 } | |
922 else | |
923 { | |
924 for (i = 0; i < nargs; i++) | |
925 { | |
926 if (strcmp(t -> strval, s -> params[i]) == 0) | |
927 break; | |
928 } | |
929 } | |
930 if ((i == s -> nargs) && !(s -> vargs)) | |
931 { | |
932 struct token *te; | |
933 // expand argument | |
934 // FIXME: handle # and ## | |
935 for (te = exparglist[i]; te; te = te -> next) | |
936 { | |
937 if (t2) | |
938 { | |
939 t2 -> next = token_dup(te); | |
940 t2 = t2 -> next; | |
941 } | |
942 else | |
943 { | |
944 t3 = token_dup(te); | |
945 t2 = t2; | |
946 } | |
947 } | |
948 continue; | |
949 } | |
950 } | |
951 if (t2) | |
952 { | |
953 t2 -> next = token_dup(t); | |
954 t2 = t2 -> next; | |
955 } | |
956 else | |
957 { | |
958 t3 = token_dup(t); | |
959 t2 = t3; | |
960 } | |
961 } | |
962 | |
963 /* put the new expansion in front of the input, if relevant; if we | |
964 expanded to nothing, no need to create an expansion record or | |
965 put anything into the input queue */ | |
966 if (t3) | |
967 { | |
968 t2 -> next = token_create(TOK_ENDEXPAND, "", -1, -1, ""); | |
969 t2 -> next -> next = pp -> tokqueue; | |
970 pp -> tokqueue = t3; | |
971 | |
972 /* set up expansion record */ | |
973 e = lw_alloc(sizeof(struct expand_e)); | |
974 e -> next = pp -> expand_list; | |
975 pp -> expand_list = e; | |
976 e -> s = s; | |
977 } | |
978 | |
979 /* now clean up */ | |
980 for (i = 0; i < nargs; i++) | |
981 { | |
982 lw_free(arglist[i]); | |
983 lw_free(exparglist[i]); | |
984 } | |
985 lw_free(arglist); | |
986 lw_free(exparglist); | |
987 | |
988 return 1; | |
989 } |