more verbose error messages for missing files
[neatcc.git] / cpp.c
blobe43f0501e48cd036c6be427dda60bfc1b6fa4a01
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 void read_tilleol(char *dst)
186 while (cur < len && isspace(buf[cur]) && buf[cur] != '\n')
187 cur++;
188 while (cur < len && buf[cur] != '\n') {
189 if (buf[cur] == '\\' && buf[cur + 1] == '\n')
190 cur += 2;
191 else if (jumpcomment())
192 *dst++ = buf[cur++];
194 *dst = '\0';
197 static char *putstr(char *d, char *s)
199 while (*s)
200 *d++ = *s++;
201 *d = '\0';
202 return d;
205 #define MAXLOCS (1 << 10)
207 static char *locs[MAXLOCS] = {};
208 static int nlocs = 0;
210 void cpp_addpath(char *s)
212 locs[nlocs++] = s;
215 static int include_find(char *name, int std)
217 int i;
218 for (i = std ? nlocs - 1 : nlocs; i >= 0; i--) {
219 char path[1 << 10];
220 char *s;
221 s = path;
222 if (locs[i]) {
223 s = putstr(s, locs[i]);
224 *s++ = '/';
226 s = putstr(s, name);
227 if (!include_file(path))
228 return 0;
230 return -1;
233 static int jumpstr(void)
235 if (buf[cur] == '\'') {
236 while (cur < len && buf[++cur] != '\'')
237 if (buf[cur] == '\\')
238 cur++;
239 cur++;
240 return 0;
242 if (buf[cur] == '"') {
243 while (cur < len && buf[++cur] != '"')
244 if (buf[cur] == '\\')
245 cur++;
246 cur++;
247 return 0;
249 return 1;
252 static void readarg(char *s)
254 int depth = 0;
255 int beg = cur;
256 while (cur < len && (depth || buf[cur] != ',' && buf[cur] != ')')) {
257 if (!jumpstr() || !jumpcomment())
258 continue;
259 switch (buf[cur++]) {
260 case '(':
261 case '[':
262 case '{':
263 depth++;
264 break;
265 case ')':
266 case ']':
267 case '}':
268 depth--;
269 break;
272 if (s) {
273 memcpy(s, buf + beg, cur - beg);
274 s[cur - beg] = '\0';
278 static int macro_find(char *name)
280 char *n = tab_get(&mtab, name);
281 if (!n)
282 return -1;
283 return container(n, struct macro, name) - macros;
286 static void macro_undef(char *name)
288 int i = macro_find(name);
289 if (i >= 0)
290 tab_del(&mtab, macros[i].name);
293 static int macro_new(char *name)
295 int i = macro_find(name);
296 if (i >= 0)
297 return i;
298 if (nmacros >= MAXDEFS)
299 die("nomem: MAXDEFS reached!\n");
300 i = nmacros++;
301 strcpy(macros[i].name, name);
302 tab_add(&mtab, macros[i].name);
303 return i;
306 static void macro_define(void)
308 char name[NAMELEN];
309 struct macro *d;
310 read_word(name);
311 d = &macros[macro_new(name)];
312 d->isfunc = 0;
313 d->nargs = 0;
314 if (buf[cur] == '(') {
315 cur++;
316 jumpws();
317 while (cur < len && buf[cur] != ')') {
318 readarg(d->args[d->nargs++]);
319 jumpws();
320 if (buf[cur] != ',')
321 break;
322 cur++;
323 jumpws();
325 cur++;
326 d->isfunc = 1;
328 read_tilleol(d->def);
331 int cpp_read(char *buf);
333 static char ebuf[BUFSIZE];
334 static int elen;
335 static int ecur;
337 static long evalexpr(void);
339 static int cpp_eval(void)
341 int bufid;
342 int ret;
343 char evalbuf[BUFSIZE];
344 read_tilleol(evalbuf);
345 buf_new(BUF_EVAL, evalbuf, strlen(evalbuf));
346 bufid = nbufs;
347 elen = 0;
348 ecur = 0;
349 while (bufid < nbufs || (bufid == nbufs && cur < len))
350 elen += cpp_read(ebuf + elen);
351 ret = evalexpr();
352 buf_pop();
353 return ret;
356 static void jumpifs(int jumpelse)
358 int depth = 0;
359 while (cur < len) {
360 if (buf[cur] == '#') {
361 char cmd[NAMELEN];
362 cur++;
363 read_word(cmd);
364 if (!strcmp("else", cmd))
365 if (!depth && !jumpelse)
366 break;
367 if (!strcmp("elif", cmd))
368 if (!depth && !jumpelse && cpp_eval())
369 break;
370 if (!strcmp("endif", cmd)) {
371 if (!depth)
372 break;
373 else
374 depth--;
376 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd) ||
377 !strcmp("if", cmd))
378 depth++;
379 continue;
381 if (!jumpcomment())
382 continue;
383 if (!jumpstr())
384 continue;
385 cur++;
389 static int cpp_cmd(void)
391 char cmd[NAMELEN];
392 cur++;
393 read_word(cmd);
394 if (!strcmp("define", cmd)) {
395 macro_define();
396 return 0;
398 if (!strcmp("undef", cmd)) {
399 char name[NAMELEN];
400 read_word(name);
401 macro_undef(name);
402 return 0;
404 if (!strcmp("ifdef", cmd) || !strcmp("ifndef", cmd) ||
405 !strcmp("if", cmd)) {
406 char name[NAMELEN];
407 int matched = 0;
408 if (cmd[2]) {
409 int not = cmd[2] == 'n';
410 read_word(name);
411 matched = not ? macro_find(name) < 0 :
412 macro_find(name) >= 0;
413 } else {
414 matched = cpp_eval();
416 if (!matched)
417 jumpifs(0);
418 return 0;
420 if (!strcmp("else", cmd) || !strcmp("elif", cmd)) {
421 jumpifs(1);
422 return 0;
424 if (!strcmp("endif", cmd))
425 return 0;
426 if (!strcmp("include", cmd)) {
427 char file[NAMELEN];
428 char *s, *e;
429 jumpws();
430 s = buf + cur + 1;
431 e = strchr(buf + cur + 1, buf[cur] == '"' ? '"' : '>');
432 memcpy(file, s, e - s);
433 file[e - s] = '\0';
434 cur += e - s + 2;
435 if (include_find(file, *e == '>') == -1)
436 die("cannot include <%s>\n", file);
437 return 0;
439 return 1;
442 static int macro_arg(struct macro *m, char *arg)
444 int i;
445 for (i = 0; i < m->nargs; i++)
446 if (!strcmp(arg, m->args[i]))
447 return i;
448 return -1;
451 static int buf_arg_find(char *name)
453 int i;
454 for (i = nbufs - 1; i >= 0; i--) {
455 struct buf *mbuf = &bufs[i];
456 struct macro *m = mbuf->macro;
457 if (mbuf->type == BUF_MACRO && macro_arg(m, name) >= 0)
458 return i;
459 if (mbuf->type == BUF_ARG)
460 i = mbuf->arg_buf;
462 return -1;
465 static void macro_expand(void)
467 char name[NAMELEN];
468 struct macro *m;
469 int mbuf;
470 read_word(name);
471 if ((mbuf = buf_arg_find(name)) >= 0) {
472 int arg = macro_arg(bufs[mbuf].macro, name);
473 char *dat = bufs[mbuf].args[arg];
474 buf_arg(dat, mbuf);
475 return;
477 m = &macros[macro_find(name)];
478 if (!m->isfunc) {
479 buf_macro(m);
480 return;
482 jumpws();
483 if (buf[cur] == '(') {
484 int i = 0;
485 struct buf *mbuf = &bufs[nbufs];
486 cur++;
487 jumpws();
488 while (cur < len && buf[cur] != ')') {
489 readarg(mbuf->args[i++]);
490 jumpws();
491 if (buf[cur] != ',')
492 break;
493 cur++;
494 jumpws();
496 while (i < m->nargs)
497 mbuf->args[i++][0] = '\0';
498 cur++;
499 buf_macro(m);
503 static int buf_expanding(char *macro)
505 int i;
506 for (i = nbufs - 1; i >= 0; i--) {
507 if (bufs[i].type == BUF_ARG)
508 return 0;
509 if (bufs[i].type == BUF_MACRO &&
510 !strcmp(macro, bufs[i].macro->name))
511 return 1;
513 return 0;
516 static int expandable(char *word)
518 if (buf_arg_find(word) >= 0)
519 return 1;
520 return !buf_expanding(word) && macro_find(word) != -1;
523 void cpp_define(char *name, char *def)
525 char tmp_buf[MACROLEN];
526 char *s = tmp_buf;
527 s = putstr(s, name);
528 *s++ = '\t';
529 s = putstr(s, def);
530 buf_new(BUF_TEMP, tmp_buf, s - tmp_buf);
531 macro_define();
532 buf_pop();
535 static int seen_macro;
537 static int hunk_off;
538 static int hunk_len;
540 int cpp_read(char *s)
542 int old;
543 if (seen_macro) {
544 seen_macro = 0;
545 macro_expand();
547 if (cur == len) {
548 struct buf *cbuf = &bufs[nbufs - 1];
549 if (nbufs < 2)
550 return -1;
551 if (cbuf->type & BUF_FILE)
552 free(buf);
553 buf_pop();
555 old = cur;
556 if (buf[cur] == '#')
557 if (!cpp_cmd())
558 return 0;
559 while (cur < len) {
560 if (buf[cur] == '#')
561 break;
562 if (!jumpcomment())
563 continue;
564 if (!jumpstr())
565 continue;
566 if (isalpha(buf[cur]) || buf[cur] == '_') {
567 char word[NAMELEN];
568 read_word(word);
569 if (expandable(word)) {
570 cur -= strlen(word);
571 seen_macro = 1;
572 break;
574 if (buf_iseval() && !strcmp("defined", word)) {
575 int parens = 0;
576 jumpws();
577 if (buf[cur] == '(') {
578 parens = 1;
579 cur++;
581 read_word(word);
582 if (parens) {
583 jumpws();
584 cur++;
587 continue;
589 cur++;
591 memcpy(s, buf + old, cur - old);
592 s[cur - old] = '\0';
593 if (!buf_iseval()) {
594 hunk_off += hunk_len;
595 hunk_len = cur - old;
597 return cur - old;
600 /* preprocessor constant expression evaluation */
602 static char etok[NAMELEN];
603 static int enext;
605 static char *tok2[] = {
606 "<<", ">>", "&&", "||", "==", "!=", "<=", ">="
609 static int eval_tok(void)
611 char *s = etok;
612 int i;
613 while (ecur < elen) {
614 while (ecur < elen && isspace(ebuf[ecur]))
615 ecur++;
616 if (ebuf[ecur] == '/' && ebuf[ecur + 1] == '*') {
617 while (ecur < elen && (ebuf[ecur - 2] != '*' ||
618 ebuf[ecur - 1] != '/'))
619 ecur++;
620 continue;
622 break;
624 if (ecur >= elen)
625 return TOK_EOF;
626 if (isalpha(ebuf[ecur]) || ebuf[ecur] == '_') {
627 while (isalnum(ebuf[ecur]) || ebuf[ecur] == '_')
628 *s++ = ebuf[ecur++];
629 *s = '\0';
630 return TOK_NAME;
632 if (isdigit(ebuf[ecur])) {
633 while (isdigit(ebuf[ecur]))
634 *s++ = ebuf[ecur++];
635 while (tolower(ebuf[ecur]) == 'u' || tolower(ebuf[ecur]) == 'l')
636 ecur++;
637 return TOK_NUM;
639 for (i = 0; i < ARRAY_SIZE(tok2); i++)
640 if (TOK2(tok2[i]) == TOK2(ebuf + ecur)) {
641 int ret = TOK2(tok2[i]);
642 ecur += 2;
643 return ret;
645 return ebuf[ecur++];
648 static int eval_see(void)
650 if (enext == -1)
651 enext = eval_tok();
652 return enext;
655 static int eval_get(void)
657 if (enext != -1) {
658 int ret = enext;
659 enext = -1;
660 return ret;
662 return eval_tok();
665 static long eval_num(void)
667 return atol(etok);
670 static int eval_jmp(int tok)
672 if (eval_see() == tok) {
673 eval_get();
674 return 0;
676 return 1;
679 static void eval_expect(int tok)
681 eval_jmp(tok);
684 static char *eval_id(void)
686 return etok;
689 static long evalcexpr(void);
691 static long evalatom(void)
693 if (!eval_jmp(TOK_NUM))
694 return eval_num();
695 if (!eval_jmp(TOK_NAME)) {
696 int parens = !eval_jmp('(');
697 long ret;
698 eval_expect(TOK_NAME);
699 ret = macro_find(eval_id()) >= 0;
700 if (parens)
701 eval_expect(')');
702 return ret;
704 if (!eval_jmp('(')) {
705 long ret = evalcexpr();
706 eval_expect(')');
707 return ret;
709 return -1;
712 static long evalpre(void)
714 if (!eval_jmp('!'))
715 return !evalpre();
716 if (!eval_jmp('-'))
717 return -evalpre();
718 if (!eval_jmp('~'))
719 return ~evalpre();
720 return evalatom();
723 static long evalmul(void)
725 long ret = evalpre();
726 while (1) {
727 if (!eval_jmp('*')) {
728 ret *= evalpre();
729 continue;
731 if (!eval_jmp('/')) {
732 ret /= evalpre();
733 continue;
735 if (!eval_jmp('%')) {
736 ret %= evalpre();
737 continue;
739 break;
741 return ret;
744 static long evaladd(void)
746 long ret = evalmul();
747 while (1) {
748 if (!eval_jmp('+')) {
749 ret += evalmul();
750 continue;
752 if (!eval_jmp('-')) {
753 ret -= evalmul();
754 continue;
756 break;
758 return ret;
761 static long evalshift(void)
763 long ret = evaladd();
764 while (1) {
765 if (!eval_jmp(TOK2("<<"))) {
766 ret <<= evaladd();
767 continue;
769 if (!eval_jmp(TOK2(">>"))) {
770 ret >>= evaladd();
771 continue;
773 break;
775 return ret;
778 static long evalcmp(void)
780 long ret = evalshift();
781 while (1) {
782 if (!eval_jmp('<')) {
783 ret = ret < evalshift();
784 continue;
786 if (!eval_jmp('>')) {
787 ret = ret > evalshift();
788 continue;
790 if (!eval_jmp(TOK2("<="))) {
791 ret = ret <= evalshift();
792 continue;
794 if (!eval_jmp(TOK2(">="))) {
795 ret = ret >= evalshift();
796 continue;
798 break;
800 return ret;
803 static long evaleq(void)
805 long ret = evalcmp();
806 while (1) {
807 if (!eval_jmp(TOK2("=="))) {
808 ret = ret == evalcmp();
809 continue;
811 if (!eval_jmp(TOK2("!="))) {
812 ret = ret != evalcmp();
813 continue;
815 break;
817 return ret;
820 static long evalbitand(void)
822 long ret = evaleq();
823 while (!eval_jmp('&'))
824 ret &= evaleq();
825 return ret;
828 static long evalxor(void)
830 long ret = evalbitand();
831 while (!eval_jmp('^'))
832 ret ^= evalbitand();
833 return ret;
836 static long evalbitor(void)
838 long ret = evalxor();
839 while (!eval_jmp('|'))
840 ret |= evalxor();
841 return ret;
844 static long evaland(void)
846 long ret = evalbitor();
847 while (!eval_jmp(TOK2("&&")))
848 ret = ret && evalbitor();
849 return ret;
852 static long evalor(void)
854 long ret = evaland();
855 while (!eval_jmp(TOK2("||")))
856 ret = ret || evaland();
857 return ret;
860 static long evalcexpr(void)
862 long ret = evalor();
863 if (eval_jmp('?'))
864 return ret;
865 if (ret)
866 return evalor();
867 while (eval_get() != ':')
869 return evalor();
872 static long evalexpr(void)
874 enext = -1;
875 return evalcexpr();
878 static int buf_loc(char *s, int off)
880 char *e = s + off;
881 int n = 1;
882 while ((s = strchr(s, '\n')) && s < e) {
883 n++;
884 s++;
886 return n;
889 char *cpp_loc(long addr)
891 static char loc[256];
892 int line = -1;
893 int i;
894 for (i = nbufs - 1; i > 0; i--)
895 if (bufs[i].type == BUF_FILE)
896 break;
897 if (addr >= hunk_off && i == nbufs - 1)
898 line = buf_loc(buf, (cur - hunk_len) + (addr - hunk_off));
899 else
900 line = buf_loc(bufs[i].buf, bufs[i].cur);
901 sprintf(loc, "%s:%d", bufs[i].path, line);
902 return loc;