1 /***** spin: pc_zpp.c *****/
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 */
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 */
21 enum cstate { PLAIN, IN_STRING, IN_QUOTE, S_COMM, COMMENT, E_COMM };
28 #define debug(x,y) if (verbose) printf(x,y)
30 static FILE *outpp /* = stdout */;
32 static int if_truth[MAXNEST];
33 static int printing[MAXNEST];
34 static int if_depth, nr_defs, verbose = 0;
35 static enum cstate state = PLAIN;
36 static char Out1[GENEROUS], Out2[GENEROUS];
38 static struct Defines {
43 static int process(char *, int, char *);
44 static int zpp_do(char *);
46 extern char *emalloc(int); /* main.c */
52 for (q = p+strlen(p)-1; q > p; q--)
53 if (*q == '\n' || *q == '\t' || *q == ' ')
58 q = p + strspn(p, " \t");
59 if (!(r = strchr(q, '\t')))
61 if (!r) { s = ""; goto adddef; }
62 s = r + strspn(r, " \t");
65 { debug("zpp: #define with arguments %s\n", q);
68 for (r = q+strlen(q)-1; r > q; r--)
69 if (*r == ' ' || *r == '\t')
73 if (nr_defs >= MAXDEF)
74 { debug("zpp: too many #defines (max %d)\n", nr_defs);
77 if (strcmp(q, s) != 0)
79 adddef: for (j = 0; j < nr_defs; j++)
80 if (!strcmp(d[j].src, q))
82 d[nr_defs].src = emalloc(strlen(q)+1);
83 d[nr_defs].trg = emalloc(strlen(s)+1);
84 strcpy(d[nr_defs].src, q);
85 strcpy(d[nr_defs].trg, s);
86 d[nr_defs++].exists = 1;
94 return (isalnum(c) || c == '_');
99 { char *out, *in1, *in2, *startat;
102 startat = in1 = Out2; strcpy(Out2, p0);
103 out = Out1; *out = '\0';
105 for (i = nr_defs-1; i >= 0; i--)
106 { if (!d[i].exists) continue;
107 j = (int) strlen(d[i].src);
108 more: in2 = strstr(startat, d[i].src);
109 if (!in2) /* no more matches */
113 if ((in2 == in1 || !isvalid(*(in2-1)))
114 && (in2+j == '\0' || !isvalid(*(in2+j))))
117 if (strlen(in1)+strlen(d[i].trg)+strlen(in2+j) >= GENEROUS)
119 printf("spin: circular macro expansion %s -> %s ?\n",
124 strcat(out, d[i].trg);
127 { startat = in1 = Out1;
130 { startat = in1 = Out2;
135 { startat = in2+1; /* +1 not +j.. */
137 goto more; /* recursive defines */
146 q = p + strspn(p, " \t");
147 for (s = (q + strlen(q) - 1); s > q; s--)
148 if (*s == ' ' || *s == '\t' || *s == '\n')
157 { int i; char *q = do_common(p);
159 for (i = 0; i < nr_defs; i++)
160 if (!strcmp(d[i].src, q))
167 { int i; char *q = do_common(p);
169 for (i = 0; i < nr_defs; i++)
171 && !strcmp(d[i].src, q))
179 if (++if_depth >= MAXNEST)
180 { debug("zpp: too deeply nested (max %d)\n", MAXNEST);
183 if_truth[if_depth] = (check_ifdef(p) != (char *)0);
184 printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
192 if (++if_depth >= MAXNEST)
193 { debug("zpp: too deeply nested (max %d)\n", MAXNEST);
196 if_truth[if_depth] = (check_ifdef(p) == (char *)0);
197 printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
206 if (strcmp(q, "0") == 0)
207 if_truth[if_depth] = 0;
208 else if (strcmp(q, "1") == 0)
209 if_truth[if_depth] = 1;
217 { char *q = do_common(p);
218 if (++if_depth >= MAXNEST)
219 { debug("zpp: too deeply nested (max %d)\n", MAXNEST);
223 && !is_simple(check_ifdef(q)))
224 { debug("zpp: cannot handle #if %s\n", q);
227 printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
233 do_else(char *unused)
235 if_truth[if_depth] = 1-if_truth[if_depth];
236 printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
245 { debug("zpp: unbalanced #endif %s\n", p);
258 { q = strchr (p, '\"');
259 r = strrchr(p, '\"');
260 if (!q || !r || q == r)
261 { debug("zpp: malformed #include %s", p);
272 for (q = p; *q != '\n' && *q != '\0'; q++)
276 case '"': state = IN_STRING; break;
277 case '\'': state = IN_QUOTE; break;
278 case '/': state = S_COMM; break;
279 case '\\': q++; break;
283 if (*q == '"') state = PLAIN;
284 else if (*q == '\\') q++;
287 if (*q == '\'') state = PLAIN;
288 else if (*q == '\\') q++;
294 } else if (*q != '/')
298 state = (*q == '*') ? E_COMM: COMMENT;
309 if (state == S_COMM) state = PLAIN;
310 else if (state == E_COMM) state = COMMENT;
311 return (state == COMMENT);
316 { char buf[2048], buf2[MAXLINE], *p; int n, on;
317 FILE *inp; int lno = 0, nw_lno = 0;
319 if ((inp = fopen(fnm, "r")) == NULL)
320 { fprintf(stdout, "spin: error, '%s': No such file\n", fnm);
321 return 0; /* 4.1.2 was stderr */
323 printing[0] = if_truth[0] = 1;
324 fprintf(outpp, "#line %d \"%s\"\n", lno+1, fnm);
325 while (fgets(buf, MAXLINE, inp))
326 { lno++; n = (int) strlen(buf);
328 while (n > 2 && buf[n-2] == '\\')
330 feedme: if (!fgets(buf2, MAXLINE, inp))
331 { debug("zpp: unexpected EOF ln %d\n", lno);
332 return 0; /* switch to cpp */
335 if (n + (int) strlen(buf2) >= 2048)
336 { debug("zpp: line %d too long\n", lno);
340 n = (int) strlen(buf);
342 if (in_comment(&buf[on]))
343 { buf[n-1] = '\0'; /* eat newline */
344 on = n-1; nw_lno = 1;
347 p = buf + strspn(buf, " \t");
348 if (nw_lno && *p != '#')
349 fprintf(outpp, "#line %d \"%s\"\n", lno, fnm);
351 { if (!process(p+1, lno+1, fnm))
353 } else if (printing[if_depth])
354 fprintf(outpp, "%s", apply(buf));
361 try_zpp(char *fnm, char *onm)
363 if ((outpp = fopen(onm, "w")) == NULL)
367 return r; /* 1 = ok; 0 = use cpp */
370 static struct Directives {
373 int (*handler)(char *);
376 { 6, "define", do_define, 1 },
377 { 4, "else", do_else, 0 },
378 { 5, "endif", do_endif, 0 },
379 { 5, "ifdef", do_ifdef, 0 },
380 { 6, "ifndef", do_ifndef, 0 },
381 { 2, "if", do_if, 0 },
382 { 7, "include", do_include, 1 },
383 { 8, "undefine", do_undefine, 1 },
387 process(char *q, int lno, char *fnm)
391 if (*p != ' ' && *p != '\t')
393 for (i = 0; i < (int) (sizeof(s)/sizeof(struct Directives)); i++)
394 if (!strncmp(s[i].directive, p, s[i].len))
396 && !printing[if_depth])
398 fprintf(outpp, "#line %d \"%s\"\n", lno, fnm);
399 r = s[i].handler(p + s[i].len);
400 if (i == 6) /* include */
401 fprintf(outpp, "#line %d \"%s\"\n", lno, fnm);
405 debug("zpp: unrecognized directive: %s", p);