13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 33e12c5d1SDavid du Colombier #include <stdio.h> 43e12c5d1SDavid du Colombier #include "cpp.h" 53e12c5d1SDavid du Colombier 63e12c5d1SDavid du Colombier #define OUTS 16384 73e12c5d1SDavid du Colombier char outbuf[OUTS]; 83e12c5d1SDavid du Colombier char *outp = outbuf; 93e12c5d1SDavid du Colombier Source *cursource; 103e12c5d1SDavid du Colombier int nerrs; 113e12c5d1SDavid du Colombier struct token nltoken = { NL, 0, 0, 0, 1, (uchar*)"\n" }; 123e12c5d1SDavid du Colombier char *curtime; 133e12c5d1SDavid du Colombier int incdepth; 143e12c5d1SDavid du Colombier int ifdepth; 153e12c5d1SDavid du Colombier int ifsatisfied[NIF]; 163e12c5d1SDavid du Colombier int skipping; 173e12c5d1SDavid du Colombier 18219b2ee8SDavid du Colombier int 193e12c5d1SDavid du Colombier main(int argc, char **argv) 203e12c5d1SDavid du Colombier { 213e12c5d1SDavid du Colombier Tokenrow tr; 223e12c5d1SDavid du Colombier long t; 233e12c5d1SDavid du Colombier char ebuf[BUFSIZ]; 243e12c5d1SDavid du Colombier 253e12c5d1SDavid du Colombier setbuf(stderr, ebuf); 263e12c5d1SDavid du Colombier t = time(NULL); 273e12c5d1SDavid du Colombier curtime = ctime(t); 283e12c5d1SDavid du Colombier maketokenrow(3, &tr); 293e12c5d1SDavid du Colombier expandlex(); 303e12c5d1SDavid du Colombier setup(argc, argv); 313e12c5d1SDavid du Colombier fixlex(); 323e12c5d1SDavid du Colombier iniths(); 333e12c5d1SDavid du Colombier genline(); 343e12c5d1SDavid du Colombier process(&tr); 353e12c5d1SDavid du Colombier flushout(); 363e12c5d1SDavid du Colombier fflush(stderr); 373e12c5d1SDavid du Colombier exits(nerrs? "errors" : 0); 38219b2ee8SDavid du Colombier return 0; 393e12c5d1SDavid du Colombier } 403e12c5d1SDavid du Colombier 413e12c5d1SDavid du Colombier void 423e12c5d1SDavid du Colombier process(Tokenrow *trp) 433e12c5d1SDavid du Colombier { 443e12c5d1SDavid du Colombier int anymacros = 0; 453e12c5d1SDavid du Colombier 463e12c5d1SDavid du Colombier for (;;) { 473e12c5d1SDavid du Colombier if (trp->tp >= trp->lp) { 483e12c5d1SDavid du Colombier trp->tp = trp->lp = trp->bp; 493e12c5d1SDavid du Colombier outp = outbuf; 503e12c5d1SDavid du Colombier anymacros |= gettokens(trp, 1); 513e12c5d1SDavid du Colombier trp->tp = trp->bp; 523e12c5d1SDavid du Colombier } 533e12c5d1SDavid du Colombier if (trp->tp->type == END) { 543e12c5d1SDavid du Colombier if (--incdepth>=0) { 553e12c5d1SDavid du Colombier if (cursource->ifdepth) 563e12c5d1SDavid du Colombier error(ERROR, 573e12c5d1SDavid du Colombier "Unterminated conditional in #include"); 583e12c5d1SDavid du Colombier unsetsource(); 593e12c5d1SDavid du Colombier cursource->line += cursource->lineinc; 603e12c5d1SDavid du Colombier trp->tp = trp->lp; 613e12c5d1SDavid du Colombier genline(); 623e12c5d1SDavid du Colombier continue; 633e12c5d1SDavid du Colombier } 643e12c5d1SDavid du Colombier if (ifdepth) 653e12c5d1SDavid du Colombier error(ERROR, "Unterminated #if/#ifdef/#ifndef"); 663e12c5d1SDavid du Colombier break; 673e12c5d1SDavid du Colombier } 683e12c5d1SDavid du Colombier if (trp->tp->type==SHARP) { 693e12c5d1SDavid du Colombier trp->tp += 1; 703e12c5d1SDavid du Colombier control(trp); 713e12c5d1SDavid du Colombier } else if (!skipping && anymacros) 723e12c5d1SDavid du Colombier expandrow(trp, NULL); 733e12c5d1SDavid du Colombier if (skipping) 743e12c5d1SDavid du Colombier setempty(trp); 753e12c5d1SDavid du Colombier puttokens(trp); 763e12c5d1SDavid du Colombier anymacros = 0; 773e12c5d1SDavid du Colombier cursource->line += cursource->lineinc; 783e12c5d1SDavid du Colombier if (cursource->lineinc>1) { 793e12c5d1SDavid du Colombier genline(); 803e12c5d1SDavid du Colombier } 813e12c5d1SDavid du Colombier } 823e12c5d1SDavid du Colombier } 833e12c5d1SDavid du Colombier 843e12c5d1SDavid du Colombier void 853e12c5d1SDavid du Colombier control(Tokenrow *trp) 863e12c5d1SDavid du Colombier { 873e12c5d1SDavid du Colombier Nlist *np; 883e12c5d1SDavid du Colombier Token *tp; 893e12c5d1SDavid du Colombier 903e12c5d1SDavid du Colombier tp = trp->tp; 913e12c5d1SDavid du Colombier if (tp->type!=NAME) { 923e12c5d1SDavid du Colombier if (tp->type==NUMBER) 933e12c5d1SDavid du Colombier goto kline; 943e12c5d1SDavid du Colombier if (tp->type != NL) 953e12c5d1SDavid du Colombier error(ERROR, "Unidentifiable control line"); 963e12c5d1SDavid du Colombier return; /* else empty line */ 973e12c5d1SDavid du Colombier } 983e12c5d1SDavid du Colombier if ((np = lookup(tp, 0))==NULL || (np->flag&ISKW)==0 && !skipping) { 993e12c5d1SDavid du Colombier error(WARNING, "Unknown preprocessor control %t", tp); 1003e12c5d1SDavid du Colombier return; 1013e12c5d1SDavid du Colombier } 1023e12c5d1SDavid du Colombier if (skipping) { 1033e12c5d1SDavid du Colombier switch (np->val) { 1043e12c5d1SDavid du Colombier case KENDIF: 1053e12c5d1SDavid du Colombier if (--ifdepth<skipping) 1063e12c5d1SDavid du Colombier skipping = 0; 1073e12c5d1SDavid du Colombier --cursource->ifdepth; 1083e12c5d1SDavid du Colombier setempty(trp); 1093e12c5d1SDavid du Colombier return; 1103e12c5d1SDavid du Colombier 1113e12c5d1SDavid du Colombier case KIFDEF: 1123e12c5d1SDavid du Colombier case KIFNDEF: 1133e12c5d1SDavid du Colombier case KIF: 1143e12c5d1SDavid du Colombier if (++ifdepth >= NIF) 1153e12c5d1SDavid du Colombier error(FATAL, "#if too deeply nested"); 1163e12c5d1SDavid du Colombier ++cursource->ifdepth; 1173e12c5d1SDavid du Colombier return; 1183e12c5d1SDavid du Colombier 1193e12c5d1SDavid du Colombier case KELIF: 1203e12c5d1SDavid du Colombier case KELSE: 1213e12c5d1SDavid du Colombier if (ifdepth<=skipping) 1223e12c5d1SDavid du Colombier break; 1233e12c5d1SDavid du Colombier return; 1243e12c5d1SDavid du Colombier 1253e12c5d1SDavid du Colombier default: 1263e12c5d1SDavid du Colombier return; 1273e12c5d1SDavid du Colombier } 1283e12c5d1SDavid du Colombier } 1293e12c5d1SDavid du Colombier switch (np->val) { 1303e12c5d1SDavid du Colombier case KDEFINE: 1313e12c5d1SDavid du Colombier dodefine(trp); 1323e12c5d1SDavid du Colombier break; 1333e12c5d1SDavid du Colombier 1343e12c5d1SDavid du Colombier case KUNDEF: 1353e12c5d1SDavid du Colombier tp += 1; 1363e12c5d1SDavid du Colombier if (tp->type!=NAME || trp->lp - trp->bp != 4) { 1373e12c5d1SDavid du Colombier error(ERROR, "Syntax error in #undef"); 1383e12c5d1SDavid du Colombier break; 1393e12c5d1SDavid du Colombier } 140*7dd7cddfSDavid du Colombier if ((np = lookup(tp, 0))) { 141*7dd7cddfSDavid du Colombier if (np->flag&ISUNCHANGE) { 142*7dd7cddfSDavid du Colombier error(ERROR, "#defined token %t can't be undefined", tp); 143*7dd7cddfSDavid du Colombier return; 144*7dd7cddfSDavid du Colombier } 1453e12c5d1SDavid du Colombier np->flag &= ~ISDEFINED; 146*7dd7cddfSDavid du Colombier } 1473e12c5d1SDavid du Colombier break; 1483e12c5d1SDavid du Colombier 1493e12c5d1SDavid du Colombier case KPRAGMA: 1503e12c5d1SDavid du Colombier return; 1513e12c5d1SDavid du Colombier 1523e12c5d1SDavid du Colombier case KIFDEF: 1533e12c5d1SDavid du Colombier case KIFNDEF: 1543e12c5d1SDavid du Colombier case KIF: 155bd389b36SDavid du Colombier if (++ifdepth >= NIF) 1563e12c5d1SDavid du Colombier error(FATAL, "#if too deeply nested"); 1573e12c5d1SDavid du Colombier ++cursource->ifdepth; 1583e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 0; 1593e12c5d1SDavid du Colombier if (eval(trp, np->val)) 1603e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 1; 1613e12c5d1SDavid du Colombier else 1623e12c5d1SDavid du Colombier skipping = ifdepth; 1633e12c5d1SDavid du Colombier break; 1643e12c5d1SDavid du Colombier 1653e12c5d1SDavid du Colombier case KELIF: 1663e12c5d1SDavid du Colombier if (ifdepth==0) { 1673e12c5d1SDavid du Colombier error(ERROR, "#elif with no #if"); 1683e12c5d1SDavid du Colombier return; 1693e12c5d1SDavid du Colombier } 1703e12c5d1SDavid du Colombier if (ifsatisfied[ifdepth]==2) 1713e12c5d1SDavid du Colombier error(ERROR, "#elif after #else"); 1723e12c5d1SDavid du Colombier if (eval(trp, np->val)) { 1733e12c5d1SDavid du Colombier if (ifsatisfied[ifdepth]) 1743e12c5d1SDavid du Colombier skipping = ifdepth; 1753e12c5d1SDavid du Colombier else { 1763e12c5d1SDavid du Colombier skipping = 0; 1773e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 1; 1783e12c5d1SDavid du Colombier } 1793e12c5d1SDavid du Colombier } else 1803e12c5d1SDavid du Colombier skipping = ifdepth; 1813e12c5d1SDavid du Colombier break; 1823e12c5d1SDavid du Colombier 1833e12c5d1SDavid du Colombier case KELSE: 1843e12c5d1SDavid du Colombier if (ifdepth==0 || cursource->ifdepth==0) { 1853e12c5d1SDavid du Colombier error(ERROR, "#else with no #if"); 1863e12c5d1SDavid du Colombier return; 1873e12c5d1SDavid du Colombier } 1883e12c5d1SDavid du Colombier if (ifsatisfied[ifdepth]==2) 1893e12c5d1SDavid du Colombier error(ERROR, "#else after #else"); 1903e12c5d1SDavid du Colombier if (trp->lp - trp->bp != 3) 1913e12c5d1SDavid du Colombier error(ERROR, "Syntax error in #else"); 1923e12c5d1SDavid du Colombier skipping = ifsatisfied[ifdepth]? ifdepth: 0; 1933e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 2; 1943e12c5d1SDavid du Colombier break; 1953e12c5d1SDavid du Colombier 1963e12c5d1SDavid du Colombier case KENDIF: 1973e12c5d1SDavid du Colombier if (ifdepth==0 || cursource->ifdepth==0) { 1983e12c5d1SDavid du Colombier error(ERROR, "#endif with no #if"); 1993e12c5d1SDavid du Colombier return; 2003e12c5d1SDavid du Colombier } 2013e12c5d1SDavid du Colombier --ifdepth; 2023e12c5d1SDavid du Colombier --cursource->ifdepth; 2033e12c5d1SDavid du Colombier if (trp->lp - trp->bp != 3) 2043e12c5d1SDavid du Colombier error(WARNING, "Syntax error in #endif"); 2053e12c5d1SDavid du Colombier break; 2063e12c5d1SDavid du Colombier 2073e12c5d1SDavid du Colombier case KERROR: 2083e12c5d1SDavid du Colombier trp->tp = tp+1; 2093e12c5d1SDavid du Colombier error(WARNING, "#error directive: %r", trp); 2103e12c5d1SDavid du Colombier break; 2113e12c5d1SDavid du Colombier 2123e12c5d1SDavid du Colombier case KLINE: 2133e12c5d1SDavid du Colombier trp->tp = tp+1; 2143e12c5d1SDavid du Colombier expandrow(trp, "<line>"); 2153e12c5d1SDavid du Colombier tp = trp->bp+2; 2163e12c5d1SDavid du Colombier kline: 2173e12c5d1SDavid du Colombier if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp 2183e12c5d1SDavid du Colombier || (tp+3==trp->lp && ((tp+1)->type!=STRING)||*(tp+1)->t=='L')){ 2193e12c5d1SDavid du Colombier error(ERROR, "Syntax error in #line"); 2203e12c5d1SDavid du Colombier return; 2213e12c5d1SDavid du Colombier } 2223e12c5d1SDavid du Colombier cursource->line = atol((char*)tp->t)-1; 2233e12c5d1SDavid du Colombier if (cursource->line<0 || cursource->line>=32768) 2243e12c5d1SDavid du Colombier error(WARNING, "#line specifies number out of range"); 2253e12c5d1SDavid du Colombier tp = tp+1; 2263e12c5d1SDavid du Colombier if (tp+1<trp->lp) 2273e12c5d1SDavid du Colombier cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0); 2283e12c5d1SDavid du Colombier return; 2293e12c5d1SDavid du Colombier 2303e12c5d1SDavid du Colombier case KDEFINED: 2313e12c5d1SDavid du Colombier error(ERROR, "Bad syntax for control line"); 2323e12c5d1SDavid du Colombier break; 2333e12c5d1SDavid du Colombier 2343e12c5d1SDavid du Colombier case KINCLUDE: 2353e12c5d1SDavid du Colombier doinclude(trp); 2363e12c5d1SDavid du Colombier trp->lp = trp->bp; 2373e12c5d1SDavid du Colombier return; 2383e12c5d1SDavid du Colombier 2393e12c5d1SDavid du Colombier case KEVAL: 2403e12c5d1SDavid du Colombier eval(trp, np->val); 2413e12c5d1SDavid du Colombier break; 2423e12c5d1SDavid du Colombier 2433e12c5d1SDavid du Colombier default: 2443e12c5d1SDavid du Colombier error(ERROR, "Preprocessor control `%t' not yet implemented", tp); 2453e12c5d1SDavid du Colombier break; 2463e12c5d1SDavid du Colombier } 2473e12c5d1SDavid du Colombier setempty(trp); 2483e12c5d1SDavid du Colombier return; 2493e12c5d1SDavid du Colombier } 2503e12c5d1SDavid du Colombier 2513e12c5d1SDavid du Colombier void * 2523e12c5d1SDavid du Colombier domalloc(int size) 2533e12c5d1SDavid du Colombier { 2543e12c5d1SDavid du Colombier void *p = malloc(size); 2553e12c5d1SDavid du Colombier 2563e12c5d1SDavid du Colombier if (p==NULL) 2573e12c5d1SDavid du Colombier error(FATAL, "Out of memory from malloc"); 2583e12c5d1SDavid du Colombier return p; 2593e12c5d1SDavid du Colombier } 2603e12c5d1SDavid du Colombier 2613e12c5d1SDavid du Colombier void 2623e12c5d1SDavid du Colombier dofree(void *p) 2633e12c5d1SDavid du Colombier { 2643e12c5d1SDavid du Colombier free(p); 2653e12c5d1SDavid du Colombier } 2663e12c5d1SDavid du Colombier 2673e12c5d1SDavid du Colombier void 2683e12c5d1SDavid du Colombier error(enum errtype type, char *string, ...) 2693e12c5d1SDavid du Colombier { 2703e12c5d1SDavid du Colombier va_list ap; 2713e12c5d1SDavid du Colombier char *cp, *ep; 2723e12c5d1SDavid du Colombier Token *tp; 2733e12c5d1SDavid du Colombier Tokenrow *trp; 274219b2ee8SDavid du Colombier Source *s; 2753e12c5d1SDavid du Colombier int i; 2763e12c5d1SDavid du Colombier 2773e12c5d1SDavid du Colombier fprintf(stderr, "cpp: "); 278219b2ee8SDavid du Colombier for (s=cursource; s; s=s->next) 279219b2ee8SDavid du Colombier if (*s->filename) 280219b2ee8SDavid du Colombier fprintf(stderr, "%s:%d ", s->filename, s->line); 2813e12c5d1SDavid du Colombier va_start(ap, string); 2823e12c5d1SDavid du Colombier for (ep=string; *ep; ep++) { 2833e12c5d1SDavid du Colombier if (*ep=='%') { 2843e12c5d1SDavid du Colombier switch (*++ep) { 2853e12c5d1SDavid du Colombier 2863e12c5d1SDavid du Colombier case 's': 2873e12c5d1SDavid du Colombier cp = va_arg(ap, char *); 2883e12c5d1SDavid du Colombier fprintf(stderr, "%s", cp); 2893e12c5d1SDavid du Colombier break; 2903e12c5d1SDavid du Colombier case 'd': 2913e12c5d1SDavid du Colombier i = va_arg(ap, int); 2923e12c5d1SDavid du Colombier fprintf(stderr, "%d", i); 2933e12c5d1SDavid du Colombier break; 2943e12c5d1SDavid du Colombier case 't': 2953e12c5d1SDavid du Colombier tp = va_arg(ap, Token *); 2963e12c5d1SDavid du Colombier fprintf(stderr, "%.*s", tp->len, tp->t); 2973e12c5d1SDavid du Colombier break; 2983e12c5d1SDavid du Colombier 2993e12c5d1SDavid du Colombier case 'r': 3003e12c5d1SDavid du Colombier trp = va_arg(ap, Tokenrow *); 3013e12c5d1SDavid du Colombier for (tp=trp->tp; tp<trp->lp&&tp->type!=NL; tp++) { 3023e12c5d1SDavid du Colombier if (tp>trp->tp && tp->wslen) 3033e12c5d1SDavid du Colombier fputc(' ', stderr); 3043e12c5d1SDavid du Colombier fprintf(stderr, "%.*s", tp->len, tp->t); 3053e12c5d1SDavid du Colombier } 3063e12c5d1SDavid du Colombier break; 3073e12c5d1SDavid du Colombier 3083e12c5d1SDavid du Colombier default: 3093e12c5d1SDavid du Colombier fputc(*ep, stderr); 3103e12c5d1SDavid du Colombier break; 3113e12c5d1SDavid du Colombier } 3123e12c5d1SDavid du Colombier } else 3133e12c5d1SDavid du Colombier fputc(*ep, stderr); 3143e12c5d1SDavid du Colombier } 3153e12c5d1SDavid du Colombier va_end(ap); 3163e12c5d1SDavid du Colombier fputc('\n', stderr); 3173e12c5d1SDavid du Colombier if (type==FATAL) 3183e12c5d1SDavid du Colombier exits("error"); 3193e12c5d1SDavid du Colombier if (type!=WARNING) 3203e12c5d1SDavid du Colombier nerrs = 1; 3213e12c5d1SDavid du Colombier fflush(stderr); 3223e12c5d1SDavid du Colombier } 323