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