xref: /plan9/sys/src/cmd/cpp/cpp.c (revision ad1af46927dd6466ebbfcad9e65ece52cfaf8172)
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
main(int argc,char ** argv)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
process(Tokenrow * trp)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)
7205dd1647SDavid du Colombier 			expandrow(trp, NULL, Notinmacro);
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
control(Tokenrow * trp)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) {
1039a747e4fSDavid du Colombier 		if ((np->flag&ISKW)==0)
1049a747e4fSDavid 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;
211*ad1af469SDavid du Colombier 		error(ERROR, "#error directive: %r", trp);
212*ad1af469SDavid du Colombier 		break;
213*ad1af469SDavid du Colombier 
214*ad1af469SDavid du Colombier 	case KWARNING:
215*ad1af469SDavid du Colombier 		trp->tp = tp+1;
216*ad1af469SDavid du Colombier 		error(WARNING, "#warning directive: %r", trp);
2173e12c5d1SDavid du Colombier 		break;
2183e12c5d1SDavid du Colombier 
2193e12c5d1SDavid du Colombier 	case KLINE:
2203e12c5d1SDavid du Colombier 		trp->tp = tp+1;
22105dd1647SDavid du Colombier 		expandrow(trp, "<line>", Notinmacro);
2223e12c5d1SDavid du Colombier 		tp = trp->bp+2;
2233e12c5d1SDavid du Colombier 	kline:
2243e12c5d1SDavid du Colombier 		if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp
2253e12c5d1SDavid du Colombier 		 || (tp+3==trp->lp && ((tp+1)->type!=STRING)||*(tp+1)->t=='L')){
2263e12c5d1SDavid du Colombier 			error(ERROR, "Syntax error in #line");
2273e12c5d1SDavid du Colombier 			return;
2283e12c5d1SDavid du Colombier 		}
2293e12c5d1SDavid du Colombier 		cursource->line = atol((char*)tp->t)-1;
2303e12c5d1SDavid du Colombier 		if (cursource->line<0 || cursource->line>=32768)
2313e12c5d1SDavid du Colombier 			error(WARNING, "#line specifies number out of range");
2323e12c5d1SDavid du Colombier 		tp = tp+1;
2333e12c5d1SDavid du Colombier 		if (tp+1<trp->lp)
2343e12c5d1SDavid du Colombier 			cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0);
2353e12c5d1SDavid du Colombier 		return;
2363e12c5d1SDavid du Colombier 
2373e12c5d1SDavid du Colombier 	case KDEFINED:
2383e12c5d1SDavid du Colombier 		error(ERROR, "Bad syntax for control line");
2393e12c5d1SDavid du Colombier 		break;
2403e12c5d1SDavid du Colombier 
2413e12c5d1SDavid du Colombier 	case KINCLUDE:
2423e12c5d1SDavid du Colombier 		doinclude(trp);
2433e12c5d1SDavid du Colombier 		trp->lp = trp->bp;
2443e12c5d1SDavid du Colombier 		return;
2453e12c5d1SDavid du Colombier 
2463e12c5d1SDavid du Colombier 	case KEVAL:
2473e12c5d1SDavid du Colombier 		eval(trp, np->val);
2483e12c5d1SDavid du Colombier 		break;
2493e12c5d1SDavid du Colombier 
2503e12c5d1SDavid du Colombier 	default:
2513e12c5d1SDavid du Colombier 		error(ERROR, "Preprocessor control `%t' not yet implemented", tp);
2523e12c5d1SDavid du Colombier 		break;
2533e12c5d1SDavid du Colombier 	}
2543e12c5d1SDavid du Colombier 	setempty(trp);
2553e12c5d1SDavid du Colombier 	return;
2563e12c5d1SDavid du Colombier }
2573e12c5d1SDavid du Colombier 
2583e12c5d1SDavid du Colombier void *
dorealloc(void * ptr,int size)259a8453668SDavid du Colombier dorealloc(void *ptr, int size)
260a8453668SDavid du Colombier {
261a8453668SDavid du Colombier 	void *p = realloc(ptr, size);
262a8453668SDavid du Colombier 
263a8453668SDavid du Colombier 	if (p==NULL)
264a8453668SDavid du Colombier 		error(FATAL, "Out of memory from realloc");
265a8453668SDavid du Colombier 	return p;
266a8453668SDavid du Colombier }
267a8453668SDavid du Colombier 
268a8453668SDavid du Colombier void *
domalloc(int size)2693e12c5d1SDavid du Colombier domalloc(int size)
2703e12c5d1SDavid du Colombier {
2713e12c5d1SDavid du Colombier 	void *p = malloc(size);
2723e12c5d1SDavid du Colombier 
2733e12c5d1SDavid du Colombier 	if (p==NULL)
2743e12c5d1SDavid du Colombier 		error(FATAL, "Out of memory from malloc");
2753e12c5d1SDavid du Colombier 	return p;
2763e12c5d1SDavid du Colombier }
2773e12c5d1SDavid du Colombier 
2783e12c5d1SDavid du Colombier void
dofree(void * p)2793e12c5d1SDavid du Colombier dofree(void *p)
2803e12c5d1SDavid du Colombier {
2813e12c5d1SDavid du Colombier 	free(p);
2823e12c5d1SDavid du Colombier }
2833e12c5d1SDavid du Colombier 
2843e12c5d1SDavid du Colombier void
error(enum errtype type,char * string,...)2853e12c5d1SDavid du Colombier error(enum errtype type, char *string, ...)
2863e12c5d1SDavid du Colombier {
2873e12c5d1SDavid du Colombier 	va_list ap;
2883e12c5d1SDavid du Colombier 	char *cp, *ep;
2893e12c5d1SDavid du Colombier 	Token *tp;
2903e12c5d1SDavid du Colombier 	Tokenrow *trp;
291219b2ee8SDavid du Colombier 	Source *s;
2923e12c5d1SDavid du Colombier 	int i;
29380ee5cbfSDavid du Colombier 	void *p;
2943e12c5d1SDavid du Colombier 
2953e12c5d1SDavid du Colombier 	fprintf(stderr, "cpp: ");
296219b2ee8SDavid du Colombier 	for (s=cursource; s; s=s->next)
297219b2ee8SDavid du Colombier 		if (*s->filename)
298219b2ee8SDavid du Colombier 			fprintf(stderr, "%s:%d ", s->filename, s->line);
2993e12c5d1SDavid du Colombier 	va_start(ap, string);
3003e12c5d1SDavid du Colombier 	for (ep=string; *ep; ep++) {
3013e12c5d1SDavid du Colombier 		if (*ep=='%') {
3023e12c5d1SDavid du Colombier 			switch (*++ep) {
3033e12c5d1SDavid du Colombier 
3043e12c5d1SDavid du Colombier 			case 's':
3053e12c5d1SDavid du Colombier 				cp = va_arg(ap, char *);
3063e12c5d1SDavid du Colombier 				fprintf(stderr, "%s", cp);
3073e12c5d1SDavid du Colombier 				break;
3083e12c5d1SDavid du Colombier 			case 'd':
3093e12c5d1SDavid du Colombier 				i = va_arg(ap, int);
3103e12c5d1SDavid du Colombier 				fprintf(stderr, "%d", i);
3113e12c5d1SDavid du Colombier 				break;
31280ee5cbfSDavid du Colombier 			case 'p':
31380ee5cbfSDavid du Colombier 				p = va_arg(ap, void *);
31480ee5cbfSDavid du Colombier 				fprintf(stderr, "%p", p);
31580ee5cbfSDavid du Colombier 				break;
3163e12c5d1SDavid du Colombier 			case 't':
3173e12c5d1SDavid du Colombier 				tp = va_arg(ap, Token *);
3183e12c5d1SDavid du Colombier 				fprintf(stderr, "%.*s", tp->len, tp->t);
3193e12c5d1SDavid du Colombier 				break;
3203e12c5d1SDavid du Colombier 
3213e12c5d1SDavid du Colombier 			case 'r':
3223e12c5d1SDavid du Colombier 				trp = va_arg(ap, Tokenrow *);
3233e12c5d1SDavid du Colombier 				for (tp=trp->tp; tp<trp->lp&&tp->type!=NL; tp++) {
3243e12c5d1SDavid du Colombier 					if (tp>trp->tp && tp->wslen)
3253e12c5d1SDavid du Colombier 						fputc(' ', stderr);
3263e12c5d1SDavid du Colombier 					fprintf(stderr, "%.*s", tp->len, tp->t);
3273e12c5d1SDavid du Colombier 				}
3283e12c5d1SDavid du Colombier 				break;
3293e12c5d1SDavid du Colombier 
3303e12c5d1SDavid du Colombier 			default:
3313e12c5d1SDavid du Colombier 				fputc(*ep, stderr);
3323e12c5d1SDavid du Colombier 				break;
3333e12c5d1SDavid du Colombier 			}
3343e12c5d1SDavid du Colombier 		} else
3353e12c5d1SDavid du Colombier 			fputc(*ep, stderr);
3363e12c5d1SDavid du Colombier 	}
3373e12c5d1SDavid du Colombier 	va_end(ap);
3383e12c5d1SDavid du Colombier 	fputc('\n', stderr);
3393e12c5d1SDavid du Colombier 	if (type==FATAL)
3403e12c5d1SDavid du Colombier 		exits("error");
3413e12c5d1SDavid du Colombier 	if (type!=WARNING)
3423e12c5d1SDavid du Colombier 		nerrs = 1;
3433e12c5d1SDavid du Colombier 	fflush(stderr);
3443e12c5d1SDavid du Colombier }
345