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