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 19*219b2ee8SDavid du Colombier int 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); 39*219b2ee8SDavid du Colombier return 0; 403e12c5d1SDavid du Colombier } 413e12c5d1SDavid du Colombier 423e12c5d1SDavid du Colombier void 433e12c5d1SDavid du Colombier process(Tokenrow *trp) 443e12c5d1SDavid du Colombier { 453e12c5d1SDavid du Colombier int anymacros = 0; 463e12c5d1SDavid du Colombier 473e12c5d1SDavid du Colombier for (;;) { 483e12c5d1SDavid du Colombier if (trp->tp >= trp->lp) { 493e12c5d1SDavid du Colombier trp->tp = trp->lp = trp->bp; 503e12c5d1SDavid du Colombier outp = outbuf; 513e12c5d1SDavid du Colombier anymacros |= gettokens(trp, 1); 523e12c5d1SDavid du Colombier trp->tp = trp->bp; 533e12c5d1SDavid du Colombier } 543e12c5d1SDavid du Colombier if (trp->tp->type == END) { 553e12c5d1SDavid du Colombier if (--incdepth>=0) { 563e12c5d1SDavid du Colombier if (cursource->ifdepth) 573e12c5d1SDavid du Colombier error(ERROR, 583e12c5d1SDavid du Colombier "Unterminated conditional in #include"); 593e12c5d1SDavid du Colombier unsetsource(); 603e12c5d1SDavid du Colombier cursource->line += cursource->lineinc; 613e12c5d1SDavid du Colombier trp->tp = trp->lp; 623e12c5d1SDavid du Colombier genline(); 633e12c5d1SDavid du Colombier continue; 643e12c5d1SDavid du Colombier } 653e12c5d1SDavid du Colombier if (ifdepth) 663e12c5d1SDavid du Colombier error(ERROR, "Unterminated #if/#ifdef/#ifndef"); 673e12c5d1SDavid du Colombier break; 683e12c5d1SDavid du Colombier } 693e12c5d1SDavid du Colombier if (trp->tp->type==SHARP) { 703e12c5d1SDavid du Colombier trp->tp += 1; 713e12c5d1SDavid du Colombier control(trp); 723e12c5d1SDavid du Colombier } else if (!skipping && anymacros) 733e12c5d1SDavid du Colombier expandrow(trp, NULL); 743e12c5d1SDavid du Colombier if (skipping) 753e12c5d1SDavid du Colombier setempty(trp); 763e12c5d1SDavid du Colombier puttokens(trp); 773e12c5d1SDavid du Colombier anymacros = 0; 783e12c5d1SDavid du Colombier cursource->line += cursource->lineinc; 793e12c5d1SDavid du Colombier if (cursource->lineinc>1) { 803e12c5d1SDavid du Colombier genline(); 813e12c5d1SDavid du Colombier } 823e12c5d1SDavid du Colombier } 833e12c5d1SDavid du Colombier } 843e12c5d1SDavid du Colombier 853e12c5d1SDavid du Colombier void 863e12c5d1SDavid du Colombier control(Tokenrow *trp) 873e12c5d1SDavid du Colombier { 883e12c5d1SDavid du Colombier Nlist *np; 893e12c5d1SDavid du Colombier Token *tp; 903e12c5d1SDavid du Colombier 913e12c5d1SDavid du Colombier tp = trp->tp; 923e12c5d1SDavid du Colombier if (tp->type!=NAME) { 933e12c5d1SDavid du Colombier if (tp->type==NUMBER) 943e12c5d1SDavid du Colombier goto kline; 953e12c5d1SDavid du Colombier if (tp->type != NL) 963e12c5d1SDavid du Colombier error(ERROR, "Unidentifiable control line"); 973e12c5d1SDavid du Colombier return; /* else empty line */ 983e12c5d1SDavid du Colombier } 993e12c5d1SDavid du Colombier if ((np = lookup(tp, 0))==NULL || (np->flag&ISKW)==0 && !skipping) { 1003e12c5d1SDavid du Colombier error(WARNING, "Unknown preprocessor control %t", tp); 1013e12c5d1SDavid du Colombier return; 1023e12c5d1SDavid du Colombier } 1033e12c5d1SDavid du Colombier if (skipping) { 1043e12c5d1SDavid du Colombier switch (np->val) { 1053e12c5d1SDavid du Colombier case KENDIF: 1063e12c5d1SDavid du Colombier if (--ifdepth<skipping) 1073e12c5d1SDavid du Colombier skipping = 0; 1083e12c5d1SDavid du Colombier --cursource->ifdepth; 1093e12c5d1SDavid du Colombier setempty(trp); 1103e12c5d1SDavid du Colombier return; 1113e12c5d1SDavid du Colombier 1123e12c5d1SDavid du Colombier case KIFDEF: 1133e12c5d1SDavid du Colombier case KIFNDEF: 1143e12c5d1SDavid du Colombier case KIF: 1153e12c5d1SDavid du Colombier if (++ifdepth >= NIF) 1163e12c5d1SDavid du Colombier error(FATAL, "#if too deeply nested"); 1173e12c5d1SDavid du Colombier ++cursource->ifdepth; 1183e12c5d1SDavid du Colombier return; 1193e12c5d1SDavid du Colombier 1203e12c5d1SDavid du Colombier case KELIF: 1213e12c5d1SDavid du Colombier case KELSE: 1223e12c5d1SDavid du Colombier if (ifdepth<=skipping) 1233e12c5d1SDavid du Colombier break; 1243e12c5d1SDavid du Colombier return; 1253e12c5d1SDavid du Colombier 1263e12c5d1SDavid du Colombier default: 1273e12c5d1SDavid du Colombier return; 1283e12c5d1SDavid du Colombier } 1293e12c5d1SDavid du Colombier } 1303e12c5d1SDavid du Colombier switch (np->val) { 1313e12c5d1SDavid du Colombier case KDEFINE: 1323e12c5d1SDavid du Colombier dodefine(trp); 1333e12c5d1SDavid du Colombier break; 1343e12c5d1SDavid du Colombier 1353e12c5d1SDavid du Colombier case KUNDEF: 1363e12c5d1SDavid du Colombier tp += 1; 1373e12c5d1SDavid du Colombier if (tp->type!=NAME || trp->lp - trp->bp != 4) { 1383e12c5d1SDavid du Colombier error(ERROR, "Syntax error in #undef"); 1393e12c5d1SDavid du Colombier break; 1403e12c5d1SDavid du Colombier } 1413e12c5d1SDavid du Colombier if ((np = lookup(tp, 0))) 1423e12c5d1SDavid du Colombier np->flag &= ~ISDEFINED; 1433e12c5d1SDavid du Colombier break; 1443e12c5d1SDavid du Colombier 1453e12c5d1SDavid du Colombier case KPRAGMA: 1463e12c5d1SDavid du Colombier return; 1473e12c5d1SDavid du Colombier 1483e12c5d1SDavid du Colombier case KIFDEF: 1493e12c5d1SDavid du Colombier case KIFNDEF: 1503e12c5d1SDavid du Colombier case KIF: 151bd389b36SDavid du Colombier if (++ifdepth >= NIF) 1523e12c5d1SDavid du Colombier error(FATAL, "#if too deeply nested"); 1533e12c5d1SDavid du Colombier ++cursource->ifdepth; 1543e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 0; 1553e12c5d1SDavid du Colombier if (eval(trp, np->val)) 1563e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 1; 1573e12c5d1SDavid du Colombier else 1583e12c5d1SDavid du Colombier skipping = ifdepth; 1593e12c5d1SDavid du Colombier break; 1603e12c5d1SDavid du Colombier 1613e12c5d1SDavid du Colombier case KELIF: 1623e12c5d1SDavid du Colombier if (ifdepth==0) { 1633e12c5d1SDavid du Colombier error(ERROR, "#elif with no #if"); 1643e12c5d1SDavid du Colombier return; 1653e12c5d1SDavid du Colombier } 1663e12c5d1SDavid du Colombier if (ifsatisfied[ifdepth]==2) 1673e12c5d1SDavid du Colombier error(ERROR, "#elif after #else"); 1683e12c5d1SDavid du Colombier if (eval(trp, np->val)) { 1693e12c5d1SDavid du Colombier if (ifsatisfied[ifdepth]) 1703e12c5d1SDavid du Colombier skipping = ifdepth; 1713e12c5d1SDavid du Colombier else { 1723e12c5d1SDavid du Colombier skipping = 0; 1733e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 1; 1743e12c5d1SDavid du Colombier } 1753e12c5d1SDavid du Colombier } else 1763e12c5d1SDavid du Colombier skipping = ifdepth; 1773e12c5d1SDavid du Colombier break; 1783e12c5d1SDavid du Colombier 1793e12c5d1SDavid du Colombier case KELSE: 1803e12c5d1SDavid du Colombier if (ifdepth==0 || cursource->ifdepth==0) { 1813e12c5d1SDavid du Colombier error(ERROR, "#else with no #if"); 1823e12c5d1SDavid du Colombier return; 1833e12c5d1SDavid du Colombier } 1843e12c5d1SDavid du Colombier if (ifsatisfied[ifdepth]==2) 1853e12c5d1SDavid du Colombier error(ERROR, "#else after #else"); 1863e12c5d1SDavid du Colombier if (trp->lp - trp->bp != 3) 1873e12c5d1SDavid du Colombier error(ERROR, "Syntax error in #else"); 1883e12c5d1SDavid du Colombier skipping = ifsatisfied[ifdepth]? ifdepth: 0; 1893e12c5d1SDavid du Colombier ifsatisfied[ifdepth] = 2; 1903e12c5d1SDavid du Colombier break; 1913e12c5d1SDavid du Colombier 1923e12c5d1SDavid du Colombier case KENDIF: 1933e12c5d1SDavid du Colombier if (ifdepth==0 || cursource->ifdepth==0) { 1943e12c5d1SDavid du Colombier error(ERROR, "#endif with no #if"); 1953e12c5d1SDavid du Colombier return; 1963e12c5d1SDavid du Colombier } 1973e12c5d1SDavid du Colombier --ifdepth; 1983e12c5d1SDavid du Colombier --cursource->ifdepth; 1993e12c5d1SDavid du Colombier if (trp->lp - trp->bp != 3) 2003e12c5d1SDavid du Colombier error(WARNING, "Syntax error in #endif"); 2013e12c5d1SDavid du Colombier break; 2023e12c5d1SDavid du Colombier 2033e12c5d1SDavid du Colombier case KERROR: 2043e12c5d1SDavid du Colombier trp->tp = tp+1; 2053e12c5d1SDavid du Colombier error(WARNING, "#error directive: %r", trp); 2063e12c5d1SDavid du Colombier break; 2073e12c5d1SDavid du Colombier 2083e12c5d1SDavid du Colombier case KLINE: 2093e12c5d1SDavid du Colombier trp->tp = tp+1; 2103e12c5d1SDavid du Colombier expandrow(trp, "<line>"); 2113e12c5d1SDavid du Colombier tp = trp->bp+2; 2123e12c5d1SDavid du Colombier kline: 2133e12c5d1SDavid du Colombier if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp 2143e12c5d1SDavid du Colombier || (tp+3==trp->lp && ((tp+1)->type!=STRING)||*(tp+1)->t=='L')){ 2153e12c5d1SDavid du Colombier error(ERROR, "Syntax error in #line"); 2163e12c5d1SDavid du Colombier return; 2173e12c5d1SDavid du Colombier } 2183e12c5d1SDavid du Colombier cursource->line = atol((char*)tp->t)-1; 2193e12c5d1SDavid du Colombier if (cursource->line<0 || cursource->line>=32768) 2203e12c5d1SDavid du Colombier error(WARNING, "#line specifies number out of range"); 2213e12c5d1SDavid du Colombier tp = tp+1; 2223e12c5d1SDavid du Colombier if (tp+1<trp->lp) 2233e12c5d1SDavid du Colombier cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0); 2243e12c5d1SDavid du Colombier return; 2253e12c5d1SDavid du Colombier 2263e12c5d1SDavid du Colombier case KDEFINED: 2273e12c5d1SDavid du Colombier error(ERROR, "Bad syntax for control line"); 2283e12c5d1SDavid du Colombier break; 2293e12c5d1SDavid du Colombier 2303e12c5d1SDavid du Colombier case KINCLUDE: 2313e12c5d1SDavid du Colombier doinclude(trp); 2323e12c5d1SDavid du Colombier trp->lp = trp->bp; 2333e12c5d1SDavid du Colombier return; 2343e12c5d1SDavid du Colombier 2353e12c5d1SDavid du Colombier case KEVAL: 2363e12c5d1SDavid du Colombier eval(trp, np->val); 2373e12c5d1SDavid du Colombier break; 2383e12c5d1SDavid du Colombier 2393e12c5d1SDavid du Colombier default: 2403e12c5d1SDavid du Colombier error(ERROR, "Preprocessor control `%t' not yet implemented", tp); 2413e12c5d1SDavid du Colombier break; 2423e12c5d1SDavid du Colombier } 2433e12c5d1SDavid du Colombier setempty(trp); 2443e12c5d1SDavid du Colombier return; 2453e12c5d1SDavid du Colombier } 2463e12c5d1SDavid du Colombier 2473e12c5d1SDavid du Colombier void * 2483e12c5d1SDavid du Colombier domalloc(int size) 2493e12c5d1SDavid du Colombier { 2503e12c5d1SDavid du Colombier void *p = malloc(size); 2513e12c5d1SDavid du Colombier 2523e12c5d1SDavid du Colombier if (p==NULL) 2533e12c5d1SDavid du Colombier error(FATAL, "Out of memory from malloc"); 2543e12c5d1SDavid du Colombier return p; 2553e12c5d1SDavid du Colombier } 2563e12c5d1SDavid du Colombier 2573e12c5d1SDavid du Colombier void 2583e12c5d1SDavid du Colombier dofree(void *p) 2593e12c5d1SDavid du Colombier { 2603e12c5d1SDavid du Colombier free(p); 2613e12c5d1SDavid du Colombier } 2623e12c5d1SDavid du Colombier 2633e12c5d1SDavid du Colombier void 2643e12c5d1SDavid du Colombier error(enum errtype type, char *string, ...) 2653e12c5d1SDavid du Colombier { 2663e12c5d1SDavid du Colombier va_list ap; 2673e12c5d1SDavid du Colombier char *cp, *ep; 2683e12c5d1SDavid du Colombier Token *tp; 2693e12c5d1SDavid du Colombier Tokenrow *trp; 270*219b2ee8SDavid du Colombier Source *s; 2713e12c5d1SDavid du Colombier int i; 2723e12c5d1SDavid du Colombier 2733e12c5d1SDavid du Colombier fprintf(stderr, "cpp: "); 274*219b2ee8SDavid du Colombier for (s=cursource; s; s=s->next) 275*219b2ee8SDavid du Colombier if (*s->filename) 276*219b2ee8SDavid du Colombier fprintf(stderr, "%s:%d ", s->filename, s->line); 2773e12c5d1SDavid du Colombier va_start(ap, string); 2783e12c5d1SDavid du Colombier for (ep=string; *ep; ep++) { 2793e12c5d1SDavid du Colombier if (*ep=='%') { 2803e12c5d1SDavid du Colombier switch (*++ep) { 2813e12c5d1SDavid du Colombier 2823e12c5d1SDavid du Colombier case 's': 2833e12c5d1SDavid du Colombier cp = va_arg(ap, char *); 2843e12c5d1SDavid du Colombier fprintf(stderr, "%s", cp); 2853e12c5d1SDavid du Colombier break; 2863e12c5d1SDavid du Colombier case 'd': 2873e12c5d1SDavid du Colombier i = va_arg(ap, int); 2883e12c5d1SDavid du Colombier fprintf(stderr, "%d", i); 2893e12c5d1SDavid du Colombier break; 2903e12c5d1SDavid du Colombier case 't': 2913e12c5d1SDavid du Colombier tp = va_arg(ap, Token *); 2923e12c5d1SDavid du Colombier fprintf(stderr, "%.*s", tp->len, tp->t); 2933e12c5d1SDavid du Colombier break; 2943e12c5d1SDavid du Colombier 2953e12c5d1SDavid du Colombier case 'r': 2963e12c5d1SDavid du Colombier trp = va_arg(ap, Tokenrow *); 2973e12c5d1SDavid du Colombier for (tp=trp->tp; tp<trp->lp&&tp->type!=NL; tp++) { 2983e12c5d1SDavid du Colombier if (tp>trp->tp && tp->wslen) 2993e12c5d1SDavid du Colombier fputc(' ', stderr); 3003e12c5d1SDavid du Colombier fprintf(stderr, "%.*s", tp->len, tp->t); 3013e12c5d1SDavid du Colombier } 3023e12c5d1SDavid du Colombier break; 3033e12c5d1SDavid du Colombier 3043e12c5d1SDavid du Colombier default: 3053e12c5d1SDavid du Colombier fputc(*ep, stderr); 3063e12c5d1SDavid du Colombier break; 3073e12c5d1SDavid du Colombier } 3083e12c5d1SDavid du Colombier } else 3093e12c5d1SDavid du Colombier fputc(*ep, stderr); 3103e12c5d1SDavid du Colombier } 3113e12c5d1SDavid du Colombier va_end(ap); 3123e12c5d1SDavid du Colombier fputc('\n', stderr); 3133e12c5d1SDavid du Colombier if (type==FATAL) 3143e12c5d1SDavid du Colombier exits("error"); 3153e12c5d1SDavid du Colombier if (type!=WARNING) 3163e12c5d1SDavid du Colombier nerrs = 1; 3173e12c5d1SDavid du Colombier fflush(stderr); 3183e12c5d1SDavid du Colombier } 319