xref: /plan9/sys/src/cmd/cpp/cpp.c (revision ad1af46927dd6466ebbfcad9e65ece52cfaf8172)
1 #include <u.h>
2 #include <libc.h>
3 #include <stdio.h>
4 #include "cpp.h"
5 
6 #define	OUTS	16384
7 char	outbuf[OUTS];
8 char	*outp = outbuf;
9 Source	*cursource;
10 int	nerrs;
11 struct	token nltoken = { NL, 0, 0, 0, 1, (uchar*)"\n" };
12 char	*curtime;
13 int	incdepth;
14 int	ifdepth;
15 int	ifsatisfied[NIF];
16 int	skipping;
17 
18 int
main(int argc,char ** argv)19 main(int argc, char **argv)
20 {
21 	Tokenrow tr;
22 	long t;
23 	char ebuf[BUFSIZ];
24 
25 	setbuf(stderr, ebuf);
26 	t = time(NULL);
27 	curtime = ctime(t);
28 	maketokenrow(3, &tr);
29 	expandlex();
30 	setup(argc, argv);
31 	fixlex();
32 	iniths();
33 	genline();
34 	process(&tr);
35 	flushout();
36 	fflush(stderr);
37 	exits(nerrs? "errors" : 0);
38 	return 0;
39 }
40 
41 void
process(Tokenrow * trp)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, Notinmacro);
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
control(Tokenrow * trp)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 		if ((np->flag&ISKW)==0)
104 			return;
105 		switch (np->val) {
106 		case KENDIF:
107 			if (--ifdepth<skipping)
108 				skipping = 0;
109 			--cursource->ifdepth;
110 			setempty(trp);
111 			return;
112 
113 		case KIFDEF:
114 		case KIFNDEF:
115 		case KIF:
116 			if (++ifdepth >= NIF)
117 				error(FATAL, "#if too deeply nested");
118 			++cursource->ifdepth;
119 			return;
120 
121 		case KELIF:
122 		case KELSE:
123 			if (ifdepth<=skipping)
124 				break;
125 			return;
126 
127 		default:
128 			return;
129 		}
130 	}
131 	switch (np->val) {
132 	case KDEFINE:
133 		dodefine(trp);
134 		break;
135 
136 	case KUNDEF:
137 		tp += 1;
138 		if (tp->type!=NAME || trp->lp - trp->bp != 4) {
139 			error(ERROR, "Syntax error in #undef");
140 			break;
141 		}
142 		if ((np = lookup(tp, 0))) {
143 			if (np->flag&ISUNCHANGE) {
144 				error(ERROR, "#defined token %t can't be undefined", tp);
145 				return;
146 			}
147 			np->flag &= ~ISDEFINED;
148 		}
149 		break;
150 
151 	case KPRAGMA:
152 		return;
153 
154 	case KIFDEF:
155 	case KIFNDEF:
156 	case KIF:
157 		if (++ifdepth >= NIF)
158 			error(FATAL, "#if too deeply nested");
159 		++cursource->ifdepth;
160 		ifsatisfied[ifdepth] = 0;
161 		if (eval(trp, np->val))
162 			ifsatisfied[ifdepth] = 1;
163 		else
164 			skipping = ifdepth;
165 		break;
166 
167 	case KELIF:
168 		if (ifdepth==0) {
169 			error(ERROR, "#elif with no #if");
170 			return;
171 		}
172 		if (ifsatisfied[ifdepth]==2)
173 			error(ERROR, "#elif after #else");
174 		if (eval(trp, np->val)) {
175 			if (ifsatisfied[ifdepth])
176 				skipping = ifdepth;
177 			else {
178 				skipping = 0;
179 				ifsatisfied[ifdepth] = 1;
180 			}
181 		} else
182 			skipping = ifdepth;
183 		break;
184 
185 	case KELSE:
186 		if (ifdepth==0 || cursource->ifdepth==0) {
187 			error(ERROR, "#else with no #if");
188 			return;
189 		}
190 		if (ifsatisfied[ifdepth]==2)
191 			error(ERROR, "#else after #else");
192 		if (trp->lp - trp->bp != 3)
193 			error(ERROR, "Syntax error in #else");
194 		skipping = ifsatisfied[ifdepth]? ifdepth: 0;
195 		ifsatisfied[ifdepth] = 2;
196 		break;
197 
198 	case KENDIF:
199 		if (ifdepth==0 || cursource->ifdepth==0) {
200 			error(ERROR, "#endif with no #if");
201 			return;
202 		}
203 		--ifdepth;
204 		--cursource->ifdepth;
205 		if (trp->lp - trp->bp != 3)
206 			error(WARNING, "Syntax error in #endif");
207 		break;
208 
209 	case KERROR:
210 		trp->tp = tp+1;
211 		error(ERROR, "#error directive: %r", trp);
212 		break;
213 
214 	case KWARNING:
215 		trp->tp = tp+1;
216 		error(WARNING, "#warning directive: %r", trp);
217 		break;
218 
219 	case KLINE:
220 		trp->tp = tp+1;
221 		expandrow(trp, "<line>", Notinmacro);
222 		tp = trp->bp+2;
223 	kline:
224 		if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp
225 		 || (tp+3==trp->lp && ((tp+1)->type!=STRING)||*(tp+1)->t=='L')){
226 			error(ERROR, "Syntax error in #line");
227 			return;
228 		}
229 		cursource->line = atol((char*)tp->t)-1;
230 		if (cursource->line<0 || cursource->line>=32768)
231 			error(WARNING, "#line specifies number out of range");
232 		tp = tp+1;
233 		if (tp+1<trp->lp)
234 			cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0);
235 		return;
236 
237 	case KDEFINED:
238 		error(ERROR, "Bad syntax for control line");
239 		break;
240 
241 	case KINCLUDE:
242 		doinclude(trp);
243 		trp->lp = trp->bp;
244 		return;
245 
246 	case KEVAL:
247 		eval(trp, np->val);
248 		break;
249 
250 	default:
251 		error(ERROR, "Preprocessor control `%t' not yet implemented", tp);
252 		break;
253 	}
254 	setempty(trp);
255 	return;
256 }
257 
258 void *
dorealloc(void * ptr,int size)259 dorealloc(void *ptr, int size)
260 {
261 	void *p = realloc(ptr, size);
262 
263 	if (p==NULL)
264 		error(FATAL, "Out of memory from realloc");
265 	return p;
266 }
267 
268 void *
domalloc(int size)269 domalloc(int size)
270 {
271 	void *p = malloc(size);
272 
273 	if (p==NULL)
274 		error(FATAL, "Out of memory from malloc");
275 	return p;
276 }
277 
278 void
dofree(void * p)279 dofree(void *p)
280 {
281 	free(p);
282 }
283 
284 void
error(enum errtype type,char * string,...)285 error(enum errtype type, char *string, ...)
286 {
287 	va_list ap;
288 	char *cp, *ep;
289 	Token *tp;
290 	Tokenrow *trp;
291 	Source *s;
292 	int i;
293 	void *p;
294 
295 	fprintf(stderr, "cpp: ");
296 	for (s=cursource; s; s=s->next)
297 		if (*s->filename)
298 			fprintf(stderr, "%s:%d ", s->filename, s->line);
299 	va_start(ap, string);
300 	for (ep=string; *ep; ep++) {
301 		if (*ep=='%') {
302 			switch (*++ep) {
303 
304 			case 's':
305 				cp = va_arg(ap, char *);
306 				fprintf(stderr, "%s", cp);
307 				break;
308 			case 'd':
309 				i = va_arg(ap, int);
310 				fprintf(stderr, "%d", i);
311 				break;
312 			case 'p':
313 				p = va_arg(ap, void *);
314 				fprintf(stderr, "%p", p);
315 				break;
316 			case 't':
317 				tp = va_arg(ap, Token *);
318 				fprintf(stderr, "%.*s", tp->len, tp->t);
319 				break;
320 
321 			case 'r':
322 				trp = va_arg(ap, Tokenrow *);
323 				for (tp=trp->tp; tp<trp->lp&&tp->type!=NL; tp++) {
324 					if (tp>trp->tp && tp->wslen)
325 						fputc(' ', stderr);
326 					fprintf(stderr, "%.*s", tp->len, tp->t);
327 				}
328 				break;
329 
330 			default:
331 				fputc(*ep, stderr);
332 				break;
333 			}
334 		} else
335 			fputc(*ep, stderr);
336 	}
337 	va_end(ap);
338 	fputc('\n', stderr);
339 	if (type==FATAL)
340 		exits("error");
341 	if (type!=WARNING)
342 		nerrs = 1;
343 	fflush(stderr);
344 }
345