summaryrefslogtreecommitdiff
path: root/sys/src/cmd/spin/pc_zpp.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/spin/pc_zpp.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/spin/pc_zpp.c')
-rwxr-xr-xsys/src/cmd/spin/pc_zpp.c408
1 files changed, 408 insertions, 0 deletions
diff --git a/sys/src/cmd/spin/pc_zpp.c b/sys/src/cmd/spin/pc_zpp.c
new file mode 100755
index 000000000..5d2a69b15
--- /dev/null
+++ b/sys/src/cmd/spin/pc_zpp.c
@@ -0,0 +1,408 @@
+/***** 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>
+
+#ifdef PC
+enum cstate { PLAIN, IN_STRING, IN_QUOTE, S_COMM, COMMENT, E_COMM };
+
+#define MAXNEST 32
+#define MAXDEF 128
+#define MAXLINE 512
+#define GENEROUS 4096
+
+#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(int); /* 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: circular macro expansion %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 *unused)
+{
+ 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
+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, '%s': No such file\n", fnm);
+ return 0; /* 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 (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, "w")) == 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;
+ 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