gen: move the management of ds[] to gen.c
[neatcc.git] / cpp.c
blob3a27589dc78235cdc7dcc561781113bdb42b5612
1 #include <ctype.h>
2 #include <fcntl.h>
3 #include <stdarg.h>
4 #include <stddef.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include "ncc.h"
12 #include "tab.h"
13 #include "tok.h"
15 static char *buf;
16 static int len;
17 static int cur;
19 static struct macro {
20 char name[NAMELEN];
21 char def[MACROLEN];
22 char args[NARGS][NAMELEN];
23 int nargs;
24 int isfunc;
25 } macros[NDEFS];
26 static int nmacros;
27 /* macro hash table */
28 static struct tab mtab;
30 #define BUF_FILE 0
31 #define BUF_MACRO 1
32 #define BUF_ARG 2
33 #define BUF_EVAL 3
34 #define BUF_TEMP 4
36 static struct buf {
37 char *buf;
38 int len;
39 int cur;
40 int type;
41 /* for BUF_FILE */
42 char path[NAMELEN];
43 /* for BUF_MACRO */
44 struct macro *macro;
45 char args[NARGS][MACROLEN]; /* arguments passed to a macro */
46 /* for BUF_ARG */
47 int arg_buf; /* the bufs index of the owning macro */
48 } bufs[NBUFS];
49 static int nbufs;
50 static int bufs_limit = 1; /* cpp_read() limit; useful in cpp_eval() */
52 void die(char *fmt, ...)
54 va_list ap;
55 char msg[512];
56 va_start(ap, fmt);
57 vsprintf(msg, fmt, ap);
58 va_end(ap);
59 write(2, msg, strlen(msg));
60 exit(1);
63 static void buf_new(int type, char *dat, int dlen)
65 if (nbufs) {
66 bufs[nbufs - 1].buf = buf;
67 bufs[nbufs - 1].cur = cur;
68 bufs[nbufs - 1].len = len;
70 if (nbufs >= NBUFS)
71 die("nomem: NBUFS reached!\n");
72 nbufs++;
73 cur = 0;
74 buf = dat;
75 len = dlen;
76 bufs[nbufs - 1].type = type;
79 static void buf_file(char *path, char *dat, int dlen)
81 buf_new(BUF_FILE, dat, dlen);
82 strcpy(bufs[nbufs - 1].path, path ? path : "");
85 static void buf_macro(struct macro *m)
87 buf_new(BUF_MACRO, m->def, strlen(m->def));
88 bufs[nbufs - 1].macro = m;
91 static void buf_arg(char *arg, int mbuf)
93 buf_new(BUF_ARG, arg, strlen(arg));
94 bufs[nbufs - 1].arg_buf = mbuf;
97 static void buf_pop(void)
99 nbufs--;
100 if (nbufs) {
101 cur = bufs[nbufs - 1].cur;
102 len = bufs[nbufs - 1].len;
103 buf = bufs[nbufs - 1].buf;
107 static int buf_iseval(void)
109 int i;
110 for (i = nbufs - 1; i >= 0; i--)
111 if (bufs[i].type == BUF_EVAL)
112 return 1;
113 return 0;
116 static size_t file_size(int fd)
118 struct stat st;
119 if (!fstat(fd, &st))
120 return st.st_size;
121 return 0;
124 static int include_file(char *path)
126 int fd = open(path, O_RDONLY);
127 int n = 0, nr = 0;
128 char *dat;
129 int size;
130 if (fd == -1)
131 return -1;
132 size = file_size(fd) + 1;
133 dat = malloc(size);
134 while ((n = read(fd, dat + nr, size - nr)) > 0)
135 nr += n;
136 close(fd);
137 dat[nr] = '\0';
138 buf_file(path, dat, nr);
139 return 0;
142 int cpp_init(char *path)
144 return include_file(path);
147 static int jumpws(void)
149 int old = cur;
150 while (cur < len && isspace(buf[cur]))
151 cur++;
152 return cur == old;
155 static void read_word(char *dst)
157 jumpws();
158 while (cur < len && (isalnum(buf[cur]) || buf[cur] == '_'))
159 *dst++ = buf[cur++];
160 *dst = '\0';
163 static int jumpcomment(void)
165 if (buf[cur] == '/' && buf[cur + 1] == '*') {
166 while (++cur < len) {
167 if (buf[cur] == '*' && buf[cur + 1] == '/') {
168 cur += 2;
169 return 0;
173 if (buf[cur] == '/' && buf[cur + 1] == '/') {
174 while (++cur < len)
175 if (buf[cur] == '\n')
176 break;
177 return 0;
179 return 1;
182 static int jumpstr(void)
184 if (buf[cur] == '\'') {
185 while (cur < len && buf[++cur] != '\'')
186 if (buf[cur] == '\\')
187 cur++;
188 cur++;
189 return 0;
191 if (buf[cur] == '"') {
192 while (cur < len && buf[++cur] != '"')
193 if (buf[cur] == '\\')
194 cur++;
195 cur++;
196 return 0;
198 return 1;
201 static void read_tilleol(char *dst)
203 while (cur < len && isspace(buf[cur]) && buf[cur] != '\n')
204 cur++;
205 while (cur < len && buf[cur] != '\n') {
206 int last = cur;
207 if (buf[cur] == '\\' && buf[cur + 1] == '\n') {
208 cur += 2;
209 continue;
211 if (!jumpstr()) {
212 memcpy(dst, buf + last, cur - last);
213 dst += cur - last;
214 continue;
216 if (!jumpcomment())
217 continue;
218 *dst++ = buf[cur++];
220 *dst = '\0';
223 static char *putstr(char *d, char *s)
225 while (*s)
226 *d++ = *s++;
227 *d = '\0';
228 return d;
231 static char *locs[NLOCS] = {};
232 static int nlocs = 0;
234 void cpp_addpath(char *s)
236 locs[nlocs++] = s;
239 static int include_find(char *name, int std)
241 int i;
242 for (i = std ? nlocs - 1 : nlocs; i >= 0; i--) {
243 char path[1 << 10];
244 char *s;
245 s = path;
246 if (locs[i]) {
247 s = putstr(s, locs[i]);
248 *s++ = '/';
250 s = putstr(s, name);
251 if (!include_file(path))
252 return 0;
254 return -1;
257 static void readarg(char *s)
259 int depth = 0;
260 int beg = cur;
261 while (cur < len && (depth || (buf[cur] != ',' && buf[cur] != ')'))) {
262 if (!jumpstr() || !jumpcomment())
263 continue;
264 switch (buf[cur++]) {
265 case '(':
266 case '[':
267 case '{':
268 depth++;
269 break;
270 case ')':
271 case ']':
272 case '}':
273 depth--;
274 break;
277 if (s) {
278 memcpy(s, buf + beg, cur - beg);
279 s[cur - beg] = '\0';
283 static int macro_find(char *name)
285 char *n = tab_get(&mtab, name);
286 if (!n)
287 return -1;
288 return container(n, struct macro, name) - macros;
291 static void macro_undef(char *name)
293 int i = macro_find(name);
294 if (i >= 0)
295 tab_del(&mtab, macros[i].name);
298 static int macro_new(char *name)
300 int i = macro_find(name);
301 if (i >= 0)
302 return i;
303 if (nmacros >= NDEFS)
304 die("nomem: NDEFS reached!\n");
305 i = nmacros++;
306 strcpy(macros[i].name, name);
307 tab_add(&mtab, macros[i].name);
308 return i;
311 static void macro_define(void)
313 char name[NAMELEN];
314 struct macro *d;
315 read_word(name);
316 d = &macros[macro_new(name)];
317 d->isfunc = 0;
318 d->nargs = 0;
319 if (buf[cur] == '(') {
320 cur++;
321 jumpws();
322 while (cur < len && buf[cur] != ')') {
323 readarg(d->args[d->nargs++]);
324 jumpws();
325 if (buf[cur] != ',')
326 break;
327 cur++;
328 jumpws();
330 cur++;
331 d->isfunc = 1;
333 read_tilleol(d->def);
336 int cpp_read(char *buf);
338 static char ebuf[BUFLEN];
339 static int elen;
340 static int ecur;
342 static long evalexpr(void);
344 static int cpp_eval(void)
346 char evalbuf[BUFLEN];
347 int old_limit;
348 int ret, nr;
349 read_tilleol(evalbuf);
350 buf_new(BUF_EVAL, evalbuf, strlen(evalbuf));
351 elen = 0;
352 ecur = 0;
353 old_limit = bufs_limit;
354 bufs_limit = nbufs;
355 while ((nr = cpp_read(ebuf + elen)) >= 0)
356 elen += nr;
357 bufs_limit = old_limit;
358 ret = evalexpr();
359 buf_pop();
360 return ret;
363 static void jumpifs(int jumpelse)
365 int depth = 0;
366 while (cur < len) {
367 if (buf[cur] == '#') {
368 char cmd[NAMELEN];
369 cur++;
370 read_word(cmd);
371 if (!strcmp("else", cmd))
372 if (!depth && !jumpelse)
373 break;
374 if (!strcmp("elif", cmd))
375 if (!depth && !jumpelse && cpp_eval())
376 break;
377 if (!strcmp("endif", cmd)) {
378 if (!depth)
379 break;
380 else
381 depth--;
383 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd) ||
384 !strcmp("if", cmd))
385 depth++;
386 continue;
388 if (!jumpcomment())
389 continue;
390 if (!jumpstr())
391 continue;
392 cur++;
396 static int cpp_cmd(void)
398 char cmd[NAMELEN];
399 cur++;
400 read_word(cmd);
401 if (!strcmp("define", cmd)) {
402 macro_define();
403 return 0;
405 if (!strcmp("undef", cmd)) {
406 char name[NAMELEN];
407 read_word(name);
408 macro_undef(name);
409 return 0;
411 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd) ||
412 !strcmp("if", cmd)) {
413 char name[NAMELEN];
414 int matched = 0;
415 if (cmd[2]) {
416 int not = cmd[2] == 'n';
417 read_word(name);
418 matched = not ? macro_find(name) < 0 :
419 macro_find(name) >= 0;
420 } else {
421 matched = cpp_eval();
423 if (!matched)
424 jumpifs(0);
425 return 0;
427 if (!strcmp("else", cmd) || !strcmp("elif", cmd)) {
428 jumpifs(1);
429 return 0;
431 if (!strcmp("endif", cmd))
432 return 0;
433 if (!strcmp("include", cmd)) {
434 char file[NAMELEN];
435 char *s, *e;
436 jumpws();
437 s = buf + cur + 1;
438 e = strchr(buf + cur + 1, buf[cur] == '"' ? '"' : '>');
439 memcpy(file, s, e - s);
440 file[e - s] = '\0';
441 cur += e - s + 2;
442 if (include_find(file, *e == '>') == -1)
443 err("cannot include <%s>\n", file);
444 return 0;
446 return 1;
449 static int macro_arg(struct macro *m, char *arg)
451 int i;
452 for (i = 0; i < m->nargs; i++)
453 if (!strcmp(arg, m->args[i]))
454 return i;
455 return -1;
458 static int buf_arg_find(char *name)
460 int i;
461 for (i = nbufs - 1; i >= 0; i--) {
462 struct buf *mbuf = &bufs[i];
463 struct macro *m = mbuf->macro;
464 if (mbuf->type == BUF_MACRO && macro_arg(m, name) >= 0)
465 return i;
466 if (mbuf->type == BUF_ARG)
467 i = mbuf->arg_buf;
469 return -1;
472 static void macro_expand(char *name)
474 struct macro *m;
475 int mbuf;
476 if ((mbuf = buf_arg_find(name)) >= 0) {
477 int arg = macro_arg(bufs[mbuf].macro, name);
478 char *dat = bufs[mbuf].args[arg];
479 buf_arg(dat, mbuf);
480 return;
482 m = &macros[macro_find(name)];
483 if (!m->isfunc) {
484 buf_macro(m);
485 return;
487 jumpws();
488 if (buf[cur] == '(') {
489 int i = 0;
490 struct buf *mbuf = &bufs[nbufs];
491 cur++;
492 jumpws();
493 while (cur < len && buf[cur] != ')') {
494 readarg(mbuf->args[i++]);
495 jumpws();
496 if (buf[cur] != ',')
497 break;
498 cur++;
499 jumpws();
501 while (i < m->nargs)
502 mbuf->args[i++][0] = '\0';
503 cur++;
504 buf_macro(m);
508 static int buf_expanding(char *macro)
510 int i;
511 for (i = nbufs - 1; i >= 0; i--) {
512 if (bufs[i].type == BUF_ARG)
513 return 0;
514 if (bufs[i].type == BUF_MACRO &&
515 !strcmp(macro, bufs[i].macro->name))
516 return 1;
518 return 0;
521 /* return 1 for plain macros and arguments and 2 for function macros */
522 static int expandable(char *word)
524 int i;
525 if (buf_arg_find(word) >= 0)
526 return 1;
527 if (buf_expanding(word))
528 return 0;
529 i = macro_find(word);
530 return i >= 0 ? macros[i].isfunc + 1 : 0;
533 void cpp_define(char *name, char *def)
535 char tmp_buf[MACROLEN];
536 char *s = tmp_buf;
537 s = putstr(s, name);
538 *s++ = '\t';
539 s = putstr(s, def);
540 buf_new(BUF_TEMP, tmp_buf, s - tmp_buf);
541 macro_define();
542 buf_pop();
545 static int seen_macro; /* seen a macro; 2 if a function macro */
546 static char seen_name[NAMELEN]; /* the name of the last macro */
548 static int hunk_off;
549 static int hunk_len;
551 int cpp_read(char *s)
553 int old, end;
554 int jump_name = 0;
555 if (seen_macro == 1) {
556 macro_expand(seen_name);
557 seen_macro = 0;
559 if (cur == len) {
560 struct buf *cbuf = &bufs[nbufs - 1];
561 if (nbufs < bufs_limit + 1)
562 return -1;
563 if (cbuf->type == BUF_FILE)
564 free(buf);
565 buf_pop();
567 old = cur;
568 if (buf[cur] == '#')
569 if (!cpp_cmd())
570 return 0;
571 while (cur < len) {
572 if (!jumpws())
573 continue;
574 if (buf[cur] == '#')
575 break;
576 if (!jumpcomment())
577 continue;
578 if (seen_macro == 2) {
579 if (buf[cur] == '(')
580 macro_expand(seen_name);
581 seen_macro = 0;
582 old = cur;
583 continue;
585 if (!jumpstr())
586 continue;
587 if (isalnum(buf[cur]) || buf[cur] == '_') {
588 char word[NAMELEN];
589 read_word(word);
590 seen_macro = expandable(word);
591 if (seen_macro) {
592 strcpy(seen_name, word);
593 jump_name = 1;
594 break;
596 if (buf_iseval() && !strcmp("defined", word)) {
597 int parens = 0;
598 jumpws();
599 if (buf[cur] == '(') {
600 parens = 1;
601 cur++;
603 read_word(word);
604 if (parens) {
605 jumpws();
606 cur++;
609 continue;
611 cur++;
613 /* macros are expanded later; ignore its name */
614 end = jump_name ? cur - strlen(seen_name) : cur;
615 memcpy(s, buf + old, end - old);
616 s[end - old] = '\0';
617 if (!buf_iseval()) {
618 hunk_off += hunk_len;
619 hunk_len = end - old;
621 return end - old;
624 /* preprocessor constant expression evaluation */
626 static char etok[NAMELEN];
627 static int enext;
629 static char *tok2[] = {
630 "<<", ">>", "&&", "||", "==", "!=", "<=", ">="
633 static int eval_tok(void)
635 char *s = etok;
636 int i;
637 while (ecur < elen) {
638 while (ecur < elen && isspace(ebuf[ecur]))
639 ecur++;
640 if (ebuf[ecur] == '/' && ebuf[ecur + 1] == '*') {
641 while (ecur < elen && (ebuf[ecur - 2] != '*' ||
642 ebuf[ecur - 1] != '/'))
643 ecur++;
644 continue;
646 break;
648 if (ecur >= elen)
649 return TOK_EOF;
650 if (isalpha(ebuf[ecur]) || ebuf[ecur] == '_') {
651 while (isalnum(ebuf[ecur]) || ebuf[ecur] == '_')
652 *s++ = ebuf[ecur++];
653 *s = '\0';
654 return TOK_NAME;
656 if (isdigit(ebuf[ecur])) {
657 while (isdigit(ebuf[ecur]))
658 *s++ = ebuf[ecur++];
659 while (tolower(ebuf[ecur]) == 'u' || tolower(ebuf[ecur]) == 'l')
660 ecur++;
661 *s = '\0';
662 return TOK_NUM;
664 for (i = 0; i < LEN(tok2); i++)
665 if (TOK2(tok2[i]) == TOK2(ebuf + ecur)) {
666 int ret = TOK2(tok2[i]);
667 ecur += 2;
668 return ret;
670 return ebuf[ecur++];
673 static int eval_see(void)
675 if (enext == -1)
676 enext = eval_tok();
677 return enext;
680 static int eval_get(void)
682 if (enext != -1) {
683 int ret = enext;
684 enext = -1;
685 return ret;
687 return eval_tok();
690 static long eval_num(void)
692 return atol(etok);
695 static int eval_jmp(int tok)
697 if (eval_see() == tok) {
698 eval_get();
699 return 0;
701 return 1;
704 static void eval_expect(int tok)
706 eval_jmp(tok);
709 static char *eval_id(void)
711 return etok;
714 static long evalcexpr(void);
716 static long evalatom(void)
718 if (!eval_jmp(TOK_NUM))
719 return eval_num();
720 if (!eval_jmp(TOK_NAME)) {
721 int parens = !eval_jmp('(');
722 long ret;
723 eval_expect(TOK_NAME);
724 ret = macro_find(eval_id()) >= 0;
725 if (parens)
726 eval_expect(')');
727 return ret;
729 if (!eval_jmp('(')) {
730 long ret = evalcexpr();
731 eval_expect(')');
732 return ret;
734 return -1;
737 static long evalpre(void)
739 if (!eval_jmp('!'))
740 return !evalpre();
741 if (!eval_jmp('-'))
742 return -evalpre();
743 if (!eval_jmp('~'))
744 return ~evalpre();
745 return evalatom();
748 static long evalmul(void)
750 long ret = evalpre();
751 while (1) {
752 if (!eval_jmp('*')) {
753 ret *= evalpre();
754 continue;
756 if (!eval_jmp('/')) {
757 ret /= evalpre();
758 continue;
760 if (!eval_jmp('%')) {
761 ret %= evalpre();
762 continue;
764 break;
766 return ret;
769 static long evaladd(void)
771 long ret = evalmul();
772 while (1) {
773 if (!eval_jmp('+')) {
774 ret += evalmul();
775 continue;
777 if (!eval_jmp('-')) {
778 ret -= evalmul();
779 continue;
781 break;
783 return ret;
786 static long evalshift(void)
788 long ret = evaladd();
789 while (1) {
790 if (!eval_jmp(TOK2("<<"))) {
791 ret <<= evaladd();
792 continue;
794 if (!eval_jmp(TOK2(">>"))) {
795 ret >>= evaladd();
796 continue;
798 break;
800 return ret;
803 static long evalcmp(void)
805 long ret = evalshift();
806 while (1) {
807 if (!eval_jmp('<')) {
808 ret = ret < evalshift();
809 continue;
811 if (!eval_jmp('>')) {
812 ret = ret > evalshift();
813 continue;
815 if (!eval_jmp(TOK2("<="))) {
816 ret = ret <= evalshift();
817 continue;
819 if (!eval_jmp(TOK2(">="))) {
820 ret = ret >= evalshift();
821 continue;
823 break;
825 return ret;
828 static long evaleq(void)
830 long ret = evalcmp();
831 while (1) {
832 if (!eval_jmp(TOK2("=="))) {
833 ret = ret == evalcmp();
834 continue;
836 if (!eval_jmp(TOK2("!="))) {
837 ret = ret != evalcmp();
838 continue;
840 break;
842 return ret;
845 static long evalbitand(void)
847 long ret = evaleq();
848 while (!eval_jmp('&'))
849 ret &= evaleq();
850 return ret;
853 static long evalxor(void)
855 long ret = evalbitand();
856 while (!eval_jmp('^'))
857 ret ^= evalbitand();
858 return ret;
861 static long evalbitor(void)
863 long ret = evalxor();
864 while (!eval_jmp('|'))
865 ret |= evalxor();
866 return ret;
869 static long evaland(void)
871 long ret = evalbitor();
872 while (!eval_jmp(TOK2("&&")))
873 ret = ret && evalbitor();
874 return ret;
877 static long evalor(void)
879 long ret = evaland();
880 while (!eval_jmp(TOK2("||")))
881 ret = ret || evaland();
882 return ret;
885 static long evalcexpr(void)
887 long ret = evalor();
888 if (eval_jmp('?'))
889 return ret;
890 if (ret)
891 return evalor();
892 while (eval_get() != ':')
894 return evalor();
897 static long evalexpr(void)
899 enext = -1;
900 return evalcexpr();
903 static int buf_loc(char *s, int off)
905 char *e = s + off;
906 int n = 1;
907 while ((s = strchr(s, '\n')) && s < e) {
908 n++;
909 s++;
911 return n;
914 char *cpp_loc(long addr)
916 static char loc[256];
917 int line = -1;
918 int i;
919 for (i = nbufs - 1; i > 0; i--)
920 if (bufs[i].type == BUF_FILE)
921 break;
922 if (addr >= hunk_off && i == nbufs - 1)
923 line = buf_loc(buf, (cur - hunk_len) + (addr - hunk_off));
924 else
925 line = buf_loc(bufs[i].buf, bufs[i].cur);
926 sprintf(loc, "%s:%d", bufs[i].path, line);
927 return loc;