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) { 103*9a747e4fSDavid du Colombier if ((np->flag&ISKW)==0) 104*9a747e4fSDavid du Colombier return; 1053e12c5d1SDavid du Colombier switch (np->val) { 1063e12c5d1SDavid du Colombier case KENDIF: 1073e12c5d1SDavid du Colombier if (--ifdepth<skipping) 1083e12c5d1SDavid du Colombier skipping = 0; 1093e12c5d1SDavid du Colombier --cursource->ifdepth; 1103e12c5d1SDavid du Colombier setempty(trp); 1113e12c5d1SDavid du Colombier return; 1123e12c5d1SDavid du Colombier 1133e12c5d1SDavid du Colombier case KIFDEF: 1143e12c5d1SDavid du Colombier case KIFNDEF: 1153e12c5d1SDavid du Colombier case KIF: 1163e12c5d1SDavid du Colombier if (++ifdepth >= NIF) 1173e12c5d1SDavid du Colombier error(FATAL, "#if too deeply nested"); 1183e12c5d1SDavid du Colombier ++cursource->ifdepth; 1193e12c5d1SDavid du Colombier return; 1203e12c5d1SDavid du Colombier 1213e12c5d1SDavid du Colombier case KELIF: 1223e12c5d1SDavid du Colombier case KELSE: 1233e12c5d1SDavid du Colombier if (ifdepth<=skipping) 1243e12c5d1SDavid du Colombier break; 1253e12c5d1SDavid du Colombier return; 1263e12c5d1SDavid du Colombier 1273e12c5d1SDavid du Colombier default: 1283e12c5d1SDavid du Colombier return; 1293e12c5d1SDavid du Colombier } 1303e12c5d1SDavid du Colombier } 1313e12c5d1SDavid du Colombier switch (np->val) { 1323e12c5d1SDavid du Colombier case KDEFINE: 1333e12c5d1SDavid du Colombier dodefine(trp); 1343e12c5d1SDavid du Colombier break; 1353e12c5d1SDavid du Colombier 1363e12c5d1SDavid du Colombier case KUNDEF: 1373e12c5d1SDavid du Colombier tp += 1; 1383e12c5d1SDavid du Colombier if (tp->type!=NAME || trp->lp - trp->bp != 4) { 1393e12c5d1SDavid du Colombier error(ERROR, "Syntax error in #undef"); 1403e12c5d1SDavid du Colombier break; 1413e12c5d1SDavid du Colombier } 1427dd7cddfSDavid du Colombier if ((np = lookup(tp, 0))) { 1437dd7cddfSDavid du Colombier if (np->flag&ISUNCHANGE) { 1447dd7cddfSDavid du Colombier error(ERROR, "#defined token %t can't be undefined", tp); 1457dd7cddfSDavid du Colombier return; 1467dd7cddfSDavid du Colombier } 1473e12c5d1SDavid du Colombier np->flag &= ~ISDEFINED; 1487dd7cddfSDavid du Colombier } 1493e12c5d1SDavid du Colombier break; 1503e12c5d1SDavid du Colombier 1513e12c5d1SDavid du Colombier case KPRAGMA: 1523e12c5d1SDavid du Colombier return; 1533e12c5d1SDavid du Colombier 1543e12c5d1SDavid du Colombier case KIFDEF: 1553e12c5d1SDavid du Colombier case KIFNDEF: 1563e12c5d1SDavid du Colombier case KIF: 157bd389b36SDavid du Colombier if (++ifdepth >= NIF) 1583e12c5d1SDavid du Colombier error(FATAL, "#if too deeply nested"); 1593e12c5d1SDavid du Colombier ++cursource->ifdepth; 1603e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 0; 1613e12c5d1SDavid du Colombier if (eval(trp, np->val)) 1623e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 1; 1633e12c5d1SDavid du Colombier else 1643e12c5d1SDavid du Colombier skipping = ifdepth; 1653e12c5d1SDavid du Colombier break; 1663e12c5d1SDavid du Colombier 1673e12c5d1SDavid du Colombier case KELIF: 1683e12c5d1SDavid du Colombier if (ifdepth==0) { 1693e12c5d1SDavid du Colombier error(ERROR, "#elif with no #if"); 1703e12c5d1SDavid du Colombier return; 1713e12c5d1SDavid du Colombier } 1723e12c5d1SDavid du Colombier if (ifsatisfied[ifdepth]==2) 1733e12c5d1SDavid du Colombier error(ERROR, "#elif after #else"); 1743e12c5d1SDavid du Colombier if (eval(trp, np->val)) { 1753e12c5d1SDavid du Colombier if (ifsatisfied[ifdepth]) 1763e12c5d1SDavid du Colombier skipping = ifdepth; 1773e12c5d1SDavid du Colombier else { 1783e12c5d1SDavid du Colombier skipping = 0; 1793e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 1; 1803e12c5d1SDavid du Colombier } 1813e12c5d1SDavid du Colombier } else 1823e12c5d1SDavid du Colombier skipping = ifdepth; 1833e12c5d1SDavid du Colombier break; 1843e12c5d1SDavid du Colombier 1853e12c5d1SDavid du Colombier case KELSE: 1863e12c5d1SDavid du Colombier if (ifdepth==0 || cursource->ifdepth==0) { 1873e12c5d1SDavid du Colombier error(ERROR, "#else with no #if"); 1883e12c5d1SDavid du Colombier return; 1893e12c5d1SDavid du Colombier } 1903e12c5d1SDavid du Colombier if (ifsatisfied[ifdepth]==2) 1913e12c5d1SDavid du Colombier error(ERROR, "#else after #else"); 1923e12c5d1SDavid du Colombier if (trp->lp - trp->bp != 3) 1933e12c5d1SDavid du Colombier error(ERROR, "Syntax error in #else"); 1943e12c5d1SDavid du Colombier skipping = ifsatisfied[ifdepth]? ifdepth: 0; 1953e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 2; 1963e12c5d1SDavid du Colombier break; 1973e12c5d1SDavid du Colombier 1983e12c5d1SDavid du Colombier case KENDIF: 1993e12c5d1SDavid du Colombier if (ifdepth==0 || cursource->ifdepth==0) { 2003e12c5d1SDavid du Colombier error(ERROR, "#endif with no #if"); 2013e12c5d1SDavid du Colombier return; 2023e12c5d1SDavid du Colombier } 2033e12c5d1SDavid du Colombier --ifdepth; 2043e12c5d1SDavid du Colombier --cursource->ifdepth; 2053e12c5d1SDavid du Colombier if (trp->lp - trp->bp != 3) 2063e12c5d1SDavid du Colombier error(WARNING, "Syntax error in #endif"); 2073e12c5d1SDavid du Colombier break; 2083e12c5d1SDavid du Colombier 2093e12c5d1SDavid du Colombier case KERROR: 2103e12c5d1SDavid du Colombier trp->tp = tp+1; 2113e12c5d1SDavid du Colombier error(WARNING, "#error directive: %r", trp); 2123e12c5d1SDavid du Colombier break; 2133e12c5d1SDavid du Colombier 2143e12c5d1SDavid du Colombier case KLINE: 2153e12c5d1SDavid du Colombier trp->tp = tp+1; 2163e12c5d1SDavid du Colombier expandrow(trp, "<line>"); 2173e12c5d1SDavid du Colombier tp = trp->bp+2; 2183e12c5d1SDavid du Colombier kline: 2193e12c5d1SDavid du Colombier if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp 2203e12c5d1SDavid du Colombier || (tp+3==trp->lp && ((tp+1)->type!=STRING)||*(tp+1)->t=='L')){ 2213e12c5d1SDavid du Colombier error(ERROR, "Syntax error in #line"); 2223e12c5d1SDavid du Colombier return; 2233e12c5d1SDavid du Colombier } 2243e12c5d1SDavid du Colombier cursource->line = atol((char*)tp->t)-1; 2253e12c5d1SDavid du Colombier if (cursource->line<0 || cursource->line>=32768) 2263e12c5d1SDavid du Colombier error(WARNING, "#line specifies number out of range"); 2273e12c5d1SDavid du Colombier tp = tp+1; 2283e12c5d1SDavid du Colombier if (tp+1<trp->lp) 2293e12c5d1SDavid du Colombier cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0); 2303e12c5d1SDavid du Colombier return; 2313e12c5d1SDavid du Colombier 2323e12c5d1SDavid du Colombier case KDEFINED: 2333e12c5d1SDavid du Colombier error(ERROR, "Bad syntax for control line"); 2343e12c5d1SDavid du Colombier break; 2353e12c5d1SDavid du Colombier 2363e12c5d1SDavid du Colombier case KINCLUDE: 2373e12c5d1SDavid du Colombier doinclude(trp); 2383e12c5d1SDavid du Colombier trp->lp = trp->bp; 2393e12c5d1SDavid du Colombier return; 2403e12c5d1SDavid du Colombier 2413e12c5d1SDavid du Colombier case KEVAL: 2423e12c5d1SDavid du Colombier eval(trp, np->val); 2433e12c5d1SDavid du Colombier break; 2443e12c5d1SDavid du Colombier 2453e12c5d1SDavid du Colombier default: 2463e12c5d1SDavid du Colombier error(ERROR, "Preprocessor control `%t' not yet implemented", tp); 2473e12c5d1SDavid du Colombier break; 2483e12c5d1SDavid du Colombier } 2493e12c5d1SDavid du Colombier setempty(trp); 2503e12c5d1SDavid du Colombier return; 2513e12c5d1SDavid du Colombier } 2523e12c5d1SDavid du Colombier 2533e12c5d1SDavid du Colombier void * 2543e12c5d1SDavid du Colombier domalloc(int size) 2553e12c5d1SDavid du Colombier { 2563e12c5d1SDavid du Colombier void *p = malloc(size); 2573e12c5d1SDavid du Colombier 2583e12c5d1SDavid du Colombier if (p==NULL) 2593e12c5d1SDavid du Colombier error(FATAL, "Out of memory from malloc"); 2603e12c5d1SDavid du Colombier return p; 2613e12c5d1SDavid du Colombier } 2623e12c5d1SDavid du Colombier 2633e12c5d1SDavid du Colombier void 2643e12c5d1SDavid du Colombier dofree(void *p) 2653e12c5d1SDavid du Colombier { 2663e12c5d1SDavid du Colombier free(p); 2673e12c5d1SDavid du Colombier } 2683e12c5d1SDavid du Colombier 2693e12c5d1SDavid du Colombier void 2703e12c5d1SDavid du Colombier error(enum errtype type, char *string, ...) 2713e12c5d1SDavid du Colombier { 2723e12c5d1SDavid du Colombier va_list ap; 2733e12c5d1SDavid du Colombier char *cp, *ep; 2743e12c5d1SDavid du Colombier Token *tp; 2753e12c5d1SDavid du Colombier Tokenrow *trp; 276219b2ee8SDavid du Colombier Source *s; 2773e12c5d1SDavid du Colombier int i; 27880ee5cbfSDavid du Colombier void *p; 2793e12c5d1SDavid du Colombier 2803e12c5d1SDavid du Colombier fprintf(stderr, "cpp: "); 281219b2ee8SDavid du Colombier for (s=cursource; s; s=s->next) 282219b2ee8SDavid du Colombier if (*s->filename) 283219b2ee8SDavid du Colombier fprintf(stderr, "%s:%d ", s->filename, s->line); 2843e12c5d1SDavid du Colombier va_start(ap, string); 2853e12c5d1SDavid du Colombier for (ep=string; *ep; ep++) { 2863e12c5d1SDavid du Colombier if (*ep=='%') { 2873e12c5d1SDavid du Colombier switch (*++ep) { 2883e12c5d1SDavid du Colombier 2893e12c5d1SDavid du Colombier case 's': 2903e12c5d1SDavid du Colombier cp = va_arg(ap, char *); 2913e12c5d1SDavid du Colombier fprintf(stderr, "%s", cp); 2923e12c5d1SDavid du Colombier break; 2933e12c5d1SDavid du Colombier case 'd': 2943e12c5d1SDavid du Colombier i = va_arg(ap, int); 2953e12c5d1SDavid du Colombier fprintf(stderr, "%d", i); 2963e12c5d1SDavid du Colombier break; 29780ee5cbfSDavid du Colombier case 'p': 29880ee5cbfSDavid du Colombier p = va_arg(ap, void *); 29980ee5cbfSDavid du Colombier fprintf(stderr, "%p", p); 30080ee5cbfSDavid du Colombier break; 3013e12c5d1SDavid du Colombier case 't': 3023e12c5d1SDavid du Colombier tp = va_arg(ap, Token *); 3033e12c5d1SDavid du Colombier fprintf(stderr, "%.*s", tp->len, tp->t); 3043e12c5d1SDavid du Colombier break; 3053e12c5d1SDavid du Colombier 3063e12c5d1SDavid du Colombier case 'r': 3073e12c5d1SDavid du Colombier trp = va_arg(ap, Tokenrow *); 3083e12c5d1SDavid du Colombier for (tp=trp->tp; tp<trp->lp&&tp->type!=NL; tp++) { 3093e12c5d1SDavid du Colombier if (tp>trp->tp && tp->wslen) 3103e12c5d1SDavid du Colombier fputc(' ', stderr); 3113e12c5d1SDavid du Colombier fprintf(stderr, "%.*s", tp->len, tp->t); 3123e12c5d1SDavid du Colombier } 3133e12c5d1SDavid du Colombier break; 3143e12c5d1SDavid du Colombier 3153e12c5d1SDavid du Colombier default: 3163e12c5d1SDavid du Colombier fputc(*ep, stderr); 3173e12c5d1SDavid du Colombier break; 3183e12c5d1SDavid du Colombier } 3193e12c5d1SDavid du Colombier } else 3203e12c5d1SDavid du Colombier fputc(*ep, stderr); 3213e12c5d1SDavid du Colombier } 3223e12c5d1SDavid du Colombier va_end(ap); 3233e12c5d1SDavid du Colombier fputc('\n', stderr); 3243e12c5d1SDavid du Colombier if (type==FATAL) 3253e12c5d1SDavid du Colombier exits("error"); 3263e12c5d1SDavid du Colombier if (type!=WARNING) 3273e12c5d1SDavid du Colombier nerrs = 1; 3283e12c5d1SDavid du Colombier fflush(stderr); 3293e12c5d1SDavid du Colombier } 330