xref: /plan9/sys/src/cmd/cpp/cpp.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
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