]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cpp/cpp.c
merge
[plan9front.git] / sys / src / cmd / cpp / cpp.c
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
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
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
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 *
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 *
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
279 dofree(void *p)
280 {
281         free(p);
282 }
283
284 void
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 }