/***** spin: pc_zpp.c *****/ /* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories. *//* All Rights Reserved. This software is for educational purposes only. *//* No guarantee whatsoever is expressed or implied by the distribution of *//* this code. Permission is given to distribute this code provided that *//* this introductory message is not removed and no monies are exchanged. *//* Software written by Gerard J. Holzmann. For tool documentation see: *//* http://spinroot.com/ *//* Send all bug-reports and/or questions to: bugs@spinroot.com */ /* pc_zpp.c is only used in the PC version of Spin *//* it is included to avoid too great a reliance on an external cpp */ #include <stdlib.h>#include <stdio.h>#include <string.h>#include <ctype.h>#include "spin.h" #ifdef PCenum cstate { PLAIN, IN_STRING, IN_QUOTE, S_COMM, COMMENT, E_COMM }; #define MAXNEST 32#define MAXDEF 128#define MAXLINE 2048#define GENEROUS 8192 #define debug(x,y) if (verbose) printf(x,y) static FILE *outpp /* = stdout */; static int if_truth[MAXNEST];static int printing[MAXNEST];static int if_depth, nr_defs, verbose = 0;static enum cstate state = PLAIN;static char Out1[GENEROUS], Out2[GENEROUS]; static struct Defines { int exists; char *src, *trg;} d[MAXDEF]; static int process(char *, int, char *);static int zpp_do(char *); extern char *emalloc(size_t); /* main.c */ static intdo_define(char *p){ char *q, *r, *s; for (q = p+strlen(p)-1; q > p; q--) if (*q == '\n' || *q == '\t' || *q == ' ') *q = '\0'; else break; q = p + strspn(p, " \t"); if (!(r = strchr(q, '\t'))) r = strchr(q, ' '); if (!r) { s = ""; goto adddef; } s = r + strspn(r, " \t"); *r = '\0'; if (strchr(q, '(')) { debug("zpp: #define with arguments %s\n", q); return 0; } for (r = q+strlen(q)-1; r > q; r--) if (*r == ' ' || *r == '\t') *r = '\0'; else break; if (nr_defs >= MAXDEF) { debug("zpp: too many #defines (max %d)\n", nr_defs); return 0; } if (strcmp(q, s) != 0) { int j;adddef: for (j = 0; j < nr_defs; j++) if (!strcmp(d[j].src, q)) d[j].exists = 0; d[nr_defs].src = emalloc(strlen(q)+1); d[nr_defs].trg = emalloc(strlen(s)+1); strcpy(d[nr_defs].src, q); strcpy(d[nr_defs].trg, s); d[nr_defs++].exists = 1; } return 1;} static intisvalid(int c){ return (isalnum(c) || c == '_');} static char *apply(char *p0){ char *out, *in1, *in2, *startat; int i, j; startat = in1 = Out2; strcpy(Out2, p0); out = Out1; *out = '\0'; for (i = nr_defs-1; i >= 0; i--) { if (!d[i].exists) continue; j = (int) strlen(d[i].src);more: in2 = strstr(startat, d[i].src); if (!in2) /* no more matches */ { startat = in1; continue; } if ((in2 == in1 || !isvalid(*(in2-1))) && (in2+j == '\0' || !isvalid(*(in2+j)))) { *in2 = '\0'; if (strlen(in1)+strlen(d[i].trg)+strlen(in2+j) >= GENEROUS) { printf("spin: macro expansion overflow %s -> %s ?\n", d[i].src, d[i].trg); return in1; } strcat(out, in1); strcat(out, d[i].trg); strcat(out, in2+j); if (in1 == Out2) { startat = in1 = Out1; out = Out2; } else { startat = in1 = Out2; out = Out1; } *out = '\0'; } else { startat = in2+1; /* +1 not +j.. */ } goto more; /* recursive defines */ } return in1;} static char *do_common(char *p){ char *q, *s; q = p + strspn(p, " \t"); for (s = (q + strlen(q) - 1); s > q; s--) if (*s == ' ' || *s == '\t' || *s == '\n') *s = '\0'; else break; return q;} static intdo_undefine(char *p){ int i; char *q = do_common(p); for (i = 0; i < nr_defs; i++) if (!strcmp(d[i].src, q)) d[i].exists = 0; return 1;} static char *check_ifdef(char *p){ int i; char *q = do_common(p); for (i = 0; i < nr_defs; i++) if (d[i].exists && !strcmp(d[i].src, q)) return d[i].trg; return (char *) 0;} static intdo_ifdef(char *p){ if (++if_depth >= MAXNEST) { debug("zpp: too deeply nested (max %d)\n", MAXNEST); return 0; } if_truth[if_depth] = (check_ifdef(p) != (char *)0); printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth]; return 1;} static intdo_ifndef(char *p){ if (++if_depth >= MAXNEST) { debug("zpp: too deeply nested (max %d)\n", MAXNEST); return 0; } if_truth[if_depth] = (check_ifdef(p) == (char *)0); printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth]; return 1;} static intis_simple(char *q){ if (!q) return 0; if (strcmp(q, "0") == 0) if_truth[if_depth] = 0; else if (strcmp(q, "1") == 0) if_truth[if_depth] = 1; else return 0; return 1;} static intdo_if(char *p){ char *q = do_common(p); if (++if_depth >= MAXNEST) { debug("zpp: too deeply nested (max %d)\n", MAXNEST); return 0; } if (!is_simple(q) && !is_simple(check_ifdef(q))) { debug("zpp: cannot handle #if %s\n", q); return 0; } printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth]; return 1;} static intdo_else(char *p){ debug("zpp: do_else %s", p); if_truth[if_depth] = 1-if_truth[if_depth]; printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth]; return 1;} static intdo_endif(char *p){ if (--if_depth < 0) { debug("zpp: unbalanced #endif %s\n", p); return 0; } return 1;} static intdo_include(char *p){ char *r, *q; q = strchr(p, '<'); r = strrchr(p, '>'); if (!q || !r) { q = strchr (p, '\"'); r = strrchr(p, '\"'); if (!q || !r || q == r) { debug("zpp: malformed #include %s", p); return 0; } } *r = '\0'; return zpp_do(++q);} static intin_comment(char *p){ char *q = p; for (q = p; *q != '\n' && *q != '\0'; q++) switch (state) { case PLAIN: switch (*q) { case '"': state = IN_STRING; break; case '\'': state = IN_QUOTE; break; case '/': state = S_COMM; break; case '\\': q++; break; } break; case IN_STRING: if (*q == '"') state = PLAIN; else if (*q == '\\') q++; break; case IN_QUOTE: if (*q == '\'') state = PLAIN; else if (*q == '\\') q++; break; case S_COMM: if (*q == '*') { *(q-1) = *q = ' '; state = COMMENT; } else if (*q != '/') state = PLAIN; break; case COMMENT: state = (*q == '*') ? E_COMM: COMMENT; *q = ' '; break; case E_COMM: if (*q == '/') state = PLAIN; else if (*q != '*') state = COMMENT; *q = ' '; break; } if (state == S_COMM) state = PLAIN; else if (state == E_COMM) state = COMMENT; return (state == COMMENT);} static intstrip_cpp_comments(char *p){ char *q; q = strstr(p, "//"); if (q) { if (q > p && *(q-1) == '\\') { return strip_cpp_comments(q+1); } *q = '\n'; *(q+1) = '\0'; return 1; } return 0;} static intzpp_do(char *fnm){ char buf[2048], buf2[MAXLINE], *p; int n, on; FILE *inp; int lno = 0, nw_lno = 0; if ((inp = fopen(fnm, "r")) == NULL) { fprintf(stdout, "spin: error: No file '%s'\n", fnm); exit(1); /* 4.1.2 was stderr */ } printing[0] = if_truth[0] = 1; fprintf(outpp, "#line %d \"%s\"\n", lno+1, fnm); while (fgets(buf, MAXLINE, inp)) { lno++; n = (int) strlen(buf); on = 0; nw_lno = 0; while (n > 2 && buf[n-2] == '\\') { buf[n-2] = '\0';feedme: if (!fgets(buf2, MAXLINE, inp)) { debug("zpp: unexpected EOF ln %d\n", lno); return 0; /* switch to cpp */ } lno++; if (n + (int) strlen(buf2) >= 2048) { debug("zpp: line %d too long\n", lno); return 0; } strcat(buf, buf2); n = (int) strlen(buf); } if (strip_cpp_comments(&buf[on])) n = (int) strlen(buf); if (in_comment(&buf[on])) { buf[n-1] = '\0'; /* eat newline */ on = n-1; nw_lno = 1; goto feedme; } p = buf + strspn(buf, " \t"); if (nw_lno && *p != '#') fprintf(outpp, "#line %d \"%s\"\n", lno, fnm); if (*p == '#') { if (!process(p+1, lno+1, fnm)) return 0; } else if (printing[if_depth]) fprintf(outpp, "%s", apply(buf)); } fclose(inp); return 1;} inttry_zpp(char *fnm, char *onm){ int r; if ((outpp = fopen(onm, MFLAGS)) == NULL) return 0; r = zpp_do(fnm); fclose(outpp); return r; /* 1 = ok; 0 = use cpp */} static struct Directives { int len; char *directive; int (*handler)(char *); int interp;} s[] = { { 6, "define", do_define, 1 }, { 4, "else", do_else, 0 }, { 5, "endif", do_endif, 0 }, { 5, "ifdef", do_ifdef, 0 }, { 6, "ifndef", do_ifndef, 0 }, { 2, "if", do_if, 0 }, { 7, "include", do_include, 1 }, { 8, "undefine", do_undefine, 1 },}; static intprocess(char *q, int lno, char *fnm){ char *p; int i, r; for (p = q; *p; p++) if (*p != ' ' && *p != '\t') break; if (strncmp(p, "line", 4) == 0) { p += 4; while (*p == ' ' || *p == '\t') { p++; } lno = atoi(p); return 1; /* line directive */ } if (isdigit((int) *p)) { lno = atoi(p); return 1; } if (strncmp(p, "error", 5) == 0) { printf("spin: %s", p); exit(1); } if (strncmp(p, "warning", 7) == 0) { printf("spin: %s", p); return 1; } for (i = 0; i < (int) (sizeof(s)/sizeof(struct Directives)); i++) if (!strncmp(s[i].directive, p, s[i].len)) { if (s[i].interp && !printing[if_depth]) return 1; fprintf(outpp, "#line %d \"%s\"\n", lno, fnm); r = s[i].handler(p + s[i].len); if (i == 6) /* include */ fprintf(outpp, "#line %d \"%s\"\n", lno, fnm); return r; } debug("zpp: unrecognized directive: %s", p); return 0;}#endif
/***** spin: pc_zpp.c *****/
/* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories. */
/* All Rights Reserved. This software is for educational purposes only. */
/* No guarantee whatsoever is expressed or implied by the distribution of */
/* this code. Permission is given to distribute this code provided that */
/* this introductory message is not removed and no monies are exchanged. */
/* Software written by Gerard J. Holzmann. For tool documentation see: */
/* http://spinroot.com/ */
/* Send all bug-reports and/or questions to: bugs@spinroot.com */
/* pc_zpp.c is only used in the PC version of Spin */
/* it is included to avoid too great a reliance on an external cpp */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "spin.h"
#ifdef PC
enum cstate { PLAIN, IN_STRING, IN_QUOTE, S_COMM, COMMENT, E_COMM };
#define MAXNEST 32
#define MAXDEF 128
#define MAXLINE 2048
#define GENEROUS 8192
#define debug(x,y) if (verbose) printf(x,y)
static FILE *outpp /* = stdout */;
static int if_truth[MAXNEST];
static int printing[MAXNEST];
static int if_depth, nr_defs, verbose = 0;
static enum cstate state = PLAIN;
static char Out1[GENEROUS], Out2[GENEROUS];
static struct Defines {
int exists;
char *src, *trg;
} d[MAXDEF];
static int process(char *, int, char *);
static int zpp_do(char *);
extern char *emalloc(size_t); /* main.c */
static int
do_define(char *p)
{ char *q, *r, *s;
for (q = p+strlen(p)-1; q > p; q--)
if (*q == '\n' || *q == '\t' || *q == ' ')
*q = '\0';
else
break;
q = p + strspn(p, " \t");
if (!(r = strchr(q, '\t')))
r = strchr(q, ' ');
if (!r) { s = ""; goto adddef; }
s = r + strspn(r, " \t");
*r = '\0';
if (strchr(q, '('))
{ debug("zpp: #define with arguments %s\n", q);
return 0;
}
for (r = q+strlen(q)-1; r > q; r--)
if (*r == ' ' || *r == '\t')
*r = '\0';
else
break;
if (nr_defs >= MAXDEF)
{ debug("zpp: too many #defines (max %d)\n", nr_defs);
return 0;
}
if (strcmp(q, s) != 0)
{ int j;
adddef: for (j = 0; j < nr_defs; j++)
if (!strcmp(d[j].src, q))
d[j].exists = 0;
d[nr_defs].src = emalloc(strlen(q)+1);
d[nr_defs].trg = emalloc(strlen(s)+1);
strcpy(d[nr_defs].src, q);
strcpy(d[nr_defs].trg, s);
d[nr_defs++].exists = 1;
}
return 1;
}
static int
isvalid(int c)
{
return (isalnum(c) || c == '_');
}
static char *
apply(char *p0)
{ char *out, *in1, *in2, *startat;
int i, j;
startat = in1 = Out2; strcpy(Out2, p0);
out = Out1; *out = '\0';
for (i = nr_defs-1; i >= 0; i--)
{ if (!d[i].exists) continue;
j = (int) strlen(d[i].src);
more: in2 = strstr(startat, d[i].src);
if (!in2) /* no more matches */
{ startat = in1;
continue;
}
if ((in2 == in1 || !isvalid(*(in2-1)))
&& (in2+j == '\0' || !isvalid(*(in2+j))))
{ *in2 = '\0';
if (strlen(in1)+strlen(d[i].trg)+strlen(in2+j) >= GENEROUS)
{
printf("spin: macro expansion overflow %s -> %s ?\n",
d[i].src, d[i].trg);
return in1;
}
strcat(out, in1);
strcat(out, d[i].trg);
strcat(out, in2+j);
if (in1 == Out2)
{ startat = in1 = Out1;
out = Out2;
} else
{ startat = in1 = Out2;
out = Out1;
}
*out = '\0';
} else
{ startat = in2+1; /* +1 not +j.. */
}
goto more; /* recursive defines */
}
return in1;
}
static char *
do_common(char *p)
{ char *q, *s;
q = p + strspn(p, " \t");
for (s = (q + strlen(q) - 1); s > q; s--)
if (*s == ' ' || *s == '\t' || *s == '\n')
*s = '\0';
else
break;
return q;
}
static int
do_undefine(char *p)
{ int i; char *q = do_common(p);
for (i = 0; i < nr_defs; i++)
if (!strcmp(d[i].src, q))
d[i].exists = 0;
return 1;
}
static char *
check_ifdef(char *p)
{ int i; char *q = do_common(p);
for (i = 0; i < nr_defs; i++)
if (d[i].exists
&& !strcmp(d[i].src, q))
return d[i].trg;
return (char *) 0;
}
static int
do_ifdef(char *p)
{
if (++if_depth >= MAXNEST)
{ debug("zpp: too deeply nested (max %d)\n", MAXNEST);
return 0;
}
if_truth[if_depth] = (check_ifdef(p) != (char *)0);
printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
return 1;
}
static int
do_ifndef(char *p)
{
if (++if_depth >= MAXNEST)
{ debug("zpp: too deeply nested (max %d)\n", MAXNEST);
return 0;
}
if_truth[if_depth] = (check_ifdef(p) == (char *)0);
printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
return 1;
}
static int
is_simple(char *q)
{
if (!q) return 0;
if (strcmp(q, "0") == 0)
if_truth[if_depth] = 0;
else if (strcmp(q, "1") == 0)
if_truth[if_depth] = 1;
else
return 0;
return 1;
}
static int
do_if(char *p)
{ char *q = do_common(p);
if (++if_depth >= MAXNEST)
{ debug("zpp: too deeply nested (max %d)\n", MAXNEST);
return 0;
}
if (!is_simple(q)
&& !is_simple(check_ifdef(q)))
{ debug("zpp: cannot handle #if %s\n", q);
return 0;
}
printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
return 1;
}
static int
do_else(char *p)
{
debug("zpp: do_else %s", p);
if_truth[if_depth] = 1-if_truth[if_depth];
printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
return 1;
}
static int
do_endif(char *p)
{
if (--if_depth < 0)
{ debug("zpp: unbalanced #endif %s\n", p);
return 0;
}
return 1;
}
static int
do_include(char *p)
{ char *r, *q;
q = strchr(p, '<');
r = strrchr(p, '>');
if (!q || !r)
{ q = strchr (p, '\"');
r = strrchr(p, '\"');
if (!q || !r || q == r)
{ debug("zpp: malformed #include %s", p);
return 0;
} }
*r = '\0';
return zpp_do(++q);
}
static int
in_comment(char *p)
{ char *q = p;
for (q = p; *q != '\n' && *q != '\0'; q++)
switch (state) {
case PLAIN:
switch (*q) {
case '"': state = IN_STRING; break;
case '\'': state = IN_QUOTE; break;
case '/': state = S_COMM; break;
case '\\': q++; break;
}
break;
case IN_STRING:
if (*q == '"') state = PLAIN;
else if (*q == '\\') q++;
break;
case IN_QUOTE:
if (*q == '\'') state = PLAIN;
else if (*q == '\\') q++;
break;
case S_COMM:
if (*q == '*')
{ *(q-1) = *q = ' ';
state = COMMENT;
} else if (*q != '/')
state = PLAIN;
break;
case COMMENT:
state = (*q == '*') ? E_COMM: COMMENT;
*q = ' ';
break;
case E_COMM:
if (*q == '/')
state = PLAIN;
else if (*q != '*')
state = COMMENT;
*q = ' ';
break;
}
if (state == S_COMM) state = PLAIN;
else if (state == E_COMM) state = COMMENT;
return (state == COMMENT);
}
static int
strip_cpp_comments(char *p)
{ char *q;
q = strstr(p, "//");
if (q)
{ if (q > p && *(q-1) == '\\')
{ return strip_cpp_comments(q+1);
}
*q = '\n';
*(q+1) = '\0';
return 1;
}
return 0;
}
static int
zpp_do(char *fnm)
{ char buf[2048], buf2[MAXLINE], *p; int n, on;
FILE *inp; int lno = 0, nw_lno = 0;
if ((inp = fopen(fnm, "r")) == NULL)
{ fprintf(stdout, "spin: error: No file '%s'\n", fnm);
exit(1); /* 4.1.2 was stderr */
}
printing[0] = if_truth[0] = 1;
fprintf(outpp, "#line %d \"%s\"\n", lno+1, fnm);
while (fgets(buf, MAXLINE, inp))
{ lno++; n = (int) strlen(buf);
on = 0; nw_lno = 0;
while (n > 2 && buf[n-2] == '\\')
{ buf[n-2] = '\0';
feedme:
if (!fgets(buf2, MAXLINE, inp))
{ debug("zpp: unexpected EOF ln %d\n", lno);
return 0; /* switch to cpp */
}
lno++;
if (n + (int) strlen(buf2) >= 2048)
{ debug("zpp: line %d too long\n", lno);
return 0;
}
strcat(buf, buf2);
n = (int) strlen(buf);
}
if (strip_cpp_comments(&buf[on]))
n = (int) strlen(buf);
if (in_comment(&buf[on]))
{ buf[n-1] = '\0'; /* eat newline */
on = n-1; nw_lno = 1;
goto feedme;
}
p = buf + strspn(buf, " \t");
if (nw_lno && *p != '#')
fprintf(outpp, "#line %d \"%s\"\n", lno, fnm);
if (*p == '#')
{ if (!process(p+1, lno+1, fnm))
return 0;
} else if (printing[if_depth])
fprintf(outpp, "%s", apply(buf));
}
fclose(inp);
return 1;
}
int
try_zpp(char *fnm, char *onm)
{ int r;
if ((outpp = fopen(onm, MFLAGS)) == NULL)
return 0;
r = zpp_do(fnm);
fclose(outpp);
return r; /* 1 = ok; 0 = use cpp */
}
static struct Directives {
int len;
char *directive;
int (*handler)(char *);
int interp;
} s[] = {
{ 6, "define", do_define, 1 },
{ 4, "else", do_else, 0 },
{ 5, "endif", do_endif, 0 },
{ 5, "ifdef", do_ifdef, 0 },
{ 6, "ifndef", do_ifndef, 0 },
{ 2, "if", do_if, 0 },
{ 7, "include", do_include, 1 },
{ 8, "undefine", do_undefine, 1 },
};
static int
process(char *q, int lno, char *fnm)
{ char *p; int i, r;
for (p = q; *p; p++)
if (*p != ' ' && *p != '\t')
break;
if (strncmp(p, "line", 4) == 0)
{ p += 4;
while (*p == ' ' || *p == '\t')
{ p++;
}
lno = atoi(p);
return 1; /* line directive */
}
if (isdigit((int) *p))
{ lno = atoi(p);
return 1;
}
if (strncmp(p, "error", 5) == 0)
{ printf("spin: %s", p);
exit(1);
}
if (strncmp(p, "warning", 7) == 0)
{ printf("spin: %s", p);
return 1;
}
for (i = 0; i < (int) (sizeof(s)/sizeof(struct Directives)); i++)
if (!strncmp(s[i].directive, p, s[i].len))
{ if (s[i].interp
&& !printing[if_depth])
return 1;
fprintf(outpp, "#line %d \"%s\"\n", lno, fnm);
r = s[i].handler(p + s[i].len);
if (i == 6) /* include */
fprintf(outpp, "#line %d \"%s\"\n", lno, fnm);
return r;
}
debug("zpp: unrecognized directive: %s", p);
return 0;
}
#endif