xref: /plan9-contrib/sys/src/cmd/cpp/cpp.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1 #include <u.h>
2 #include <libc.h>
3 #include <stdio.h>
4 #include <stdarg.h>
5 #include "cpp.h"
6 
7 #define	OUTS	16384
8 char	outbuf[OUTS];
9 char	*outp = outbuf;
10 Source	*cursource;
11 int	nerrs;
12 struct	token nltoken = { NL, 0, 0, 0, 1, (uchar*)"\n" };
13 char	*curtime;
14 int	incdepth;
15 int	ifdepth;
16 int	ifsatisfied[NIF];
17 int	skipping;
18 
19 void
20 main(int argc, char **argv)
21 {
22 	Tokenrow tr;
23 	long t;
24 	char ebuf[BUFSIZ];
25 
26 	setbuf(stderr, ebuf);
27 	t = time(NULL);
28 	curtime = ctime(t);
29 	maketokenrow(3, &tr);
30 	expandlex();
31 	setup(argc, argv);
32 	fixlex();
33 	iniths();
34 	genline();
35 	process(&tr);
36 	flushout();
37 	fflush(stderr);
38 	exits(nerrs? "errors" : 0);
39 }
40 
41 void
42 process(Tokenrow *trp)
43 {
44 	int anymacros = 0;
45 
46 	for (;;) {
47 		if (trp->tp >= trp->lp) {
48 			trp->tp = trp->lp = trp->bp;
49 			outp = outbuf;
50 			anymacros |= gettokens(trp, 1);
51 			trp->tp = trp->bp;
52 		}
53 		if (trp->tp->type == END) {
54 			if (--incdepth>=0) {
55 				if (cursource->ifdepth)
56 					error(ERROR,
57 					 "Unterminated conditional in #include");
58 				unsetsource();
59 				cursource->line += cursource->lineinc;
60 				trp->tp = trp->lp;
61 				genline();
62 				continue;
63 			}
64 			if (ifdepth)
65 				error(ERROR, "Unterminated #if/#ifdef/#ifndef");
66 			break;
67 		}
68 		if (trp->tp->type==SHARP) {
69 			trp->tp += 1;
70 			control(trp);
71 		} else if (!skipping && anymacros)
72 			expandrow(trp, NULL);
73 		if (skipping)
74 			setempty(trp);
75 		puttokens(trp);
76 		anymacros = 0;
77 		cursource->line += cursource->lineinc;
78 		if (cursource->lineinc>1) {
79 			genline();
80 		}
81 	}
82 }
83 
84 void
85 control(Tokenrow *trp)
86 {
87 	Nlist *np;
88 	Token *tp;
89 
90 	tp = trp->tp;
91 	if (tp->type!=NAME) {
92 		if (tp->type==NUMBER)
93 			goto kline;
94 		if (tp->type != NL)
95 			error(ERROR, "Unidentifiable control line");
96 		return;			/* else empty line */
97 	}
98 	if ((np = lookup(tp, 0))==NULL || (np->flag&ISKW)==0 && !skipping) {
99 		error(WARNING, "Unknown preprocessor control %t", tp);
100 		return;
101 	}
102 	if (skipping) {
103 		switch (np->val) {
104 		case KENDIF:
105 			if (--ifdepth<skipping)
106 				skipping = 0;
107 			--cursource->ifdepth;
108 			setempty(trp);
109 			return;
110 
111 		case KIFDEF:
112 		case KIFNDEF:
113 		case KIF:
114 			if (++ifdepth >= NIF)
115 				error(FATAL, "#if too deeply nested");
116 			++cursource->ifdepth;
117 			return;
118 
119 		case KELIF:
120 		case KELSE:
121 			if (ifdepth<=skipping)
122 				break;
123 			return;
124 
125 		default:
126 			return;
127 		}
128 	}
129 	switch (np->val) {
130 	case KDEFINE:
131 		dodefine(trp);
132 		break;
133 
134 	case KUNDEF:
135 		tp += 1;
136 		if (tp->type!=NAME || trp->lp - trp->bp != 4) {
137 			error(ERROR, "Syntax error in #undef");
138 			break;
139 		}
140 		if ((np = lookup(tp, 0)))
141 			np->flag &= ~ISDEFINED;
142 		break;
143 
144 	case KPRAGMA:
145 		return;
146 
147 	case KIFDEF:
148 	case KIFNDEF:
149 	case KIF:
150 		if (++ifdepth > NIF)
151 			error(FATAL, "#if too deeply nested");
152 		++cursource->ifdepth;
153 		ifsatisfied[ifdepth] = 0;
154 		if (eval(trp, np->val))
155 			ifsatisfied[ifdepth] = 1;
156 		else
157 			skipping = ifdepth;
158 		break;
159 
160 	case KELIF:
161 		if (ifdepth==0) {
162 			error(ERROR, "#elif with no #if");
163 			return;
164 		}
165 		if (ifsatisfied[ifdepth]==2)
166 			error(ERROR, "#elif after #else");
167 		if (eval(trp, np->val)) {
168 			if (ifsatisfied[ifdepth])
169 				skipping = ifdepth;
170 			else {
171 				skipping = 0;
172 				ifsatisfied[ifdepth] = 1;
173 			}
174 		} else
175 			skipping = ifdepth;
176 		break;
177 
178 	case KELSE:
179 		if (ifdepth==0 || cursource->ifdepth==0) {
180 			error(ERROR, "#else with no #if");
181 			return;
182 		}
183 		if (ifsatisfied[ifdepth]==2)
184 			error(ERROR, "#else after #else");
185 		if (trp->lp - trp->bp != 3)
186 			error(ERROR, "Syntax error in #else");
187 		skipping = ifsatisfied[ifdepth]? ifdepth: 0;
188 		ifsatisfied[ifdepth] = 2;
189 		break;
190 
191 	case KENDIF:
192 		if (ifdepth==0 || cursource->ifdepth==0) {
193 			error(ERROR, "#endif with no #if");
194 			return;
195 		}
196 		--ifdepth;
197 		--cursource->ifdepth;
198 		if (trp->lp - trp->bp != 3)
199 			error(WARNING, "Syntax error in #endif");
200 		break;
201 
202 	case KERROR:
203 		trp->tp = tp+1;
204 		error(WARNING, "#error directive: %r", trp);
205 		break;
206 
207 	case KLINE:
208 		trp->tp = tp+1;
209 		expandrow(trp, "<line>");
210 		tp = trp->bp+2;
211 	kline:
212 		if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp
213 		 || (tp+3==trp->lp && ((tp+1)->type!=STRING)||*(tp+1)->t=='L')){
214 			error(ERROR, "Syntax error in #line");
215 			return;
216 		}
217 		cursource->line = atol((char*)tp->t)-1;
218 		if (cursource->line<0 || cursource->line>=32768)
219 			error(WARNING, "#line specifies number out of range");
220 		tp = tp+1;
221 		if (tp+1<trp->lp)
222 			cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0);
223 		return;
224 
225 	case KDEFINED:
226 		error(ERROR, "Bad syntax for control line");
227 		break;
228 
229 	case KINCLUDE:
230 		doinclude(trp);
231 		trp->lp = trp->bp;
232 		return;
233 
234 	case KEVAL:
235 		eval(trp, np->val);
236 		break;
237 
238 	default:
239 		error(ERROR, "Preprocessor control `%t' not yet implemented", tp);
240 		break;
241 	}
242 	setempty(trp);
243 	return;
244 }
245 
246 void *
247 domalloc(int size)
248 {
249 	void *p = malloc(size);
250 
251 	if (p==NULL)
252 		error(FATAL, "Out of memory from malloc");
253 	return p;
254 }
255 
256 void
257 dofree(void *p)
258 {
259 	free(p);
260 }
261 
262 void
263 error(enum errtype type, char *string, ...)
264 {
265 	va_list ap;
266 	char *cp, *ep;
267 	Token *tp;
268 	Tokenrow *trp;
269 	int i;
270 
271 	if (*cursource->filename)
272 		fprintf(stderr, "cpp: %s:%d: ", cursource->filename, cursource->line);
273 	else
274 		fprintf(stderr, "cpp: ");
275 	va_start(ap, string);
276 	for (ep=string; *ep; ep++) {
277 		if (*ep=='%') {
278 			switch (*++ep) {
279 
280 			case 's':
281 				cp = va_arg(ap, char *);
282 				fprintf(stderr, "%s", cp);
283 				break;
284 			case 'd':
285 				i = va_arg(ap, int);
286 				fprintf(stderr, "%d", i);
287 				break;
288 			case 't':
289 				tp = va_arg(ap, Token *);
290 				fprintf(stderr, "%.*s", tp->len, tp->t);
291 				break;
292 
293 			case 'r':
294 				trp = va_arg(ap, Tokenrow *);
295 				for (tp=trp->tp; tp<trp->lp&&tp->type!=NL; tp++) {
296 					if (tp>trp->tp && tp->wslen)
297 						fputc(' ', stderr);
298 					fprintf(stderr, "%.*s", tp->len, tp->t);
299 				}
300 				break;
301 
302 			default:
303 				fputc(*ep, stderr);
304 				break;
305 			}
306 		} else
307 			fputc(*ep, stderr);
308 	}
309 	va_end(ap);
310 	fputc('\n', stderr);
311 	if (type==FATAL)
312 		exits("error");
313 	if (type!=WARNING)
314 		nerrs = 1;
315 	fflush(stderr);
316 }
317