gen: simplify branch instructions by removing o_filljmp()
[neatcc.git] / cpp.c
blobae8d8c5221428b34cf5a7a79e391bf74e8b0429b
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 "tok.h"
12 #include "tab.h"
14 static char *buf;
15 static int len;
16 static int cur;
18 #define MAXDEFS (1 << 12)
19 #define MACROLEN (1 << 10)
20 #define MAXARGS (1 << 5)
21 #define NBUCKET (MAXDEFS << 1)
23 static struct macro {
24 char name[NAMELEN];
25 char def[MACROLEN];
26 char args[MAXARGS][NAMELEN];
27 int nargs;
28 int isfunc;
29 } macros[MAXDEFS];
30 static int nmacros;
31 /* macro hash table */
32 static struct tab mtab;
34 #define MAXBUFS (1 << 5)
35 #define BUF_FILE 0
36 #define BUF_MACRO 1
37 #define BUF_ARG 2
38 #define BUF_EVAL 3
39 #define BUF_TEMP 4
41 static struct buf {
42 char *buf;
43 int len;
44 int cur;
45 int type;
46 /* for BUF_FILE */
47 char path[NAMELEN];
48 /* for BUF_MACRO */
49 struct macro *macro;
50 char args[MAXARGS][MACROLEN]; /* arguments passed to a macro */
51 /* for BUF_ARG */
52 int arg_buf; /* the bufs index of the owning macro */
53 } bufs[MAXBUFS];
54 static int nbufs;
56 void die(char *fmt, ...)
58 va_list ap;
59 char msg[512];
60 va_start(ap, fmt);
61 vsprintf(msg, fmt, ap);
62 va_end(ap);
63 write(2, msg, strlen(msg));
64 exit(1);
67 static void buf_new(int type, char *dat, int dlen)
69 if (nbufs) {
70 bufs[nbufs - 1].buf = buf;
71 bufs[nbufs - 1].cur = cur;
72 bufs[nbufs - 1].len = len;
74 if (nbufs >= MAXBUFS)
75 die("nomem: MAXBUFS reached!\n");
76 nbufs++;
77 cur = 0;
78 buf = dat;
79 len = dlen;
80 bufs[nbufs - 1].type = type;
83 static void buf_file(char *path, char *dat, int dlen)
85 buf_new(BUF_FILE, dat, dlen);
86 strcpy(bufs[nbufs - 1].path, path ? path : "");
89 static void buf_macro(struct macro *m)
91 buf_new(BUF_MACRO, m->def, strlen(m->def));
92 bufs[nbufs - 1].macro = m;
95 static void buf_arg(char *arg, int mbuf)
97 buf_new(BUF_ARG, arg, strlen(arg));
98 bufs[nbufs - 1].arg_buf = mbuf;
101 static void buf_pop(void)
103 nbufs--;
104 if (nbufs) {
105 cur = bufs[nbufs - 1].cur;
106 len = bufs[nbufs - 1].len;
107 buf = bufs[nbufs - 1].buf;
111 static int buf_iseval(void)
113 int i;
114 for (i = nbufs - 1; i >= 0; i--)
115 if (bufs[i].type == BUF_EVAL)
116 return 1;
117 return 0;
120 static size_t file_size(int fd)
122 struct stat st;
123 if (!fstat(fd, &st))
124 return st.st_size;
125 return 0;
128 static int include_file(char *path)
130 int fd = open(path, O_RDONLY);
131 int n = 0, nr = 0;
132 char *dat;
133 int size;
134 if (fd == -1)
135 return -1;
136 size = file_size(fd) + 1;
137 dat = malloc(size);
138 while ((n = read(fd, dat + nr, size - nr)) > 0)
139 nr += n;
140 close(fd);
141 dat[nr] = '\0';
142 buf_file(path, dat, nr);
143 return 0;
146 int cpp_init(char *path)
148 return include_file(path);
151 static void jumpws(void)
153 while (cur < len && isspace(buf[cur]))
154 cur++;
157 static void read_word(char *dst)
159 jumpws();
160 while (cur < len && (isalnum(buf[cur]) || buf[cur] == '_'))
161 *dst++ = buf[cur++];
162 *dst = '\0';
165 static int jumpcomment(void)
167 if (buf[cur] == '/' && buf[cur + 1] == '*') {
168 while (++cur < len) {
169 if (buf[cur] == '*' && buf[cur + 1] == '/') {
170 cur += 2;
171 return 0;
175 if (buf[cur] == '/' && buf[cur + 1] == '/') {
176 while (++cur < len)
177 if (buf[cur] == '\n')
178 break;
179 return 0;
181 return 1;
184 static int jumpstr(void)
186 if (buf[cur] == '\'') {
187 while (cur < len && buf[++cur] != '\'')
188 if (buf[cur] == '\\')
189 cur++;
190 cur++;
191 return 0;
193 if (buf[cur] == '"') {
194 while (cur < len && buf[++cur] != '"')
195 if (buf[cur] == '\\')
196 cur++;
197 cur++;
198 return 0;
200 return 1;
203 static void read_tilleol(char *dst)
205 while (cur < len && isspace(buf[cur]) && buf[cur] != '\n')
206 cur++;
207 while (cur < len && buf[cur] != '\n') {
208 int last = cur;
209 if (buf[cur] == '\\' && buf[cur + 1] == '\n') {
210 cur += 2;
211 continue;
213 if (!jumpstr()) {
214 memcpy(dst, buf + last, cur - last);
215 dst += cur - last;
216 continue;
218 if (!jumpcomment())
219 continue;
220 *dst++ = buf[cur++];
222 *dst = '\0';
225 static char *putstr(char *d, char *s)
227 while (*s)
228 *d++ = *s++;
229 *d = '\0';
230 return d;
233 #define MAXLOCS (1 << 10)
235 static char *locs[MAXLOCS] = {};
236 static int nlocs = 0;
238 void cpp_addpath(char *s)
240 locs[nlocs++] = s;
243 static int include_find(char *name, int std)
245 int i;
246 for (i = std ? nlocs - 1 : nlocs; i >= 0; i--) {
247 char path[1 << 10];
248 char *s;
249 s = path;
250 if (locs[i]) {
251 s = putstr(s, locs[i]);
252 *s++ = '/';
254 s = putstr(s, name);
255 if (!include_file(path))
256 return 0;
258 return -1;
261 static void readarg(char *s)
263 int depth = 0;
264 int beg = cur;
265 while (cur < len && (depth || buf[cur] != ',' && buf[cur] != ')')) {
266 if (!jumpstr() || !jumpcomment())
267 continue;
268 switch (buf[cur++]) {
269 case '(':
270 case '[':
271 case '{':
272 depth++;
273 break;
274 case ')':
275 case ']':
276 case '}':
277 depth--;
278 break;
281 if (s) {
282 memcpy(s, buf + beg, cur - beg);
283 s[cur - beg] = '\0';
287 static int macro_find(char *name)
289 char *n = tab_get(&mtab, name);
290 if (!n)
291 return -1;
292 return container(n, struct macro, name) - macros;
295 static void macro_undef(char *name)
297 int i = macro_find(name);
298 if (i >= 0)
299 tab_del(&mtab, macros[i].name);
302 static int macro_new(char *name)
304 int i = macro_find(name);
305 if (i >= 0)
306 return i;
307 if (nmacros >= MAXDEFS)
308 die("nomem: MAXDEFS reached!\n");
309 i = nmacros++;
310 strcpy(macros[i].name, name);
311 tab_add(&mtab, macros[i].name);
312 return i;
315 static void macro_define(void)
317 char name[NAMELEN];
318 struct macro *d;
319 read_word(name);
320 d = &macros[macro_new(name)];
321 d->isfunc = 0;
322 d->nargs = 0;
323 if (buf[cur] == '(') {
324 cur++;
325 jumpws();
326 while (cur < len && buf[cur] != ')') {
327 readarg(d->args[d->nargs++]);
328 jumpws();
329 if (buf[cur] != ',')
330 break;
331 cur++;
332 jumpws();
334 cur++;
335 d->isfunc = 1;
337 read_tilleol(d->def);
340 int cpp_read(char *buf);
342 static char ebuf[BUFSIZE];
343 static int elen;
344 static int ecur;
346 static long evalexpr(void);
348 static int cpp_eval(void)
350 int bufid;
351 int ret;
352 char evalbuf[BUFSIZE];
353 read_tilleol(evalbuf);
354 buf_new(BUF_EVAL, evalbuf, strlen(evalbuf));
355 bufid = nbufs;
356 elen = 0;
357 ecur = 0;
358 while (bufid < nbufs || (bufid == nbufs && cur < len))
359 elen += cpp_read(ebuf + elen);
360 ret = evalexpr();
361 buf_pop();
362 return ret;
365 static void jumpifs(int jumpelse)
367 int depth = 0;
368 while (cur < len) {
369 if (buf[cur] == '#') {
370 char cmd[NAMELEN];
371 cur++;
372 read_word(cmd);
373 if (!strcmp("else", cmd))
374 if (!depth && !jumpelse)
375 break;
376 if (!strcmp("elif", cmd))
377 if (!depth && !jumpelse && cpp_eval())
378 break;
379 if (!strcmp("endif", cmd)) {
380 if (!depth)
381 break;
382 else
383 depth--;
385 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd) ||
386 !strcmp("if", cmd))
387 depth++;
388 continue;
390 if (!jumpcomment())
391 continue;
392 if (!jumpstr())
393 continue;
394 cur++;
398 static int cpp_cmd(void)
400 char cmd[NAMELEN];
401 cur++;
402 read_word(cmd);
403 if (!strcmp("define", cmd)) {
404 macro_define();
405 return 0;
407 if (!strcmp("undef", cmd)) {
408 char name[NAMELEN];
409 read_word(name);
410 macro_undef(name);
411 return 0;
413 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd) ||
414 !strcmp("if", cmd)) {
415 char name[NAMELEN];
416 int matched = 0;
417 if (cmd[2]) {
418 int not = cmd[2] == 'n';
419 read_word(name);
420 matched = not ? macro_find(name) < 0 :
421 macro_find(name) >= 0;
422 } else {
423 matched = cpp_eval();
425 if (!matched)
426 jumpifs(0);
427 return 0;
429 if (!strcmp("else", cmd) || !strcmp("elif", cmd)) {
430 jumpifs(1);
431 return 0;
433 if (!strcmp("endif", cmd))
434 return 0;
435 if (!strcmp("include", cmd)) {
436 char file[NAMELEN];
437 char *s, *e;
438 jumpws();
439 s = buf + cur + 1;
440 e = strchr(buf + cur + 1, buf[cur] == '"' ? '"' : '>');
441 memcpy(file, s, e - s);
442 file[e - s] = '\0';
443 cur += e - s + 2;
444 if (include_find(file, *e == '>') == -1)
445 die("cannot include <%s>\n", file);
446 return 0;
448 return 1;
451 static int macro_arg(struct macro *m, char *arg)
453 int i;
454 for (i = 0; i < m->nargs; i++)
455 if (!strcmp(arg, m->args[i]))
456 return i;
457 return -1;
460 static int buf_arg_find(char *name)
462 int i;
463 for (i = nbufs - 1; i >= 0; i--) {
464 struct buf *mbuf = &bufs[i];
465 struct macro *m = mbuf->macro;
466 if (mbuf->type == BUF_MACRO && macro_arg(m, name) >= 0)
467 return i;
468 if (mbuf->type == BUF_ARG)
469 i = mbuf->arg_buf;
471 return -1;
474 static void macro_expand(void)
476 char name[NAMELEN];
477 struct macro *m;
478 int mbuf;
479 read_word(name);
480 if ((mbuf = buf_arg_find(name)) >= 0) {
481 int arg = macro_arg(bufs[mbuf].macro, name);
482 char *dat = bufs[mbuf].args[arg];
483 buf_arg(dat, mbuf);
484 return;
486 m = &macros[macro_find(name)];
487 if (!m->isfunc) {
488 buf_macro(m);
489 return;
491 jumpws();
492 if (buf[cur] == '(') {
493 int i = 0;
494 struct buf *mbuf = &bufs[nbufs];
495 cur++;
496 jumpws();
497 while (cur < len && buf[cur] != ')') {
498 readarg(mbuf->args[i++]);
499 jumpws();
500 if (buf[cur] != ',')
501 break;
502 cur++;
503 jumpws();
505 while (i < m->nargs)
506 mbuf->args[i++][0] = '\0';
507 cur++;
508 buf_macro(m);
512 static int buf_expanding(char *macro)
514 int i;
515 for (i = nbufs - 1; i >= 0; i--) {
516 if (bufs[i].type == BUF_ARG)
517 return 0;
518 if (bufs[i].type == BUF_MACRO &&
519 !strcmp(macro, bufs[i].macro->name))
520 return 1;
522 return 0;
525 static int expandable(char *word)
527 if (buf_arg_find(word) >= 0)
528 return 1;
529 return !buf_expanding(word) && macro_find(word) != -1;
532 void cpp_define(char *name, char *def)
534 char tmp_buf[MACROLEN];
535 char *s = tmp_buf;
536 s = putstr(s, name);
537 *s++ = '\t';
538 s = putstr(s, def);
539 buf_new(BUF_TEMP, tmp_buf, s - tmp_buf);
540 macro_define();
541 buf_pop();
544 static int seen_macro;
546 static int hunk_off;
547 static int hunk_len;
549 int cpp_read(char *s)
551 int old;
552 if (seen_macro) {
553 seen_macro = 0;
554 macro_expand();
556 if (cur == len) {
557 struct buf *cbuf = &bufs[nbufs - 1];
558 if (nbufs < 2)
559 return -1;
560 if (cbuf->type == BUF_FILE)
561 free(buf);
562 buf_pop();
564 old = cur;
565 if (buf[cur] == '#')
566 if (!cpp_cmd())
567 return 0;
568 while (cur < len) {
569 if (buf[cur] == '#')
570 break;
571 if (!jumpcomment())
572 continue;
573 if (!jumpstr())
574 continue;
575 if (isalpha(buf[cur]) || buf[cur] == '_') {
576 char word[NAMELEN];
577 read_word(word);
578 if (expandable(word)) {
579 cur -= strlen(word);
580 seen_macro = 1;
581 break;
583 if (buf_iseval() && !strcmp("defined", word)) {
584 int parens = 0;
585 jumpws();
586 if (buf[cur] == '(') {
587 parens = 1;
588 cur++;
590 read_word(word);
591 if (parens) {
592 jumpws();
593 cur++;
596 continue;
598 cur++;
600 memcpy(s, buf + old, cur - old);
601 s[cur - old] = '\0';
602 if (!buf_iseval()) {
603 hunk_off += hunk_len;
604 hunk_len = cur - old;
606 return cur - old;
609 /* preprocessor constant expression evaluation */
611 static char etok[NAMELEN];
612 static int enext;
614 static char *tok2[] = {
615 "<<", ">>", "&&", "||", "==", "!=", "<=", ">="
618 static int eval_tok(void)
620 char *s = etok;
621 int i;
622 while (ecur < elen) {
623 while (ecur < elen && isspace(ebuf[ecur]))
624 ecur++;
625 if (ebuf[ecur] == '/' && ebuf[ecur + 1] == '*') {
626 while (ecur < elen && (ebuf[ecur - 2] != '*' ||
627 ebuf[ecur - 1] != '/'))
628 ecur++;
629 continue;
631 break;
633 if (ecur >= elen)
634 return TOK_EOF;
635 if (isalpha(ebuf[ecur]) || ebuf[ecur] == '_') {
636 while (isalnum(ebuf[ecur]) || ebuf[ecur] == '_')
637 *s++ = ebuf[ecur++];
638 *s = '\0';
639 return TOK_NAME;
641 if (isdigit(ebuf[ecur])) {
642 while (isdigit(ebuf[ecur]))
643 *s++ = ebuf[ecur++];
644 while (tolower(ebuf[ecur]) == 'u' || tolower(ebuf[ecur]) == 'l')
645 ecur++;
646 *s = '\0';
647 return TOK_NUM;
649 for (i = 0; i < ARRAY_SIZE(tok2); i++)
650 if (TOK2(tok2[i]) == TOK2(ebuf + ecur)) {
651 int ret = TOK2(tok2[i]);
652 ecur += 2;
653 return ret;
655 return ebuf[ecur++];
658 static int eval_see(void)
660 if (enext == -1)
661 enext = eval_tok();
662 return enext;
665 static int eval_get(void)
667 if (enext != -1) {
668 int ret = enext;
669 enext = -1;
670 return ret;
672 return eval_tok();
675 static long eval_num(void)
677 return atol(etok);
680 static int eval_jmp(int tok)
682 if (eval_see() == tok) {
683 eval_get();
684 return 0;
686 return 1;
689 static void eval_expect(int tok)
691 eval_jmp(tok);
694 static char *eval_id(void)
696 return etok;
699 static long evalcexpr(void);
701 static long evalatom(void)
703 if (!eval_jmp(TOK_NUM))
704 return eval_num();
705 if (!eval_jmp(TOK_NAME)) {
706 int parens = !eval_jmp('(');
707 long ret;
708 eval_expect(TOK_NAME);
709 ret = macro_find(eval_id()) >= 0;
710 if (parens)
711 eval_expect(')');
712 return ret;
714 if (!eval_jmp('(')) {
715 long ret = evalcexpr();
716 eval_expect(')');
717 return ret;
719 return -1;
722 static long evalpre(void)
724 if (!eval_jmp('!'))
725 return !evalpre();
726 if (!eval_jmp('-'))
727 return -evalpre();
728 if (!eval_jmp('~'))
729 return ~evalpre();
730 return evalatom();
733 static long evalmul(void)
735 long ret = evalpre();
736 while (1) {
737 if (!eval_jmp('*')) {
738 ret *= evalpre();
739 continue;
741 if (!eval_jmp('/')) {
742 ret /= evalpre();
743 continue;
745 if (!eval_jmp('%')) {
746 ret %= evalpre();
747 continue;
749 break;
751 return ret;
754 static long evaladd(void)
756 long ret = evalmul();
757 while (1) {
758 if (!eval_jmp('+')) {
759 ret += evalmul();
760 continue;
762 if (!eval_jmp('-')) {
763 ret -= evalmul();
764 continue;
766 break;
768 return ret;
771 static long evalshift(void)
773 long ret = evaladd();
774 while (1) {
775 if (!eval_jmp(TOK2("<<"))) {
776 ret <<= evaladd();
777 continue;
779 if (!eval_jmp(TOK2(">>"))) {
780 ret >>= evaladd();
781 continue;
783 break;
785 return ret;
788 static long evalcmp(void)
790 long ret = evalshift();
791 while (1) {
792 if (!eval_jmp('<')) {
793 ret = ret < evalshift();
794 continue;
796 if (!eval_jmp('>')) {
797 ret = ret > evalshift();
798 continue;
800 if (!eval_jmp(TOK2("<="))) {
801 ret = ret <= evalshift();
802 continue;
804 if (!eval_jmp(TOK2(">="))) {
805 ret = ret >= evalshift();
806 continue;
808 break;
810 return ret;
813 static long evaleq(void)
815 long ret = evalcmp();
816 while (1) {
817 if (!eval_jmp(TOK2("=="))) {
818 ret = ret == evalcmp();
819 continue;
821 if (!eval_jmp(TOK2("!="))) {
822 ret = ret != evalcmp();
823 continue;
825 break;
827 return ret;
830 static long evalbitand(void)
832 long ret = evaleq();
833 while (!eval_jmp('&'))
834 ret &= evaleq();
835 return ret;
838 static long evalxor(void)
840 long ret = evalbitand();
841 while (!eval_jmp('^'))
842 ret ^= evalbitand();
843 return ret;
846 static long evalbitor(void)
848 long ret = evalxor();
849 while (!eval_jmp('|'))
850 ret |= evalxor();
851 return ret;
854 static long evaland(void)
856 long ret = evalbitor();
857 while (!eval_jmp(TOK2("&&")))
858 ret = ret && evalbitor();
859 return ret;
862 static long evalor(void)
864 long ret = evaland();
865 while (!eval_jmp(TOK2("||")))
866 ret = ret || evaland();
867 return ret;
870 static long evalcexpr(void)
872 long ret = evalor();
873 if (eval_jmp('?'))
874 return ret;
875 if (ret)
876 return evalor();
877 while (eval_get() != ':')
879 return evalor();
882 static long evalexpr(void)
884 enext = -1;
885 return evalcexpr();
888 static int buf_loc(char *s, int off)
890 char *e = s + off;
891 int n = 1;
892 while ((s = strchr(s, '\n')) && s < e) {
893 n++;
894 s++;
896 return n;
899 char *cpp_loc(long addr)
901 static char loc[256];
902 int line = -1;
903 int i;
904 for (i = nbufs - 1; i > 0; i--)
905 if (bufs[i].type == BUF_FILE)
906 break;
907 if (addr >= hunk_off && i == nbufs - 1)
908 line = buf_loc(buf, (cur - hunk_len) + (addr - hunk_off));
909 else
910 line = buf_loc(bufs[i].buf, bufs[i].cur);
911 sprintf(loc, "%s:%d", bufs[i].path, line);
912 return loc;