ref: d0ae2e369e0221e796f4b58255b21ce3592d80dc
dir: /sys/src/cmd/cpp/cpp.c/
#include <u.h> #include <libc.h> #include <stdio.h> #include "cpp.h" #define OUTS 16384 char outbuf[OUTS]; char *outp = outbuf; Source *cursource; int nerrs; struct token nltoken = { NL, 0, 0, 0, 1, (uchar*)"\n" }; char *curtime; int incdepth; int ifdepth; int ifsatisfied[NIF]; int skipping; int main(int argc, char **argv) { Tokenrow tr; long t; char ebuf[BUFSIZ]; setbuf(stderr, ebuf); t = time(NULL); curtime = ctime(t); maketokenrow(3, &tr); expandlex(); setup(argc, argv); iniths(); genline(); process(&tr); flushout(); fflush(stderr); exits(nerrs? "errors" : 0); } void process(Tokenrow *trp) { int anymacros = 0; for (;;) { if (trp->tp >= trp->lp) { trp->tp = trp->lp = trp->bp; outp = outbuf; anymacros |= gettokens(trp, 1); trp->tp = trp->bp; } if (trp->tp->type == END) { if (--incdepth>=0) { if (cursource->ifdepth) error(ERROR, "Unterminated conditional in #include"); unsetsource(); cursource->line += cursource->lineinc; trp->tp = trp->lp; genline(); continue; } if (ifdepth) error(ERROR, "Unterminated #if/#ifdef/#ifndef"); break; } if (trp->tp->type==SHARP) { trp->tp += 1; control(trp); } else if (!skipping && anymacros) expandrow(trp, NULL); if (skipping) setempty(trp); puttokens(trp); anymacros = 0; cursource->line += cursource->lineinc; if (cursource->lineinc>1) { genline(); } } } void control(Tokenrow *trp) { Nlist *np; Token *tp; Dir *d; Once n; tp = trp->tp; if (tp->type!=NAME) { if (tp->type==NUMBER) goto kline; if (tp->type != NL) error(ERROR, "Unidentifiable control line"); return; /* else empty line */ } if ((np = lookup(tp, 0))==NULL || (np->flag&ISKW)==0 && !skipping) { error(WARNING, "Unknown preprocessor control %t", tp); return; } if (skipping) { if ((np->flag&ISKW)==0) return; switch (np->val) { case KENDIF: if (--ifdepth<skipping) skipping = 0; --cursource->ifdepth; setempty(trp); return; case KIFDEF: case KIFNDEF: case KIF: if (++ifdepth >= NIF) error(FATAL, "#if too deeply nested"); ++cursource->ifdepth; return; case KELIF: case KELSE: if (ifdepth<=skipping) break; return; default: return; } } switch (np->val) { case KDEFINE: dodefine(trp); break; case KUNDEF: tp += 1; if (tp->type!=NAME || trp->lp - trp->bp != 4) { error(ERROR, "Syntax error in #undef"); break; } if ((np = lookup(tp, 0))) { if (np->flag&ISUNCHANGE) { error(ERROR, "#defined token %t can't be undefined", tp); return; } np->flag &= ~ISDEFINED; } break; case KPRAGMA: tp += 1; if (tp->type!=NAME || tp->len < 4 || memcmp(tp->t, "once", 4) != 0) return; if (nblocked >= NONCE) error(FATAL, "#pragma once list max length exceeded"); d = dirfstat(cursource->fd); if (d == nil) error(FATAL, "Out of memory from dirfstat"); n.qid = d->qid; n.type = d->type; n.dev = d->dev; incblocked[nblocked++] = n; free(d); break; case KIFDEF: case KIFNDEF: case KIF: if (++ifdepth >= NIF) error(FATAL, "#if too deeply nested"); ++cursource->ifdepth; ifsatisfied[ifdepth] = 0; if (eval(trp, np->val)) ifsatisfied[ifdepth] = 1; else skipping = ifdepth; break; case KELIF: if (ifdepth==0) { error(ERROR, "#elif with no #if"); return; } if (ifsatisfied[ifdepth]==2) error(ERROR, "#elif after #else"); if (eval(trp, np->val)) { if (ifsatisfied[ifdepth]) skipping = ifdepth; else { skipping = 0; ifsatisfied[ifdepth] = 1; } } else skipping = ifdepth; break; case KELSE: if (ifdepth==0 || cursource->ifdepth==0) { error(ERROR, "#else with no #if"); return; } if (ifsatisfied[ifdepth]==2) error(ERROR, "#else after #else"); if (trp->lp - trp->bp != 3) error(ERROR, "Syntax error in #else"); skipping = ifsatisfied[ifdepth]? ifdepth: 0; ifsatisfied[ifdepth] = 2; break; case KENDIF: if (ifdepth==0 || cursource->ifdepth==0) { error(ERROR, "#endif with no #if"); return; } --ifdepth; --cursource->ifdepth; if (trp->lp - trp->bp != 3) error(WARNING, "Syntax error in #endif"); break; case KERROR: trp->tp = tp+1; error(ERROR, "#error directive: %r", trp); break; case KWARNING: trp->tp = tp+1; error(WARNING, "#warning directive: %r", trp); break; case KLINE: trp->tp = tp+1; expandrow(trp, "<line>"); tp = trp->bp+2; kline: if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp || (tp+3==trp->lp && ((tp+1)->type!=STRING)||*(tp+1)->t=='L')){ error(ERROR, "Syntax error in #line"); return; } cursource->line = atol((char*)tp->t)-1; if (cursource->line<0 || cursource->line>=32768) error(WARNING, "#line specifies number out of range"); tp = tp+1; if (tp+1<trp->lp) cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0); return; case KDEFINED: error(ERROR, "Bad syntax for control line"); break; case KINCLUDE: doinclude(trp); trp->lp = trp->bp; return; case KEVAL: eval(trp, np->val); break; default: error(ERROR, "Preprocessor control `%t' not yet implemented", tp); break; } setempty(trp); return; } void * dorealloc(void *ptr, int size) { void *p = realloc(ptr, size); if (p==NULL) error(FATAL, "Out of memory from realloc"); return p; } void * domalloc(int size) { void *p = malloc(size); if (p==NULL) error(FATAL, "Out of memory from malloc"); return p; } void dofree(void *p) { free(p); } void error(enum errtype type, char *string, ...) { va_list ap; char *cp, *ep; Token *tp; Tokenrow *trp; Source *s; int i; void *p; fprintf(stderr, "cpp: "); for (s=cursource; s; s=s->next) if (*s->filename) fprintf(stderr, "%s:%d ", s->filename, s->line); va_start(ap, string); for (ep=string; *ep; ep++) { if (*ep=='%') { switch (*++ep) { case 's': cp = va_arg(ap, char *); fprintf(stderr, "%s", cp); break; case 'd': i = va_arg(ap, int); fprintf(stderr, "%d", i); break; case 'p': p = va_arg(ap, void *); fprintf(stderr, "%p", p); break; case 't': tp = va_arg(ap, Token *); fprintf(stderr, "%.*s", tp->len, tp->t); break; case 'r': trp = va_arg(ap, Tokenrow *); for (tp=trp->tp; tp<trp->lp&&tp->type!=NL; tp++) { if (tp>trp->tp && tp->wslen) fputc(' ', stderr); fprintf(stderr, "%.*s", tp->len, tp->t); } break; default: fputc(*ep, stderr); break; } } else fputc(*ep, stderr); } va_end(ap); fputc('\n', stderr); if (type==FATAL) exits("error"); if (type!=WARNING) nerrs = 1; fflush(stderr); }