Mercurial > hg > index.cgi
comparison lwcc/preproc.c @ 495:5b8871fd7503
Merged previous lwcc development branch into mainline.
author | William Astle <lost@l-w.ca> |
---|---|
date | Mon, 05 Aug 2019 21:27:09 -0600 |
parents | 836dc5371980 |
children |
comparison
equal
deleted
inserted
replaced
493:6073f4a33475 | 495:5b8871fd7503 |
---|---|
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 <stdio.h> | |
23 #include <stdlib.h> | |
24 #include <string.h> | |
25 #include <time.h> | |
26 #include <unistd.h> | |
27 | |
28 #include <lw_alloc.h> | |
29 #include <lw_string.h> | |
30 #include <lw_strbuf.h> | |
31 #include <lw_strpool.h> | |
32 | |
33 #include "cpp.h" | |
34 #include "symbol.h" | |
35 #include "token.h" | |
36 | |
37 static int expand_macro(struct preproc_info *, char *); | |
38 static void process_directive(struct preproc_info *); | |
39 static long eval_expr(struct preproc_info *); | |
40 extern struct token *preproc_lex_next_token(struct preproc_info *); | |
41 static long preproc_numval(struct preproc_info *, struct token *); | |
42 static int eval_escape(char **); | |
43 extern int preproc_lex_fetch_byte(struct preproc_info *); | |
44 extern void preproc_lex_unfetch_byte(struct preproc_info *, int); | |
45 | |
46 | |
47 struct token *preproc_next_processed_token(struct preproc_info *pp) | |
48 { | |
49 struct token *ct; | |
50 | |
51 again: | |
52 ct = preproc_next_token(pp); | |
53 if (ct -> ttype == TOK_EOF) | |
54 return ct; | |
55 if (ct -> ttype == TOK_EOL) | |
56 { | |
57 pp -> ppeolseen = 1; | |
58 return ct; | |
59 } | |
60 | |
61 if (ct -> ttype == TOK_HASH && pp -> ppeolseen == 1) | |
62 { | |
63 // preprocessor directive | |
64 process_directive(pp); | |
65 goto again; | |
66 } | |
67 // if we're in a false section, don't return the token; keep scanning | |
68 if (pp -> skip_level) | |
69 goto again; | |
70 | |
71 if (ct -> ttype != TOK_WSPACE) | |
72 pp -> ppeolseen = 0; | |
73 | |
74 if (ct -> ttype == TOK_IDENT) | |
75 { | |
76 // possible macro expansion | |
77 if (expand_macro(pp, ct -> strval)) | |
78 goto again; | |
79 } | |
80 | |
81 return ct; | |
82 } | |
83 | |
84 static struct token *preproc_next_processed_token_nws(struct preproc_info *pp) | |
85 { | |
86 struct token *t; | |
87 | |
88 do | |
89 { | |
90 t = preproc_next_processed_token(pp); | |
91 } while (t -> ttype == TOK_WSPACE); | |
92 return t; | |
93 } | |
94 | |
95 static struct token *preproc_next_token_nws(struct preproc_info *pp) | |
96 { | |
97 struct token *t; | |
98 | |
99 do | |
100 { | |
101 t = preproc_next_token(pp); | |
102 } while (t -> ttype == TOK_WSPACE); | |
103 return t; | |
104 } | |
105 | |
106 static void skip_eol(struct preproc_info *pp) | |
107 { | |
108 struct token *t; | |
109 | |
110 if (pp -> curtok && pp -> curtok -> ttype == TOK_EOL) | |
111 return; | |
112 do | |
113 { | |
114 t = preproc_next_token(pp); | |
115 } while (t -> ttype != TOK_EOL); | |
116 } | |
117 | |
118 static void check_eol(struct preproc_info *pp) | |
119 { | |
120 struct token *t; | |
121 | |
122 t = preproc_next_token_nws(pp); | |
123 if (t -> ttype != TOK_EOL) | |
124 preproc_throw_warning(pp, "Extra text after preprocessor directive"); | |
125 skip_eol(pp); | |
126 } | |
127 | |
128 static void dir_ifdef(struct preproc_info *pp) | |
129 { | |
130 struct token *ct; | |
131 | |
132 if (pp -> skip_level) | |
133 { | |
134 pp -> skip_level++; | |
135 skip_eol(pp); | |
136 return; | |
137 } | |
138 | |
139 do | |
140 { | |
141 ct = preproc_next_token(pp); | |
142 } while (ct -> ttype == TOK_WSPACE); | |
143 | |
144 if (ct -> ttype != TOK_IDENT) | |
145 { | |
146 preproc_throw_error(pp, "Bad #ifdef"); | |
147 skip_eol(pp); | |
148 } | |
149 | |
150 if (symtab_find(pp, ct -> strval) == NULL) | |
151 { | |
152 pp -> skip_level++; | |
153 } | |
154 else | |
155 { | |
156 pp -> found_level++; | |
157 } | |
158 check_eol(pp); | |
159 } | |
160 | |
161 static void dir_ifndef(struct preproc_info *pp) | |
162 { | |
163 struct token *ct; | |
164 | |
165 if (pp -> skip_level) | |
166 { | |
167 pp -> skip_level++; | |
168 skip_eol(pp); | |
169 return; | |
170 } | |
171 | |
172 do | |
173 { | |
174 ct = preproc_next_token(pp); | |
175 } while (ct -> ttype == TOK_WSPACE); | |
176 | |
177 if (ct -> ttype != TOK_IDENT) | |
178 { | |
179 preproc_throw_error(pp, "Bad #ifdef"); | |
180 skip_eol(pp); | |
181 } | |
182 | |
183 if (symtab_find(pp, ct -> strval) != NULL) | |
184 { | |
185 pp -> skip_level++; | |
186 } | |
187 else | |
188 { | |
189 pp -> found_level++; | |
190 } | |
191 check_eol(pp); | |
192 } | |
193 | |
194 static void dir_if(struct preproc_info *pp) | |
195 { | |
196 if (pp -> skip_level || !eval_expr(pp)) | |
197 pp -> skip_level++; | |
198 else | |
199 pp -> found_level++; | |
200 } | |
201 | |
202 static void dir_elif(struct preproc_info *pp) | |
203 { | |
204 if (pp -> skip_level == 0) | |
205 pp -> else_skip_level = pp -> found_level; | |
206 if (pp -> skip_level) | |
207 { | |
208 if (pp -> else_skip_level > pp -> found_level) | |
209 ; | |
210 else if (--(pp -> skip_level) != 0) | |
211 pp -> skip_level++; | |
212 else if (eval_expr(pp)) | |
213 pp -> found_level++; | |
214 else | |
215 pp -> skip_level++; | |
216 } | |
217 else if (pp -> found_level) | |
218 { | |
219 pp -> skip_level++; | |
220 pp -> found_level--; | |
221 } | |
222 else | |
223 preproc_throw_error(pp, "#elif in non-conditional section"); | |
224 } | |
225 | |
226 static void dir_else(struct preproc_info *pp) | |
227 { | |
228 if (pp -> skip_level) | |
229 { | |
230 if (pp -> else_skip_level > pp -> found_level) | |
231 ; | |
232 else if (--(pp -> skip_level) != 0) | |
233 pp -> skip_level++; | |
234 else | |
235 pp -> found_level++; | |
236 } | |
237 else if (pp -> found_level) | |
238 { | |
239 pp -> skip_level++; | |
240 pp -> found_level--; | |
241 } | |
242 else | |
243 { | |
244 preproc_throw_error(pp, "#else in non-conditional section"); | |
245 } | |
246 if (pp -> else_level == pp -> found_level + pp -> skip_level) | |
247 { | |
248 preproc_throw_error(pp, "Too many #else"); | |
249 } | |
250 pp -> else_level = pp -> found_level + pp -> skip_level; | |
251 check_eol(pp); | |
252 } | |
253 | |
254 static void dir_endif(struct preproc_info *pp) | |
255 { | |
256 if (pp -> skip_level) | |
257 pp -> skip_level--; | |
258 else if (pp -> found_level) | |
259 pp -> found_level--; | |
260 else | |
261 preproc_throw_error(pp, "#endif in non-conditional section"); | |
262 if (pp -> skip_level == 0) | |
263 pp -> else_skip_level = 0; | |
264 pp -> else_level = 0; | |
265 check_eol(pp); | |
266 } | |
267 | |
268 static void dir_define(struct preproc_info *pp) | |
269 { | |
270 struct token_list *tl = NULL; | |
271 struct token *ct; | |
272 int nargs = -1; | |
273 int vargs = 0; | |
274 char *mname = NULL; | |
275 | |
276 char **arglist = NULL; | |
277 | |
278 if (pp -> skip_level) | |
279 { | |
280 skip_eol(pp); | |
281 return; | |
282 } | |
283 | |
284 ct = preproc_next_token_nws(pp); | |
285 if (ct -> ttype != TOK_IDENT) | |
286 goto baddefine; | |
287 | |
288 mname = lw_strdup(ct -> strval); | |
289 ct = preproc_next_token(pp); | |
290 if (ct -> ttype == TOK_WSPACE) | |
291 { | |
292 /* object like macro */ | |
293 } | |
294 else if (ct -> ttype == TOK_EOL) | |
295 { | |
296 /* object like macro - empty value */ | |
297 goto out; | |
298 } | |
299 else if (ct -> ttype == TOK_OPAREN) | |
300 { | |
301 /* function like macro - parse args */ | |
302 nargs = 0; | |
303 vargs = 0; | |
304 for (;;) | |
305 { | |
306 ct = preproc_next_token_nws(pp); | |
307 if (ct -> ttype == TOK_EOL) | |
308 { | |
309 goto baddefine; | |
310 } | |
311 if (ct -> ttype == TOK_CPAREN) | |
312 break; | |
313 | |
314 if (ct -> ttype == TOK_IDENT) | |
315 { | |
316 /* parameter name */ | |
317 nargs++; | |
318 /* record argument name */ | |
319 arglist = lw_realloc(arglist, sizeof(char *) * nargs); | |
320 arglist[nargs - 1] = lw_strdup(ct -> strval); | |
321 | |
322 /* check for end of args or comma */ | |
323 ct = preproc_next_token_nws(pp); | |
324 if (ct -> ttype == TOK_CPAREN) | |
325 break; | |
326 else if (ct -> ttype == TOK_COMMA) | |
327 continue; | |
328 else | |
329 goto baddefine; | |
330 } | |
331 else if (ct -> ttype == TOK_ELLIPSIS) | |
332 { | |
333 /* variadic macro */ | |
334 vargs = 1; | |
335 ct = preproc_next_token_nws(pp); | |
336 if (ct -> ttype != TOK_CPAREN) | |
337 goto baddefine; | |
338 break; | |
339 } | |
340 else | |
341 goto baddefine; | |
342 } | |
343 } | |
344 else | |
345 { | |
346 baddefine: | |
347 preproc_throw_error(pp, "bad #define", ct -> ttype); | |
348 baddefine2: | |
349 token_list_destroy(tl); | |
350 skip_eol(pp); | |
351 lw_free(mname); | |
352 while (nargs > 0) | |
353 lw_free(arglist[--nargs]); | |
354 lw_free(arglist); | |
355 return; | |
356 } | |
357 | |
358 tl = token_list_create(); | |
359 for (;;) | |
360 { | |
361 ct = preproc_next_token(pp); | |
362 | |
363 if (ct -> ttype == TOK_EOL) | |
364 break; | |
365 token_list_append(tl, token_dup(ct)); | |
366 } | |
367 out: | |
368 if (strcmp(mname, "defined") == 0) | |
369 { | |
370 preproc_throw_warning(pp, "attempt to define 'defined' as a macro not allowed"); | |
371 goto baddefine2; | |
372 } | |
373 else if (symtab_find(pp, mname) != NULL) | |
374 { | |
375 /* need to do a token compare between the old value and the new value | |
376 to decide whether to complain */ | |
377 preproc_throw_warning(pp, "%s previous defined", mname); | |
378 symtab_undef(pp, mname); | |
379 } | |
380 symtab_define(pp, mname, tl, nargs, arglist, vargs); | |
381 lw_free(mname); | |
382 while (nargs > 0) | |
383 lw_free(arglist[--nargs]); | |
384 lw_free(arglist); | |
385 /* no need to check for EOL here */ | |
386 } | |
387 | |
388 void preproc_add_macro(struct preproc_info *pp, char *str) | |
389 { | |
390 char *s; | |
391 | |
392 pp -> lexstr = lw_strdup(str); | |
393 pp -> lexstrloc = 0; | |
394 s = strchr(pp -> lexstr, '='); | |
395 if (s) | |
396 *s = ' '; | |
397 | |
398 dir_define(pp); | |
399 | |
400 lw_free(pp -> lexstr); | |
401 pp -> lexstr = NULL; | |
402 pp -> lexstrloc = 0; | |
403 } | |
404 | |
405 static void dir_undef(struct preproc_info *pp) | |
406 { | |
407 struct token *ct; | |
408 if (pp -> skip_level) | |
409 { | |
410 skip_eol(pp); | |
411 return; | |
412 } | |
413 | |
414 do | |
415 { | |
416 ct = preproc_next_token(pp); | |
417 } while (ct -> ttype == TOK_WSPACE); | |
418 | |
419 if (ct -> ttype != TOK_IDENT) | |
420 { | |
421 preproc_throw_error(pp, "Bad #undef"); | |
422 skip_eol(pp); | |
423 } | |
424 | |
425 symtab_undef(pp, ct -> strval); | |
426 check_eol(pp); | |
427 } | |
428 | |
429 char *streol(struct preproc_info *pp) | |
430 { | |
431 struct lw_strbuf *s; | |
432 struct token *ct; | |
433 int i; | |
434 | |
435 s = lw_strbuf_new(); | |
436 do | |
437 { | |
438 ct = preproc_next_token(pp); | |
439 } while (ct -> ttype == TOK_WSPACE); | |
440 | |
441 while (ct -> ttype != TOK_EOL) | |
442 { | |
443 for (i = 0; ct -> strval[i]; i++) | |
444 lw_strbuf_add(s, ct -> strval[i]); | |
445 ct = preproc_next_token(pp); | |
446 } | |
447 return lw_strbuf_end(s); | |
448 } | |
449 | |
450 static void dir_error(struct preproc_info *pp) | |
451 { | |
452 char *s; | |
453 | |
454 if (pp -> skip_level) | |
455 { | |
456 skip_eol(pp); | |
457 return; | |
458 } | |
459 | |
460 s = streol(pp); | |
461 preproc_throw_error(pp, "%s", s); | |
462 lw_free(s); | |
463 } | |
464 | |
465 static void dir_warning(struct preproc_info *pp) | |
466 { | |
467 char *s; | |
468 | |
469 if (pp -> skip_level) | |
470 { | |
471 skip_eol(pp); | |
472 return; | |
473 } | |
474 | |
475 s = streol(pp); | |
476 preproc_throw_warning(pp, "%s", s); | |
477 lw_free(s); | |
478 } | |
479 | |
480 static char *preproc_file_exists_in_dir(char *dir, char *fn) | |
481 { | |
482 int l; | |
483 char *f; | |
484 | |
485 l = snprintf(NULL, 0, "%s/%s", dir, fn); | |
486 f = lw_alloc(l + 1); | |
487 snprintf(f, l + 1, "%s/%s", dir, fn); | |
488 | |
489 if (access(f, R_OK) == 0) | |
490 return f; | |
491 lw_free(f); | |
492 return NULL; | |
493 } | |
494 | |
495 static char *preproc_find_file(struct preproc_info *pp, char *fn, int sys) | |
496 { | |
497 char *tstr; | |
498 char *pref; | |
499 char *rfn; | |
500 | |
501 /* pass through absolute paths, dumb as they are */ | |
502 if (fn[0] == '/') | |
503 return lw_strdup(fn); | |
504 | |
505 if (!sys) | |
506 { | |
507 /* look in the directory with the current file */ | |
508 tstr = strchr(pp -> fn, '/'); | |
509 if (!tstr) | |
510 pref = lw_strdup("."); | |
511 else | |
512 { | |
513 pref = lw_alloc(tstr - pp -> fn + 1); | |
514 memcpy(pref, pp -> fn, tstr - pp -> fn); | |
515 pref[tstr - pp -> fn] = 0; | |
516 } | |
517 rfn = preproc_file_exists_in_dir(pref, fn); | |
518 lw_free(pref); | |
519 if (rfn) | |
520 return rfn; | |
521 | |
522 /* look in the "quote" dir list */ | |
523 lw_stringlist_reset(pp -> quotelist); | |
524 for (pref = lw_stringlist_current(pp -> quotelist); pref; pref = lw_stringlist_next(pp -> quotelist)) | |
525 { | |
526 rfn = preproc_file_exists_in_dir(pref, fn); | |
527 if (rfn) | |
528 return rfn; | |
529 } | |
530 } | |
531 | |
532 /* look in the "include" dir list */ | |
533 lw_stringlist_reset(pp -> inclist); | |
534 for (pref = lw_stringlist_current(pp -> inclist); pref; pref = lw_stringlist_next(pp -> inclist)) | |
535 { | |
536 rfn = preproc_file_exists_in_dir(pref, fn); | |
537 if (rfn) | |
538 return rfn; | |
539 } | |
540 | |
541 /* the default search list is provided by the driver program */ | |
542 return NULL; | |
543 } | |
544 | |
545 static void dir_include(struct preproc_info *pp) | |
546 { | |
547 FILE *fp; | |
548 struct token *ct; | |
549 int sys = 0; | |
550 char *fn; | |
551 struct lw_strbuf *strbuf; | |
552 int i; | |
553 struct preproc_info *fs; | |
554 | |
555 ct = preproc_next_token_nws(pp); | |
556 if (ct -> ttype == TOK_STR_LIT) | |
557 { | |
558 usrinc: | |
559 sys = strlen(ct -> strval); | |
560 fn = lw_alloc(sys - 1); | |
561 memcpy(fn, ct -> strval + 1, sys - 2); | |
562 fn[sys - 2] = 0; | |
563 sys = 0; | |
564 goto doinc; | |
565 } | |
566 else if (ct -> ttype == TOK_LT) | |
567 { | |
568 strbuf = lw_strbuf_new(); | |
569 for (;;) | |
570 { | |
571 int c; | |
572 c = preproc_lex_fetch_byte(pp); | |
573 if (c == CPP_EOL) | |
574 { | |
575 preproc_lex_unfetch_byte(pp, c); | |
576 preproc_throw_error(pp, "Bad #include"); | |
577 lw_free(lw_strbuf_end(strbuf)); | |
578 break; | |
579 } | |
580 if (c == '>') | |
581 break; | |
582 lw_strbuf_add(strbuf, c); | |
583 } | |
584 ct = preproc_next_token_nws(pp); | |
585 if (ct -> ttype != TOK_EOL) | |
586 { | |
587 preproc_throw_error(pp, "Bad #include"); | |
588 skip_eol(pp); | |
589 lw_free(lw_strbuf_end(strbuf)); | |
590 return; | |
591 } | |
592 sys = 1; | |
593 fn = lw_strbuf_end(strbuf); | |
594 goto doinc; | |
595 } | |
596 else | |
597 { | |
598 preproc_unget_token(pp, ct); | |
599 // computed include | |
600 ct = preproc_next_processed_token_nws(pp); | |
601 if (ct -> ttype == TOK_STR_LIT) | |
602 goto usrinc; | |
603 else if (ct -> ttype == TOK_LT) | |
604 { | |
605 strbuf = lw_strbuf_new(); | |
606 for (;;) | |
607 { | |
608 ct = preproc_next_processed_token(pp); | |
609 if (ct -> ttype == TOK_GT) | |
610 break; | |
611 if (ct -> ttype == TOK_EOL) | |
612 { | |
613 preproc_throw_error(pp, "Bad #include"); | |
614 lw_free(lw_strbuf_end(strbuf)); | |
615 return; | |
616 } | |
617 for (i = 0; ct -> strval[i]; ct++) | |
618 { | |
619 lw_strbuf_add(strbuf, ct -> strval[i]); | |
620 } | |
621 } | |
622 ct = preproc_next_processed_token_nws(pp); | |
623 if (ct -> ttype != TOK_EOL) | |
624 { | |
625 preproc_throw_error(pp, "Bad #include"); | |
626 skip_eol(pp); | |
627 lw_free(lw_strbuf_end(strbuf)); | |
628 return; | |
629 } | |
630 sys = 1; | |
631 fn = lw_strbuf_end(strbuf); | |
632 goto doinc; | |
633 } | |
634 else | |
635 { | |
636 skip_eol(pp); | |
637 preproc_throw_error(pp, "Bad #include"); | |
638 return; | |
639 } | |
640 } | |
641 doinc: | |
642 fn = preproc_find_file(pp, fn, sys); | |
643 if (!fn) | |
644 goto badfile; | |
645 fp = fopen(fn, "rb"); | |
646 if (!fp) | |
647 { | |
648 lw_free(fn); | |
649 badfile: | |
650 preproc_throw_error(pp, "Cannot open #include file %s - this is fatal", fn); | |
651 exit(1); | |
652 } | |
653 | |
654 /* save the current include file state, etc. */ | |
655 fs = lw_alloc(sizeof(struct preproc_info)); | |
656 *fs = *pp; | |
657 fs -> n = pp -> filestack; | |
658 pp -> curtok = NULL; | |
659 pp -> filestack = fs; | |
660 pp -> fn = lw_strpool_strdup(pp -> strpool, fn); | |
661 lw_free(fn); | |
662 pp -> fp = fp; | |
663 pp -> ra = CPP_NOUNG; | |
664 pp -> ppeolseen = 1; | |
665 pp -> eolstate = 0; | |
666 pp -> lineno = 1; | |
667 pp -> column = 0; | |
668 pp -> qseen = 0; | |
669 pp -> ungetbufl = 0; | |
670 pp -> ungetbufs = 0; | |
671 pp -> ungetbuf = NULL; | |
672 pp -> unget = 0; | |
673 pp -> eolseen = 0; | |
674 pp -> nlseen = 0; | |
675 pp -> skip_level = 0; | |
676 pp -> found_level = 0; | |
677 pp -> else_level = 0; | |
678 pp -> else_skip_level = 0; | |
679 pp -> tokqueue = NULL; | |
680 // now get on with processing | |
681 } | |
682 | |
683 static void dir_line(struct preproc_info *pp) | |
684 { | |
685 struct token *ct; | |
686 long lineno; | |
687 char *estr; | |
688 | |
689 lineno = -1; | |
690 | |
691 ct = preproc_next_processed_token_nws(pp); | |
692 if (ct -> ttype == TOK_NUMBER) | |
693 { | |
694 lineno = strtoul(ct -> strval, &estr, 10); | |
695 if (*estr) | |
696 { | |
697 preproc_throw_error(pp, "Bad #line"); | |
698 skip_eol(pp); | |
699 return; | |
700 } | |
701 } | |
702 else | |
703 { | |
704 preproc_throw_error(pp, "Bad #line"); | |
705 skip_eol(pp); | |
706 return; | |
707 } | |
708 ct = preproc_next_processed_token_nws(pp); | |
709 if (ct -> ttype == TOK_EOL) | |
710 { | |
711 pp -> lineno = lineno; | |
712 return; | |
713 } | |
714 if (ct -> ttype != TOK_STR_LIT) | |
715 { | |
716 preproc_throw_error(pp, "Bad #line"); | |
717 skip_eol(pp); | |
718 return; | |
719 } | |
720 estr = lw_strdup(ct -> strval); | |
721 ct = preproc_next_processed_token_nws(pp); | |
722 if (ct -> ttype != TOK_EOL) | |
723 { | |
724 preproc_throw_error(pp, "Bad #line"); | |
725 skip_eol(pp); | |
726 lw_free(estr); | |
727 return; | |
728 } | |
729 pp -> fn = estr; | |
730 pp -> lineno = lineno; | |
731 } | |
732 | |
733 static void dir_pragma(struct preproc_info *pp) | |
734 { | |
735 if (pp -> skip_level) | |
736 { | |
737 skip_eol(pp); | |
738 return; | |
739 } | |
740 | |
741 preproc_throw_warning(pp, "Unsupported #pragma"); | |
742 skip_eol(pp); | |
743 } | |
744 | |
745 struct { char *name; void (*fn)(struct preproc_info *); } dirlist[] = | |
746 { | |
747 { "ifdef", dir_ifdef }, | |
748 { "ifndef", dir_ifndef }, | |
749 { "if", dir_if }, | |
750 { "else", dir_else }, | |
751 { "elif", dir_elif }, | |
752 { "endif", dir_endif }, | |
753 { "define", dir_define }, | |
754 { "undef", dir_undef }, | |
755 { "include", dir_include }, | |
756 { "error", dir_error }, | |
757 { "warning", dir_warning }, | |
758 { "line", dir_line }, | |
759 { "pragma", dir_pragma }, | |
760 { NULL, NULL } | |
761 }; | |
762 | |
763 static void process_directive(struct preproc_info *pp) | |
764 { | |
765 struct token *ct; | |
766 int i; | |
767 | |
768 do | |
769 { | |
770 ct = preproc_next_token(pp); | |
771 } while (ct -> ttype == TOK_WSPACE); | |
772 | |
773 // NULL directive | |
774 if (ct -> ttype == TOK_EOL) | |
775 return; | |
776 | |
777 if (ct -> ttype == TOK_NUMBER) | |
778 { | |
779 // this is probably a file marker from a previous run of the preprocessor | |
780 char *fn; | |
781 struct lw_strbuf *sb; | |
782 | |
783 i = preproc_numval(pp, ct); | |
784 ct = preproc_next_token_nws(pp); | |
785 if (ct -> ttype != TOK_STR_LIT) | |
786 goto baddir; | |
787 pp -> lineno = i; | |
788 sb = lw_strbuf_new(); | |
789 for (fn = ct -> strval; *fn && *fn != '"'; ) | |
790 { | |
791 if (*fn == '\\') | |
792 { | |
793 lw_strbuf_add(sb, eval_escape(&fn)); | |
794 } | |
795 else | |
796 { | |
797 lw_strbuf_add(sb, *fn++); | |
798 } | |
799 } | |
800 fn = lw_strbuf_end(sb); | |
801 pp -> fn = lw_strpool_strdup(pp -> strpool, fn); | |
802 lw_free(fn); | |
803 skip_eol(pp); | |
804 return; | |
805 } | |
806 | |
807 if (ct -> ttype != TOK_IDENT) | |
808 goto baddir; | |
809 | |
810 for (i = 0; dirlist[i].name; i++) | |
811 { | |
812 if (strcmp(dirlist[i].name, ct -> strval) == 0) | |
813 { | |
814 (*(dirlist[i].fn))(pp); | |
815 return; | |
816 } | |
817 } | |
818 baddir: | |
819 preproc_throw_error(pp, "Bad preprocessor directive"); | |
820 while (ct -> ttype != TOK_EOL) | |
821 ct = preproc_next_token(pp); | |
822 return; | |
823 } | |
824 | |
825 /* | |
826 Evaluate a preprocessor expression | |
827 */ | |
828 | |
829 /* same as skip_eol() but the EOL token is not consumed */ | |
830 static void skip_eoe(struct preproc_info *pp) | |
831 { | |
832 skip_eol(pp); | |
833 preproc_unget_token(pp, pp -> curtok); | |
834 } | |
835 | |
836 static long eval_expr_real(struct preproc_info *, int); | |
837 | |
838 static long eval_term_real(struct preproc_info *pp) | |
839 { | |
840 long tval = 0; | |
841 struct token *ct; | |
842 | |
843 eval_next: | |
844 ct = preproc_next_processed_token_nws(pp); | |
845 if (ct -> ttype == TOK_EOL) | |
846 { | |
847 preproc_throw_error(pp, "Bad expression"); | |
848 return 0; | |
849 } | |
850 | |
851 switch (ct -> ttype) | |
852 { | |
853 case TOK_OPAREN: | |
854 tval = eval_expr_real(pp, 0); | |
855 ct = preproc_next_processed_token_nws(pp); | |
856 if (ct -> ttype != ')') | |
857 { | |
858 preproc_throw_error(pp, "Unbalanced () in expression"); | |
859 skip_eoe(pp); | |
860 return 0; | |
861 } | |
862 return tval; | |
863 | |
864 case TOK_ADD: // unary + | |
865 goto eval_next; | |
866 | |
867 case TOK_SUB: // unary - | |
868 tval = eval_expr_real(pp, 200); | |
869 return -tval; | |
870 | |
871 /* NOTE: we should only get "TOK_IDENT" from an undefined macro */ | |
872 case TOK_IDENT: // some sort of function, symbol, etc. | |
873 if (strcmp(ct -> strval, "defined")) | |
874 { | |
875 /* the defined operator */ | |
876 /* any number in the "defined" bit will be | |
877 treated as a defined symbol, even zero */ | |
878 ct = preproc_next_token_nws(pp); | |
879 if (ct -> ttype == TOK_OPAREN) | |
880 { | |
881 ct = preproc_next_token_nws(pp); | |
882 if (ct -> ttype != TOK_IDENT) | |
883 { | |
884 preproc_throw_error(pp, "Bad expression"); | |
885 skip_eoe(pp); | |
886 return 0; | |
887 } | |
888 if (symtab_find(pp, ct -> strval) == NULL) | |
889 tval = 0; | |
890 else | |
891 tval = 1; | |
892 ct = preproc_next_token_nws(pp); | |
893 if (ct -> ttype != TOK_CPAREN) | |
894 { | |
895 preproc_throw_error(pp, "Bad expression"); | |
896 skip_eoe(pp); | |
897 return 0; | |
898 } | |
899 return tval; | |
900 } | |
901 else if (ct -> ttype == TOK_IDENT) | |
902 { | |
903 return (symtab_find(pp, ct -> strval) != NULL) ? 1 : 0; | |
904 } | |
905 preproc_throw_error(pp, "Bad expression"); | |
906 skip_eoe(pp); | |
907 return 0; | |
908 } | |
909 /* unknown identifier - it's zero */ | |
910 return 0; | |
911 | |
912 /* numbers */ | |
913 case TOK_NUMBER: | |
914 return preproc_numval(pp, ct); | |
915 | |
916 default: | |
917 preproc_throw_error(pp, "Bad expression"); | |
918 skip_eoe(pp); | |
919 return 0; | |
920 } | |
921 return 0; | |
922 } | |
923 | |
924 static long eval_expr_real(struct preproc_info *pp, int p) | |
925 { | |
926 static const struct operinfo | |
927 { | |
928 int tok; | |
929 int prec; | |
930 } operators[] = | |
931 { | |
932 { TOK_ADD, 100 }, | |
933 { TOK_SUB, 100 }, | |
934 { TOK_STAR, 150 }, | |
935 { TOK_DIV, 150 }, | |
936 { TOK_MOD, 150 }, | |
937 { TOK_LT, 75 }, | |
938 { TOK_LE, 75 }, | |
939 { TOK_GT, 75 }, | |
940 { TOK_GE, 75 }, | |
941 { TOK_EQ, 70 }, | |
942 { TOK_NE, 70 }, | |
943 { TOK_BAND, 30 }, | |
944 { TOK_BOR, 25 }, | |
945 { TOK_NONE, 0 } | |
946 }; | |
947 | |
948 int op; | |
949 long term1, term2, term3; | |
950 struct token *ct; | |
951 | |
952 term1 = eval_term_real(pp); | |
953 eval_next: | |
954 ct = preproc_next_processed_token_nws(pp); | |
955 for (op = 0; operators[op].tok != TOK_NONE; op++) | |
956 { | |
957 if (operators[op].tok == ct -> ttype) | |
958 break; | |
959 } | |
960 /* if it isn't a recognized operator, assume end of expression */ | |
961 if (operators[op].tok == TOK_NONE) | |
962 { | |
963 preproc_unget_token(pp, ct); | |
964 return term1; | |
965 } | |
966 | |
967 /* if new operation is not higher than the current precedence, let the previous op finish */ | |
968 if (operators[op].prec <= p) | |
969 return term1; | |
970 | |
971 /* get the second term */ | |
972 term2 = eval_expr_real(pp, operators[op].prec); | |
973 | |
974 switch (operators[op].tok) | |
975 { | |
976 case TOK_ADD: | |
977 term3 = term1 + term2; | |
978 break; | |
979 | |
980 case TOK_SUB: | |
981 term3 = term1 - term2; | |
982 break; | |
983 | |
984 case TOK_STAR: | |
985 term3 = term1 * term2; | |
986 break; | |
987 | |
988 case TOK_DIV: | |
989 if (!term2) | |
990 { | |
991 preproc_throw_warning(pp, "Division by zero"); | |
992 term3 = 0; | |
993 break; | |
994 } | |
995 term3 = term1 / term2; | |
996 break; | |
997 | |
998 case TOK_MOD: | |
999 if (!term2) | |
1000 { | |
1001 preproc_throw_warning(pp, "Division by zero"); | |
1002 term3 = 0; | |
1003 break; | |
1004 } | |
1005 term3 = term1 % term2; | |
1006 break; | |
1007 | |
1008 case TOK_BAND: | |
1009 term3 = (term1 && term2); | |
1010 break; | |
1011 | |
1012 case TOK_BOR: | |
1013 term3 = (term1 || term2); | |
1014 break; | |
1015 | |
1016 case TOK_EQ: | |
1017 term3 = (term1 == term2); | |
1018 break; | |
1019 | |
1020 case TOK_NE: | |
1021 term3 = (term1 != term2); | |
1022 break; | |
1023 | |
1024 case TOK_GT: | |
1025 term3 = (term1 > term2); | |
1026 break; | |
1027 | |
1028 case TOK_GE: | |
1029 term3 = (term1 >= term2); | |
1030 break; | |
1031 | |
1032 case TOK_LT: | |
1033 term3 = (term1 < term2); | |
1034 break; | |
1035 | |
1036 case TOK_LE: | |
1037 term3 = (term1 <= term2); | |
1038 break; | |
1039 | |
1040 default: | |
1041 term3 = 0; | |
1042 break; | |
1043 } | |
1044 term1 = term3; | |
1045 goto eval_next; | |
1046 } | |
1047 | |
1048 static long eval_expr(struct preproc_info *pp) | |
1049 { | |
1050 long rv; | |
1051 struct token *t; | |
1052 | |
1053 rv = eval_expr_real(pp, 0); | |
1054 t = preproc_next_token_nws(pp); | |
1055 if (t -> ttype != TOK_EOL) | |
1056 { | |
1057 preproc_throw_error(pp, "Bad expression"); | |
1058 skip_eol(pp); | |
1059 } | |
1060 return rv; | |
1061 } | |
1062 | |
1063 static int eval_escape(char **t) | |
1064 { | |
1065 int c; | |
1066 int c2; | |
1067 | |
1068 if (**t == 0) | |
1069 return 0; | |
1070 c = *(*t)++; | |
1071 int rv = 0; | |
1072 | |
1073 switch (c) | |
1074 { | |
1075 case 'n': | |
1076 return 10; | |
1077 case 'r': | |
1078 return 13; | |
1079 case 'b': | |
1080 return 8; | |
1081 case 'e': | |
1082 return 27; | |
1083 case 'f': | |
1084 return 12; | |
1085 case 't': | |
1086 return 9; | |
1087 case 'v': | |
1088 return 11; | |
1089 case 'a': | |
1090 return 7; | |
1091 case '0': case '1': case '2': case '3': case '4': | |
1092 case '5': case '6': case '7': | |
1093 // octal constant | |
1094 rv = c - '0'; | |
1095 c2 = 1; | |
1096 for (; c2 < 3; c2++) | |
1097 { | |
1098 c = *(*t)++; | |
1099 if (c < '0' || c > '7') | |
1100 break; | |
1101 rv = (rv << 3) | (c - '0'); | |
1102 } | |
1103 return rv; | |
1104 case 'x': | |
1105 // hex constant | |
1106 for (;;) | |
1107 { | |
1108 c = *(*t)++; | |
1109 if (c < '0' || (c > '9' && c < 'A') || (c > 'F' && c < 'a') || c > 'f') | |
1110 break; | |
1111 c = c - '0'; | |
1112 if (c > 9) | |
1113 c -= 7; | |
1114 if (c > 15) | |
1115 c -= 32; | |
1116 rv = (rv << 4) | c; | |
1117 } | |
1118 return rv & 0xff; | |
1119 default: | |
1120 return c; | |
1121 } | |
1122 } | |
1123 | |
1124 /* convert a numeric string to a number */ | |
1125 long preproc_numval(struct preproc_info *pp, struct token *t) | |
1126 { | |
1127 unsigned long long rv = 0; | |
1128 unsigned long long rv2 = 0; | |
1129 char *tstr = t -> strval; | |
1130 int radix = 10; | |
1131 int c; | |
1132 int ovf = 0; | |
1133 union { long sv; unsigned long uv; } tv; | |
1134 | |
1135 if (t -> ttype == TOK_CHR_LIT) | |
1136 { | |
1137 tstr++; | |
1138 while (*tstr && *tstr != '\'') | |
1139 { | |
1140 if (*tstr == '\\') | |
1141 { | |
1142 tstr++; | |
1143 c = eval_escape(&tstr); | |
1144 } | |
1145 else | |
1146 c = *tstr++; | |
1147 rv = (rv << 8) | c; | |
1148 if (rv / radix < rv2) | |
1149 ovf = 1; | |
1150 rv2 = rv; | |
1151 | |
1152 } | |
1153 goto done; | |
1154 } | |
1155 | |
1156 | |
1157 if (*tstr == '0') | |
1158 { | |
1159 radix = 8; | |
1160 tstr++; | |
1161 if (*tstr == 'x') | |
1162 { | |
1163 radix = 16; | |
1164 tstr++; | |
1165 } | |
1166 } | |
1167 while (*tstr) | |
1168 { | |
1169 c = *tstr++; | |
1170 if (c < '0' || (c > '9' && c < 'A') || (c > 'F' && c < 'a') || c > 'f') | |
1171 break; | |
1172 c -= '0'; | |
1173 if (c > 9) | |
1174 c -= 7; | |
1175 if (c > 15) | |
1176 c -= 32; | |
1177 if (c >= radix) | |
1178 break; | |
1179 rv = rv * radix + c; | |
1180 if (rv / radix < rv2) | |
1181 ovf = 1; | |
1182 rv2 = rv; | |
1183 } | |
1184 tstr--; | |
1185 while (*tstr == 'l' || *tstr == 'L') | |
1186 tstr++; | |
1187 tv.uv = rv; | |
1188 if (tv.sv < 0 && radix == 10) | |
1189 ovf = 1; | |
1190 done: | |
1191 if (ovf) | |
1192 preproc_throw_error(pp, "Constant out of range: %s", t -> strval); | |
1193 return rv; | |
1194 } | |
1195 | |
1196 /* | |
1197 Below here is the logic for expanding a macro | |
1198 */ | |
1199 static char *stringify(struct token_list *tli) | |
1200 { | |
1201 struct lw_strbuf *s; | |
1202 int ws = 0; | |
1203 struct token *tl = tli -> head; | |
1204 | |
1205 s = lw_strbuf_new(); | |
1206 lw_strbuf_add(s, '"'); | |
1207 | |
1208 while (tl && tl -> ttype == TOK_WSPACE) | |
1209 tl = tl -> next; | |
1210 | |
1211 for (; tl; tl = tl -> next) | |
1212 { | |
1213 if (tl -> ttype == TOK_WSPACE) | |
1214 { | |
1215 ws = 1; | |
1216 continue; | |
1217 } | |
1218 if (ws) | |
1219 { | |
1220 lw_strbuf_add(s, ' '); | |
1221 } | |
1222 for (ws = 0; tl -> strval[ws]; ws++) | |
1223 { | |
1224 if (tl -> ttype == TOK_STR_LIT || tl -> ttype == TOK_CHR_LIT) | |
1225 { | |
1226 if (tl -> strval[ws] == '"' || tl -> strval[ws] == '\\') | |
1227 lw_strbuf_add(s, '\\'); | |
1228 } | |
1229 } | |
1230 ws = 0; | |
1231 } | |
1232 | |
1233 lw_strbuf_add(s, '"'); | |
1234 return lw_strbuf_end(s); | |
1235 } | |
1236 | |
1237 static int macro_arg(struct symtab_e *s, char *str) | |
1238 { | |
1239 int i; | |
1240 if (strcmp(str, "__VA_ARGS__") == 0) | |
1241 i = s -> nargs; | |
1242 else | |
1243 for (i = 0; i < s -> nargs; i++) | |
1244 if (strcmp(s -> params[i], str) == 0) | |
1245 break; | |
1246 if (i == s -> nargs) | |
1247 if (s -> vargs == 0) | |
1248 return -1; | |
1249 return i; | |
1250 } | |
1251 | |
1252 /* return list to tokens as a result of ## expansion */ | |
1253 static struct token_list *paste_tokens(struct preproc_info *pp, struct symtab_e *s, struct token_list **arglist, struct token *t1, struct token *t2) | |
1254 { | |
1255 struct token_list *left; | |
1256 struct token_list *right; | |
1257 char *tstr; | |
1258 struct token *ttok; | |
1259 int i; | |
1260 | |
1261 if (t1 -> ttype == TOK_IDENT) | |
1262 { | |
1263 i = macro_arg(s, t1 -> strval); | |
1264 if (i == -1) | |
1265 { | |
1266 left = token_list_create(); | |
1267 token_list_append(left, token_dup(t1)); | |
1268 } | |
1269 else | |
1270 { | |
1271 left = token_list_dup(arglist[i]); | |
1272 } | |
1273 } | |
1274 else | |
1275 { | |
1276 left = token_list_create(); | |
1277 token_list_append(left, token_dup(t1)); | |
1278 } | |
1279 // munch trailing white space | |
1280 while (left -> tail && left -> tail -> ttype == TOK_WSPACE) | |
1281 { | |
1282 token_list_remove(left -> tail); | |
1283 } | |
1284 | |
1285 if (t2 -> ttype == TOK_IDENT) | |
1286 { | |
1287 i = macro_arg(s, t2 -> strval); | |
1288 if (i == -1) | |
1289 { | |
1290 right = token_list_create(); | |
1291 token_list_append(right, token_dup(t2)); | |
1292 } | |
1293 else | |
1294 { | |
1295 right = token_list_dup(arglist[i]); | |
1296 } | |
1297 } | |
1298 else | |
1299 { | |
1300 right = token_list_create(); | |
1301 token_list_append(right, token_dup(t2)); | |
1302 } | |
1303 // munch leading white space | |
1304 while (right -> head && right -> head -> ttype == TOK_WSPACE) | |
1305 { | |
1306 token_list_remove(right -> head); | |
1307 } | |
1308 | |
1309 // nothing to append at all | |
1310 if (left -> head != NULL && right -> head == NULL) | |
1311 { | |
1312 // right arg is empty - use left | |
1313 token_list_destroy(right); | |
1314 return left; | |
1315 } | |
1316 if (left -> head == NULL && right -> head != NULL) | |
1317 { | |
1318 // left arg is empty, use right | |
1319 token_list_destroy(left); | |
1320 return right; | |
1321 } | |
1322 if (left -> head == NULL && right -> head == NULL) | |
1323 { | |
1324 // both empty, use left | |
1325 token_list_destroy(right); | |
1326 return left; | |
1327 } | |
1328 | |
1329 // both non-empty - past left tail with right head | |
1330 // then past the right list onto the left | |
1331 tstr = lw_alloc(strlen(left -> tail -> strval) + strlen(right -> head -> strval) + 1); | |
1332 strcpy(tstr, left -> tail -> strval); | |
1333 strcat(tstr, right -> head -> strval); | |
1334 | |
1335 pp -> lexstr = tstr; | |
1336 pp -> lexstrloc = 0; | |
1337 | |
1338 ttok = preproc_lex_next_token(pp); | |
1339 if (ttok -> ttype != TOK_ERROR && pp -> lexstr[pp -> lexstrloc] == 0) | |
1340 { | |
1341 // we have a new token here | |
1342 token_list_remove(left -> tail); | |
1343 token_list_remove(right -> head); | |
1344 token_list_append(left, token_dup(ttok)); | |
1345 } | |
1346 lw_free(tstr); | |
1347 pp -> lexstr = NULL; | |
1348 pp -> lexstrloc = 0; | |
1349 for (ttok = right -> head; ttok; ttok = ttok -> next) | |
1350 { | |
1351 token_list_append(left, token_dup(ttok)); | |
1352 } | |
1353 token_list_destroy(right); | |
1354 return left; | |
1355 } | |
1356 | |
1357 static int expand_macro(struct preproc_info *pp, char *mname) | |
1358 { | |
1359 struct symtab_e *s; | |
1360 struct token *t, *t2, *t3; | |
1361 int nargs = 0; | |
1362 struct expand_e *e; | |
1363 struct token_list **exparglist = NULL; | |
1364 struct token_list **arglist = NULL; | |
1365 int i; | |
1366 int pcount; | |
1367 char *tstr; | |
1368 struct token_list *expand_list; | |
1369 int repl; | |
1370 struct token_list *rtl; | |
1371 | |
1372 // check for built in macros | |
1373 if (strcmp(mname, "__FILE__") == 0) | |
1374 { | |
1375 struct lw_strbuf *sb; | |
1376 | |
1377 sb = lw_strbuf_new(); | |
1378 lw_strbuf_add(sb, '"'); | |
1379 for (tstr = (char *)(pp -> fn); *tstr; tstr++) | |
1380 { | |
1381 if (*tstr == 32 || (*tstr > 34 && *tstr < 127)) | |
1382 { | |
1383 lw_strbuf_add(sb, *tstr); | |
1384 } | |
1385 else | |
1386 { | |
1387 lw_strbuf_add(sb, '\\'); | |
1388 lw_strbuf_add(sb, (*tstr >> 6) + '0'); | |
1389 lw_strbuf_add(sb, ((*tstr >> 3) & 7) + '0'); | |
1390 lw_strbuf_add(sb, (*tstr & 7) + '0'); | |
1391 } | |
1392 } | |
1393 lw_strbuf_add(sb, '"'); | |
1394 tstr = lw_strbuf_end(sb); | |
1395 preproc_unget_token(pp, token_create(TOK_STR_LIT, tstr, pp -> lineno, pp -> column, pp -> fn)); | |
1396 lw_free(tstr); | |
1397 return 1; | |
1398 } | |
1399 else if (strcmp(mname, "__LINE__") == 0) | |
1400 { | |
1401 char nbuf[25]; | |
1402 snprintf(nbuf, 25, "%d", pp -> lineno); | |
1403 preproc_unget_token(pp, token_create(TOK_NUMBER, nbuf, pp -> lineno, pp -> column, pp -> fn)); | |
1404 return 1; | |
1405 } | |
1406 else if (strcmp(mname, "__DATE__") == 0) | |
1407 { | |
1408 char dbuf[14]; | |
1409 struct tm *tv; | |
1410 time_t tm; | |
1411 static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; | |
1412 | |
1413 tm = time(NULL); | |
1414 tv = localtime(&tm); | |
1415 snprintf(dbuf, 14, "\"%s %2d %04d\"", months[tv -> tm_mon], tv -> tm_mday, tv -> tm_year + 1900); | |
1416 preproc_unget_token(pp, token_create(TOK_STR_LIT, dbuf, pp -> lineno, pp -> column, pp -> fn)); | |
1417 return 1; | |
1418 } | |
1419 else if (strcmp(mname, "__TIME__") == 0) | |
1420 { | |
1421 char tbuf[11]; | |
1422 struct tm *tv; | |
1423 time_t tm; | |
1424 | |
1425 tm = time(NULL); | |
1426 tv = localtime(&tm); | |
1427 snprintf(tbuf, 11, "\"%02d:%02d:%02d\"", tv -> tm_hour, tv -> tm_min, tv -> tm_sec); | |
1428 preproc_unget_token(pp, token_create(TOK_STR_LIT, tbuf, pp -> lineno, pp -> column, pp -> fn)); | |
1429 return 1; | |
1430 } | |
1431 | |
1432 s = symtab_find(pp, mname); | |
1433 if (!s) | |
1434 return 0; | |
1435 | |
1436 for (e = pp -> expand_list; e; e = e -> next) | |
1437 { | |
1438 /* don't expand if we're already expanding the same macro */ | |
1439 if (e -> s == s) | |
1440 return 0; | |
1441 } | |
1442 | |
1443 if (s -> nargs == -1) | |
1444 { | |
1445 /* short circuit NULL expansion */ | |
1446 if (s -> tl == NULL) | |
1447 return 1; | |
1448 | |
1449 goto expandmacro; | |
1450 } | |
1451 | |
1452 // look for opening paren after optional whitespace | |
1453 t2 = NULL; | |
1454 t = NULL; | |
1455 for (;;) | |
1456 { | |
1457 t = preproc_next_token(pp); | |
1458 if (t -> ttype != TOK_WSPACE && t -> ttype != TOK_EOL) | |
1459 break; | |
1460 t -> next = t2; | |
1461 t2 = t2; | |
1462 } | |
1463 if (t -> ttype != TOK_OPAREN) | |
1464 { | |
1465 // not a function-like invocation | |
1466 while (t2) | |
1467 { | |
1468 t = t2 -> next; | |
1469 preproc_unget_token(pp, t2); | |
1470 t2 = t; | |
1471 } | |
1472 return 0; | |
1473 } | |
1474 | |
1475 // parse parameters here | |
1476 t = preproc_next_token_nws(pp); | |
1477 nargs = 1; | |
1478 arglist = lw_alloc(sizeof(struct token_list *)); | |
1479 arglist[0] = token_list_create(); | |
1480 t2 = NULL; | |
1481 | |
1482 while (t -> ttype != TOK_CPAREN) | |
1483 { | |
1484 pcount = 0; | |
1485 if (t -> ttype == TOK_EOF) | |
1486 { | |
1487 preproc_throw_error(pp, "Unexpected EOF in macro call"); | |
1488 break; | |
1489 } | |
1490 if (t -> ttype == TOK_EOL) | |
1491 continue; | |
1492 if (t -> ttype == TOK_OPAREN) | |
1493 pcount++; | |
1494 else if (t -> ttype == TOK_CPAREN && pcount) | |
1495 pcount--; | |
1496 if (t -> ttype == TOK_COMMA && pcount == 0) | |
1497 { | |
1498 if (!(s -> vargs) || (nargs > s -> nargs)) | |
1499 { | |
1500 nargs++; | |
1501 arglist = lw_realloc(arglist, sizeof(struct token_list *) * nargs); | |
1502 arglist[nargs - 1] = token_list_create(); | |
1503 t2 = NULL; | |
1504 continue; | |
1505 } | |
1506 } | |
1507 token_list_append(arglist[nargs - 1], token_dup(t)); | |
1508 } | |
1509 | |
1510 if (s -> vargs) | |
1511 { | |
1512 if (nargs <= s -> nargs) | |
1513 { | |
1514 preproc_throw_error(pp, "Wrong number of arguments (%d) for variadic macro %s which takes %d arguments", nargs, mname, s -> nargs); | |
1515 } | |
1516 } | |
1517 else | |
1518 { | |
1519 if (s -> nargs != nargs && !(s -> nargs == 0 && nargs == 1 && arglist[nargs - 1])) | |
1520 { | |
1521 preproc_throw_error(pp, "Wrong number of arguments (%d) for macro %s which takes %d arguments", nargs, mname, s -> nargs); | |
1522 } | |
1523 } | |
1524 | |
1525 /* now calculate the pre-expansions of the arguments */ | |
1526 exparglist = lw_alloc(nargs * sizeof(struct token_list *)); | |
1527 for (i = 0; i < nargs; i++) | |
1528 { | |
1529 exparglist[i] = token_list_create(); | |
1530 // NOTE: do nothing if empty argument | |
1531 if (arglist[i] == NULL || arglist[i] -> head == NULL) | |
1532 continue; | |
1533 pp -> sourcelist = arglist[i]->head; | |
1534 for (;;) | |
1535 { | |
1536 t = preproc_next_processed_token(pp); | |
1537 if (t -> ttype == TOK_EOF) | |
1538 break; | |
1539 token_list_append(exparglist[i], token_dup(t)); | |
1540 } | |
1541 } | |
1542 | |
1543 expandmacro: | |
1544 expand_list = token_list_dup(s -> tl); | |
1545 | |
1546 // scan for stringification and handle it | |
1547 repl = 0; | |
1548 while (repl == 0) | |
1549 { | |
1550 for (t = expand_list -> head; t; t = t -> next) | |
1551 { | |
1552 if (t -> ttype == TOK_HASH && t -> next && t -> next -> ttype == TOK_IDENT) | |
1553 { | |
1554 i = macro_arg(s, t -> next -> strval); | |
1555 if (i != -1) | |
1556 { | |
1557 repl = 1; | |
1558 tstr = stringify(arglist[i]); | |
1559 token_list_remove(t -> next); | |
1560 token_list_insert(expand_list, t, token_create(TOK_STR_LIT, tstr, t -> lineno, t -> column, t -> fn)); | |
1561 token_list_remove(t); | |
1562 lw_free(tstr); | |
1563 break; | |
1564 } | |
1565 } | |
1566 } | |
1567 repl = 1; | |
1568 } | |
1569 | |
1570 | |
1571 // scan for concatenation and handle it | |
1572 | |
1573 for (t = expand_list -> head; t; t = t -> next) | |
1574 { | |
1575 if (t -> ttype == TOK_DBLHASH) | |
1576 { | |
1577 // have a concatenation operator here | |
1578 for (t2 = t -> prev; t2; t2 = t2 -> prev) | |
1579 { | |
1580 if (t2 -> ttype != TOK_WSPACE) | |
1581 break; | |
1582 } | |
1583 for (t3 = t -> next; t3; t3 = t3 -> next) | |
1584 { | |
1585 if (t3 -> ttype != TOK_WSPACE) | |
1586 break; | |
1587 } | |
1588 // if no non-whitespace before or after, ignore it | |
1589 if (!t2 || !t3) | |
1590 continue; | |
1591 // eat the whitespace before and after | |
1592 while (t -> prev != t2) | |
1593 token_list_remove(t -> prev); | |
1594 while (t -> next != t3) | |
1595 token_list_remove(t -> next); | |
1596 // now paste t -> prev with t -> next and replace t with the result | |
1597 // continue scanning for ## at t -> next -> next | |
1598 t3 = t -> next -> next; | |
1599 | |
1600 rtl = paste_tokens(pp, s, arglist, t -> prev, t -> next); | |
1601 token_list_remove(t -> next); | |
1602 token_list_remove(t -> prev); | |
1603 t2 = t -> prev; | |
1604 token_list_remove(t); | |
1605 for (t = rtl -> head; t; t = t -> next) | |
1606 { | |
1607 token_list_insert(expand_list, t2, token_dup(t)); | |
1608 } | |
1609 t = t3 -> prev; | |
1610 token_list_destroy(rtl); | |
1611 } | |
1612 } | |
1613 | |
1614 // now scan for arguments and expand them | |
1615 for (t = expand_list -> head; t; t = t -> next) | |
1616 { | |
1617 again: | |
1618 if (t -> ttype == TOK_IDENT) | |
1619 { | |
1620 /* identifiers might need expansion to arguments */ | |
1621 i = macro_arg(s, t -> strval); | |
1622 if (i != -1) | |
1623 { | |
1624 t3 = t -> next; | |
1625 for (t2 = exparglist[i] -> tail; t2; t2 = t2 -> prev) | |
1626 token_list_insert(expand_list, t, token_dup(t2)); | |
1627 token_list_remove(t); | |
1628 t = t3; | |
1629 goto again; | |
1630 } | |
1631 } | |
1632 } | |
1633 | |
1634 /* put the new expansion in front of the input, if relevant; if we | |
1635 expanded to nothing, no need to create an expansion record or | |
1636 put anything into the input queue */ | |
1637 if (expand_list -> head) | |
1638 { | |
1639 token_list_append(expand_list, token_create(TOK_ENDEXPAND, "", -1, -1, "")); | |
1640 | |
1641 // move the expanded list into the token queue | |
1642 for (t = expand_list -> tail; t; t = t -> prev) | |
1643 preproc_unget_token(pp, token_dup(t)); | |
1644 | |
1645 /* set up expansion record */ | |
1646 e = lw_alloc(sizeof(struct expand_e)); | |
1647 e -> next = pp -> expand_list; | |
1648 pp -> expand_list = e; | |
1649 e -> s = s; | |
1650 } | |
1651 | |
1652 /* now clean up */ | |
1653 token_list_destroy(expand_list); | |
1654 for (i = 0; i < nargs; i++) | |
1655 { | |
1656 token_list_destroy(arglist[i]); | |
1657 token_list_destroy(exparglist[i]); | |
1658 } | |
1659 lw_free(arglist); | |
1660 lw_free(exparglist); | |
1661 | |
1662 return 1; | |
1663 } | |
1664 | |
1665 struct token *preproc_next(struct preproc_info *pp) | |
1666 { | |
1667 struct token *t; | |
1668 | |
1669 t = preproc_next_processed_token(pp); | |
1670 pp -> curtok = NULL; | |
1671 return t; | |
1672 } |