cpp: space between macro and '('
[neatcc/cc.git] / cpp.c
blob427d6c02df198fcc77979d2ed645a40678748842
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 << 10)
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)
27 static struct buf {
28 char buf[BUFSIZE];
29 int len;
30 int cur;
31 } bufs[MAXBUFS];
32 static int nbufs;
34 static void buf_new(void)
36 if (nbufs) {
37 bufs[nbufs - 1].cur = cur;
38 bufs[nbufs - 1].len = len;
40 if (nbufs >= MAXBUFS)
41 die("nomem: MAXBUFS reached!\n");
42 nbufs++;
43 cur = 0;
44 len = 0;
45 buf = bufs[nbufs - 1].buf;
48 static void buf_pop(void)
50 nbufs--;
51 if (nbufs) {
52 cur = bufs[nbufs - 1].cur;
53 len = bufs[nbufs - 1].len;
54 buf = bufs[nbufs - 1].buf;
58 static void include(int fd)
60 int n = 0;
61 buf_new();
62 while ((n = read(fd, buf + len, BUFSIZE - len)) > 0)
63 len += n;
66 void cpp_init(int fd)
68 cpp_define("__STDC__", "");
69 cpp_define("__x86_64__", "");
70 cpp_define("__linux__", "");
71 include(fd);
74 static void jumpws(void)
76 while (cur < len && isspace(buf[cur]))
77 cur++;
80 static void read_word(char *dst)
82 jumpws();
83 while (cur < len && (isalnum(buf[cur]) || buf[cur] == '_'))
84 *dst++ = buf[cur++];
85 *dst = '\0';
88 static void jumpcomment(void)
90 while (++cur < len) {
91 if (buf[cur] == '*' && buf[cur + 1] == '/') {
92 cur += 2;
93 break;
98 static void read_tilleol(char *dst)
100 while (cur < len && isspace(buf[cur]) && buf[cur] != '\n')
101 cur++;
102 while (cur < len && buf[cur] != '\n') {
103 if (buf[cur] == '\\')
104 cur += 2;
105 else if (buf[cur] == '/' && buf[cur + 1] == '*')
106 jumpcomment();
107 else
108 *dst++ = buf[cur++];
110 *dst = '\0';
113 static char *putstr(char *d, char *s)
115 while (*s)
116 *d++ = *s++;
117 *d = '\0';
118 return d;
121 #define MAXLOCS (1 << 10)
123 static char *locs[MAXLOCS] = {"/usr/include"};
124 static int nlocs = 1;
126 void cpp_addpath(char *s)
128 locs[nlocs++] = s;
131 static int include_find(char *name, int std)
133 int i;
134 int fd;
135 for (i = std ? nlocs - 1 : nlocs; i >= 0; i--) {
136 char path[1 << 10];
137 char *s;
138 s = path;
139 if (locs[i]) {
140 s = putstr(s, locs[i]);
141 *s++ = '/';
143 s = putstr(s, name);
144 fd = open(path, O_RDONLY);
145 if (fd != -1)
146 return fd;
148 return -1;
151 static void jumpstr(void)
153 if (buf[cur] == '\'') {
154 while (cur < len && buf[++cur] != '\'')
155 if (buf[cur] == '\\')
156 cur++;
157 cur++;
158 return;
160 if (buf[cur] == '"') {
161 while (cur < len && buf[++cur] != '"')
162 if (buf[cur] == '\\')
163 cur++;
164 cur++;
165 return;
169 static void readarg(char *s)
171 int depth = 0;
172 int beg = cur;
173 while (cur < len && (depth || buf[cur] != ',' && buf[cur] != ')')) {
174 switch (buf[cur]) {
175 case '(':
176 case '[':
177 case '{':
178 cur++;
179 depth++;
180 break;
181 case ')':
182 case ']':
183 case '}':
184 cur++;
185 depth--;
186 break;
187 case '\'':
188 case '"':
189 jumpstr();
190 break;
191 default:
192 if (buf[cur] == '/' && buf[cur + 1] == '*')
193 jumpcomment();
194 else
195 cur++;
198 memcpy(s, buf + beg, cur - beg);
199 s[cur - beg] = '\0';
202 static int macro_find(char *name)
204 int i;
205 for (i = 0; i < nmacros; i++)
206 if (!strcmp(name, macros[i].name))
207 return i;
208 return -1;
211 static int macro_new(char *name)
213 int i;
214 for (i = 0; i < nmacros; i++) {
215 if (!strcmp(name, macros[i].name))
216 return i;
217 if (!*macros[i].name) {
218 strcpy(macros[i].name, name);
219 return i;
222 if (nmacros >= MAXDEFS)
223 die("nomem: MAXDEFS reached!\n");
224 strcpy(macros[nmacros++].name, name);
225 return nmacros - 1;
228 static void macro_define(void)
230 char name[NAMELEN];
231 struct macro *d;
232 read_word(name);
233 d = &macros[macro_new(name)];
234 d->isfunc = 0;
235 if (buf[cur] == '(') {
236 cur++;
237 jumpws();
238 while (cur < len && buf[cur] != ')') {
239 readarg(d->args[d->nargs++]);
240 jumpws();
241 if (buf[cur++] != ',')
242 break;
243 jumpws();
245 d->isfunc = 1;
247 read_tilleol(d->def);
250 int cpp_read(char *buf);
252 static char ebuf[BUFSIZE];
253 static int elen;
254 static int ecur;
255 static int cppeval;
257 static long evalexpr(void);
259 static int cpp_eval(void)
261 int bufid;
262 int ret;
263 char evalbuf[BUFSIZE];
264 read_tilleol(evalbuf);
265 buf_new();
266 strcpy(buf, evalbuf);
267 len = strlen(evalbuf);
268 bufid = nbufs;
269 elen = 0;
270 ecur = 0;
271 cppeval = 1;
272 while (bufid < nbufs || cur < len)
273 elen += cpp_read(ebuf + elen);
274 cppeval = 0;
275 ret = evalexpr();
276 buf_pop();
277 return ret;
280 static void jumpifs(int jumpelse)
282 int depth = 0;
283 while (cur < len) {
284 if (buf[cur] == '#') {
285 char cmd[NAMELEN];
286 cur++;
287 read_word(cmd);
288 if (!strcmp("else", cmd))
289 if (!depth && !jumpelse)
290 break;
291 if (!strcmp("elif", cmd))
292 if (!depth && !jumpelse && cpp_eval())
293 break;
294 if (!strcmp("endif", cmd)) {
295 if (!depth)
296 break;
297 else
298 depth--;
300 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd) ||
301 !strcmp("if", cmd))
302 depth++;
303 continue;
305 if (buf[cur] == '/' && buf[cur + 1] == '*') {
306 jumpcomment();
307 continue;
309 if (buf[cur] == '\'' || buf[cur] == '"') {
310 jumpstr();
311 continue;
313 cur++;
317 static void cpp_cmd(void)
319 char cmd[NAMELEN];
320 cur++;
321 read_word(cmd);
322 if (!strcmp("define", cmd)) {
323 macro_define();
324 return;
326 if (!strcmp("undef", cmd)) {
327 char name[NAMELEN];
328 int idx;
329 read_word(name);
330 idx = macro_find(name);
331 if (idx != -1)
332 strcpy(macros[idx].name, "");
333 return;
335 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd) ||
336 !strcmp("if", cmd)) {
337 char name[NAMELEN];
338 int matched = 0;
339 if (cmd[2]) {
340 int not = cmd[2] == 'n';
341 read_word(name);
342 matched = not ? macro_find(name) < 0 :
343 macro_find(name) >= 0;
344 } else {
345 matched = cpp_eval();
347 if (!matched)
348 jumpifs(0);
349 return;
351 if (!strcmp("else", cmd) || !strcmp("elif", cmd)) {
352 jumpifs(1);
353 return;
355 if (!strcmp("endif", cmd))
356 return;
357 if (!strcmp("include", cmd)) {
358 char file[NAMELEN];
359 char *s, *e;
360 int fd;
361 jumpws();
362 s = buf + cur + 1;
363 e = strchr(buf + cur + 1, buf[cur] == '"' ? '"' : '>');
364 memcpy(file, s, e - s);
365 file[e - s] = '\0';
366 cur += e - s + 2;
367 fd = include_find(file, *e == '>');
368 if (fd == -1)
369 return;
370 include(fd);
371 close(fd);
372 return;
376 static int macro_arg(struct macro *m, char *arg)
378 int i;
379 for (i = 0; i < m->nargs; i++)
380 if (!strcmp(arg, m->args[i]))
381 return i;
382 return -1;
385 static void macro_expand(void)
387 char name[NAMELEN];
388 char args[MAXARGS][MACROLEN];
389 int nargs = 0;
390 struct macro *m;
391 char *dst;
392 int dstlen = 0;
393 int beg;
394 read_word(name);
395 m = &macros[macro_find(name)];
396 if (!m->isfunc) {
397 buf_new();
398 strcpy(buf, m->def);
399 len = strlen(m->def);
400 return;
402 jumpws();
403 if (buf[cur] == '(') {
404 cur++;
405 jumpws();
406 while (cur < len && buf[cur] != ')') {
407 readarg(args[nargs++]);
408 jumpws();
409 if (buf[cur] != ',')
410 break;
411 jumpws();
413 cur++;
414 m->isfunc = 1;
416 buf_new();
417 dst = buf;
418 buf = m->def;
419 len = strlen(m->def);
420 beg = cur;
421 while (cur < len) {
422 if (buf[cur] == '/' && buf[cur + 1] == '*') {
423 jumpcomment();
424 continue;
426 if (strchr("'\"", buf[cur])) {
427 jumpstr();
428 continue;
430 if (isalpha(buf[cur]) || buf[cur] == '_') {
431 int arg;
432 char word[NAMELEN];
433 read_word(word);
434 if ((arg = macro_arg(m, word)) != -1) {
435 int len = cur - beg - strlen(word);
436 char *argstr = arg > nargs ? "" : args[arg];
437 int arglen = strlen(argstr);
438 memcpy(dst + dstlen, buf + beg, len);
439 dstlen += len;
440 memcpy(dst + dstlen, argstr, arglen);
441 dstlen += arglen;
442 beg = cur;
444 continue;
446 cur++;
448 memcpy(dst + dstlen, buf + beg, len - beg);
449 dstlen += len - beg;
450 buf = dst;
451 len = dstlen;
452 cur = 0;
453 buf[len] = '\0';
456 void cpp_define(char *name, char *def)
458 char *s;
459 buf_new();
460 s = buf;
461 s = putstr(s, name);
462 *s++ = '\t';
463 s = putstr(s, def);
464 len = s - buf;
465 macro_define();
466 buf_pop();
469 static int definedword;
471 int cpp_read(char *s)
473 int old;
474 if (definedword) {
475 definedword = 0;
476 macro_expand();
478 if (cur == len) {
479 if (nbufs < 2)
480 return -1;
481 buf_pop();
483 old = cur;
484 if (buf[cur] == '#') {
485 cpp_cmd();
486 return 0;
488 while (cur < len) {
489 if (buf[cur] == '#')
490 break;
491 if (buf[cur] == '/' && buf[cur + 1] == '*') {
492 jumpcomment();
493 continue;
495 if (buf[cur] == '\'' || buf[cur] == '"') {
496 jumpstr();
497 continue;
499 if (isalpha(buf[cur]) || buf[cur] == '_') {
500 char word[NAMELEN];
501 read_word(word);
502 if (macro_find(word) != -1) {
503 cur -= strlen(word);
504 definedword = 1;
505 break;
507 if (cppeval && !strcmp("defined", word)) {
508 int parens = 0;
509 jumpws();
510 if (buf[cur] == '(') {
511 parens = 1;
512 cur++;
514 read_word(word);
515 if (parens) {
516 jumpws();
517 cur++;
520 continue;
522 cur++;
524 memcpy(s, buf + old, cur - old);
525 s[cur - old] = '\0';
526 return cur - old;
529 /* preprocessor constant expression evaluation */
531 static char etok[NAMELEN];
532 static int enext;
534 static char *tok2[] = {
535 "<<", ">>", "&&", "||", "==", "!=", "<=", ">="
538 static int eval_tok(void)
540 char *s = etok;
541 int i;
542 while (ecur < elen) {
543 while (ecur < elen && isspace(ebuf[ecur]))
544 ecur++;
545 if (ebuf[ecur] == '/' && ebuf[ecur + 1] == '*') {
546 while (ecur < elen && (ebuf[ecur - 2] != '*' ||
547 ebuf[ecur - 1] != '/'))
548 ecur++;
549 continue;
551 break;
553 if (ecur >= elen)
554 return TOK_EOF;
555 if (isalpha(ebuf[ecur]) || ebuf[ecur] == '_') {
556 while (isalnum(ebuf[ecur]) || ebuf[ecur] == '_')
557 *s++ = ebuf[ecur++];
558 *s = '\0';
559 return TOK_NAME;
561 if (isdigit(ebuf[ecur])) {
562 while (isdigit(ebuf[ecur]))
563 *s++ = ebuf[ecur++];
564 while (tolower(ebuf[ecur]) == 'u' || tolower(ebuf[ecur]) == 'l')
565 ecur++;
566 return TOK_NUM;
568 for (i = 0; i < ARRAY_SIZE(tok2); i++)
569 if (TOK2(tok2[i]) == TOK2(ebuf + ecur)) {
570 int ret = TOK2(tok2[i]);
571 ecur += 2;
572 return ret;
574 return ebuf[ecur++];
577 static int eval_see(void)
579 if (enext == -1)
580 enext = eval_tok();
581 return enext;
584 static int eval_get(void)
586 if (enext != -1) {
587 int ret = enext;
588 enext = -1;
589 return ret;
591 return eval_tok();
594 static long eval_num(void)
596 return atol(etok);
599 static int eval_jmp(int tok)
601 if (eval_see() == tok) {
602 eval_get();
603 return 0;
605 return 1;
608 static void eval_expect(int tok)
610 eval_jmp(tok);
613 static char *eval_id(void)
615 return etok;
618 static long evalcexpr(void);
620 static long evalatom(void)
622 if (!eval_jmp(TOK_NUM))
623 return eval_num();
624 if (!eval_jmp(TOK_NAME)) {
625 int parens = !eval_jmp('(');
626 long ret;
627 eval_expect(TOK_NAME);
628 ret = macro_find(eval_id()) >= 0;
629 if (parens)
630 eval_expect(')');
631 return ret;
633 if (!eval_jmp('(')) {
634 long ret = evalcexpr();
635 eval_expect(')');
636 return ret;
638 return -1;
641 static long evalpre(void)
643 if (!eval_jmp('!'))
644 return !evalpre();
645 if (!eval_jmp('-'))
646 return -evalpre();
647 if (!eval_jmp('~'))
648 return ~evalpre();
649 return evalatom();
652 static long evalmul(void)
654 long ret = evalpre();
655 while (1) {
656 if (!eval_jmp('*')) {
657 ret *= evalpre();
658 continue;
660 if (!eval_jmp('/')) {
661 ret /= evalpre();
662 continue;
664 if (!eval_jmp('%')) {
665 ret %= evalpre();
666 continue;
668 break;
670 return ret;
673 static long evaladd(void)
675 long ret = evalmul();
676 while (1) {
677 if (!eval_jmp('+')) {
678 ret += evalmul();
679 continue;
681 if (!eval_jmp('-')) {
682 ret -= evalmul();
683 continue;
685 break;
687 return ret;
690 static long evalshift(void)
692 long ret = evaladd();
693 while (1) {
694 if (!eval_jmp(TOK2("<<"))) {
695 ret <<= evaladd();
696 continue;
698 if (!eval_jmp(TOK2(">>"))) {
699 ret >>= evaladd();
700 continue;
702 break;
704 return ret;
707 static long evalcmp(void)
709 long ret = evalshift();
710 while (1) {
711 if (!eval_jmp('<')) {
712 ret = ret < evalshift();
713 continue;
715 if (!eval_jmp('>')) {
716 ret = ret > evalshift();
717 continue;
719 if (!eval_jmp(TOK2("<="))) {
720 ret = ret <= evalshift();
721 continue;
723 if (!eval_jmp(TOK2(">="))) {
724 ret = ret >= evalshift();
725 continue;
727 break;
729 return ret;
732 static long evaleq(void)
734 long ret = evalcmp();
735 while (1) {
736 if (!eval_jmp(TOK2("=="))) {
737 ret = ret == evalcmp();
738 continue;
740 if (!eval_jmp(TOK2("!="))) {
741 ret = ret != evalcmp();
742 continue;
744 break;
746 return ret;
749 static long evalbitand(void)
751 long ret = evaleq();
752 while (!eval_jmp('&'))
753 ret &= evaleq();
754 return ret;
757 static long evalxor(void)
759 long ret = evalbitand();
760 while (!eval_jmp('^'))
761 ret ^= evalbitand();
762 return ret;
765 static long evalbitor(void)
767 long ret = evalxor();
768 while (!eval_jmp('|'))
769 ret |= evalxor();
770 return ret;
773 static long evaland(void)
775 long ret = evalbitor();
776 while (!eval_jmp(TOK2("&&")))
777 ret = ret && evalbitor();
778 return ret;
781 static long evalor(void)
783 long ret = evaland();
784 while (!eval_jmp(TOK2("||")))
785 ret = ret || evaland();
786 return ret;
789 static long evalcexpr(void)
791 long ret = evalor();
792 if (eval_jmp('?'))
793 return ret;
794 if (ret)
795 return evalor();
796 while (eval_get() != ':')
798 return evalor();
801 static long evalexpr(void)
803 enext = -1;
804 return evalcexpr();