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 }