cpp: merge cur++'s in readarg()
[neatcc/cc.git] / cpp.c
blobc5819ebb1214fc8c24d6f88e0ba1e436847ab465
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 void die(char *msg)
57 write(2, msg, strlen(msg));
58 exit(1);
61 static void buf_new(int type, char *dat, int dlen)
63 if (nbufs) {
64 bufs[nbufs - 1].buf = buf;
65 bufs[nbufs - 1].cur = cur;
66 bufs[nbufs - 1].len = len;
68 if (nbufs >= MAXBUFS)
69 die("nomem: MAXBUFS reached!\n");
70 nbufs++;
71 cur = 0;
72 buf = dat;
73 len = dlen;
74 bufs[nbufs - 1].type = type;
77 static void buf_file(char *path, char *dat, int dlen)
79 buf_new(BUF_FILE, dat, dlen);
80 strcpy(bufs[nbufs - 1].path, path ? path : "");
83 static void buf_macro(struct macro *m)
85 buf_new(BUF_MACRO, m->def, strlen(m->def));
86 bufs[nbufs - 1].macro = m;
89 static void buf_arg(char *arg, int mbuf)
91 buf_new(BUF_ARG, arg, strlen(arg));
92 bufs[nbufs - 1].arg_buf = mbuf;
95 static void buf_pop(void)
97 nbufs--;
98 if (nbufs) {
99 cur = bufs[nbufs - 1].cur;
100 len = bufs[nbufs - 1].len;
101 buf = bufs[nbufs - 1].buf;
105 static int buf_iseval(void)
107 int i;
108 for (i = nbufs - 1; i >= 0; i--)
109 if (bufs[i].type == BUF_EVAL)
110 return 1;
111 return 0;
114 static size_t file_size(int fd)
116 struct stat st;
117 if (!fstat(fd, &st))
118 return st.st_size;
119 return 0;
122 static int include_file(char *path)
124 int fd = open(path, O_RDONLY);
125 int n = 0, nr = 0;
126 char *dat;
127 int size;
128 if (fd == -1)
129 return -1;
130 size = file_size(fd) + 1;
131 dat = malloc(size);
132 while ((n = read(fd, dat + nr, size - nr)) > 0)
133 nr += n;
134 close(fd);
135 dat[nr] = '\0';
136 buf_file(path, dat, nr);
137 return 0;
140 int cpp_init(char *path)
142 return include_file(path);
145 static void jumpws(void)
147 while (cur < len && isspace(buf[cur]))
148 cur++;
151 static void read_word(char *dst)
153 jumpws();
154 while (cur < len && (isalnum(buf[cur]) || buf[cur] == '_'))
155 *dst++ = buf[cur++];
156 *dst = '\0';
159 static int jumpcomment(void)
161 if (buf[cur] == '/' && buf[cur + 1] == '*') {
162 while (++cur < len) {
163 if (buf[cur] == '*' && buf[cur + 1] == '/') {
164 cur += 2;
165 return 0;
169 if (buf[cur] == '/' && buf[cur + 1] == '/') {
170 while (++cur < len)
171 if (buf[cur] == '\n')
172 break;
173 return 0;
175 return 1;
178 static void read_tilleol(char *dst)
180 while (cur < len && isspace(buf[cur]) && buf[cur] != '\n')
181 cur++;
182 while (cur < len && buf[cur] != '\n') {
183 if (buf[cur] == '\\' && buf[cur + 1] == '\n')
184 cur += 2;
185 else if (jumpcomment())
186 *dst++ = buf[cur++];
188 *dst = '\0';
191 static char *putstr(char *d, char *s)
193 while (*s)
194 *d++ = *s++;
195 *d = '\0';
196 return d;
199 #define MAXLOCS (1 << 10)
201 static char *locs[MAXLOCS] = {"/usr/include"};
202 static int nlocs = 1;
204 void cpp_addpath(char *s)
206 locs[nlocs++] = s;
209 static int include_find(char *name, int std)
211 int i;
212 for (i = std ? nlocs - 1 : nlocs; i >= 0; i--) {
213 char path[1 << 10];
214 char *s;
215 s = path;
216 if (locs[i]) {
217 s = putstr(s, locs[i]);
218 *s++ = '/';
220 s = putstr(s, name);
221 if (!include_file(path))
222 return 0;
224 return -1;
227 static int jumpstr(void)
229 if (buf[cur] == '\'') {
230 while (cur < len && buf[++cur] != '\'')
231 if (buf[cur] == '\\')
232 cur++;
233 cur++;
234 return 0;
236 if (buf[cur] == '"') {
237 while (cur < len && buf[++cur] != '"')
238 if (buf[cur] == '\\')
239 cur++;
240 cur++;
241 return 0;
243 return 1;
246 static void readarg(char *s)
248 int depth = 0;
249 int beg = cur;
250 while (cur < len && (depth || buf[cur] != ',' && buf[cur] != ')')) {
251 if (!jumpstr() || !jumpcomment())
252 continue;
253 switch (buf[cur++]) {
254 case '(':
255 case '[':
256 case '{':
257 depth++;
258 break;
259 case ')':
260 case ']':
261 case '}':
262 depth--;
263 break;
266 if (s) {
267 memcpy(s, buf + beg, cur - beg);
268 s[cur - beg] = '\0';
272 static int macro_find(char *name)
274 char *n = tab_get(&mtab, name);
275 if (!n)
276 return -1;
277 return container(n, struct macro, name) - macros;
280 static void macro_undef(char *name)
282 int i = macro_find(name);
283 if (i >= 0)
284 tab_del(&mtab, macros[i].name);
287 static int macro_new(char *name)
289 int i = macro_find(name);
290 if (i >= 0)
291 return i;
292 if (nmacros >= MAXDEFS)
293 die("nomem: MAXDEFS reached!\n");
294 i = nmacros++;
295 strcpy(macros[i].name, name);
296 tab_add(&mtab, macros[i].name);
297 return i;
300 static void macro_define(void)
302 char name[NAMELEN];
303 struct macro *d;
304 read_word(name);
305 d = &macros[macro_new(name)];
306 d->isfunc = 0;
307 d->nargs = 0;
308 if (buf[cur] == '(') {
309 cur++;
310 jumpws();
311 while (cur < len && buf[cur] != ')') {
312 readarg(d->args[d->nargs++]);
313 jumpws();
314 if (buf[cur] != ',')
315 break;
316 cur++;
317 jumpws();
319 cur++;
320 d->isfunc = 1;
322 read_tilleol(d->def);
325 int cpp_read(char *buf);
327 static char ebuf[BUFSIZE];
328 static int elen;
329 static int ecur;
331 static long evalexpr(void);
333 static int cpp_eval(void)
335 int bufid;
336 int ret;
337 char evalbuf[BUFSIZE];
338 read_tilleol(evalbuf);
339 buf_new(BUF_EVAL, evalbuf, strlen(evalbuf));
340 bufid = nbufs;
341 elen = 0;
342 ecur = 0;
343 while (bufid < nbufs || (bufid == nbufs && cur < len))
344 elen += cpp_read(ebuf + elen);
345 ret = evalexpr();
346 buf_pop();
347 return ret;
350 static void jumpifs(int jumpelse)
352 int depth = 0;
353 while (cur < len) {
354 if (buf[cur] == '#') {
355 char cmd[NAMELEN];
356 cur++;
357 read_word(cmd);
358 if (!strcmp("else", cmd))
359 if (!depth && !jumpelse)
360 break;
361 if (!strcmp("elif", cmd))
362 if (!depth && !jumpelse && cpp_eval())
363 break;
364 if (!strcmp("endif", cmd)) {
365 if (!depth)
366 break;
367 else
368 depth--;
370 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd) ||
371 !strcmp("if", cmd))
372 depth++;
373 continue;
375 if (!jumpcomment())
376 continue;
377 if (!jumpstr())
378 continue;
379 cur++;
383 static int cpp_cmd(void)
385 char cmd[NAMELEN];
386 cur++;
387 read_word(cmd);
388 if (!strcmp("define", cmd)) {
389 macro_define();
390 return 0;
392 if (!strcmp("undef", cmd)) {
393 char name[NAMELEN];
394 read_word(name);
395 macro_undef(name);
396 return 0;
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 0;
414 if (!strcmp("else", cmd) || !strcmp("elif", cmd)) {
415 jumpifs(1);
416 return 0;
418 if (!strcmp("endif", cmd))
419 return 0;
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 0;
433 return 1;
436 static int macro_arg(struct macro *m, char *arg)
438 int i;
439 for (i = 0; i < m->nargs; i++)
440 if (!strcmp(arg, m->args[i]))
441 return i;
442 return -1;
445 static int buf_arg_find(char *name)
447 int i;
448 for (i = nbufs - 1; i >= 0; i--) {
449 struct buf *mbuf = &bufs[i];
450 struct macro *m = mbuf->macro;
451 if (mbuf->type == BUF_MACRO && macro_arg(m, name) >= 0)
452 return i;
453 if (mbuf->type == BUF_ARG)
454 i = mbuf->arg_buf;
456 return -1;
459 static void macro_expand(void)
461 char name[NAMELEN];
462 struct macro *m;
463 int mbuf;
464 read_word(name);
465 if ((mbuf = buf_arg_find(name)) >= 0) {
466 int arg = macro_arg(bufs[mbuf].macro, name);
467 char *dat = bufs[mbuf].args[arg];
468 buf_arg(dat, mbuf);
469 return;
471 m = &macros[macro_find(name)];
472 if (!m->isfunc) {
473 buf_macro(m);
474 return;
476 jumpws();
477 if (buf[cur] == '(') {
478 int i = 0;
479 struct buf *mbuf = &bufs[nbufs];
480 cur++;
481 jumpws();
482 while (cur < len && buf[cur] != ')') {
483 readarg(mbuf->args[i++]);
484 jumpws();
485 if (buf[cur] != ',')
486 break;
487 cur++;
488 jumpws();
490 while (i < m->nargs)
491 mbuf->args[i++][0] = '\0';
492 cur++;
493 buf_macro(m);
497 static int buf_expanding(char *macro)
499 int i;
500 for (i = nbufs - 1; i >= 0; i--) {
501 if (bufs[i].type == BUF_ARG)
502 return 0;
503 if (bufs[i].type == BUF_MACRO &&
504 !strcmp(macro, bufs[i].macro->name))
505 return 1;
507 return 0;
510 static int expandable(char *word)
512 if (buf_arg_find(word) >= 0)
513 return 1;
514 return !buf_expanding(word) && macro_find(word) != -1;
517 void cpp_define(char *name, char *def)
519 char tmp_buf[MACROLEN];
520 char *s = tmp_buf;
521 s = putstr(s, name);
522 *s++ = '\t';
523 s = putstr(s, def);
524 buf_new(BUF_TEMP, tmp_buf, s - tmp_buf);
525 macro_define();
526 buf_pop();
529 static int seen_macro;
531 static int hunk_off;
532 static int hunk_len;
534 int cpp_read(char *s)
536 int old;
537 if (seen_macro) {
538 seen_macro = 0;
539 macro_expand();
541 if (cur == len) {
542 struct buf *cbuf = &bufs[nbufs - 1];
543 if (nbufs < 2)
544 return -1;
545 if (cbuf->type & BUF_FILE)
546 free(buf);
547 buf_pop();
549 old = cur;
550 if (buf[cur] == '#')
551 if (!cpp_cmd())
552 return 0;
553 while (cur < len) {
554 if (buf[cur] == '#')
555 break;
556 if (!jumpcomment())
557 continue;
558 if (!jumpstr())
559 continue;
560 if (isalpha(buf[cur]) || buf[cur] == '_') {
561 char word[NAMELEN];
562 read_word(word);
563 if (expandable(word)) {
564 cur -= strlen(word);
565 seen_macro = 1;
566 break;
568 if (buf_iseval() && !strcmp("defined", word)) {
569 int parens = 0;
570 jumpws();
571 if (buf[cur] == '(') {
572 parens = 1;
573 cur++;
575 read_word(word);
576 if (parens) {
577 jumpws();
578 cur++;
581 continue;
583 cur++;
585 memcpy(s, buf + old, cur - old);
586 s[cur - old] = '\0';
587 if (!buf_iseval()) {
588 hunk_off += hunk_len;
589 hunk_len = cur - old;
591 return cur - old;
594 /* preprocessor constant expression evaluation */
596 static char etok[NAMELEN];
597 static int enext;
599 static char *tok2[] = {
600 "<<", ">>", "&&", "||", "==", "!=", "<=", ">="
603 static int eval_tok(void)
605 char *s = etok;
606 int i;
607 while (ecur < elen) {
608 while (ecur < elen && isspace(ebuf[ecur]))
609 ecur++;
610 if (ebuf[ecur] == '/' && ebuf[ecur + 1] == '*') {
611 while (ecur < elen && (ebuf[ecur - 2] != '*' ||
612 ebuf[ecur - 1] != '/'))
613 ecur++;
614 continue;
616 break;
618 if (ecur >= elen)
619 return TOK_EOF;
620 if (isalpha(ebuf[ecur]) || ebuf[ecur] == '_') {
621 while (isalnum(ebuf[ecur]) || ebuf[ecur] == '_')
622 *s++ = ebuf[ecur++];
623 *s = '\0';
624 return TOK_NAME;
626 if (isdigit(ebuf[ecur])) {
627 while (isdigit(ebuf[ecur]))
628 *s++ = ebuf[ecur++];
629 while (tolower(ebuf[ecur]) == 'u' || tolower(ebuf[ecur]) == 'l')
630 ecur++;
631 return TOK_NUM;
633 for (i = 0; i < ARRAY_SIZE(tok2); i++)
634 if (TOK2(tok2[i]) == TOK2(ebuf + ecur)) {
635 int ret = TOK2(tok2[i]);
636 ecur += 2;
637 return ret;
639 return ebuf[ecur++];
642 static int eval_see(void)
644 if (enext == -1)
645 enext = eval_tok();
646 return enext;
649 static int eval_get(void)
651 if (enext != -1) {
652 int ret = enext;
653 enext = -1;
654 return ret;
656 return eval_tok();
659 static long eval_num(void)
661 return atol(etok);
664 static int eval_jmp(int tok)
666 if (eval_see() == tok) {
667 eval_get();
668 return 0;
670 return 1;
673 static void eval_expect(int tok)
675 eval_jmp(tok);
678 static char *eval_id(void)
680 return etok;
683 static long evalcexpr(void);
685 static long evalatom(void)
687 if (!eval_jmp(TOK_NUM))
688 return eval_num();
689 if (!eval_jmp(TOK_NAME)) {
690 int parens = !eval_jmp('(');
691 long ret;
692 eval_expect(TOK_NAME);
693 ret = macro_find(eval_id()) >= 0;
694 if (parens)
695 eval_expect(')');
696 return ret;
698 if (!eval_jmp('(')) {
699 long ret = evalcexpr();
700 eval_expect(')');
701 return ret;
703 return -1;
706 static long evalpre(void)
708 if (!eval_jmp('!'))
709 return !evalpre();
710 if (!eval_jmp('-'))
711 return -evalpre();
712 if (!eval_jmp('~'))
713 return ~evalpre();
714 return evalatom();
717 static long evalmul(void)
719 long ret = evalpre();
720 while (1) {
721 if (!eval_jmp('*')) {
722 ret *= evalpre();
723 continue;
725 if (!eval_jmp('/')) {
726 ret /= evalpre();
727 continue;
729 if (!eval_jmp('%')) {
730 ret %= evalpre();
731 continue;
733 break;
735 return ret;
738 static long evaladd(void)
740 long ret = evalmul();
741 while (1) {
742 if (!eval_jmp('+')) {
743 ret += evalmul();
744 continue;
746 if (!eval_jmp('-')) {
747 ret -= evalmul();
748 continue;
750 break;
752 return ret;
755 static long evalshift(void)
757 long ret = evaladd();
758 while (1) {
759 if (!eval_jmp(TOK2("<<"))) {
760 ret <<= evaladd();
761 continue;
763 if (!eval_jmp(TOK2(">>"))) {
764 ret >>= evaladd();
765 continue;
767 break;
769 return ret;
772 static long evalcmp(void)
774 long ret = evalshift();
775 while (1) {
776 if (!eval_jmp('<')) {
777 ret = ret < evalshift();
778 continue;
780 if (!eval_jmp('>')) {
781 ret = ret > evalshift();
782 continue;
784 if (!eval_jmp(TOK2("<="))) {
785 ret = ret <= evalshift();
786 continue;
788 if (!eval_jmp(TOK2(">="))) {
789 ret = ret >= evalshift();
790 continue;
792 break;
794 return ret;
797 static long evaleq(void)
799 long ret = evalcmp();
800 while (1) {
801 if (!eval_jmp(TOK2("=="))) {
802 ret = ret == evalcmp();
803 continue;
805 if (!eval_jmp(TOK2("!="))) {
806 ret = ret != evalcmp();
807 continue;
809 break;
811 return ret;
814 static long evalbitand(void)
816 long ret = evaleq();
817 while (!eval_jmp('&'))
818 ret &= evaleq();
819 return ret;
822 static long evalxor(void)
824 long ret = evalbitand();
825 while (!eval_jmp('^'))
826 ret ^= evalbitand();
827 return ret;
830 static long evalbitor(void)
832 long ret = evalxor();
833 while (!eval_jmp('|'))
834 ret |= evalxor();
835 return ret;
838 static long evaland(void)
840 long ret = evalbitor();
841 while (!eval_jmp(TOK2("&&")))
842 ret = ret && evalbitor();
843 return ret;
846 static long evalor(void)
848 long ret = evaland();
849 while (!eval_jmp(TOK2("||")))
850 ret = ret || evaland();
851 return ret;
854 static long evalcexpr(void)
856 long ret = evalor();
857 if (eval_jmp('?'))
858 return ret;
859 if (ret)
860 return evalor();
861 while (eval_get() != ':')
863 return evalor();
866 static long evalexpr(void)
868 enext = -1;
869 return evalcexpr();
872 static int buf_loc(char *s, int off)
874 char *e = s + off;
875 int n = 1;
876 while ((s = strchr(s, '\n')) && s < e) {
877 n++;
878 s++;
880 return n;
883 int cpp_loc(char *s, long addr)
885 int line = -1;
886 int i;
887 for (i = nbufs - 1; i > 0; i--)
888 if (bufs[i].type == BUF_FILE)
889 break;
890 if (addr >= hunk_off && i == nbufs - 1)
891 line = buf_loc(buf, (cur - hunk_len) + (addr - hunk_off));
892 else
893 line = buf_loc(bufs[i].buf, bufs[i].cur);
894 sprintf(s, "%s:%d: ", bufs[i].path, line);
895 return strlen(s);