gen: use better names for opcodes
[neatcc.git] / cpp.c
blob795bb8c670f524992cf2d3d1ad08b0934be6628d
1 #include <ctype.h>
2 #include <fcntl.h>
3 #include <stddef.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include "tok.h"
11 #include "tab.h"
13 static char *buf;
14 static int len;
15 static int cur;
17 #define MAXDEFS (1 << 12)
18 #define MACROLEN (1 << 10)
19 #define MAXARGS (1 << 5)
20 #define NBUCKET (MAXDEFS << 1)
22 static struct macro {
23 char name[NAMELEN];
24 char def[MACROLEN];
25 char args[MAXARGS][NAMELEN];
26 int nargs;
27 int isfunc;
28 } macros[MAXDEFS];
29 static int nmacros;
30 /* macro hash table */
31 static struct tab mtab;
33 #define MAXBUFS (1 << 5)
34 #define BUF_FILE 0
35 #define BUF_MACRO 1
36 #define BUF_ARG 2
37 #define BUF_EVAL 3
38 #define BUF_TEMP 4
40 static struct buf {
41 char *buf;
42 int len;
43 int cur;
44 int type;
45 /* for BUF_FILE */
46 char path[NAMELEN];
47 /* for BUF_MACRO */
48 struct macro *macro;
49 char args[MAXARGS][MACROLEN]; /* arguments passed to a macro */
50 /* for BUF_ARG */
51 int arg_buf; /* the bufs index of the owning macro */
52 } bufs[MAXBUFS];
53 static int nbufs;
55 static void buf_new(int type, char *dat, int dlen)
57 if (nbufs) {
58 bufs[nbufs - 1].buf = buf;
59 bufs[nbufs - 1].cur = cur;
60 bufs[nbufs - 1].len = len;
62 if (nbufs >= MAXBUFS)
63 die("nomem: MAXBUFS reached!\n");
64 nbufs++;
65 cur = 0;
66 buf = dat;
67 len = dlen;
68 bufs[nbufs - 1].type = type;
71 static void buf_file(char *path, char *dat, int dlen)
73 buf_new(BUF_FILE, dat, dlen);
74 strcpy(bufs[nbufs - 1].path, path ? path : "");
77 static void buf_macro(struct macro *m)
79 buf_new(BUF_MACRO, m->def, strlen(m->def));
80 bufs[nbufs - 1].macro = m;
83 static void buf_arg(char *arg, int mbuf)
85 buf_new(BUF_ARG, arg, strlen(arg));
86 bufs[nbufs - 1].arg_buf = mbuf;
89 static void buf_pop(void)
91 nbufs--;
92 if (nbufs) {
93 cur = bufs[nbufs - 1].cur;
94 len = bufs[nbufs - 1].len;
95 buf = bufs[nbufs - 1].buf;
99 static int buf_iseval(void)
101 int i;
102 for (i = nbufs - 1; i >= 0; i--)
103 if (bufs[i].type == BUF_EVAL)
104 return 1;
105 return 0;
108 static size_t file_size(int fd)
110 struct stat st;
111 if (!fstat(fd, &st))
112 return st.st_size;
113 return 0;
116 static int include_file(char *path)
118 int fd = open(path, O_RDONLY);
119 int n = 0, nr = 0;
120 char *dat;
121 int size;
122 if (fd == -1)
123 return -1;
124 size = file_size(fd) + 1;
125 dat = malloc(size);
126 while ((n = read(fd, dat + nr, size - nr)) > 0)
127 nr += n;
128 close(fd);
129 dat[nr] = '\0';
130 buf_file(path, dat, nr);
131 return 0;
134 int cpp_init(char *path)
136 cpp_define("__STDC__", "");
137 cpp_define("__i386__", "");
138 cpp_define("__linux__", "");
139 return include_file(path);
142 static void jumpws(void)
144 while (cur < len && isspace(buf[cur]))
145 cur++;
148 static void read_word(char *dst)
150 jumpws();
151 while (cur < len && (isalnum(buf[cur]) || buf[cur] == '_'))
152 *dst++ = buf[cur++];
153 *dst = '\0';
156 static void jumpcomment(void)
158 while (++cur < len) {
159 if (buf[cur] == '*' && buf[cur + 1] == '/') {
160 cur += 2;
161 break;
166 static void read_tilleol(char *dst)
168 while (cur < len && isspace(buf[cur]) && buf[cur] != '\n')
169 cur++;
170 while (cur < len && buf[cur] != '\n') {
171 if (buf[cur] == '\\')
172 cur += 2;
173 else if (buf[cur] == '/' && buf[cur + 1] == '*')
174 jumpcomment();
175 else
176 *dst++ = buf[cur++];
178 *dst = '\0';
181 static char *putstr(char *d, char *s)
183 while (*s)
184 *d++ = *s++;
185 *d = '\0';
186 return d;
189 #define MAXLOCS (1 << 10)
191 static char *locs[MAXLOCS] = {"/usr/include"};
192 static int nlocs = 1;
194 void cpp_addpath(char *s)
196 locs[nlocs++] = s;
199 static int include_find(char *name, int std)
201 int i;
202 for (i = std ? nlocs - 1 : nlocs; i >= 0; i--) {
203 char path[1 << 10];
204 char *s;
205 s = path;
206 if (locs[i]) {
207 s = putstr(s, locs[i]);
208 *s++ = '/';
210 s = putstr(s, name);
211 if (!include_file(path))
212 return 0;
214 return -1;
217 static void jumpstr(void)
219 if (buf[cur] == '\'') {
220 while (cur < len && buf[++cur] != '\'')
221 if (buf[cur] == '\\')
222 cur++;
223 cur++;
224 return;
226 if (buf[cur] == '"') {
227 while (cur < len && buf[++cur] != '"')
228 if (buf[cur] == '\\')
229 cur++;
230 cur++;
231 return;
235 static void readarg(char *s)
237 int depth = 0;
238 int beg = cur;
239 while (cur < len && (depth || buf[cur] != ',' && buf[cur] != ')')) {
240 switch (buf[cur]) {
241 case '(':
242 case '[':
243 case '{':
244 cur++;
245 depth++;
246 break;
247 case ')':
248 case ']':
249 case '}':
250 cur++;
251 depth--;
252 break;
253 case '\'':
254 case '"':
255 jumpstr();
256 break;
257 default:
258 if (buf[cur] == '/' && buf[cur + 1] == '*')
259 jumpcomment();
260 else
261 cur++;
264 if (s) {
265 memcpy(s, buf + beg, cur - beg);
266 s[cur - beg] = '\0';
270 static int macro_find(char *name)
272 char *n = tab_get(&mtab, name);
273 if (!n)
274 return -1;
275 return container(n, struct macro, name) - macros;
278 static void macro_undef(char *name)
280 int i = macro_find(name);
281 if (i >= 0)
282 tab_del(&mtab, macros[i].name);
285 static int macro_new(char *name)
287 int i = macro_find(name);
288 if (i >= 0)
289 return i;
290 if (nmacros >= MAXDEFS)
291 die("nomem: MAXDEFS reached!\n");
292 i = nmacros++;
293 strcpy(macros[i].name, name);
294 tab_add(&mtab, macros[i].name);
295 return i;
298 static void macro_define(void)
300 char name[NAMELEN];
301 struct macro *d;
302 read_word(name);
303 d = &macros[macro_new(name)];
304 d->isfunc = 0;
305 d->nargs = 0;
306 if (buf[cur] == '(') {
307 cur++;
308 jumpws();
309 while (cur < len && buf[cur] != ')') {
310 readarg(d->args[d->nargs++]);
311 jumpws();
312 if (buf[cur++] != ',')
313 break;
314 jumpws();
316 d->isfunc = 1;
318 read_tilleol(d->def);
321 int cpp_read(char *buf);
323 static char ebuf[BUFSIZE];
324 static int elen;
325 static int ecur;
327 static long evalexpr(void);
329 static int cpp_eval(void)
331 int bufid;
332 int ret;
333 char evalbuf[BUFSIZE];
334 read_tilleol(evalbuf);
335 buf_new(BUF_EVAL, evalbuf, strlen(evalbuf));
336 bufid = nbufs;
337 elen = 0;
338 ecur = 0;
339 while (bufid < nbufs || (bufid == nbufs && cur < len))
340 elen += cpp_read(ebuf + elen);
341 ret = evalexpr();
342 buf_pop();
343 return ret;
346 static void jumpifs(int jumpelse)
348 int depth = 0;
349 while (cur < len) {
350 if (buf[cur] == '#') {
351 char cmd[NAMELEN];
352 cur++;
353 read_word(cmd);
354 if (!strcmp("else", cmd))
355 if (!depth && !jumpelse)
356 break;
357 if (!strcmp("elif", cmd))
358 if (!depth && !jumpelse && cpp_eval())
359 break;
360 if (!strcmp("endif", cmd)) {
361 if (!depth)
362 break;
363 else
364 depth--;
366 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd) ||
367 !strcmp("if", cmd))
368 depth++;
369 continue;
371 if (buf[cur] == '/' && buf[cur + 1] == '*') {
372 jumpcomment();
373 continue;
375 if (buf[cur] == '\'' || buf[cur] == '"') {
376 jumpstr();
377 continue;
379 cur++;
383 static void cpp_cmd(void)
385 char cmd[NAMELEN];
386 cur++;
387 read_word(cmd);
388 if (!strcmp("define", cmd)) {
389 macro_define();
390 return;
392 if (!strcmp("undef", cmd)) {
393 char name[NAMELEN];
394 read_word(name);
395 macro_undef(name);
396 return;
398 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd) ||
399 !strcmp("if", cmd)) {
400 char name[NAMELEN];
401 int matched = 0;
402 if (cmd[2]) {
403 int not = cmd[2] == 'n';
404 read_word(name);
405 matched = not ? macro_find(name) < 0 :
406 macro_find(name) >= 0;
407 } else {
408 matched = cpp_eval();
410 if (!matched)
411 jumpifs(0);
412 return;
414 if (!strcmp("else", cmd) || !strcmp("elif", cmd)) {
415 jumpifs(1);
416 return;
418 if (!strcmp("endif", cmd))
419 return;
420 if (!strcmp("include", cmd)) {
421 char file[NAMELEN];
422 char *s, *e;
423 jumpws();
424 s = buf + cur + 1;
425 e = strchr(buf + cur + 1, buf[cur] == '"' ? '"' : '>');
426 memcpy(file, s, e - s);
427 file[e - s] = '\0';
428 cur += e - s + 2;
429 if (include_find(file, *e == '>') == -1)
430 die("cannot include file\n");
431 return;
435 static int macro_arg(struct macro *m, char *arg)
437 int i;
438 for (i = 0; i < m->nargs; i++)
439 if (!strcmp(arg, m->args[i]))
440 return i;
441 return -1;
444 static int buf_arg_find(char *name)
446 int i;
447 for (i = nbufs - 1; i >= 0; i--) {
448 struct buf *mbuf = &bufs[i];
449 struct macro *m = mbuf->macro;
450 if (mbuf->type == BUF_MACRO && macro_arg(m, name) >= 0)
451 return i;
452 if (mbuf->type == BUF_ARG)
453 i = mbuf->arg_buf;
455 return -1;
458 static void macro_expand(void)
460 char name[NAMELEN];
461 struct macro *m;
462 int mbuf;
463 read_word(name);
464 if ((mbuf = buf_arg_find(name)) >= 0) {
465 int arg = macro_arg(bufs[mbuf].macro, name);
466 char *dat = bufs[mbuf].args[arg];
467 buf_arg(dat, mbuf);
468 return;
470 m = &macros[macro_find(name)];
471 if (!m->isfunc) {
472 buf_macro(m);
473 return;
475 jumpws();
476 if (buf[cur] == '(') {
477 int i = 0;
478 struct buf *mbuf = &bufs[nbufs];
479 cur++;
480 jumpws();
481 while (cur < len && buf[cur] != ')') {
482 readarg(mbuf->args[i++]);
483 jumpws();
484 if (buf[cur] != ',')
485 break;
486 cur++;
487 jumpws();
489 while (i < m->nargs)
490 mbuf->args[i++][0] = '\0';
491 cur++;
492 buf_macro(m);
496 static int buf_expanding(char *macro)
498 int i;
499 for (i = nbufs - 1; i >= 0; i--) {
500 if (bufs[i].type == BUF_ARG)
501 return 0;
502 if (bufs[i].type == BUF_MACRO &&
503 !strcmp(macro, bufs[i].macro->name))
504 return 1;
506 return 0;
509 static int expandable(char *word)
511 if (buf_arg_find(word) >= 0)
512 return 1;
513 return !buf_expanding(word) && macro_find(word) != -1;
516 void cpp_define(char *name, char *def)
518 char tmp_buf[MACROLEN];
519 char *s = tmp_buf;
520 s = putstr(s, name);
521 *s++ = '\t';
522 s = putstr(s, def);
523 buf_new(BUF_TEMP, tmp_buf, s - tmp_buf);
524 macro_define();
525 buf_pop();
528 static int seen_macro;
530 static int hunk_off;
531 static int hunk_len;
533 int cpp_read(char *s)
535 int old;
536 if (seen_macro) {
537 seen_macro = 0;
538 macro_expand();
540 if (cur == len) {
541 struct buf *cbuf = &bufs[nbufs - 1];
542 if (nbufs < 2)
543 return -1;
544 if (cbuf->type & BUF_FILE)
545 free(buf);
546 buf_pop();
548 old = cur;
549 if (buf[cur] == '#') {
550 cpp_cmd();
551 return 0;
553 while (cur < len) {
554 if (buf[cur] == '#')
555 break;
556 if (buf[cur] == '/' && buf[cur + 1] == '*') {
557 jumpcomment();
558 continue;
560 if (buf[cur] == '\'' || buf[cur] == '"') {
561 jumpstr();
562 continue;
564 if (isalpha(buf[cur]) || buf[cur] == '_') {
565 char word[NAMELEN];
566 read_word(word);
567 if (expandable(word)) {
568 cur -= strlen(word);
569 seen_macro = 1;
570 break;
572 if (buf_iseval() && !strcmp("defined", word)) {
573 int parens = 0;
574 jumpws();
575 if (buf[cur] == '(') {
576 parens = 1;
577 cur++;
579 read_word(word);
580 if (parens) {
581 jumpws();
582 cur++;
585 continue;
587 cur++;
589 memcpy(s, buf + old, cur - old);
590 s[cur - old] = '\0';
591 if (!buf_iseval()) {
592 hunk_off += hunk_len;
593 hunk_len = cur - old;
595 return cur - old;
598 /* preprocessor constant expression evaluation */
600 static char etok[NAMELEN];
601 static int enext;
603 static char *tok2[] = {
604 "<<", ">>", "&&", "||", "==", "!=", "<=", ">="
607 static int eval_tok(void)
609 char *s = etok;
610 int i;
611 while (ecur < elen) {
612 while (ecur < elen && isspace(ebuf[ecur]))
613 ecur++;
614 if (ebuf[ecur] == '/' && ebuf[ecur + 1] == '*') {
615 while (ecur < elen && (ebuf[ecur - 2] != '*' ||
616 ebuf[ecur - 1] != '/'))
617 ecur++;
618 continue;
620 break;
622 if (ecur >= elen)
623 return TOK_EOF;
624 if (isalpha(ebuf[ecur]) || ebuf[ecur] == '_') {
625 while (isalnum(ebuf[ecur]) || ebuf[ecur] == '_')
626 *s++ = ebuf[ecur++];
627 *s = '\0';
628 return TOK_NAME;
630 if (isdigit(ebuf[ecur])) {
631 while (isdigit(ebuf[ecur]))
632 *s++ = ebuf[ecur++];
633 while (tolower(ebuf[ecur]) == 'u' || tolower(ebuf[ecur]) == 'l')
634 ecur++;
635 return TOK_NUM;
637 for (i = 0; i < ARRAY_SIZE(tok2); i++)
638 if (TOK2(tok2[i]) == TOK2(ebuf + ecur)) {
639 int ret = TOK2(tok2[i]);
640 ecur += 2;
641 return ret;
643 return ebuf[ecur++];
646 static int eval_see(void)
648 if (enext == -1)
649 enext = eval_tok();
650 return enext;
653 static int eval_get(void)
655 if (enext != -1) {
656 int ret = enext;
657 enext = -1;
658 return ret;
660 return eval_tok();
663 static long eval_num(void)
665 return atol(etok);
668 static int eval_jmp(int tok)
670 if (eval_see() == tok) {
671 eval_get();
672 return 0;
674 return 1;
677 static void eval_expect(int tok)
679 eval_jmp(tok);
682 static char *eval_id(void)
684 return etok;
687 static long evalcexpr(void);
689 static long evalatom(void)
691 if (!eval_jmp(TOK_NUM))
692 return eval_num();
693 if (!eval_jmp(TOK_NAME)) {
694 int parens = !eval_jmp('(');
695 long ret;
696 eval_expect(TOK_NAME);
697 ret = macro_find(eval_id()) >= 0;
698 if (parens)
699 eval_expect(')');
700 return ret;
702 if (!eval_jmp('(')) {
703 long ret = evalcexpr();
704 eval_expect(')');
705 return ret;
707 return -1;
710 static long evalpre(void)
712 if (!eval_jmp('!'))
713 return !evalpre();
714 if (!eval_jmp('-'))
715 return -evalpre();
716 if (!eval_jmp('~'))
717 return ~evalpre();
718 return evalatom();
721 static long evalmul(void)
723 long ret = evalpre();
724 while (1) {
725 if (!eval_jmp('*')) {
726 ret *= evalpre();
727 continue;
729 if (!eval_jmp('/')) {
730 ret /= evalpre();
731 continue;
733 if (!eval_jmp('%')) {
734 ret %= evalpre();
735 continue;
737 break;
739 return ret;
742 static long evaladd(void)
744 long ret = evalmul();
745 while (1) {
746 if (!eval_jmp('+')) {
747 ret += evalmul();
748 continue;
750 if (!eval_jmp('-')) {
751 ret -= evalmul();
752 continue;
754 break;
756 return ret;
759 static long evalshift(void)
761 long ret = evaladd();
762 while (1) {
763 if (!eval_jmp(TOK2("<<"))) {
764 ret <<= evaladd();
765 continue;
767 if (!eval_jmp(TOK2(">>"))) {
768 ret >>= evaladd();
769 continue;
771 break;
773 return ret;
776 static long evalcmp(void)
778 long ret = evalshift();
779 while (1) {
780 if (!eval_jmp('<')) {
781 ret = ret < evalshift();
782 continue;
784 if (!eval_jmp('>')) {
785 ret = ret > evalshift();
786 continue;
788 if (!eval_jmp(TOK2("<="))) {
789 ret = ret <= evalshift();
790 continue;
792 if (!eval_jmp(TOK2(">="))) {
793 ret = ret >= evalshift();
794 continue;
796 break;
798 return ret;
801 static long evaleq(void)
803 long ret = evalcmp();
804 while (1) {
805 if (!eval_jmp(TOK2("=="))) {
806 ret = ret == evalcmp();
807 continue;
809 if (!eval_jmp(TOK2("!="))) {
810 ret = ret != evalcmp();
811 continue;
813 break;
815 return ret;
818 static long evalbitand(void)
820 long ret = evaleq();
821 while (!eval_jmp('&'))
822 ret &= evaleq();
823 return ret;
826 static long evalxor(void)
828 long ret = evalbitand();
829 while (!eval_jmp('^'))
830 ret ^= evalbitand();
831 return ret;
834 static long evalbitor(void)
836 long ret = evalxor();
837 while (!eval_jmp('|'))
838 ret |= evalxor();
839 return ret;
842 static long evaland(void)
844 long ret = evalbitor();
845 while (!eval_jmp(TOK2("&&")))
846 ret = ret && evalbitor();
847 return ret;
850 static long evalor(void)
852 long ret = evaland();
853 while (!eval_jmp(TOK2("||")))
854 ret = ret || evaland();
855 return ret;
858 static long evalcexpr(void)
860 long ret = evalor();
861 if (eval_jmp('?'))
862 return ret;
863 if (ret)
864 return evalor();
865 while (eval_get() != ':')
867 return evalor();
870 static long evalexpr(void)
872 enext = -1;
873 return evalcexpr();
876 static int buf_loc(char *s, int off)
878 char *e = s + off;
879 int n = 1;
880 while ((s = strchr(s, '\n')) && s < e) {
881 n++;
882 s++;
884 return n;
887 int cpp_loc(char *s, long addr)
889 int line = -1;
890 int i;
891 for (i = nbufs - 1; i > 0; i--)
892 if (bufs[i].type == BUF_FILE)
893 break;
894 if (addr >= hunk_off && i == nbufs - 1)
895 line = buf_loc(buf, (cur - hunk_len) + (addr - hunk_off));
896 else
897 line = buf_loc(bufs[i].buf, bufs[i].cur);
898 sprintf(s, "%s:%d: ", bufs[i].path, line);
899 return strlen(s);