13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 33e12c5d1SDavid du Colombier #include <stdio.h> 43e12c5d1SDavid du Colombier #include <stdarg.h> 53e12c5d1SDavid du Colombier #include "cpp.h" 63e12c5d1SDavid du Colombier 73e12c5d1SDavid du Colombier #define OUTS 16384 83e12c5d1SDavid du Colombier char outbuf[OUTS]; 93e12c5d1SDavid du Colombier char *outp = outbuf; 103e12c5d1SDavid du Colombier Source *cursource; 113e12c5d1SDavid du Colombier int nerrs; 123e12c5d1SDavid du Colombier struct token nltoken = { NL, 0, 0, 0, 1, (uchar*)"\n" }; 133e12c5d1SDavid du Colombier char *curtime; 143e12c5d1SDavid du Colombier int incdepth; 153e12c5d1SDavid du Colombier int ifdepth; 163e12c5d1SDavid du Colombier int ifsatisfied[NIF]; 173e12c5d1SDavid du Colombier int skipping; 183e12c5d1SDavid du Colombier 193e12c5d1SDavid du Colombier void 203e12c5d1SDavid du Colombier main(int argc, char **argv) 213e12c5d1SDavid du Colombier { 223e12c5d1SDavid du Colombier Tokenrow tr; 233e12c5d1SDavid du Colombier long t; 243e12c5d1SDavid du Colombier char ebuf[BUFSIZ]; 253e12c5d1SDavid du Colombier 263e12c5d1SDavid du Colombier setbuf(stderr, ebuf); 273e12c5d1SDavid du Colombier t = time(NULL); 283e12c5d1SDavid du Colombier curtime = ctime(t); 293e12c5d1SDavid du Colombier maketokenrow(3, &tr); 303e12c5d1SDavid du Colombier expandlex(); 313e12c5d1SDavid du Colombier setup(argc, argv); 323e12c5d1SDavid du Colombier fixlex(); 333e12c5d1SDavid du Colombier iniths(); 343e12c5d1SDavid du Colombier genline(); 353e12c5d1SDavid du Colombier process(&tr); 363e12c5d1SDavid du Colombier flushout(); 373e12c5d1SDavid du Colombier fflush(stderr); 383e12c5d1SDavid du Colombier exits(nerrs? "errors" : 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 } 1403e12c5d1SDavid du Colombier if ((np = lookup(tp, 0))) 1413e12c5d1SDavid du Colombier np->flag &= ~ISDEFINED; 1423e12c5d1SDavid du Colombier break; 1433e12c5d1SDavid du Colombier 1443e12c5d1SDavid du Colombier case KPRAGMA: 1453e12c5d1SDavid du Colombier return; 1463e12c5d1SDavid du Colombier 1473e12c5d1SDavid du Colombier case KIFDEF: 1483e12c5d1SDavid du Colombier case KIFNDEF: 1493e12c5d1SDavid du Colombier case KIF: 150*bd389b36SDavid du Colombier if (++ifdepth >= NIF) 1513e12c5d1SDavid du Colombier error(FATAL, "#if too deeply nested"); 1523e12c5d1SDavid du Colombier ++cursource->ifdepth; 1533e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 0; 1543e12c5d1SDavid du Colombier if (eval(trp, np->val)) 1553e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 1; 1563e12c5d1SDavid du Colombier else 1573e12c5d1SDavid du Colombier skipping = ifdepth; 1583e12c5d1SDavid du Colombier break; 1593e12c5d1SDavid du Colombier 1603e12c5d1SDavid du Colombier case KELIF: 1613e12c5d1SDavid du Colombier if (ifdepth==0) { 1623e12c5d1SDavid du Colombier error(ERROR, "#elif with no #if"); 1633e12c5d1SDavid du Colombier return; 1643e12c5d1SDavid du Colombier } 1653e12c5d1SDavid du Colombier if (ifsatisfied[ifdepth]==2) 1663e12c5d1SDavid du Colombier error(ERROR, "#elif after #else"); 1673e12c5d1SDavid du Colombier if (eval(trp, np->val)) { 1683e12c5d1SDavid du Colombier if (ifsatisfied[ifdepth]) 1693e12c5d1SDavid du Colombier skipping = ifdepth; 1703e12c5d1SDavid du Colombier else { 1713e12c5d1SDavid du Colombier skipping = 0; 1723e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 1; 1733e12c5d1SDavid du Colombier } 1743e12c5d1SDavid du Colombier } else 1753e12c5d1SDavid du Colombier skipping = ifdepth; 1763e12c5d1SDavid du Colombier break; 1773e12c5d1SDavid du Colombier 1783e12c5d1SDavid du Colombier case KELSE: 1793e12c5d1SDavid du Colombier if (ifdepth==0 || cursource->ifdepth==0) { 1803e12c5d1SDavid du Colombier error(ERROR, "#else with no #if"); 1813e12c5d1SDavid du Colombier return; 1823e12c5d1SDavid du Colombier } 1833e12c5d1SDavid du Colombier if (ifsatisfied[ifdepth]==2) 1843e12c5d1SDavid du Colombier error(ERROR, "#else after #else"); 1853e12c5d1SDavid du Colombier if (trp->lp - trp->bp != 3) 1863e12c5d1SDavid du Colombier error(ERROR, "Syntax error in #else"); 1873e12c5d1SDavid du Colombier skipping = ifsatisfied[ifdepth]? ifdepth: 0; 1883e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 2; 1893e12c5d1SDavid du Colombier break; 1903e12c5d1SDavid du Colombier 1913e12c5d1SDavid du Colombier case KENDIF: 1923e12c5d1SDavid du Colombier if (ifdepth==0 || cursource->ifdepth==0) { 1933e12c5d1SDavid du Colombier error(ERROR, "#endif with no #if"); 1943e12c5d1SDavid du Colombier return; 1953e12c5d1SDavid du Colombier } 1963e12c5d1SDavid du Colombier --ifdepth; 1973e12c5d1SDavid du Colombier --cursource->ifdepth; 1983e12c5d1SDavid du Colombier if (trp->lp - trp->bp != 3) 1993e12c5d1SDavid du Colombier error(WARNING, "Syntax error in #endif"); 2003e12c5d1SDavid du Colombier break; 2013e12c5d1SDavid du Colombier 2023e12c5d1SDavid du Colombier case KERROR: 2033e12c5d1SDavid du Colombier trp->tp = tp+1; 2043e12c5d1SDavid du Colombier error(WARNING, "#error directive: %r", trp); 2053e12c5d1SDavid du Colombier break; 2063e12c5d1SDavid du Colombier 2073e12c5d1SDavid du Colombier case KLINE: 2083e12c5d1SDavid du Colombier trp->tp = tp+1; 2093e12c5d1SDavid du Colombier expandrow(trp, "<line>"); 2103e12c5d1SDavid du Colombier tp = trp->bp+2; 2113e12c5d1SDavid du Colombier kline: 2123e12c5d1SDavid du Colombier if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp 2133e12c5d1SDavid du Colombier || (tp+3==trp->lp && ((tp+1)->type!=STRING)||*(tp+1)->t=='L')){ 2143e12c5d1SDavid du Colombier error(ERROR, "Syntax error in #line"); 2153e12c5d1SDavid du Colombier return; 2163e12c5d1SDavid du Colombier } 2173e12c5d1SDavid du Colombier cursource->line = atol((char*)tp->t)-1; 2183e12c5d1SDavid du Colombier if (cursource->line<0 || cursource->line>=32768) 2193e12c5d1SDavid du Colombier error(WARNING, "#line specifies number out of range"); 2203e12c5d1SDavid du Colombier tp = tp+1; 2213e12c5d1SDavid du Colombier if (tp+1<trp->lp) 2223e12c5d1SDavid du Colombier cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0); 2233e12c5d1SDavid du Colombier return; 2243e12c5d1SDavid du Colombier 2253e12c5d1SDavid du Colombier case KDEFINED: 2263e12c5d1SDavid du Colombier error(ERROR, "Bad syntax for control line"); 2273e12c5d1SDavid du Colombier break; 2283e12c5d1SDavid du Colombier 2293e12c5d1SDavid du Colombier case KINCLUDE: 2303e12c5d1SDavid du Colombier doinclude(trp); 2313e12c5d1SDavid du Colombier trp->lp = trp->bp; 2323e12c5d1SDavid du Colombier return; 2333e12c5d1SDavid du Colombier 2343e12c5d1SDavid du Colombier case KEVAL: 2353e12c5d1SDavid du Colombier eval(trp, np->val); 2363e12c5d1SDavid du Colombier break; 2373e12c5d1SDavid du Colombier 2383e12c5d1SDavid du Colombier default: 2393e12c5d1SDavid du Colombier error(ERROR, "Preprocessor control `%t' not yet implemented", tp); 2403e12c5d1SDavid du Colombier break; 2413e12c5d1SDavid du Colombier } 2423e12c5d1SDavid du Colombier setempty(trp); 2433e12c5d1SDavid du Colombier return; 2443e12c5d1SDavid du Colombier } 2453e12c5d1SDavid du Colombier 2463e12c5d1SDavid du Colombier void * 2473e12c5d1SDavid du Colombier domalloc(int size) 2483e12c5d1SDavid du Colombier { 2493e12c5d1SDavid du Colombier void *p = malloc(size); 2503e12c5d1SDavid du Colombier 2513e12c5d1SDavid du Colombier if (p==NULL) 2523e12c5d1SDavid du Colombier error(FATAL, "Out of memory from malloc"); 2533e12c5d1SDavid du Colombier return p; 2543e12c5d1SDavid du Colombier } 2553e12c5d1SDavid du Colombier 2563e12c5d1SDavid du Colombier void 2573e12c5d1SDavid du Colombier dofree(void *p) 2583e12c5d1SDavid du Colombier { 2593e12c5d1SDavid du Colombier free(p); 2603e12c5d1SDavid du Colombier } 2613e12c5d1SDavid du Colombier 2623e12c5d1SDavid du Colombier void 2633e12c5d1SDavid du Colombier error(enum errtype type, char *string, ...) 2643e12c5d1SDavid du Colombier { 2653e12c5d1SDavid du Colombier va_list ap; 2663e12c5d1SDavid du Colombier char *cp, *ep; 2673e12c5d1SDavid du Colombier Token *tp; 2683e12c5d1SDavid du Colombier Tokenrow *trp; 2693e12c5d1SDavid du Colombier int i; 2703e12c5d1SDavid du Colombier 2713e12c5d1SDavid du Colombier if (*cursource->filename) 2723e12c5d1SDavid du Colombier fprintf(stderr, "cpp: %s:%d: ", cursource->filename, cursource->line); 2733e12c5d1SDavid du Colombier else 2743e12c5d1SDavid du Colombier fprintf(stderr, "cpp: "); 2753e12c5d1SDavid du Colombier va_start(ap, string); 2763e12c5d1SDavid du Colombier for (ep=string; *ep; ep++) { 2773e12c5d1SDavid du Colombier if (*ep=='%') { 2783e12c5d1SDavid du Colombier switch (*++ep) { 2793e12c5d1SDavid du Colombier 2803e12c5d1SDavid du Colombier case 's': 2813e12c5d1SDavid du Colombier cp = va_arg(ap, char *); 2823e12c5d1SDavid du Colombier fprintf(stderr, "%s", cp); 2833e12c5d1SDavid du Colombier break; 2843e12c5d1SDavid du Colombier case 'd': 2853e12c5d1SDavid du Colombier i = va_arg(ap, int); 2863e12c5d1SDavid du Colombier fprintf(stderr, "%d", i); 2873e12c5d1SDavid du Colombier break; 2883e12c5d1SDavid du Colombier case 't': 2893e12c5d1SDavid du Colombier tp = va_arg(ap, Token *); 2903e12c5d1SDavid du Colombier fprintf(stderr, "%.*s", tp->len, tp->t); 2913e12c5d1SDavid du Colombier break; 2923e12c5d1SDavid du Colombier 2933e12c5d1SDavid du Colombier case 'r': 2943e12c5d1SDavid du Colombier trp = va_arg(ap, Tokenrow *); 2953e12c5d1SDavid du Colombier for (tp=trp->tp; tp<trp->lp&&tp->type!=NL; tp++) { 2963e12c5d1SDavid du Colombier if (tp>trp->tp && tp->wslen) 2973e12c5d1SDavid du Colombier fputc(' ', stderr); 2983e12c5d1SDavid du Colombier fprintf(stderr, "%.*s", tp->len, tp->t); 2993e12c5d1SDavid du Colombier } 3003e12c5d1SDavid du Colombier break; 3013e12c5d1SDavid du Colombier 3023e12c5d1SDavid du Colombier default: 3033e12c5d1SDavid du Colombier fputc(*ep, stderr); 3043e12c5d1SDavid du Colombier break; 3053e12c5d1SDavid du Colombier } 3063e12c5d1SDavid du Colombier } else 3073e12c5d1SDavid du Colombier fputc(*ep, stderr); 3083e12c5d1SDavid du Colombier } 3093e12c5d1SDavid du Colombier va_end(ap); 3103e12c5d1SDavid du Colombier fputc('\n', stderr); 3113e12c5d1SDavid du Colombier if (type==FATAL) 3123e12c5d1SDavid du Colombier exits("error"); 3133e12c5d1SDavid du Colombier if (type!=WARNING) 3143e12c5d1SDavid du Colombier nerrs = 1; 3153e12c5d1SDavid du Colombier fflush(stderr); 3163e12c5d1SDavid du Colombier } 317