gen: fix freeing registers before call
[neatcc/cc.git] / cpp.c
blob7ae737ccaa6a07d47c1dd06d266dd891490f3728
1 #include <ctype.h>
2 #include <fcntl.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include "tok.h"
8 static char *buf;
9 static int len;
10 static int cur;
12 #define MAXDEFS (1 << 12)
13 #define MACROLEN (1 << 10)
14 #define MAXARGS (1 << 5)
16 static struct macro {
17 char name[NAMELEN];
18 char def[MACROLEN];
19 char args[MAXARGS][NAMELEN];
20 int nargs;
21 int isfunc;
22 } macros[MAXDEFS];
23 static int nmacros;
25 #define MAXBUFS (1 << 5)
26 #define BUF_FILE 0
27 #define BUF_MACRO 1
28 #define BUF_EVAL 2
29 #define BUF_TEMP 3
31 static struct buf {
32 char buf[BUFSIZE];
33 char name[NAMELEN];
34 int len;
35 int cur;
36 int type;
37 } bufs[MAXBUFS];
38 static int nbufs;
40 static void buf_new(int type, char *name)
42 if (nbufs) {
43 bufs[nbufs - 1].cur = cur;
44 bufs[nbufs - 1].len = len;
46 if (nbufs >= MAXBUFS)
47 die("nomem: MAXBUFS reached!\n");
48 nbufs++;
49 cur = 0;
50 len = 0;
51 buf = bufs[nbufs - 1].buf;
52 bufs[nbufs - 1].type = type;
53 strcpy(bufs[nbufs -1].name, name ? name : "");
56 static void buf_pop(void)
58 nbufs--;
59 if (nbufs) {
60 cur = bufs[nbufs - 1].cur;
61 len = bufs[nbufs - 1].len;
62 buf = bufs[nbufs - 1].buf;
66 static int buf_iseval(void)
68 int i;
69 for (i = 0; i < nbufs; i++)
70 if (bufs[i].type == BUF_EVAL)
71 return 1;
72 return 0;
75 static int buf_expanding(char *macro)
77 int i;
78 for (i = 0; i < nbufs; i++)
79 if (bufs[i].type == BUF_MACRO && !strcmp(macro, bufs[i].name))
80 return 1;
81 return 0;
84 static void include(int fd)
86 int n = 0;
87 buf_new(BUF_FILE, NULL);
88 while ((n = read(fd, buf + len, BUFSIZE - len)) > 0)
89 len += n;
92 void cpp_init(int fd)
94 cpp_define("__STDC__", "");
95 cpp_define("__x86_64__", "");
96 cpp_define("__linux__", "");
97 include(fd);
100 static void jumpws(void)
102 while (cur < len && isspace(buf[cur]))
103 cur++;
106 static void read_word(char *dst)
108 jumpws();
109 while (cur < len && (isalnum(buf[cur]) || buf[cur] == '_'))
110 *dst++ = buf[cur++];
111 *dst = '\0';
114 static void jumpcomment(void)
116 while (++cur < len) {
117 if (buf[cur] == '*' && buf[cur + 1] == '/') {
118 cur += 2;
119 break;
124 static void read_tilleol(char *dst)
126 while (cur < len && isspace(buf[cur]) && buf[cur] != '\n')
127 cur++;
128 while (cur < len && buf[cur] != '\n') {
129 if (buf[cur] == '\\')
130 cur += 2;
131 else if (buf[cur] == '/' && buf[cur + 1] == '*')
132 jumpcomment();
133 else
134 *dst++ = buf[cur++];
136 *dst = '\0';
139 static char *putstr(char *d, char *s)
141 while (*s)
142 *d++ = *s++;
143 *d = '\0';
144 return d;
147 #define MAXLOCS (1 << 10)
149 static char *locs[MAXLOCS] = {"/usr/include"};
150 static int nlocs = 1;
152 void cpp_addpath(char *s)
154 locs[nlocs++] = s;
157 static int include_find(char *name, int std)
159 int i;
160 int fd;
161 for (i = std ? nlocs - 1 : nlocs; i >= 0; i--) {
162 char path[1 << 10];
163 char *s;
164 s = path;
165 if (locs[i]) {
166 s = putstr(s, locs[i]);
167 *s++ = '/';
169 s = putstr(s, name);
170 fd = open(path, O_RDONLY);
171 if (fd != -1)
172 return fd;
174 return -1;
177 static void jumpstr(void)
179 if (buf[cur] == '\'') {
180 while (cur < len && buf[++cur] != '\'')
181 if (buf[cur] == '\\')
182 cur++;
183 cur++;
184 return;
186 if (buf[cur] == '"') {
187 while (cur < len && buf[++cur] != '"')
188 if (buf[cur] == '\\')
189 cur++;
190 cur++;
191 return;
195 static void readarg(char *s)
197 int depth = 0;
198 int beg = cur;
199 while (cur < len && (depth || buf[cur] != ',' && buf[cur] != ')')) {
200 switch (buf[cur]) {
201 case '(':
202 case '[':
203 case '{':
204 cur++;
205 depth++;
206 break;
207 case ')':
208 case ']':
209 case '}':
210 cur++;
211 depth--;
212 break;
213 case '\'':
214 case '"':
215 jumpstr();
216 break;
217 default:
218 if (buf[cur] == '/' && buf[cur + 1] == '*')
219 jumpcomment();
220 else
221 cur++;
224 memcpy(s, buf + beg, cur - beg);
225 s[cur - beg] = '\0';
228 static int macro_find(char *name)
230 int i;
231 for (i = 0; i < nmacros; i++)
232 if (!strcmp(name, macros[i].name))
233 return i;
234 return -1;
237 static int macro_new(char *name)
239 int i;
240 for (i = 0; i < nmacros; i++) {
241 if (!strcmp(name, macros[i].name))
242 return i;
243 if (!*macros[i].name) {
244 strcpy(macros[i].name, name);
245 return i;
248 if (nmacros >= MAXDEFS)
249 die("nomem: MAXDEFS reached!\n");
250 strcpy(macros[nmacros++].name, name);
251 return nmacros - 1;
254 static void macro_define(void)
256 char name[NAMELEN];
257 struct macro *d;
258 read_word(name);
259 d = &macros[macro_new(name)];
260 d->isfunc = 0;
261 if (buf[cur] == '(') {
262 cur++;
263 jumpws();
264 while (cur < len && buf[cur] != ')') {
265 readarg(d->args[d->nargs++]);
266 jumpws();
267 if (buf[cur++] != ',')
268 break;
269 jumpws();
271 d->isfunc = 1;
273 read_tilleol(d->def);
276 int cpp_read(char *buf);
278 static char ebuf[BUFSIZE];
279 static int elen;
280 static int ecur;
282 static long evalexpr(void);
284 static int cpp_eval(void)
286 int bufid;
287 int ret;
288 char evalbuf[BUFSIZE];
289 read_tilleol(evalbuf);
290 buf_new(BUF_EVAL, NULL);
291 strcpy(buf, evalbuf);
292 len = strlen(evalbuf);
293 bufid = nbufs;
294 elen = 0;
295 ecur = 0;
296 while (bufid < nbufs || cur < len)
297 elen += cpp_read(ebuf + elen);
298 ret = evalexpr();
299 buf_pop();
300 return ret;
303 static void jumpifs(int jumpelse)
305 int depth = 0;
306 while (cur < len) {
307 if (buf[cur] == '#') {
308 char cmd[NAMELEN];
309 cur++;
310 read_word(cmd);
311 if (!strcmp("else", cmd))
312 if (!depth && !jumpelse)
313 break;
314 if (!strcmp("elif", cmd))
315 if (!depth && !jumpelse && cpp_eval())
316 break;
317 if (!strcmp("endif", cmd)) {
318 if (!depth)
319 break;
320 else
321 depth--;
323 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd) ||
324 !strcmp("if", cmd))
325 depth++;
326 continue;
328 if (buf[cur] == '/' && buf[cur + 1] == '*') {
329 jumpcomment();
330 continue;
332 if (buf[cur] == '\'' || buf[cur] == '"') {
333 jumpstr();
334 continue;
336 cur++;
340 static void cpp_cmd(void)
342 char cmd[NAMELEN];
343 cur++;
344 read_word(cmd);
345 if (!strcmp("define", cmd)) {
346 macro_define();
347 return;
349 if (!strcmp("undef", cmd)) {
350 char name[NAMELEN];
351 int idx;
352 read_word(name);
353 idx = macro_find(name);
354 if (idx != -1)
355 strcpy(macros[idx].name, "");
356 return;
358 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd) ||
359 !strcmp("if", cmd)) {
360 char name[NAMELEN];
361 int matched = 0;
362 if (cmd[2]) {
363 int not = cmd[2] == 'n';
364 read_word(name);
365 matched = not ? macro_find(name) < 0 :
366 macro_find(name) >= 0;
367 } else {
368 matched = cpp_eval();
370 if (!matched)
371 jumpifs(0);
372 return;
374 if (!strcmp("else", cmd) || !strcmp("elif", cmd)) {
375 jumpifs(1);
376 return;
378 if (!strcmp("endif", cmd))
379 return;
380 if (!strcmp("include", cmd)) {
381 char file[NAMELEN];
382 char *s, *e;
383 int fd;
384 jumpws();
385 s = buf + cur + 1;
386 e = strchr(buf + cur + 1, buf[cur] == '"' ? '"' : '>');
387 memcpy(file, s, e - s);
388 file[e - s] = '\0';
389 cur += e - s + 2;
390 fd = include_find(file, *e == '>');
391 if (fd == -1)
392 return;
393 include(fd);
394 close(fd);
395 return;
399 static int macro_arg(struct macro *m, char *arg)
401 int i;
402 for (i = 0; i < m->nargs; i++)
403 if (!strcmp(arg, m->args[i]))
404 return i;
405 return -1;
408 static void macro_expand(void)
410 char name[NAMELEN];
411 char args[MAXARGS][MACROLEN];
412 int nargs = 0;
413 struct macro *m;
414 char *dst;
415 int dstlen = 0;
416 int beg;
417 read_word(name);
418 m = &macros[macro_find(name)];
419 if (!m->isfunc) {
420 buf_new(BUF_MACRO, name);
421 strcpy(buf, m->def);
422 len = strlen(m->def);
423 return;
425 jumpws();
426 if (buf[cur] == '(') {
427 cur++;
428 jumpws();
429 while (cur < len && buf[cur] != ')') {
430 readarg(args[nargs++]);
431 jumpws();
432 if (buf[cur] != ',')
433 break;
434 cur++;
435 jumpws();
437 cur++;
438 m->isfunc = 1;
440 buf_new(BUF_MACRO, name);
441 dst = buf;
442 buf = m->def;
443 len = strlen(m->def);
444 beg = cur;
445 while (cur < len) {
446 if (buf[cur] == '/' && buf[cur + 1] == '*') {
447 jumpcomment();
448 continue;
450 if (strchr("'\"", buf[cur])) {
451 jumpstr();
452 continue;
454 if (isalpha(buf[cur]) || buf[cur] == '_') {
455 int arg;
456 char word[NAMELEN];
457 read_word(word);
458 if ((arg = macro_arg(m, word)) != -1) {
459 int len = cur - beg - strlen(word);
460 char *argstr = arg > nargs ? "" : args[arg];
461 int arglen = strlen(argstr);
462 memcpy(dst + dstlen, buf + beg, len);
463 dstlen += len;
464 memcpy(dst + dstlen, argstr, arglen);
465 dstlen += arglen;
466 beg = cur;
468 continue;
470 cur++;
472 memcpy(dst + dstlen, buf + beg, len - beg);
473 dstlen += len - beg;
474 buf = dst;
475 len = dstlen;
476 cur = 0;
477 buf[len] = '\0';
480 void cpp_define(char *name, char *def)
482 char *s;
483 buf_new(BUF_TEMP, NULL);
484 s = buf;
485 s = putstr(s, name);
486 *s++ = '\t';
487 s = putstr(s, def);
488 len = s - buf;
489 macro_define();
490 buf_pop();
493 static int definedword;
495 int cpp_read(char *s)
497 int old;
498 if (definedword) {
499 definedword = 0;
500 macro_expand();
502 if (cur == len) {
503 if (nbufs < 2)
504 return -1;
505 buf_pop();
507 old = cur;
508 if (buf[cur] == '#') {
509 cpp_cmd();
510 return 0;
512 while (cur < len) {
513 if (buf[cur] == '#')
514 break;
515 if (buf[cur] == '/' && buf[cur + 1] == '*') {
516 jumpcomment();
517 continue;
519 if (buf[cur] == '\'' || buf[cur] == '"') {
520 jumpstr();
521 continue;
523 if (isalpha(buf[cur]) || buf[cur] == '_') {
524 char word[NAMELEN];
525 read_word(word);
526 if (!buf_expanding(word) && macro_find(word) != -1) {
527 cur -= strlen(word);
528 definedword = 1;
529 break;
531 if (buf_iseval() && !strcmp("defined", word)) {
532 int parens = 0;
533 jumpws();
534 if (buf[cur] == '(') {
535 parens = 1;
536 cur++;
538 read_word(word);
539 if (parens) {
540 jumpws();
541 cur++;
544 continue;
546 cur++;
548 memcpy(s, buf + old, cur - old);
549 s[cur - old] = '\0';
550 return cur - old;
553 /* preprocessor constant expression evaluation */
555 static char etok[NAMELEN];
556 static int enext;
558 static char *tok2[] = {
559 "<<", ">>", "&&", "||", "==", "!=", "<=", ">="
562 static int eval_tok(void)
564 char *s = etok;
565 int i;
566 while (ecur < elen) {
567 while (ecur < elen && isspace(ebuf[ecur]))
568 ecur++;
569 if (ebuf[ecur] == '/' && ebuf[ecur + 1] == '*') {
570 while (ecur < elen && (ebuf[ecur - 2] != '*' ||
571 ebuf[ecur - 1] != '/'))
572 ecur++;
573 continue;
575 break;
577 if (ecur >= elen)
578 return TOK_EOF;
579 if (isalpha(ebuf[ecur]) || ebuf[ecur] == '_') {
580 while (isalnum(ebuf[ecur]) || ebuf[ecur] == '_')
581 *s++ = ebuf[ecur++];
582 *s = '\0';
583 return TOK_NAME;
585 if (isdigit(ebuf[ecur])) {
586 while (isdigit(ebuf[ecur]))
587 *s++ = ebuf[ecur++];
588 while (tolower(ebuf[ecur]) == 'u' || tolower(ebuf[ecur]) == 'l')
589 ecur++;
590 return TOK_NUM;
592 for (i = 0; i < ARRAY_SIZE(tok2); i++)
593 if (TOK2(tok2[i]) == TOK2(ebuf + ecur)) {
594 int ret = TOK2(tok2[i]);
595 ecur += 2;
596 return ret;
598 return ebuf[ecur++];
601 static int eval_see(void)
603 if (enext == -1)
604 enext = eval_tok();
605 return enext;
608 static int eval_get(void)
610 if (enext != -1) {
611 int ret = enext;
612 enext = -1;
613 return ret;
615 return eval_tok();
618 static long eval_num(void)
620 return atol(etok);
623 static int eval_jmp(int tok)
625 if (eval_see() == tok) {
626 eval_get();
627 return 0;
629 return 1;
632 static void eval_expect(int tok)
634 eval_jmp(tok);
637 static char *eval_id(void)
639 return etok;
642 static long evalcexpr(void);
644 static long evalatom(void)
646 if (!eval_jmp(TOK_NUM))
647 return eval_num();
648 if (!eval_jmp(TOK_NAME)) {
649 int parens = !eval_jmp('(');
650 long ret;
651 eval_expect(TOK_NAME);
652 ret = macro_find(eval_id()) >= 0;
653 if (parens)
654 eval_expect(')');
655 return ret;
657 if (!eval_jmp('(')) {
658 long ret = evalcexpr();
659 eval_expect(')');
660 return ret;
662 return -1;
665 static long evalpre(void)
667 if (!eval_jmp('!'))
668 return !evalpre();
669 if (!eval_jmp('-'))
670 return -evalpre();
671 if (!eval_jmp('~'))
672 return ~evalpre();
673 return evalatom();
676 static long evalmul(void)
678 long ret = evalpre();
679 while (1) {
680 if (!eval_jmp('*')) {
681 ret *= evalpre();
682 continue;
684 if (!eval_jmp('/')) {
685 ret /= evalpre();
686 continue;
688 if (!eval_jmp('%')) {
689 ret %= evalpre();
690 continue;
692 break;
694 return ret;
697 static long evaladd(void)
699 long ret = evalmul();
700 while (1) {
701 if (!eval_jmp('+')) {
702 ret += evalmul();
703 continue;
705 if (!eval_jmp('-')) {
706 ret -= evalmul();
707 continue;
709 break;
711 return ret;
714 static long evalshift(void)
716 long ret = evaladd();
717 while (1) {
718 if (!eval_jmp(TOK2("<<"))) {
719 ret <<= evaladd();
720 continue;
722 if (!eval_jmp(TOK2(">>"))) {
723 ret >>= evaladd();
724 continue;
726 break;
728 return ret;
731 static long evalcmp(void)
733 long ret = evalshift();
734 while (1) {
735 if (!eval_jmp('<')) {
736 ret = ret < evalshift();
737 continue;
739 if (!eval_jmp('>')) {
740 ret = ret > evalshift();
741 continue;
743 if (!eval_jmp(TOK2("<="))) {
744 ret = ret <= evalshift();
745 continue;
747 if (!eval_jmp(TOK2(">="))) {
748 ret = ret >= evalshift();
749 continue;
751 break;
753 return ret;
756 static long evaleq(void)
758 long ret = evalcmp();
759 while (1) {
760 if (!eval_jmp(TOK2("=="))) {
761 ret = ret == evalcmp();
762 continue;
764 if (!eval_jmp(TOK2("!="))) {
765 ret = ret != evalcmp();
766 continue;
768 break;
770 return ret;
773 static long evalbitand(void)
775 long ret = evaleq();
776 while (!eval_jmp('&'))
777 ret &= evaleq();
778 return ret;
781 static long evalxor(void)
783 long ret = evalbitand();
784 while (!eval_jmp('^'))
785 ret ^= evalbitand();
786 return ret;
789 static long evalbitor(void)
791 long ret = evalxor();
792 while (!eval_jmp('|'))
793 ret |= evalxor();
794 return ret;
797 static long evaland(void)
799 long ret = evalbitor();
800 while (!eval_jmp(TOK2("&&")))
801 ret = ret && evalbitor();
802 return ret;
805 static long evalor(void)
807 long ret = evaland();
808 while (!eval_jmp(TOK2("||")))
809 ret = ret || evaland();
810 return ret;
813 static long evalcexpr(void)
815 long ret = evalor();
816 if (eval_jmp('?'))
817 return ret;
818 if (ret)
819 return evalor();
820 while (eval_get() != ':')
822 return evalor();
825 static long evalexpr(void)
827 enext = -1;
828 return evalcexpr();