1 /***** spin: pc_zpp.c *****/
2
3 /* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories. */
4 /* All Rights Reserved. This software is for educational purposes only. */
5 /* No guarantee whatsoever is expressed or implied by the distribution of */
6 /* this code. Permission is given to distribute this code provided that */
7 /* this introductory message is not removed and no monies are exchanged. */
8 /* Software written by Gerard J. Holzmann. For tool documentation see: */
9 /* http://spinroot.com/ */
10 /* Send all bug-reports and/or questions to: bugs@spinroot.com */
11
12 /* pc_zpp.c is only used in the PC version of Spin */
13 /* it is included to avoid too great a reliance on an external cpp */
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include "spin.h"
20
21 #ifdef PC
22 enum cstate { PLAIN, IN_STRING, IN_QUOTE, S_COMM, COMMENT, E_COMM };
23
24 #define MAXNEST 32
25 #define MAXDEF 128
26 #define MAXLINE 2048
27 #define GENEROUS 8192
28
29 #define debug(x,y) if (verbose) printf(x,y)
30
31 static FILE *outpp /* = stdout */;
32
33 static int if_truth[MAXNEST];
34 static int printing[MAXNEST];
35 static int if_depth, nr_defs, verbose = 0;
36 static enum cstate state = PLAIN;
37 static char Out1[GENEROUS], Out2[GENEROUS];
38
39 static struct Defines {
40 int exists;
41 char *src, *trg;
42 } d[MAXDEF];
43
44 static int process(char *, int, char *);
45 static int zpp_do(char *);
46
47 extern char *emalloc(size_t); /* main.c */
48
49 static int
do_define(char * p)50 do_define(char *p)
51 { char *q, *r, *s;
52
53 for (q = p+strlen(p)-1; q > p; q--)
54 if (*q == '\n' || *q == '\t' || *q == ' ')
55 *q = '\0';
56 else
57 break;
58
59 q = p + strspn(p, " \t");
60 if (!(r = strchr(q, '\t')))
61 r = strchr(q, ' ');
62 if (!r) { s = ""; goto adddef; }
63 s = r + strspn(r, " \t");
64 *r = '\0';
65 if (strchr(q, '('))
66 { debug("zpp: #define with arguments %s\n", q);
67 return 0;
68 }
69 for (r = q+strlen(q)-1; r > q; r--)
70 if (*r == ' ' || *r == '\t')
71 *r = '\0';
72 else
73 break;
74 if (nr_defs >= MAXDEF)
75 { debug("zpp: too many #defines (max %d)\n", nr_defs);
76 return 0;
77 }
78 if (strcmp(q, s) != 0)
79 { int j;
80 adddef: for (j = 0; j < nr_defs; j++)
81 if (!strcmp(d[j].src, q))
82 d[j].exists = 0;
83 d[nr_defs].src = emalloc(strlen(q)+1);
84 d[nr_defs].trg = emalloc(strlen(s)+1);
85 strcpy(d[nr_defs].src, q);
86 strcpy(d[nr_defs].trg, s);
87 d[nr_defs++].exists = 1;
88 }
89 return 1;
90 }
91
92 static int
isvalid(int c)93 isvalid(int c)
94 {
95 return (isalnum(c) || c == '_');
96 }
97
98 static char *
apply(char * p0)99 apply(char *p0)
100 { char *out, *in1, *in2, *startat;
101 int i, j;
102
103 startat = in1 = Out2; strcpy(Out2, p0);
104 out = Out1; *out = '\0';
105
106 for (i = nr_defs-1; i >= 0; i--)
107 { if (!d[i].exists) continue;
108 j = (int) strlen(d[i].src);
109 more: in2 = strstr(startat, d[i].src);
110 if (!in2) /* no more matches */
111 { startat = in1;
112 continue;
113 }
114 if ((in2 == in1 || !isvalid(*(in2-1)))
115 && (in2+j == '\0' || !isvalid(*(in2+j))))
116 { *in2 = '\0';
117
118 if (strlen(in1)+strlen(d[i].trg)+strlen(in2+j) >= GENEROUS)
119 {
120 printf("spin: macro expansion overflow %s -> %s ?\n",
121 d[i].src, d[i].trg);
122 return in1;
123 }
124 strcat(out, in1);
125 strcat(out, d[i].trg);
126 strcat(out, in2+j);
127 if (in1 == Out2)
128 { startat = in1 = Out1;
129 out = Out2;
130 } else
131 { startat = in1 = Out2;
132 out = Out1;
133 }
134 *out = '\0';
135 } else
136 { startat = in2+1; /* +1 not +j.. */
137 }
138 goto more; /* recursive defines */
139 }
140 return in1;
141 }
142
143 static char *
do_common(char * p)144 do_common(char *p)
145 { char *q, *s;
146
147 q = p + strspn(p, " \t");
148 for (s = (q + strlen(q) - 1); s > q; s--)
149 if (*s == ' ' || *s == '\t' || *s == '\n')
150 *s = '\0';
151 else
152 break;
153 return q;
154 }
155
156 static int
do_undefine(char * p)157 do_undefine(char *p)
158 { int i; char *q = do_common(p);
159
160 for (i = 0; i < nr_defs; i++)
161 if (!strcmp(d[i].src, q))
162 d[i].exists = 0;
163 return 1;
164 }
165
166 static char *
check_ifdef(char * p)167 check_ifdef(char *p)
168 { int i; char *q = do_common(p);
169
170 for (i = 0; i < nr_defs; i++)
171 if (d[i].exists
172 && !strcmp(d[i].src, q))
173 return d[i].trg;
174 return (char *) 0;
175 }
176
177 static int
do_ifdef(char * p)178 do_ifdef(char *p)
179 {
180 if (++if_depth >= MAXNEST)
181 { debug("zpp: too deeply nested (max %d)\n", MAXNEST);
182 return 0;
183 }
184 if_truth[if_depth] = (check_ifdef(p) != (char *)0);
185 printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
186
187 return 1;
188 }
189
190 static int
do_ifndef(char * p)191 do_ifndef(char *p)
192 {
193 if (++if_depth >= MAXNEST)
194 { debug("zpp: too deeply nested (max %d)\n", MAXNEST);
195 return 0;
196 }
197 if_truth[if_depth] = (check_ifdef(p) == (char *)0);
198 printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
199
200 return 1;
201 }
202
203 static int
is_simple(char * q)204 is_simple(char *q)
205 {
206 if (!q) return 0;
207 if (strcmp(q, "0") == 0)
208 if_truth[if_depth] = 0;
209 else if (strcmp(q, "1") == 0)
210 if_truth[if_depth] = 1;
211 else
212 return 0;
213 return 1;
214 }
215
216 static int
do_if(char * p)217 do_if(char *p)
218 { char *q = do_common(p);
219 if (++if_depth >= MAXNEST)
220 { debug("zpp: too deeply nested (max %d)\n", MAXNEST);
221 return 0;
222 }
223 if (!is_simple(q)
224 && !is_simple(check_ifdef(q)))
225 { debug("zpp: cannot handle #if %s\n", q);
226 return 0;
227 }
228 printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
229
230 return 1;
231 }
232
233 static int
do_else(char * p)234 do_else(char *p)
235 {
236 debug("zpp: do_else %s", p);
237 if_truth[if_depth] = 1-if_truth[if_depth];
238 printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
239
240 return 1;
241 }
242
243 static int
do_endif(char * p)244 do_endif(char *p)
245 {
246 if (--if_depth < 0)
247 { debug("zpp: unbalanced #endif %s\n", p);
248 return 0;
249 }
250 return 1;
251 }
252
253 static int
do_include(char * p)254 do_include(char *p)
255 { char *r, *q;
256
257 q = strchr(p, '<');
258 r = strrchr(p, '>');
259 if (!q || !r)
260 { q = strchr (p, '\"');
261 r = strrchr(p, '\"');
262 if (!q || !r || q == r)
263 { debug("zpp: malformed #include %s", p);
264 return 0;
265 } }
266 *r = '\0';
267 return zpp_do(++q);
268 }
269
270 static int
in_comment(char * p)271 in_comment(char *p)
272 { char *q = p;
273
274 for (q = p; *q != '\n' && *q != '\0'; q++)
275 switch (state) {
276 case PLAIN:
277 switch (*q) {
278 case '"': state = IN_STRING; break;
279 case '\'': state = IN_QUOTE; break;
280 case '/': state = S_COMM; break;
281 case '\\': q++; break;
282 }
283 break;
284 case IN_STRING:
285 if (*q == '"') state = PLAIN;
286 else if (*q == '\\') q++;
287 break;
288 case IN_QUOTE:
289 if (*q == '\'') state = PLAIN;
290 else if (*q == '\\') q++;
291 break;
292 case S_COMM:
293 if (*q == '*')
294 { *(q-1) = *q = ' ';
295 state = COMMENT;
296 } else if (*q != '/')
297 state = PLAIN;
298 break;
299 case COMMENT:
300 state = (*q == '*') ? E_COMM: COMMENT;
301 *q = ' ';
302 break;
303 case E_COMM:
304 if (*q == '/')
305 state = PLAIN;
306 else if (*q != '*')
307 state = COMMENT;
308 *q = ' ';
309 break;
310 }
311 if (state == S_COMM) state = PLAIN;
312 else if (state == E_COMM) state = COMMENT;
313 return (state == COMMENT);
314 }
315
316 static int
strip_cpp_comments(char * p)317 strip_cpp_comments(char *p)
318 { char *q;
319
320 q = strstr(p, "//");
321 if (q)
322 { if (q > p && *(q-1) == '\\')
323 { return strip_cpp_comments(q+1);
324 }
325 *q = '\n';
326 *(q+1) = '\0';
327 return 1;
328 }
329 return 0;
330 }
331
332 static int
zpp_do(char * fnm)333 zpp_do(char *fnm)
334 { char buf[2048], buf2[MAXLINE], *p; int n, on;
335 FILE *inp; int lno = 0, nw_lno = 0;
336
337 if ((inp = fopen(fnm, "r")) == NULL)
338 { fprintf(stdout, "spin: error: No file '%s'\n", fnm);
339 exit(1); /* 4.1.2 was stderr */
340 }
341 printing[0] = if_truth[0] = 1;
342 fprintf(outpp, "#line %d \"%s\"\n", lno+1, fnm);
343 while (fgets(buf, MAXLINE, inp))
344 { lno++; n = (int) strlen(buf);
345 on = 0; nw_lno = 0;
346 while (n > 2 && buf[n-2] == '\\')
347 { buf[n-2] = '\0';
348 feedme:
349 if (!fgets(buf2, MAXLINE, inp))
350 { debug("zpp: unexpected EOF ln %d\n", lno);
351 return 0; /* switch to cpp */
352 }
353 lno++;
354 if (n + (int) strlen(buf2) >= 2048)
355 { debug("zpp: line %d too long\n", lno);
356 return 0;
357 }
358 strcat(buf, buf2);
359 n = (int) strlen(buf);
360 }
361
362 if (strip_cpp_comments(&buf[on]))
363 n = (int) strlen(buf);
364
365 if (in_comment(&buf[on]))
366 { buf[n-1] = '\0'; /* eat newline */
367 on = n-1; nw_lno = 1;
368 goto feedme;
369 }
370 p = buf + strspn(buf, " \t");
371 if (nw_lno && *p != '#')
372 fprintf(outpp, "#line %d \"%s\"\n", lno, fnm);
373 if (*p == '#')
374 { if (!process(p+1, lno+1, fnm))
375 return 0;
376 } else if (printing[if_depth])
377 fprintf(outpp, "%s", apply(buf));
378 }
379 fclose(inp);
380 return 1;
381 }
382
383 int
try_zpp(char * fnm,char * onm)384 try_zpp(char *fnm, char *onm)
385 { int r;
386 if ((outpp = fopen(onm, MFLAGS)) == NULL)
387 return 0;
388 r = zpp_do(fnm);
389 fclose(outpp);
390 return r; /* 1 = ok; 0 = use cpp */
391 }
392
393 static struct Directives {
394 int len;
395 char *directive;
396 int (*handler)(char *);
397 int interp;
398 } s[] = {
399 { 6, "define", do_define, 1 },
400 { 4, "else", do_else, 0 },
401 { 5, "endif", do_endif, 0 },
402 { 5, "ifdef", do_ifdef, 0 },
403 { 6, "ifndef", do_ifndef, 0 },
404 { 2, "if", do_if, 0 },
405 { 7, "include", do_include, 1 },
406 { 8, "undefine", do_undefine, 1 },
407 };
408
409 static int
process(char * q,int lno,char * fnm)410 process(char *q, int lno, char *fnm)
411 { char *p; int i, r;
412
413 for (p = q; *p; p++)
414 if (*p != ' ' && *p != '\t')
415 break;
416
417 if (strncmp(p, "line", 4) == 0)
418 { p += 4;
419 while (*p == ' ' || *p == '\t')
420 { p++;
421 }
422 lno = atoi(p);
423 return 1; /* line directive */
424 }
425 if (isdigit((int) *p))
426 { lno = atoi(p);
427 return 1;
428 }
429 if (strncmp(p, "error", 5) == 0)
430 { printf("spin: %s", p);
431 exit(1);
432 }
433 if (strncmp(p, "warning", 7) == 0)
434 { printf("spin: %s", p);
435 return 1;
436 }
437 for (i = 0; i < (int) (sizeof(s)/sizeof(struct Directives)); i++)
438 if (!strncmp(s[i].directive, p, s[i].len))
439 { if (s[i].interp
440 && !printing[if_depth])
441 return 1;
442 fprintf(outpp, "#line %d \"%s\"\n", lno, fnm);
443 r = s[i].handler(p + s[i].len);
444 if (i == 6) /* include */
445 fprintf(outpp, "#line %d \"%s\"\n", lno, fnm);
446 return r;
447 }
448
449 debug("zpp: unrecognized directive: %s", p);
450 return 0;
451 }
452 #endif
453