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