summaryrefslogtreecommitdiff
path: root/sys/src/cmd/spin
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
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/spin')
-rwxr-xr-xsys/src/cmd/spin/README11
-rwxr-xr-xsys/src/cmd/spin/dstep.c411
-rwxr-xr-xsys/src/cmd/spin/flow.c794
-rwxr-xr-xsys/src/cmd/spin/guided.c313
-rwxr-xr-xsys/src/cmd/spin/main.c778
-rwxr-xr-xsys/src/cmd/spin/mesg.c644
-rwxr-xr-xsys/src/cmd/spin/mkfile56
-rwxr-xr-xsys/src/cmd/spin/pangen1.c1275
-rwxr-xr-xsys/src/cmd/spin/pangen1.h5139
-rwxr-xr-xsys/src/cmd/spin/pangen2.c2996
-rwxr-xr-xsys/src/cmd/spin/pangen2.h858
-rwxr-xr-xsys/src/cmd/spin/pangen3.c391
-rwxr-xr-xsys/src/cmd/spin/pangen3.h940
-rwxr-xr-xsys/src/cmd/spin/pangen4.c344
-rwxr-xr-xsys/src/cmd/spin/pangen4.h727
-rwxr-xr-xsys/src/cmd/spin/pangen5.c857
-rwxr-xr-xsys/src/cmd/spin/pangen5.h424
-rwxr-xr-xsys/src/cmd/spin/pangen6.c2352
-rwxr-xr-xsys/src/cmd/spin/pc_zpp.c408
-rwxr-xr-xsys/src/cmd/spin/ps_msc.c448
-rwxr-xr-xsys/src/cmd/spin/reprosrc.c136
-rwxr-xr-xsys/src/cmd/spin/run.c602
-rwxr-xr-xsys/src/cmd/spin/sched.c1025
-rwxr-xr-xsys/src/cmd/spin/spin.h399
-rwxr-xr-xsys/src/cmd/spin/spin.y722
-rwxr-xr-xsys/src/cmd/spin/spinlex.c1384
-rwxr-xr-xsys/src/cmd/spin/structs.c659
-rwxr-xr-xsys/src/cmd/spin/sym.c534
-rwxr-xr-xsys/src/cmd/spin/tl.h128
-rwxr-xr-xsys/src/cmd/spin/tl_buchi.c666
-rwxr-xr-xsys/src/cmd/spin/tl_cache.c328
-rwxr-xr-xsys/src/cmd/spin/tl_lex.c148
-rwxr-xr-xsys/src/cmd/spin/tl_main.c234
-rwxr-xr-xsys/src/cmd/spin/tl_mem.c120
-rwxr-xr-xsys/src/cmd/spin/tl_parse.c400
-rwxr-xr-xsys/src/cmd/spin/tl_rewrt.c301
-rwxr-xr-xsys/src/cmd/spin/tl_trans.c875
-rwxr-xr-xsys/src/cmd/spin/vars.c347
-rwxr-xr-xsys/src/cmd/spin/version.h1
39 files changed, 29175 insertions, 0 deletions
diff --git a/sys/src/cmd/spin/README b/sys/src/cmd/spin/README
new file mode 100755
index 000000000..5e419923e
--- /dev/null
+++ b/sys/src/cmd/spin/README
@@ -0,0 +1,11 @@
+the latest version of spin is always
+available via:
+ http://spinroot.com/spin/whatispin.html
+
+to make the sources compile with the mkfile on Plan 9
+the following changes were made:
+
+ omitted memory.h from spin.h
+ changed /lib/cpp to /bin/cpp in main.c
+ simplified non_fatal() in main.c to remove
+ use of yychar
diff --git a/sys/src/cmd/spin/dstep.c b/sys/src/cmd/spin/dstep.c
new file mode 100755
index 000000000..f24860309
--- /dev/null
+++ b/sys/src/cmd/spin/dstep.c
@@ -0,0 +1,411 @@
+/***** spin: dstep.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include "spin.h"
+#include "y.tab.h"
+
+#define MAXDSTEP 1024 /* was 512 */
+
+char *NextLab[64];
+int Level=0, GenCode=0, IsGuard=0, TestOnly=0;
+
+static int Tj=0, Jt=0, LastGoto=0;
+static int Tojump[MAXDSTEP], Jumpto[MAXDSTEP], Special[MAXDSTEP];
+static void putCode(FILE *, Element *, Element *, Element *, int);
+
+extern int Pid, claimnr, separate, OkBreak;
+
+static void
+Sourced(int n, int special)
+{ int i;
+ for (i = 0; i < Tj; i++)
+ if (Tojump[i] == n)
+ return;
+ if (Tj >= MAXDSTEP)
+ fatal("d_step sequence too long", (char *)0);
+ Special[Tj] = special;
+ Tojump[Tj++] = n;
+}
+
+static void
+Dested(int n)
+{ int i;
+ for (i = 0; i < Tj; i++)
+ if (Tojump[i] == n)
+ return;
+ for (i = 0; i < Jt; i++)
+ if (Jumpto[i] == n)
+ return;
+ if (Jt >= MAXDSTEP)
+ fatal("d_step sequence too long", (char *)0);
+ Jumpto[Jt++] = n;
+ LastGoto = 1;
+}
+
+static void
+Mopup(FILE *fd)
+{ int i, j;
+
+ for (i = 0; i < Jt; i++)
+ { for (j = 0; j < Tj; j++)
+ if (Tojump[j] == Jumpto[i])
+ break;
+ if (j == Tj)
+ { char buf[12];
+ if (Jumpto[i] == OkBreak)
+ { if (!LastGoto)
+ fprintf(fd, "S_%.3d_0: /* break-dest */\n",
+ OkBreak);
+ } else {
+ sprintf(buf, "S_%.3d_0", Jumpto[i]);
+ non_fatal("goto %s breaks from d_step seq", buf);
+ } } }
+ for (j = 0; j < Tj; j++)
+ { for (i = 0; i < Jt; i++)
+ if (Tojump[j] == Jumpto[i])
+ break;
+#ifdef DEBUG
+ if (i == Jt && !Special[i])
+ fprintf(fd, "\t\t/* no goto's to S_%.3d_0 */\n",
+ Tojump[j]);
+#endif
+ }
+ for (j = i = 0; j < Tj; j++)
+ if (Special[j])
+ { Tojump[i] = Tojump[j];
+ Special[i] = 2;
+ if (i >= MAXDSTEP)
+ fatal("cannot happen (dstep.c)", (char *)0);
+ i++;
+ }
+ Tj = i; /* keep only the global exit-labels */
+ Jt = 0;
+}
+
+static int
+FirstTime(int n)
+{ int i;
+ for (i = 0; i < Tj; i++)
+ if (Tojump[i] == n)
+ return (Special[i] <= 1);
+ return 1;
+}
+
+static void
+illegal(Element *e, char *str)
+{
+ printf("illegal operator in 'd_step:' '");
+ comment(stdout, e->n, 0);
+ printf("'\n");
+ fatal("'%s'", str);
+}
+
+static void
+filterbad(Element *e)
+{
+ switch (e->n->ntyp) {
+ case ASSERT:
+ case PRINT:
+ case 'c':
+ /* run cannot be completely undone
+ * with sv_save-sv_restor
+ */
+ if (any_oper(e->n->lft, RUN))
+ illegal(e, "run operator in d_step");
+
+ /* remote refs inside d_step sequences
+ * would be okay, but they cannot always
+ * be interpreted by the simulator the
+ * same as by the verifier (e.g., for an
+ * error trail)
+ */
+ if (any_oper(e->n->lft, 'p'))
+ illegal(e, "remote reference in d_step");
+ break;
+ case '@':
+ illegal(e, "process termination");
+ break;
+ case D_STEP:
+ illegal(e, "nested d_step sequence");
+ break;
+ case ATOMIC:
+ illegal(e, "nested atomic sequence");
+ break;
+ default:
+ break;
+ }
+}
+
+static int
+CollectGuards(FILE *fd, Element *e, int inh)
+{ SeqList *h; Element *ee;
+
+ for (h = e->sub; h; h = h->nxt)
+ { ee = huntstart(h->this->frst);
+ filterbad(ee);
+ switch (ee->n->ntyp) {
+ case NON_ATOMIC:
+ inh += CollectGuards(fd, ee->n->sl->this->frst, inh);
+ break;
+ case IF:
+ inh += CollectGuards(fd, ee, inh);
+ break;
+ case '.':
+ if (ee->nxt->n->ntyp == DO)
+ inh += CollectGuards(fd, ee->nxt, inh);
+ break;
+ case ELSE:
+ if (inh++ > 0) fprintf(fd, " || ");
+/* 4.2.5 */ if (Pid != claimnr)
+ fprintf(fd, "(boq == -1 /* else */)");
+ else
+ fprintf(fd, "(1 /* else */)");
+ break;
+ case 'R':
+ if (inh++ > 0) fprintf(fd, " || ");
+ fprintf(fd, "("); TestOnly=1;
+ putstmnt(fd, ee->n, ee->seqno);
+ fprintf(fd, ")"); TestOnly=0;
+ break;
+ case 'r':
+ if (inh++ > 0) fprintf(fd, " || ");
+ fprintf(fd, "("); TestOnly=1;
+ putstmnt(fd, ee->n, ee->seqno);
+ fprintf(fd, ")"); TestOnly=0;
+ break;
+ case 's':
+ if (inh++ > 0) fprintf(fd, " || ");
+ fprintf(fd, "("); TestOnly=1;
+/* 4.2.1 */ if (Pid != claimnr) fprintf(fd, "(boq == -1) && ");
+ putstmnt(fd, ee->n, ee->seqno);
+ fprintf(fd, ")"); TestOnly=0;
+ break;
+ case 'c':
+ if (inh++ > 0) fprintf(fd, " || ");
+ fprintf(fd, "("); TestOnly=1;
+ if (Pid != claimnr)
+ fprintf(fd, "(boq == -1 && ");
+ putstmnt(fd, ee->n->lft, e->seqno);
+ if (Pid != claimnr)
+ fprintf(fd, ")");
+ fprintf(fd, ")"); TestOnly=0;
+ break;
+ } }
+ return inh;
+}
+
+int
+putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno)
+{ int isg=0; char buf[64];
+
+ NextLab[0] = "continue";
+ filterbad(s->frst);
+
+ switch (s->frst->n->ntyp) {
+ case UNLESS:
+ non_fatal("'unless' inside d_step - ignored", (char *) 0);
+ return putcode(fd, s->frst->n->sl->this, nxt, 0, ln, seqno);
+ case NON_ATOMIC:
+ (void) putcode(fd, s->frst->n->sl->this, ZE, 1, ln, seqno);
+ break;
+ case IF:
+ fprintf(fd, "if (!(");
+ if (!CollectGuards(fd, s->frst, 0)) /* what about boq? */
+ fprintf(fd, "1");
+ fprintf(fd, "))\n\t\t\tcontinue;");
+ isg = 1;
+ break;
+ case '.':
+ if (s->frst->nxt->n->ntyp == DO)
+ { fprintf(fd, "if (!(");
+ if (!CollectGuards(fd, s->frst->nxt, 0))
+ fprintf(fd, "1");
+ fprintf(fd, "))\n\t\t\tcontinue;");
+ isg = 1;
+ }
+ break;
+ case 'R': /* <- can't really happen (it's part of a 'c') */
+ fprintf(fd, "if (!("); TestOnly=1;
+ putstmnt(fd, s->frst->n, s->frst->seqno);
+ fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
+ break;
+ case 'r':
+ fprintf(fd, "if (!("); TestOnly=1;
+ putstmnt(fd, s->frst->n, s->frst->seqno);
+ fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
+ break;
+ case 's':
+ fprintf(fd, "if (");
+#if 1
+/* 4.2.1 */ if (Pid != claimnr) fprintf(fd, "(boq != -1) || ");
+#endif
+ fprintf(fd, "!("); TestOnly=1;
+ putstmnt(fd, s->frst->n, s->frst->seqno);
+ fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
+ break;
+ case 'c':
+ fprintf(fd, "if (!(");
+ if (Pid != claimnr) fprintf(fd, "boq == -1 && ");
+ TestOnly=1;
+ putstmnt(fd, s->frst->n->lft, s->frst->seqno);
+ fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
+ break;
+ case ELSE:
+ fprintf(fd, "if (boq != -1 || (");
+ if (separate != 2) fprintf(fd, "trpt->");
+ fprintf(fd, "o_pm&1))\n\t\t\tcontinue;");
+ break;
+ case ASGN: /* new 3.0.8 */
+ fprintf(fd, "IfNotBlocked");
+ break;
+ }
+ if (justguards) return 0;
+
+ fprintf(fd, "\n\t\tsv_save();\n\t\t");
+#if 1
+ fprintf(fd, "reached[%d][%d] = 1;\n\t\t", Pid, seqno);
+ fprintf(fd, "reached[%d][t->st] = 1;\n\t\t", Pid); /* true next state */
+ fprintf(fd, "reached[%d][tt] = 1;\n", Pid); /* true current state */
+#endif
+ sprintf(buf, "Uerror(\"block in d_step seq, line %d\")", ln);
+ NextLab[0] = buf;
+ putCode(fd, s->frst, s->extent, nxt, isg);
+
+ if (nxt)
+ { extern Symbol *Fname;
+ extern int lineno;
+
+ if (FirstTime(nxt->Seqno)
+ && (!(nxt->status & DONE2) || !(nxt->status & D_ATOM)))
+ { fprintf(fd, "S_%.3d_0: /* 1 */\n", nxt->Seqno);
+ nxt->status |= DONE2;
+ LastGoto = 0;
+ }
+ Sourced(nxt->Seqno, 1);
+ lineno = ln;
+ Fname = nxt->n->fn;
+ Mopup(fd);
+ }
+ unskip(s->frst->seqno);
+ return LastGoto;
+}
+
+static void
+putCode(FILE *fd, Element *f, Element *last, Element *next, int isguard)
+{ Element *e, *N;
+ SeqList *h; int i;
+ char NextOpt[64];
+ static int bno = 0;
+
+ for (e = f; e; e = e->nxt)
+ { if (e->status & DONE2)
+ continue;
+ e->status |= DONE2;
+
+ if (!(e->status & D_ATOM))
+ { if (!LastGoto)
+ { fprintf(fd, "\t\tgoto S_%.3d_0;\n",
+ e->Seqno);
+ Dested(e->Seqno);
+ }
+ break;
+ }
+ fprintf(fd, "S_%.3d_0: /* 2 */\n", e->Seqno);
+ LastGoto = 0;
+ Sourced(e->Seqno, 0);
+
+ if (!e->sub)
+ { filterbad(e);
+ switch (e->n->ntyp) {
+ case NON_ATOMIC:
+ h = e->n->sl;
+ putCode(fd, h->this->frst,
+ h->this->extent, e->nxt, 0);
+ break;
+ case BREAK:
+ if (LastGoto) break;
+ if (e->nxt)
+ { i = target( huntele(e->nxt,
+ e->status, -1))->Seqno;
+ fprintf(fd, "\t\tgoto S_%.3d_0; ", i);
+ fprintf(fd, "/* 'break' */\n");
+ Dested(i);
+ } else
+ { if (next)
+ { fprintf(fd, "\t\tgoto S_%.3d_0;",
+ next->Seqno);
+ fprintf(fd, " /* NEXT */\n");
+ Dested(next->Seqno);
+ } else
+ fatal("cannot interpret d_step", 0);
+ }
+ break;
+ case GOTO:
+ if (LastGoto) break;
+ i = huntele( get_lab(e->n,1),
+ e->status, -1)->Seqno;
+ fprintf(fd, "\t\tgoto S_%.3d_0; ", i);
+ fprintf(fd, "/* 'goto' */\n");
+ Dested(i);
+ break;
+ case '.':
+ if (LastGoto) break;
+ if (e->nxt && (e->nxt->status & DONE2))
+ { i = e->nxt?e->nxt->Seqno:0;
+ fprintf(fd, "\t\tgoto S_%.3d_0;", i);
+ fprintf(fd, " /* '.' */\n");
+ Dested(i);
+ }
+ break;
+ default:
+ putskip(e->seqno);
+ GenCode = 1; IsGuard = isguard;
+ fprintf(fd, "\t\t");
+ putstmnt(fd, e->n, e->seqno);
+ fprintf(fd, ";\n");
+ GenCode = IsGuard = isguard = LastGoto = 0;
+ break;
+ }
+ i = e->nxt?e->nxt->Seqno:0;
+ if (e->nxt && e->nxt->status & DONE2 && !LastGoto)
+ { fprintf(fd, "\t\tgoto S_%.3d_0; ", i);
+ fprintf(fd, "/* ';' */\n");
+ Dested(i);
+ break;
+ }
+ } else
+ { for (h = e->sub, i=1; h; h = h->nxt, i++)
+ { sprintf(NextOpt, "goto S_%.3d_%d",
+ e->Seqno, i);
+ NextLab[++Level] = NextOpt;
+ N = (e->n && e->n->ntyp == DO) ? e : e->nxt;
+ putCode(fd, h->this->frst,
+ h->this->extent, N, 1);
+ Level--;
+ fprintf(fd, "%s: /* 3 */\n", &NextOpt[5]);
+ LastGoto = 0;
+ }
+ if (!LastGoto)
+ { fprintf(fd, "\t\tUerror(\"blocking sel ");
+ fprintf(fd, "in d_step (nr.%d, near line %d)\");\n",
+ bno++, (e->n)?e->n->ln:0);
+ LastGoto = 0;
+ }
+ }
+ if (e == last)
+ { if (!LastGoto && next)
+ { fprintf(fd, "\t\tgoto S_%.3d_0;\n",
+ next->Seqno);
+ Dested(next->Seqno);
+ }
+ break;
+ } }
+}
diff --git a/sys/src/cmd/spin/flow.c b/sys/src/cmd/spin/flow.c
new file mode 100755
index 000000000..ac3e4e4b6
--- /dev/null
+++ b/sys/src/cmd/spin/flow.c
@@ -0,0 +1,794 @@
+/***** spin: flow.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include "spin.h"
+#include "y.tab.h"
+
+extern Symbol *Fname;
+extern int nr_errs, lineno, verbose;
+extern short has_unless, has_badelse;
+
+Element *Al_El = ZE;
+Label *labtab = (Label *) 0;
+int Unique=0, Elcnt=0, DstepStart = -1;
+
+static Lbreak *breakstack = (Lbreak *) 0;
+static Lextok *innermost;
+static SeqList *cur_s = (SeqList *) 0;
+static int break_id=0;
+
+static Element *if_seq(Lextok *);
+static Element *new_el(Lextok *);
+static Element *unless_seq(Lextok *);
+static void add_el(Element *, Sequence *);
+static void attach_escape(Sequence *, Sequence *);
+static void mov_lab(Symbol *, Element *, Element *);
+static void walk_atomic(Element *, Element *, int);
+
+void
+open_seq(int top)
+{ SeqList *t;
+ Sequence *s = (Sequence *) emalloc(sizeof(Sequence));
+
+ t = seqlist(s, cur_s);
+ cur_s = t;
+ if (top) Elcnt = 1;
+}
+
+void
+rem_Seq(void)
+{
+ DstepStart = Unique;
+}
+
+void
+unrem_Seq(void)
+{
+ DstepStart = -1;
+}
+
+static int
+Rjumpslocal(Element *q, Element *stop)
+{ Element *lb, *f;
+ SeqList *h;
+
+ /* allow no jumps out of a d_step sequence */
+ for (f = q; f && f != stop; f = f->nxt)
+ { if (f && f->n && f->n->ntyp == GOTO)
+ { lb = get_lab(f->n, 0);
+ if (!lb || lb->Seqno < DstepStart)
+ { lineno = f->n->ln;
+ Fname = f->n->fn;
+ return 0;
+ } }
+ for (h = f->sub; h; h = h->nxt)
+ { if (!Rjumpslocal(h->this->frst, h->this->last))
+ return 0;
+
+ } }
+ return 1;
+}
+
+void
+cross_dsteps(Lextok *a, Lextok *b)
+{
+ if (a && b
+ && a->indstep != b->indstep)
+ { lineno = a->ln;
+ Fname = a->fn;
+ fatal("jump into d_step sequence", (char *) 0);
+ }
+}
+
+int
+is_skip(Lextok *n)
+{
+ return (n->ntyp == PRINT
+ || n->ntyp == PRINTM
+ || (n->ntyp == 'c'
+ && n->lft
+ && n->lft->ntyp == CONST
+ && n->lft->val == 1));
+}
+
+void
+check_sequence(Sequence *s)
+{ Element *e, *le = ZE;
+ Lextok *n;
+ int cnt = 0;
+
+ for (e = s->frst; e; le = e, e = e->nxt)
+ { n = e->n;
+ if (is_skip(n) && !has_lab(e, 0))
+ { cnt++;
+ if (cnt > 1
+ && n->ntyp != PRINT
+ && n->ntyp != PRINTM)
+ { if (verbose&32)
+ printf("spin: line %d %s, redundant skip\n",
+ n->ln, n->fn->name);
+ if (e != s->frst
+ && e != s->last
+ && e != s->extent)
+ { e->status |= DONE; /* not unreachable */
+ le->nxt = e->nxt; /* remove it */
+ e = le;
+ }
+ }
+ } else
+ cnt = 0;
+ }
+}
+
+void
+prune_opts(Lextok *n)
+{ SeqList *l;
+ extern Symbol *context;
+ extern char *claimproc;
+
+ if (!n
+ || (context && claimproc && strcmp(context->name, claimproc) == 0))
+ return;
+
+ for (l = n->sl; l; l = l->nxt) /* find sequences of unlabeled skips */
+ check_sequence(l->this);
+}
+
+Sequence *
+close_seq(int nottop)
+{ Sequence *s = cur_s->this;
+ Symbol *z;
+
+ if (nottop > 0 && (z = has_lab(s->frst, 0)))
+ { printf("error: (%s:%d) label %s placed incorrectly\n",
+ (s->frst->n)?s->frst->n->fn->name:"-",
+ (s->frst->n)?s->frst->n->ln:0,
+ z->name);
+ switch (nottop) {
+ case 1:
+ printf("=====> stmnt unless Label: stmnt\n");
+ printf("sorry, cannot jump to the guard of an\n");
+ printf("escape (it is not a unique state)\n");
+ break;
+ case 2:
+ printf("=====> instead of ");
+ printf("\"Label: stmnt unless stmnt\"\n");
+ printf("=====> always use ");
+ printf("\"Label: { stmnt unless stmnt }\"\n");
+ break;
+ case 3:
+ printf("=====> instead of ");
+ printf("\"atomic { Label: statement ... }\"\n");
+ printf("=====> always use ");
+ printf("\"Label: atomic { statement ... }\"\n");
+ break;
+ case 4:
+ printf("=====> instead of ");
+ printf("\"d_step { Label: statement ... }\"\n");
+ printf("=====> always use ");
+ printf("\"Label: d_step { statement ... }\"\n");
+ break;
+ case 5:
+ printf("=====> instead of ");
+ printf("\"{ Label: statement ... }\"\n");
+ printf("=====> always use ");
+ printf("\"Label: { statement ... }\"\n");
+ break;
+ case 6:
+ printf("=====>instead of\n");
+ printf(" do (or if)\n");
+ printf(" :: ...\n");
+ printf(" :: Label: statement\n");
+ printf(" od (of fi)\n");
+ printf("=====>always use\n");
+ printf("Label: do (or if)\n");
+ printf(" :: ...\n");
+ printf(" :: statement\n");
+ printf(" od (or fi)\n");
+ break;
+ case 7:
+ printf("cannot happen - labels\n");
+ break;
+ }
+ alldone(1);
+ }
+
+ if (nottop == 4
+ && !Rjumpslocal(s->frst, s->last))
+ fatal("non_local jump in d_step sequence", (char *) 0);
+
+ cur_s = cur_s->nxt;
+ s->maxel = Elcnt;
+ s->extent = s->last;
+ if (!s->last)
+ fatal("sequence must have at least one statement", (char *) 0);
+ return s;
+}
+
+Lextok *
+do_unless(Lextok *No, Lextok *Es)
+{ SeqList *Sl;
+ Lextok *Re = nn(ZN, UNLESS, ZN, ZN);
+ Re->ln = No->ln;
+ Re->fn = No->fn;
+
+ has_unless++;
+ if (Es->ntyp == NON_ATOMIC)
+ Sl = Es->sl;
+ else
+ { open_seq(0); add_seq(Es);
+ Sl = seqlist(close_seq(1), 0);
+ }
+
+ if (No->ntyp == NON_ATOMIC)
+ { No->sl->nxt = Sl;
+ Sl = No->sl;
+ } else if (No->ntyp == ':'
+ && (No->lft->ntyp == NON_ATOMIC
+ || No->lft->ntyp == ATOMIC
+ || No->lft->ntyp == D_STEP))
+ {
+ int tok = No->lft->ntyp;
+
+ No->lft->sl->nxt = Sl;
+ Re->sl = No->lft->sl;
+
+ open_seq(0); add_seq(Re);
+ Re = nn(ZN, tok, ZN, ZN);
+ Re->sl = seqlist(close_seq(7), 0);
+ Re->ln = No->ln;
+ Re->fn = No->fn;
+
+ Re = nn(No, ':', Re, ZN); /* lift label */
+ Re->ln = No->ln;
+ Re->fn = No->fn;
+ return Re;
+ } else
+ { open_seq(0); add_seq(No);
+ Sl = seqlist(close_seq(2), Sl);
+ }
+
+ Re->sl = Sl;
+ return Re;
+}
+
+SeqList *
+seqlist(Sequence *s, SeqList *r)
+{ SeqList *t = (SeqList *) emalloc(sizeof(SeqList));
+
+ t->this = s;
+ t->nxt = r;
+ return t;
+}
+
+static Element *
+new_el(Lextok *n)
+{ Element *m;
+
+ if (n)
+ { if (n->ntyp == IF || n->ntyp == DO)
+ return if_seq(n);
+ if (n->ntyp == UNLESS)
+ return unless_seq(n);
+ }
+ m = (Element *) emalloc(sizeof(Element));
+ m->n = n;
+ m->seqno = Elcnt++;
+ m->Seqno = Unique++;
+ m->Nxt = Al_El; Al_El = m;
+ return m;
+}
+
+static int
+has_chanref(Lextok *n)
+{
+ if (!n) return 0;
+
+ switch (n->ntyp) {
+ case 's': case 'r':
+#if 0
+ case 'R': case LEN:
+#endif
+ case FULL: case NFULL:
+ case EMPTY: case NEMPTY:
+ return 1;
+ default:
+ break;
+ }
+ if (has_chanref(n->lft))
+ return 1;
+
+ return has_chanref(n->rgt);
+}
+
+void
+loose_ends(void) /* properly tie-up ends of sub-sequences */
+{ Element *e, *f;
+
+ for (e = Al_El; e; e = e->Nxt)
+ { if (!e->n
+ || !e->nxt)
+ continue;
+ switch (e->n->ntyp) {
+ case ATOMIC:
+ case NON_ATOMIC:
+ case D_STEP:
+ f = e->nxt;
+ while (f && f->n->ntyp == '.')
+ f = f->nxt;
+ if (0) printf("link %d, {%d .. %d} -> %d (ntyp=%d) was %d\n",
+ e->seqno,
+ e->n->sl->this->frst->seqno,
+ e->n->sl->this->last->seqno,
+ f?f->seqno:-1, f?f->n->ntyp:-1,
+ e->n->sl->this->last->nxt?e->n->sl->this->last->nxt->seqno:-1);
+ if (!e->n->sl->this->last->nxt)
+ e->n->sl->this->last->nxt = f;
+ else
+ { if (e->n->sl->this->last->nxt->n->ntyp != GOTO)
+ { if (!f || e->n->sl->this->last->nxt->seqno != f->seqno)
+ non_fatal("unexpected: loose ends", (char *)0);
+ } else
+ e->n->sl->this->last = e->n->sl->this->last->nxt;
+ /*
+ * fix_dest can push a goto into the nxt position
+ * in that case the goto wins and f is not needed
+ * but the last fields needs adjusting
+ */
+ }
+ break;
+ } }
+}
+
+static Element *
+if_seq(Lextok *n)
+{ int tok = n->ntyp;
+ SeqList *s = n->sl;
+ Element *e = new_el(ZN);
+ Element *t = new_el(nn(ZN,'.',ZN,ZN)); /* target */
+ SeqList *z, *prev_z = (SeqList *) 0;
+ SeqList *move_else = (SeqList *) 0; /* to end of optionlist */
+ int ref_chans = 0;
+
+ for (z = s; z; z = z->nxt)
+ { if (!z->this->frst)
+ continue;
+ if (z->this->frst->n->ntyp == ELSE)
+ { if (move_else)
+ fatal("duplicate `else'", (char *) 0);
+ if (z->nxt) /* is not already at the end */
+ { move_else = z;
+ if (prev_z)
+ prev_z->nxt = z->nxt;
+ else
+ s = n->sl = z->nxt;
+ continue;
+ }
+ } else
+ ref_chans |= has_chanref(z->this->frst->n);
+ prev_z = z;
+ }
+ if (move_else)
+ { move_else->nxt = (SeqList *) 0;
+ /* if there is no prev, then else was at the end */
+ if (!prev_z) fatal("cannot happen - if_seq", (char *) 0);
+ prev_z->nxt = move_else;
+ prev_z = move_else;
+ }
+ if (prev_z
+ && ref_chans
+ && prev_z->this->frst->n->ntyp == ELSE)
+ { prev_z->this->frst->n->val = 1;
+ has_badelse++;
+ non_fatal("dubious use of 'else' combined with i/o,",
+ (char *)0);
+ nr_errs--;
+ }
+
+ e->n = nn(n, tok, ZN, ZN);
+ e->n->sl = s; /* preserve as info only */
+ e->sub = s;
+ for (z = s; z; prev_z = z, z = z->nxt)
+ add_el(t, z->this); /* append target */
+ if (tok == DO)
+ { add_el(t, cur_s->this); /* target upfront */
+ t = new_el(nn(n, BREAK, ZN, ZN)); /* break target */
+ set_lab(break_dest(), t); /* new exit */
+ breakstack = breakstack->nxt; /* pop stack */
+ }
+ add_el(e, cur_s->this);
+ add_el(t, cur_s->this);
+ return e; /* destination node for label */
+}
+
+static void
+escape_el(Element *f, Sequence *e)
+{ SeqList *z;
+
+ for (z = f->esc; z; z = z->nxt)
+ if (z->this == e)
+ return; /* already there */
+
+ /* cover the lower-level escapes of this state */
+ for (z = f->esc; z; z = z->nxt)
+ attach_escape(z->this, e);
+
+ /* now attach escape to the state itself */
+
+ f->esc = seqlist(e, f->esc); /* in lifo order... */
+#ifdef DEBUG
+ printf("attach %d (", e->frst->Seqno);
+ comment(stdout, e->frst->n, 0);
+ printf(") to %d (", f->Seqno);
+ comment(stdout, f->n, 0);
+ printf(")\n");
+#endif
+ switch (f->n->ntyp) {
+ case UNLESS:
+ attach_escape(f->sub->this, e);
+ break;
+ case IF:
+ case DO:
+ for (z = f->sub; z; z = z->nxt)
+ attach_escape(z->this, e);
+ break;
+ case D_STEP:
+ /* attach only to the guard stmnt */
+ escape_el(f->n->sl->this->frst, e);
+ break;
+ case ATOMIC:
+ case NON_ATOMIC:
+ /* attach to all stmnts */
+ attach_escape(f->n->sl->this, e);
+ break;
+ }
+}
+
+static void
+attach_escape(Sequence *n, Sequence *e)
+{ Element *f;
+
+ for (f = n->frst; f; f = f->nxt)
+ { escape_el(f, e);
+ if (f == n->extent)
+ break;
+ }
+}
+
+static Element *
+unless_seq(Lextok *n)
+{ SeqList *s = n->sl;
+ Element *e = new_el(ZN);
+ Element *t = new_el(nn(ZN,'.',ZN,ZN)); /* target */
+ SeqList *z;
+
+ e->n = nn(n, UNLESS, ZN, ZN);
+ e->n->sl = s; /* info only */
+ e->sub = s;
+
+ /* need 2 sequences: normal execution and escape */
+ if (!s || !s->nxt || s->nxt->nxt)
+ fatal("unexpected unless structure", (char *)0);
+
+ /* append the target state to both */
+ for (z = s; z; z = z->nxt)
+ add_el(t, z->this);
+
+ /* attach escapes to all states in normal sequence */
+ attach_escape(s->this, s->nxt->this);
+
+ add_el(e, cur_s->this);
+ add_el(t, cur_s->this);
+#ifdef DEBUG
+ printf("unless element (%d,%d):\n", e->Seqno, t->Seqno);
+ for (z = s; z; z = z->nxt)
+ { Element *x; printf("\t%d,%d,%d :: ",
+ z->this->frst->Seqno,
+ z->this->extent->Seqno,
+ z->this->last->Seqno);
+ for (x = z->this->frst; x; x = x->nxt)
+ printf("(%d)", x->Seqno);
+ printf("\n");
+ }
+#endif
+ return e;
+}
+
+Element *
+mk_skip(void)
+{ Lextok *t = nn(ZN, CONST, ZN, ZN);
+ t->val = 1;
+ return new_el(nn(ZN, 'c', t, ZN));
+}
+
+static void
+add_el(Element *e, Sequence *s)
+{
+ if (e->n->ntyp == GOTO)
+ { Symbol *z = has_lab(e, (1|2|4));
+ if (z)
+ { Element *y; /* insert a skip */
+ y = mk_skip();
+ mov_lab(z, e, y); /* inherit label */
+ add_el(y, s);
+ } }
+#ifdef DEBUG
+ printf("add_el %d after %d -- ",
+ e->Seqno, (s->last)?s->last->Seqno:-1);
+ comment(stdout, e->n, 0);
+ printf("\n");
+#endif
+ if (!s->frst)
+ s->frst = e;
+ else
+ s->last->nxt = e;
+ s->last = e;
+}
+
+static Element *
+colons(Lextok *n)
+{
+ if (!n)
+ return ZE;
+ if (n->ntyp == ':')
+ { Element *e = colons(n->lft);
+ set_lab(n->sym, e);
+ return e;
+ }
+ innermost = n;
+ return new_el(n);
+}
+
+void
+add_seq(Lextok *n)
+{ Element *e;
+
+ if (!n) return;
+ innermost = n;
+ e = colons(n);
+ if (innermost->ntyp != IF
+ && innermost->ntyp != DO
+ && innermost->ntyp != UNLESS)
+ add_el(e, cur_s->this);
+}
+
+void
+set_lab(Symbol *s, Element *e)
+{ Label *l; extern Symbol *context;
+
+ if (!s) return;
+ for (l = labtab; l; l = l->nxt)
+ if (l->s == s && l->c == context)
+ { non_fatal("label %s redeclared", s->name);
+ break;
+ }
+ l = (Label *) emalloc(sizeof(Label));
+ l->s = s;
+ l->c = context;
+ l->e = e;
+ l->nxt = labtab;
+ labtab = l;
+}
+
+Element *
+get_lab(Lextok *n, int md)
+{ Label *l;
+ Symbol *s = n->sym;
+
+ for (l = labtab; l; l = l->nxt)
+ if (s == l->s)
+ return (l->e);
+
+ lineno = n->ln;
+ Fname = n->fn;
+ if (md) fatal("undefined label %s", s->name);
+ return ZE;
+}
+
+Symbol *
+has_lab(Element *e, int special)
+{ Label *l;
+
+ for (l = labtab; l; l = l->nxt)
+ { if (e != l->e)
+ continue;
+ if (special == 0
+ || ((special&1) && !strncmp(l->s->name, "accept", 6))
+ || ((special&2) && !strncmp(l->s->name, "end", 3))
+ || ((special&4) && !strncmp(l->s->name, "progress", 8)))
+ return (l->s);
+ }
+ return ZS;
+}
+
+static void
+mov_lab(Symbol *z, Element *e, Element *y)
+{ Label *l;
+
+ for (l = labtab; l; l = l->nxt)
+ if (e == l->e)
+ { l->e = y;
+ return;
+ }
+ if (e->n)
+ { lineno = e->n->ln;
+ Fname = e->n->fn;
+ }
+ fatal("cannot happen - mov_lab %s", z->name);
+}
+
+void
+fix_dest(Symbol *c, Symbol *a) /* c:label name, a:proctype name */
+{ Label *l; extern Symbol *context;
+
+#if 0
+ printf("ref to label '%s' in proctype '%s', search:\n",
+ c->name, a->name);
+ for (l = labtab; l; l = l->nxt)
+ printf(" %s in %s\n", l->s->name, l->c->name);
+#endif
+
+ for (l = labtab; l; l = l->nxt)
+ { if (strcmp(c->name, l->s->name) == 0
+ && strcmp(a->name, l->c->name) == 0) /* ? */
+ break;
+ }
+ if (!l)
+ { printf("spin: label '%s' (proctype %s)\n", c->name, a->name);
+ non_fatal("unknown label '%s'", c->name);
+ if (context == a)
+ printf("spin: cannot remote ref a label inside the same proctype\n");
+ return;
+ }
+ if (!l->e || !l->e->n)
+ fatal("fix_dest error (%s)", c->name);
+ if (l->e->n->ntyp == GOTO)
+ { Element *y = (Element *) emalloc(sizeof(Element));
+ int keep_ln = l->e->n->ln;
+ Symbol *keep_fn = l->e->n->fn;
+
+ /* insert skip - or target is optimized away */
+ y->n = l->e->n; /* copy of the goto */
+ y->seqno = find_maxel(a); /* unique seqno within proc */
+ y->nxt = l->e->nxt;
+ y->Seqno = Unique++; y->Nxt = Al_El; Al_El = y;
+
+ /* turn the original element+seqno into a skip */
+ l->e->n = nn(ZN, 'c', nn(ZN, CONST, ZN, ZN), ZN);
+ l->e->n->ln = l->e->n->lft->ln = keep_ln;
+ l->e->n->fn = l->e->n->lft->fn = keep_fn;
+ l->e->n->lft->val = 1;
+ l->e->nxt = y; /* append the goto */
+ }
+ l->e->status |= CHECK2; /* treat as if global */
+ if (l->e->status & (ATOM | L_ATOM | D_ATOM))
+ { non_fatal("cannot reference label inside atomic or d_step (%s)",
+ c->name);
+ }
+}
+
+int
+find_lab(Symbol *s, Symbol *c, int markit)
+{ Label *l;
+
+ for (l = labtab; l; l = l->nxt)
+ { if (strcmp(s->name, l->s->name) == 0
+ && strcmp(c->name, l->c->name) == 0)
+ { l->visible |= markit;
+ return (l->e->seqno);
+ } }
+ return 0;
+}
+
+void
+pushbreak(void)
+{ Lbreak *r = (Lbreak *) emalloc(sizeof(Lbreak));
+ Symbol *l;
+ char buf[64];
+
+ sprintf(buf, ":b%d", break_id++);
+ l = lookup(buf);
+ r->l = l;
+ r->nxt = breakstack;
+ breakstack = r;
+}
+
+Symbol *
+break_dest(void)
+{
+ if (!breakstack)
+ fatal("misplaced break statement", (char *)0);
+ return breakstack->l;
+}
+
+void
+make_atomic(Sequence *s, int added)
+{ Element *f;
+
+ walk_atomic(s->frst, s->last, added);
+
+ f = s->last;
+ switch (f->n->ntyp) { /* is last step basic stmnt or sequence ? */
+ case NON_ATOMIC:
+ case ATOMIC:
+ /* redo and search for the last step of that sequence */
+ make_atomic(f->n->sl->this, added);
+ break;
+
+ case UNLESS:
+ /* escapes are folded into main sequence */
+ make_atomic(f->sub->this, added);
+ break;
+
+ default:
+ f->status &= ~ATOM;
+ f->status |= L_ATOM;
+ break;
+ }
+}
+
+static void
+walk_atomic(Element *a, Element *b, int added)
+{ Element *f; Symbol *ofn; int oln;
+ SeqList *h;
+
+ ofn = Fname;
+ oln = lineno;
+ for (f = a; ; f = f->nxt)
+ { f->status |= (ATOM|added);
+ switch (f->n->ntyp) {
+ case ATOMIC:
+ if (verbose&32)
+ printf("spin: warning, line %3d %s, atomic inside %s (ignored)\n",
+ f->n->ln, f->n->fn->name, (added)?"d_step":"atomic");
+ goto mknonat;
+ case D_STEP:
+ if (!(verbose&32))
+ { if (added) goto mknonat;
+ break;
+ }
+ printf("spin: warning, line %3d %s, d_step inside ",
+ f->n->ln, f->n->fn->name);
+ if (added)
+ { printf("d_step (ignored)\n");
+ goto mknonat;
+ }
+ printf("atomic\n");
+ break;
+ case NON_ATOMIC:
+mknonat: f->n->ntyp = NON_ATOMIC; /* can jump here */
+ h = f->n->sl;
+ walk_atomic(h->this->frst, h->this->last, added);
+ break;
+ case UNLESS:
+ if (added)
+ { printf("spin: error, line %3d %s, unless in d_step (ignored)\n",
+ f->n->ln, f->n->fn->name);
+ }
+ }
+ for (h = f->sub; h; h = h->nxt)
+ walk_atomic(h->this->frst, h->this->last, added);
+ if (f == b)
+ break;
+ }
+ Fname = ofn;
+ lineno = oln;
+}
+
+void
+dumplabels(void)
+{ Label *l;
+
+ for (l = labtab; l; l = l->nxt)
+ if (l->c != 0 && l->s->name[0] != ':')
+ printf("label %s %d <%s>\n",
+ l->s->name, l->e->seqno, l->c->name);
+}
diff --git a/sys/src/cmd/spin/guided.c b/sys/src/cmd/spin/guided.c
new file mode 100755
index 000000000..0bc4dcbc7
--- /dev/null
+++ b/sys/src/cmd/spin/guided.c
@@ -0,0 +1,313 @@
+/***** spin: guided.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include "spin.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "y.tab.h"
+
+extern RunList *run, *X;
+extern Element *Al_El;
+extern Symbol *Fname, *oFname;
+extern int verbose, lineno, xspin, jumpsteps, depth, merger, cutoff;
+extern int nproc, nstop, Tval, ntrail, columns;
+extern short Have_claim, Skip_claim;
+extern void ana_src(int, int);
+
+int TstOnly = 0, pno;
+
+static int lastclaim = -1;
+static FILE *fd;
+static void lost_trail(void);
+
+static void
+whichproc(int p)
+{ RunList *oX;
+
+ for (oX = run; oX; oX = oX->nxt)
+ if (oX->pid == p)
+ { printf("(%s) ", oX->n->name);
+ break;
+ }
+}
+
+static int
+newer(char *f1, char *f2)
+{
+#if defined(WIN32) || defined(WIN64)
+ struct _stat x, y;
+#else
+ struct stat x, y;
+#endif
+
+ if (stat(f1, (struct stat *)&x) < 0) return 0;
+ if (stat(f2, (struct stat *)&y) < 0) return 1;
+ if (x.st_mtime < y.st_mtime) return 0;
+
+ return 1;
+}
+
+void
+hookup(void)
+{ Element *e;
+
+ for (e = Al_El; e; e = e->Nxt)
+ if (e->n
+ && (e->n->ntyp == ATOMIC
+ || e->n->ntyp == NON_ATOMIC
+ || e->n->ntyp == D_STEP))
+ (void) huntstart(e);
+}
+
+int
+not_claim(void)
+{
+ return (!Have_claim || !X || X->pid != 0);
+}
+
+void
+match_trail(void)
+{ int i, a, nst;
+ Element *dothis;
+ char snap[512], *q;
+
+ /*
+ * if source model name is leader.pml
+ * look for the trail file under these names:
+ * leader.pml.trail
+ * leader.pml.tra
+ * leader.trail
+ * leader.tra
+ */
+
+ if (ntrail)
+ sprintf(snap, "%s%d.trail", oFname->name, ntrail);
+ else
+ sprintf(snap, "%s.trail", oFname->name);
+
+ if ((fd = fopen(snap, "r")) == NULL)
+ { snap[strlen(snap)-2] = '\0'; /* .tra */
+ if ((fd = fopen(snap, "r")) == NULL)
+ { if ((q = strchr(oFname->name, '.')) != NULL)
+ { *q = '\0';
+ if (ntrail)
+ sprintf(snap, "%s%d.trail",
+ oFname->name, ntrail);
+ else
+ sprintf(snap, "%s.trail",
+ oFname->name);
+ *q = '.';
+
+ if ((fd = fopen(snap, "r")) != NULL)
+ goto okay;
+
+ snap[strlen(snap)-2] = '\0'; /* last try */
+ if ((fd = fopen(snap, "r")) != NULL)
+ goto okay;
+ }
+ printf("spin: cannot find trail file\n");
+ alldone(1);
+ } }
+okay:
+ if (xspin == 0 && newer(oFname->name, snap))
+ printf("spin: warning, \"%s\" is newer than %s\n",
+ oFname->name, snap);
+
+ Tval = 1;
+
+ /*
+ * sets Tval because timeouts may be part of trail
+ * this used to also set m_loss to 1, but that is
+ * better handled with the runtime -m flag
+ */
+
+ hookup();
+
+ while (fscanf(fd, "%d:%d:%d\n", &depth, &pno, &nst) == 3)
+ { if (depth == -2) { start_claim(pno); continue; }
+ if (depth == -4) { merger = 1; ana_src(0, 1); continue; }
+ if (depth == -1)
+ { if (verbose)
+ { if (columns == 2)
+ dotag(stdout, " CYCLE>\n");
+ else
+ dotag(stdout, "<<<<<START OF CYCLE>>>>>\n");
+ }
+ continue;
+ }
+
+ if (cutoff > 0 && depth >= cutoff)
+ { printf("-------------\n");
+ printf("depth-limit (-u%d steps) reached\n", cutoff);
+ break;
+ }
+
+ if (Skip_claim && pno == 0) continue;
+
+ for (dothis = Al_El; dothis; dothis = dothis->Nxt)
+ { if (dothis->Seqno == nst)
+ break;
+ }
+ if (!dothis)
+ { printf("%3d: proc %d, no matching stmnt %d\n",
+ depth, pno - Have_claim, nst);
+ lost_trail();
+ }
+
+ i = nproc - nstop + Skip_claim;
+
+ if (dothis->n->ntyp == '@')
+ { if (pno == i-1)
+ { run = run->nxt;
+ nstop++;
+ if (verbose&4)
+ { if (columns == 2)
+ { dotag(stdout, "<end>\n");
+ continue;
+ }
+ if (Have_claim && pno == 0)
+ printf("%3d: claim terminates\n",
+ depth);
+ else
+ printf("%3d: proc %d terminates\n",
+ depth, pno - Have_claim);
+ }
+ continue;
+ }
+ if (pno <= 1) continue; /* init dies before never */
+ printf("%3d: stop error, ", depth);
+ printf("proc %d (i=%d) trans %d, %c\n",
+ pno - Have_claim, i, nst, dothis->n->ntyp);
+ lost_trail();
+ }
+ for (X = run; X; X = X->nxt)
+ { if (--i == pno)
+ break;
+ }
+ if (!X)
+ { printf("%3d: no process %d ", depth, pno - Have_claim);
+ printf("(state %d)\n", nst);
+ lost_trail();
+ }
+ X->pc = dothis;
+ lineno = dothis->n->ln;
+ Fname = dothis->n->fn;
+
+ if (dothis->n->ntyp == D_STEP)
+ { Element *g, *og = dothis;
+ do {
+ g = eval_sub(og);
+ if (g && depth >= jumpsteps
+ && ((verbose&32) || ((verbose&4) && not_claim())))
+ { if (columns != 2)
+ { p_talk(og, 1);
+
+ if (og->n->ntyp == D_STEP)
+ og = og->n->sl->this->frst;
+
+ printf("\t[");
+ comment(stdout, og->n, 0);
+ printf("]\n");
+ }
+ if (verbose&1) dumpglobals();
+ if (verbose&2) dumplocal(X);
+ if (xspin) printf("\n");
+ }
+ og = g;
+ } while (g && g != dothis->nxt);
+ if (X != NULL)
+ { X->pc = g?huntele(g, 0, -1):g;
+ }
+ } else
+ {
+keepgoing: if (dothis->merge_start)
+ a = dothis->merge_start;
+ else
+ a = dothis->merge;
+
+ if (X != NULL)
+ { X->pc = eval_sub(dothis);
+ if (X->pc) X->pc = huntele(X->pc, 0, a);
+ }
+
+ if (depth >= jumpsteps
+ && ((verbose&32) || ((verbose&4) && not_claim()))) /* -v or -p */
+ { if (columns != 2)
+ { p_talk(dothis, 1);
+
+ if (dothis->n->ntyp == D_STEP)
+ dothis = dothis->n->sl->this->frst;
+
+ printf("\t[");
+ comment(stdout, dothis->n, 0);
+ printf("]");
+ if (a && (verbose&32))
+ printf("\t<merge %d now @%d>",
+ dothis->merge,
+ (X && X->pc)?X->pc->seqno:-1);
+ printf("\n");
+ }
+ if (verbose&1) dumpglobals();
+ if (verbose&2) dumplocal(X);
+ if (xspin) printf("\n");
+
+ if (X && !X->pc)
+ { X->pc = dothis;
+ printf("\ttransition failed\n");
+ a = 0; /* avoid inf loop */
+ }
+ }
+ if (a && X && X->pc && X->pc->seqno != a)
+ { dothis = X->pc;
+ goto keepgoing;
+ } }
+
+ if (Have_claim && X && X->pid == 0
+ && dothis && dothis->n
+ && lastclaim != dothis->n->ln)
+ { lastclaim = dothis->n->ln;
+ if (columns == 2)
+ { char t[128];
+ sprintf(t, "#%d", lastclaim);
+ pstext(0, t);
+ } else
+ {
+ printf("Never claim moves to line %d\t[", lastclaim);
+ comment(stdout, dothis->n, 0);
+ printf("]\n");
+ } } }
+ printf("spin: trail ends after %d steps\n", depth);
+ wrapup(0);
+}
+
+static void
+lost_trail(void)
+{ int d, p, n, l;
+
+ while (fscanf(fd, "%d:%d:%d:%d\n", &d, &p, &n, &l) == 4)
+ { printf("step %d: proc %d ", d, p); whichproc(p);
+ printf("(state %d) - d %d\n", n, l);
+ }
+ wrapup(1); /* no return */
+}
+
+int
+pc_value(Lextok *n)
+{ int i = nproc - nstop;
+ int pid = eval(n);
+ RunList *Y;
+
+ for (Y = run; Y; Y = Y->nxt)
+ { if (--i == pid)
+ return Y->pc->seqno;
+ }
+ return 0;
+}
diff --git a/sys/src/cmd/spin/main.c b/sys/src/cmd/spin/main.c
new file mode 100755
index 000000000..d70164424
--- /dev/null
+++ b/sys/src/cmd/spin/main.c
@@ -0,0 +1,778 @@
+/***** spin: main.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include <stdlib.h>
+#include "spin.h"
+#include "version.h"
+#include <signal.h>
+/* #include <malloc.h> */
+#include <time.h>
+#ifdef PC
+#include <io.h>
+extern int unlink(const char *);
+#else
+#include <unistd.h>
+#endif
+#include "y.tab.h"
+
+extern int DstepStart, lineno, tl_terse;
+extern FILE *yyin, *yyout, *tl_out;
+extern Symbol *context;
+extern char *claimproc;
+extern void repro_src(void);
+extern void qhide(int);
+
+Symbol *Fname, *oFname;
+
+int Etimeouts; /* nr timeouts in program */
+int Ntimeouts; /* nr timeouts in never claim */
+int analyze, columns, dumptab, has_remote, has_remvar;
+int interactive, jumpsteps, m_loss, nr_errs, cutoff;
+int s_trail, ntrail, verbose, xspin, notabs, rvopt;
+int no_print, no_wrapup, Caccess, limited_vis, like_java;
+int separate; /* separate compilation */
+int export_ast; /* pangen5.c */
+int inlineonly; /* show inlined code */
+int seedy; /* be verbose about chosen seed */
+
+int dataflow = 1, merger = 1, deadvar = 1, ccache = 1;
+
+static int preprocessonly, SeedUsed;
+
+#if 0
+meaning of flags on verbose:
+ 1 -g global variable values
+ 2 -l local variable values
+ 4 -p all process actions
+ 8 -r receives
+ 16 -s sends
+ 32 -v verbose
+ 64 -w very verbose
+#endif
+
+static char Operator[] = "operator: ";
+static char Keyword[] = "keyword: ";
+static char Function[] = "function-name: ";
+static char **add_ltl = (char **)0;
+static char **ltl_file = (char **)0;
+static char **nvr_file = (char **)0;
+static char *PreArg[64];
+static int PreCnt = 0;
+static char out1[64];
+static void explain(int);
+
+#ifndef CPP
+ /* OS2: "spin -Picc -E/Pd+ -E/Q+" */
+ /* Visual C++: "spin -PCL -E/E */
+#ifdef PC
+#define CPP "gcc -E -x c" /* most systems have gcc anyway */
+ /* else use "cpp" */
+#else
+#ifdef SOLARIS
+#define CPP "/usr/ccs/lib/cpp"
+#else
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+#define CPP "cpp"
+#else
+#define CPP "/bin/cpp" /* classic Unix systems */
+#endif
+#endif
+#endif
+
+#endif
+static char *PreProc = CPP;
+extern int depth; /* at least some steps were made */
+
+void
+alldone(int estatus)
+{
+ if (preprocessonly == 0
+ && strlen(out1) > 0)
+ (void) unlink((const char *)out1);
+
+ if (seedy && !analyze && !export_ast
+ && !s_trail && !preprocessonly && depth > 0)
+ printf("seed used: %d\n", SeedUsed);
+
+ if (xspin && (analyze || s_trail))
+ { if (estatus)
+ printf("spin: %d error(s) - aborting\n",
+ estatus);
+ else
+ printf("Exit-Status 0\n");
+ }
+ exit(estatus);
+}
+
+void
+preprocess(char *a, char *b, int a_tmp)
+{ char precmd[512], cmd[1024]; int i;
+#ifdef PC
+ extern int try_zpp(char *, char *);
+ if (PreCnt == 0 && try_zpp(a, b)) goto out;
+#endif
+ strcpy(precmd, PreProc);
+ for (i = 1; i <= PreCnt; i++)
+ { strcat(precmd, " ");
+ strcat(precmd, PreArg[i]);
+ }
+ sprintf(cmd, "%s %s > %s", precmd, a, b);
+ if (system((const char *)cmd))
+ { (void) unlink((const char *) b);
+ if (a_tmp) (void) unlink((const char *) a);
+ fprintf(stdout, "spin: preprocessing failed\n"); /* 4.1.2 was stderr */
+ alldone(1); /* no return, error exit */
+ }
+#ifdef PC
+out:
+#endif
+ if (a_tmp) (void) unlink((const char *) a);
+}
+
+FILE *
+cpyfile(char *src, char *tgt)
+{ FILE *inp, *out;
+ char buf[1024];
+
+ inp = fopen(src, "r");
+ out = fopen(tgt, "w");
+ if (!inp || !out)
+ { printf("spin: cannot cp %s to %s\n", src, tgt);
+ alldone(1);
+ }
+ while (fgets(buf, 1024, inp))
+ fprintf(out, "%s", buf);
+ fclose(inp);
+ return out;
+}
+
+void
+usage(void)
+{
+ printf("use: spin [-option] ... [-option] file\n");
+ printf("\tNote: file must always be the last argument\n");
+ printf("\t-A apply slicing algorithm\n");
+ printf("\t-a generate a verifier in pan.c\n");
+ printf("\t-B no final state details in simulations\n");
+ printf("\t-b don't execute printfs in simulation\n");
+ printf("\t-C print channel access info (combine with -g etc.)\n");
+ printf("\t-c columnated -s -r simulation output\n");
+ printf("\t-d produce symbol-table information\n");
+ printf("\t-Dyyy pass -Dyyy to the preprocessor\n");
+ printf("\t-Eyyy pass yyy to the preprocessor\n");
+ printf("\t-f \"..formula..\" translate LTL ");
+ printf("into never claim\n");
+ printf("\t-F file like -f, but with the LTL ");
+ printf("formula stored in a 1-line file\n");
+ printf("\t-g print all global variables\n");
+ printf("\t-h at end of run, print value of seed for random nr generator used\n");
+ printf("\t-i interactive (random simulation)\n");
+ printf("\t-I show result of inlining and preprocessing\n");
+ printf("\t-J reverse eval order of nested unlesses\n");
+ printf("\t-jN skip the first N steps ");
+ printf("in simulation trail\n");
+ printf("\t-l print all local variables\n");
+ printf("\t-M print msc-flow in Postscript\n");
+ printf("\t-m lose msgs sent to full queues\n");
+ printf("\t-N file use never claim stored in file\n");
+ printf("\t-nN seed for random nr generator\n");
+ printf("\t-o1 turn off dataflow-optimizations in verifier\n");
+ printf("\t-o2 don't hide write-only variables in verifier\n");
+ printf("\t-o3 turn off statement merging in verifier\n");
+ printf("\t-Pxxx use xxx for preprocessing\n");
+ printf("\t-p print all statements\n");
+ printf("\t-qN suppress io for queue N in printouts\n");
+ printf("\t-r print receive events\n");
+ printf("\t-S1 and -S2 separate pan source for claim and model\n");
+ printf("\t-s print send events\n");
+ printf("\t-T do not indent printf output\n");
+ printf("\t-t[N] follow [Nth] simulation trail\n");
+ printf("\t-Uyyy pass -Uyyy to the preprocessor\n");
+ printf("\t-uN stop a simulation run after N steps\n");
+ printf("\t-v verbose, more warnings\n");
+ printf("\t-w very verbose (when combined with -l or -g)\n");
+ printf("\t-[XYZ] reserved for use by xspin interface\n");
+ printf("\t-V print version number and exit\n");
+ alldone(1);
+}
+
+void
+optimizations(char nr)
+{
+ switch (nr) {
+ case '1':
+ dataflow = 1 - dataflow; /* dataflow */
+ if (verbose&32)
+ printf("spin: dataflow optimizations turned %s\n",
+ dataflow?"on":"off");
+ break;
+ case '2':
+ /* dead variable elimination */
+ deadvar = 1 - deadvar;
+ if (verbose&32)
+ printf("spin: dead variable elimination turned %s\n",
+ deadvar?"on":"off");
+ break;
+ case '3':
+ /* statement merging */
+ merger = 1 - merger;
+ if (verbose&32)
+ printf("spin: statement merging turned %s\n",
+ merger?"on":"off");
+ break;
+
+ case '4':
+ /* rv optimization */
+ rvopt = 1 - rvopt;
+ if (verbose&32)
+ printf("spin: rendezvous optimization turned %s\n",
+ rvopt?"on":"off");
+ break;
+ case '5':
+ /* case caching */
+ ccache = 1 - ccache;
+ if (verbose&32)
+ printf("spin: case caching turned %s\n",
+ ccache?"on":"off");
+ break;
+ default:
+ printf("spin: bad or missing parameter on -o\n");
+ usage();
+ break;
+ }
+}
+
+#if 0
+static int
+Rename(const char *old, char *new)
+{ FILE *fo, *fn;
+ char buf[1024];
+
+ if ((fo = fopen(old, "r")) == NULL)
+ { printf("spin: cannot open %s\n", old);
+ return 1;
+ }
+ if ((fn = fopen(new, "w")) == NULL)
+ { printf("spin: cannot create %s\n", new);
+ fclose(fo);
+ return 2;
+ }
+ while (fgets(buf, 1024, fo))
+ fputs(buf, fn);
+
+ fclose(fo);
+ fclose(fn);
+
+ return 0; /* success */
+}
+#endif
+
+int
+main(int argc, char *argv[])
+{ Symbol *s;
+ int T = (int) time((time_t *)0);
+ int usedopts = 0;
+ extern void ana_src(int, int);
+
+ yyin = stdin;
+ yyout = stdout;
+ tl_out = stdout;
+
+ /* unused flags: e, w, x, y, z, A, G, I, L, O, Q, R, S, T, W */
+ while (argc > 1 && argv[1][0] == '-')
+ { switch (argv[1][1]) {
+
+ /* generate code for separate compilation: S1 or S2 */
+ case 'S': separate = atoi(&argv[1][2]);
+ /* fall through */
+ case 'a': analyze = 1; break;
+
+ case 'A': export_ast = 1; break;
+ case 'B': no_wrapup = 1; break;
+ case 'b': no_print = 1; break;
+ case 'C': Caccess = 1; break;
+ case 'c': columns = 1; break;
+ case 'D': PreArg[++PreCnt] = (char *) &argv[1][0];
+ break; /* define */
+ case 'd': dumptab = 1; break;
+ case 'E': PreArg[++PreCnt] = (char *) &argv[1][2];
+ break;
+ case 'F': ltl_file = (char **) (argv+2);
+ argc--; argv++; break;
+ case 'f': add_ltl = (char **) argv;
+ argc--; argv++; break;
+ case 'g': verbose += 1; break;
+ case 'h': seedy = 1; break;
+ case 'i': interactive = 1; break;
+ case 'I': inlineonly = 1; break;
+ case 'J': like_java = 1; break;
+ case 'j': jumpsteps = atoi(&argv[1][2]); break;
+ case 'l': verbose += 2; break;
+ case 'M': columns = 2; break;
+ case 'm': m_loss = 1; break;
+ case 'N': nvr_file = (char **) (argv+2);
+ argc--; argv++; break;
+ case 'n': T = atoi(&argv[1][2]); tl_terse = 1; break;
+ case 'o': optimizations(argv[1][2]);
+ usedopts = 1; break;
+ case 'P': PreProc = (char *) &argv[1][2]; break;
+ case 'p': verbose += 4; break;
+ case 'q': if (isdigit(argv[1][2]))
+ qhide(atoi(&argv[1][2]));
+ break;
+ case 'r': verbose += 8; break;
+ case 's': verbose += 16; break;
+ case 'T': notabs = 1; break;
+ case 't': s_trail = 1;
+ if (isdigit(argv[1][2]))
+ ntrail = atoi(&argv[1][2]);
+ break;
+ case 'U': PreArg[++PreCnt] = (char *) &argv[1][0];
+ break; /* undefine */
+ case 'u': cutoff = atoi(&argv[1][2]); break; /* new 3.4.14 */
+ case 'v': verbose += 32; break;
+ case 'V': printf("%s\n", Version);
+ alldone(0);
+ break;
+ case 'w': verbose += 64; break;
+ case 'X': xspin = notabs = 1;
+#ifndef PC
+ signal(SIGPIPE, alldone); /* not posix... */
+#endif
+ break;
+ case 'Y': limited_vis = 1; break; /* used by xspin */
+ case 'Z': preprocessonly = 1; break; /* used by xspin */
+
+ default : usage(); break;
+ }
+ argc--; argv++;
+ }
+ if (usedopts && !analyze)
+ printf("spin: warning -o[123] option ignored in simulations\n");
+
+ if (ltl_file)
+ { char formula[4096];
+ add_ltl = ltl_file-2; add_ltl[1][1] = 'f';
+ if (!(tl_out = fopen(*ltl_file, "r")))
+ { printf("spin: cannot open %s\n", *ltl_file);
+ alldone(1);
+ }
+ fgets(formula, 4096, tl_out);
+ fclose(tl_out);
+ tl_out = stdout;
+ *ltl_file = (char *) formula;
+ }
+ if (argc > 1)
+ { char cmd[128], out2[64];
+
+ /* must remain in current dir */
+ strcpy(out1, "pan.pre");
+
+ if (add_ltl || nvr_file)
+ strcpy(out2, "pan.___");
+
+ if (add_ltl)
+ { tl_out = cpyfile(argv[1], out2);
+ nr_errs = tl_main(2, add_ltl); /* in tl_main.c */
+ fclose(tl_out);
+ preprocess(out2, out1, 1);
+ } else if (nvr_file)
+ { FILE *fd; char buf[1024];
+
+ if ((fd = fopen(*nvr_file, "r")) == NULL)
+ { printf("spin: cannot open %s\n",
+ *nvr_file);
+ alldone(1);
+ }
+ tl_out = cpyfile(argv[1], out2);
+ while (fgets(buf, 1024, fd))
+ fprintf(tl_out, "%s", buf);
+ fclose(tl_out);
+ fclose(fd);
+ preprocess(out2, out1, 1);
+ } else
+ preprocess(argv[1], out1, 0);
+
+ if (preprocessonly)
+ alldone(0);
+
+ if (!(yyin = fopen(out1, "r")))
+ { printf("spin: cannot open %s\n", out1);
+ alldone(1);
+ }
+
+ if (strncmp(argv[1], "progress", 8) == 0
+ || strncmp(argv[1], "accept", 6) == 0)
+ sprintf(cmd, "_%s", argv[1]);
+ else
+ strcpy(cmd, argv[1]);
+ oFname = Fname = lookup(cmd);
+ if (oFname->name[0] == '\"')
+ { int i = (int) strlen(oFname->name);
+ oFname->name[i-1] = '\0';
+ oFname = lookup(&oFname->name[1]);
+ }
+ } else
+ { oFname = Fname = lookup("<stdin>");
+ if (add_ltl)
+ { if (argc > 0)
+ exit(tl_main(2, add_ltl));
+ printf("spin: missing argument to -f\n");
+ alldone(1);
+ }
+ printf("%s\n", Version);
+ printf("reading input from stdin:\n");
+ fflush(stdout);
+ }
+ if (columns == 2)
+ { extern void putprelude(void);
+ if (xspin || verbose&(1|4|8|16|32))
+ { printf("spin: -c precludes all flags except -t\n");
+ alldone(1);
+ }
+ putprelude();
+ }
+ if (columns && !(verbose&8) && !(verbose&16))
+ verbose += (8+16);
+ if (columns == 2 && limited_vis)
+ verbose += (1+4);
+ Srand(T); /* defined in run.c */
+ SeedUsed = T;
+ s = lookup("_"); s->type = PREDEF; /* write-only global var */
+ s = lookup("_p"); s->type = PREDEF;
+ s = lookup("_pid"); s->type = PREDEF;
+ s = lookup("_last"); s->type = PREDEF;
+ s = lookup("_nr_pr"); s->type = PREDEF; /* new 3.3.10 */
+
+ yyparse();
+ fclose(yyin);
+ loose_ends();
+
+ if (inlineonly)
+ { repro_src();
+ return 0;
+ }
+
+ chanaccess();
+ if (!Caccess)
+ { if (!s_trail && (dataflow || merger))
+ ana_src(dataflow, merger);
+ sched();
+ alldone(nr_errs);
+ }
+ return 0;
+}
+
+int
+yywrap(void) /* dummy routine */
+{
+ return 1;
+}
+
+void
+non_fatal(char *s1, char *s2)
+{ extern char yytext[];
+
+ printf("spin: line %3d %s, Error: ",
+ lineno, Fname?Fname->name:"nofilename");
+ if (s2)
+ printf(s1, s2);
+ else
+ printf(s1);
+ if (yytext && strlen(yytext)>1)
+ printf(" near '%s'", yytext);
+ printf("\n");
+ nr_errs++;
+}
+
+void
+fatal(char *s1, char *s2)
+{
+ non_fatal(s1, s2);
+ alldone(1);
+}
+
+char *
+emalloc(int n)
+{ char *tmp;
+
+ if (n == 0)
+ return NULL; /* robert shelton 10/20/06 */
+
+ if (!(tmp = (char *) malloc(n)))
+ fatal("not enough memory", (char *)0);
+ memset(tmp, 0, n);
+ return tmp;
+}
+
+void
+trapwonly(Lextok *n, char *unused)
+{ extern int realread;
+ short i = (n->sym)?n->sym->type:0;
+
+ if (i != MTYPE
+ && i != BIT
+ && i != BYTE
+ && i != SHORT
+ && i != INT
+ && i != UNSIGNED)
+ return;
+
+ if (realread)
+ n->sym->hidden |= 128; /* var is read at least once */
+}
+
+void
+setaccess(Symbol *sp, Symbol *what, int cnt, int t)
+{ Access *a;
+
+ for (a = sp->access; a; a = a->lnk)
+ if (a->who == context
+ && a->what == what
+ && a->cnt == cnt
+ && a->typ == t)
+ return;
+
+ a = (Access *) emalloc(sizeof(Access));
+ a->who = context;
+ a->what = what;
+ a->cnt = cnt;
+ a->typ = t;
+ a->lnk = sp->access;
+ sp->access = a;
+}
+
+Lextok *
+nn(Lextok *s, int t, Lextok *ll, Lextok *rl)
+{ Lextok *n = (Lextok *) emalloc(sizeof(Lextok));
+ static int warn_nn = 0;
+
+ n->ntyp = (short) t;
+ if (s && s->fn)
+ { n->ln = s->ln;
+ n->fn = s->fn;
+ } else if (rl && rl->fn)
+ { n->ln = rl->ln;
+ n->fn = rl->fn;
+ } else if (ll && ll->fn)
+ { n->ln = ll->ln;
+ n->fn = ll->fn;
+ } else
+ { n->ln = lineno;
+ n->fn = Fname;
+ }
+ if (s) n->sym = s->sym;
+ n->lft = ll;
+ n->rgt = rl;
+ n->indstep = DstepStart;
+
+ if (t == TIMEOUT) Etimeouts++;
+
+ if (!context) return n;
+
+ if (t == 'r' || t == 's')
+ setaccess(n->sym, ZS, 0, t);
+ if (t == 'R')
+ setaccess(n->sym, ZS, 0, 'P');
+
+ if (context->name == claimproc)
+ { int forbidden = separate;
+ switch (t) {
+ case ASGN:
+ printf("spin: Warning, never claim has side-effect\n");
+ break;
+ case 'r': case 's':
+ non_fatal("never claim contains i/o stmnts",(char *)0);
+ break;
+ case TIMEOUT:
+ /* never claim polls timeout */
+ if (Ntimeouts && Etimeouts)
+ forbidden = 0;
+ Ntimeouts++; Etimeouts--;
+ break;
+ case LEN: case EMPTY: case FULL:
+ case 'R': case NFULL: case NEMPTY:
+ /* status becomes non-exclusive */
+ if (n->sym && !(n->sym->xu&XX))
+ { n->sym->xu |= XX;
+ if (separate == 2) {
+ printf("spin: warning, make sure that the S1 model\n");
+ printf(" also polls channel '%s' in its claim\n",
+ n->sym->name);
+ } }
+ forbidden = 0;
+ break;
+ case 'c':
+ AST_track(n, 0); /* register as a slice criterion */
+ /* fall thru */
+ default:
+ forbidden = 0;
+ break;
+ }
+ if (forbidden)
+ { printf("spin: never, saw "); explain(t); printf("\n");
+ fatal("incompatible with separate compilation",(char *)0);
+ }
+ } else if ((t == ENABLED || t == PC_VAL) && !(warn_nn&t))
+ { printf("spin: Warning, using %s outside never claim\n",
+ (t == ENABLED)?"enabled()":"pc_value()");
+ warn_nn |= t;
+ } else if (t == NONPROGRESS)
+ { fatal("spin: Error, using np_ outside never claim\n", (char *)0);
+ }
+ return n;
+}
+
+Lextok *
+rem_lab(Symbol *a, Lextok *b, Symbol *c) /* proctype name, pid, label name */
+{ Lextok *tmp1, *tmp2, *tmp3;
+
+ has_remote++;
+ c->type = LABEL; /* refered to in global context here */
+ fix_dest(c, a); /* in case target of rem_lab is jump */
+ tmp1 = nn(ZN, '?', b, ZN); tmp1->sym = a;
+ tmp1 = nn(ZN, 'p', tmp1, ZN);
+ tmp1->sym = lookup("_p");
+ tmp2 = nn(ZN, NAME, ZN, ZN); tmp2->sym = a;
+ tmp3 = nn(ZN, 'q', tmp2, ZN); tmp3->sym = c;
+ return nn(ZN, EQ, tmp1, tmp3);
+#if 0
+ .---------------EQ-------.
+ / \
+ 'p' -sym-> _p 'q' -sym-> c (label name)
+ / /
+ '?' -sym-> a (proctype) NAME -sym-> a (proctype name)
+ /
+ b (pid expr)
+#endif
+}
+
+Lextok *
+rem_var(Symbol *a, Lextok *b, Symbol *c, Lextok *ndx)
+{ Lextok *tmp1;
+
+ has_remote++;
+ has_remvar++;
+ dataflow = 0; /* turn off dead variable resets 4.2.5 */
+ tmp1 = nn(ZN, '?', b, ZN); tmp1->sym = a;
+ tmp1 = nn(ZN, 'p', tmp1, ndx);
+ tmp1->sym = c;
+ return tmp1;
+#if 0
+ cannot refer to struct elements
+ only to scalars and arrays
+
+ 'p' -sym-> c (variable name)
+ / \______ possible arrayindex on c
+ /
+ '?' -sym-> a (proctype)
+ /
+ b (pid expr)
+#endif
+}
+
+static void
+explain(int n)
+{ FILE *fd = stdout;
+ switch (n) {
+ default: if (n > 0 && n < 256)
+ fprintf(fd, "'%c' = '", n);
+ fprintf(fd, "%d'", n);
+ break;
+ case '\b': fprintf(fd, "\\b"); break;
+ case '\t': fprintf(fd, "\\t"); break;
+ case '\f': fprintf(fd, "\\f"); break;
+ case '\n': fprintf(fd, "\\n"); break;
+ case '\r': fprintf(fd, "\\r"); break;
+ case 'c': fprintf(fd, "condition"); break;
+ case 's': fprintf(fd, "send"); break;
+ case 'r': fprintf(fd, "recv"); break;
+ case 'R': fprintf(fd, "recv poll %s", Operator); break;
+ case '@': fprintf(fd, "@"); break;
+ case '?': fprintf(fd, "(x->y:z)"); break;
+ case ACTIVE: fprintf(fd, "%sactive", Keyword); break;
+ case AND: fprintf(fd, "%s&&", Operator); break;
+ case ASGN: fprintf(fd, "%s=", Operator); break;
+ case ASSERT: fprintf(fd, "%sassert", Function); break;
+ case ATOMIC: fprintf(fd, "%satomic", Keyword); break;
+ case BREAK: fprintf(fd, "%sbreak", Keyword); break;
+ case C_CODE: fprintf(fd, "%sc_code", Keyword); break;
+ case C_DECL: fprintf(fd, "%sc_decl", Keyword); break;
+ case C_EXPR: fprintf(fd, "%sc_expr", Keyword); break;
+ case C_STATE: fprintf(fd, "%sc_state",Keyword); break;
+ case C_TRACK: fprintf(fd, "%sc_track",Keyword); break;
+ case CLAIM: fprintf(fd, "%snever", Keyword); break;
+ case CONST: fprintf(fd, "a constant"); break;
+ case DECR: fprintf(fd, "%s--", Operator); break;
+ case D_STEP: fprintf(fd, "%sd_step", Keyword); break;
+ case D_PROCTYPE: fprintf(fd, "%sd_proctype", Keyword); break;
+ case DO: fprintf(fd, "%sdo", Keyword); break;
+ case DOT: fprintf(fd, "."); break;
+ case ELSE: fprintf(fd, "%selse", Keyword); break;
+ case EMPTY: fprintf(fd, "%sempty", Function); break;
+ case ENABLED: fprintf(fd, "%senabled",Function); break;
+ case EQ: fprintf(fd, "%s==", Operator); break;
+ case EVAL: fprintf(fd, "%seval", Function); break;
+ case FI: fprintf(fd, "%sfi", Keyword); break;
+ case FULL: fprintf(fd, "%sfull", Function); break;
+ case GE: fprintf(fd, "%s>=", Operator); break;
+ case GOTO: fprintf(fd, "%sgoto", Keyword); break;
+ case GT: fprintf(fd, "%s>", Operator); break;
+ case HIDDEN: fprintf(fd, "%shidden", Keyword); break;
+ case IF: fprintf(fd, "%sif", Keyword); break;
+ case INCR: fprintf(fd, "%s++", Operator); break;
+ case INAME: fprintf(fd, "inline name"); break;
+ case INLINE: fprintf(fd, "%sinline", Keyword); break;
+ case INIT: fprintf(fd, "%sinit", Keyword); break;
+ case ISLOCAL: fprintf(fd, "%slocal", Keyword); break;
+ case LABEL: fprintf(fd, "a label-name"); break;
+ case LE: fprintf(fd, "%s<=", Operator); break;
+ case LEN: fprintf(fd, "%slen", Function); break;
+ case LSHIFT: fprintf(fd, "%s<<", Operator); break;
+ case LT: fprintf(fd, "%s<", Operator); break;
+ case MTYPE: fprintf(fd, "%smtype", Keyword); break;
+ case NAME: fprintf(fd, "an identifier"); break;
+ case NE: fprintf(fd, "%s!=", Operator); break;
+ case NEG: fprintf(fd, "%s! (not)",Operator); break;
+ case NEMPTY: fprintf(fd, "%snempty", Function); break;
+ case NFULL: fprintf(fd, "%snfull", Function); break;
+ case NON_ATOMIC: fprintf(fd, "sub-sequence"); break;
+ case NONPROGRESS: fprintf(fd, "%snp_", Function); break;
+ case OD: fprintf(fd, "%sod", Keyword); break;
+ case OF: fprintf(fd, "%sof", Keyword); break;
+ case OR: fprintf(fd, "%s||", Operator); break;
+ case O_SND: fprintf(fd, "%s!!", Operator); break;
+ case PC_VAL: fprintf(fd, "%spc_value",Function); break;
+ case PNAME: fprintf(fd, "process name"); break;
+ case PRINT: fprintf(fd, "%sprintf", Function); break;
+ case PRINTM: fprintf(fd, "%sprintm", Function); break;
+ case PRIORITY: fprintf(fd, "%spriority", Keyword); break;
+ case PROCTYPE: fprintf(fd, "%sproctype",Keyword); break;
+ case PROVIDED: fprintf(fd, "%sprovided",Keyword); break;
+ case RCV: fprintf(fd, "%s?", Operator); break;
+ case R_RCV: fprintf(fd, "%s??", Operator); break;
+ case RSHIFT: fprintf(fd, "%s>>", Operator); break;
+ case RUN: fprintf(fd, "%srun", Operator); break;
+ case SEP: fprintf(fd, "token: ::"); break;
+ case SEMI: fprintf(fd, ";"); break;
+ case SHOW: fprintf(fd, "%sshow", Keyword); break;
+ case SND: fprintf(fd, "%s!", Operator); break;
+ case STRING: fprintf(fd, "a string"); break;
+ case TRACE: fprintf(fd, "%strace", Keyword); break;
+ case TIMEOUT: fprintf(fd, "%stimeout",Keyword); break;
+ case TYPE: fprintf(fd, "data typename"); break;
+ case TYPEDEF: fprintf(fd, "%stypedef",Keyword); break;
+ case XU: fprintf(fd, "%sx[rs]", Keyword); break;
+ case UMIN: fprintf(fd, "%s- (unary minus)", Operator); break;
+ case UNAME: fprintf(fd, "a typename"); break;
+ case UNLESS: fprintf(fd, "%sunless", Keyword); break;
+ }
+}
diff --git a/sys/src/cmd/spin/mesg.c b/sys/src/cmd/spin/mesg.c
new file mode 100755
index 000000000..4b2806b40
--- /dev/null
+++ b/sys/src/cmd/spin/mesg.c
@@ -0,0 +1,644 @@
+/***** spin: mesg.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include "spin.h"
+#include "y.tab.h"
+
+#ifndef MAXQ
+#define MAXQ 2500 /* default max # queues */
+#endif
+
+extern RunList *X;
+extern Symbol *Fname;
+extern Lextok *Mtype;
+extern int verbose, TstOnly, s_trail, analyze, columns;
+extern int lineno, depth, xspin, m_loss, jumpsteps;
+extern int nproc, nstop;
+extern short Have_claim;
+
+Queue *qtab = (Queue *) 0; /* linked list of queues */
+Queue *ltab[MAXQ]; /* linear list of queues */
+int nqs = 0, firstrow = 1;
+char Buf[4096];
+
+static Lextok *n_rem = (Lextok *) 0;
+static Queue *q_rem = (Queue *) 0;
+
+static int a_rcv(Queue *, Lextok *, int);
+static int a_snd(Queue *, Lextok *);
+static int sa_snd(Queue *, Lextok *);
+static int s_snd(Queue *, Lextok *);
+extern void sr_buf(int, int);
+extern void sr_mesg(FILE *, int, int);
+extern void putarrow(int, int);
+static void sr_talk(Lextok *, int, char *, char *, int, Queue *);
+
+int
+cnt_mpars(Lextok *n)
+{ Lextok *m;
+ int i=0;
+
+ for (m = n; m; m = m->rgt)
+ i += Cnt_flds(m);
+ return i;
+}
+
+int
+qmake(Symbol *s)
+{ Lextok *m;
+ Queue *q;
+ int i;
+
+ if (!s->ini)
+ return 0;
+
+ if (nqs >= MAXQ)
+ { lineno = s->ini->ln;
+ Fname = s->ini->fn;
+ fatal("too many queues (%s)", s->name);
+ }
+ if (analyze && nqs >= 255)
+ { fatal("too many channel types", (char *)0);
+ }
+
+ if (s->ini->ntyp != CHAN)
+ return eval(s->ini);
+
+ q = (Queue *) emalloc(sizeof(Queue));
+ q->qid = ++nqs;
+ q->nslots = s->ini->val;
+ q->nflds = cnt_mpars(s->ini->rgt);
+ q->setat = depth;
+
+ i = max(1, q->nslots); /* 0-slot qs get 1 slot minimum */
+
+ q->contents = (int *) emalloc(q->nflds*i*sizeof(int));
+ q->fld_width = (int *) emalloc(q->nflds*sizeof(int));
+ q->stepnr = (int *) emalloc(i*sizeof(int));
+
+ for (m = s->ini->rgt, i = 0; m; m = m->rgt)
+ { if (m->sym && m->ntyp == STRUCT)
+ i = Width_set(q->fld_width, i, getuname(m->sym));
+ else
+ q->fld_width[i++] = m->ntyp;
+ }
+ q->nxt = qtab;
+ qtab = q;
+ ltab[q->qid-1] = q;
+
+ return q->qid;
+}
+
+int
+qfull(Lextok *n)
+{ int whichq = eval(n->lft)-1;
+
+ if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
+ return (ltab[whichq]->qlen >= ltab[whichq]->nslots);
+ return 0;
+}
+
+int
+qlen(Lextok *n)
+{ int whichq = eval(n->lft)-1;
+
+ if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
+ return ltab[whichq]->qlen;
+ return 0;
+}
+
+int
+q_is_sync(Lextok *n)
+{ int whichq = eval(n->lft)-1;
+
+ if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
+ return (ltab[whichq]->nslots == 0);
+ return 0;
+}
+
+int
+qsend(Lextok *n)
+{ int whichq = eval(n->lft)-1;
+
+ if (whichq == -1)
+ { printf("Error: sending to an uninitialized chan\n");
+ whichq = 0;
+ return 0;
+ }
+ if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
+ { ltab[whichq]->setat = depth;
+ if (ltab[whichq]->nslots > 0)
+ return a_snd(ltab[whichq], n);
+ else
+ return s_snd(ltab[whichq], n);
+ }
+ return 0;
+}
+
+int
+qrecv(Lextok *n, int full)
+{ int whichq = eval(n->lft)-1;
+
+ if (whichq == -1)
+ { if (n->sym && !strcmp(n->sym->name, "STDIN"))
+ { Lextok *m;
+
+ if (TstOnly) return 1;
+
+ for (m = n->rgt; m; m = m->rgt)
+ if (m->lft->ntyp != CONST && m->lft->ntyp != EVAL)
+ { int c = getchar();
+ (void) setval(m->lft, c);
+ } else
+ fatal("invalid use of STDIN", (char *)0);
+
+ whichq = 0;
+ return 1;
+ }
+ printf("Error: receiving from an uninitialized chan %s\n",
+ n->sym?n->sym->name:"");
+ whichq = 0;
+ return 0;
+ }
+ if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
+ { ltab[whichq]->setat = depth;
+ return a_rcv(ltab[whichq], n, full);
+ }
+ return 0;
+}
+
+static int
+sa_snd(Queue *q, Lextok *n) /* sorted asynchronous */
+{ Lextok *m;
+ int i, j, k;
+ int New, Old;
+
+ for (i = 0; i < q->qlen; i++)
+ for (j = 0, m = n->rgt; m && j < q->nflds; m = m->rgt, j++)
+ { New = cast_val(q->fld_width[j], eval(m->lft), 0);
+ Old = q->contents[i*q->nflds+j];
+ if (New == Old) continue;
+ if (New > Old) break; /* inner loop */
+ if (New < Old) goto found;
+ }
+found:
+ for (j = q->qlen-1; j >= i; j--)
+ for (k = 0; k < q->nflds; k++)
+ { q->contents[(j+1)*q->nflds+k] =
+ q->contents[j*q->nflds+k]; /* shift up */
+ if (k == 0)
+ q->stepnr[j+1] = q->stepnr[j];
+ }
+ return i*q->nflds; /* new q offset */
+}
+
+void
+typ_ck(int ft, int at, char *s)
+{
+ if ((verbose&32) && ft != at
+ && (ft == CHAN || at == CHAN))
+ { char buf[128], tag1[64], tag2[64];
+ (void) sputtype(tag1, ft);
+ (void) sputtype(tag2, at);
+ sprintf(buf, "type-clash in %s, (%s<-> %s)", s, tag1, tag2);
+ non_fatal("%s", buf);
+ }
+}
+
+static int
+a_snd(Queue *q, Lextok *n)
+{ Lextok *m;
+ int i = q->qlen*q->nflds; /* q offset */
+ int j = 0; /* q field# */
+
+ if (q->nslots > 0 && q->qlen >= q->nslots)
+ return m_loss; /* q is full */
+
+ if (TstOnly) return 1;
+
+ if (n->val) i = sa_snd(q, n); /* sorted insert */
+
+ q->stepnr[i/q->nflds] = depth;
+
+ for (m = n->rgt; m && j < q->nflds; m = m->rgt, j++)
+ { int New = eval(m->lft);
+ q->contents[i+j] = cast_val(q->fld_width[j], New, 0);
+ if ((verbose&16) && depth >= jumpsteps)
+ sr_talk(n, New, "Send ", "->", j, q);
+ typ_ck(q->fld_width[j], Sym_typ(m->lft), "send");
+ }
+ if ((verbose&16) && depth >= jumpsteps)
+ { for (i = j; i < q->nflds; i++)
+ sr_talk(n, 0, "Send ", "->", i, q);
+ if (j < q->nflds)
+ printf("%3d: warning: missing params in send\n",
+ depth);
+ if (m)
+ printf("%3d: warning: too many params in send\n",
+ depth);
+ }
+ q->qlen++;
+ return 1;
+}
+
+static int
+a_rcv(Queue *q, Lextok *n, int full)
+{ Lextok *m;
+ int i=0, oi, j, k;
+ extern int Rvous;
+
+ if (q->qlen == 0)
+ return 0; /* q is empty */
+try_slot:
+ /* test executability */
+ for (m = n->rgt, j=0; m && j < q->nflds; m = m->rgt, j++)
+ if ((m->lft->ntyp == CONST
+ && q->contents[i*q->nflds+j] != m->lft->val)
+ || (m->lft->ntyp == EVAL
+ && q->contents[i*q->nflds+j] != eval(m->lft->lft)))
+ { if (n->val == 0 /* fifo recv */
+ || n->val == 2 /* fifo poll */
+ || ++i >= q->qlen) /* last slot */
+ return 0; /* no match */
+ goto try_slot;
+ }
+ if (TstOnly) return 1;
+
+ if (verbose&8)
+ { if (j < q->nflds)
+ printf("%3d: warning: missing params in next recv\n",
+ depth);
+ else if (m)
+ printf("%3d: warning: too many params in next recv\n",
+ depth);
+ }
+
+ /* set the fields */
+ if (Rvous)
+ { n_rem = n;
+ q_rem = q;
+ }
+
+ oi = q->stepnr[i];
+ for (m = n->rgt, j = 0; m && j < q->nflds; m = m->rgt, j++)
+ { if (columns && !full) /* was columns == 1 */
+ continue;
+ if ((verbose&8) && !Rvous && depth >= jumpsteps)
+ { sr_talk(n, q->contents[i*q->nflds+j],
+ (full && n->val < 2)?"Recv ":"[Recv] ", "<-", j, q);
+ }
+ if (!full)
+ continue; /* test */
+ if (m && m->lft->ntyp != CONST && m->lft->ntyp != EVAL)
+ { (void) setval(m->lft, q->contents[i*q->nflds+j]);
+ typ_ck(q->fld_width[j], Sym_typ(m->lft), "recv");
+ }
+ if (n->val < 2) /* not a poll */
+ for (k = i; k < q->qlen-1; k++)
+ { q->contents[k*q->nflds+j] =
+ q->contents[(k+1)*q->nflds+j];
+ if (j == 0)
+ q->stepnr[k] = q->stepnr[k+1];
+ }
+ }
+
+ if ((!columns || full)
+ && (verbose&8) && !Rvous && depth >= jumpsteps)
+ for (i = j; i < q->nflds; i++)
+ { sr_talk(n, 0,
+ (full && n->val < 2)?"Recv ":"[Recv] ", "<-", i, q);
+ }
+ if (columns == 2 && full && !Rvous && depth >= jumpsteps)
+ putarrow(oi, depth);
+
+ if (full && n->val < 2)
+ q->qlen--;
+ return 1;
+}
+
+static int
+s_snd(Queue *q, Lextok *n)
+{ Lextok *m;
+ RunList *rX, *sX = X; /* rX=recvr, sX=sendr */
+ int i, j = 0; /* q field# */
+
+ for (m = n->rgt; m && j < q->nflds; m = m->rgt, j++)
+ { q->contents[j] = cast_val(q->fld_width[j], eval(m->lft), 0);
+ typ_ck(q->fld_width[j], Sym_typ(m->lft), "rv-send");
+ }
+ q->qlen = 1;
+ if (!complete_rendez())
+ { q->qlen = 0;
+ return 0;
+ }
+ if (TstOnly)
+ { q->qlen = 0;
+ return 1;
+ }
+ q->stepnr[0] = depth;
+ if ((verbose&16) && depth >= jumpsteps)
+ { m = n->rgt;
+ rX = X; X = sX;
+ for (j = 0; m && j < q->nflds; m = m->rgt, j++)
+ sr_talk(n, eval(m->lft), "Sent ", "->", j, q);
+ for (i = j; i < q->nflds; i++)
+ sr_talk(n, 0, "Sent ", "->", i, q);
+ if (j < q->nflds)
+ printf("%3d: warning: missing params in rv-send\n",
+ depth);
+ else if (m)
+ printf("%3d: warning: too many params in rv-send\n",
+ depth);
+ X = rX; /* restore receiver's context */
+ if (!s_trail)
+ { if (!n_rem || !q_rem)
+ fatal("cannot happen, s_snd", (char *) 0);
+ m = n_rem->rgt;
+ for (j = 0; m && j < q->nflds; m = m->rgt, j++)
+ { if (m->lft->ntyp != NAME
+ || strcmp(m->lft->sym->name, "_") != 0)
+ i = eval(m->lft);
+ else i = 0;
+
+ if (verbose&8)
+ sr_talk(n_rem,i,"Recv ","<-",j,q_rem);
+ }
+ if (verbose&8)
+ for (i = j; i < q->nflds; i++)
+ sr_talk(n_rem, 0, "Recv ", "<-", j, q_rem);
+ if (columns == 2)
+ putarrow(depth, depth);
+ }
+ n_rem = (Lextok *) 0;
+ q_rem = (Queue *) 0;
+ }
+ return 1;
+}
+
+void
+channm(Lextok *n)
+{ char lbuf[512];
+
+ if (n->sym->type == CHAN)
+ strcat(Buf, n->sym->name);
+ else if (n->sym->type == NAME)
+ strcat(Buf, lookup(n->sym->name)->name);
+ else if (n->sym->type == STRUCT)
+ { Symbol *r = n->sym;
+ if (r->context)
+ r = findloc(r);
+ ini_struct(r);
+ printf("%s", r->name);
+ strcpy(lbuf, "");
+ struct_name(n->lft, r, 1, lbuf);
+ strcat(Buf, lbuf);
+ } else
+ strcat(Buf, "-");
+ if (n->lft->lft)
+ { sprintf(lbuf, "[%d]", eval(n->lft->lft));
+ strcat(Buf, lbuf);
+ }
+}
+
+static void
+difcolumns(Lextok *n, char *tr, int v, int j, Queue *q)
+{ extern int pno;
+
+ if (j == 0)
+ { Buf[0] = '\0';
+ channm(n);
+ strcat(Buf, (strncmp(tr, "Sen", 3))?"?":"!");
+ } else
+ strcat(Buf, ",");
+ if (tr[0] == '[') strcat(Buf, "[");
+ sr_buf(v, q->fld_width[j] == MTYPE);
+ if (j == q->nflds - 1)
+ { int cnr;
+ if (s_trail) cnr = pno; else cnr = X?X->pid - Have_claim:0;
+ if (tr[0] == '[') strcat(Buf, "]");
+ pstext(cnr, Buf);
+ }
+}
+
+static void
+docolumns(Lextok *n, char *tr, int v, int j, Queue *q)
+{ int i;
+
+ if (firstrow)
+ { printf("q\\p");
+ for (i = 0; i < nproc-nstop - Have_claim; i++)
+ printf(" %3d", i);
+ printf("\n");
+ firstrow = 0;
+ }
+ if (j == 0)
+ { printf("%3d", q->qid);
+ if (X)
+ for (i = 0; i < X->pid - Have_claim; i++)
+ printf(" .");
+ printf(" ");
+ Buf[0] = '\0';
+ channm(n);
+ printf("%s%c", Buf, (strncmp(tr, "Sen", 3))?'?':'!');
+ } else
+ printf(",");
+ if (tr[0] == '[') printf("[");
+ sr_mesg(stdout, v, q->fld_width[j] == MTYPE);
+ if (j == q->nflds - 1)
+ { if (tr[0] == '[') printf("]");
+ printf("\n");
+ }
+}
+
+typedef struct QH {
+ int n;
+ struct QH *nxt;
+} QH;
+QH *qh;
+
+void
+qhide(int q)
+{ QH *p = (QH *) emalloc(sizeof(QH));
+ p->n = q;
+ p->nxt = qh;
+ qh = p;
+}
+
+int
+qishidden(int q)
+{ QH *p;
+ for (p = qh; p; p = p->nxt)
+ if (p->n == q)
+ return 1;
+ return 0;
+}
+
+static void
+sr_talk(Lextok *n, int v, char *tr, char *a, int j, Queue *q)
+{ char s[64];
+
+ if (qishidden(eval(n->lft)))
+ return;
+
+ if (columns)
+ { if (columns == 2)
+ difcolumns(n, tr, v, j, q);
+ else
+ docolumns(n, tr, v, j, q);
+ return;
+ }
+ if (xspin)
+ { if ((verbose&4) && tr[0] != '[')
+ sprintf(s, "(state -)\t[values: %d",
+ eval(n->lft));
+ else
+ sprintf(s, "(state -)\t[%d", eval(n->lft));
+ if (strncmp(tr, "Sen", 3) == 0)
+ strcat(s, "!");
+ else
+ strcat(s, "?");
+ } else
+ { strcpy(s, tr);
+ }
+
+ if (j == 0)
+ { whoruns(1);
+ printf("line %3d %s %s",
+ n->ln, n->fn->name, s);
+ } else
+ printf(",");
+ sr_mesg(stdout, v, q->fld_width[j] == MTYPE);
+
+ if (j == q->nflds - 1)
+ { if (xspin)
+ { printf("]\n");
+ if (!(verbose&4)) printf("\n");
+ return;
+ }
+ printf("\t%s queue %d (", a, eval(n->lft));
+ Buf[0] = '\0';
+ channm(n);
+ printf("%s)\n", Buf);
+ }
+ fflush(stdout);
+}
+
+void
+sr_buf(int v, int j)
+{ int cnt = 1; Lextok *n;
+ char lbuf[512];
+
+ for (n = Mtype; n && j; n = n->rgt, cnt++)
+ if (cnt == v)
+ { if(strlen(n->lft->sym->name) >= sizeof(lbuf))
+ { non_fatal("mtype name %s too long", n->lft->sym->name);
+ break;
+ }
+ sprintf(lbuf, "%s", n->lft->sym->name);
+ strcat(Buf, lbuf);
+ return;
+ }
+ sprintf(lbuf, "%d", v);
+ strcat(Buf, lbuf);
+}
+
+void
+sr_mesg(FILE *fd, int v, int j)
+{ Buf[0] ='\0';
+ sr_buf(v, j);
+ fprintf(fd, Buf);
+}
+
+void
+doq(Symbol *s, int n, RunList *r)
+{ Queue *q;
+ int j, k;
+
+ if (!s->val) /* uninitialized queue */
+ return;
+ for (q = qtab; q; q = q->nxt)
+ if (q->qid == s->val[n])
+ { if (xspin > 0
+ && (verbose&4)
+ && q->setat < depth)
+ continue;
+ if (q->nslots == 0)
+ continue; /* rv q always empty */
+ printf("\t\tqueue %d (", q->qid);
+ if (r)
+ printf("%s(%d):", r->n->name, r->pid - Have_claim);
+ if (s->nel != 1)
+ printf("%s[%d]): ", s->name, n);
+ else
+ printf("%s): ", s->name);
+ for (k = 0; k < q->qlen; k++)
+ { printf("[");
+ for (j = 0; j < q->nflds; j++)
+ { if (j > 0) printf(",");
+ sr_mesg(stdout, q->contents[k*q->nflds+j],
+ q->fld_width[j] == MTYPE);
+ }
+ printf("]");
+ }
+ printf("\n");
+ break;
+ }
+}
+
+void
+nochan_manip(Lextok *p, Lextok *n, int d)
+{ int e = 1;
+
+ if (d == 0 && p->sym && p->sym->type == CHAN)
+ { setaccess(p->sym, ZS, 0, 'L');
+
+ if (n && n->ntyp == CONST)
+ fatal("invalid asgn to chan", (char *) 0);
+
+ if (n && n->sym && n->sym->type == CHAN)
+ { setaccess(n->sym, ZS, 0, 'V');
+ return;
+ }
+ }
+
+ if (!n || n->ntyp == LEN || n->ntyp == RUN)
+ return;
+
+ if (n->sym && n->sym->type == CHAN)
+ { if (d == 1)
+ fatal("invalid use of chan name", (char *) 0);
+ else
+ setaccess(n->sym, ZS, 0, 'V');
+ }
+
+ if (n->ntyp == NAME
+ || n->ntyp == '.')
+ e = 0; /* array index or struct element */
+
+ nochan_manip(p, n->lft, e);
+ nochan_manip(p, n->rgt, 1);
+}
+
+void
+no_internals(Lextok *n)
+{ char *sp;
+
+ if (!n->sym
+ || !n->sym->name)
+ return;
+
+ sp = n->sym->name;
+
+ if ((strlen(sp) == strlen("_nr_pr") && strcmp(sp, "_nr_pr") == 0)
+ || (strlen(sp) == strlen("_p") && strcmp(sp, "_p") == 0))
+ { fatal("attempt to assign value to system variable %s", sp);
+ }
+}
diff --git a/sys/src/cmd/spin/mkfile b/sys/src/cmd/spin/mkfile
new file mode 100755
index 000000000..abbef6239
--- /dev/null
+++ b/sys/src/cmd/spin/mkfile
@@ -0,0 +1,56 @@
+</$objtype/mkfile
+
+TARG=spin
+
+SPIN_OS=\
+ dstep.$O\
+ flow.$O\
+ guided.$O\
+ main.$O\
+ mesg.$O\
+ pangen1.$O\
+ pangen2.$O\
+ pangen3.$O\
+ pangen4.$O\
+ pangen5.$O\
+ pangen6.$O\
+ pc_zpp.$O\
+ ps_msc.$O\
+ reprosrc.$O\
+ run.$O\
+ sched.$O\
+ spinlex.$O\
+ structs.$O\
+ sym.$O\
+ vars.$O\
+ y.tab.$O\
+
+TL_OS=\
+ tl_buchi.$O\
+ tl_cache.$O\
+ tl_lex.$O\
+ tl_main.$O\
+ tl_mem.$O\
+ tl_parse.$O\
+ tl_rewrt.$O\
+ tl_trans.$O\
+
+OFILES=$SPIN_OS $TL_OS
+
+YFILES=spin.y
+
+HFILES=y.tab.h
+
+BIN=/$objtype/bin
+</sys/src/cmd/mkone
+
+CC=pcc -c
+CFLAGS=-B -D_POSIX_SOURCE
+YFLAGS=-S -d
+
+$SPIN_OS: spin.h
+$TL_OS: tl.h
+
+main.$O pangen2.$O ps_msc.$O: version.h
+pangen1.$O: pangen1.h pangen3.h
+pangen2.$O: pangen2.h pangen4.h pangen5.h
diff --git a/sys/src/cmd/spin/pangen1.c b/sys/src/cmd/spin/pangen1.c
new file mode 100755
index 000000000..cbef9dba5
--- /dev/null
+++ b/sys/src/cmd/spin/pangen1.c
@@ -0,0 +1,1275 @@
+/***** spin: pangen1.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include "spin.h"
+#include "y.tab.h"
+#include "pangen1.h"
+#include "pangen3.h"
+
+extern FILE *tc, *th, *tt;
+extern Label *labtab;
+extern Ordered *all_names;
+extern ProcList *rdy;
+extern Queue *qtab;
+extern Symbol *Fname;
+extern int lineno, verbose, Pid, separate;
+extern int nrRdy, nqs, mst, Mpars, claimnr, eventmapnr;
+extern short has_sorted, has_random, has_provided;
+
+int Npars=0, u_sync=0, u_async=0, hastrack = 1;
+short has_io = 0;
+short has_state=0; /* code contains c_state */
+
+static Symbol *LstSet=ZS;
+static int acceptors=0, progressors=0, nBits=0;
+static int Types[] = { UNSIGNED, BIT, BYTE, CHAN, MTYPE, SHORT, INT, STRUCT };
+
+static int doglobal(char *, int);
+static void dohidden(void);
+static void do_init(FILE *, Symbol *);
+static void end_labs(Symbol *, int);
+static void put_ptype(char *, int, int, int);
+static void tc_predef_np(void);
+static void put_pinit(ProcList *);
+ void walk_struct(FILE *, int, char *, Symbol *, char *, char *, char *);
+
+static void
+reverse_names(ProcList *p)
+{
+ if (!p) return;
+ reverse_names(p->nxt);
+ fprintf(th, " \"%s\",\n", p->n->name);
+}
+
+void
+genheader(void)
+{ ProcList *p; int i;
+
+ if (separate == 2)
+ { putunames(th);
+ goto here;
+ }
+
+ fprintf(th, "#define SYNC %d\n", u_sync);
+ fprintf(th, "#define ASYNC %d\n\n", u_async);
+
+ putunames(th);
+
+ fprintf(tc, "short Air[] = { ");
+ for (p = rdy, i=0; p; p = p->nxt, i++)
+ fprintf(tc, "%s (short) Air%d", (p!=rdy)?",":"", i);
+ fprintf(tc, ", (short) Air%d", i); /* np_ */
+ fprintf(tc, " };\n");
+
+ fprintf(th, "char *procname[] = {\n");
+ reverse_names(rdy);
+ fprintf(th, " \":np_:\",\n");
+ fprintf(th, "};\n\n");
+
+here:
+ for (p = rdy; p; p = p->nxt)
+ put_ptype(p->n->name, p->tn, mst, nrRdy+1);
+ /* +1 for np_ */
+ put_ptype("np_", nrRdy, mst, nrRdy+1);
+
+ ntimes(th, 0, 1, Head0);
+
+ if (separate != 2)
+ { extern void c_add_stack(FILE *);
+
+ ntimes(th, 0, 1, Header);
+ c_add_stack(th);
+ ntimes(th, 0, 1, Header0);
+ }
+ ntimes(th, 0, 1, Head1);
+
+ LstSet = ZS;
+ (void) doglobal("", PUTV);
+
+ hastrack = c_add_sv(th);
+
+ fprintf(th, " uchar sv[VECTORSZ];\n");
+ fprintf(th, "} State");
+#ifdef SOLARIS
+ fprintf(th,"\n#ifdef GCC\n");
+ fprintf(th, "\t__attribute__ ((aligned(8)))");
+ fprintf(th, "\n#endif\n\t");
+#endif
+ fprintf(th, ";\n\n");
+
+ fprintf(th, "#define HAS_TRACK %d\n", hastrack);
+
+ if (separate != 2)
+ dohidden();
+}
+
+void
+genaddproc(void)
+{ ProcList *p;
+ int i = 0;
+
+ if (separate ==2) goto shortcut;
+
+ fprintf(tc, "int\naddproc(int n");
+ for (i = 0; i < Npars; i++)
+ fprintf(tc, ", int par%d", i);
+
+ ntimes(tc, 0, 1, Addp0);
+ ntimes(tc, 1, nrRdy+1, R5); /* +1 for np_ */
+ ntimes(tc, 0, 1, Addp1);
+
+ if (has_provided)
+ { fprintf(tt, "\nint\nprovided(int II, unsigned char ot, ");
+ fprintf(tt, "int tt, Trans *t)\n");
+ fprintf(tt, "{\n\tswitch(ot) {\n");
+ }
+shortcut:
+ tc_predef_np();
+ for (p = rdy; p; p = p->nxt)
+ { Pid = p->tn;
+ put_pinit(p);
+ }
+ if (separate == 2) return;
+
+ Pid = 0;
+ if (has_provided)
+ { fprintf(tt, "\tdefault: return 1; /* e.g., a claim */\n");
+ fprintf(tt, "\t}\n\treturn 0;\n}\n");
+ }
+
+ ntimes(tc, i, i+1, R6);
+ if (separate == 0)
+ ntimes(tc, 1, nrRdy+1, R5); /* +1 for np_ */
+ else
+ ntimes(tc, 1, nrRdy, R5);
+ ntimes(tc, 0, 1, R8a);
+}
+
+void
+do_locinits(FILE *fd)
+{ ProcList *p;
+
+ for (p = rdy; p; p = p->nxt)
+ c_add_locinit(fd, p->tn, p->n->name);
+}
+
+void
+genother(void)
+{ ProcList *p;
+
+ switch (separate) {
+ case 2:
+ if (claimnr >= 0)
+ ntimes(tc, claimnr, claimnr+1, R0); /* claim only */
+ break;
+ case 1:
+ ntimes(tc, 0, 1, Code0);
+ ntimes(tc, 0, claimnr, R0); /* all except claim */
+ ntimes(tc, claimnr+1, nrRdy, R0);
+ break;
+ case 0:
+ ntimes(tc, 0, 1, Code0);
+ ntimes(tc, 0, nrRdy+1, R0); /* +1 for np_ */
+ break;
+ }
+
+ for (p = rdy; p; p = p->nxt)
+ end_labs(p->n, p->tn);
+
+ switch (separate) {
+ case 2:
+ if (claimnr >= 0)
+ ntimes(tc, claimnr, claimnr+1, R0a); /* claim only */
+ return;
+ case 1:
+ ntimes(tc, 0, claimnr, R0a); /* all except claim */
+ ntimes(tc, claimnr+1, nrRdy, R0a);
+ fprintf(tc, " if (state_tables)\n");
+ fprintf(tc, " ini_claim(%d, 0);\n", claimnr);
+ break;
+ case 0:
+ ntimes(tc, 0, nrRdy, R0a); /* all */
+ break;
+ }
+
+ ntimes(tc, 0, 1, R0b);
+ if (separate == 1 && acceptors == 0)
+ acceptors = 1; /* assume at least 1 acceptstate */
+ ntimes(th, acceptors, acceptors+1, Code1);
+ ntimes(th, progressors, progressors+1, Code3);
+ ntimes(th, nrRdy+1, nrRdy+2, R2); /* +1 for np_ */
+
+ fprintf(tc, " iniglobals();\n");
+ ntimes(tc, 0, 1, Code2a);
+ ntimes(tc, 0, 1, Code2b); /* bfs option */
+ ntimes(tc, 0, 1, Code2c);
+ ntimes(tc, 0, nrRdy, R4);
+ fprintf(tc, "}\n\n");
+
+ fprintf(tc, "void\n");
+ fprintf(tc, "iniglobals(void)\n{\n");
+ if (doglobal("", INIV) > 0)
+ { fprintf(tc, "#ifdef VAR_RANGES\n");
+ (void) doglobal("logval(\"", LOGV);
+ fprintf(tc, "#endif\n");
+ }
+ ntimes(tc, 1, nqs+1, R3);
+ fprintf(tc, "\tMaxbody = max(Maxbody, sizeof(State)-VECTORSZ);");
+ fprintf(tc, "\n}\n\n");
+}
+
+void
+gensvmap(void)
+{
+ ntimes(tc, 0, 1, SvMap);
+}
+
+static struct {
+ char *s, *t; int n, m, p;
+} ln[] = {
+ {"end", "stopstate", 3, 0, 0},
+ {"progress", "progstate", 8, 0, 1},
+ {"accept", "accpstate", 6, 1, 0},
+ {0, 0, 0, 0, 0},
+};
+
+static void
+end_labs(Symbol *s, int i)
+{ int oln = lineno;
+ Symbol *ofn = Fname;
+ Label *l;
+ int j; char foo[128];
+
+ if ((i == claimnr && separate == 1)
+ || (i != claimnr && separate == 2))
+ return;
+
+ for (l = labtab; l; l = l->nxt)
+ for (j = 0; ln[j].n; j++)
+ if (strncmp(l->s->name, ln[j].s, ln[j].n) == 0
+ && strcmp(l->c->name, s->name) == 0)
+ { fprintf(tc, "\t%s[%d][%d] = 1;\n",
+ ln[j].t, i, l->e->seqno);
+ acceptors += ln[j].m;
+ progressors += ln[j].p;
+ if (l->e->status & D_ATOM)
+ { sprintf(foo, "%s label inside d_step",
+ ln[j].s);
+ goto complain;
+ }
+ if (j > 0 && (l->e->status & ATOM))
+ { sprintf(foo, "%s label inside atomic",
+ ln[j].s);
+ complain: lineno = l->e->n->ln;
+ Fname = l->e->n->fn;
+ printf("spin: %3d:%s, warning, %s - is invisible\n",
+ lineno, Fname?Fname->name:"-", foo);
+ }
+ }
+ /* visible states -- through remote refs: */
+ for (l = labtab; l; l = l->nxt)
+ if (l->visible
+ && strcmp(l->s->context->name, s->name) == 0)
+ fprintf(tc, "\tvisstate[%d][%d] = 1;\n",
+ i, l->e->seqno);
+
+ lineno = oln;
+ Fname = ofn;
+}
+
+void
+ntimes(FILE *fd, int n, int m, char *c[])
+{
+ int i, j;
+ for (j = 0; c[j]; j++)
+ for (i = n; i < m; i++)
+ { fprintf(fd, c[j], i, i, i, i, i, i);
+ fprintf(fd, "\n");
+ }
+}
+
+void
+prehint(Symbol *s)
+{ Lextok *n;
+
+ printf("spin: warning, ");
+ if (!s) return;
+
+ n = (s->context != ZS)?s->context->ini:s->ini;
+ if (n)
+ printf("line %3d %s, ", n->ln, n->fn->name);
+}
+
+void
+checktype(Symbol *sp, char *s)
+{ char buf[128]; int i;
+
+ if (!s
+ || (sp->type != BYTE
+ && sp->type != SHORT
+ && sp->type != INT))
+ return;
+
+ if (sp->hidden&16) /* formal parameter */
+ { ProcList *p; Lextok *f, *t;
+ int posnr = 0;
+ for (p = rdy; p; p = p->nxt)
+ if (p->n->name
+ && strcmp(s, p->n->name) == 0)
+ break;
+ if (p)
+ for (f = p->p; f; f = f->rgt) /* list of types */
+ for (t = f->lft; t; t = t->rgt, posnr++)
+ if (t->sym
+ && strcmp(t->sym->name, sp->name) == 0)
+ { checkrun(sp, posnr);
+ return;
+ }
+
+ } else if (!(sp->hidden&4))
+ { if (!(verbose&32)) return;
+ sputtype(buf, sp->type);
+ i = (int) strlen(buf);
+ while (buf[--i] == ' ') buf[i] = '\0';
+ prehint(sp);
+ if (sp->context)
+ printf("proctype %s:", s);
+ else
+ printf("global");
+ printf(" '%s %s' could be declared 'bit %s'\n",
+ buf, sp->name, sp->name);
+ } else if (sp->type != BYTE && !(sp->hidden&8))
+ { if (!(verbose&32)) return;
+ sputtype(buf, sp->type);
+ i = (int) strlen(buf);
+ while (buf[--i] == ' ') buf[i] = '\0';
+ prehint(sp);
+ if (sp->context)
+ printf("proctype %s:", s);
+ else
+ printf("global");
+ printf(" '%s %s' could be declared 'byte %s'\n",
+ buf, sp->name, sp->name);
+ }
+}
+
+int
+dolocal(FILE *ofd, char *pre, int dowhat, int p, char *s)
+{ int h, j, k=0; extern int nr_errs;
+ Ordered *walk;
+ Symbol *sp;
+ char buf[64], buf2[128], buf3[128];
+
+ if (dowhat == INIV)
+ { /* initialize in order of declaration */
+ for (walk = all_names; walk; walk = walk->next)
+ { sp = walk->entry;
+ if (sp->context
+ && !sp->owner
+ && strcmp(s, sp->context->name) == 0)
+ { checktype(sp, s); /* fall through */
+ if (!(sp->hidden&16))
+ { sprintf(buf, "((P%d *)pptr(h))->", p);
+ do_var(ofd, dowhat, buf, sp, "", " = ", ";\n");
+ }
+ k++;
+ } }
+ } else
+ { for (j = 0; j < 8; j++)
+ for (h = 0; h <= 1; h++)
+ for (walk = all_names; walk; walk = walk->next)
+ { sp = walk->entry;
+ if (sp->context
+ && !sp->owner
+ && sp->type == Types[j]
+ && ((h == 0 && sp->nel == 1) || (h == 1 && sp->nel > 1))
+ && strcmp(s, sp->context->name) == 0)
+ { switch (dowhat) {
+ case LOGV:
+ if (sp->type == CHAN
+ && verbose == 0)
+ break;
+ sprintf(buf, "%s%s:", pre, s);
+ { sprintf(buf2, "\", ((P%d *)pptr(h))->", p);
+ sprintf(buf3, ");\n");
+ }
+ do_var(ofd, dowhat, "", sp, buf, buf2, buf3);
+ break;
+ case PUTV:
+ sprintf(buf, "((P%d *)pptr(h))->", p);
+ do_var(ofd, dowhat, buf, sp, "", " = ", ";\n");
+ k++;
+ break;
+ }
+ if (strcmp(s, ":never:") == 0)
+ { printf("error: %s defines local %s\n",
+ s, sp->name);
+ nr_errs++;
+ } } } }
+
+ return k;
+}
+
+void
+c_chandump(FILE *fd)
+{ Queue *q;
+ char buf[256];
+ int i;
+
+ if (!qtab)
+ { fprintf(fd, "void\nc_chandump(int unused) ");
+ fprintf(fd, "{ unused = unused++; /* avoid complaints */ }\n");
+ return;
+ }
+
+ fprintf(fd, "void\nc_chandump(int from)\n");
+ fprintf(fd, "{ uchar *z; int slot;\n");
+
+ fprintf(fd, " from--;\n");
+ fprintf(fd, " if (from >= (int) now._nr_qs || from < 0)\n");
+ fprintf(fd, " { printf(\"pan: bad qid %%d\\n\", from+1);\n");
+ fprintf(fd, " return;\n");
+ fprintf(fd, " }\n");
+ fprintf(fd, " z = qptr(from);\n");
+ fprintf(fd, " switch (((Q0 *)z)->_t) {\n");
+
+ for (q = qtab; q; q = q->nxt)
+ { fprintf(fd, " case %d:\n\t\t", q->qid);
+ sprintf(buf, "((Q%d *)z)->", q->qid);
+
+ fprintf(fd, "for (slot = 0; slot < %sQlen; slot++)\n\t\t", buf);
+ fprintf(fd, "{ printf(\" [\");\n\t\t");
+ for (i = 0; i < q->nflds; i++)
+ { if (q->fld_width[i] == MTYPE)
+ { fprintf(fd, "\tprintm(%scontents[slot].fld%d);\n\t\t",
+ buf, i);
+ } else
+ fprintf(fd, "\tprintf(\"%%d,\", %scontents[slot].fld%d);\n\t\t",
+ buf, i);
+ }
+ fprintf(fd, " printf(\"],\");\n\t\t");
+ fprintf(fd, "}\n\t\t");
+ fprintf(fd, "break;\n");
+ }
+ fprintf(fd, " }\n");
+ fprintf(fd, " printf(\"\\n\");\n}\n");
+}
+
+void
+c_var(FILE *fd, char *pref, Symbol *sp)
+{ char buf[256];
+ int i;
+
+ switch (sp->type) {
+ case STRUCT:
+ /* c_struct(fd, pref, sp); */
+ fprintf(fd, "\t\tprintf(\"\t(struct %s)\\n\");\n",
+ sp->name);
+ sprintf(buf, "%s%s.", pref, sp->name);
+ c_struct(fd, buf, sp);
+ break;
+ case BIT: case BYTE:
+ case SHORT: case INT:
+ case UNSIGNED:
+ sputtype(buf, sp->type);
+ if (sp->nel == 1)
+ { fprintf(fd, "\tprintf(\"\t%s %s:\t%%d\\n\", %s%s);\n",
+ buf, sp->name, pref, sp->name);
+ } else
+ { fprintf(fd, "\t{\tint l_in;\n");
+ fprintf(fd, "\t\tfor (l_in = 0; l_in < %d; l_in++)\n", sp->nel);
+ fprintf(fd, "\t\t{\n");
+ fprintf(fd, "\t\t\tprintf(\"\t%s %s[%%d]:\t%%d\\n\", l_in, %s%s[l_in]);\n",
+ buf, sp->name, pref, sp->name);
+ fprintf(fd, "\t\t}\n");
+ fprintf(fd, "\t}\n");
+ }
+ break;
+ case CHAN:
+ if (sp->nel == 1)
+ { fprintf(fd, "\tprintf(\"\tchan %s (=%%d):\tlen %%d:\\t\", ",
+ sp->name);
+ fprintf(fd, "%s%s, q_len(%s%s));\n",
+ pref, sp->name, pref, sp->name);
+ fprintf(fd, "\tc_chandump(%s%s);\n", pref, sp->name);
+ } else
+ for (i = 0; i < sp->nel; i++)
+ { fprintf(fd, "\tprintf(\"\tchan %s[%d] (=%%d):\tlen %%d:\\t\", ",
+ sp->name, i);
+ fprintf(fd, "%s%s[%d], q_len(%s%s[%d]));\n",
+ pref, sp->name, i, pref, sp->name, i);
+ fprintf(fd, "\tc_chandump(%s%s[%d]);\n",
+ pref, sp->name, i);
+ }
+ break;
+ }
+}
+
+int
+c_splurge_any(ProcList *p)
+{ Ordered *walk;
+ Symbol *sp;
+
+ if (strcmp(p->n->name, ":never:") != 0
+ && strcmp(p->n->name, ":trace:") != 0
+ && strcmp(p->n->name, ":notrace:") != 0)
+ for (walk = all_names; walk; walk = walk->next)
+ { sp = walk->entry;
+ if (!sp->context
+ || sp->type == 0
+ || strcmp(sp->context->name, p->n->name) != 0
+ || sp->owner || (sp->hidden&1)
+ || (sp->type == MTYPE && ismtype(sp->name)))
+ continue;
+
+ return 1;
+ }
+ return 0;
+}
+
+void
+c_splurge(FILE *fd, ProcList *p)
+{ Ordered *walk;
+ Symbol *sp;
+ char pref[64];
+
+ if (strcmp(p->n->name, ":never:") != 0
+ && strcmp(p->n->name, ":trace:") != 0
+ && strcmp(p->n->name, ":notrace:") != 0)
+ for (walk = all_names; walk; walk = walk->next)
+ { sp = walk->entry;
+ if (!sp->context
+ || sp->type == 0
+ || strcmp(sp->context->name, p->n->name) != 0
+ || sp->owner || (sp->hidden&1)
+ || (sp->type == MTYPE && ismtype(sp->name)))
+ continue;
+
+ sprintf(pref, "((P%d *)pptr(pid))->", p->tn);
+ c_var(fd, pref, sp);
+ }
+}
+
+void
+c_wrapper(FILE *fd) /* allow pan.c to print out global sv entries */
+{ Ordered *walk;
+ ProcList *p;
+ Symbol *sp;
+ Lextok *n;
+ extern Lextok *Mtype;
+ int j;
+
+ fprintf(fd, "void\nc_globals(void)\n{\t/* int i; */\n");
+ fprintf(fd, " printf(\"global vars:\\n\");\n");
+ for (walk = all_names; walk; walk = walk->next)
+ { sp = walk->entry;
+ if (sp->context || sp->owner || (sp->hidden&1)
+ || (sp->type == MTYPE && ismtype(sp->name)))
+ continue;
+
+ c_var(fd, "now.", sp);
+ }
+ fprintf(fd, "}\n");
+
+ fprintf(fd, "void\nc_locals(int pid, int tp)\n{\t/* int i; */\n");
+ fprintf(fd, " switch(tp) {\n");
+ for (p = rdy; p; p = p->nxt)
+ { fprintf(fd, " case %d:\n", p->tn);
+ fprintf(fd, " \tprintf(\"local vars proc %%d (%s):\\n\", pid);\n",
+ p->n->name);
+ if (c_splurge_any(p))
+ { fprintf(fd, " \tprintf(\"local vars proc %%d (%s):\\n\", pid);\n",
+ p->n->name);
+ c_splurge(fd, p);
+ } else
+ { fprintf(fd, " \t/* none */\n");
+ }
+ fprintf(fd, " \tbreak;\n");
+ }
+ fprintf(fd, " }\n}\n");
+
+ fprintf(fd, "void\nprintm(int x)\n{\n");
+ fprintf(fd, " switch (x) {\n");
+ for (n = Mtype, j = 1; n && j; n = n->rgt, j++)
+ fprintf(fd, "\tcase %d: Printf(\"%s\"); break;\n",
+ j, n->lft->sym->name);
+ fprintf(fd, " default: Printf(\"%%d\", x);\n");
+ fprintf(fd, " }\n");
+ fprintf(fd, "}\n");
+}
+
+static int
+doglobal(char *pre, int dowhat)
+{ Ordered *walk;
+ Symbol *sp;
+ int j, cnt = 0;
+
+ for (j = 0; j < 8; j++)
+ for (walk = all_names; walk; walk = walk->next)
+ { sp = walk->entry;
+ if (!sp->context
+ && !sp->owner
+ && sp->type == Types[j])
+ { if (Types[j] != MTYPE || !ismtype(sp->name))
+ switch (dowhat) {
+ case LOGV:
+ if (sp->type == CHAN
+ && verbose == 0)
+ break;
+ if (sp->hidden&1)
+ break;
+ do_var(tc, dowhat, "", sp,
+ pre, "\", now.", ");\n");
+ break;
+ case INIV:
+ checktype(sp, (char *) 0);
+ cnt++; /* fall through */
+ case PUTV:
+ do_var(tc, dowhat, (sp->hidden&1)?"":"now.", sp,
+ "", " = ", ";\n");
+ break;
+ } } }
+ return cnt;
+}
+
+static void
+dohidden(void)
+{ Ordered *walk;
+ Symbol *sp;
+ int j;
+
+ for (j = 0; j < 8; j++)
+ for (walk = all_names; walk; walk = walk->next)
+ { sp = walk->entry;
+ if ((sp->hidden&1)
+ && sp->type == Types[j])
+ { if (sp->context || sp->owner)
+ fatal("cannot hide non-globals (%s)", sp->name);
+ if (sp->type == CHAN)
+ fatal("cannot hide channels (%s)", sp->name);
+ fprintf(th, "/* hidden variable: */");
+ typ2c(sp);
+ } }
+ fprintf(th, "int _; /* a predefined write-only variable */\n\n");
+}
+
+void
+do_var(FILE *ofd, int dowhat, char *s, Symbol *sp,
+ char *pre, char *sep, char *ter)
+{ int i;
+
+ switch(dowhat) {
+ case PUTV:
+
+ if (sp->hidden&1) break;
+
+ typ2c(sp);
+ break;
+ case LOGV:
+ case INIV:
+ if (sp->type == STRUCT)
+ { /* struct may contain a chan */
+ walk_struct(ofd, dowhat, s, sp, pre, sep, ter);
+ break;
+ }
+ if (!sp->ini && dowhat != LOGV) /* it defaults to 0 */
+ break;
+ if (sp->nel == 1)
+ { fprintf(ofd, "\t\t%s%s%s%s",
+ pre, s, sp->name, sep);
+ if (dowhat == LOGV)
+ fprintf(ofd, "%s%s", s, sp->name);
+ else
+ do_init(ofd, sp);
+ fprintf(ofd, "%s", ter);
+ } else
+ { if (sp->ini && sp->ini->ntyp == CHAN)
+ { for (i = 0; i < sp->nel; i++)
+ { fprintf(ofd, "\t\t%s%s%s[%d]%s",
+ pre, s, sp->name, i, sep);
+ if (dowhat == LOGV)
+ fprintf(ofd, "%s%s[%d]",
+ s, sp->name, i);
+ else
+ do_init(ofd, sp);
+ fprintf(ofd, "%s", ter);
+ }
+ } else
+ { fprintf(ofd, "\t{\tint l_in;\n");
+ fprintf(ofd, "\t\tfor (l_in = 0; l_in < %d; l_in++)\n", sp->nel);
+ fprintf(ofd, "\t\t{\n");
+ fprintf(ofd, "\t\t\t%s%s%s[l_in]%s",
+ pre, s, sp->name, sep);
+ if (dowhat == LOGV)
+ fprintf(ofd, "%s%s[l_in]", s, sp->name);
+ else
+ putstmnt(ofd, sp->ini, 0);
+ fprintf(ofd, "%s", ter);
+ fprintf(ofd, "\t\t}\n");
+ fprintf(ofd, "\t}\n");
+ } }
+ break;
+ }
+}
+
+static void
+do_init(FILE *ofd, Symbol *sp)
+{ int i; extern Queue *ltab[];
+
+ if (sp->ini
+ && sp->type == CHAN
+ && ((i = qmake(sp)) > 0))
+ { if (sp->ini->ntyp == CHAN)
+ fprintf(ofd, "addqueue(%d, %d)",
+ i, ltab[i-1]->nslots == 0);
+ else
+ fprintf(ofd, "%d", i);
+ } else
+ putstmnt(ofd, sp->ini, 0);
+}
+
+static int
+blog(int n) /* for small log2 without rounding problems */
+{ int m=1, r=2;
+
+ while (r < n) { m++; r *= 2; }
+ return 1+m;
+}
+
+static void
+put_ptype(char *s, int i, int m0, int m1)
+{ int k;
+
+ if (strcmp(s, ":init:") == 0)
+ fprintf(th, "#define Pinit ((P%d *)this)\n", i);
+
+ if (strcmp(s, ":never:") != 0
+ && strcmp(s, ":trace:") != 0
+ && strcmp(s, ":notrace:") != 0
+ && strcmp(s, ":init:") != 0
+ && strcmp(s, "_:never_template:_") != 0
+ && strcmp(s, "np_") != 0)
+ fprintf(th, "#define P%s ((P%d *)this)\n", s, i);
+
+ fprintf(th, "typedef struct P%d { /* %s */\n", i, s);
+ fprintf(th, " unsigned _pid : 8; /* 0..255 */\n");
+ fprintf(th, " unsigned _t : %d; /* proctype */\n", blog(m1));
+ fprintf(th, " unsigned _p : %d; /* state */\n", blog(m0));
+ LstSet = ZS;
+ nBits = 8 + blog(m1) + blog(m0);
+ k = dolocal(tc, "", PUTV, i, s); /* includes pars */
+
+ c_add_loc(th, s);
+
+ fprintf(th, "} P%d;\n", i);
+ if ((!LstSet && k > 0) || has_state)
+ fprintf(th, "#define Air%d 0\n", i);
+ else
+ { fprintf(th, "#define Air%d (sizeof(P%d) - ", i, i);
+ if (k == 0)
+ { fprintf(th, "%d", (nBits+7)/8);
+ goto done;
+ }
+ if ((LstSet->type != BIT && LstSet->type != UNSIGNED)
+ || LstSet->nel != 1)
+ { fprintf(th, "Offsetof(P%d, %s) - %d*sizeof(",
+ i, LstSet->name, LstSet->nel);
+ }
+ switch(LstSet->type) {
+ case UNSIGNED:
+ fprintf(th, "%d", (nBits+7)/8);
+ break;
+ case BIT:
+ if (LstSet->nel == 1)
+ { fprintf(th, "%d", (nBits+7)/8);
+ break;
+ } /* else fall through */
+ case MTYPE: case BYTE: case CHAN:
+ fprintf(th, "uchar)"); break;
+ case SHORT:
+ fprintf(th, "short)"); break;
+ case INT:
+ fprintf(th, "int)"); break;
+ default:
+ fatal("cannot happen Air %s",
+ LstSet->name);
+ }
+done: fprintf(th, ")\n");
+ }
+}
+
+static void
+tc_predef_np(void)
+{ int i = nrRdy; /* 1+ highest proctype nr */
+
+ fprintf(th, "#define _NP_ %d\n", i);
+/* if (separate == 2) fprintf(th, "extern "); */
+ fprintf(th, "uchar reached%d[3]; /* np_ */\n", i);
+
+ fprintf(th, "#define nstates%d 3 /* np_ */\n", i);
+ fprintf(th, "#define endstate%d 2 /* np_ */\n\n", i);
+ fprintf(th, "#define start%d 0 /* np_ */\n", i);
+
+ fprintf(tc, "\tcase %d: /* np_ */\n", i);
+ if (separate == 1)
+ { fprintf(tc, "\t\tini_claim(%d, h);\n", i);
+ } else
+ { fprintf(tc, "\t\t((P%d *)pptr(h))->_t = %d;\n", i, i);
+ fprintf(tc, "\t\t((P%d *)pptr(h))->_p = 0;\n", i);
+ fprintf(tc, "\t\treached%d[0] = 1;\n", i);
+ fprintf(tc, "\t\taccpstate[%d][1] = 1;\n", i);
+ }
+ fprintf(tc, "\t\tbreak;\n");
+}
+
+static void
+put_pinit(ProcList *P)
+{ Lextok *fp, *fpt, *t;
+ Element *e = P->s->frst;
+ Symbol *s = P->n;
+ Lextok *p = P->p;
+ int i = P->tn;
+ int ini, j, k;
+
+ if (i == claimnr
+ && separate == 1)
+ { fprintf(tc, "\tcase %d: /* %s */\n", i, s->name);
+ fprintf(tc, "\t\tini_claim(%d, h);\n", i);
+ fprintf(tc, "\t\tbreak;\n");
+ return;
+ }
+ if (i != claimnr
+ && separate == 2)
+ return;
+
+ ini = huntele(e, e->status, -1)->seqno;
+ fprintf(th, "#define start%d %d\n", i, ini);
+ if (i == claimnr)
+ fprintf(th, "#define start_claim %d\n", ini);
+ if (i == eventmapnr)
+ fprintf(th, "#define start_event %d\n", ini);
+
+ fprintf(tc, "\tcase %d: /* %s */\n", i, s->name);
+
+ fprintf(tc, "\t\t((P%d *)pptr(h))->_t = %d;\n", i, i);
+ fprintf(tc, "\t\t((P%d *)pptr(h))->_p = %d;", i, ini);
+ fprintf(tc, " reached%d[%d]=1;\n", i, ini);
+
+ if (has_provided)
+ { fprintf(tt, "\tcase %d: /* %s */\n\t\t", i, s->name);
+ if (P->prov)
+ { fprintf(tt, "if (");
+ putstmnt(tt, P->prov, 0);
+ fprintf(tt, ")\n\t\t\t");
+ }
+ fprintf(tt, "return 1;\n");
+ if (P->prov)
+ fprintf(tt, "\t\tbreak;\n");
+ }
+
+ fprintf(tc, "\t\t/* params: */\n");
+ for (fp = p, j=0; fp; fp = fp->rgt)
+ for (fpt = fp->lft; fpt; fpt = fpt->rgt, j++)
+ { t = (fpt->ntyp == ',') ? fpt->lft : fpt;
+ if (t->sym->nel != 1)
+ { lineno = t->ln;
+ Fname = t->fn;
+ fatal("array in parameter list, %s",
+ t->sym->name);
+ }
+ fprintf(tc, "\t\t((P%d *)pptr(h))->", i);
+ if (t->sym->type == STRUCT)
+ { if (full_name(tc, t, t->sym, 1))
+ { lineno = t->ln;
+ Fname = t->fn;
+ fatal("hidden array in parameter %s",
+ t->sym->name);
+ }
+ } else
+ fprintf(tc, "%s", t->sym->name);
+ fprintf(tc, " = par%d;\n", j);
+ }
+ fprintf(tc, "\t\t/* locals: */\n");
+ k = dolocal(tc, "", INIV, i, s->name);
+ if (k > 0)
+ { fprintf(tc, "#ifdef VAR_RANGES\n");
+ (void) dolocal(tc, "logval(\"", LOGV, i, s->name);
+ fprintf(tc, "#endif\n");
+ }
+
+ fprintf(tc, "#ifdef HAS_CODE\n");
+ fprintf(tc, "\t\tlocinit%d(h);\n", i);
+ fprintf(tc, "#endif\n");
+
+ dumpclaims(tc, i, s->name);
+ fprintf(tc, "\t break;\n");
+}
+
+Element *
+huntstart(Element *f)
+{ Element *e = f;
+ Element *elast = (Element *) 0;
+ int cnt = 0;
+
+ while (elast != e && cnt++ < 200) /* new 4.0.8 */
+ { elast = e;
+ if (e->n)
+ { if (e->n->ntyp == '.' && e->nxt)
+ e = e->nxt;
+ else if (e->n->ntyp == UNLESS)
+ e = e->sub->this->frst;
+ } }
+
+ if (cnt >= 200 || !e)
+ fatal("confusing control structure", (char *) 0);
+ return e;
+}
+
+Element *
+huntele(Element *f, int o, int stopat)
+{ Element *g, *e = f;
+ int cnt=0; /* a precaution against loops */
+
+ if (e)
+ for (cnt = 0; cnt < 200 && e->n; cnt++)
+ {
+ if (e->seqno == stopat)
+ break;
+
+ switch (e->n->ntyp) {
+ case GOTO:
+ g = get_lab(e->n,1);
+ cross_dsteps(e->n, g->n);
+ break;
+ case '.':
+ case BREAK:
+ if (!e->nxt)
+ return e;
+ g = e->nxt;
+ break;
+ case UNLESS:
+ g = huntele(e->sub->this->frst, o, stopat);
+ break;
+ case D_STEP:
+ case ATOMIC:
+ case NON_ATOMIC:
+ default:
+ return e;
+ }
+ if ((o & ATOM) && !(g->status & ATOM))
+ return e;
+ e = g;
+ }
+ if (cnt >= 200 || !e)
+ fatal("confusing control structure", (char *) 0);
+ return e;
+}
+
+void
+typ2c(Symbol *sp)
+{ int wsbits = sizeof(long)*8; /* wordsize in bits */
+ switch (sp->type) {
+ case UNSIGNED:
+ if (sp->hidden&1)
+ fprintf(th, "\tuchar %s;", sp->name);
+ else
+ fprintf(th, "\tunsigned %s : %d",
+ sp->name, sp->nbits);
+ LstSet = sp;
+ if (nBits%wsbits > 0
+ && wsbits - nBits%wsbits < sp->nbits)
+ { /* must padd to a word-boundary */
+ nBits += wsbits - nBits%wsbits;
+ }
+ nBits += sp->nbits;
+ break;
+ case BIT:
+ if (sp->nel == 1 && !(sp->hidden&1))
+ { fprintf(th, "\tunsigned %s : 1", sp->name);
+ LstSet = sp;
+ nBits++;
+ break;
+ } /* else fall through */
+ if (!(sp->hidden&1) && (verbose&32))
+ printf("spin: warning: bit-array %s[%d] mapped to byte-array\n",
+ sp->name, sp->nel);
+ nBits += 8*sp->nel; /* mapped onto array of uchars */
+ case MTYPE:
+ case BYTE:
+ case CHAN: /* good for up to 255 channels */
+ fprintf(th, "\tuchar %s", sp->name);
+ LstSet = sp;
+ break;
+ case SHORT:
+ fprintf(th, "\tshort %s", sp->name);
+ LstSet = sp;
+ break;
+ case INT:
+ fprintf(th, "\tint %s", sp->name);
+ LstSet = sp;
+ break;
+ case STRUCT:
+ if (!sp->Snm)
+ fatal("undeclared structure element %s", sp->name);
+ fprintf(th, "\tstruct %s %s",
+ sp->Snm->name,
+ sp->name);
+ LstSet = ZS;
+ break;
+ case CODE_FRAG:
+ case PREDEF:
+ return;
+ default:
+ fatal("variable %s undeclared", sp->name);
+ }
+
+ if (sp->nel != 1)
+ fprintf(th, "[%d]", sp->nel);
+ fprintf(th, ";\n");
+}
+
+static void
+ncases(FILE *fd, int p, int n, int m, char *c[])
+{ int i, j;
+
+ for (j = 0; c[j]; j++)
+ for (i = n; i < m; i++)
+ { fprintf(fd, c[j], i, p, i);
+ fprintf(fd, "\n");
+ }
+}
+
+void
+qlen_type(int qmax)
+{
+ fprintf(th, "\t");
+ if (qmax < 256)
+ fprintf(th, "uchar");
+ else if (qmax < 65535)
+ fprintf(th, "ushort");
+ else
+ fprintf(th, "uint");
+ fprintf(th, " Qlen; /* q_size */\n");
+}
+
+void
+genaddqueue(void)
+{ char buf0[256];
+ int j, qmax = 0;
+ Queue *q;
+
+ ntimes(tc, 0, 1, Addq0);
+ if (has_io && !nqs)
+ fprintf(th, "#define NQS 1 /* nqs=%d, but has_io */\n", nqs);
+ else
+ fprintf(th, "#define NQS %d\n", nqs);
+ fprintf(th, "short q_flds[%d];\n", nqs+1);
+ fprintf(th, "short q_max[%d];\n", nqs+1);
+
+ for (q = qtab; q; q = q->nxt)
+ if (q->nslots > qmax)
+ qmax = q->nslots;
+
+ for (q = qtab; q; q = q->nxt)
+ { j = q->qid;
+ fprintf(tc, "\tcase %d: j = sizeof(Q%d);", j, j);
+ fprintf(tc, " q_flds[%d] = %d;", j, q->nflds);
+ fprintf(tc, " q_max[%d] = %d;", j, max(1,q->nslots));
+ fprintf(tc, " break;\n");
+
+ fprintf(th, "typedef struct Q%d {\n", j);
+ qlen_type(qmax); /* 4.2.2 */
+ fprintf(th, " uchar _t; /* q_type */\n");
+ fprintf(th, " struct {\n");
+
+ for (j = 0; j < q->nflds; j++)
+ { switch (q->fld_width[j]) {
+ case BIT:
+ if (q->nflds != 1)
+ { fprintf(th, "\t\tunsigned");
+ fprintf(th, " fld%d : 1;\n", j);
+ break;
+ } /* else fall through: smaller struct */
+ case MTYPE:
+ case CHAN:
+ case BYTE:
+ fprintf(th, "\t\tuchar fld%d;\n", j);
+ break;
+ case SHORT:
+ fprintf(th, "\t\tshort fld%d;\n", j);
+ break;
+ case INT:
+ fprintf(th, "\t\tint fld%d;\n", j);
+ break;
+ default:
+ fatal("bad channel spec", "");
+ }
+ }
+ fprintf(th, " } contents[%d];\n", max(1, q->nslots));
+ fprintf(th, "} Q%d;\n", q->qid);
+ }
+
+ fprintf(th, "typedef struct Q0 {\t/* generic q */\n");
+ qlen_type(qmax); /* 4.2.2 */
+ fprintf(th, " uchar _t;\n");
+ fprintf(th, "} Q0;\n");
+
+ ntimes(tc, 0, 1, Addq1);
+
+ if (has_random)
+ { fprintf(th, "int Q_has(int");
+ for (j = 0; j < Mpars; j++)
+ fprintf(th, ", int, int");
+ fprintf(th, ");\n");
+
+ fprintf(tc, "int\nQ_has(int into");
+ for (j = 0; j < Mpars; j++)
+ fprintf(tc, ", int want%d, int fld%d", j, j);
+ fprintf(tc, ")\n");
+ fprintf(tc, "{ int i;\n\n");
+ fprintf(tc, " if (!into--)\n");
+ fprintf(tc, " uerror(\"ref to unknown chan ");
+ fprintf(tc, "(recv-poll)\");\n\n");
+ fprintf(tc, " if (into >= now._nr_qs || into < 0)\n");
+ fprintf(tc, " Uerror(\"qrecv bad queue#\");\n\n");
+ fprintf(tc, " for (i = 0; i < ((Q0 *)qptr(into))->Qlen;");
+ fprintf(tc, " i++)\n");
+ fprintf(tc, " {\n");
+ for (j = 0; j < Mpars; j++)
+ { fprintf(tc, " if (want%d && ", j);
+ fprintf(tc, "qrecv(into+1, i, %d, 0) != fld%d)\n",
+ j, j);
+ fprintf(tc, " continue;\n");
+ }
+ fprintf(tc, " return i+1;\n");
+ fprintf(tc, " }\n");
+ fprintf(tc, " return 0;\n");
+ fprintf(tc, "}\n");
+ }
+
+ fprintf(tc, "#if NQS>0\n");
+ fprintf(tc, "void\nqsend(int into, int sorted");
+ for (j = 0; j < Mpars; j++)
+ fprintf(tc, ", int fld%d", j);
+ fprintf(tc, ")\n");
+ ntimes(tc, 0, 1, Addq11);
+
+ for (q = qtab; q; q = q->nxt)
+ { sprintf(buf0, "((Q%d *)z)->", q->qid);
+ fprintf(tc, "\tcase %d:%s\n", q->qid,
+ (q->nslots)?"":" /* =rv= */");
+ if (q->nslots == 0) /* reset handshake point */
+ fprintf(tc, "\t\t(trpt+2)->o_m = 0;\n");
+
+ if (has_sorted)
+ { fprintf(tc, "\t\tif (!sorted) goto append%d;\n", q->qid);
+ fprintf(tc, "\t\tfor (j = 0; j < %sQlen; j++)\n", buf0);
+ fprintf(tc, "\t\t{\t/* find insertion point */\n");
+ sprintf(buf0, "((Q%d *)z)->contents[j].fld", q->qid);
+ for (j = 0; j < q->nflds; j++)
+ { fprintf(tc, "\t\t\tif (fld%d > %s%d) continue;\n",
+ j, buf0, j);
+ fprintf(tc, "\t\t\tif (fld%d < %s%d) ", j, buf0, j);
+ fprintf(tc, "goto found%d;\n\n", q->qid);
+ }
+ fprintf(tc, "\t\t}\n");
+ fprintf(tc, "\tfound%d:\n", q->qid);
+ sprintf(buf0, "((Q%d *)z)->", q->qid);
+ fprintf(tc, "\t\tfor (k = %sQlen - 1; k >= j; k--)\n", buf0);
+ fprintf(tc, "\t\t{\t/* shift up */\n");
+ for (j = 0; j < q->nflds; j++)
+ { fprintf(tc, "\t\t\t%scontents[k+1].fld%d = ",
+ buf0, j);
+ fprintf(tc, "%scontents[k].fld%d;\n",
+ buf0, j);
+ }
+ fprintf(tc, "\t\t}\n");
+ fprintf(tc, "\tappend%d:\t/* insert in slot j */\n", q->qid);
+ }
+
+ fprintf(tc, "#ifdef HAS_SORTED\n");
+ fprintf(tc, "\t\t(trpt+1)->ipt = j;\n"); /* ipt was bup.oval */
+ fprintf(tc, "#endif\n");
+ fprintf(tc, "\t\t%sQlen = %sQlen + 1;\n", buf0, buf0);
+ sprintf(buf0, "((Q%d *)z)->contents[j].fld", q->qid);
+ for (j = 0; j < q->nflds; j++)
+ fprintf(tc, "\t\t%s%d = fld%d;\n", buf0, j, j);
+ fprintf(tc, "\t\tbreak;\n");
+ }
+ ntimes(tc, 0, 1, Addq2);
+
+ for (q = qtab; q; q = q->nxt)
+ fprintf(tc, "\tcase %d: return %d;\n", q->qid, (!q->nslots));
+
+ ntimes(tc, 0, 1, Addq3);
+
+ for (q = qtab; q; q = q->nxt)
+ fprintf(tc, "\tcase %d: return (q_sz(from) == %d);\n",
+ q->qid, max(1, q->nslots));
+
+ ntimes(tc, 0, 1, Addq4);
+ for (q = qtab; q; q = q->nxt)
+ { sprintf(buf0, "((Q%d *)z)->", q->qid);
+ fprintf(tc, " case %d:%s\n\t\t",
+ q->qid, (q->nslots)?"":" /* =rv= */");
+ if (q->nflds == 1)
+ { fprintf(tc, "if (fld == 0) r = %s", buf0);
+ fprintf(tc, "contents[slot].fld0;\n");
+ } else
+ { fprintf(tc, "switch (fld) {\n");
+ ncases(tc, q->qid, 0, q->nflds, R12);
+ fprintf(tc, "\t\tdefault: Uerror");
+ fprintf(tc, "(\"too many fields in recv\");\n");
+ fprintf(tc, "\t\t}\n");
+ }
+ fprintf(tc, "\t\tif (done)\n");
+ if (q->nslots == 0)
+ { fprintf(tc, "\t\t{ j = %sQlen - 1;\n", buf0);
+ fprintf(tc, "\t\t %sQlen = 0;\n", buf0);
+ sprintf(buf0, "\t\t\t((Q%d *)z)->contents", q->qid);
+ } else
+ { fprintf(tc, "\t\t{ j = %sQlen;\n", buf0);
+ fprintf(tc, "\t\t %sQlen = --j;\n", buf0);
+ fprintf(tc, "\t\t for (k=slot; k<j; k++)\n");
+ fprintf(tc, "\t\t {\n");
+ sprintf(buf0, "\t\t\t((Q%d *)z)->contents", q->qid);
+ for (j = 0; j < q->nflds; j++)
+ { fprintf(tc, "\t%s[k].fld%d = \n", buf0, j);
+ fprintf(tc, "\t\t%s[k+1].fld%d;\n", buf0, j);
+ }
+ fprintf(tc, "\t\t }\n");
+ }
+
+ for (j = 0; j < q->nflds; j++)
+ fprintf(tc, "%s[j].fld%d = 0;\n", buf0, j);
+ fprintf(tc, "\t\t\tif (fld+1 != %d)\n\t\t\t", q->nflds);
+ fprintf(tc, "\tuerror(\"missing pars in receive\");\n");
+ /* incompletely received msgs cannot be unrecv'ed */
+ fprintf(tc, "\t\t}\n");
+ fprintf(tc, "\t\tbreak;\n");
+ }
+ ntimes(tc, 0, 1, Addq5);
+ for (q = qtab; q; q = q->nxt)
+ fprintf(tc, " case %d: j = sizeof(Q%d); break;\n",
+ q->qid, q->qid);
+ ntimes(tc, 0, 1, R8b);
+
+ ntimes(th, 0, 1, Proto); /* tag on function prototypes */
+ fprintf(th, "void qsend(int, int");
+ for (j = 0; j < Mpars; j++)
+ fprintf(th, ", int");
+ fprintf(th, ");\n");
+
+ fprintf(th, "#define Addproc(x) addproc(x");
+ for (j = 0; j < Npars; j++)
+ fprintf(th, ", 0");
+ fprintf(th, ")\n");
+}
diff --git a/sys/src/cmd/spin/pangen1.h b/sys/src/cmd/spin/pangen1.h
new file mode 100755
index 000000000..81facb646
--- /dev/null
+++ b/sys/src/cmd/spin/pangen1.h
@@ -0,0 +1,5139 @@
+/***** spin: pangen1.h *****/
+
+/* Copyright (c) 1989-2005 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 */
+
+static char *Code2a[] = { /* the tail of procedure run() */
+ "#if defined(VERI) && !defined(NOREDUCE) && !defined(NP)",
+ " if (!state_tables",
+ "#ifdef HAS_CODE",
+ " && !readtrail",
+ "#endif",
+ " )",
+ " { printf(\"warning: for p.o. reduction to be valid \");",
+ " printf(\"the never claim must be stutter-invariant\\n\");",
+ " printf(\"(never claims generated from LTL \");",
+ " printf(\"formulae are stutter-invariant)\\n\");",
+ " }",
+ "#endif",
+ " UnBlock; /* disable rendez-vous */",
+ "#ifdef BITSTATE",
+#ifndef POWOW
+ " if (udmem)",
+ " { udmem *= 1024L*1024L;",
+ " SS = (uchar *) emalloc(udmem);",
+ " bstore = bstore_mod;",
+ " } else",
+#endif
+ " SS = (uchar *) emalloc(1L<<(ssize-3));",
+ "#else",
+ " hinit();",
+ "#endif",
+ "#if defined(FULLSTACK) && defined(BITSTATE)",
+ " onstack_init();",
+ "#endif",
+ "#if defined(CNTRSTACK) && !defined(BFS)",
+ " LL = (uchar *) emalloc(1L<<(ssize-3));",
+ "#endif",
+ " stack = ( Stack *) emalloc(sizeof(Stack));",
+ " svtack = (Svtack *) emalloc(sizeof(Svtack));",
+ " /* a place to point for Pptr of non-running procs: */",
+ " noptr = (uchar *) emalloc(Maxbody * sizeof(char));",
+ "#ifdef SVDUMP",
+ " if (vprefix > 0)",
+ " write(svfd, (uchar *) &vprefix, sizeof(int));",
+ "#endif",
+ "#ifdef VERI",
+ " Addproc(VERI); /* never - pid = 0 */",
+ "#endif",
+ " active_procs(); /* started after never */",
+ "#ifdef EVENT_TRACE",
+ " now._event = start_event;",
+ " reached[EVENT_TRACE][start_event] = 1;",
+ "#endif",
+
+ "#ifdef HAS_CODE",
+ " globinit();",
+ "#endif",
+ "#ifdef BITSTATE",
+ "go_again:",
+ "#endif",
+ " do_the_search();",
+ "#ifdef BITSTATE",
+ " if (--Nrun > 0 && HASH_CONST[++HASH_NR])",
+ " { printf(\"Run %%d:\\n\", HASH_NR);",
+ " wrap_stats();",
+ " printf(\"\\n\");",
+ " memset(SS, 0, 1L<<(ssize-3));",
+ "#if defined(CNTRSTACK)",
+ " memset(LL, 0, 1L<<(ssize-3));",
+ "#endif",
+ "#if defined(FULLSTACK)",
+ " memset((uchar *) S_Tab, 0, ",
+ " maxdepth*sizeof(struct H_el *));",
+ "#endif",
+ " nstates=nlinks=truncs=truncs2=ngrabs = 0;",
+ " nlost=nShadow=hcmp = 0;",
+ " Fa=Fh=Zh=Zn = 0;",
+ " PUT=PROBE=ZAPS=Ccheck=Cholds = 0;",
+ " goto go_again;",
+ " }",
+ "#endif",
+ "}",
+ "#ifdef HAS_PROVIDED",
+ "int provided(int, uchar, int, Trans *);",
+ "#endif",
+
+#ifndef PRINTF
+ "int",
+ "Printf(const char *fmt, ...)",
+ "{ /* Make sure the args to Printf",
+ " * are always evaluated (e.g., they",
+ " * could contain a run stmnt)",
+ " * but do not generate the output",
+ " * during verification runs",
+ " * unless explicitly wanted",
+ " * If this fails on your system",
+ " * compile SPIN itself -DPRINTF",
+ " * and this code is not generated",
+ " */",
+ "#ifdef HAS_CODE",
+ " if (readtrail)",
+ " { va_list args;",
+ " va_start(args, fmt);",
+ " vprintf(fmt, args);",
+ " va_end(args);",
+ " return 1;",
+ " }",
+ "#endif",
+ "#ifdef PRINTF",
+ " va_list args;",
+ " va_start(args, fmt);",
+ " vprintf(fmt, args);",
+ " va_end(args);",
+ "#endif",
+ " return 1;",
+ "}",
+#endif
+ "extern void printm(int);",
+
+ "#ifndef SC",
+ "#define getframe(i) &trail[i];",
+ "#else",
+ "static long HHH, DDD, hiwater;",
+ "static long CNT1, CNT2;",
+ "static int stackwrite;",
+ "static int stackread;",
+ "static Trail frameptr;",
+ "Trail *",
+ "getframe(int d)",
+ "{",
+ " if (CNT1 == CNT2)",
+ " return &trail[d];",
+ "",
+ " if (d >= (CNT1-CNT2)*DDD)",
+ " return &trail[d - (CNT1-CNT2)*DDD];",
+ "",
+ " if (!stackread",
+ " && (stackread = open(stackfile, 0)) < 0)",
+ " { printf(\"getframe: cannot open %%s\\n\", stackfile);",
+ " wrapup();",
+ " }",
+ " if (lseek(stackread, d* (off_t) sizeof(Trail), SEEK_SET) == -1",
+ " || read(stackread, &frameptr, sizeof(Trail)) != sizeof(Trail))",
+ " { printf(\"getframe: frame read error\\n\");",
+ " wrapup();",
+ " }",
+ " return &frameptr;",
+ "}",
+ "#endif",
+
+ "#if !defined(SAFETY) && !defined(BITSTATE)",
+ "#if !defined(FULLSTACK) || defined(MA)",
+ "#define depth_of(x) A_depth /* an estimate */",
+ "#else",
+ "int",
+ "depth_of(struct H_el *s)",
+ "{ Trail *t; int d;",
+ " for (d = 0; d <= A_depth; d++)",
+ " { t = getframe(d);",
+ " if (s == t->ostate)",
+ " return d;",
+ " }",
+ " printf(\"pan: cannot happen, depth_of\\n\");",
+ " return depthfound;",
+ "}",
+ "#endif",
+ "#endif",
+
+ "void",
+ "pan_exit(int val)",
+ "{ if (signoff) printf(\"--end of output--\\n\");",
+ " exit(val);",
+ "}",
+
+ "#ifdef HAS_CODE",
+ "char *",
+ "transmognify(char *s)",
+ "{ char *v, *w;",
+ " static char buf[2][2048];",
+ " int i, toggle = 0;",
+
+ " if (!s || strlen(s) > 2047) return s;",
+ " memset(buf[0], 0, 2048);",
+ " memset(buf[1], 0, 2048);",
+ " strcpy(buf[toggle], s);",
+ " while ((v = strstr(buf[toggle], \"{c_code\")))", /* assign v */
+ " { *v = '\\0'; v++;",
+ " strcpy(buf[1-toggle], buf[toggle]);",
+ " for (w = v; *w != '}' && *w != '\\0'; w++) /* skip */;",
+ " if (*w != '}') return s;",
+ " *w = '\\0'; w++;",
+ " for (i = 0; code_lookup[i].c; i++)",
+ " if (strcmp(v, code_lookup[i].c) == 0",
+ " && strlen(v) == strlen(code_lookup[i].c))",
+ " { if (strlen(buf[1-toggle])",
+ " + strlen(code_lookup[i].t)",
+ " + strlen(w) > 2047)",
+ " return s;",
+ " strcat(buf[1-toggle], code_lookup[i].t);",
+ " break;",
+ " }",
+ " strcat(buf[1-toggle], w);",
+ " toggle = 1 - toggle;",
+ " }",
+ " buf[toggle][2047] = '\\0';",
+ " return buf[toggle];",
+ "}",
+ "#else",
+ "char * transmognify(char *s) { return s; }",
+ "#endif",
+
+ "#ifdef HAS_CODE",
+ "void",
+ "add_src_txt(int ot, int tt)",
+ "{ Trans *t;",
+ " char *q;",
+ "",
+ " for (t = trans[ot][tt]; t; t = t->nxt)",
+ " { printf(\"\\t\\t\");",
+
+ " q = transmognify(t->tp);",
+ " for ( ; q && *q; q++)",
+ " if (*q == '\\n')",
+ " printf(\"\\\\n\");",
+ " else",
+ " putchar(*q);",
+ " printf(\"\\n\");",
+ " }",
+ "}",
+ "void",
+ "wrap_trail(void)",
+ "{ static int wrap_in_progress = 0;",
+ " int i; short II;",
+ " P0 *z;",
+ "",
+ " if (wrap_in_progress++) return;",
+ "",
+ " printf(\"spin: trail ends after %%ld steps\\n\", depth);",
+ " if (onlyproc >= 0)",
+ " { if (onlyproc >= now._nr_pr) pan_exit(0);",
+ " II = onlyproc;",
+ " z = (P0 *)pptr(II);",
+ " printf(\"%%3ld:\tproc %%d (%%s) \",",
+ " depth, II, procname[z->_t]);",
+ " for (i = 0; src_all[i].src; i++)",
+ " if (src_all[i].tp == (int) z->_t)",
+ " { printf(\" line %%3d\",",
+ " src_all[i].src[z->_p]);",
+ " break;",
+ " }",
+ " printf(\" (state %%2d)\", z->_p);",
+ " if (!stopstate[z->_t][z->_p])",
+ " printf(\" (invalid end state)\");",
+ " printf(\"\\n\");",
+ " add_src_txt(z->_t, z->_p);",
+ " pan_exit(0);",
+ " }",
+ " printf(\"#processes %%d:\\n\", now._nr_pr);",
+ " if (depth < 0) depth = 0;",
+ " for (II = 0; II < now._nr_pr; II++)",
+ " { z = (P0 *)pptr(II);",
+ " printf(\"%%3ld:\tproc %%d (%%s) \",",
+ " depth, II, procname[z->_t]);",
+ " for (i = 0; src_all[i].src; i++)",
+ " if (src_all[i].tp == (int) z->_t)",
+ " { printf(\" line %%3d\",",
+ " src_all[i].src[z->_p]);",
+ " break;",
+ " }",
+ " printf(\" (state %%2d)\", z->_p);",
+ " if (!stopstate[z->_t][z->_p])",
+ " printf(\" (invalid end state)\");",
+ " printf(\"\\n\");",
+ " add_src_txt(z->_t, z->_p);",
+ " }",
+ " c_globals();",
+ " for (II = 0; II < now._nr_pr; II++)",
+ " { z = (P0 *)pptr(II);",
+ " c_locals(II, z->_t);",
+ " }",
+ "#ifdef ON_EXIT",
+ " ON_EXIT;",
+ "#endif",
+ " pan_exit(0);",
+ "}",
+ "FILE *",
+ "findtrail(void)",
+ "{ FILE *fd;",
+ " char fnm[512], *q;",
+ " char MyFile[512];",
+ "",
+ " strcpy(MyFile, TrailFile);", /* avoid problem with non-writable strings */
+ "",
+ " if (whichtrail)",
+ " { sprintf(fnm, \"%%s%%d.%%s\", MyFile, whichtrail, tprefix);",
+ " fd = fopen(fnm, \"r\");",
+ " if (fd == NULL && (q = strchr(MyFile, \'.\')))",
+ " { *q = \'\\0\';", /* e.g., strip .pml on original file */
+ " sprintf(fnm, \"%%s%%d.%%s\", MyFile, whichtrail, tprefix);",
+ " *q = \'.\';",
+ " fd = fopen(fnm, \"r\");",
+ " if (fd == NULL)",
+ " { printf(\"pan: cannot find %%s%%d.%%s or %%s\\n\", ",
+ " MyFile, whichtrail, tprefix, fnm);",
+ " pan_exit(1);",
+ " } }",
+ " } else",
+ " { sprintf(fnm, \"%%s.%%s\", MyFile, tprefix);",
+ " fd = fopen(fnm, \"r\");",
+ " if (fd == NULL && (q = strchr(MyFile, \'.\')))",
+ " { *q = \'\\0\';", /* e.g., strip .pml on original file */
+ " sprintf(fnm, \"%%s.%%s\", MyFile, tprefix);",
+ " *q = \'.\';",
+ " fd = fopen(fnm, \"r\");",
+ " if (fd == NULL)",
+ " { printf(\"pan: cannot find %%s.%%s or %%s\\n\", ",
+ " MyFile, tprefix, fnm);",
+ " pan_exit(1);",
+ " } } }",
+ " if (fd == NULL)",
+ " { printf(\"pan: cannot find trailfile %%s\\n\", fnm);",
+ " pan_exit(1);",
+ " }",
+ " return fd;",
+ "}",
+ "",
+ "uchar do_transit(Trans *, short);",
+ "",
+ "void",
+ "getrail(void)",
+ "{ FILE *fd;",
+ " char *q;",
+ " int i, t_id, lastnever=-1; short II;",
+ " Trans *t;",
+ " P0 *z;",
+ "",
+ " fd = findtrail(); /* exits if unsuccessful */",
+ " while (fscanf(fd, \"%%ld:%%d:%%d\\n\", &depth, &i, &t_id) == 3)",
+ " { if (depth == -1)",
+ " printf(\"<<<<<START OF CYCLE>>>>>\\n\");",
+ " if (depth < 0)",
+ " continue;",
+ " if (i > now._nr_pr)",
+ " { printf(\"pan: Error, proc %%d invalid pid \", i);",
+ " printf(\"transition %%d\\n\", t_id);",
+ " break;",
+ " }",
+ " II = i;",
+ "",
+ " z = (P0 *)pptr(II);",
+ " for (t = trans[z->_t][z->_p]; t; t = t->nxt)",
+ " if (t->t_id == t_id)",
+ " break;",
+ " if (!t)",
+ " { for (i = 0; i < NrStates[z->_t]; i++)",
+ " { t = trans[z->_t][i];",
+ " if (t && t->t_id == t_id)",
+ " { printf(\" Recovered at state %%d\\n\", i);",
+ " z->_p = i;",
+ " goto recovered;",
+ " } }",
+ " printf(\"pan: Error, proc %%d type %%d state %%d: \",",
+ " II, z->_t, z->_p);",
+ " printf(\"transition %%d not found\\n\", t_id);",
+ " for (t = trans[z->_t][z->_p]; t; t = t->nxt)",
+ " printf(\" t_id %%d -- case %%d, [%%s]\\n\",",
+ " t->t_id, t->forw, t->tp);",
+ " break; /* pan_exit(1); */",
+ " }",
+ "recovered:",
+ " q = transmognify(t->tp);",
+ " if (gui) simvals[0] = \'\\0\';",
+
+ " this = pptr(II);",
+ " trpt->tau |= 1;", /* timeout always possible */
+ " if (!do_transit(t, II))",
+ " { if (onlyproc >= 0 && II != onlyproc)",
+ " goto moveon;",
+ " printf(\"pan: error, next transition UNEXECUTABLE on replay\\n\");",
+ " printf(\" most likely causes: missing c_track statements\\n\");",
+ " printf(\" or illegal side-effects in c_expr statements\\n\");",
+ " }",
+
+ " if (onlyproc >= 0 && II != onlyproc)",
+ " goto moveon;",
+
+ " if (verbose)",
+ " { printf(\"depth: %%3ld proc: %%3d trans: %%3d (%%d procs) \",",
+ " depth, II, t_id, now._nr_pr);",
+ " printf(\"forw=%%3d [%%s]\\n\", t->forw, q);",
+ "",
+ " c_globals();",
+ " for (i = 0; i < now._nr_pr; i++)",
+ " { c_locals(i, ((P0 *)pptr(i))->_t);",
+ " }",
+ " } else",
+ " if (strcmp(procname[z->_t], \":never:\") == 0)",
+ " { if (lastnever != (int) z->_p)",
+ " { for (i = 0; src_all[i].src; i++)",
+ " if (src_all[i].tp == (int) z->_t)",
+ " { printf(\"MSC: ~G %%d\\n\",",
+ " src_all[i].src[z->_p]);",
+ " break;",
+ " }",
+ " if (!src_all[i].src)",
+ " printf(\"MSC: ~R %%d\\n\", z->_p);",
+ " }",
+ " lastnever = z->_p;",
+ " goto sameas;",
+ " } else",
+ " if (strcmp(procname[z->_t], \":np_:\") != 0)",
+ " {",
+ "sameas: if (no_rck) goto moveon;",
+ " if (coltrace)",
+ " { printf(\"%%ld: \", depth);",
+ " for (i = 0; i < II; i++)",
+ " printf(\"\\t\\t\");",
+ " printf(\"%%s(%%d):\", procname[z->_t], II);",
+ " printf(\"[%%s]\\n\", q?q:\"\");",
+ " } else if (!silent)",
+ " { if (strlen(simvals) > 0) {",
+ " printf(\"%%3ld: proc %%2d (%%s)\", ",
+ " depth, II, procname[z->_t]);",
+ " for (i = 0; src_all[i].src; i++)",
+ " if (src_all[i].tp == (int) z->_t)",
+ " { printf(\" line %%3d \\\"pan_in\\\" \",",
+ " src_all[i].src[z->_p]);",
+ " break;",
+ " }",
+ " printf(\"(state %%d)\t[values: %%s]\\n\", z->_p, simvals);",
+ " }",
+ " printf(\"%%3ld: proc %%2d (%%s)\", ",
+ " depth, II, procname[z->_t]);",
+ " for (i = 0; src_all[i].src; i++)",
+ " if (src_all[i].tp == (int) z->_t)",
+ " { printf(\" line %%3d \\\"pan_in\\\" \",",
+ " src_all[i].src[z->_p]);",
+ " break;",
+ " }",
+ " printf(\"(state %%d)\t[%%s]\\n\", z->_p, q?q:\"\");",
+ " printf(\"\\n\");",
+ " } }",
+ "moveon: z->_p = t->st;",
+ " }",
+ " wrap_trail();",
+ "}",
+ "#endif",
+ "int",
+ "f_pid(int pt)",
+ "{ int i;",
+ " P0 *z;",
+ " for (i = 0; i < now._nr_pr; i++)",
+ " { z = (P0 *)pptr(i);",
+ " if (z->_t == (unsigned) pt)",
+ " return BASE+z->_pid;",
+ " }",
+ " return -1;",
+ "}",
+ "#ifdef VERI",
+ "void check_claim(int);",
+ "#endif",
+ "",
+ "#ifdef BITSTATE",
+#ifndef POWOW
+ "int",
+ "bstore_mod(char *v, int n) /* hasharray size not a power of two */",
+ "{ unsigned long x, y;",
+ " unsigned int i = 1;",
+ "",
+ " d_hash((uchar *) v, n); /* sets j3, j4, K1, K2 */",
+ " x = K2; y = j3;",
+ " for (;;)",
+ " { if (!(SS[x%%udmem]&(1<<y))) break;", /* take the hit in speed */
+ " if (i == hfns) {",
+ "#ifdef DEBUG",
+ " printf(\"Old bitstate\\n\");",
+ "#endif",
+ " return 1;",
+ " }",
+ " x = (x + K1 + i);", /* no mask, using mod */
+ " y = (y + j4) & 7;",
+ " i++;",
+ " }",
+ "#ifdef RANDSTOR",
+ " if (rand()%%100 > RANDSTOR) return 0;",
+ "#endif",
+ " for (;;)",
+ " { SS[x%%udmem] |= (1<<y);",
+ " if (i == hfns) break;", /* done */
+ " x = (x + K1 + i);", /* no mask */
+ " y = (y + j4) & 7;",
+ " i++;",
+ " }",
+ "#ifdef DEBUG",
+ " printf(\"New bitstate\\n\");",
+ "#endif",
+ " if (now._a_t&1)",
+ " { nShadow++;",
+ " }",
+ " return 0;",
+ "}",
+#endif
+ "int",
+ "bstore_reg(char *v, int n) /* extended hashing, Peter Dillinger, 2004 */",
+ "{ unsigned long x, y;",
+ " unsigned int i = 1;",
+ "",
+ " d_hash((uchar *) v, n); /* sets j1-j4 */",
+ " x = j2; y = j3;",
+ " for (;;)",
+ " { if (!(SS[x]&(1<<y))) break;", /* at least one bit not set */
+ " if (i == hfns) {",
+ "#ifdef DEBUG",
+ " printf(\"Old bitstate\\n\");",
+ "#endif",
+ " return 1;",
+ " }",
+ " x = (x + j1 + i) & nmask;",
+ " y = (y + j4) & 7;",
+ " i++;",
+ " }",
+ "#ifdef RANDSTOR",
+ " if (rand()%%100 > RANDSTOR) return 0;",
+ "#endif",
+ " for (;;)",
+ " { SS[x] |= (1<<y);",
+ " if (i == hfns) break;", /* done */
+ " x = (x + j1 + i) & nmask;",
+ " y = (y + j4) & 7;",
+ " i++;",
+ " }",
+ "#ifdef DEBUG",
+ " printf(\"New bitstate\\n\");",
+ "#endif",
+ " if (now._a_t&1)",
+ " { nShadow++;",
+ " }",
+ " return 0;",
+ "}",
+ "#endif",
+ "unsigned long TMODE = 0666; /* file permission bits for trail files */",
+ "",
+ "int trcnt=1;",
+ "char snap[64], fnm[512];",
+ "",
+ "int",
+ "make_trail(void)",
+ "{ int fd;",
+ " char *q;",
+ " char MyFile[512];",
+ "",
+ " q = strrchr(TrailFile, \'/\');",
+ " if (q == NULL) q = TrailFile; else q++;",
+ " strcpy(MyFile, q); /* TrailFile is not a writable string */",
+ "",
+ " if (iterative == 0 && Nr_Trails++ > 0)",
+ " sprintf(fnm, \"%%s%%d.%%s\",",
+ " MyFile, Nr_Trails-1, tprefix);",
+ " else",
+ " sprintf(fnm, \"%%s.%%s\", MyFile, tprefix);",
+ "",
+ " if ((fd = creat(fnm, TMODE)) < 0)",
+ " { if ((q = strchr(MyFile, \'.\')))",
+ " { *q = \'\\0\';", /* strip .pml */
+ " if (iterative == 0 && Nr_Trails-1 > 0)",
+ " sprintf(fnm, \"%%s%%d.%%s\",",
+ " MyFile, Nr_Trails-1, tprefix);",
+ " else",
+ " sprintf(fnm, \"%%s.%%s\", MyFile, tprefix);",
+ " *q = \'.\';",
+ " fd = creat(fnm, TMODE);",
+ " } }",
+ " if (fd < 0)",
+ " { printf(\"pan: cannot create %%s\\n\", fnm);",
+ " perror(\"cause\");",
+ " } else",
+ " { printf(\"pan: wrote %%s\\n\", fnm);",
+ " }",
+ " return fd;",
+ "}",
+ 0
+};
+
+static char *Code2b[] = { /* breadth-first search option */
+ "#ifdef BFS",
+ "#define Q_PROVISO",
+ "#ifndef INLINE_REV",
+ "#define INLINE_REV",
+ "#endif",
+ "",
+ "typedef struct SV_Hold {",
+ " State *sv;",
+ " int sz;",
+ " struct SV_Hold *nxt;",
+ "} SV_Hold;",
+ "",
+ "typedef struct EV_Hold {",
+ " char *sv;", /* Mask */
+ " int sz;", /* vsize */
+ " int nrpr;",
+ " int nrqs;",
+ "#if VECTORSZ>32000",
+ " int *po;",
+ "#else",
+ " short *po;",
+ "#endif",
+ " int *qo;",
+ " uchar *ps, *qs;",
+ " struct EV_Hold *nxt;",
+ "} EV_Hold;",
+ "",
+ "typedef struct BFS_Trail {",
+ " Trail *frame;",
+ " SV_Hold *onow;",
+ " EV_Hold *omask;",
+ "#ifdef Q_PROVISO",
+ " struct H_el *lstate;",
+ "#endif",
+ " short boq;",
+ " struct BFS_Trail *nxt;",
+ "} BFS_Trail;",
+ "",
+ "BFS_Trail *bfs_trail, *bfs_bot, *bfs_free;",
+ "",
+ "SV_Hold *svhold, *svfree;",
+ "",
+ "uchar do_reverse(Trans *, short, uchar);",
+ "void snapshot(void);",
+ "",
+ "SV_Hold *",
+ "getsv(int n)",
+ "{ SV_Hold *h = (SV_Hold *) 0, *oh;",
+ "",
+ " oh = (SV_Hold *) 0;",
+ " for (h = svfree; h; oh = h, h = h->nxt)",
+ " { if (n == h->sz)",
+ " { if (!oh)",
+ " svfree = h->nxt;",
+ " else",
+ " oh->nxt = h->nxt;",
+ " h->nxt = (SV_Hold *) 0;",
+ " break;",
+ " }",
+ " if (n < h->sz)",
+ " { h = (SV_Hold *) 0;",
+ " break;",
+ " }",
+ " /* else continue */",
+ " }",
+ "",
+ " if (!h)",
+ " { h = (SV_Hold *) emalloc(sizeof(SV_Hold));",
+ " h->sz = n;",
+ " h->sv = (State *) emalloc(sizeof(State) - VECTORSZ + n);",
+ " }",
+ " return h;",
+ "}",
+ "",
+ "EV_Hold *",
+ "getsv_mask(int n)",
+ "{ EV_Hold *h;",
+ " static EV_Hold *kept = (EV_Hold *) 0;",
+ "",
+ " for (h = kept; h; h = h->nxt)",
+ " if (n == h->sz",
+ " && (memcmp((char *) Mask, (char *) h->sv, n) == 0)",
+ " && (now._nr_pr == h->nrpr)",
+ " && (now._nr_qs == h->nrqs)",
+ "#if VECTORSZ>32000",
+ " && (memcmp((char *) proc_offset, (char *) h->po, now._nr_pr * sizeof(int)) == 0)",
+ " && (memcmp((char *) q_offset, (char *) h->qo, now._nr_qs * sizeof(int)) == 0)",
+ "#else",
+ " && (memcmp((char *) proc_offset, (char *) h->po, now._nr_pr * sizeof(short)) == 0)",
+ " && (memcmp((char *) q_offset, (char *) h->qo, now._nr_qs * sizeof(short)) == 0)",
+ "#endif",
+ " && (memcmp((char *) proc_skip, (char *) h->ps, now._nr_pr * sizeof(uchar)) == 0)",
+ " && (memcmp((char *) q_skip, (char *) h->qs, now._nr_qs * sizeof(uchar)) == 0))",
+ " break;",
+ " if (!h)",
+ " { h = (EV_Hold *) emalloc(sizeof(EV_Hold));",
+ " h->sz = n;",
+ " h->nrpr = now._nr_pr;",
+ " h->nrqs = now._nr_qs;",
+ "",
+ " h->sv = (char *) emalloc(n * sizeof(char));",
+ " memcpy((char *) h->sv, (char *) Mask, n);",
+ "",
+ " if (now._nr_pr > 0)",
+ " { h->po = (int *) emalloc(now._nr_pr * sizeof(int));",
+ " h->ps = (int *) emalloc(now._nr_pr * sizeof(int));",
+ "#if VECTORSZ>32000",
+ " memcpy((char *) h->po, (char *) proc_offset, now._nr_pr * sizeof(int));",
+ "#else",
+ " memcpy((char *) h->po, (char *) proc_offset, now._nr_pr * sizeof(short));",
+ "#endif",
+ " memcpy((char *) h->ps, (char *) proc_skip, now._nr_pr * sizeof(uchar));",
+ " }",
+ " if (now._nr_qs > 0)",
+ " { h->qo = (int *) emalloc(now._nr_qs * sizeof(int));",
+ " h->qs = (int *) emalloc(now._nr_qs * sizeof(int));",
+ "#if VECTORSZ>32000",
+ " memcpy((char *) h->qo, (char *) q_offset, now._nr_qs * sizeof(int));",
+ "#else",
+ " memcpy((char *) h->qo, (char *) q_offset, now._nr_qs * sizeof(short));",
+ "#endif",
+ " memcpy((char *) h->qs, (char *) q_skip, now._nr_qs * sizeof(uchar));",
+ " }",
+ "",
+ " h->nxt = kept;",
+ " kept = h;",
+ " }",
+ " return h;",
+ "}",
+ "",
+ "void",
+ "freesv(SV_Hold *p)",
+ "{ SV_Hold *h, *oh;",
+ "",
+ " oh = (SV_Hold *) 0;",
+ " for (h = svfree; h; oh = h, h = h->nxt)",
+ " if (h->sz >= p->sz)",
+ " break;",
+ "",
+ " if (!oh)",
+ " { p->nxt = svfree;",
+ " svfree = p;",
+ " } else",
+ " { p->nxt = h;",
+ " oh->nxt = p;",
+ " }",
+ "}",
+ "",
+ "BFS_Trail *",
+ "get_bfs_frame(void)",
+ "{ BFS_Trail *t;",
+ "",
+ " if (bfs_free)",
+ " { t = bfs_free;",
+ " bfs_free = bfs_free->nxt;",
+ " t->nxt = (BFS_Trail *) 0;",
+ " } else",
+ " { t = (BFS_Trail *) emalloc(sizeof(BFS_Trail));",
+ " }",
+ " t->frame = (Trail *) emalloc(sizeof(Trail));", /* always new */
+ " return t;",
+ "}",
+ "",
+ "void",
+ "push_bfs(Trail *f, int d)",
+ "{ BFS_Trail *t;",
+ "",
+ " t = get_bfs_frame();",
+ " memcpy((char *)t->frame, (char *)f, sizeof(Trail));",
+ " t->frame->o_tt = d; /* depth */",
+ "",
+ " t->boq = boq;",
+ " t->onow = getsv(vsize);",
+ " memcpy((char *)t->onow->sv, (char *)&now, vsize);",
+ " t->omask = getsv_mask(vsize);",
+ "#if defined(FULLSTACK) && defined(Q_PROVISO)",
+ " t->lstate = Lstate;",
+ "#endif",
+ " if (!bfs_bot)",
+ " { bfs_bot = bfs_trail = t;",
+ " } else",
+ " { bfs_bot->nxt = t;",
+ " bfs_bot = t;",
+ " }",
+ "#ifdef CHECK",
+ " printf(\"PUSH %%u (%%d)\\n\", t->frame, d);",
+ "#endif",
+ "}",
+ "",
+ "Trail *",
+ "pop_bfs(void)",
+ "{ BFS_Trail *t;",
+ "",
+ " if (!bfs_trail)",
+ " return (Trail *) 0;",
+ "",
+ " t = bfs_trail;",
+ " bfs_trail = t->nxt;",
+ " if (!bfs_trail)",
+ " bfs_bot = (BFS_Trail *) 0;",
+ "#if defined(Q_PROVISO) && !defined(BITSTATE) && !defined(NOREDUCE)",
+ " if (t->lstate) t->lstate->tagged = 0;",
+ "#endif",
+ "",
+ " t->nxt = bfs_free;",
+ " bfs_free = t;",
+ "",
+ " vsize = t->onow->sz;",
+ " boq = t->boq;",
+ "",
+ " memcpy((uchar *) &now, (uchar *) t->onow->sv, vsize);",
+ " memcpy((uchar *) Mask, (uchar *) t->omask->sv, vsize);",
+
+ " if (now._nr_pr > 0)",
+ "#if VECTORSZ>32000",
+ " { memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(int));",
+ "#else",
+ " { memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(short));",
+ "#endif",
+ " memcpy((char *)proc_skip, (char *)t->omask->ps, now._nr_pr * sizeof(uchar));",
+ " }",
+ " if (now._nr_qs > 0)",
+ "#if VECTORSZ>32000",
+ " { memcpy((uchar *)q_offset, (uchar *)t->omask->qo, now._nr_qs * sizeof(int));",
+ "#else",
+ " { memcpy((uchar *)q_offset, (uchar *)t->omask->qo, now._nr_qs * sizeof(short));",
+ "#endif",
+ " memcpy((uchar *)q_skip, (uchar *)t->omask->qs, now._nr_qs * sizeof(uchar));",
+ " }",
+
+ " freesv(t->onow); /* omask not freed */",
+ "#ifdef CHECK",
+ " printf(\"POP %%u (%%d)\\n\", t->frame, t->frame->o_tt);",
+ "#endif",
+ " return t->frame;",
+ "}",
+ "",
+ "void",
+ "store_state(Trail *ntrpt, int shortcut, short oboq)",
+ "{",
+ "#ifdef VERI",
+ " Trans *t2 = (Trans *) 0;",
+ " uchar ot; int tt, E_state;",
+ " uchar o_opm = trpt->o_pm, *othis = this;",
+ "",
+ " if (shortcut)",
+ " {",
+ "#ifdef VERBOSE",
+ " printf(\"claim: shortcut\\n\");",
+ "#endif",
+ " goto store_it; /* no claim move */",
+ " }",
+ "",
+ " this = (((uchar *)&now)+proc_offset[0]); /* 0 = never claim */",
+ " trpt->o_pm = 0;", /* to interpret else in never claim */
+ "",
+ " tt = (int) ((P0 *)this)->_p;",
+ " ot = (uchar) ((P0 *)this)->_t;",
+ "",
+ "#ifdef HAS_UNLESS",
+ " E_state = 0;",
+ "#endif",
+ " for (t2 = trans[ot][tt]; t2; t2 = t2?t2->nxt:(Trans *)0)",
+ " {",
+ "#ifdef HAS_UNLESS",
+ " if (E_state > 0",
+ " && E_state != t2->e_trans)",
+ " break;",
+ "#endif",
+ " if (do_transit(t2, 0))",
+ " {",
+ "#ifdef VERBOSE",
+ " if (!reached[ot][t2->st])",
+ " printf(\"depth: %%d -- claim move from %%d -> %%d\\n\",",
+ " trpt->o_tt, ((P0 *)this)->_p, t2->st);",
+ "#endif",
+ "#ifdef HAS_UNLESS",
+ " E_state = t2->e_trans;",
+ "#endif",
+ " if (t2->st > 0)",
+ " { ((P0 *)this)->_p = t2->st;",
+ " reached[ot][t2->st] = 1;",
+ "#ifndef NOCLAIM",
+ " check_claim(t2->st);",
+ "#endif",
+ " }",
+ " if (now._nr_pr == 0) /* claim terminated */",
+ " uerror(\"end state in claim reached\");",
+ "",
+ "#ifdef PEG",
+ " peg[t2->forw]++;",
+ "#endif",
+ " trpt->o_pm |= 1;",
+ " if (t2->atom&2)", /* atomic in claim */
+ " Uerror(\"atomic in claim not supported in BFS mode\");",
+ "store_it:",
+ "",
+ "#endif", /* VERI */
+ "",
+ "#ifdef BITSTATE",
+ " if (!bstore((char *)&now, vsize))",
+ "#else",
+ "#ifdef MA",
+ " if (!gstore((char *)&now, vsize, 0))",
+ "#else",
+ " if (!hstore((char *)&now, vsize))",
+ "#endif",
+ "#endif",
+ " { nstates++;",
+ "#ifndef NOREDUCE",
+ " trpt->tau |= 64;", /* succ definitely outside stack */
+ "#endif",
+ "#if SYNC",
+ " if (boq != -1)",
+ " midrv++;",
+ " else if (oboq != -1)",
+ " { Trail *x;",
+ " x = (Trail *) trpt->ostate; /* pre-rv state */",
+ " if (x) x->o_pm |= 4; /* mark success */",
+ " }",
+ "#endif",
+ " push_bfs(ntrpt, trpt->o_tt+1);",
+ " } else",
+ " { truncs++;",
+
+ "#if !defined(NOREDUCE) && defined(FULLSTACK) && defined(Q_PROVISO)",
+ "#if !defined(QLIST) && !defined(BITSTATE)",
+ " if (Lstate && Lstate->tagged) trpt->tau |= 64;",
+ "#else",
+ " if (trpt->tau&32)",
+ " { BFS_Trail *tprov;",
+ " for (tprov = bfs_trail; tprov; tprov = tprov->nxt)",
+ " if (!memcmp((uchar *)&now, (uchar *)tprov->onow->sv, vsize))",
+ " { trpt->tau |= 64;",
+ " break; /* state is in queue */",
+ " } }",
+ "#endif",
+ "#endif",
+ " }",
+ "#ifdef VERI",
+ " ((P0 *)this)->_p = tt; /* reset claim */",
+ " if (t2)",
+ " do_reverse(t2, 0, 0);",
+ " else",
+ " break;",
+ " } }",
+ " this = othis;",
+ " trpt->o_pm = o_opm;",
+ "#endif",
+ "}",
+ "",
+ "Trail *ntrpt;", /* 4.2.8 */
+ "",
+ "void",
+ "bfs(void)",
+ "{ Trans *t; Trail *otrpt, *x;",
+ " uchar _n, _m, ot, nps = 0;",
+ " int tt, E_state;",
+ " short II, From = (short) (now._nr_pr-1), To = BASE;",
+ " short oboq = boq;",
+ "",
+ " ntrpt = (Trail *) emalloc(sizeof(Trail));",
+ " trpt->ostate = (struct H_el *) 0;",
+ " trpt->tau = 0;",
+ "",
+ " trpt->o_tt = -1;",
+ " store_state(ntrpt, 0, oboq); /* initial state */",
+ "",
+ " while ((otrpt = pop_bfs())) /* also restores now */",
+ " { memcpy((char *) trpt, (char *) otrpt, sizeof(Trail));",
+ "#if defined(C_States) && (HAS_TRACK==1)",
+ " c_revert((uchar *) &(now.c_state[0]));",
+ "#endif",
+ " if (trpt->o_pm & 4)",
+ " {",
+ "#ifdef VERBOSE",
+ " printf(\"Revisit of atomic not needed (%%d)\\n\",",
+ " trpt->o_pm);", /* at least 1 rv succeeded */
+ "#endif",
+ " continue;",
+ " }",
+ "#ifndef NOREDUCE",
+ " nps = 0;",
+ "#endif",
+ " if (trpt->o_pm == 8)",
+ " { revrv++;",
+ " if (trpt->tau&8)",
+ " {",
+ "#ifdef VERBOSE",
+ " printf(\"Break atomic (pm:%%d,tau:%%d)\\n\",",
+ " trpt->o_pm, trpt->tau);",
+ "#endif",
+ " trpt->tau &= ~8;",
+ " }",
+ "#ifndef NOREDUCE",
+ " else if (trpt->tau&32)", /* was a preselected move */
+ " {",
+ "#ifdef VERBOSE",
+ " printf(\"Void preselection (pm:%%d,tau:%%d)\\n\",",
+ " trpt->o_pm, trpt->tau);",
+ "#endif",
+ " trpt->tau &= ~32;",
+ " nps = 1; /* no preselection in repeat */",
+ " }",
+ "#endif",
+ " }",
+ " trpt->o_pm &= ~(4|8);",
+ " if (trpt->o_tt > mreached)",
+ " { mreached = trpt->o_tt;",
+ " if (mreached%%10 == 0)",
+ " { printf(\"Depth= %%7d States= %%7g \", mreached, nstates);",
+ " printf(\"Transitions= %%7g \", nstates+truncs);",
+ "#ifdef MA",
+ " printf(\"Nodes= %%7d \", nr_states);",
+ "#endif",
+ " printf(\"Memory= %%-6.3f\\n\", memcnt/1000000.);",
+ " fflush(stdout);",
+ " } }",
+ " depth = trpt->o_tt;",
+
+ " if (depth >= maxdepth)",
+ " {",
+ "#if SYNC",
+ " Trail *x;",
+ " if (boq != -1)",
+ " { x = (Trail *) trpt->ostate;",
+ " if (x) x->o_pm |= 4; /* not failing */",
+ " }",
+ "#endif",
+ " truncs++;",
+ " if (!warned)",
+ " { warned = 1;",
+ " printf(\"error: max search depth too small\\n\");",
+ " }",
+ " if (bounded)",
+ " uerror(\"depth limit reached\");",
+ " continue;",
+ " }",
+
+/* PO */
+ "#ifndef NOREDUCE",
+ " if (boq == -1 && !(trpt->tau&8) && nps == 0)",
+ " for (II = now._nr_pr-1; II >= BASE; II -= 1)",
+ " {",
+ "Pickup: this = pptr(II);",
+ " tt = (int) ((P0 *)this)->_p;",
+ " ot = (uchar) ((P0 *)this)->_t;",
+ " if (trans[ot][tt]->atom & 8)", /* safe */
+ " { t = trans[ot][tt];",
+ " if (t->qu[0] != 0)",
+ " { Ccheck++;",
+ " if (!q_cond(II, t))",
+ " continue;",
+ " Cholds++;",
+ " }",
+ " From = To = II;",
+ " trpt->tau |= 32; /* preselect marker */",
+ "#ifdef DEBUG",
+ " printf(\"%%3d: proc %%d PreSelected (tau=%%d)\\n\", ",
+ " depth, II, trpt->tau);",
+ "#endif",
+ " goto MainLoop;",
+ " } }",
+ " trpt->tau &= ~32;", /* not preselected */
+ "#endif",
+/* PO */
+ "Repeat:",
+ " if (trpt->tau&8) /* atomic */",
+ " { From = To = (short ) trpt->pr;",
+ " nlinks++;",
+ " } else",
+ " { From = now._nr_pr-1;",
+ " To = BASE;",
+ " }",
+ "MainLoop:",
+ " _n = _m = 0;",
+ " for (II = From; II >= To; II -= 1)",
+ " {",
+ " this = (((uchar *)&now)+proc_offset[II]);",
+ " tt = (int) ((P0 *)this)->_p;",
+ " ot = (uchar) ((P0 *)this)->_t;",
+ "#if SYNC",
+ " /* no rendezvous with same proc */",
+ " if (boq != -1 && trpt->pr == II) continue;",
+ "#endif",
+ " ntrpt->pr = (uchar) II;",
+ " ntrpt->st = tt; ",
+ " trpt->o_pm &= ~1; /* no move yet */",
+ "#ifdef EVENT_TRACE",
+ " trpt->o_event = now._event;",
+ "#endif",
+ "#ifdef HAS_PROVIDED",
+ " if (!provided(II, ot, tt, t)) continue;",
+ "#endif",
+ "#ifdef HAS_UNLESS",
+ " E_state = 0;",
+ "#endif",
+ " for (t = trans[ot][tt]; t; t = t->nxt)",
+ " {",
+ "#ifdef HAS_UNLESS",
+ " if (E_state > 0",
+ " && E_state != t->e_trans)",
+ " break;",
+ "#endif",
+ " ntrpt->o_t = t;",
+ "",
+ " oboq = boq;",
+ "",
+ " if (!(_m = do_transit(t, II)))",
+ " continue;",
+ "",
+ " trpt->o_pm |= 1; /* we moved */",
+ " (trpt+1)->o_m = _m; /* for unsend */",
+ "#ifdef PEG",
+ " peg[t->forw]++;",
+ "#endif",
+ "#ifdef CHECK",
+ " printf(\"%%3d: proc %%d exec %%d, \",",
+ " depth, II, t->forw);",
+ " printf(\"%%d to %%d, %%s %%s %%s\",",
+ " tt, t->st, t->tp,",
+ " (t->atom&2)?\"atomic\":\"\",",
+ " (boq != -1)?\"rendez-vous\":\"\");",
+ "#ifdef HAS_UNLESS",
+ " if (t->e_trans)",
+ " printf(\" (escapes to state %%d)\", t->st);",
+ "#endif",
+ " printf(\" %%saccepting [tau=%%d]\\n\",",
+ " (trpt->o_pm&2)?\"\":\"non-\", trpt->tau);",
+ "#endif",
+ "#ifdef HAS_UNLESS",
+ " E_state = t->e_trans;",
+ "#if SYNC>0",
+ " if (t->e_trans > 0 && (boq != -1 /* || oboq != -1 */))",
+ " { fprintf(efd, \"error:\tthe use of rendezvous stmnt in the escape clause\\n\");",
+ " fprintf(efd, \"\tof an unless stmnt is not compatible with -DBFS\\n\");",
+ " pan_exit(1);",
+ " }",
+ "#endif",
+ "#endif",
+ " if (t->st > 0) ((P0 *)this)->_p = t->st;",
+ "",
+ " /* ptr to pred: */ ntrpt->ostate = (struct H_el *) otrpt;",
+ " ntrpt->st = tt;",
+ " if (boq == -1 && (t->atom&2)) /* atomic */",
+ " ntrpt->tau = 8; /* record for next move */",
+ " else",
+ " ntrpt->tau = 0;",
+ "",
+ " store_state(ntrpt, (boq != -1 || (t->atom&2)), oboq);",
+ "#ifdef EVENT_TRACE",
+ " now._event = trpt->o_event;",
+ "#endif",
+ "",
+ " /* undo move and continue */",
+ " trpt++; /* this is where ovals and ipt are set */",
+ " do_reverse(t, II, _m); /* restore now. */",
+ " trpt--;",
+ "#ifdef CHECK",
+ " printf(\"%%3d: proc %%d \", depth, II);",
+ " printf(\"reverses %%d, %%d to %%d,\",",
+ " t->forw, tt, t->st);",
+ " printf(\" %%s [abit=%%d,adepth=%%d,\",",
+ " t->tp, now._a_t, A_depth);",
+ " printf(\"tau=%%d,%%d]\\n\",",
+ " trpt->tau, (trpt-1)->tau);",
+ "#endif",
+ " reached[ot][t->st] = 1;",
+ " reached[ot][tt] = 1;",
+ "",
+ " ((P0 *)this)->_p = tt;",
+ " _n |= _m;",
+ " } }",
+/* PO */
+ "#ifndef NOREDUCE",
+ " /* preselected - no succ definitely outside stack */",
+ " if ((trpt->tau&32) && !(trpt->tau&64))",
+ " { From = now._nr_pr-1; To = BASE;",
+ "#ifdef DEBUG",
+ " printf(\"%%3d: proc %%d UnSelected (_n=%%d, tau=%%d)\\n\", ",
+ " depth, II+1, (int) _n, trpt->tau);",
+ "#endif",
+ " _n = 0; trpt->tau &= ~32;",
+ " if (II >= BASE)",
+ " goto Pickup;",
+ " goto MainLoop;",
+ " }",
+ " trpt->tau &= ~(32|64);",
+ "#endif",
+/* PO */
+ " if (_n != 0)",
+ " continue;",
+ "#ifdef DEBUG",
+ " printf(\"%%3d: no move [II=%%d, tau=%%d, boq=%%d, _nr_pr=%%d]\\n\",",
+ " depth, II, trpt->tau, boq, now._nr_pr);",
+ "#endif",
+ " if (boq != -1)",
+ " { failedrv++;",
+ " x = (Trail *) trpt->ostate; /* pre-rv state */",
+ " if (!x) continue; /* root state */",
+ " if ((x->tau&8) || (x->tau&32)) /* break atomic or preselect at parent */",
+ " { x->o_pm |= 8; /* mark failure */",
+ " this = (((uchar *)&now)+proc_offset[otrpt->pr]);",
+ "#ifdef VERBOSE",
+ " printf(\"\\treset state of %%d from %%d to %%d\\n\",",
+ " otrpt->pr, ((P0 *)this)->_p, otrpt->st);",
+ "#endif",
+ " ((P0 *)this)->_p = otrpt->st;",
+ " unsend(boq); /* retract rv offer */",
+ " boq = -1;",
+
+ " push_bfs(x, x->o_tt);",
+ "#ifdef VERBOSE",
+ " printf(\"failed rv, repush with %%d\\n\", x->o_pm);",
+ "#endif",
+ " }",
+ "#ifdef VERBOSE",
+ " else printf(\"failed rv, tau at parent: %%d\\n\", x->tau);",
+ "#endif",
+ " } else if (now._nr_pr > 0)",
+ " {",
+ " if ((trpt->tau&8)) /* atomic */",
+ " { trpt->tau &= ~(1|8); /* 1=timeout, 8=atomic */",
+ "#ifdef DEBUG",
+ " printf(\"%%3d: atomic step proc %%d blocks\\n\",",
+ " depth, II+1);",
+ "#endif",
+ " goto Repeat;",
+ " }",
+ "",
+ " if (!(trpt->tau&1)) /* didn't try timeout yet */",
+ " { trpt->tau |= 1;",
+ "#ifdef DEBUG",
+ " printf(\"%%d: timeout\\n\", depth);",
+ "#endif",
+ " goto MainLoop;",
+ " }",
+ "#ifndef VERI",
+ " if (!noends && !a_cycles && !endstate())",
+ " uerror(\"invalid end state\");",
+ "#endif",
+ " } }",
+ "}",
+ "",
+ "void",
+ "putter(Trail *trpt, int fd)",
+ "{ long j;",
+ "",
+ " if (!trpt) return;",
+ "",
+ " if (trpt != (Trail *) trpt->ostate)",
+ " putter((Trail *) trpt->ostate, fd);",
+ "",
+ " if (trpt->o_t)",
+ " { sprintf(snap, \"%%d:%%d:%%d\\n\",",
+ " trcnt++, trpt->pr, trpt->o_t->t_id);",
+ " j = strlen(snap);",
+ " if (write(fd, snap, j) != j)",
+ " { printf(\"pan: error writing %%s\\n\", fnm);",
+ " pan_exit(1);",
+ " } }",
+ "}",
+ "",
+ "void",
+ "nuerror(char *str)",
+ "{ int fd = make_trail();",
+ " int j;",
+ "",
+ " if (fd < 0) return;",
+ "#ifdef VERI",
+ " sprintf(snap, \"-2:%%d:-2\\n\", VERI);",
+ " write(fd, snap, strlen(snap));",
+ "#endif",
+ "#ifdef MERGED",
+ " sprintf(snap, \"-4:-4:-4\\n\");",
+ " write(fd, snap, strlen(snap));",
+ "#endif",
+ " trcnt = 1;",
+ " putter(trpt, fd);",
+ " if (ntrpt->o_t)", /* 4.2.8 -- Alex example, missing last transition */
+ " { sprintf(snap, \"%%d:%%d:%%d\\n\",",
+ " trcnt++, ntrpt->pr, ntrpt->o_t->t_id);",
+ " j = strlen(snap);",
+ " if (write(fd, snap, j) != j)",
+ " { printf(\"pan: error writing %%s\\n\", fnm);",
+ " pan_exit(1);",
+ " } }",
+ " close(fd);",
+ " if (errors >= upto && upto != 0)",
+ " {",
+ " wrapup();",
+ " }",
+ "}",
+ "#endif", /* BFS */
+ 0,
+};
+
+static char *Code2c[] = {
+ "void",
+ "do_the_search(void)",
+ "{ int i;",
+ " depth = mreached = 0;",
+ " trpt = &trail[0];",
+ "#ifdef VERI",
+ " trpt->tau |= 4; /* the claim moves first */",
+ "#endif",
+ " for (i = 0; i < (int) now._nr_pr; i++)",
+ " { P0 *ptr = (P0 *) pptr(i);",
+ "#ifndef NP",
+ " if (!(trpt->o_pm&2)",
+ " && accpstate[ptr->_t][ptr->_p])",
+ " { trpt->o_pm |= 2;",
+ " }",
+ "#else",
+ " if (!(trpt->o_pm&4)",
+ " && progstate[ptr->_t][ptr->_p])",
+ " { trpt->o_pm |= 4;",
+ " }",
+ "#endif",
+ " }",
+ "#ifdef EVENT_TRACE",
+ "#ifndef NP",
+ " if (accpstate[EVENT_TRACE][now._event])",
+ " { trpt->o_pm |= 2;",
+ " }",
+ "#else",
+ " if (progstate[EVENT_TRACE][now._event])",
+ " { trpt->o_pm |= 4;",
+ " }",
+ "#endif",
+ "#endif",
+ "#ifndef NOCOMP",
+ " Mask[0] = Mask[1] = 1; /* _nr_pr, _nr_qs */",
+ " if (!a_cycles)",
+ " { i = &(now._a_t) - (uchar *) &now;",
+ " Mask[i] = 1; /* _a_t */",
+ " }",
+ "#ifndef NOFAIR",
+ " if (!fairness)",
+ " { int j = 0;",
+ " i = &(now._cnt[0]) - (uchar *) &now;",
+ " while (j++ < NFAIR)",
+ " Mask[i++] = 1; /* _cnt[] */",
+ " }",
+ "#endif",
+ "#endif",
+ "#ifndef NOFAIR",
+ " if (fairness",
+ " && (a_cycles && (trpt->o_pm&2)))",
+ " { now._a_t = 2; /* set the A-bit */",
+ " now._cnt[0] = now._nr_pr + 1;", /* NEW: +1 */
+ "#ifdef VERBOSE",
+ " printf(\"%%3d: fairness Rule 1, cnt=%%d, _a_t=%%d\\n\",",
+ " depth, now._cnt[now._a_t&1], now._a_t);",
+ "#endif",
+ " }",
+ "#endif",
+
+ "#if defined(C_States) && (HAS_TRACK==1)",
+ " /* capture initial state of tracked C objects */",
+ " c_update((uchar *) &(now.c_state[0]));",
+ "#endif",
+
+ "#ifdef HAS_CODE",
+ " if (readtrail) getrail(); /* no return */",
+ "#endif",
+ "#ifdef BFS",
+ " bfs();",
+ "#else",
+ "#if defined(C_States) && defined(HAS_STACK) && (HAS_TRACK==1)",
+ " /* initial state of tracked & unmatched objects */",
+ " c_stack((uchar *) &(svtack->c_stack[0]));",
+ "#endif",
+ "#ifdef RANDOMIZE",
+ " srand(123);",
+ "#endif",
+ " new_state(); /* start 1st DFS */",
+ "#endif",
+ "}",
+
+ "#ifdef INLINE_REV",
+ "uchar",
+ "do_reverse(Trans *t, short II, uchar M)",
+ "{ uchar _m = M;",
+ " int tt = (int) ((P0 *)this)->_p;",
+ "#include REVERSE_MOVES",
+ "R999: return _m;",
+ "}",
+ "#endif",
+
+ "#ifndef INLINE",
+ "#ifdef EVENT_TRACE",
+ "static char _tp = 'n'; static int _qid = 0;",
+ "#endif",
+ "uchar",
+ "do_transit(Trans *t, short II)",
+ "{ uchar _m = 0;",
+ " int tt = (int) ((P0 *)this)->_p;",
+ "#ifdef M_LOSS",
+ " uchar delta_m = 0;",
+ "#endif",
+ "#ifdef EVENT_TRACE",
+ " short oboq = boq;",
+ " uchar ot = (uchar) ((P0 *)this)->_t;",
+ " if (ot == EVENT_TRACE) boq = -1;",
+ "#define continue { boq = oboq; return 0; }",
+ "#else",
+ "#define continue return 0",
+ "#ifdef SEPARATE",
+ " uchar ot = (uchar) ((P0 *)this)->_t;",
+ "#endif",
+ "#endif",
+ "#include FORWARD_MOVES",
+ "P999:",
+ "#ifdef EVENT_TRACE",
+ " if (ot == EVENT_TRACE) boq = oboq;",
+ "#endif",
+ " return _m;",
+ "#undef continue",
+ "}",
+
+ "#ifdef EVENT_TRACE",
+ "void",
+ "require(char tp, int qid)",
+ "{ Trans *t;",
+ " _tp = tp; _qid = qid;",
+ "",
+ " if (now._event != endevent)",
+ " for (t = trans[EVENT_TRACE][now._event]; t; t = t->nxt)",
+ " { if (do_transit(t, EVENT_TRACE))",
+ " { now._event = t->st;",
+ " reached[EVENT_TRACE][t->st] = 1;",
+ "#ifdef VERBOSE",
+ " printf(\" event_trace move to -> %%d\\n\", t->st);",
+ "#endif",
+ "#ifndef BFS",
+ "#ifndef NP",
+ " if (accpstate[EVENT_TRACE][now._event])",
+ " (trpt+1)->o_pm |= 2;",
+ "#else",
+ " if (progstate[EVENT_TRACE][now._event])",
+ " (trpt+1)->o_pm |= 4;",
+ "#endif",
+ "#endif",
+ "#ifdef NEGATED_TRACE",
+ " if (now._event == endevent)",
+ " {",
+ "#ifndef BFS",
+ " depth++; trpt++;",
+ "#endif",
+ " uerror(\"event_trace error (all events matched)\");",
+ "#ifndef BFS",
+ " trpt--; depth--;",
+ "#endif",
+ " break;",
+ " }",
+ "#endif",
+ " for (t = t->nxt; t; t = t->nxt)",
+ " { if (do_transit(t, EVENT_TRACE))",
+ " Uerror(\"non-determinism in event-trace\");",
+ " }",
+ " return;",
+ " }",
+ "#ifdef VERBOSE",
+ " else",
+ " printf(\" event_trace miss '%%c' -- %%d, %%d, %%d\\n\",",
+ " tp, qid, now._event, t->forw);",
+ "#endif",
+ " }",
+ "#ifdef NEGATED_TRACE",
+ " now._event = endevent; /* only 1st try will count -- fixed 4.2.6 */",
+ "#else",
+ "#ifndef BFS",
+ " depth++; trpt++;",
+ "#endif",
+ " uerror(\"event_trace error (no matching event)\");",
+ "#ifndef BFS",
+ " trpt--; depth--;",
+ "#endif",
+ "#endif",
+ "}",
+ "#endif",
+
+ "int",
+ "enabled(int iam, int pid)",
+ "{ Trans *t; uchar *othis = this;",
+ " int res = 0; int tt; uchar ot;",
+ "#ifdef VERI",
+ " /* if (pid > 0) */ pid++;",
+ "#endif",
+ " if (pid == iam)",
+ " Uerror(\"used: enabled(pid=thisproc)\");",
+ " if (pid < 0 || pid >= (int) now._nr_pr)",
+ " return 0;",
+ " this = pptr(pid);",
+ " TstOnly = 1;",
+ " tt = (int) ((P0 *)this)->_p;",
+ " ot = (uchar) ((P0 *)this)->_t;",
+ " for (t = trans[ot][tt]; t; t = t->nxt)",
+ " if (do_transit(t, (short) pid))",
+ " { res = 1;",
+ " break;",
+ " }",
+ " TstOnly = 0;",
+ " this = othis;",
+ " return res;",
+ "}",
+ "#endif",
+ "void",
+ "snapshot(void)",
+ "{ static long sdone = (long) 0;",
+ " long ndone = (unsigned long) nstates/1000000;",
+ " if (ndone == sdone) return;",
+ " sdone = ndone;",
+ " printf(\"Depth= %%7d States= %%7g \", mreached, nstates);",
+ " printf(\"Transitions= %%7g \", nstates+truncs);",
+ "#ifdef MA",
+ " printf(\"Nodes= %%7d \", nr_states);",
+ "#endif",
+ " printf(\"Memory= %%-6.3f\\n\", memcnt/1000000.);",
+ " fflush(stdout);",
+ "}",
+
+ "#ifdef SC",
+ "void",
+ "stack2disk(void)",
+ "{",
+ " if (!stackwrite",
+ " && (stackwrite = creat(stackfile, TMODE)) < 0)",
+ " Uerror(\"cannot create stackfile\");",
+ "",
+ " if (write(stackwrite, trail, DDD*sizeof(Trail))",
+ " != DDD*sizeof(Trail))",
+ " Uerror(\"stackfile write error -- disk is full?\");",
+ "",
+ " memmove(trail, &trail[DDD], (HHH-DDD+2)*sizeof(Trail));",
+ " memset(&trail[HHH-DDD+2], 0, (omaxdepth - HHH + DDD - 2)*sizeof(Trail));",
+ " CNT1++;",
+ "}",
+ "void",
+ "disk2stack(void)",
+ "{ long have;",
+ "",
+ " CNT2++;",
+ " memmove(&trail[DDD], trail, (HHH-DDD+2)*sizeof(Trail));",
+ "",
+ " if (!stackwrite",
+ " || lseek(stackwrite, -DDD* (off_t) sizeof(Trail), SEEK_CUR) == -1)",
+ " Uerror(\"disk2stack lseek error\");",
+ "",
+ " if (!stackread",
+ " && (stackread = open(stackfile, 0)) < 0)",
+ " Uerror(\"cannot open stackfile\");",
+ "",
+ " if (lseek(stackread, (CNT1-CNT2)*DDD* (off_t) sizeof(Trail), SEEK_SET) == -1)",
+ " Uerror(\"disk2stack lseek error\");",
+ "",
+ " have = read(stackread, trail, DDD*sizeof(Trail));",
+ " if (have != DDD*sizeof(Trail))",
+ " Uerror(\"stackfile read error\");",
+ "}",
+ "#endif",
+
+ "uchar *",
+ "Pptr(int x)", /* as a fct, to avoid a problem with the p9 compiler */
+ "{ if (x < 0 || x >= MAXPROC || !proc_offset[x])", /* does not exist */
+ " return noptr;",
+ " else",
+ " return (uchar *) pptr(x);",
+ "}",
+ "int qs_empty(void);",
+
+ "/*",
+ " * new_state() is the main DFS search routine in the verifier",
+ " * it has a lot of code ifdef-ed together to support",
+ " * different search modes, which makes it quite unreadable.",
+ " * if you are studying the code, first use the C preprocessor",
+ " * to generate a specific version from the pan.c source,",
+ " * e.g. by saying:",
+ " * gcc -E -DNOREDUCE -DBITSTATE pan.c > ppan.c",
+ " * and then study the resulting file, rather than this one",
+ " */",
+ "#if !defined(BFS) && (!defined(BITSTATE) || !defined(MA))",
+ "void",
+ "new_state(void)",
+ "{ Trans *t;",
+ " uchar _n, _m, ot;",
+ "#ifdef RANDOMIZE",
+ " short ooi, eoi;",
+ "#endif",
+ "#ifdef M_LOSS",
+ " uchar delta_m = 0;",
+ "#endif",
+ " short II, JJ = 0, kk;",
+ " int tt;",
+ " short From = now._nr_pr-1, To = BASE;",
+ "Down:",
+ "#ifdef CHECK",
+ " printf(\"%%d: Down - %%s\",",
+ " depth, (trpt->tau&4)?\"claim\":\"program\");",
+ " printf(\" %%saccepting [pids %%d-%%d]\\n\",",
+ " (trpt->o_pm&2)?\"\":\"non-\", From, To);",
+ "#endif",
+
+ "#ifdef SC",
+ " if (depth > hiwater)",
+ " { stack2disk();",
+ " maxdepth += DDD;",
+ " hiwater += DDD;",
+ " trpt -= DDD;",
+ " if(verbose)",
+ " printf(\"zap %%d: %%d (maxdepth now %%d)\\n\",",
+ " CNT1, hiwater, maxdepth);",
+ " }",
+ "#endif",
+
+ " trpt->tau &= ~(16|32|64); /* make sure these are off */",
+ "#if defined(FULLSTACK) && defined(MA)",
+ " trpt->proviso = 0;",
+ "#endif",
+ " if (depth >= maxdepth)",
+ " { truncs++;",
+ "#if SYNC",
+ " (trpt+1)->o_n = 1; /* not a deadlock */",
+ "#endif",
+ " if (!warned)",
+ " { warned = 1;",
+ " printf(\"error: max search depth too small\\n\");",
+ " }",
+ " if (bounded) uerror(\"depth limit reached\");",
+ " (trpt-1)->tau |= 16; /* worstcase guess */",
+ " goto Up;",
+ " }",
+ "AllOver:",
+ "#if defined(FULLSTACK) && !defined(MA)",
+ " /* if atomic or rv move, carry forward previous state */",
+ " trpt->ostate = (trpt-1)->ostate;", /* was: = (struct H_el *) 0;*/
+ "#endif",
+ "#ifdef VERI",
+ " if ((trpt->tau&4) || ((trpt-1)->tau&128))",
+ "#endif",
+ " if (boq == -1) { /* if not mid-rv */",
+ "#ifndef SAFETY",
+ " /* this check should now be redundant",
+ " * because the seed state also appears",
+ " * on the 1st dfs stack and would be",
+ " * matched in hstore below",
+ " */",
+ " if ((now._a_t&1) && depth > A_depth)",
+ " { if (!memcmp((char *)&A_Root, ",
+ " (char *)&now, vsize))",
+ " {",
+ " depthfound = A_depth;",
+ "#ifdef CHECK",
+ " printf(\"matches seed\\n\");",
+ "#endif",
+ "#ifdef NP",
+ " uerror(\"non-progress cycle\");",
+ "#else",
+ " uerror(\"acceptance cycle\");",
+ "#endif",
+ " goto Up;",
+ " }",
+ "#ifdef CHECK",
+ " printf(\"not seed\\n\");",
+ "#endif",
+ " }",
+ "#endif",
+ " if (!(trpt->tau&8)) /* if no atomic move */",
+ " {",
+ "#ifdef BITSTATE",
+ "#ifdef CNTRSTACK", /* -> bitstate, reduced, safety */
+ " II = bstore((char *)&now, vsize);",
+ " trpt->j6 = j1; trpt->j7 = j2;",
+ " JJ = LL[j1] && LL[j2];",
+ "#else",
+ "#ifdef FULLSTACK",
+ " JJ = onstack_now();", /* sets j1 */
+ "#else",
+ "#ifndef NOREDUCE",
+ " JJ = II; /* worstcase guess for p.o. */",
+ "#endif",
+ "#endif",
+ " II = bstore((char *)&now, vsize);", /* sets j1-j4 */
+ "#endif",
+ "#else",
+ "#ifdef MA",
+ " II = gstore((char *)&now, vsize, 0);",
+ "#ifndef FULLSTACK",
+ " JJ = II;",
+ "#else",
+ " JJ = (II == 2)?1:0;",
+ "#endif",
+ "#else",
+ " II = hstore((char *)&now, vsize);",
+ "#ifdef FULLSTACK",
+ " JJ = (II == 2)?1:0;",
+ "#endif",
+ "#endif",
+ "#endif",
+ " kk = (II == 1 || II == 2);",
+ /* II==0 new state */
+ /* II==1 old state */
+ /* II==2 on current dfs stack */
+ /* II==3 on 1st dfs stack */
+ "#ifndef SAFETY",
+
+ " if (!fairness && a_cycles)",
+ " if (II == 2 && ((trpt->o_pm&2) || ((trpt-1)->o_pm&2)))",
+ " { II = 3; /* Schwoon & Esparza 2005, Gastin&Moro 2004 */",
+ "#ifdef VERBOSE",
+ " printf(\"state match on dfs stack\\n\");",
+ "#endif",
+ " goto same_case;",
+ " }",
+
+
+ "#if defined(FULLSTACK) && defined(BITSTATE)",
+ " if (!JJ && (now._a_t&1) && depth > A_depth)",
+ " { int oj1 = j1;",
+ " uchar o_a_t = now._a_t;",
+ " now._a_t &= ~(1|16|32);", /* 1st stack */
+ " if (onstack_now())", /* changes j1 */
+ " { II = 3;",
+ "#ifdef VERBOSE",
+ " printf(\"state match on 1st dfs stack\\n\");",
+ "#endif",
+ " }",
+ " now._a_t = o_a_t;", /* restore */
+ " j1 = oj1;",
+ " }",
+ "#endif",
+ " if (II == 3 && a_cycles && (now._a_t&1))",
+ " {",
+ "#ifndef NOFAIR",
+ " if (fairness && now._cnt[1] > 1) /* was != 0 */",
+ " {",
+ "#ifdef VERBOSE",
+ " printf(\"\tfairness count non-zero\\n\");",
+ "#endif",
+ " II = 0;", /* treat as new state */
+ " } else",
+ "#endif",
+ " {",
+ "#ifndef BITSTATE",
+ " nShadow--;",
+ "#endif",
+ "same_case: if (Lstate) depthfound = Lstate->D;",
+ "#ifdef NP",
+ " uerror(\"non-progress cycle\");",
+ "#else",
+ " uerror(\"acceptance cycle\");",
+ "#endif",
+ " goto Up;",
+ " }",
+ " }",
+ "#endif",
+
+ "#ifndef NOREDUCE",
+ "#ifndef SAFETY",
+ " if ((II && JJ) || (II == 3))",
+ " { /* marker for liveness proviso */",
+ " (trpt-1)->tau |= 16;",
+ " truncs2++;",
+ " }",
+ "#else",
+ " if (!II || !JJ)",
+ " { /* successor outside stack */",
+ " (trpt-1)->tau |= 64;",
+ " }",
+ "#endif",
+ "#endif",
+ " if (II)",
+ " { truncs++;",
+ " goto Up;",
+ " }",
+ " if (!kk)",
+ " { nstates++;",
+ " if ((unsigned long) nstates%%1000000 == 0)",
+ " snapshot();",
+ "#ifdef SVDUMP",
+ " if (vprefix > 0)",
+ " if (write(svfd, (uchar *) &now, vprefix) != vprefix)",
+ " { fprintf(efd, \"writing %%s.svd failed\\n\", Source);",
+ " wrapup();",
+ " }",
+ "#endif",
+ "#if defined(MA) && defined(W_XPT)",
+ " if ((unsigned long) nstates%%W_XPT == 0)",
+ " { void w_xpoint(void);",
+ " w_xpoint();",
+ " }",
+ "#endif",
+ " }",
+ "#if defined(FULLSTACK) || defined(CNTRSTACK)",
+ " onstack_put();",
+ "#ifdef DEBUG2",
+ "#if defined(FULLSTACK) && !defined(MA)",
+ " printf(\"%%d: putting %%u (%%d)\\n\", depth,",
+ " trpt->ostate, ",
+ " (trpt->ostate)?trpt->ostate->tagged:0);",
+ "#else",
+ " printf(\"%%d: putting\\n\", depth);",
+ "#endif",
+ "#endif",
+ "#endif",
+ " } }",
+
+
+ " if (depth > mreached)",
+ " mreached = depth;",
+ "#ifdef VERI",
+ " if (trpt->tau&4)",
+ "#endif",
+ " trpt->tau &= ~(1|2); /* timeout and -request off */",
+ " _n = 0;",
+ "#if SYNC",
+ " (trpt+1)->o_n = 0;",
+ "#endif",
+ "#ifdef VERI",
+ " if (now._nr_pr == 0) /* claim terminated */",
+ " uerror(\"end state in claim reached\");",
+ " check_claim(((P0 *)pptr(0))->_p);",
+ "Stutter:",
+ " if (trpt->tau&4) /* must make a claimmove */",
+ " {",
+
+ "#ifndef NOFAIR",
+ " if ((now._a_t&2) /* A-bit set */",
+ " && now._cnt[now._a_t&1] == 1)",
+ " { now._a_t &= ~2;",
+ " now._cnt[now._a_t&1] = 0;",
+ " trpt->o_pm |= 16;",
+ "#ifdef DEBUG",
+ " printf(\"%%3d: fairness Rule 3.: _a_t = %%d\\n\",",
+ " depth, now._a_t);",
+ "#endif",
+ " }",
+ "#endif",
+
+ " II = 0; /* never */",
+ " goto Veri0;",
+ " }",
+ "#endif",
+ "#ifndef NOREDUCE",
+ " /* Look for a process with only safe transitions */",
+ " /* (special rules apply in the 2nd dfs) */",
+"#ifdef SAFETY",
+ " if (boq == -1 && From != To)",
+"#else",
+ "/* implied: #ifdef FULLSTACK */",
+ " if (boq == -1 && From != To",
+ " && (!(now._a_t&1)",
+ " || (a_cycles &&",
+ "#ifndef BITSTATE",
+ "#ifdef MA",
+ "#ifdef VERI",
+ " !((trpt-1)->proviso))",
+ "#else",
+ " !(trpt->proviso))",
+ "#endif",
+ "#else",
+ "#ifdef VERI",
+ " (trpt-1)->ostate &&",
+ " !(((char *)&((trpt-1)->ostate->state))[0] & 128))",
+ "#else",
+ " !(((char *)&(trpt->ostate->state))[0] & 128))",
+ "#endif",
+ "#endif",
+ "#else",
+ "#ifdef VERI",
+ " (trpt-1)->ostate &&",
+ " (trpt-1)->ostate->proviso == 0)",
+ "#else",
+ " trpt->ostate->proviso == 0)",
+ "#endif",
+ "#endif",
+ " ))",
+ "/* #endif */",
+"#endif",
+ " for (II = From; II >= To; II -= 1)",
+ " {",
+ "Resume: /* pick up here if preselect fails */",
+ " this = pptr(II);",
+ " tt = (int) ((P0 *)this)->_p;",
+ " ot = (uchar) ((P0 *)this)->_t;",
+ " if (trans[ot][tt]->atom & 8)",
+ " { t = trans[ot][tt];",
+ " if (t->qu[0] != 0)",
+ " { Ccheck++;",
+ " if (!q_cond(II, t))",
+ " continue;",
+ " Cholds++;",
+ " }",
+ " From = To = II;",
+ "#ifdef NIBIS",
+ " t->om = 0;",
+ "#endif",
+ " trpt->tau |= 32; /* preselect marker */",
+ "#ifdef DEBUG",
+ "#ifdef NIBIS",
+ " printf(\"%%3d: proc %%d Pre\", depth, II);",
+ " printf(\"Selected (om=%%d, tau=%%d)\\n\", ",
+ " t->om, trpt->tau);",
+ "#else",
+ " printf(\"%%3d: proc %%d PreSelected (tau=%%d)\\n\", ",
+ " depth, II, trpt->tau);",
+ "#endif",
+ "#endif",
+ " goto Again;",
+ " }",
+ " }",
+ " trpt->tau &= ~32;",
+ "#endif",
+ "#if !defined(NOREDUCE) || (defined(ETIM) && !defined(VERI))",
+ "Again:",
+ "#endif",
+ " /* The Main Expansion Loop over Processes */",
+
+ " trpt->o_pm &= ~(8|16|32|64); /* fairness-marks */",
+
+ "#ifndef NOFAIR",
+ " if (fairness && boq == -1",
+ "#ifdef VERI",
+ " && (!(trpt->tau&4) && !((trpt-1)->tau&128))",
+ "#endif",
+ " && !(trpt->tau&8))",
+ " { /* A_bit = 1; Cnt = N in acc states with A_bit 0 */",
+ " if (!(now._a_t&2))", /* A-bit not set */
+ " {",
+ " if (a_cycles && (trpt->o_pm&2))",
+ " { /* Accepting state */",
+ " now._a_t |= 2;",
+ " now._cnt[now._a_t&1] = now._nr_pr + 1;", /* NEW +1 */
+ " trpt->o_pm |= 8;",
+ "#ifdef DEBUG",
+ " printf(\"%%3d: fairness Rule 1: cnt=%%d, _a_t=%%d\\n\",",
+ " depth, now._cnt[now._a_t&1], now._a_t);",
+ "#endif",
+ " }",
+ " } else", /* A-bit set */
+ " { /* A_bit = 0 when Cnt 0 */",
+ " if (now._cnt[now._a_t&1] == 1)", /* NEW: 1 iso 0 */
+ " { now._a_t &= ~2;", /* reset a-bit */
+ " now._cnt[now._a_t&1] = 0;", /* NEW: reset cnt */
+ " trpt->o_pm |= 16;",
+ "#ifdef DEBUG",
+ " printf(\"%%3d: fairness Rule 3: _a_t = %%d\\n\",",
+ " depth, now._a_t);",
+ "#endif",
+ " } } }",
+ "#endif",
+
+ " for (II = From; II >= To; II -= 1)",
+ " {",
+ "#if SYNC",
+ " /* no rendezvous with same proc */",
+ " if (boq != -1 && trpt->pr == II) continue;",
+ "#endif",
+ "#ifdef VERI",
+ "Veri0:",
+ "#endif",
+ " this = pptr(II);",
+ " tt = (int) ((P0 *)this)->_p;",
+ " ot = (uchar) ((P0 *)this)->_t;",
+
+ "#ifdef NIBIS",
+ " /* don't repeat a previous preselected expansion */",
+ " /* could hit this if reduction proviso was false */",
+ " t = trans[ot][tt];",
+ " if (!(trpt->tau&4)", /* not claim */
+ " && !(trpt->tau&1)", /* not timeout */
+ " && !(trpt->tau&32)", /* not preselected */
+ " && (t->atom & 8)", /* local */
+ " && boq == -1", /* not inside rendezvous */
+ " && From != To)", /* not inside atomic seq */
+ " { if (t->qu[0] == 0", /* unconditional */
+ " || q_cond(II, t))", /* true condition */
+ " { _m = t->om;",
+ " if (_m>_n||(_n>3&&_m!=0)) _n=_m;",
+ " continue; /* did it before */",
+ " } }",
+ "#endif",
+ " trpt->o_pm &= ~1; /* no move in this pid yet */",
+ "#ifdef EVENT_TRACE",
+ " (trpt+1)->o_event = now._event;",
+ "#endif",
+ " /* Fairness: Cnt++ when Cnt == II */",
+ "#ifndef NOFAIR",
+ " trpt->o_pm &= ~64; /* didn't apply rule 2 */",
+ " if (fairness",
+ " && boq == -1", /* not mid rv - except rcv - NEW 3.0.8 */
+ " && !(trpt->o_pm&32)", /* Rule 2 not in effect */
+ " && (now._a_t&2)", /* A-bit is set */
+ " && now._cnt[now._a_t&1] == II+2)",
+ " { now._cnt[now._a_t&1] -= 1;",
+ "#ifdef VERI",
+ " /* claim need not participate */",
+ " if (II == 1)",
+ " now._cnt[now._a_t&1] = 1;",
+ "#endif",
+ "#ifdef DEBUG",
+ " printf(\"%%3d: proc %%d fairness \", depth, II);",
+ " printf(\"Rule 2: --cnt to %%d (%%d)\\n\",",
+ " now._cnt[now._a_t&1], now._a_t);",
+ "#endif",
+ " trpt->o_pm |= (32|64);",
+ " }",
+ "#endif",
+ "#ifdef HAS_PROVIDED",
+ " if (!provided(II, ot, tt, t)) continue;",
+ "#endif",
+ " /* check all trans of proc II - escapes first */",
+ "#ifdef HAS_UNLESS",
+ " trpt->e_state = 0;",
+ "#endif",
+ " (trpt+1)->pr = (uchar) II;", /* for uerror */
+ " (trpt+1)->st = tt;",
+
+ "#ifdef RANDOMIZE",
+ " for (ooi = eoi = 0, t = trans[ot][tt]; t; t = t->nxt, ooi++)",
+ " if (strcmp(t->tp, \"else\") == 0)",
+ " eoi++;",
+ "",
+ " if (eoi)",
+ " { t = trans[ot][tt];",
+ "#ifdef VERBOSE",
+ " printf(\"randomizer: suppressed, saw else\\n\");",
+ "#endif",
+ " } else",
+ " { eoi = rand()%%ooi;",
+ "#ifdef VERBOSE",
+ " printf(\"randomizer: skip %%d in %%d\\n\", eoi, ooi);",
+ "#endif",
+ " for (t = trans[ot][tt]; t; t = t->nxt)",
+ " if (eoi-- <= 0) break;",
+ " }",
+ "DOMORE:",
+ " for ( ; t && ooi > 0; t = t->nxt, ooi--)",
+ "#else",
+ " for (t = trans[ot][tt]; t; t = t->nxt)",
+ "#endif",
+ " {",
+ "#ifdef HAS_UNLESS",
+ " /* exploring all transitions from",
+ " * a single escape state suffices",
+ " */",
+ " if (trpt->e_state > 0",
+ " && trpt->e_state != t->e_trans)",
+ " {",
+ "#ifdef DEBUG",
+ " printf(\"skip 2nd escape %%d (did %%d before)\\n\",",
+ " t->e_trans, trpt->e_state);",
+ "#endif",
+ " break;",
+ " }",
+ "#endif",
+ " (trpt+1)->o_t = t;", /* for uerror */
+ "#ifdef INLINE",
+ "#include FORWARD_MOVES",
+ "P999: /* jumps here when move succeeds */",
+ "#else",
+ " if (!(_m = do_transit(t, II))) continue;",
+ "#endif",
+ " if (boq == -1)",
+"#ifdef CTL",
+ " /* for branching-time, can accept reduction only if */",
+ " /* the persistent set contains just 1 transition */",
+ " { if ((trpt->tau&32) && (trpt->o_pm&1))",
+ " trpt->tau |= 16;",
+ " trpt->o_pm |= 1; /* we moved */",
+ " }",
+"#else",
+ " trpt->o_pm |= 1; /* we moved */",
+"#endif",
+ "#ifdef PEG",
+ " peg[t->forw]++;",
+ "#endif",
+
+ "#if defined(VERBOSE) || defined(CHECK)",
+ "#if defined(SVDUMP)",
+ " printf(\"%%3d: proc %%d exec %%d \\n\", ",
+ " depth, II, t->t_id);",
+ "#else",
+ " printf(\"%%3d: proc %%d exec %%d, \", ",
+ " depth, II, t->forw);",
+ " printf(\"%%d to %%d, %%s %%s %%s\", ",
+ " tt, t->st, t->tp,",
+ " (t->atom&2)?\"atomic\":\"\",",
+ " (boq != -1)?\"rendez-vous\":\"\");",
+ "#ifdef HAS_UNLESS",
+ " if (t->e_trans)",
+ " printf(\" (escapes to state %%d)\",",
+ " t->st);",
+ "#endif",
+ " printf(\" %%saccepting [tau=%%d]\\n\",",
+ " (trpt->o_pm&2)?\"\":\"non-\", trpt->tau);",
+ "#endif",
+ "#ifdef RANDOMIZE",
+ " printf(\" randomizer %%d\\n\", ooi);",
+ "#endif",
+ "#endif",
+
+ "#ifdef HAS_LAST",
+ "#ifdef VERI",
+ " if (II != 0)",
+ "#endif",
+ " now._last = II - BASE;",
+ "#endif",
+ "#ifdef HAS_UNLESS",
+ " trpt->e_state = t->e_trans;",
+ "#endif",
+
+ " depth++; trpt++;",
+ " trpt->pr = (uchar) II;",
+ " trpt->st = tt;",
+ " trpt->o_pm &= ~(2|4);",
+ " if (t->st > 0)",
+ " { ((P0 *)this)->_p = t->st;",
+ "/* moved down reached[ot][t->st] = 1; */",
+ " }",
+ "#ifndef SAFETY",
+ " if (a_cycles)",
+ " {",
+ "#if (ACCEPT_LAB>0 && !defined(NP)) || (PROG_LAB>0 && defined(HAS_NP))",
+ " int ii;",
+ "#endif",
+ "#define P__Q ((P0 *)pptr(ii))",
+ "#if ACCEPT_LAB>0",
+ "#ifdef NP",
+ " /* state 1 of np_ claim is accepting */",
+ " if (((P0 *)pptr(0))->_p == 1)",
+ " trpt->o_pm |= 2;",
+ "#else",
+ " for (ii = 0; ii < (int) now._nr_pr; ii++)",
+ " { if (accpstate[P__Q->_t][P__Q->_p])",
+ " { trpt->o_pm |= 2;",
+ " break;",
+ " } }",
+ "#endif",
+ "#endif",
+ "#if defined(HAS_NP) && PROG_LAB>0",
+ " for (ii = 0; ii < (int) now._nr_pr; ii++)",
+ " { if (progstate[P__Q->_t][P__Q->_p])",
+ " { trpt->o_pm |= 4;",
+ " break;",
+ " } }",
+ "#endif",
+ "#undef P__Q",
+ " }",
+ "#endif",
+ " trpt->o_t = t; trpt->o_n = _n;",
+ " trpt->o_ot = ot; trpt->o_tt = tt;",
+ " trpt->o_To = To; trpt->o_m = _m;",
+ " trpt->tau = 0;",
+"#ifdef RANDOMIZE",
+ " trpt->oo_i = ooi;",
+"#endif",
+ " if (boq != -1 || (t->atom&2))",
+ " { trpt->tau |= 8;",
+ "#ifdef VERI",
+ " /* atomic sequence in claim */",
+ " if((trpt-1)->tau&4)",
+ " trpt->tau |= 4;",
+ " else",
+ " trpt->tau &= ~4;",
+ " } else",
+ " { if ((trpt-1)->tau&4)",
+ " trpt->tau &= ~4;",
+ " else",
+ " trpt->tau |= 4;",
+ " }",
+ " /* if claim allowed timeout, so */",
+ " /* does the next program-step: */",
+ " if (((trpt-1)->tau&1) && !(trpt->tau&4))",
+ " trpt->tau |= 1;",
+ "#else",
+ " } else",
+ " trpt->tau &= ~8;",
+ "#endif",
+ " if (boq == -1 && (t->atom&2))",
+ " { From = To = II; nlinks++;",
+ " } else",
+ " { From = now._nr_pr-1; To = BASE;",
+ " }",
+ " goto Down; /* pseudo-recursion */",
+ "Up:",
+ "#ifdef CHECK",
+ " printf(\"%%d: Up - %%s\\n\", depth,",
+ " (trpt->tau&4)?\"claim\":\"program\");",
+ "#endif",
+ "#ifdef MA",
+ " if (depth <= 0) return;",
+ " /* e.g., if first state is old, after a restart */",
+ "#endif",
+
+ "#ifdef SC",
+ " if (CNT1 > CNT2",
+ " && depth < hiwater - (HHH-DDD) + 2)",
+ " {",
+ " trpt += DDD;",
+ " disk2stack();",
+ " maxdepth -= DDD;",
+ " hiwater -= DDD;",
+ "if(verbose)",
+ "printf(\"unzap %%d: %%d\\n\", CNT2, hiwater);",
+ " }",
+ "#endif",
+
+ "#ifndef NOFAIR",
+ " if (trpt->o_pm&128) /* fairness alg */",
+ " { now._cnt[now._a_t&1] = trpt->bup.oval;",
+ " _n = 1; trpt->o_pm &= ~128;",
+ " depth--; trpt--;",
+ "#if defined(VERBOSE) || defined(CHECK)",
+ " printf(\"%%3d: reversed fairness default move\\n\", depth);",
+ "#endif",
+ " goto Q999;",
+ " }",
+ "#endif",
+
+ "#ifdef HAS_LAST",
+ "#ifdef VERI",
+ " { int d; Trail *trl;",
+ " now._last = 0;",
+ " for (d = 1; d < depth; d++)",
+ " { trl = getframe(depth-d); /* was (trpt-d) */",
+ " if (trl->pr != 0)",
+ " { now._last = trl->pr - BASE;",
+ " break;",
+ " } } }",
+ "#else",
+ " now._last = (depth<1)?0:(trpt-1)->pr;",
+ "#endif",
+ "#endif",
+ "#ifdef EVENT_TRACE",
+ " now._event = trpt->o_event;",
+ "#endif",
+ "#ifndef SAFETY",
+ " if ((now._a_t&1) && depth <= A_depth)",
+ " return; /* to checkcycles() */",
+ "#endif",
+ " t = trpt->o_t; _n = trpt->o_n;",
+ " ot = trpt->o_ot; II = trpt->pr;",
+ " tt = trpt->o_tt; this = pptr(II);",
+ " To = trpt->o_To; _m = trpt->o_m;",
+"#ifdef RANDOMIZE",
+ " ooi = trpt->oo_i;",
+"#endif",
+ "#ifdef INLINE_REV",
+ " _m = do_reverse(t, II, _m);",
+ "#else",
+ "#include REVERSE_MOVES",
+ "R999: /* jumps here when done */",
+ "#endif",
+
+ "#ifdef VERBOSE",
+ " printf(\"%%3d: proc %%d \", depth, II);",
+ " printf(\"reverses %%d, %%d to %%d,\",",
+ " t->forw, tt, t->st);",
+ " printf(\" %%s [abit=%%d,adepth=%%d,\", ",
+ " t->tp, now._a_t, A_depth);",
+ " printf(\"tau=%%d,%%d]\\n\", ",
+ " trpt->tau, (trpt-1)->tau);",
+ "#endif",
+ "#ifndef NOREDUCE",
+ " /* pass the proviso tags */",
+ " if ((trpt->tau&8) /* rv or atomic */",
+ " && (trpt->tau&16))",
+ " (trpt-1)->tau |= 16;",
+ "#ifdef SAFETY",
+ " if ((trpt->tau&8) /* rv or atomic */",
+ " && (trpt->tau&64))",
+ " (trpt-1)->tau |= 64;",
+ "#endif",
+ "#endif",
+ " depth--; trpt--;",
+ "#ifdef NIBIS",
+ " (trans[ot][tt])->om = _m; /* head of list */",
+ "#endif",
+
+ " /* i.e., not set if rv fails */",
+ " if (_m)",
+ " {",
+ "#if defined(VERI) && !defined(NP)",
+ " if (II == 0 && verbose && !reached[ot][t->st])",
+ " {",
+ " printf(\"depth %%d: Claim reached state %%d (line %%d)\\n\",",
+ " depth, t->st, src_claim [t->st]);",
+ " fflush(stdout);",
+ " }",
+ "#endif",
+ " reached[ot][t->st] = 1;",
+ " reached[ot][tt] = 1;",
+ " }",
+ "#ifdef HAS_UNLESS",
+ " else trpt->e_state = 0; /* undo */",
+ "#endif",
+
+ " if (_m>_n||(_n>3&&_m!=0)) _n=_m;",
+ " ((P0 *)this)->_p = tt;",
+ " } /* all options */",
+
+ "#ifdef RANDOMIZE",
+ " if (!t && ooi > 0)", /* means we skipped some initial options */
+ " { t = trans[ot][tt];",
+ "#ifdef VERBOSE",
+ " printf(\"randomizer: continue for %%d more\\n\", ooi);",
+ "#endif",
+ " goto DOMORE;",
+ " }",
+ "#ifdef VERBOSE",
+ " else",
+ " printf(\"randomizer: done\\n\");",
+ "#endif",
+ "#endif",
+
+ "#ifndef NOFAIR",
+ " /* Fairness: undo Rule 2 */",
+ " if ((trpt->o_pm&32)",/* rule 2 was applied */
+ " && (trpt->o_pm&64))",/* by this process II */
+ " { if (trpt->o_pm&1)",/* it didn't block */
+ " {",
+ "#ifdef VERI",
+ " if (now._cnt[now._a_t&1] == 1)", /* NEW: 1 iso 0 */
+ " now._cnt[now._a_t&1] = 2;", /* NEW: 2 iso 1*/
+ "#endif",
+ " now._cnt[now._a_t&1] += 1;",
+ "#ifdef VERBOSE",
+ " printf(\"%%3d: proc %%d fairness \", depth, II);",
+ " printf(\"undo Rule 2, cnt=%%d, _a_t=%%d\\n\",",
+ " now._cnt[now._a_t&1], now._a_t);",
+ "#endif",
+ " trpt->o_pm &= ~(32|64);",
+ " } else", /* process blocked */
+ " { if (_n > 0)", /* a prev proc didn't */
+ " {", /* start over */
+ " trpt->o_pm &= ~64;",
+ " II = From+1;",
+ " } } }",
+ "#endif",
+
+ "#ifdef VERI",
+ " if (II == 0) break; /* never claim */",
+ "#endif",
+ " } /* all processes */",
+
+ "#ifndef NOFAIR",
+ " /* Fairness: undo Rule 2 */",
+ " if (trpt->o_pm&32) /* remains if proc blocked */",
+ " {",
+ "#ifdef VERI",
+ " if (now._cnt[now._a_t&1] == 1)", /* NEW: 1 iso 0 */
+ " now._cnt[now._a_t&1] = 2;", /* NEW: 2 iso 1 */
+ "#endif",
+ " now._cnt[now._a_t&1] += 1;",
+ "#ifdef VERBOSE",
+ " printf(\"%%3d: proc -- fairness \", depth);",
+ " printf(\"undo Rule 2, cnt=%%d, _a_t=%%d\\n\",",
+ " now._cnt[now._a_t&1], now._a_t);",
+ "#endif",
+ " trpt->o_pm &= ~32;",
+ " }",
+"#ifndef NP",
+ /* 12/97 non-progress cycles cannot be created
+ * by stuttering extension, here or elsewhere
+ */
+ " if (fairness",
+ " && _n == 0 /* nobody moved */",
+ "#ifdef VERI",
+ " && !(trpt->tau&4) /* in program move */",
+ "#endif",
+ " && !(trpt->tau&8) /* not an atomic one */",
+ "#ifdef OTIM",
+ " && ((trpt->tau&1) || endstate())",
+ "#else",
+ "#ifdef ETIM",
+ " && (trpt->tau&1) /* already tried timeout */",
+ "#endif",
+ "#endif",
+ "#ifndef NOREDUCE",
+ " /* see below */",
+ " && !((trpt->tau&32) && (_n == 0 || (trpt->tau&16)))",
+ "#endif",
+ " && now._cnt[now._a_t&1] > 0) /* needed more procs */",
+ " { depth++; trpt++;",
+ " trpt->o_pm |= 128 | ((trpt-1)->o_pm&(2|4));",
+ " trpt->bup.oval = now._cnt[now._a_t&1];",
+ " now._cnt[now._a_t&1] = 1;",
+ "#ifdef VERI",
+ " trpt->tau = 4;",
+ "#else",
+ " trpt->tau = 0;",
+ "#endif",
+ " From = now._nr_pr-1; To = BASE;",
+ "#if defined(VERBOSE) || defined(CHECK)",
+ " printf(\"%%3d: fairness default move \", depth);",
+ " printf(\"(all procs block)\\n\");",
+ "#endif",
+ " goto Down;",
+ " }",
+"#endif",
+ "Q999: /* returns here with _n>0 when done */;",
+
+ " if (trpt->o_pm&8)",
+ " { now._a_t &= ~2;",
+ " now._cnt[now._a_t&1] = 0;",
+ " trpt->o_pm &= ~8;",
+ "#ifdef VERBOSE",
+ " printf(\"%%3d: fairness undo Rule 1, _a_t=%%d\\n\",",
+ " depth, now._a_t);",
+ "#endif",
+ " }",
+ " if (trpt->o_pm&16)",
+ " { now._a_t |= 2;", /* restore a-bit */
+ " now._cnt[now._a_t&1] = 1;", /* NEW: restore cnt */
+ " trpt->o_pm &= ~16;",
+ "#ifdef VERBOSE",
+ " printf(\"%%3d: fairness undo Rule 3, _a_t=%%d\\n\",",
+ " depth, now._a_t);",
+ "#endif",
+ " }",
+ "#endif",
+
+ "#ifndef NOREDUCE",
+"#ifdef SAFETY",
+ " /* preselected move - no successors outside stack */",
+ " if ((trpt->tau&32) && !(trpt->tau&64))",
+ " { From = now._nr_pr-1; To = BASE;",
+ "#ifdef DEBUG",
+ " printf(\"%%3d: proc %%d UnSelected (_n=%%d, tau=%%d)\\n\", ",
+ " depth, II+1, _n, trpt->tau);",
+ "#endif",
+ " _n = 0; trpt->tau &= ~(16|32|64);",
+ " if (II >= BASE) /* II already decremented */",
+ " goto Resume;",
+ " else",
+ " goto Again;",
+ " }",
+"#else",
+ " /* at least one move that was preselected at this */",
+ " /* level, blocked or truncated at the next level */",
+ "/* implied: #ifdef FULLSTACK */",
+ " if ((trpt->tau&32) && (_n == 0 || (trpt->tau&16)))",
+ " {",
+ "#ifdef DEBUG",
+ " printf(\"%%3d: proc %%d UnSelected (_n=%%d, tau=%%d)\\n\", ",
+ " depth, II+1, (int) _n, trpt->tau);",
+ "#endif",
+ " if (a_cycles && (trpt->tau&16))",
+ " { if (!(now._a_t&1))",
+ " {",
+ "#ifdef DEBUG",
+ " printf(\"%%3d: setting proviso bit\\n\", depth);",
+ "#endif",
+ "#ifndef BITSTATE",
+ "#ifdef MA",
+ "#ifdef VERI",
+ " (trpt-1)->proviso = 1;",
+ "#else",
+ " trpt->proviso = 1;",
+ "#endif",
+ "#else",
+ "#ifdef VERI",
+ " if ((trpt-1)->ostate)",
+ " ((char *)&((trpt-1)->ostate->state))[0] |= 128;",
+ "#else",
+ " ((char *)&(trpt->ostate->state))[0] |= 128;",
+ "#endif",
+ "#endif",
+ "#else",
+ "#ifdef VERI",
+ " if ((trpt-1)->ostate)",
+ " (trpt-1)->ostate->proviso = 1;",
+ "#else",
+ " trpt->ostate->proviso = 1;",
+ "#endif",
+ "#endif",
+ " From = now._nr_pr-1; To = BASE;",
+ " _n = 0; trpt->tau &= ~(16|32|64);",
+ " goto Again; /* do full search */",
+ " } /* else accept reduction */",
+ " } else",
+ " { From = now._nr_pr-1; To = BASE;",
+ " _n = 0; trpt->tau &= ~(16|32|64);",
+ " if (II >= BASE) /* already decremented */",
+ " goto Resume;",
+ " else",
+ " goto Again;",
+ " } }",
+ "/* #endif */",
+"#endif",
+ "#endif",
+
+ " if (_n == 0 || ((trpt->tau&4) && (trpt->tau&2)))",
+ " {",
+ "#ifdef DEBUG",
+ " printf(\"%%3d: no move [II=%%d, tau=%%d, boq=%%d]\\n\",",
+ " depth, II, trpt->tau, boq);",
+ "#endif",
+ "#if SYNC",
+ " /* ok if a rendez-vous fails: */",
+ " if (boq != -1) goto Done;",
+ "#endif",
+ " /* ok if no procs or we're at maxdepth */",
+ " if ((now._nr_pr == 0 && (!strict || qs_empty()))",
+ "#ifdef OTIM",
+ " || endstate()",
+ "#endif",
+ " || depth >= maxdepth-1) goto Done;",
+
+ " if ((trpt->tau&8) && !(trpt->tau&4))",
+ " { trpt->tau &= ~(1|8);",
+ " /* 1=timeout, 8=atomic */",
+ " From = now._nr_pr-1; To = BASE;",
+ "#ifdef DEBUG",
+ " printf(\"%%3d: atomic step proc %%d \", depth, II+1);",
+ " printf(\"unexecutable\\n\");",
+ "#endif",
+ "#ifdef VERI",
+ " trpt->tau |= 4; /* switch to claim */",
+ "#endif",
+ " goto AllOver;",
+ " }",
+
+ "#ifdef ETIM",
+ " if (!(trpt->tau&1)) /* didn't try timeout yet */",
+ " {",
+ "#ifdef VERI",
+ " if (trpt->tau&4)",
+ " {",
+ "#ifndef NTIM",
+ " if (trpt->tau&2) /* requested */",
+ "#endif",
+ " { trpt->tau |= 1;",
+ " trpt->tau &= ~2;",
+ "#ifdef DEBUG",
+ " printf(\"%%d: timeout\\n\", depth);",
+ "#endif",
+ " goto Stutter;",
+ " } }",
+ " else",
+ " { /* only claim can enable timeout */",
+ " if ((trpt->tau&8)",
+ " && !((trpt-1)->tau&4))",
+ "/* blocks inside an atomic */ goto BreakOut;",
+ "#ifdef DEBUG",
+ " printf(\"%%d: req timeout\\n\",",
+ " depth);",
+ "#endif",
+ " (trpt-1)->tau |= 2; /* request */",
+ " goto Up;",
+ " }",
+ "#else",
+
+ "#ifdef DEBUG",
+ " printf(\"%%d: timeout\\n\", depth);",
+ "#endif",
+ " trpt->tau |= 1;",
+ " goto Again;",
+ "#endif",
+ " }",
+ "#endif",
+
+ /* old location of atomic block code */
+ "#ifdef VERI",
+ "BreakOut:",
+ "#ifndef NOSTUTTER",
+ " if (!(trpt->tau&4))",
+ " { trpt->tau |= 4; /* claim stuttering */",
+ " trpt->tau |= 128; /* stutter mark */",
+ "#ifdef DEBUG",
+ " printf(\"%%d: claim stutter\\n\", depth);",
+ "#endif",
+ " goto Stutter;",
+ " }",
+ "#else",
+ " ;",
+ "#endif",
+ "#else",
+ " if (!noends && !a_cycles && !endstate())",
+ " { depth--; trpt--; /* new 4.2.3 */",
+ " uerror(\"invalid end state\");",
+ " depth++; trpt++;",
+ " }",
+ "#ifndef NOSTUTTER",
+ " else if (a_cycles && (trpt->o_pm&2)) /* new 4.2.4 */",
+ " { depth--; trpt--;",
+ " uerror(\"accept stutter\");",
+ " depth++; trpt++;",
+ " }",
+ "#endif",
+ "#endif",
+ " }",
+ "Done:",
+ " if (!(trpt->tau&8)) /* not in atomic seqs */",
+ " {",
+ "#ifndef SAFETY",
+ " if (_n != 0", /* we made a move */
+ "#ifdef VERI",
+ " /* --after-- a program-step, i.e., */",
+ " /* after backtracking a claim-step */",
+ " && (trpt->tau&4)",
+ " /* with at least one running process */",
+ " /* unless in a stuttered accept state */",
+ " && ((now._nr_pr > 1) || (trpt->o_pm&2))",
+ "#endif",
+ " && !(now._a_t&1))", /* not in 2nd DFS */
+ " {",
+ "#ifndef NOFAIR",
+ " if (fairness)", /* implies a_cycles */
+ " {",
+ "#ifdef VERBOSE",
+ " printf(\"Consider check %%d %%d...\\n\",",
+ " now._a_t, now._cnt[0]);",
+ "#endif",
+#if 0
+ the a-bit is set, which means that the fairness
+ counter is running -- it was started in an accepting state.
+ we check that the counter reached 1, which means that all
+ processes moved least once.
+ this means we can start the search for cycles -
+ to be able to return to this state, we should be able to
+ run down the counter to 1 again -- which implies a visit to
+ the accepting state -- even though the Seed state for this
+ search is itself not necessarily accepting
+#endif
+ " if ((now._a_t&2) /* A-bit */",
+ " && (now._cnt[0] == 1))",
+ " checkcycles();",
+ " } else",
+ "#endif",
+ " if (a_cycles && (trpt->o_pm&2))",
+ " checkcycles();",
+ " }",
+ "#endif",
+"#ifndef MA",
+ "#if defined(FULLSTACK) || defined(CNTRSTACK)",
+ "#ifdef VERI",
+ " if (boq == -1",
+ " && (((trpt->tau&4) && !(trpt->tau&128))",
+ " || ( (trpt-1)->tau&128)))",
+ "#else",
+ " if (boq == -1)",
+ "#endif",
+ " {",
+ "#ifdef DEBUG2",
+ "#if defined(FULLSTACK)",
+ " printf(\"%%d: zapping %%u (%%d)\\n\",",
+ " depth, trpt->ostate,",
+ " (trpt->ostate)?trpt->ostate->tagged:0);",
+ "#endif",
+ "#endif",
+ " onstack_zap();",
+ " }",
+ "#endif",
+"#else",
+ "#ifdef VERI",
+ " if (boq == -1",
+ " && (((trpt->tau&4) && !(trpt->tau&128))",
+ " || ( (trpt-1)->tau&128)))",
+ "#else",
+ " if (boq == -1)",
+ "#endif",
+ " {",
+ "#ifdef DEBUG",
+ " printf(\"%%d: zapping\\n\", depth);",
+ "#endif",
+ " onstack_zap();",
+ "#ifndef NOREDUCE",
+ " if (trpt->proviso)",
+ " gstore((char *) &now, vsize, 1);",
+ "#endif",
+ " }",
+"#endif",
+ " }",
+ " if (depth > 0) goto Up;",
+ "}\n",
+ "#else",
+ "void new_state(void) { /* place holder */ }",
+ "#endif", /* BFS */
+ "",
+ "void",
+ "assert(int a, char *s, int ii, int tt, Trans *t)",
+ "{",
+ " if (!a && !noasserts)",
+ " { char bad[1024];",
+ " strcpy(bad, \"assertion violated \");",
+ " if (strlen(s) > 1000)",
+ " { strncpy(&bad[19], (const char *) s, 1000);",
+ " bad[1019] = '\\0';",
+ " } else",
+ " strcpy(&bad[19], s);",
+ " uerror(bad);",
+ " }",
+ "}",
+ "#ifndef NOBOUNDCHECK",
+ "int",
+ "Boundcheck(int x, int y, int a1, int a2, Trans *a3)",
+ "{",
+ " assert((x >= 0 && x < y), \"- invalid array index\",",
+ " a1, a2, a3);",
+ " return x;",
+ "}",
+ "#endif",
+ "void",
+ "wrap_stats(void)",
+ "{",
+ " if (nShadow>0)",
+ " printf(\"%%8g states, stored (%%g visited)\\n\",",
+ " nstates - nShadow, nstates);",
+ " else",
+ " printf(\"%%8g states, stored\\n\", nstates);",
+ "#ifdef BFS",
+ "#if SYNC",
+ " printf(\" %%8g nominal states (- rv and atomic)\\n\", nstates-midrv-nlinks+revrv);",
+ " printf(\" %%8g rvs succeeded\\n\", midrv-failedrv);",
+ "#else",
+ " printf(\" %%8g nominal states (stored-atomic)\\n\", nstates-nlinks);",
+ "#endif",
+ "#ifdef DEBUG",
+ " printf(\" %%8g midrv\\n\", midrv);",
+ " printf(\" %%8g failedrv\\n\", failedrv);",
+ " printf(\" %%8g revrv\\n\", revrv);",
+ "#endif",
+ "#endif",
+ " printf(\"%%8g states, matched\\n\", truncs);",
+ "#ifdef CHECK",
+ " printf(\"%%8g matches within stack\\n\",truncs2);",
+ "#endif",
+ " if (nShadow>0)",
+ " printf(\"%%8g transitions (= visited+matched)\\n\",",
+ " nstates+truncs);",
+ " else",
+ " printf(\"%%8g transitions (= stored+matched)\\n\",",
+ " nstates+truncs);",
+ " printf(\"%%8g atomic steps\\n\", nlinks);",
+ " if (nlost) printf(\"%%g lost messages\\n\", (double) nlost);",
+ "",
+ "#ifndef BITSTATE",
+ " printf(\"hash conflicts: %%g (resolved)\\n\", hcmp);",
+ "#else",
+ "#ifdef CHECK",
+ " printf(\"%%8g states allocated for dfs stack\\n\", ngrabs);",
+ "#endif",
+ " printf(\"\\nhash factor: %%4g (best if > 100.)\\n\\n\",",
+ " (double)(1<<(ssize-8)) / (double) nstates * 256.0);",
+ " printf(\"bits set per state: %%u (-k%%u)\\n\", hfns, hfns);",
+ "#if 0",
+#ifndef POWOW
+ " if (udmem)",
+ " printf(\"total bits available: %%8g (-M%%ld)\\n\",",
+ " ((double) udmem) * 8.0, udmem/(1024L*1024L));",
+ " else",
+#endif
+ " printf(\"total bits available: %%8g (-w%%d)\\n\",",
+ " ((double) (1L << (ssize-4)) * 16.0), ssize);",
+ "#endif",
+"#ifdef COVEST",
+ " /* this code requires compilation with -lm on some systems */",
+ " { double pow(double, double);",
+ " double log(double);",
+ " unsigned int best_k;",
+ " double i, n = 30000.0L;",
+ " double f, p, q, m, c, est = 0.0L, k = (double)hfns;",
+ " c = (double) nstates / n;",
+ " m = (double) (1<<(ssize-8)) * 256.0L / c;",
+ " p = 1.0L - (k / m); q = 1.0L;",
+ " for (i = 0.0L; i - est < n; i += 1.0L)",
+ " { q *= p;",
+ " est += pow(1.0L - q, k);",
+ " }",
+ " f = m/i;",
+ " est *= c;",
+ " i *= c;",
+ " /* account for loss from enhanced double hashing */",
+ " if (hfns > 2) est += i * pow(0.5, (double) ssize * 2.0);",
+ "",
+ " if (f < 1.134) best_k = 1;",
+ " else if (f < 2.348) best_k = 2;",
+ " else if (f < 3.644) best_k = 3;",
+ " else best_k = (unsigned int) (pow(3.8L,1.0L/(f+4.2L))*f*.69315L + 0.99999999L);",
+ "",
+ " if (best_k != hfns && best_k > ssize)",
+ " best_k = (unsigned int) 1.0 + ssize/log((double)best_k / (double)ssize + 3.0);",
+ "",
+ " if (best_k > 32)",
+ " best_k = 1 + (unsigned int) (32.0/log((double)best_k/35.0));",
+ "",
+ " if (est * (double) nstates < 1.0)",
+ " { printf(\"prob. of omissions: negligible\\n\");",
+ " return; /* no hints needed */",
+ " }",
+ "",
+ " if (best_k != hfns)",
+ " { printf(\"hint: repeating the search with -k%%u \", best_k);",
+ " printf(\"may increase accuracy\\n\");",
+ " } else",
+ " { printf(\"hint: the current setting for -k (-k%%d) \", hfns);",
+ " printf(\"is likely to be optimal for -w%%d\\n\", ssize);",
+ " }",
+ " if (ssize < 32)",
+ " { printf(\"hint: increasing -w above -w%%d \", ssize);",
+ " printf(\"will increase accuracy (max is -w34)\\n\");",
+ " printf(\"(in xspin, increase Estimated State Space Size)\\n\");",
+ " } }",
+"#endif",
+ "#endif",
+ "}",
+ "void",
+ "wrapup(void)",
+ "{",
+ "#if defined(BITSTATE) || !defined(NOCOMP)",
+ " double nr1, nr2, nr3 = 0.0, nr4, nr5 = 0.0;",
+ "#if !defined(MA) && (defined(MEMCNT) || defined(MEMLIM))",
+ " int mverbose = 1;",
+ "#else",
+ " int mverbose = verbose;",
+ "#endif",
+ "#endif",
+
+ " signal(SIGINT, SIG_DFL);",
+ " printf(\"(%%s)\\n\", Version);",
+ " if (!done) printf(\"Warning: Search not completed\\n\");",
+ "#ifdef SC",
+ " (void) unlink((const char *)stackfile);",
+ "#endif",
+ "#ifdef BFS",
+ " printf(\" + Using Breadth-First Search\\n\");",
+ "#endif",
+ "#ifndef NOREDUCE",
+ " printf(\" + Partial Order Reduction\\n\");",
+ "#endif",
+#if 0
+ "#ifdef Q_PROVISO",
+ " printf(\" + Queue Proviso\\n\");",
+ "#endif",
+#endif
+ "#ifdef COLLAPSE",
+ " printf(\" + Compression\\n\");",
+ "#endif",
+ "#ifdef MA",
+ " printf(\" + Graph Encoding (-DMA=%%d)\\n\", MA);",
+ "#ifdef R_XPT",
+ " printf(\" Restarted from checkpoint %%s.xpt\\n\", Source);",
+ "#endif",
+ "#endif",
+ "#ifdef CHECK",
+ "#ifdef FULLSTACK",
+ " printf(\" + FullStack Matching\\n\");",
+ "#endif",
+ "#ifdef CNTRSTACK",
+ " printf(\" + CntrStack Matching\\n\");",
+ "#endif",
+ "#endif",
+ "#ifdef BITSTATE",
+ " printf(\"\\nBit statespace search for:\\n\");",
+ "#else",
+ "#ifdef HC",
+ " printf(\"\\nHash-Compact %%d search for:\\n\", HC);",
+ "#else",
+ " printf(\"\\nFull statespace search for:\\n\");",
+ "#endif",
+ "#endif",
+ "#ifdef EVENT_TRACE",
+ "#ifdef NEGATED_TRACE",
+ " printf(\"\tnotrace assertion \t+\\n\");",
+ "#else",
+ " printf(\"\ttrace assertion \t+\\n\");",
+ "#endif",
+ "#endif",
+ "#ifdef VERI",
+ " printf(\"\tnever claim \t+\\n\");",
+ " printf(\"\tassertion violations\t\");",
+ " if (noasserts)",
+ " printf(\"- (disabled by -A flag)\\n\");",
+ " else",
+ " printf(\"+ (if within scope of claim)\\n\");",
+ "#else",
+ "#ifdef NOCLAIM",
+ " printf(\"\tnever claim \t- (not selected)\\n\");",
+ "#else",
+ " printf(\"\tnever claim \t- (none specified)\\n\");",
+ "#endif",
+ " printf(\"\tassertion violations\t\");",
+ " if (noasserts)",
+ " printf(\"- (disabled by -A flag)\\n\");",
+ " else",
+ " printf(\"+\\n\");",
+ "#endif",
+ "#ifndef SAFETY",
+ "#ifdef NP",
+ " printf(\"\tnon-progress cycles \t\");",
+ "#else",
+ " printf(\"\tacceptance cycles \t\");",
+ "#endif",
+ " if (a_cycles)",
+ " printf(\"+ (fairness %%sabled)\\n\",",
+ " fairness?\"en\":\"dis\");",
+ " else printf(\"- (not selected)\\n\");",
+ "#else",
+ " printf(\"\tcycle checks \t- (disabled by -DSAFETY)\\n\");",
+ "#endif",
+ "#ifdef VERI",
+ " printf(\"\tinvalid end states\t- \");",
+ " printf(\"(disabled by \");",
+ " if (noends)",
+ " printf(\"-E flag)\\n\\n\");",
+ " else",
+ " printf(\"never claim)\\n\\n\");",
+ "#else",
+ " printf(\"\tinvalid end states\t\");",
+ " if (noends)",
+ " printf(\"- (disabled by -E flag)\\n\\n\");",
+ " else",
+ " printf(\"+\\n\\n\");",
+ "#endif",
+ " printf(\"State-vector %%d byte, depth reached %%d\", ",
+ " hmax, mreached);",
+ " printf(\", errors: %%d\\n\", errors);",
+ "#ifdef MA",
+ " if (done)",
+ " { extern void dfa_stats(void);",
+ " if (maxgs+a_cycles+2 < MA)",
+ " printf(\"MA stats: -DMA=%%d is sufficient\\n\",",
+ " maxgs+a_cycles+2);",
+ " dfa_stats();",
+ " }",
+ "#endif",
+ " wrap_stats();",
+ "#ifdef CHECK",
+ " printf(\"stackframes: %%d/%%d\\n\\n\", smax, svmax);",
+ " printf(\"stats: fa %%d, fh %%d, zh %%d, zn %%d - \",",
+ " Fa, Fh, Zh, Zn);",
+ " printf(\"check %%d holds %%d\\n\", Ccheck, Cholds);",
+ " printf(\"stack stats: puts %%d, probes %%d, zaps %%d\\n\",",
+ " PUT, PROBE, ZAPS);",
+ "#else",
+ " printf(\"\\n\");",
+ "#endif",
+ "",
+ "#if defined(BITSTATE) || !defined(NOCOMP)",
+ " nr1 = (nstates-nShadow)*",
+ " (double)(hmax+sizeof(struct H_el)-sizeof(unsigned));",
+ "#ifdef BFS",
+ " nr2 = 0.0;",
+ "#else",
+ " nr2 = (double) ((maxdepth+3)*sizeof(Trail));",
+ "#endif",
+
+ "#ifndef BITSTATE",
+ "#if !defined(MA) || defined(COLLAPSE)",
+ " nr3 = (double) (1L<<ssize)*sizeof(struct H_el *);",
+ "#endif",
+ "#else",
+#ifndef POWOW
+ " if (udmem)",
+ " nr3 = (double) (udmem);",
+ " else",
+#endif
+ " nr3 = (double) (1L<<(ssize-3));",
+ "#ifdef CNTRSTACK",
+ " nr3 += (double) (1L<<(ssize-3));",
+ "#endif",
+ "#ifdef FULLSTACK",
+ " nr5 = (double) (maxdepth*sizeof(struct H_el *));",
+ "#endif",
+ "#endif",
+ " nr4 = (double) (svmax * (sizeof(Svtack) + hmax))",
+ " + (double) (smax * (sizeof(Stack) + Maxbody));",
+ "#ifndef MA",
+ " if (mverbose || memcnt < nr1+nr2+nr3+nr4+nr5)",
+ "#endif",
+ " { double remainder = memcnt;",
+ " double tmp_nr = memcnt-nr3-nr4-(nr2-fragment)-nr5;",
+ " if (tmp_nr < 0.0) tmp_nr = 0.;",
+ " printf(\"Stats on memory usage (in Megabytes):\\n\");",
+ " printf(\"%%-6.3f\tequivalent memory usage for states\",",
+ " nr1/1000000.);",
+ " printf(\" (stored*(State-vector + overhead))\\n\");",
+ "#ifdef BITSTATE",
+#ifndef POWOW
+ " if (udmem)",
+ " printf(\"%%-6.3f\tmemory used for hash array (-M%%ld)\\n\",",
+ " nr3/1000000., udmem/(1024L*1024L));",
+ " else",
+#endif
+ " printf(\"%%-6.3f\tmemory used for hash array (-w%%d)\\n\",",
+ " nr3/1000000., ssize);",
+ " if (nr5 > 0.0)",
+ " printf(\"%%-6.3f\tmemory used for bit stack\\n\",",
+ " nr5/1000000.);",
+ " remainder = remainder - nr3 - nr5;",
+ "#else",
+ " printf(\"%%-6.3f\tactual memory usage for states\",",
+ " tmp_nr/1000000.);",
+ " remainder = remainder - tmp_nr;",
+ " printf(\" (\");",
+ " if (tmp_nr > 0.)",
+ " { if (tmp_nr > nr1) printf(\"unsuccessful \");",
+ " printf(\"compression: %%.2f%%%%)\\n\",",
+ " (100.0*tmp_nr)/nr1);",
+ " } else",
+ " printf(\"less than 1k)\\n\");",
+ "#ifndef MA",
+ " if (tmp_nr > 0.)",
+ " { printf(\"\tState-vector as stored = %%.0f byte\",",
+ " (tmp_nr)/(nstates-nShadow) -",
+ " (double) (sizeof(struct H_el) - sizeof(unsigned)));",
+ " printf(\" + %%ld byte overhead\\n\",",
+ " sizeof(struct H_el)-sizeof(unsigned));",
+ " }",
+ "#endif",
+ "#if !defined(MA) || defined(COLLAPSE)",
+ " printf(\"%%-6.3f\tmemory used for hash table (-w%%d)\\n\",",
+ " nr3/1000000., ssize);",
+ " remainder = remainder - nr3;",
+ "#endif",
+ "#endif",
+ "#ifndef BFS",
+ " printf(\"%%-6.3f\tmemory used for DFS stack (-m%%ld)\\n\",",
+ " nr2/1000000., maxdepth);",
+ " remainder = remainder - nr2;",
+ "#endif",
+ " if (remainder - fragment > 0.0)",
+ " printf(\"%%-6.3f\tother (proc and chan stacks)\\n\",",
+ " (remainder-fragment)/1000000.);",
+ " if (fragment > 0.0)",
+ " printf(\"%%-6.3f\tmemory lost to fragmentation\\n\",",
+ " fragment/1000000.);",
+ " printf(\"%%-6.3f\ttotal actual memory usage\\n\\n\",",
+ " memcnt/1000000.);",
+ " }",
+ "#ifndef MA",
+ " else",
+ "#endif",
+ "#endif",
+ "#ifndef MA",
+ " printf(\"%%-6.3f\tmemory usage (Mbyte)\\n\\n\",",
+ " memcnt/1000000.);",
+ "#endif",
+ "#ifdef COLLAPSE",
+ " printf(\"nr of templates: [ globals chans procs ]\\n\");",
+ " printf(\"collapse counts: [ \");",
+ " { int i; for (i = 0; i < 256+2; i++)",
+ " if (ncomps[i] != 0)",
+ " printf(\"%%d \", ncomps[i]);",
+ " printf(\"]\\n\");",
+ " }",
+ "#endif",
+
+ " if ((done || verbose) && !no_rck) do_reach();",
+ "#ifdef PEG",
+ " { int i;",
+ " printf(\"\\nPeg Counts (transitions executed):\\n\");",
+ " for (i = 1; i < NTRANS; i++)",
+ " { if (peg[i]) putpeg(i, peg[i]);",
+ " } }",
+ "#endif",
+ "#ifdef VAR_RANGES",
+ " dumpranges();",
+ "#endif",
+ "#ifdef SVDUMP",
+ " if (vprefix > 0) close(svfd);",
+ "#endif",
+ " pan_exit(0);",
+ "}\n",
+ "void",
+ "stopped(int arg)",
+ "{ printf(\"Interrupted\\n\");",
+ " wrapup();",
+ " pan_exit(0);",
+ "}",
+ "/*",
+ " * based on Bob Jenkins hash-function from 1996",
+ " * see: http://www.burtleburtle.net/bob/",
+ " */",
+ "",
+"#if defined(HASH64) || defined(WIN64)",
+ /* 64-bit Jenkins hash: http://burtleburtle.net/bob/c/lookup8.c */
+ "#define mix(a,b,c) \\",
+ "{ a -= b; a -= c; a ^= (c>>43); \\",
+ " b -= c; b -= a; b ^= (a<<9); \\",
+ " c -= a; c -= b; c ^= (b>>8); \\",
+ " a -= b; a -= c; a ^= (c>>38); \\",
+ " b -= c; b -= a; b ^= (a<<23); \\",
+ " c -= a; c -= b; c ^= (b>>5); \\",
+ " a -= b; a -= c; a ^= (c>>35); \\",
+ " b -= c; b -= a; b ^= (a<<49); \\",
+ " c -= a; c -= b; c ^= (b>>11); \\",
+ " a -= b; a -= c; a ^= (c>>12); \\",
+ " b -= c; b -= a; b ^= (a<<18); \\",
+ " c -= a; c -= b; c ^= (b>>22); \\",
+ "}",
+"#else",
+ "#define mix(a,b,c) \\",
+ "{ a -= b; a -= c; a ^= (c>>13); \\",
+ " b -= c; b -= a; b ^= (a<<8); \\",
+ " c -= a; c -= b; c ^= (b>>13); \\",
+ " a -= b; a -= c; a ^= (c>>12); \\",
+ " b -= c; b -= a; b ^= (a<<16); \\",
+ " c -= a; c -= b; c ^= (b>>5); \\",
+ " a -= b; a -= c; a ^= (c>>3); \\",
+ " b -= c; b -= a; b ^= (a<<10); \\",
+ " c -= a; c -= b; c ^= (b>>15); \\",
+ "}",
+"#endif",
+ "void",
+ "d_hash(uchar *Cp, int Om) /* double bit hash - Jenkins */",
+ "{ unsigned long a = 0x9e3779b9, b, c = 0, len, length;",
+ " unsigned long *k = (unsigned long *) Cp;",
+ "",
+ " length = len = (unsigned long) ((unsigned long) Om + WS-1)/WS;",
+ "",
+ " b = HASH_CONST[HASH_NR];",
+ " while (len >= 3)",
+ " { a += k[0];",
+ " b += k[1];",
+ " c += k[2];",
+ " mix(a,b,c);",
+ " k += 3; len -= 3;",
+ " }",
+ " c += length;",
+ " switch (len) {",
+ " case 2: b += k[1];",
+ " case 1: a += k[0];",
+ " }",
+ " mix(a,b,c);",
+ " j1 = c&nmask; j3 = a&7;", /* 1st bit */
+ " j2 = b&nmask; j4 = (a>>3)&7;", /* 2nd bit */
+ " K1 = c; K2 = b;", /* no nmask */
+ "}",
+ "void",
+ "s_hash(uchar *cp, int om)",
+ "{ d_hash(cp, om); /* sets K1 and K2 */",
+ "#ifdef BITSTATE",
+ " if (S_Tab == H_tab)", /* state stack in bitstate search */
+ " j1 = K1 %% omaxdepth;",
+ " else",
+ "#endif", /* if (S_Tab != H_Tab) */
+ " if (ssize < 8*WS)",
+ " j1 = K1&mask;",
+ " else",
+ " j1 = K1;",
+ "}",
+ "#ifndef RANDSTOR",
+ "int *prerand;",
+ "void",
+ "inirand(void)",
+ "{ int i;",
+ " srand(123); /* fixed startpoint */",
+ " prerand = (int *) emalloc((omaxdepth+3)*sizeof(int));",
+ " for (i = 0; i < omaxdepth+3; i++)",
+ " prerand[i] = rand();",
+ "}",
+ "int",
+ "pan_rand(void)",
+ "{ if (!prerand) inirand();",
+ " return prerand[depth];",
+ "}",
+ "#endif",
+ "",
+ "int",
+ "main(int argc, char *argv[])",
+ "{ void to_compile(void);\n",
+ " efd = stderr; /* default */",
+ "#ifdef BITSTATE",
+ " bstore = bstore_reg; /* default */",
+ "#endif",
+ " while (argc > 1 && argv[1][0] == '-')",
+ " { switch (argv[1][1]) {",
+ "#ifndef SAFETY",
+ "#ifdef NP",
+ " case 'a': fprintf(efd, \"error: -a disabled\");",
+ " usage(efd); break;",
+ "#else",
+ " case 'a': a_cycles = 1; break;",
+ "#endif",
+ "#endif",
+ " case 'A': noasserts = 1; break;",
+ " case 'b': bounded = 1; break;",
+ " case 'c': upto = atoi(&argv[1][2]); break;",
+ " case 'd': state_tables++; break;",
+ " case 'e': every_error = 1; Nr_Trails = 1; break;",
+ " case 'E': noends = 1; break;",
+ "#ifdef SC",
+ " case 'F': if (strlen(argv[1]) > 2)",
+ " stackfile = &argv[1][2];",
+ " break;",
+ "#endif",
+ "#if !defined(SAFETY) && !defined(NOFAIR)",
+ " case 'f': fairness = 1; break;",
+ "#endif",
+ " case 'h': if (!argv[1][2]) usage(efd); else",
+ " HASH_NR = atoi(&argv[1][2])%%33; break;",
+ " case 'I': iterative = 2; every_error = 1; break;",
+ " case 'i': iterative = 1; every_error = 1; break;",
+ " case 'J': like_java = 1; break; /* Klaus Havelund */",
+ "#ifdef BITSTATE",
+ " case 'k': hfns = atoi(&argv[1][2]); break;",
+ "#endif",
+ "#ifndef SAFETY",
+ "#ifdef NP",
+ " case 'l': a_cycles = 1; break;",
+ "#else",
+ " case 'l': fprintf(efd, \"error: -l disabled\");",
+ " usage(efd); break;",
+ "#endif",
+ "#endif",
+#ifndef POWOW
+ "#ifdef BITSTATE",
+ " case 'M': udmem = atoi(&argv[1][2]); break;",
+ " case 'G': udmem = atoi(&argv[1][2]); udmem *= 1024; break;",
+ "#else",
+ " case 'M': case 'G':",
+ " fprintf(stderr, \"-M and -G affect only -DBITSTATE\\n\");",
+ " break;",
+ "#endif",
+#endif
+ " case 'm': maxdepth = atoi(&argv[1][2]); break;",
+ " case 'n': no_rck = 1; break;",
+ "#ifdef SVDUMP",
+ " case 'p': vprefix = atoi(&argv[1][2]); break;",
+ "#endif",
+ " case 'q': strict = 1; break;",
+ "#ifdef HAS_CODE",
+ " case 'r':",
+ "samething: readtrail = 1;",
+ " if (isdigit(argv[1][2]))",
+ " whichtrail = atoi(&argv[1][2]);",
+ " break;",
+ " case 'P': readtrail = 1; onlyproc = atoi(&argv[1][2]); break;",
+ " case 'C': coltrace = 1; goto samething;",
+ " case 'g': gui = 1; goto samething;",
+ " case 'S': silent = 1; break;",
+ "#endif",
+ " case 'R': Nrun = atoi(&argv[1][2]); break;",
+ "#ifdef BITSTATE",
+ " case 's': hfns = 1; break;",
+ "#endif",
+ " case 'T': TMODE = 0444; break;",
+ " case 't': if (argv[1][2]) tprefix = &argv[1][2]; break;",
+ " case 'V': printf(\"Generated by %%s\\n\", Version);",
+ " to_compile(); pan_exit(0); break;",
+ " case 'v': verbose = 1; break;",
+ " case 'w': ssize = atoi(&argv[1][2]); break;",
+ " case 'Y': signoff = 1; break;",
+ " case 'X': efd = stdout; break;",
+ " default : fprintf(efd, \"saw option -%%c\\n\", argv[1][1]); usage(efd); break;",
+ " }",
+ " argc--; argv++;",
+ " }",
+ " if (iterative && TMODE != 0666)",
+ " { TMODE = 0666;",
+ " fprintf(efd, \"warning: -T ignored when -i or -I is used\\n\");",
+ " }",
+ "#if defined(WIN32) || defined(WIN64)",
+ " if (TMODE == 0666)",
+ " TMODE = _S_IWRITE | _S_IREAD;",
+ " else",
+ " TMODE = _S_IREAD;",
+ "#endif",
+ "#ifdef OHASH",
+ " fprintf(efd, \"warning: -DOHASH no longer supported (directive ignored)\\n\");",
+ "#endif",
+ "#ifdef JHASH",
+ " fprintf(efd, \"warning: -DJHASH no longer supported (directive ignored)\\n\");",
+ "#endif",
+ "#ifdef HYBRID_HASH",
+ " fprintf(efd, \"warning: -DHYBRID_HASH no longer supported (directive ignored)\\n\");",
+ "#endif",
+ "#ifdef NOCOVEST",
+ " fprintf(efd, \"warning: -DNOCOVEST no longer supported (directive ignored)\\n\");",
+ "#endif",
+ "#ifdef BITSTATE",
+ "#ifdef BCOMP",
+ " fprintf(efd, \"warning: -DBCOMP no longer supported (directive ignored)\\n\");",
+ "#endif",
+ " if (hfns <= 0)",
+ " { hfns = 1;",
+ " fprintf(efd, \"warning: using -k%%d as minimal usable value\\n\", hfns);",
+ " }",
+ "#endif",
+ " omaxdepth = maxdepth;",
+ "#ifdef BITSTATE",
+ " if (WS == 4 && ssize > 34)", /* 32-bit word size */
+ " { ssize = 34;",
+ " fprintf(efd, \"warning: using -w%%d as max usable value\\n\", ssize);",
+ "/*",
+ " * -w35 would not work: 35-3 = 32 but 1^31 is the largest",
+ " * power of 2 that can be represented in an unsigned long",
+ " */",
+ " }",
+ "#else",
+ " if (WS == 4 && ssize > 27)",
+ " { ssize = 27;",
+ " fprintf(efd, \"warning: using -w%%d as max usable value\\n\", ssize);",
+ "/*",
+ " * for emalloc, the lookup table size multiplies by 4 for the pointers",
+ " * the largest power of 2 that can be represented in a ulong is 1^31",
+ " * hence the largest number of lookup table slots is 31-4 = 27",
+ " */",
+ " }",
+
+ "#endif",
+ "#ifdef SC",
+ " hiwater = HHH = maxdepth-10;",
+ " DDD = HHH/2;",
+ " if (!stackfile)",
+ " { stackfile = (char *) emalloc(strlen(Source)+4+1);",
+ " sprintf(stackfile, \"%%s._s_\", Source);",
+ " }",
+ " if (iterative)",
+ " { fprintf(efd, \"error: cannot use -i or -I with -DSC\\n\");",
+ " pan_exit(1);",
+ " }",
+ "#endif",
+
+ "#if (defined(R_XPT) || defined(W_XPT)) && !defined(MA)",
+ " fprintf(efd, \"error: -D?_XPT requires -DMA\\n\");",
+ " exit(1);",
+ "#endif",
+
+ " if (iterative && a_cycles)",
+ " fprintf(efd, \"warning: -i or -I work for safety properties only\\n\");",
+
+ "#ifdef BFS",
+ "#if defined(SC)",
+ " fprintf(efd, \"error: -DBFS not compatible with -DSC\\n\");",
+ " exit(1);",
+ "#endif",
+ "#if defined(HAS_LAST)",
+ " fprintf(efd, \"error: -DBFS not compatible with _last\\n\");",
+ " exit(1);",
+ "#endif",
+ "#if defined(REACH)",
+ " fprintf(efd, \"warning: -DREACH redundant when -DBFS is used\\n\");",
+ "#endif",
+ "#if defined(HAS_STACK)",
+ " fprintf(efd, \"error: cannot use UnMatched qualifier on c_track with BFS\\n\");",
+ " exit(1);",
+ "#endif",
+ "#endif",
+
+ "#if defined(MERGED) && defined(PEG)",
+ " fprintf(efd, \"error: to allow -DPEG use: spin -o3 -a %%s\\n\", Source);",
+ " fprintf(efd, \" to turn off transition merge optimization\\n\");",
+ " pan_exit(1);",
+ "#endif",
+ "#ifdef HC",
+ "#ifdef NOCOMP",
+ " fprintf(efd, \"error: cannot combine -DHC and -DNOCOMP\\n\");",
+ " pan_exit(1);",
+ "#endif",
+ "#ifdef BITSTATE",
+ " fprintf(efd, \"error: cannot combine -DHC and -DBITSTATE\\n\");",
+ " pan_exit(1);",
+ "#endif",
+ "#endif",
+ "#if defined(SAFETY) && defined(NP)",
+ " fprintf(efd, \"error: cannot combine -DNP and -DSAFETY\\n\");",
+ " pan_exit(1);",
+ "#endif",
+ "#ifdef MA",
+ "#ifdef BITSTATE",
+ " fprintf(efd, \"error: cannot combine -DMA and -DBITSTATE\\n\");",
+ " pan_exit(1);",
+ "#endif",
+ " if (MA <= 0)",
+ " { fprintf(efd, \"usage: -DMA=N with N > 0 and < VECTORSZ\\n\");",
+ " pan_exit(1);",
+ " }",
+ "#endif",
+ "#ifdef COLLAPSE",
+ "#if defined(BITSTATE)",
+ " fprintf(efd, \"error: cannot combine -DBITSTATE and -DCOLLAPSE\\n\");",
+ " pan_exit(1);",
+ "#endif",
+ "#if defined(NOCOMP)",
+ " fprintf(efd, \"error: cannot combine -DNOCOMP and -DCOLLAPSE\\n\");",
+ " pan_exit(1);",
+ "#endif",
+ "#endif",
+ " if (maxdepth <= 0 || ssize <= 1) usage(efd);",
+ "#if SYNC>0 && !defined(NOREDUCE)",
+ " if (a_cycles && fairness)",
+ " { fprintf(efd, \"error: p.o. reduction not compatible with \");",
+ " fprintf(efd, \"fairness (-f) in models\\n\");",
+ " fprintf(efd, \" with rendezvous operations: \");",
+ " fprintf(efd, \"recompile with -DNOREDUCE\\n\");",
+ " pan_exit(1);",
+ " }",
+ "#endif",
+ "#if defined(REM_VARS) && !defined(NOREDUCE)",
+ " { fprintf(efd, \"warning: p.o. reduction not compatible with \");",
+ " fprintf(efd, \"remote varrefs (use -DNOREDUCE)\\n\");",
+ " }",
+ "#endif",
+ "#if defined(NOCOMP) && !defined(BITSTATE)",
+ " if (a_cycles)",
+ " { fprintf(efd, \"error: -DNOCOMP voids -l and -a\\n\");",
+ " pan_exit(1);",
+ " }",
+ "#endif",
+
+ "#ifdef MEMLIM", /* MEMLIM setting takes precedence */
+ " memlim = (double) MEMLIM * (double) (1<<20); /* size in Mbyte */",
+ "#else",
+ "#ifdef MEMCNT",
+ "#if MEMCNT<31",
+ " memlim = (double) (1<<MEMCNT);",
+ "#else",
+ " memlim = (double) (1<<30);",
+ " memlim *= (double) (1<<(MEMCNT-30));",
+ "#endif",
+ "#endif",
+ "#endif",
+
+ "#ifndef BITSTATE",
+ " if (Nrun > 1) HASH_NR = Nrun - 1;",
+ "#endif",
+ " if (Nrun < 1 || Nrun > 32)",
+ " { fprintf(efd, \"error: invalid arg for -R\\n\");",
+ " usage(efd);",
+ " }",
+ "#ifndef SAFETY",
+ " if (fairness && !a_cycles)",
+ " { fprintf(efd, \"error: -f requires -a or -l\\n\");",
+ " usage(efd);",
+ " }",
+ "#if ACCEPT_LAB==0",
+ " if (a_cycles)",
+ "#ifndef VERI",
+ " { fprintf(efd, \"error: no accept labels defined \");",
+ " fprintf(efd, \"in model (for option -a)\\n\");",
+ " usage(efd);",
+ " }",
+ "#else",
+ " { fprintf(efd, \"warning: no explicit accept labels \");",
+ " fprintf(efd, \"defined in model (for -a)\\n\");",
+ " }",
+ "#endif",
+ "#endif",
+ "#endif",
+ "#if !defined(NOREDUCE)",
+ "#if defined(HAS_ENABLED)",
+ " fprintf(efd, \"error: reduced search precludes \");",
+ " fprintf(efd, \"use of 'enabled()'\\n\");",
+ " pan_exit(1);",
+ "#endif",
+ "#if defined(HAS_PCVALUE)",
+ " fprintf(efd, \"error: reduced search precludes \");",
+ " fprintf(efd, \"use of 'pcvalue()'\\n\");",
+ " pan_exit(1);",
+ "#endif",
+ "#if defined(HAS_BADELSE)",
+ " fprintf(efd, \"error: reduced search precludes \");",
+ " fprintf(efd, \"using 'else' combined with i/o stmnts\\n\");",
+ " pan_exit(1);",
+ "#endif",
+ "#if defined(HAS_LAST)",
+ " fprintf(efd, \"error: reduced search precludes \");",
+ " fprintf(efd, \"use of _last\\n\");",
+ " pan_exit(1);",
+ "#endif",
+ "#endif",
+
+ "#if SYNC>0 && !defined(NOREDUCE)",
+ "#ifdef HAS_UNLESS",
+ " fprintf(efd, \"warning: use of a rendezvous stmnts in the escape\\n\");",
+ " fprintf(efd, \"\tof an unless clause, if present, could make p.o. reduction\\n\");",
+ " fprintf(efd, \"\tinvalid (use -DNOREDUCE to avoid this)\\n\");",
+ "#ifdef BFS",
+ " fprintf(efd, \"\t(this type of rv is also not compatible with -DBFS)\\n\");",
+ "#endif",
+ "#endif",
+ "#endif",
+ "#if SYNC>0 && defined(BFS)",
+ " fprintf(efd, \"warning: use of rendezvous in BFS mode \");",
+ " fprintf(efd, \"does not preserve all invalid endstates\\n\");",
+ "#endif",
+ "#if !defined(REACH) && !defined(BITSTATE)",
+ " if (iterative != 0 && a_cycles == 0)",
+ " fprintf(efd, \"warning: -i and -I need -DREACH to work accurately\\n\");",
+ "#endif",
+ "#if defined(BITSTATE) && defined(REACH)",
+ " fprintf(efd, \"warning: -DREACH voided by -DBITSTATE\\n\");",
+ "#endif",
+ "#if defined(MA) && defined(REACH)",
+ " fprintf(efd, \"warning: -DREACH voided by -DMA\\n\");",
+ "#endif",
+ "#if defined(FULLSTACK) && defined(CNTRSTACK)",
+ " fprintf(efd, \"error: cannot combine\");",
+ " fprintf(efd, \" -DFULLSTACK and -DCNTRSTACK\\n\");",
+ " pan_exit(1);",
+ "#endif",
+ "#if defined(VERI)",
+ "#if ACCEPT_LAB>0",
+ "#ifndef BFS",
+ " if (!a_cycles",
+ "#ifdef HAS_CODE",
+ " && !readtrail",
+ "#endif",
+ " && !state_tables)",
+ " { fprintf(efd, \"warning: never claim + accept labels \");",
+ " fprintf(efd, \"requires -a flag to fully verify\\n\");",
+ " }",
+ "#else",
+ " if (",
+ "#ifdef HAS_CODE",
+ " !readtrail",
+ "#endif",
+ " && !state_tables)",
+ " { fprintf(efd, \"warning: verification in BFS mode \");",
+ " fprintf(efd, \"is restricted to safety properties\\n\");",
+ " }",
+ "#endif",
+ "#endif",
+ "#endif",
+ "#ifndef SAFETY",
+ " if (!a_cycles",
+ "#ifdef HAS_CODE",
+ " && !readtrail",
+ "#endif",
+ " && !state_tables)",
+ " { fprintf(efd, \"hint: this search is more efficient \");",
+ " fprintf(efd, \"if pan.c is compiled -DSAFETY\\n\");",
+ " }",
+ "#ifndef NOCOMP",
+ " if (!a_cycles)",
+ " S_A = 0;",
+ " else",
+ " { if (!fairness)",
+ " S_A = 1; /* _a_t */",
+ "#ifndef NOFAIR",
+ " else /* _a_t and _cnt[NFAIR] */",
+ " S_A = (&(now._cnt[0]) - (uchar *) &now) + NFAIR - 2;",
+ " /* -2 because first two uchars in now are masked */",
+ "#endif",
+ " }",
+ "#endif",
+ "#endif",
+ " signal(SIGINT, stopped);",
+
+ /******************* 4.2.5 ********************/
+ " if (WS == 4 && ssize >= 32)",
+ " { mask = 0xffffffff;",
+ "#ifdef BITSTATE",
+ " switch (ssize) {",
+ " case 34: nmask = (mask>>1); break;",
+ " case 33: nmask = (mask>>2); break;",
+ " default: nmask = (mask>>3); break;",
+ " }",
+ "#else",
+ " nmask = mask;",
+ "#endif",
+ " } else if (WS == 8)",
+ " { mask = ((1L<<ssize)-1); /* hash init */",
+ "#ifdef BITSTATE",
+ " nmask = mask>>3;",
+ "#else",
+ " nmask = mask;",
+ "#endif",
+ " } else if (WS != 4)",
+ " { fprintf(stderr, \"pan: wordsize %%ld not supported\\n\", WS);",
+ " exit(1);",
+ " } else /* WS == 4 and ssize < 32 */",
+ " { mask = ((1L<<ssize)-1); /* hash init */",
+ " nmask = (mask>>3);",
+ " }",
+ /****************** end **********************/
+
+ "#ifdef BFS",
+ " trail = (Trail *) emalloc(6*sizeof(Trail));",
+ " trail += 3;",
+ "#else",
+ " trail = (Trail *) emalloc((maxdepth+3)*sizeof(Trail));",
+ " trail++; /* protect trpt-1 refs at depth 0 */",
+ "#endif",
+ "#ifdef SVDUMP",
+ " if (vprefix > 0)",
+ " { char nm[64];",
+ " sprintf(nm, \"%%s.svd\", Source);",
+ " if ((svfd = creat(nm, 0666)) < 0)",
+ " { fprintf(efd, \"couldn't create %%s\\n\", nm);",
+ " vprefix = 0;",
+ " } }",
+ "#endif",
+ "#ifdef RANDSTOR",
+ " srand(123);",
+ "#endif",
+ "#if SYNC>0 && ASYNC==0",
+ " set_recvs();",
+ "#endif",
+ " run();",
+ " done = 1;",
+ " wrapup();",
+ " return 0;",
+ "}", /* end of main() */
+ "",
+ "void",
+ "usage(FILE *fd)",
+ "{",
+ " fprintf(fd, \"Valid Options are:\\n\");",
+ "#ifndef SAFETY",
+ "#ifdef NP",
+ " fprintf(fd, \"\t-a -> is disabled by -DNP \");",
+ " fprintf(fd, \"(-DNP compiles for -l only)\\n\");",
+ "#else",
+ " fprintf(fd, \"\t-a find acceptance cycles\\n\");",
+ "#endif",
+ "#else",
+ " fprintf(fd, \"\t-a,-l,-f -> are disabled by -DSAFETY\\n\");",
+ "#endif",
+ " fprintf(fd, \"\t-A ignore assert() violations\\n\");",
+ " fprintf(fd, \"\t-b consider it an error to exceed the depth-limit\\n\");",
+ " fprintf(fd, \"\t-cN stop at Nth error \");",
+ " fprintf(fd, \"(defaults to -c1)\\n\");",
+ " fprintf(fd, \"\t-d print state tables and stop\\n\");",
+ " fprintf(fd, \"\t-e create trails for all errors\\n\");",
+ " fprintf(fd, \"\t-E ignore invalid end states\\n\");",
+ "#ifdef SC",
+ " fprintf(fd, \"\t-Ffile use 'file' to store disk-stack\\n\");",
+ "#endif",
+ "#ifndef NOFAIR",
+ " fprintf(fd, \"\t-f add weak fairness (to -a or -l)\\n\");",
+ "#endif",
+ " fprintf(fd, \"\t-hN use different hash-seed N:1..32\\n\");",
+ " fprintf(fd, \"\t-i search for shortest path to error\\n\");",
+ " fprintf(fd, \"\t-I like -i, but approximate and faster\\n\");",
+ " fprintf(fd, \"\t-J reverse eval order of nested unlesses\\n\");",
+ "#ifdef BITSTATE",
+ " fprintf(fd, \"\t-kN set N bits per state (defaults to 3)\\n\");",
+ "#endif",
+ "#ifndef SAFETY",
+ "#ifdef NP",
+ " fprintf(fd, \"\t-l find non-progress cycles\\n\");",
+ "#else",
+ " fprintf(fd, \"\t-l find non-progress cycles -> \");",
+ " fprintf(fd, \"disabled, requires \");",
+ " fprintf(fd, \"compilation with -DNP\\n\");",
+ "#endif",
+ "#endif",
+#ifndef POWOW
+ "#ifdef BITSTATE",
+ " fprintf(fd, \"\t-MN use N Megabytes for bitstate hash array\\n\");",
+ " fprintf(fd, \"\t-GN use N Gigabytes for bitstate hash array\\n\");",
+ "#endif",
+#endif
+ " fprintf(fd, \"\t-mN max depth N steps (default=10k)\\n\");",
+ " fprintf(fd, \"\t-n no listing of unreached states\\n\");",
+ "#ifdef SVDUMP",
+ " fprintf(fd, \"\t-pN create svfile (save N bytes per state)\\n\");",
+ "#endif",
+ " fprintf(fd, \"\t-q require empty chans in valid end states\\n\");",
+ "#ifdef HAS_CODE",
+ " fprintf(fd, \"\t-r read and execute trail - can add -v,-n,-PN,-g,-C\\n\");",
+ " fprintf(fd, \"\t-rN read and execute N-th error trail\\n\");",
+ " fprintf(fd, \"\t-C read and execute trail - columnated output (can add -v,-n)\\n\");",
+ " fprintf(fd, \"\t-PN read and execute trail - restrict trail output to proc N\\n\");",
+ " fprintf(fd, \"\t-g read and execute trail + msc gui support\\n\");",
+ " fprintf(fd, \"\t-S silent replay: only user defined printfs show\\n\");",
+ "#endif",
+ "#ifdef BITSTATE",
+ " fprintf(fd, \"\t-RN repeat run Nx with N \");",
+ " fprintf(fd, \"[1..32] independent hash functions\\n\");",
+ " fprintf(fd, \"\t-s same as -k1 (single bit per state)\\n\");",
+ "#endif",
+ " fprintf(fd, \"\t-T create trail files in read-only mode\\n\");",
+ " fprintf(fd, \"\t-tsuf replace .trail with .suf on trailfiles\\n\");",
+ " fprintf(fd, \"\t-V print SPIN version number\\n\");",
+ " fprintf(fd, \"\t-v verbose -- filenames in unreached state listing\\n\");",
+ " fprintf(fd, \"\t-wN hashtable of 2^N entries \");",
+ " fprintf(fd, \"(defaults to -w%%d)\\n\", ssize);",
+ " exit(1);",
+ "}",
+ "",
+ "char *",
+ "Malloc(unsigned long n)",
+ "{ char *tmp;",
+ "#if defined(MEMCNT) || defined(MEMLIM)",
+ " if (memcnt+ (double) n > memlim) goto err;",
+ "#endif",
+"#if 1",
+ " tmp = (char *) malloc(n);",
+ " if (!tmp)",
+"#else",
+ /* on linux machines, a large amount of memory is set aside
+ * for malloc, whether it is used or not
+ * using sbrk would make this memory arena inaccessible
+ * the reason for using sbrk was originally to provide a
+ * small additional speedup (since this memory is never released)
+ */
+ " tmp = (char *) sbrk(n);",
+ " if (tmp == (char *) -1L)",
+"#endif",
+ " {",
+ "#if defined(MEMCNT) || defined(MEMLIM)",
+ "err:",
+ "#endif",
+ " printf(\"pan: out of memory\\n\");",
+ "#if defined(MEMCNT) || defined(MEMLIM)",
+ " printf(\"\t%%g bytes used\\n\", memcnt);",
+ " printf(\"\t%%g bytes more needed\\n\", (double) n);",
+ " printf(\"\t%%g bytes limit\\n\",",
+ " memlim);",
+ "#endif",
+ "#ifdef COLLAPSE",
+ " printf(\"hint: to reduce memory, recompile with\\n\");",
+ "#ifndef MA",
+ " printf(\" -DMA=%%d # better/slower compression, or\\n\", hmax);",
+ "#endif",
+ " printf(\" -DBITSTATE # supertrace, approximation\\n\");",
+ "#else",
+ "#ifndef BITSTATE",
+ " printf(\"hint: to reduce memory, recompile with\\n\");",
+ "#ifndef HC",
+ " printf(\" -DCOLLAPSE # good, fast compression, or\\n\");",
+ "#ifndef MA",
+ " printf(\" -DMA=%%d # better/slower compression, or\\n\", hmax);",
+ "#endif",
+ " printf(\" -DHC # hash-compaction, approximation\\n\");",
+ "#endif",
+ " printf(\" -DBITSTATE # supertrace, approximation\\n\");",
+ "#endif",
+ "#endif",
+ " wrapup();",
+ " }",
+ " memcnt += (double) n;",
+ " return tmp;",
+ "}",
+ "",
+ "#define CHUNK (100*VECTORSZ)",
+ "",
+ "char *",
+ "emalloc(unsigned long n) /* never released or reallocated */",
+ "{ char *tmp;",
+ " if (n == 0)",
+ " return (char *) NULL;",
+ " if (n&(sizeof(void *)-1)) /* for proper alignment */",
+ " n += sizeof(void *)-(n&(sizeof(void *)-1));",
+ " if ((unsigned long) left < n)", /* was: (left < (long)n) */
+ " { grow = (n < CHUNK) ? CHUNK : n;",
+#if 1
+ " have = Malloc(grow);",
+#else
+ " /* gcc's sbrk can give non-aligned result */",
+ " grow += sizeof(void *); /* allow realignment */",
+ " have = Malloc(grow);",
+ " if (((unsigned) have)&(sizeof(void *)-1))",
+ " { have += (long) (sizeof(void *) ",
+ " - (((unsigned) have)&(sizeof(void *)-1)));",
+ " grow -= sizeof(void *);",
+ " }",
+#endif
+ " fragment += (double) left;",
+ " left = grow;",
+ " }",
+ " tmp = have;",
+ " have += (long) n;",
+ " left -= (long) n;",
+ " memset(tmp, 0, n);",
+ " return tmp;",
+ "}",
+
+ "void",
+ "Uerror(char *str)",
+ "{ /* always fatal */",
+ " uerror(str);",
+ " wrapup();",
+ "}\n",
+ "#if defined(MA) && !defined(SAFETY)",
+ "int",
+ "Unwind(void)",
+ "{ Trans *t; uchar ot, _m; int tt; short II;",
+ "#ifdef VERBOSE",
+ " int i;",
+ "#endif",
+ " uchar oat = now._a_t;",
+ " now._a_t &= ~(1|16|32);",
+ " memcpy((char *) &comp_now, (char *) &now, vsize);",
+ " now._a_t = oat;",
+ "Up:",
+ "#ifdef SC",
+ " trpt = getframe(depth);",
+ "#endif",
+ "#ifdef VERBOSE",
+ " printf(\"%%d State: \", depth);",
+ " for (i = 0; i < vsize; i++) printf(\"%%d%%s,\",",
+ " ((char *)&now)[i], Mask[i]?\"*\":\"\");",
+ " printf(\"\\n\");",
+ "#endif",
+ "#ifndef NOFAIR",
+ " if (trpt->o_pm&128) /* fairness alg */",
+ " { now._cnt[now._a_t&1] = trpt->bup.oval;",
+ " depth--;",
+ "#ifdef SC",
+ " trpt = getframe(depth);",
+ "#else",
+ " trpt--;",
+ "#endif",
+ " goto Q999;",
+ " }",
+ "#endif",
+ "#ifdef HAS_LAST",
+ "#ifdef VERI",
+ " { int d; Trail *trl;",
+ " now._last = 0;",
+ " for (d = 1; d < depth; d++)",
+ " { trl = getframe(depth-d); /* was trl = (trpt-d); */",
+ " if (trl->pr != 0)",
+ " { now._last = trl->pr - BASE;",
+ " break;",
+ " } } }",
+ "#else",
+ " now._last = (depth<1)?0:(trpt-1)->pr;",
+ "#endif",
+ "#endif",
+ "#ifdef EVENT_TRACE",
+ " now._event = trpt->o_event;",
+ "#endif",
+ " if ((now._a_t&1) && depth <= A_depth)",
+ " { now._a_t &= ~(1|16|32);",
+ " if (fairness) now._a_t |= 2; /* ? */",
+ " A_depth = 0;",
+ " goto CameFromHere; /* checkcycles() */",
+ " }",
+ " t = trpt->o_t;",
+ " ot = trpt->o_ot; II = trpt->pr;",
+ " tt = trpt->o_tt; this = pptr(II);",
+ " _m = do_reverse(t, II, trpt->o_m);",
+ "#ifdef VERBOSE",
+ " printf(\"%%3d: proc %%d \", depth, II);",
+ " printf(\"reverses %%d, %%d to %%d,\",",
+ " t->forw, tt, t->st);",
+ " printf(\" %%s [abit=%%d,adepth=%%d,\", ",
+ " t->tp, now._a_t, A_depth);",
+ " printf(\"tau=%%d,%%d] <unwind>\\n\", ",
+ " trpt->tau, (trpt-1)->tau);",
+ "#endif",
+ " depth--;",
+ "#ifdef SC",
+ " trpt = getframe(depth);",
+ "#else",
+ " trpt--;",
+ "#endif",
+ " /* reached[ot][t->st] = 1; 3.4.13 */",
+ " ((P0 *)this)->_p = tt;",
+ "#ifndef NOFAIR",
+ " if ((trpt->o_pm&32))",
+ " {",
+ "#ifdef VERI",
+ " if (now._cnt[now._a_t&1] == 0)",
+ " now._cnt[now._a_t&1] = 1;",
+ "#endif",
+ " now._cnt[now._a_t&1] += 1;",
+ " }",
+ "Q999:",
+ " if (trpt->o_pm&8)",
+ " { now._a_t &= ~2;",
+ " now._cnt[now._a_t&1] = 0;",
+ " }",
+ " if (trpt->o_pm&16)",
+ " now._a_t |= 2;",
+ "#endif",
+ "CameFromHere:",
+ " if (memcmp((char *) &now, (char *) &comp_now, vsize) == 0)",
+ " return depth;",
+ " if (depth > 0) goto Up;",
+ " return 0;",
+ "}",
+ "#endif",
+ "static char unwinding;",
+ "void",
+ "uerror(char *str)",
+ "{ static char laststr[256];",
+ " int is_cycle;",
+ "",
+ " if (unwinding) return; /* 1.4.2 */",
+ " if (strncmp(str, laststr, 254))",
+ " printf(\"pan: %%s (at depth %%ld)\\n\", str,",
+ " (depthfound==-1)?depth:depthfound);",
+ " strncpy(laststr, str, 254);",
+ " errors++;",
+ "#ifdef HAS_CODE",
+ " if (readtrail) { wrap_trail(); return; }",
+ "#endif",
+ " is_cycle = (strstr(str, \" cycle\") != (char *) 0);",
+ " if (!is_cycle)",
+ " { depth++; trpt++;", /* include failed step */
+ " }",
+ " if ((every_error != 0)",
+ " || errors == upto)",
+ " {",
+ "#if defined(MA) && !defined(SAFETY)",
+ " if (is_cycle)",
+ " { int od = depth;",
+ " unwinding = 1;",
+ " depthfound = Unwind();",
+ " unwinding = 0;",
+ " depth = od;",
+ " }",
+ "#endif",
+"#ifdef BFS",
+ " if (depth > 1) trpt--;",
+ " nuerror(str);",
+ " if (depth > 1) trpt++;",
+"#else",
+ " putrail();",
+"#endif",
+ "#if defined(MA) && !defined(SAFETY)",
+ " if (strstr(str, \" cycle\"))",
+ " { if (every_error)",
+ " printf(\"sorry: MA writes 1 trail max\\n\");",
+ " wrapup(); /* no recovery from unwind */",
+ " }",
+ "#endif",
+ " }",
+ " if (!is_cycle)",
+ " { depth--; trpt--; /* undo */",
+ " }",
+"#ifndef BFS",
+ " if (iterative != 0 && maxdepth > 0)",
+ " { maxdepth = (iterative == 1)?(depth-1):(depth/2);",
+ " warned = 1;",
+ " printf(\"pan: reducing search depth to %%ld\\n\",",
+ " maxdepth);",
+ " } else",
+"#endif",
+ " if (errors >= upto && upto != 0)",
+ " wrapup();",
+ " depthfound = -1;",
+ "}\n",
+ "int",
+ "xrefsrc(int lno, S_F_MAP *mp, int M, int i)",
+ "{ Trans *T; int j, retval=1;",
+ " for (T = trans[M][i]; T; T = T->nxt)",
+ " if (T && T->tp)",
+ " { if (strcmp(T->tp, \".(goto)\") == 0",
+ " || strncmp(T->tp, \"goto :\", 6) == 0)",
+ " return 1; /* not reported */",
+ "",
+ " printf(\"\\tline %%d\", lno);",
+ " if (verbose)",
+ " for (j = 0; j < sizeof(mp); j++)",
+ " if (i >= mp[j].from && i <= mp[j].upto)",
+ " { printf(\", \\\"%%s\\\"\", mp[j].fnm);",
+ " break;",
+ " }",
+ " printf(\", state %%d\", i);",
+ " if (strcmp(T->tp, \"\") != 0)",
+ " { char *q;",
+ " q = transmognify(T->tp);",
+ " printf(\", \\\"%%s\\\"\", q?q:\"\");",
+ " } else if (stopstate[M][i])",
+ " printf(\", -end state-\");",
+ " printf(\"\\n\");",
+ " retval = 0; /* reported */",
+ " }",
+ " return retval;",
+ "}\n",
+ "void",
+ "r_ck(uchar *which, int N, int M, short *src, S_F_MAP *mp)",
+ "{ int i, m=0;\n",
+ "#ifdef VERI",
+ " if (M == VERI && !verbose) return;",
+ "#endif",
+ " printf(\"unreached in proctype %%s\\n\", procname[M]);",
+ " for (i = 1; i < N; i++)",
+#if 0
+ " if (which[i] == 0 /* && trans[M][i] */)",
+#else
+ " if (which[i] == 0",
+ " && (mapstate[M][i] == 0",
+ " || which[mapstate[M][i]] == 0))",
+#endif
+ " m += xrefsrc((int) src[i], mp, M, i);",
+ " else",
+ " m++;",
+ " printf(\"\t(%%d of %%d states)\\n\", N-1-m, N-1);",
+ "}\n",
+ "void",
+ "putrail(void)",
+ "{ int fd; long i, j;",
+ " Trail *trl;",
+ "#if defined VERI || defined(MERGED)",
+ " char snap[64];",
+ "#endif",
+ "",
+ " fd = make_trail();",
+ " if (fd < 0) return;",
+ "#ifdef VERI",
+ " sprintf(snap, \"-2:%%d:-2\\n\", VERI);",
+ " write(fd, snap, strlen(snap));",
+ "#endif",
+ "#ifdef MERGED",
+ " sprintf(snap, \"-4:-4:-4\\n\");",
+ " write(fd, snap, strlen(snap));",
+ "#endif",
+ " for (i = 1; i <= depth; i++)",
+ " { if (i == depthfound+1)",
+ " write(fd, \"-1:-1:-1\\n\", 9);",
+ " trl = getframe(i);",
+ " if (!trl->o_t) continue;",
+ " if (trl->o_pm&128) continue;",
+ " sprintf(snap, \"%%ld:%%d:%%d\\n\", ",
+ " i, trl->pr, trl->o_t->t_id);",
+ " j = strlen(snap);",
+ " if (write(fd, snap, j) != j)",
+ " { printf(\"pan: error writing trailfile\\n\");",
+ " close(fd);",
+ " wrapup();",
+ " }",
+ " }",
+ " close(fd);",
+ "}\n",
+ "void",
+ "sv_save(void) /* push state vector onto save stack */",
+ "{ if (!svtack->nxt)",
+ " { svtack->nxt = (Svtack *) emalloc(sizeof(Svtack));",
+ " svtack->nxt->body = emalloc(vsize*sizeof(char));",
+ " svtack->nxt->lst = svtack;",
+ " svtack->nxt->m_delta = vsize;",
+ " svmax++;",
+ " } else if (vsize > svtack->nxt->m_delta)",
+ " { svtack->nxt->body = emalloc(vsize*sizeof(char));",
+ " svtack->nxt->lst = svtack;",
+ " svtack->nxt->m_delta = vsize;",
+ " svmax++;",
+ " }",
+ " svtack = svtack->nxt;",
+ "#if SYNC",
+ " svtack->o_boq = boq;",
+ "#endif",
+ " svtack->o_delta = vsize; /* don't compress */",
+ " memcpy((char *)(svtack->body), (char *) &now, vsize);",
+ "#if defined(C_States) && defined(HAS_STACK) && (HAS_TRACK==1)",
+ " c_stack((uchar *) &(svtack->c_stack[0]));",
+ "#endif",
+ "#ifdef DEBUG",
+ " printf(\"%%d: sv_save\\n\", depth);",
+ "#endif",
+ "}\n",
+ "void",
+ "sv_restor(void) /* pop state vector from save stack */",
+ "{",
+ " memcpy((char *)&now, svtack->body, svtack->o_delta);",
+ "#if SYNC",
+ " boq = svtack->o_boq;",
+ "#endif",
+
+ "#if defined(C_States) && (HAS_TRACK==1)",
+ "#ifdef HAS_STACK",
+ " c_unstack((uchar *) &(svtack->c_stack[0]));",
+ "#endif",
+ " c_revert((uchar *) &(now.c_state[0]));",
+ "#endif",
+
+ " if (vsize != svtack->o_delta)",
+ " Uerror(\"sv_restor\");",
+ " if (!svtack->lst)",
+ " Uerror(\"error: v_restor\");",
+ " svtack = svtack->lst;",
+ "#ifdef DEBUG",
+ " printf(\" sv_restor\\n\");",
+ "#endif",
+ "}\n",
+ "void",
+ "p_restor(int h)",
+ "{ int i; char *z = (char *) &now;\n",
+ " proc_offset[h] = stack->o_offset;",
+ " proc_skip[h] = (uchar) stack->o_skip;",
+ "#ifndef XUSAFE",
+ " p_name[h] = stack->o_name;",
+ "#endif",
+ "#ifndef NOCOMP",
+ " for (i = vsize + stack->o_skip; i > vsize; i--)",
+ " Mask[i-1] = 1; /* align */",
+ "#endif",
+ " vsize += stack->o_skip;",
+ " memcpy(z+vsize, stack->body, stack->o_delta);",
+ " vsize += stack->o_delta;",
+ "#ifndef NOVSZ",
+ " now._vsz = vsize;",
+ "#endif",
+ "#ifndef NOCOMP",
+ " for (i = 1; i <= Air[((P0 *)pptr(h))->_t]; i++)",
+ " Mask[vsize - i] = 1; /* pad */",
+ " Mask[proc_offset[h]] = 1; /* _pid */",
+ "#endif",
+ " if (BASE > 0 && h > 0)",
+ " ((P0 *)pptr(h))->_pid = h-BASE;",
+ " else",
+ " ((P0 *)pptr(h))->_pid = h;",
+ " i = stack->o_delqs;",
+ " now._nr_pr += 1;",
+ " if (!stack->lst) /* debugging */",
+ " Uerror(\"error: p_restor\");",
+ " stack = stack->lst;",
+ " this = pptr(h);",
+ " while (i-- > 0)",
+ " q_restor();",
+ "}\n",
+ "void",
+ "q_restor(void)",
+ "{ char *z = (char *) &now;",
+ "#ifndef NOCOMP",
+ " int k, k_end;",
+ "#endif",
+ " q_offset[now._nr_qs] = stack->o_offset;",
+ " q_skip[now._nr_qs] = (uchar) stack->o_skip;",
+ "#ifndef XUSAFE",
+ " q_name[now._nr_qs] = stack->o_name;",
+ "#endif",
+ " vsize += stack->o_skip;",
+ " memcpy(z+vsize, stack->body, stack->o_delta);",
+ " vsize += stack->o_delta;",
+ "#ifndef NOVSZ",
+ " now._vsz = vsize;",
+ "#endif",
+ " now._nr_qs += 1;",
+ "#ifndef NOCOMP",
+ " k_end = stack->o_offset;",
+ " k = k_end - stack->o_skip;",
+ "#if SYNC",
+ "#ifndef BFS",
+ " if (q_zero(now._nr_qs)) k_end += stack->o_delta;",
+ "#endif",
+ "#endif",
+ " for ( ; k < k_end; k++)",
+ " Mask[k] = 1;",
+ "#endif",
+ " if (!stack->lst) /* debugging */",
+ " Uerror(\"error: q_restor\");",
+ " stack = stack->lst;",
+ "}",
+
+ "typedef struct IntChunks {",
+ " int *ptr;",
+ " struct IntChunks *nxt;",
+ "} IntChunks;",
+ "IntChunks *filled_chunks[512];",
+ "IntChunks *empty_chunks[512];",
+
+ "int *",
+ "grab_ints(int nr)",
+ "{ IntChunks *z;",
+ " if (nr >= 512) Uerror(\"cannot happen grab_int\");",
+ " if (filled_chunks[nr])",
+ " { z = filled_chunks[nr];",
+ " filled_chunks[nr] = filled_chunks[nr]->nxt;",
+ " } else ",
+ " { z = (IntChunks *) emalloc(sizeof(IntChunks));",
+ " z->ptr = (int *) emalloc(nr * sizeof(int));",
+ " }",
+ " z->nxt = empty_chunks[nr];",
+ " empty_chunks[nr] = z;",
+ " return z->ptr;",
+ "}",
+ "void",
+ "ungrab_ints(int *p, int nr)",
+ "{ IntChunks *z;",
+ " if (!empty_chunks[nr]) Uerror(\"cannot happen ungrab_int\");",
+ " z = empty_chunks[nr];",
+ " empty_chunks[nr] = empty_chunks[nr]->nxt;",
+ " z->ptr = p;",
+ " z->nxt = filled_chunks[nr];",
+ " filled_chunks[nr] = z;",
+ "}",
+ "int",
+ "delproc(int sav, int h)",
+ "{ int d, i=0;",
+ "#ifndef NOCOMP",
+ " int o_vsize = vsize;",
+ "#endif",
+ " if (h+1 != (int) now._nr_pr) return 0;\n",
+ " while (now._nr_qs",
+ " && q_offset[now._nr_qs-1] > proc_offset[h])",
+ " { delq(sav);",
+ " i++;",
+ " }",
+ " d = vsize - proc_offset[h];",
+ " if (sav)",
+ " { if (!stack->nxt)",
+ " { stack->nxt = (Stack *)",
+ " emalloc(sizeof(Stack));",
+ " stack->nxt->body = ",
+ " emalloc(Maxbody*sizeof(char));",
+ " stack->nxt->lst = stack;",
+ " smax++;",
+ " }",
+ " stack = stack->nxt;",
+ " stack->o_offset = proc_offset[h];",
+ "#if VECTORSZ>32000",
+ " stack->o_skip = (int) proc_skip[h];",
+ "#else",
+ " stack->o_skip = (short) proc_skip[h];",
+ "#endif",
+ "#ifndef XUSAFE",
+ " stack->o_name = p_name[h];",
+ "#endif",
+ " stack->o_delta = d;",
+ " stack->o_delqs = i;",
+ " memcpy(stack->body, (char *)pptr(h), d);",
+ " }",
+ " vsize = proc_offset[h];",
+ " now._nr_pr = now._nr_pr - 1;",
+ " memset((char *)pptr(h), 0, d);",
+ " vsize -= (int) proc_skip[h];",
+ "#ifndef NOVSZ",
+ " now._vsz = vsize;",
+ "#endif",
+ "#ifndef NOCOMP",
+ " for (i = vsize; i < o_vsize; i++)",
+ " Mask[i] = 0; /* reset */",
+ "#endif",
+ " return 1;",
+ "}\n",
+ "void",
+ "delq(int sav)",
+ "{ int h = now._nr_qs - 1;",
+ " int d = vsize - q_offset[now._nr_qs - 1];",
+ "#ifndef NOCOMP",
+ " int k, o_vsize = vsize;",
+ "#endif",
+ " if (sav)",
+ " { if (!stack->nxt)",
+ " { stack->nxt = (Stack *)",
+ " emalloc(sizeof(Stack));",
+ " stack->nxt->body = ",
+ " emalloc(Maxbody*sizeof(char));",
+ " stack->nxt->lst = stack;",
+ " smax++;",
+ " }",
+ " stack = stack->nxt;",
+ " stack->o_offset = q_offset[h];",
+ "#if VECTORSZ>32000",
+ " stack->o_skip = (int) q_skip[h];",
+ "#else",
+ " stack->o_skip = (short) q_skip[h];",
+ "#endif",
+ "#ifndef XUSAFE",
+ " stack->o_name = q_name[h];",
+ "#endif",
+ " stack->o_delta = d;",
+ " memcpy(stack->body, (char *)qptr(h), d);",
+ " }",
+ " vsize = q_offset[h];",
+ " now._nr_qs = now._nr_qs - 1;",
+ " memset((char *)qptr(h), 0, d);",
+ " vsize -= (int) q_skip[h];",
+ "#ifndef NOVSZ",
+ " now._vsz = vsize;",
+ "#endif",
+ "#ifndef NOCOMP",
+ " for (k = vsize; k < o_vsize; k++)",
+ " Mask[k] = 0; /* reset */",
+ "#endif",
+ "}\n",
+ "int",
+ "qs_empty(void)",
+ "{ int i;",
+ " for (i = 0; i < (int) now._nr_qs; i++)",
+ " { if (q_sz(i) > 0)",
+ " return 0;",
+ " }",
+ " return 1;",
+ "}\n",
+ "int",
+ "endstate(void)",
+ "{ int i; P0 *ptr;",
+ " for (i = BASE; i < (int) now._nr_pr; i++)",
+ " { ptr = (P0 *) pptr(i);",
+ " if (!stopstate[ptr->_t][ptr->_p])",
+ " return 0;",
+ " }",
+ " if (strict) return qs_empty();",
+ "#if defined(EVENT_TRACE) && !defined(OTIM)",
+ " if (!stopstate[EVENT_TRACE][now._event] && !a_cycles)",
+ " { printf(\"pan: event_trace not completed\\n\");",
+ " return 0;",
+ " }",
+ "#endif",
+ " return 1;",
+ "}\n",
+ "#ifndef SAFETY",
+ "void",
+ "checkcycles(void)",
+ "{ uchar o_a_t = now._a_t;",
+ "#ifndef NOFAIR",
+ " uchar o_cnt = now._cnt[1];",
+ "#endif",
+ "#ifdef FULLSTACK",
+ "#ifndef MA",
+ " struct H_el *sv = trpt->ostate; /* save */",
+ "#else",
+ " uchar prov = trpt->proviso; /* save */",
+ "#endif",
+ "#endif",
+ "#ifdef DEBUG",
+ " { int i; uchar *v = (uchar *) &now;",
+ " printf(\" set Seed state \");",
+ "#ifndef NOFAIR",
+ " if (fairness) printf(\"(cnt = %%d:%%d, nrpr=%%d) \",",
+ " now._cnt[0], now._cnt[1], now._nr_pr);",
+ "#endif",
+ " /* for (i = 0; i < n; i++) printf(\"%%d,\", v[i]); */",
+ " printf(\"\\n\");",
+ " }",
+ " printf(\"%%d: cycle check starts\\n\", depth);",
+ "#endif",
+ " now._a_t |= (1|16|32);",
+ " /* 1 = 2nd DFS; (16|32) to help hasher */",
+ "#ifndef NOFAIR",
+#if 0
+ " if (fairness)",
+ " { now._a_t &= ~2; /* pre-apply Rule 3 */",
+ " now._cnt[1] = 0;", /* reset both a-bit and cnt=0 */
+ " /* avoid matching seed on claim stutter on this state */",
+ " }",
+#else
+ " now._cnt[1] = now._cnt[0];",
+#endif
+ "#endif",
+ " memcpy((char *)&A_Root, (char *)&now, vsize);",
+ " A_depth = depthfound = depth;",
+ " new_state(); /* start 2nd DFS */",
+ " now._a_t = o_a_t;",
+ "#ifndef NOFAIR",
+ " now._cnt[1] = o_cnt;",
+ "#endif",
+ " A_depth = 0; depthfound = -1;",
+ "#ifdef DEBUG",
+ " printf(\"%%d: cycle check returns\\n\", depth);",
+ "#endif",
+ "#ifdef FULLSTACK",
+ "#ifndef MA",
+ " trpt->ostate = sv; /* restore */",
+ "#else",
+ " trpt->proviso = prov;",
+ "#endif",
+ "#endif",
+ "}",
+ "#endif\n",
+ "#if defined(FULLSTACK) && defined(BITSTATE)",
+ "struct H_el *Free_list = (struct H_el *) 0;",
+ "void",
+ "onstack_init(void) /* to store stack states in a bitstate search */",
+ "{ S_Tab = (struct H_el **) emalloc(maxdepth*sizeof(struct H_el *));",
+ "}",
+ "struct H_el *",
+ "grab_state(int n)",
+ "{ struct H_el *v, *last = 0;",
+ " if (H_tab == S_Tab)",
+ " { for (v = Free_list; v && ((int) v->tagged >= n); v=v->nxt)",
+ " { if ((int) v->tagged == n)",
+ " { if (last)",
+ " last->nxt = v->nxt;",
+ " else",
+ "gotcha: Free_list = v->nxt;",
+ " v->tagged = 0;",
+ " v->nxt = 0;",
+ "#ifdef COLLAPSE",
+ " v->ln = 0;",
+ "#endif",
+ " return v;",
+ " }",
+ " Fh++; last=v;",
+ " }",
+ " /* new: second try */",
+ " v = Free_list;", /* try to avoid emalloc */
+ " if (v && ((int) v->tagged >= n))",
+ " goto gotcha;",
+ " ngrabs++;",
+ " }",
+ " return (struct H_el *)",
+ " emalloc(sizeof(struct H_el)+n-sizeof(unsigned));",
+ "}\n",
+ "#else",
+ "#define grab_state(n) (struct H_el *) \\",
+ " emalloc(sizeof(struct H_el)+n-sizeof(unsigned));",
+ "#endif",
+"#ifdef COLLAPSE",
+ "unsigned long",
+ "ordinal(char *v, long n, short tp)",
+ "{ struct H_el *tmp, *ntmp; long m;",
+ " struct H_el *olst = (struct H_el *) 0;",
+ " s_hash((uchar *)v, n);",
+ " tmp = H_tab[j1];",
+ " if (!tmp)",
+ " { tmp = grab_state(n);",
+ " H_tab[j1] = tmp;",
+ " } else",
+ " for ( ;; olst = tmp, tmp = tmp->nxt)",
+ " { m = memcmp(((char *)&(tmp->state)), v, n);",
+ " if (n == tmp->ln)",
+ " {",
+ " if (m == 0)",
+ " goto done;",
+ " if (m < 0)",
+ " {",
+ "Insert: ntmp = grab_state(n);",
+ " ntmp->nxt = tmp;",
+ " if (!olst)",
+ " H_tab[j1] = ntmp;",
+ " else",
+ " olst->nxt = ntmp;",
+ " tmp = ntmp;",
+ " break;",
+ " } else if (!tmp->nxt)",
+ " {",
+ "Append: tmp->nxt = grab_state(n);",
+ " tmp = tmp->nxt;",
+ " break;",
+ " }",
+ " continue;",
+ " }",
+ " if (n < tmp->ln)",
+ " goto Insert;",
+ " else if (!tmp->nxt)",
+ " goto Append;",
+ " }",
+ " m = ++ncomps[tp];",
+ "#ifdef FULLSTACK",
+ " tmp->tagged = m;",
+ "#else",
+ " tmp->st_id = m;",
+ "#endif",
+ " memcpy(((char *)&(tmp->state)), v, n);",
+ " tmp->ln = n;",
+ "done:",
+ "#ifdef FULLSTACK",
+ " return tmp->tagged;",
+ "#else",
+ " return tmp->st_id;",
+ "#endif",
+ "}",
+ "",
+ "int",
+ "compress(char *vin, int nin) /* collapse compression */",
+ "{ char *w, *v = (char *) &comp_now;",
+ " int i, j;",
+ " unsigned long n;",
+ " static char *x;",
+ " static uchar nbytes[513]; /* 1 + 256 + 256 */",
+ " static unsigned short nbytelen;",
+ " long col_q(int, char *);",
+ " long col_p(int, char *);",
+ "#ifndef SAFETY",
+ " if (a_cycles)",
+ " *v++ = now._a_t;",
+ "#ifndef NOFAIR",
+ " if (fairness)",
+ " for (i = 0; i < NFAIR; i++)",
+ " *v++ = now._cnt[i];",
+ "#endif",
+ "#endif",
+ " nbytelen = 0;",
+
+ "#ifndef JOINPROCS",
+ " for (i = 0; i < (int) now._nr_pr; i++)",
+ " { n = col_p(i, (char *) 0);",
+ "#ifdef NOFIX",
+ " nbytes[nbytelen] = 0;",
+ "#else",
+ " nbytes[nbytelen] = 1;",
+ " *v++ = ((P0 *) pptr(i))->_t;",
+ "#endif",
+ " *v++ = n&255;",
+ " if (n >= (1<<8))",
+ " { nbytes[nbytelen]++;",
+ " *v++ = (n>>8)&255;",
+ " }",
+ " if (n >= (1<<16))",
+ " { nbytes[nbytelen]++;",
+ " *v++ = (n>>16)&255;",
+ " }",
+ " if (n >= (1<<24))",
+ " { nbytes[nbytelen]++;",
+ " *v++ = (n>>24)&255;",
+ " }",
+ " nbytelen++;",
+ " }",
+ "#else",
+ " x = scratch;",
+ " for (i = 0; i < (int) now._nr_pr; i++)",
+ " x += col_p(i, x);",
+ " n = ordinal(scratch, x-scratch, 2); /* procs */",
+ " *v++ = n&255;",
+ " nbytes[nbytelen] = 0;",
+ " if (n >= (1<<8))",
+ " { nbytes[nbytelen]++;",
+ " *v++ = (n>>8)&255;",
+ " }",
+ " if (n >= (1<<16))",
+ " { nbytes[nbytelen]++;",
+ " *v++ = (n>>16)&255;",
+ " }",
+ " if (n >= (1<<24))",
+ " { nbytes[nbytelen]++;",
+ " *v++ = (n>>24)&255;",
+ " }",
+ " nbytelen++;",
+ "#endif",
+ "#ifdef SEPQS",
+ " for (i = 0; i < (int) now._nr_qs; i++)",
+ " { n = col_q(i, (char *) 0);",
+ " nbytes[nbytelen] = 0;",
+ " *v++ = n&255;",
+ " if (n >= (1<<8))",
+ " { nbytes[nbytelen]++;",
+ " *v++ = (n>>8)&255;",
+ " }",
+ " if (n >= (1<<16))",
+ " { nbytes[nbytelen]++;",
+ " *v++ = (n>>16)&255;",
+ " }",
+ " if (n >= (1<<24))",
+ " { nbytes[nbytelen]++;",
+ " *v++ = (n>>24)&255;",
+ " }",
+ " nbytelen++;",
+ " }",
+ "#endif",
+
+ "#ifdef NOVSZ",
+ " /* 3 = _a_t, _nr_pr, _nr_qs */",
+ " w = (char *) &now + 3 * sizeof(uchar);",
+ "#ifndef NOFAIR",
+ " w += NFAIR;",
+ "#endif",
+ "#else",
+ "#if VECTORSZ<65536",
+ " w = (char *) &(now._vsz) + sizeof(unsigned short);",
+ "#else",
+ " w = (char *) &(now._vsz) + sizeof(unsigned long);",
+ "#endif",
+ "#endif",
+ " x = scratch;",
+ " *x++ = now._nr_pr;",
+ " *x++ = now._nr_qs;",
+
+ " if (now._nr_qs > 0 && qptr(0) < pptr(0))",
+ " n = qptr(0) - (uchar *) w;",
+ " else",
+ " n = pptr(0) - (uchar *) w;",
+ " j = w - (char *) &now;",
+ " for (i = 0; i < (int) n; i++, w++)",
+ " if (!Mask[j++]) *x++ = *w;",
+ "#ifndef SEPQS",
+ " for (i = 0; i < (int) now._nr_qs; i++)",
+ " x += col_q(i, x);",
+ "#endif",
+
+ " x--;",
+ " for (i = 0, j = 6; i < nbytelen; i++)",
+ " { if (j == 6)",
+ " { j = 0;",
+ " *(++x) = 0;",
+ " } else",
+ " j += 2;",
+ " *x |= (nbytes[i] << j);",
+ " }",
+ " x++;",
+ " for (j = 0; j < WS-1; j++)",
+ " *x++ = 0;",
+ " x -= j; j = 0;",
+ " n = ordinal(scratch, x-scratch, 0); /* globals */",
+ " *v++ = n&255;",
+ " if (n >= (1<< 8)) { *v++ = (n>> 8)&255; j++; }",
+ " if (n >= (1<<16)) { *v++ = (n>>16)&255; j++; }",
+ " if (n >= (1<<24)) { *v++ = (n>>24)&255; j++; }",
+ " *v++ = j; /* add last count as a byte */",
+
+ " for (i = 0; i < WS-1; i++)",
+ " *v++ = 0;",
+ " v -= i;",
+ "#if 0",
+ " printf(\"collapse %%d -> %%d\\n\",",
+ " vsize, v - (char *)&comp_now);",
+ "#endif",
+ " return v - (char *)&comp_now;",
+ "}",
+
+"#else",
+"#if !defined(NOCOMP)",
+ "int",
+ "compress(char *vin, int n) /* default compression */",
+ "{",
+ "#ifdef HC",
+ " int delta = 0;",
+ " s_hash((uchar *)vin, n); /* sets K1 and K2 */",
+ "#ifndef SAFETY",
+ " if (S_A)",
+ " { delta++; /* _a_t */",
+ "#ifndef NOFAIR",
+ " if (S_A > NFAIR)",
+ " delta += NFAIR; /* _cnt[] */",
+ "#endif",
+ " }",
+ "#endif",
+ " memcpy((char *) &comp_now + delta, (char *) &K1, WS);",
+ " delta += WS;",
+ "#if HC>0",
+ " memcpy((char *) &comp_now + delta, (char *) &K2, HC);",
+ " delta += HC;",
+ "#endif",
+ " return delta;",
+ "#else",
+ " char *vv = vin;",
+ " char *v = (char *) &comp_now;",
+ " int i;",
+ " for (i = 0; i < n; i++, vv++)",
+ " if (!Mask[i]) *v++ = *vv;",
+ " for (i = 0; i < WS-1; i++)",
+ " *v++ = 0;",
+ " v -= i;",
+ "#if 0",
+ " printf(\"compress %%d -> %%d\\n\",",
+ " n, v - (char *)&comp_now);",
+ "#endif",
+ " return v - (char *)&comp_now;",
+ "#endif",
+ "}",
+"#endif",
+"#endif",
+ "#if defined(FULLSTACK) && defined(BITSTATE)",
+"#if defined(MA)",
+ "#if !defined(onstack_now)",
+ "int onstack_now(void) {}", /* to suppress compiler errors */
+ "#endif",
+ "#if !defined(onstack_put)",
+ "void onstack_put(void) {}", /* for this invalid combination */
+ "#endif",
+ "#if !defined(onstack_zap)",
+ "void onstack_zap(void) {}", /* of directives */
+ "#endif",
+"#else",
+ "void",
+ "onstack_zap(void)",
+ "{ struct H_el *v, *w, *last = 0;",
+ " struct H_el **tmp = H_tab;",
+ " char *nv; int n, m;\n",
+ " H_tab = S_Tab;",
+ "#ifndef NOCOMP",
+ " nv = (char *) &comp_now;",
+ " n = compress((char *)&now, vsize);",
+ "#else",
+ "#if defined(BITSTATE) && defined(LC)",
+ " nv = (char *) &comp_now;",
+ " n = compact_stack((char *)&now, vsize);",
+ "#else",
+ " nv = (char *) &now;",
+ " n = vsize;",
+ "#endif",
+ "#endif",
+ "#if !defined(HC) && !(defined(BITSTATE) && defined(LC))",
+ " s_hash((uchar *)nv, n);",
+ "#endif",
+ " H_tab = tmp;",
+ " for (v = S_Tab[j1]; v; Zh++, last=v, v=v->nxt)",
+ " { m = memcmp(&(v->state), nv, n);",
+ " if (m == 0)",
+ " goto Found;",
+ " if (m < 0)",
+ " break;",
+ " }",
+ "/* NotFound: */",
+ " Uerror(\"stack out of wack - zap\");",
+ " return;",
+ "Found:",
+ " ZAPS++;",
+ " if (last)",
+ " last->nxt = v->nxt;",
+ " else",
+ " S_Tab[j1] = v->nxt;",
+ " v->tagged = (unsigned) n;",
+ "#if !defined(NOREDUCE) && !defined(SAFETY)",
+ " v->proviso = 0;",
+ "#endif",
+ " v->nxt = last = (struct H_el *) 0;",
+ " for (w = Free_list; w; Fa++, last=w, w = w->nxt)",
+ " { if ((int) w->tagged <= n)",
+ " { if (last)",
+ " { v->nxt = w; /* was: v->nxt = w->nxt; */",
+ " last->nxt = v;",
+ " } else",
+ " { v->nxt = Free_list;",
+ " Free_list = v;",
+ " }",
+ " return;",
+ " }",
+ " if (!w->nxt)",
+ " { w->nxt = v;",
+ " return;",
+ " } }",
+ " Free_list = v;",
+ "}",
+ "void",
+ "onstack_put(void)",
+ "{ struct H_el **tmp = H_tab;",
+ " H_tab = S_Tab;",
+ " if (hstore((char *)&now, vsize) != 0)",
+ "#if defined(BITSTATE) && defined(LC)",
+ " printf(\"pan: warning, double stack entry\\n\");",
+ "#else",
+ " Uerror(\"cannot happen - unstack_put\");",
+ "#endif",
+ " H_tab = tmp;",
+ " trpt->ostate = Lstate;",
+ " PUT++;",
+ "}",
+ "int",
+ "onstack_now(void)",
+ "{ struct H_el *tmp;",
+ " struct H_el **tmp2 = H_tab;",
+ " char *v; int n, m = 1;\n",
+ " H_tab = S_Tab;",
+ "#ifdef NOCOMP",
+ "#if defined(BITSTATE) && defined(LC)",
+ " v = (char *) &comp_now;",
+ " n = compact_stack((char *)&now, vsize);",
+ "#else",
+ " v = (char *) &now;",
+ " n = vsize;",
+ "#endif",
+ "#else",
+ " v = (char *) &comp_now;",
+ " n = compress((char *)&now, vsize);",
+ "#endif",
+ "#if !defined(HC) && !(defined(BITSTATE) && defined(LC))",
+ " s_hash((uchar *)v, n);",
+ "#endif",
+ " H_tab = tmp2;",
+ " for (tmp = S_Tab[j1]; tmp; Zn++, tmp = tmp->nxt)",
+ " { m = memcmp(((char *)&(tmp->state)),v,n);",
+ " if (m <= 0)",
+ " { Lstate = (struct H_el *) tmp;",
+ " break;",
+ " } }",
+ " PROBE++;",
+ " return (m == 0);",
+ "}",
+ "#endif",
+"#endif",
+
+ "#ifndef BITSTATE",
+ "void",
+ "hinit(void)",
+ "{",
+"#ifdef MA",
+ "#ifdef R_XPT",
+ " { void r_xpoint(void);",
+ " r_xpoint();",
+ " }",
+ "#else",
+ " dfa_init((unsigned short) (MA+a_cycles));",
+ "#endif",
+"#endif",
+"#if !defined(MA) || defined(COLLAPSE)",
+ " H_tab = (struct H_el **)",
+ " emalloc((1L<<ssize)*sizeof(struct H_el *));",
+"#endif",
+ "}",
+ "#endif\n",
+
+ "#if !defined(BITSTATE) || defined(FULLSTACK)",
+
+ "#ifdef DEBUG",
+ "void",
+ "dumpstate(int wasnew, char *v, int n, int tag)",
+ "{ int i;",
+ "#ifndef SAFETY",
+ " if (S_A)",
+ " { printf(\"\tstate tags %%d (%%d::%%d): \",",
+ " V_A, wasnew, v[0]);",
+ "#ifdef FULLSTACK",
+ " printf(\" %%d \", tag);",
+ "#endif",
+ " printf(\"\\n\");",
+ " }",
+ "#endif",
+ "#ifdef SDUMP",
+ "#ifndef NOCOMP",
+ " printf(\"\t State: \");",
+ " for (i = 0; i < vsize; i++) printf(\"%%d%%s,\",",
+ " ((char *)&now)[i], Mask[i]?\"*\":\"\");",
+ "#endif",
+ " printf(\"\\n\tVector: \");",
+ " for (i = 0; i < n; i++) printf(\"%%d,\", v[i]);",
+ " printf(\"\\n\");",
+ "#endif",
+ "}",
+ "#endif",
+
+"#ifdef MA",
+ "int",
+ "gstore(char *vin, int nin, uchar pbit)",
+ "{ int n, i;",
+ " uchar *v;",
+ " static uchar Info[MA+1];",
+ "#ifndef NOCOMP",
+ " n = compress(vin, nin);",
+ " v = (uchar *) &comp_now;",
+ "#else",
+ " n = nin;",
+ " v = vin;",
+ "#endif",
+ " if (n >= MA)",
+ " { printf(\"pan: error, MA too small, recompile pan.c\");",
+ " printf(\" with -DMA=N with N>%%d\\n\", n);",
+ " Uerror(\"aborting\");",
+ " }",
+ " if (n > (int) maxgs) maxgs = (unsigned int) n;",
+
+ " for (i = 0; i < n; i++)",
+ " Info[i] = v[i];",
+ " for ( ; i < MA-1; i++)",
+ " Info[i] = 0;",
+ " Info[MA-1] = pbit;",
+ " if (a_cycles) /* place _a_t at the end */",
+ " { Info[MA] = Info[0]; Info[0] = 0; }",
+ " if (!dfa_store(Info))",
+ " { if (pbit == 0",
+ " && (now._a_t&1)",
+ " && depth > A_depth)",
+ " { Info[MA] &= ~(1|16|32); /* _a_t */",
+ " if (dfa_member(MA))", /* was !dfa_member(MA) */
+ " { Info[MA-1] = 4; /* off-stack bit */",
+ " nShadow++;",
+ " if (!dfa_member(MA-1))",
+ " {",
+ "#ifdef VERBOSE",
+ " printf(\"intersected 1st dfs stack\\n\");",
+ "#endif",
+ " return 3;",
+ " } } }",
+ "#ifdef VERBOSE",
+ " printf(\"new state\\n\");",
+ "#endif",
+ " return 0; /* new state */",
+ " }",
+ "#ifdef FULLSTACK",
+ " if (pbit == 0)",
+ " { Info[MA-1] = 1; /* proviso bit */",
+ "#ifndef BFS",
+ " trpt->proviso = dfa_member(MA-1);",
+ "#endif",
+ " Info[MA-1] = 4; /* off-stack bit */",
+ " if (dfa_member(MA-1)) {",
+ "#ifdef VERBOSE",
+ " printf(\"old state\\n\");",
+ "#endif",
+ " return 1; /* off-stack */",
+ " } else {",
+ "#ifdef VERBOSE",
+ " printf(\"on-stack\\n\");",
+ "#endif",
+ " return 2; /* on-stack */",
+ " }",
+ " }",
+ "#endif",
+ "#ifdef VERBOSE",
+ " printf(\"old state\\n\");",
+ "#endif",
+ " return 1; /* old state */",
+ "}",
+"#endif",
+
+ "#if defined(BITSTATE) && defined(LC)",
+ "int",
+ "compact_stack(char *vin, int n)", /* special case of HC4 */
+ "{ int delta = 0;",
+ " s_hash((uchar *)vin, n); /* sets K1 and K2 */",
+ "#ifndef SAFETY",
+ " delta++; /* room for state[0] |= 128 */",
+ "#endif",
+ " memcpy((char *) &comp_now + delta, (char *) &K1, WS);",
+ " delta += WS;",
+ " memcpy((char *) &comp_now + delta, (char *) &K2, WS);",
+ " delta += WS; /* use all available bits */",
+ " return delta;",
+ "}",
+ "#endif",
+
+ "int",
+ "hstore(char *vin, int nin) /* hash table storage */",
+ "{ struct H_el *tmp, *ntmp, *olst = (struct H_el *) 0;",
+ " char *v; int n, m=0;",
+ "#ifdef HC",
+ " uchar rem_a;",
+ "#endif",
+ "#ifdef NOCOMP", /* defined by BITSTATE */
+ "#if defined(BITSTATE) && defined(LC)",
+ " if (S_Tab == H_tab)",
+ " { v = (char *) &comp_now;",
+ " n = compact_stack(vin, nin);",
+ " } else",
+ " { v = vin; n = nin;",
+ " }",
+ "#else",
+ " v = vin; n = nin;",
+ "#endif",
+ "#else",
+ " v = (char *) &comp_now;",
+ " #ifdef HC",
+ " rem_a = now._a_t;", /* 4.3.0 */
+ " now._a_t = 0;", /* for hashing/state matching to work right */
+ " #endif",
+ " n = compress(vin, nin);", /* with HC, this calls s_hash */
+ " #ifdef HC",
+ " now._a_t = rem_a;", /* 4.3.0 */
+ " #endif",
+ "#ifndef SAFETY",
+ " if (S_A)",
+ " { v[0] = 0; /* _a_t */",
+ "#ifndef NOFAIR",
+ " if (S_A > NFAIR)",
+ " for (m = 0; m < NFAIR; m++)",
+ " v[m+1] = 0; /* _cnt[] */",
+ "#endif",
+ " m = 0;",
+ " }",
+ "#endif",
+ "#endif",
+ "#if !defined(HC) && !(defined(BITSTATE) && defined(LC))",
+ " s_hash((uchar *)v, n);",
+ "#endif",
+ " tmp = H_tab[j1];",
+ " if (!tmp)",
+ " { tmp = grab_state(n);",
+ " H_tab[j1] = tmp;",
+ " } else",
+ " { for (;; hcmp++, olst = tmp, tmp = tmp->nxt)",
+ " { /* skip the _a_t and the _cnt bytes */",
+ "#ifdef COLLAPSE",
+ " if (tmp->ln != 0)",
+ " { if (!tmp->nxt) goto Append;",
+ " continue;",
+ " }",
+ "#endif",
+ " m = memcmp(((char *)&(tmp->state)) + S_A, ",
+ " v + S_A, n - S_A);",
+ " if (m == 0) {",
+ "#ifdef SAFETY",
+ "#define wasnew 0",
+ "#else",
+ " int wasnew = 0;",
+ "#endif",
+
+ "#ifndef SAFETY",
+ "#ifndef NOCOMP",
+ " if (S_A)",
+ " { if ((((char *)&(tmp->state))[0] & V_A) != V_A)",
+ " { wasnew = 1; nShadow++;",
+ " ((char *)&(tmp->state))[0] |= V_A;",
+ " }",
+ "#ifndef NOFAIR",
+ " if (S_A > NFAIR)",
+ " { /* 0 <= now._cnt[now._a_t&1] < MAXPROC */",
+ " unsigned ci, bp; /* index, bit pos */",
+ " ci = (now._cnt[now._a_t&1] / 8);",
+ " bp = (now._cnt[now._a_t&1] - 8*ci);",
+ " if (now._a_t&1) /* use tail-bits in _cnt */",
+ " { ci = (NFAIR - 1) - ci;",
+ " bp = 7 - bp; /* bp = 0..7 */",
+ " }",
+ " ci++; /* skip over _a_t */",
+ " bp = 1 << bp; /* the bit mask */",
+ " if ((((char *)&(tmp->state))[ci] & bp)==0)",
+ " { if (!wasnew)",
+ " { wasnew = 1;",
+ " nShadow++;",
+ " }",
+ " ((char *)&(tmp->state))[ci] |= bp;",
+ " }",
+ " }",
+ " /* else: wasnew == 0, i.e., old state */",
+ "#endif",
+ " }",
+ "#endif",
+ "#endif",
+
+ "#ifdef FULLSTACK",
+ "#ifndef SAFETY", /* or else wasnew == 0 */
+ " if (wasnew)",
+ " { Lstate = (struct H_el *) tmp;",
+ " tmp->tagged |= V_A;",
+ " if ((now._a_t&1)",
+ " && (tmp->tagged&A_V)",
+ " && depth > A_depth)",
+ " {",
+ "intersect:",
+ "#ifdef CHECK",
+ " printf(\"1st dfs-stack intersected on state %%d+\\n\",",
+ " (int) tmp->st_id);",
+ "#endif",
+ " return 3;",
+ " }",
+ "#ifdef CHECK",
+ " printf(\"\tNew state %%d+\\n\", (int) tmp->st_id);",
+ "#endif",
+ "#ifdef DEBUG",
+ " dumpstate(1, (char *)&(tmp->state),n,tmp->tagged);",
+ "#endif",
+ " return 0;",
+ " } else",
+ "#endif",
+ " if ((S_A)?(tmp->tagged&V_A):tmp->tagged)",
+ " { Lstate = (struct H_el *) tmp;",
+ "#ifndef SAFETY",
+ " /* already on current dfs stack */",
+ " /* but may also be on 1st dfs stack */",
+ " if ((now._a_t&1)",
+ " && (tmp->tagged&A_V)",
+
+ " && depth > A_depth",
+ /* new (Zhang's example) */
+ "#ifndef NOFAIR",
+ " && (!fairness || now._cnt[1] <= 1)",
+ "#endif",
+ " )",
+
+ " goto intersect;",
+ "#endif",
+ "#ifdef CHECK",
+ " printf(\"\tStack state %%d\\n\", (int) tmp->st_id);",
+ "#endif",
+ "#ifdef DEBUG",
+ " dumpstate(0, (char *)&(tmp->state),n,tmp->tagged);",
+ "#endif",
+ " return 2; /* match on stack */",
+ " }",
+ "#else",
+ " if (wasnew)",
+ " {",
+ "#ifdef CHECK",
+ " printf(\"\tNew state %%d+\\n\", (int) tmp->st_id);",
+ "#endif",
+ "#ifdef DEBUG",
+ " dumpstate(1, (char *)&(tmp->state), n, 0);",
+ "#endif",
+ " return 0;",
+ " }",
+ "#endif",
+ "#ifdef CHECK",
+ " printf(\"\tOld state %%d\\n\", (int) tmp->st_id);",
+ "#endif",
+ "#ifdef DEBUG",
+ " dumpstate(0, (char *)&(tmp->state), n, 0);",
+ "#endif",
+ "#ifdef REACH",
+ " if (tmp->D > depth)",
+ " { tmp->D = depth;",
+ "#ifdef CHECK",
+ " printf(\"\t\tReVisiting (from smaller depth)\\n\");",
+ "#endif",
+ " nstates--;",
+#if 0
+ possible variation of iterative search for shortest counter-example (pan -i
+ and pan -I) suggested by Pierre Moro (for safety properties):
+ state revisits on shorter depths do not start until after
+ the first counter-example is found. this assumes that the max search
+ depth is set large enough that a first (possibly long) counter-example
+ can be found
+ if set too short, this variant can miss the counter-example, even if
+ it would otherwise be shorter than the depth-limit.
+ (p.m. unsure if this preserves the guarantee of finding the
+ shortest counter-example - so not enabled yet)
+ " if (errors > 0 && iterative)", /* Moro */
+#endif
+ " return 0;",
+ " }",
+ "#endif",
+ "#if defined(BFS) && defined(Q_PROVISO)",
+ " Lstate = (struct H_el *) tmp;",
+ "#endif",
+ " return 1; /* match outside stack */",
+ " } else if (m < 0)",
+ " { /* insert state before tmp */",
+ " ntmp = grab_state(n);",
+ " ntmp->nxt = tmp;",
+ " if (!olst)",
+ " H_tab[j1] = ntmp;",
+ " else",
+ " olst->nxt = ntmp;",
+ " tmp = ntmp;",
+ " break;",
+ " } else if (!tmp->nxt)",
+ " { /* append after tmp */",
+ "#ifdef COLLAPSE",
+ "Append:",
+ "#endif",
+ " tmp->nxt = grab_state(n);",
+ " tmp = tmp->nxt;",
+ " break;",
+ " } }",
+ " }",
+ "#ifdef CHECK",
+ " tmp->st_id = (unsigned) nstates;",
+ "#ifdef BITSTATE",
+ " printf(\" Push state %%d\\n\", ((int) nstates) - 1);",
+ "#else",
+ " printf(\" New state %%d\\n\", (int) nstates);",
+ "#endif",
+ "#endif",
+ "#if !defined(SAFETY) || defined(REACH)",
+ " tmp->D = depth;",
+ "#endif",
+ "#ifndef SAFETY",
+ "#ifndef NOCOMP",
+ " if (S_A)",
+ " { v[0] = V_A;",
+ "#ifndef NOFAIR",
+ " if (S_A > NFAIR)",
+ " { unsigned ci, bp; /* as above */",
+ " ci = (now._cnt[now._a_t&1] / 8);",
+ " bp = (now._cnt[now._a_t&1] - 8*ci);",
+ " if (now._a_t&1)",
+ " { ci = (NFAIR - 1) - ci;",
+ " bp = 7 - bp; /* bp = 0..7 */",
+ " }",
+ " v[1+ci] = 1 << bp;",
+ " }",
+ "#endif",
+ " }",
+ "#endif",
+ "#endif",
+ " memcpy(((char *)&(tmp->state)), v, n);",
+ "#ifdef FULLSTACK",
+ " tmp->tagged = (S_A)?V_A:(depth+1);",
+ "#ifdef DEBUG",
+ " dumpstate(-1, v, n, tmp->tagged);",
+ "#endif",
+ " Lstate = (struct H_el *) tmp;",
+ "#else",
+ "#ifdef DEBUG",
+ " dumpstate(-1, v, n, 0);",
+ "#endif",
+ "#endif",
+ " return 0;",
+ "}",
+ "#endif",
+ "#include TRANSITIONS",
+ "void",
+ "do_reach(void)",
+ "{",
+ 0,
+};
diff --git a/sys/src/cmd/spin/pangen2.c b/sys/src/cmd/spin/pangen2.c
new file mode 100755
index 000000000..05ad9fa1f
--- /dev/null
+++ b/sys/src/cmd/spin/pangen2.c
@@ -0,0 +1,2996 @@
+/***** spin: pangen2.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include "spin.h"
+#include "version.h"
+#include "y.tab.h"
+#include "pangen2.h"
+#include "pangen4.h"
+#include "pangen5.h"
+
+#define DELTA 500 /* sets an upperbound on nr of chan names */
+
+#define blurb(fd, e) { fprintf(fd, "\n"); if (!merger) fprintf(fd, "\t\t/* %s:%d */\n", \
+ e->n->fn->name, e->n->ln); }
+#define tr_map(m, e) { if (!merger) fprintf(tt, "\t\ttr_2_src(%d, %s, %d);\n", \
+ m, e->n->fn->name, e->n->ln); }
+
+extern ProcList *rdy;
+extern RunList *run;
+extern Symbol *Fname, *oFname, *context;
+extern char *claimproc, *eventmap;
+extern int lineno, verbose, Npars, Mpars;
+extern int m_loss, has_remote, has_remvar, merger, rvopt, separate;
+extern int Ntimeouts, Etimeouts, deadvar;
+extern int u_sync, u_async, nrRdy;
+extern int GenCode, IsGuard, Level, TestOnly;
+extern short has_stack;
+extern char *NextLab[];
+
+FILE *tc, *th, *tt, *tm, *tb;
+
+int OkBreak = -1;
+short nocast=0; /* to turn off casts in lvalues */
+short terse=0; /* terse printing of varnames */
+short no_arrays=0;
+short has_last=0; /* spec refers to _last */
+short has_badelse=0; /* spec contains else combined with chan refs */
+short has_enabled=0; /* spec contains enabled() */
+short has_pcvalue=0; /* spec contains pc_value() */
+short has_np=0; /* spec contains np_ */
+short has_sorted=0; /* spec contains `!!' (sorted-send) operator */
+short has_random=0; /* spec contains `??' (random-recv) operator */
+short has_xu=0; /* spec contains xr or xs assertions */
+short has_unless=0; /* spec contains unless statements */
+short has_provided=0; /* spec contains PROVIDED clauses on procs */
+short has_code=0; /* spec contains c_code, c_expr, c_state */
+short _isok=0; /* checks usage of predefined variable _ */
+short evalindex=0; /* evaluate index of var names */
+short withprocname=0; /* prefix local varnames with procname */
+int mst=0; /* max nr of state/process */
+int claimnr = -1; /* claim process, if any */
+int eventmapnr = -1; /* event trace, if any */
+int Pid; /* proc currently processed */
+int multi_oval; /* set in merges, used also in pangen4.c */
+
+#define MAXMERGE 256 /* max nr of bups per merge sequence */
+
+static short CnT[MAXMERGE];
+static Lextok XZ, YZ[MAXMERGE];
+static int didcase, YZmax, YZcnt;
+
+static Lextok *Nn[2];
+static int Det; /* set if deterministic */
+static int T_sum, T_mus, t_cyc;
+static int TPE[2], EPT[2];
+static int uniq=1;
+static int multi_needed, multi_undo;
+static short AllGlobal=0; /* set if process has provided clause */
+
+int has_global(Lextok *);
+static int getweight(Lextok *);
+static int scan_seq(Sequence *);
+static void genconditionals(void);
+static void mark_seq(Sequence *);
+static void patch_atomic(Sequence *);
+static void put_seq(Sequence *, int, int);
+static void putproc(ProcList *);
+static void Tpe(Lextok *);
+extern void spit_recvs(FILE *, FILE*);
+
+static int
+fproc(char *s)
+{ ProcList *p;
+
+ for (p = rdy; p; p = p->nxt)
+ if (strcmp(p->n->name, s) == 0)
+ return p->tn;
+
+ fatal("proctype %s not found", s);
+ return -1;
+}
+
+static void
+reverse_procs(RunList *q)
+{
+ if (!q) return;
+ reverse_procs(q->nxt);
+ fprintf(tc, " Addproc(%d);\n", q->tn);
+}
+
+static void
+tm_predef_np(void)
+{
+ fprintf(th, "#define _T5 %d\n", uniq++);
+ fprintf(th, "#define _T2 %d\n", uniq++);
+ fprintf(tm, "\tcase _T5:\t/* np_ */\n");
+
+ if (separate == 2)
+ fprintf(tm, "\t\tif (!((!(o_pm&4) && !(tau&128))))\n");
+ else
+ fprintf(tm, "\t\tif (!((!(trpt->o_pm&4) && !(trpt->tau&128))))\n");
+
+ fprintf(tm, "\t\t\tcontinue;\n");
+ fprintf(tm, "\t\t/* else fall through */\n");
+ fprintf(tm, "\tcase _T2:\t/* true */\n");
+ fprintf(tm, "\t\t_m = 3; goto P999;\n");
+}
+
+static void
+tt_predef_np(void)
+{
+ fprintf(tt, "\t/* np_ demon: */\n");
+ fprintf(tt, "\ttrans[_NP_] = ");
+ fprintf(tt, "(Trans **) emalloc(2*sizeof(Trans *));\n");
+ fprintf(tt, "\tT = trans[_NP_][0] = ");
+ fprintf(tt, "settr(9997,0,1,_T5,0,\"(np_)\", 1,2,0);\n");
+ fprintf(tt, "\t T->nxt = ");
+ fprintf(tt, "settr(9998,0,0,_T2,0,\"(1)\", 0,2,0);\n");
+ fprintf(tt, "\tT = trans[_NP_][1] = ");
+ fprintf(tt, "settr(9999,0,1,_T5,0,\"(np_)\", 1,2,0);\n");
+}
+
+static struct {
+ char *nm[3];
+} Cfile[] = {
+ { { "pan.c", "pan_s.c", "pan_t.c" } },
+ { { "pan.h", "pan_s.h", "pan_t.h" } },
+ { { "pan.t", "pan_s.t", "pan_t.t" } },
+ { { "pan.m", "pan_s.m", "pan_t.m" } },
+ { { "pan.b", "pan_s.b", "pan_t.b" } }
+};
+
+void
+gensrc(void)
+{ ProcList *p;
+
+ if (!(tc = fopen(Cfile[0].nm[separate], "w")) /* main routines */
+ || !(th = fopen(Cfile[1].nm[separate], "w")) /* header file */
+ || !(tt = fopen(Cfile[2].nm[separate], "w")) /* transition matrix */
+ || !(tm = fopen(Cfile[3].nm[separate], "w")) /* forward moves */
+ || !(tb = fopen(Cfile[4].nm[separate], "w"))) /* backward moves */
+ { printf("spin: cannot create pan.[chtmfb]\n");
+ alldone(1);
+ }
+
+ fprintf(th, "#define Version \"%s\"\n", Version);
+ fprintf(th, "#define Source \"%s\"\n\n", oFname->name);
+ if (separate != 2)
+ fprintf(th, "char *TrailFile = Source; /* default */\n");
+
+ fprintf(th, "#if defined(BFS)\n");
+ fprintf(th, "#ifndef SAFETY\n");
+ fprintf(th, "#define SAFETY\n");
+ fprintf(th, "#endif\n");
+ fprintf(th, "#ifndef XUSAFE\n");
+ fprintf(th, "#define XUSAFE\n");
+ fprintf(th, "#endif\n");
+ fprintf(th, "#endif\n");
+
+ fprintf(th, "#ifndef uchar\n");
+ fprintf(th, "#define uchar unsigned char\n");
+ fprintf(th, "#endif\n");
+ fprintf(th, "#ifndef uint\n");
+ fprintf(th, "#define uint unsigned int\n");
+ fprintf(th, "#endif\n");
+
+ if (sizeof(void *) > 4) /* 64 bit machine */
+ { fprintf(th, "#ifndef HASH32\n");
+ fprintf(th, "#define HASH64\n");
+ fprintf(th, "#endif\n");
+ }
+#if 0
+ if (sizeof(long)==sizeof(int))
+ fprintf(th, "#define long int\n");
+#endif
+ if (separate == 1 && !claimproc)
+ { Symbol *n = (Symbol *) emalloc(sizeof(Symbol));
+ Sequence *s = (Sequence *) emalloc(sizeof(Sequence));
+ claimproc = n->name = "_:never_template:_";
+ ready(n, ZN, s, 0, ZN);
+ }
+ if (separate == 2)
+ { if (has_remote)
+ { printf("spin: warning, make sure that the S1 model\n");
+ printf(" includes the same remote references\n");
+ }
+ fprintf(th, "#ifndef NFAIR\n");
+ fprintf(th, "#define NFAIR 2 /* must be >= 2 */\n");
+ fprintf(th, "#endif\n");
+ if (has_last)
+ fprintf(th, "#define HAS_LAST %d\n", has_last);
+ goto doless;
+ }
+
+ fprintf(th, "#define DELTA %d\n", DELTA);
+ fprintf(th, "#ifdef MA\n");
+ fprintf(th, "#if MA==1\n"); /* user typed -DMA without size */
+ fprintf(th, "#undef MA\n#define MA 100\n");
+ fprintf(th, "#endif\n#endif\n");
+ fprintf(th, "#ifdef W_XPT\n");
+ fprintf(th, "#if W_XPT==1\n"); /* user typed -DW_XPT without size */
+ fprintf(th, "#undef W_XPT\n#define W_XPT 1000000\n");
+ fprintf(th, "#endif\n#endif\n");
+ fprintf(th, "#ifndef NFAIR\n");
+ fprintf(th, "#define NFAIR 2 /* must be >= 2 */\n");
+ fprintf(th, "#endif\n");
+ if (Ntimeouts)
+ fprintf(th, "#define NTIM %d\n", Ntimeouts);
+ if (Etimeouts)
+ fprintf(th, "#define ETIM %d\n", Etimeouts);
+ if (has_remvar)
+ fprintf(th, "#define REM_VARS 1\n");
+ if (has_remote)
+ fprintf(th, "#define REM_REFS %d\n", has_remote); /* not yet used */
+ if (has_last)
+ fprintf(th, "#define HAS_LAST %d\n", has_last);
+ if (has_sorted)
+ fprintf(th, "#define HAS_SORTED %d\n", has_sorted);
+ if (m_loss)
+ fprintf(th, "#define M_LOSS\n");
+ if (has_random)
+ fprintf(th, "#define HAS_RANDOM %d\n", has_random);
+ fprintf(th, "#define HAS_CODE\n"); /* doesn't seem to cause measurable overhead */
+ if (has_stack)
+ fprintf(th, "#define HAS_STACK\n");
+ if (has_enabled)
+ fprintf(th, "#define HAS_ENABLED 1\n");
+ if (has_unless)
+ fprintf(th, "#define HAS_UNLESS %d\n", has_unless);
+ if (has_provided)
+ fprintf(th, "#define HAS_PROVIDED %d\n", has_provided);
+ if (has_pcvalue)
+ fprintf(th, "#define HAS_PCVALUE %d\n", has_pcvalue);
+ if (has_badelse)
+ fprintf(th, "#define HAS_BADELSE %d\n", has_badelse);
+ if (has_enabled
+ || has_pcvalue
+ || has_badelse
+ || has_last)
+ { fprintf(th, "#ifndef NOREDUCE\n");
+ fprintf(th, "#define NOREDUCE 1\n");
+ fprintf(th, "#endif\n");
+ }
+ if (has_np)
+ fprintf(th, "#define HAS_NP %d\n", has_np);
+ if (merger)
+ fprintf(th, "#define MERGED 1\n");
+
+doless:
+ fprintf(th, "#ifdef NP /* includes np_ demon */\n");
+ if (!has_np)
+ fprintf(th, "#define HAS_NP 2\n");
+ fprintf(th, "#define VERI %d\n", nrRdy);
+ fprintf(th, "#define endclaim 3 /* none */\n");
+ fprintf(th, "#endif\n");
+ if (claimproc)
+ { claimnr = fproc(claimproc);
+ /* NP overrides claimproc */
+ fprintf(th, "#if !defined(NOCLAIM) && !defined NP\n");
+ fprintf(th, "#define VERI %d\n", claimnr);
+ fprintf(th, "#define endclaim endstate%d\n", claimnr);
+ fprintf(th, "#endif\n");
+ }
+ if (eventmap)
+ { eventmapnr = fproc(eventmap);
+ fprintf(th, "#define EVENT_TRACE %d\n", eventmapnr);
+ fprintf(th, "#define endevent endstate%d\n", eventmapnr);
+ if (eventmap[2] == 'o') /* ":notrace:" */
+ fprintf(th, "#define NEGATED_TRACE 1\n");
+ }
+
+ fprintf(th, "typedef struct S_F_MAP {\n");
+ fprintf(th, " char *fnm; int from; int upto;\n");
+ fprintf(th, "} S_F_MAP;\n");
+
+ fprintf(tc, "/*** Generated by %s ***/\n", Version);
+ fprintf(tc, "/*** From source: %s ***/\n\n", oFname->name);
+
+ ntimes(tc, 0, 1, Pre0);
+
+ plunk_c_decls(tc); /* types can be refered to in State */
+
+ switch (separate) {
+ case 0: fprintf(tc, "#include \"pan.h\"\n"); break;
+ case 1: fprintf(tc, "#include \"pan_s.h\"\n"); break;
+ case 2: fprintf(tc, "#include \"pan_t.h\"\n"); break;
+ }
+
+ fprintf(tc, "State A_Root; /* seed-state for cycles */\n");
+ fprintf(tc, "State now; /* the full state-vector */\n");
+ plunk_c_fcts(tc); /* State can be used in fcts */
+
+ if (separate != 2)
+ ntimes(tc, 0, 1, Preamble);
+ else
+ fprintf(tc, "extern int verbose; extern long depth;\n");
+
+ fprintf(tc, "#ifndef NOBOUNDCHECK\n");
+ fprintf(tc, "#define Index(x, y)\tBoundcheck(x, y, II, tt, t)\n");
+ fprintf(tc, "#else\n");
+ fprintf(tc, "#define Index(x, y)\tx\n");
+ fprintf(tc, "#endif\n");
+
+ c_preview(); /* sets hastrack */
+
+ for (p = rdy; p; p = p->nxt)
+ mst = max(p->s->maxel, mst);
+
+ if (separate != 2)
+ { fprintf(tt, "#ifdef PEG\n");
+ fprintf(tt, "struct T_SRC {\n");
+ fprintf(tt, " char *fl; int ln;\n");
+ fprintf(tt, "} T_SRC[NTRANS];\n\n");
+ fprintf(tt, "void\ntr_2_src(int m, char *file, int ln)\n");
+ fprintf(tt, "{ T_SRC[m].fl = file;\n");
+ fprintf(tt, " T_SRC[m].ln = ln;\n");
+ fprintf(tt, "}\n\n");
+ fprintf(tt, "void\nputpeg(int n, int m)\n");
+ fprintf(tt, "{ printf(\"%%5d\ttrans %%4d \", m, n);\n");
+ fprintf(tt, " printf(\"file %%s line %%3d\\n\",\n");
+ fprintf(tt, " T_SRC[n].fl, T_SRC[n].ln);\n");
+ fprintf(tt, "}\n");
+ if (!merger)
+ { fprintf(tt, "#else\n");
+ fprintf(tt, "#define tr_2_src(m,f,l)\n");
+ }
+ fprintf(tt, "#endif\n\n");
+ fprintf(tt, "void\nsettable(void)\n{\tTrans *T;\n");
+ fprintf(tt, "\tTrans *settr(int, int, int, int, int,");
+ fprintf(tt, " char *, int, int, int);\n\n");
+ fprintf(tt, "\ttrans = (Trans ***) ");
+ fprintf(tt, "emalloc(%d*sizeof(Trans **));\n", nrRdy+1);
+ /* +1 for np_ automaton */
+
+ if (separate == 1)
+ {
+ fprintf(tm, " if (II == 0)\n");
+ fprintf(tm, " { _m = step_claim(trpt->o_pm, trpt->tau, tt, ot, t);\n");
+ fprintf(tm, " if (_m) goto P999; else continue;\n");
+ fprintf(tm, " } else\n");
+ }
+
+ fprintf(tm, "#define rand pan_rand\n");
+ fprintf(tm, "#if defined(HAS_CODE) && defined(VERBOSE)\n");
+ fprintf(tm, " printf(\"Pr: %%d Tr: %%d\\n\", II, t->forw);\n");
+ fprintf(tm, "#endif\n");
+ fprintf(tm, " switch (t->forw) {\n");
+ } else
+ { fprintf(tt, "#ifndef PEG\n");
+ fprintf(tt, "#define tr_2_src(m,f,l)\n");
+ fprintf(tt, "#endif\n");
+ fprintf(tt, "void\nset_claim(void)\n{\tTrans *T;\n");
+ fprintf(tt, "\textern Trans ***trans;\n");
+ fprintf(tt, "\textern Trans *settr(int, int, int, int, int,");
+ fprintf(tt, " char *, int, int, int);\n\n");
+
+ fprintf(tm, "#define rand pan_rand\n");
+ fprintf(tm, "#if defined(HAS_CODE) && defined(VERBOSE)\n");
+ fprintf(tm, " printf(\"Pr: %%d Tr: %%d\\n\", II, forw);\n");
+ fprintf(tm, "#endif\n");
+ fprintf(tm, " switch (forw) {\n");
+ }
+
+ fprintf(tm, " default: Uerror(\"bad forward move\");\n");
+ fprintf(tm, " case 0: /* if without executable clauses */\n");
+ fprintf(tm, " continue;\n");
+ fprintf(tm, " case 1: /* generic 'goto' or 'skip' */\n");
+ if (separate != 2)
+ fprintf(tm, " IfNotBlocked\n");
+ fprintf(tm, " _m = 3; goto P999;\n");
+ fprintf(tm, " case 2: /* generic 'else' */\n");
+ if (separate == 2)
+ fprintf(tm, " if (o_pm&1) continue;\n");
+ else
+ { fprintf(tm, " IfNotBlocked\n");
+ fprintf(tm, " if (trpt->o_pm&1) continue;\n");
+ }
+ fprintf(tm, " _m = 3; goto P999;\n");
+ uniq = 3;
+
+ if (separate == 1)
+ fprintf(tb, " if (II == 0) goto R999;\n");
+
+ fprintf(tb, " switch (t->back) {\n");
+ fprintf(tb, " default: Uerror(\"bad return move\");\n");
+ fprintf(tb, " case 0: goto R999; /* nothing to undo */\n");
+
+ for (p = rdy; p; p = p->nxt)
+ putproc(p);
+
+
+ if (separate != 2)
+ { fprintf(th, "struct {\n");
+ fprintf(th, " int tp; short *src;\n");
+ fprintf(th, "} src_all[] = {\n");
+ for (p = rdy; p; p = p->nxt)
+ fprintf(th, " { %d, &src_ln%d[0] },\n",
+ p->tn, p->tn);
+ fprintf(th, " { 0, (short *) 0 }\n");
+ fprintf(th, "};\n");
+ fprintf(th, "short *frm_st0;\n"); /* records src states for transitions in never claim */
+ } else
+ { fprintf(th, "extern short *frm_st0;\n");
+ }
+
+ gencodetable(th);
+
+ if (separate != 1)
+ { tm_predef_np();
+ tt_predef_np();
+ }
+ fprintf(tt, "}\n\n"); /* end of settable() */
+
+ fprintf(tm, "#undef rand\n");
+ fprintf(tm, " }\n\n");
+ fprintf(tb, " }\n\n");
+
+ if (separate != 2)
+ { ntimes(tt, 0, 1, Tail);
+ genheader();
+ if (separate == 1)
+ { fprintf(th, "#define FORWARD_MOVES\t\"pan_s.m\"\n");
+ fprintf(th, "#define REVERSE_MOVES\t\"pan_s.b\"\n");
+ fprintf(th, "#define SEPARATE\n");
+ fprintf(th, "#define TRANSITIONS\t\"pan_s.t\"\n");
+ fprintf(th, "extern void ini_claim(int, int);\n");
+ } else
+ { fprintf(th, "#define FORWARD_MOVES\t\"pan.m\"\n");
+ fprintf(th, "#define REVERSE_MOVES\t\"pan.b\"\n");
+ fprintf(th, "#define TRANSITIONS\t\"pan.t\"\n");
+ }
+ genaddproc();
+ genother();
+ genaddqueue();
+ genunio();
+ genconditionals();
+ gensvmap();
+ if (!run) fatal("no runable process", (char *)0);
+ fprintf(tc, "void\n");
+ fprintf(tc, "active_procs(void)\n{\n");
+ reverse_procs(run);
+ fprintf(tc, "}\n");
+ ntimes(tc, 0, 1, Dfa);
+ ntimes(tc, 0, 1, Xpt);
+
+ fprintf(th, "#define NTRANS %d\n", uniq);
+ fprintf(th, "#ifdef PEG\n");
+ fprintf(th, "long peg[NTRANS];\n");
+ fprintf(th, "#endif\n");
+
+ if (u_sync && !u_async)
+ spit_recvs(th, tc);
+ } else
+ { genheader();
+ fprintf(th, "#define FORWARD_MOVES\t\"pan_t.m\"\n");
+ fprintf(th, "#define REVERSE_MOVES\t\"pan_t.b\"\n");
+ fprintf(th, "#define TRANSITIONS\t\"pan_t.t\"\n");
+ fprintf(tc, "extern int Maxbody;\n");
+ fprintf(tc, "#if VECTORSZ>32000\n");
+ fprintf(tc, "extern int proc_offset[];\n");
+ fprintf(tc, "#else\n");
+ fprintf(tc, "extern short proc_offset[];\n");
+ fprintf(tc, "#endif\n");
+ fprintf(tc, "extern uchar proc_skip[];\n");
+ fprintf(tc, "extern uchar *reached[];\n");
+ fprintf(tc, "extern uchar *accpstate[];\n");
+ fprintf(tc, "extern uchar *progstate[];\n");
+ fprintf(tc, "extern uchar *stopstate[];\n");
+ fprintf(tc, "extern uchar *visstate[];\n\n");
+ fprintf(tc, "extern short *mapstate[];\n");
+
+ fprintf(tc, "void\nini_claim(int n, int h)\n{");
+ fprintf(tc, "\textern State now;\n");
+ fprintf(tc, "\textern void set_claim(void);\n\n");
+ fprintf(tc, "#ifdef PROV\n");
+ fprintf(tc, "#include PROV\n");
+ fprintf(tc, "#endif\n");
+ fprintf(tc, "\tset_claim();\n");
+ genother();
+ fprintf(tc, "\n\tswitch (n) {\n");
+ genaddproc();
+ fprintf(tc, "\t}\n");
+ fprintf(tc, "\n}\n");
+ fprintf(tc, "int\nstep_claim(int o_pm, int tau, int tt, int ot, Trans *t)\n");
+ fprintf(tc, "{ int forw = t->forw; int _m = 0; extern char *noptr; int II=0;\n");
+ fprintf(tc, " extern State now;\n");
+ fprintf(tc, "#define continue return 0\n");
+ fprintf(tc, "#include \"pan_t.m\"\n");
+ fprintf(tc, "P999:\n\treturn _m;\n}\n");
+ fprintf(tc, "#undef continue\n");
+ fprintf(tc, "int\nrev_claim(int backw)\n{ return 0; }\n");
+ fprintf(tc, "#include TRANSITIONS\n");
+ }
+ if (separate != 1)
+ ntimes(tc, 0, 1, Nvr1);
+
+ if (separate != 2)
+ { c_wrapper(tc);
+ c_chandump(tc);
+ }
+}
+
+static int
+find_id(Symbol *s)
+{ ProcList *p;
+
+ if (s)
+ for (p = rdy; p; p = p->nxt)
+ if (s == p->n)
+ return p->tn;
+ return 0;
+}
+
+static void
+dolen(Symbol *s, char *pre, int pid, int ai, int qln)
+{
+ if (ai > 0)
+ fprintf(tc, "\n\t\t\t || ");
+ fprintf(tc, "%s(", pre);
+ if (!(s->hidden&1))
+ { if (s->context)
+ fprintf(tc, "((P%d *)this)->", pid);
+ else
+ fprintf(tc, "now.");
+ }
+ fprintf(tc, "%s", s->name);
+ if (qln > 1) fprintf(tc, "[%d]", ai);
+ fprintf(tc, ")");
+}
+
+struct AA { char TT[9]; char CC[8]; };
+
+static struct AA BB[4] = {
+ { "Q_FULL_F", " q_full" },
+ { "Q_FULL_T", "!q_full" },
+ { "Q_EMPT_F", " !q_len" },
+ { "Q_EMPT_T", " q_len" }
+ };
+
+static struct AA DD[4] = {
+ { "Q_FULL_F", " q_e_f" }, /* empty or full */
+ { "Q_FULL_T", "!q_full" },
+ { "Q_EMPT_F", " q_e_f" },
+ { "Q_EMPT_T", " q_len" }
+ };
+ /* this reduces the number of cases where 's' and 'r'
+ are considered conditionally safe under the
+ partial order reduction rules; as a price for
+ this simple implementation, it also affects the
+ cases where nfull and nempty can be considered
+ safe -- since these are labeled the same way as
+ 's' and 'r' respectively
+ it only affects reduction, not functionality
+ */
+
+void
+bb_or_dd(int j, int which)
+{
+ if (which)
+ { if (has_unless)
+ fprintf(tc, "%s", DD[j].CC);
+ else
+ fprintf(tc, "%s", BB[j].CC);
+ } else
+ { if (has_unless)
+ fprintf(tc, "%s", DD[j].TT);
+ else
+ fprintf(tc, "%s", BB[j].TT);
+ }
+}
+
+void
+Done_case(char *nm, Symbol *z)
+{ int j, k;
+ int nid = z->Nid;
+ int qln = z->nel;
+
+ fprintf(tc, "\t\tcase %d: if (", nid);
+ for (j = 0; j < 4; j++)
+ { fprintf(tc, "\t(t->ty[i] == ");
+ bb_or_dd(j, 0);
+ fprintf(tc, " && (");
+ for (k = 0; k < qln; k++)
+ { if (k > 0)
+ fprintf(tc, "\n\t\t\t || ");
+ bb_or_dd(j, 1);
+ fprintf(tc, "(%s%s", nm, z->name);
+ if (qln > 1)
+ fprintf(tc, "[%d]", k);
+ fprintf(tc, ")");
+ }
+ fprintf(tc, "))\n\t\t\t ");
+ if (j < 3)
+ fprintf(tc, "|| ");
+ else
+ fprintf(tc, " ");
+ }
+ fprintf(tc, ") return 0; break;\n");
+}
+
+static void
+Docase(Symbol *s, int pid, int nid)
+{ int i, j;
+
+ fprintf(tc, "\t\tcase %d: if (", nid);
+ for (j = 0; j < 4; j++)
+ { fprintf(tc, "\t(t->ty[i] == ");
+ bb_or_dd(j, 0);
+ fprintf(tc, " && (");
+ if (has_unless)
+ { for (i = 0; i < s->nel; i++)
+ dolen(s, DD[j].CC, pid, i, s->nel);
+ } else
+ { for (i = 0; i < s->nel; i++)
+ dolen(s, BB[j].CC, pid, i, s->nel);
+ }
+ fprintf(tc, "))\n\t\t\t ");
+ if (j < 3)
+ fprintf(tc, "|| ");
+ else
+ fprintf(tc, " ");
+ }
+ fprintf(tc, ") return 0; break;\n");
+}
+
+static void
+genconditionals(void)
+{ Symbol *s;
+ int last=0, j;
+ extern Ordered *all_names;
+ Ordered *walk;
+
+ fprintf(th, "#define LOCAL 1\n");
+ fprintf(th, "#define Q_FULL_F 2\n");
+ fprintf(th, "#define Q_EMPT_F 3\n");
+ fprintf(th, "#define Q_EMPT_T 4\n");
+ fprintf(th, "#define Q_FULL_T 5\n");
+ fprintf(th, "#define TIMEOUT_F 6\n");
+ fprintf(th, "#define GLOBAL 7\n");
+ fprintf(th, "#define BAD 8\n");
+ fprintf(th, "#define ALPHA_F 9\n");
+
+ fprintf(tc, "int\n");
+ fprintf(tc, "q_cond(short II, Trans *t)\n");
+ fprintf(tc, "{ int i = 0;\n");
+ fprintf(tc, " for (i = 0; i < 6; i++)\n");
+ fprintf(tc, " { if (t->ty[i] == TIMEOUT_F) return %s;\n",
+ (Etimeouts)?"(!(trpt->tau&1))":"1");
+ fprintf(tc, " if (t->ty[i] == ALPHA_F)\n");
+ fprintf(tc, "#ifdef GLOB_ALPHA\n");
+ fprintf(tc, " return 0;\n");
+ fprintf(tc, "#else\n\t\t\treturn ");
+ fprintf(tc, "(II+1 == (short) now._nr_pr && II+1 < MAXPROC);\n");
+ fprintf(tc, "#endif\n");
+
+ /* we switch on the chan name from the spec (as identified by
+ * the corresponding Nid number) rather than the actual qid
+ * because we cannot predict at compile time which specific qid
+ * will be accessed by the statement at runtime. that is:
+ * we do not know which qid to pass to q_cond at runtime
+ * but we do know which name is used. if it's a chan array, we
+ * must check all elements of the array for compliance (bummer)
+ */
+ fprintf(tc, " switch (t->qu[i]) {\n");
+ fprintf(tc, " case 0: break;\n");
+
+ for (walk = all_names; walk; walk = walk->next)
+ { s = walk->entry;
+ if (s->owner) continue;
+ j = find_id(s->context);
+ if (s->type == CHAN)
+ { if (last == s->Nid) continue; /* chan array */
+ last = s->Nid;
+ Docase(s, j, last);
+ } else if (s->type == STRUCT)
+ { /* struct may contain a chan */
+ char pregat[128];
+ extern void walk2_struct(char *, Symbol *);
+ strcpy(pregat, "");
+ if (!(s->hidden&1))
+ { if (s->context)
+ sprintf(pregat, "((P%d *)this)->",j);
+ else
+ sprintf(pregat, "now.");
+ }
+ walk2_struct(pregat, s);
+ }
+ }
+ fprintf(tc, " \tdefault: Uerror(\"unknown qid - q_cond\");\n");
+ fprintf(tc, " \t\t\treturn 0;\n");
+ fprintf(tc, " \t}\n");
+ fprintf(tc, " }\n");
+ fprintf(tc, " return 1;\n");
+ fprintf(tc, "}\n");
+}
+
+static void
+putproc(ProcList *p)
+{ Pid = p->tn;
+ Det = p->det;
+
+ if (Pid == claimnr
+ && separate == 1)
+ { fprintf(th, "extern uchar reached%d[];\n", Pid);
+#if 0
+ fprintf(th, "extern short nstates%d;\n", Pid);
+#else
+ fprintf(th, "\n#define nstates%d %d\t/* %s */\n",
+ Pid, p->s->maxel, p->n->name);
+#endif
+ fprintf(th, "extern short src_ln%d[];\n", Pid);
+ fprintf(th, "extern S_F_MAP src_file%d[];\n", Pid);
+ fprintf(th, "#define endstate%d %d\n",
+ Pid, p->s->last?p->s->last->seqno:0);
+ fprintf(th, "#define src_claim src_ln%d\n", claimnr);
+
+ return;
+ }
+ if (Pid != claimnr
+ && separate == 2)
+ { fprintf(th, "extern short src_ln%d[];\n", Pid);
+ return;
+ }
+
+ AllGlobal = (p->prov)?1:0; /* process has provided clause */
+
+ fprintf(th, "\n#define nstates%d %d\t/* %s */\n",
+ Pid, p->s->maxel, p->n->name);
+ if (Pid == claimnr)
+ fprintf(th, "#define nstates_claim nstates%d\n", Pid);
+ if (Pid == eventmapnr)
+ fprintf(th, "#define nstates_event nstates%d\n", Pid);
+
+ fprintf(th, "#define endstate%d %d\n",
+ Pid, p->s->last->seqno);
+ fprintf(tm, "\n /* PROC %s */\n", p->n->name);
+ fprintf(tb, "\n /* PROC %s */\n", p->n->name);
+ fprintf(tt, "\n /* proctype %d: %s */\n", Pid, p->n->name);
+ fprintf(tt, "\n trans[%d] = (Trans **)", Pid);
+ fprintf(tt, " emalloc(%d*sizeof(Trans *));\n\n", p->s->maxel);
+
+ if (Pid == eventmapnr)
+ { fprintf(th, "\n#define in_s_scope(x_y3_) 0");
+ fprintf(tc, "\n#define in_r_scope(x_y3_) 0");
+ }
+
+ put_seq(p->s, 2, 0);
+ if (Pid == eventmapnr)
+ { fprintf(th, "\n\n");
+ fprintf(tc, "\n\n");
+ }
+ dumpsrc(p->s->maxel, Pid);
+}
+
+static void
+addTpe(int x)
+{ int i;
+
+ if (x <= 2) return;
+
+ for (i = 0; i < T_sum; i++)
+ if (TPE[i] == x)
+ return;
+ TPE[(T_sum++)%2] = x;
+}
+
+static void
+cnt_seq(Sequence *s)
+{ Element *f;
+ SeqList *h;
+
+ if (s)
+ for (f = s->frst; f; f = f->nxt)
+ { Tpe(f->n); /* sets EPT */
+ addTpe(EPT[0]);
+ addTpe(EPT[1]);
+ for (h = f->sub; h; h = h->nxt)
+ cnt_seq(h->this);
+ if (f == s->last)
+ break;
+ }
+}
+
+static void
+typ_seq(Sequence *s)
+{
+ T_sum = 0;
+ TPE[0] = 2; TPE[1] = 0;
+ cnt_seq(s);
+ if (T_sum > 2) /* more than one type */
+ { TPE[0] = 5*DELTA; /* non-mixing */
+ TPE[1] = 0;
+ }
+}
+
+static int
+hidden(Lextok *n)
+{
+ if (n)
+ switch (n->ntyp) {
+ case FULL: case EMPTY:
+ case NFULL: case NEMPTY: case TIMEOUT:
+ Nn[(T_mus++)%2] = n;
+ break;
+ case '!': case UMIN: case '~': case ASSERT: case 'c':
+ (void) hidden(n->lft);
+ break;
+ case '/': case '*': case '-': case '+':
+ case '%': case LT: case GT: case '&': case '^':
+ case '|': case LE: case GE: case NE: case '?':
+ case EQ: case OR: case AND: case LSHIFT: case RSHIFT:
+ (void) hidden(n->lft);
+ (void) hidden(n->rgt);
+ break;
+ }
+ return T_mus;
+}
+
+static int
+getNid(Lextok *n)
+{
+ if (n->sym
+ && n->sym->type == STRUCT
+ && n->rgt && n->rgt->lft)
+ return getNid(n->rgt->lft);
+
+ if (!n->sym || n->sym->Nid == 0)
+ { fatal("bad channel name '%s'",
+ (n->sym)?n->sym->name:"no name");
+ }
+ return n->sym->Nid;
+}
+
+static int
+valTpe(Lextok *n)
+{ int res = 2;
+ /*
+ 2 = local
+ 2+1 .. 2+1*DELTA = nfull, 's' - require q_full==false
+ 2+1+1*DELTA .. 2+2*DELTA = nempty, 'r' - require q_len!=0
+ 2+1+2*DELTA .. 2+3*DELTA = empty - require q_len==0
+ 2+1+3*DELTA .. 2+4*DELTA = full - require q_full==true
+ 5*DELTA = non-mixing (i.e., always makes the selection global)
+ 6*DELTA = timeout (conditionally safe)
+ 7*DELTA = @, process deletion (conditionally safe)
+ */
+ switch (n->ntyp) { /* a series of fall-thru cases: */
+ case FULL: res += DELTA; /* add 3*DELTA + chan nr */
+ case EMPTY: res += DELTA; /* add 2*DELTA + chan nr */
+ case 'r':
+ case NEMPTY: res += DELTA; /* add 1*DELTA + chan nr */
+ case 's':
+ case NFULL: res += getNid(n->lft); /* add channel nr */
+ break;
+
+ case TIMEOUT: res = 6*DELTA; break;
+ case '@': res = 7*DELTA; break;
+ default: break;
+ }
+ return res;
+}
+
+static void
+Tpe(Lextok *n) /* mixing in selections */
+{
+ EPT[0] = 2; EPT[1] = 0;
+
+ if (!n) return;
+
+ T_mus = 0;
+ Nn[0] = Nn[1] = ZN;
+
+ if (n->ntyp == 'c')
+ { if (hidden(n->lft) > 2)
+ { EPT[0] = 5*DELTA; /* non-mixing */
+ EPT[1] = 0;
+ return;
+ }
+ } else
+ Nn[0] = n;
+
+ if (Nn[0]) EPT[0] = valTpe(Nn[0]);
+ if (Nn[1]) EPT[1] = valTpe(Nn[1]);
+}
+
+static void
+put_escp(Element *e)
+{ int n;
+ SeqList *x;
+
+ if (e->esc /* && e->n->ntyp != GOTO */ && e->n->ntyp != '.')
+ { for (x = e->esc, n = 0; x; x = x->nxt, n++)
+ { int i = huntele(x->this->frst, e->status, -1)->seqno;
+ fprintf(tt, "\ttrans[%d][%d]->escp[%d] = %d;\n",
+ Pid, e->seqno, n, i);
+ fprintf(tt, "\treached%d[%d] = 1;\n",
+ Pid, i);
+ }
+ for (x = e->esc, n=0; x; x = x->nxt, n++)
+ { fprintf(tt, " /* escape #%d: %d */\n", n,
+ huntele(x->this->frst, e->status, -1)->seqno);
+ put_seq(x->this, 2, 0); /* args?? */
+ }
+ fprintf(tt, " /* end-escapes */\n");
+ }
+}
+
+static void
+put_sub(Element *e, int Tt0, int Tt1)
+{ Sequence *s = e->n->sl->this;
+ Element *g = ZE;
+ int a;
+
+ patch_atomic(s);
+ putskip(s->frst->seqno);
+ g = huntstart(s->frst);
+ a = g->seqno;
+
+ if (0) printf("put_sub %d -> %d -> %d\n", e->seqno, s->frst->seqno, a);
+
+ if ((e->n->ntyp == ATOMIC
+ || e->n->ntyp == D_STEP)
+ && scan_seq(s))
+ mark_seq(s);
+ s->last->nxt = e->nxt;
+
+ typ_seq(s); /* sets TPE */
+
+ if (e->n->ntyp == D_STEP)
+ { int inherit = (e->status&(ATOM|L_ATOM));
+ fprintf(tm, "\tcase %d: ", uniq++);
+ fprintf(tm, "/* STATE %d - line %d %s - [",
+ e->seqno, e->n->ln, e->n->fn->name);
+ comment(tm, e->n, 0);
+ fprintf(tm, "] */\n\t\t");
+
+ if (s->last->n->ntyp == BREAK)
+ OkBreak = target(huntele(s->last->nxt,
+ s->last->status, -1))->Seqno;
+ else
+ OkBreak = -1;
+
+ if (!putcode(tm, s, e->nxt, 0, e->n->ln, e->seqno))
+ {
+ fprintf(tm, "\n#if defined(C_States) && (HAS_TRACK==1)\n");
+ fprintf(tm, "\t\tc_update((uchar *) &(now.c_state[0]));\n");
+ fprintf(tm, "#endif\n");
+
+ fprintf(tm, "\t\t_m = %d", getweight(s->frst->n));
+ if (m_loss && s->frst->n->ntyp == 's')
+ fprintf(tm, "+delta_m; delta_m = 0");
+ fprintf(tm, "; goto P999;\n\n");
+ }
+
+ fprintf(tb, "\tcase %d: ", uniq-1);
+ fprintf(tb, "/* STATE %d */\n", e->seqno);
+ fprintf(tb, "\t\tsv_restor();\n");
+ fprintf(tb, "\t\tgoto R999;\n");
+ if (e->nxt)
+ a = huntele(e->nxt, e->status, -1)->seqno;
+ else
+ a = 0;
+ tr_map(uniq-1, e);
+ fprintf(tt, "/*->*/\ttrans[%d][%d]\t= ",
+ Pid, e->seqno);
+ fprintf(tt, "settr(%d,%d,%d,%d,%d,\"",
+ e->Seqno, D_ATOM|inherit, a, uniq-1, uniq-1);
+ comment(tt, e->n, e->seqno);
+ fprintf(tt, "\", %d, ", (s->frst->status&I_GLOB)?1:0);
+ fprintf(tt, "%d, %d);\n", TPE[0], TPE[1]);
+ put_escp(e);
+ } else
+ { /* ATOMIC or NON_ATOMIC */
+ fprintf(tt, "\tT = trans[ %d][%d] = ", Pid, e->seqno);
+ fprintf(tt, "settr(%d,%d,0,0,0,\"",
+ e->Seqno, (e->n->ntyp == ATOMIC)?ATOM:0);
+ comment(tt, e->n, e->seqno);
+ if ((e->status&CHECK2)
+ || (g->status&CHECK2))
+ s->frst->status |= I_GLOB;
+ fprintf(tt, "\", %d, %d, %d);",
+ (s->frst->status&I_GLOB)?1:0, Tt0, Tt1);
+ blurb(tt, e);
+ fprintf(tt, "\tT->nxt\t= ");
+ fprintf(tt, "settr(%d,%d,%d,0,0,\"",
+ e->Seqno, (e->n->ntyp == ATOMIC)?ATOM:0, a);
+ comment(tt, e->n, e->seqno);
+ fprintf(tt, "\", %d, ", (s->frst->status&I_GLOB)?1:0);
+ if (e->n->ntyp == NON_ATOMIC)
+ { fprintf(tt, "%d, %d);", Tt0, Tt1);
+ blurb(tt, e);
+ put_seq(s, Tt0, Tt1);
+ } else
+ { fprintf(tt, "%d, %d);", TPE[0], TPE[1]);
+ blurb(tt, e);
+ put_seq(s, TPE[0], TPE[1]);
+ }
+ }
+}
+
+typedef struct CaseCache {
+ int m, b, owner;
+ Element *e;
+ Lextok *n;
+ FSM_use *u;
+ struct CaseCache *nxt;
+} CaseCache;
+
+CaseCache *casing[6];
+
+static int
+identical(Lextok *p, Lextok *q)
+{
+ if ((!p && q) || (p && !q))
+ return 0;
+ if (!p)
+ return 1;
+
+ if (p->ntyp != q->ntyp
+ || p->ismtyp != q->ismtyp
+ || p->val != q->val
+ || p->indstep != q->indstep
+ || p->sym != q->sym
+ || p->sq != q->sq
+ || p->sl != q->sl)
+ return 0;
+
+ return identical(p->lft, q->lft)
+ && identical(p->rgt, q->rgt);
+}
+
+static int
+samedeads(FSM_use *a, FSM_use *b)
+{ FSM_use *p, *q;
+
+ for (p = a, q = b; p && q; p = p->nxt, q = q->nxt)
+ if (p->var != q->var
+ || p->special != q->special)
+ return 0;
+ return (!p && !q);
+}
+
+static Element *
+findnext(Element *f)
+{ Element *g;
+
+ if (f->n->ntyp == GOTO)
+ { g = get_lab(f->n, 1);
+ return huntele(g, f->status, -1);
+ }
+ return f->nxt;
+}
+
+static Element *
+advance(Element *e, int stopat)
+{ Element *f = e;
+
+ if (stopat)
+ while (f && f->seqno != stopat)
+ { f = findnext(f);
+ switch (f->n->ntyp) {
+ case GOTO:
+ case '.':
+ case PRINT:
+ case PRINTM:
+ break;
+ default:
+ return f;
+ }
+ }
+ return (Element *) 0;
+}
+
+static int
+equiv_merges(Element *a, Element *b)
+{ Element *f, *g;
+ int stopat_a, stopat_b;
+
+ if (a->merge_start)
+ stopat_a = a->merge_start;
+ else
+ stopat_a = a->merge;
+
+ if (b->merge_start)
+ stopat_b = b->merge_start;
+ else
+ stopat_b = b->merge;
+
+ if (!stopat_a && !stopat_b)
+ return 1;
+
+ for (;;)
+ {
+ f = advance(a, stopat_a);
+ g = advance(b, stopat_b);
+ if (!f && !g)
+ return 1;
+ if (f && g)
+ return identical(f->n, g->n);
+ else
+ return 0;
+ }
+ return 1;
+}
+
+static CaseCache *
+prev_case(Element *e, int owner)
+{ int j; CaseCache *nc;
+
+ switch (e->n->ntyp) {
+ case 'r': j = 0; break;
+ case 's': j = 1; break;
+ case 'c': j = 2; break;
+ case ASGN: j = 3; break;
+ case ASSERT: j = 4; break;
+ default: j = 5; break;
+ }
+ for (nc = casing[j]; nc; nc = nc->nxt)
+ if (identical(nc->n, e->n)
+ && samedeads(nc->u, e->dead)
+ && equiv_merges(nc->e, e)
+ && nc->owner == owner)
+ return nc;
+
+ return (CaseCache *) 0;
+}
+
+static void
+new_case(Element *e, int m, int b, int owner)
+{ int j; CaseCache *nc;
+
+ switch (e->n->ntyp) {
+ case 'r': j = 0; break;
+ case 's': j = 1; break;
+ case 'c': j = 2; break;
+ case ASGN: j = 3; break;
+ case ASSERT: j = 4; break;
+ default: j = 5; break;
+ }
+ nc = (CaseCache *) emalloc(sizeof(CaseCache));
+ nc->owner = owner;
+ nc->m = m;
+ nc->b = b;
+ nc->e = e;
+ nc->n = e->n;
+ nc->u = e->dead;
+ nc->nxt = casing[j];
+ casing[j] = nc;
+}
+
+static int
+nr_bup(Element *e)
+{ FSM_use *u;
+ Lextok *v;
+ int nr = 0;
+
+ switch (e->n->ntyp) {
+ case ASGN:
+ nr++;
+ break;
+ case 'r':
+ if (e->n->val >= 1)
+ nr++; /* random recv */
+ for (v = e->n->rgt; v; v = v->rgt)
+ { if ((v->lft->ntyp == CONST
+ || v->lft->ntyp == EVAL))
+ continue;
+ nr++;
+ }
+ break;
+ default:
+ break;
+ }
+ for (u = e->dead; u; u = u->nxt)
+ { switch (u->special) {
+ case 2: /* dead after write */
+ if (e->n->ntyp == ASGN
+ && e->n->rgt->ntyp == CONST
+ && e->n->rgt->val == 0)
+ break;
+ nr++;
+ break;
+ case 1: /* dead after read */
+ nr++;
+ break;
+ } }
+ return nr;
+}
+
+static int
+nrhops(Element *e)
+{ Element *f = e, *g;
+ int cnt = 0;
+ int stopat;
+
+ if (e->merge_start)
+ stopat = e->merge_start;
+ else
+ stopat = e->merge;
+#if 0
+ printf("merge: %d merge_start %d - seqno %d\n",
+ e->merge, e->merge_start, e->seqno);
+#endif
+ do {
+ cnt += nr_bup(f);
+
+ if (f->n->ntyp == GOTO)
+ { g = get_lab(f->n, 1);
+ if (g->seqno == stopat)
+ f = g;
+ else
+ f = huntele(g, f->status, stopat);
+ } else
+ {
+ f = f->nxt;
+ }
+
+ if (f && !f->merge && !f->merge_single && f->seqno != stopat)
+ { fprintf(tm, "\n\t\tbad hop %s:%d -- at %d, <",
+ f->n->fn->name,f->n->ln, f->seqno);
+ comment(tm, f->n, 0);
+ fprintf(tm, "> looking for %d -- merge %d:%d:%d\n\t\t",
+ stopat, f->merge, f->merge_start, f->merge_single);
+ break;
+ }
+ } while (f && f->seqno != stopat);
+
+ return cnt;
+}
+
+static void
+check_needed(void)
+{
+ if (multi_needed)
+ { fprintf(tm, "(trpt+1)->bup.ovals = grab_ints(%d);\n\t\t",
+ multi_needed);
+ multi_undo = multi_needed;
+ multi_needed = 0;
+ }
+}
+
+static void
+doforward(FILE *tm, Element *e)
+{ FSM_use *u;
+
+ putstmnt(tm, e->n, e->seqno);
+
+ if (e->n->ntyp != ELSE && Det)
+ { fprintf(tm, ";\n\t\tif (trpt->o_pm&1)\n\t\t");
+ fprintf(tm, "\tuerror(\"non-determinism in D_proctype\")");
+ }
+ if (deadvar && !has_code)
+ for (u = e->dead; u; u = u->nxt)
+ { fprintf(tm, ";\n\t\t/* dead %d: %s */ ",
+ u->special, u->var->name);
+
+ switch (u->special) {
+ case 2: /* dead after write -- lval already bupped */
+ if (e->n->ntyp == ASGN) /* could be recv or asgn */
+ { if (e->n->rgt->ntyp == CONST
+ && e->n->rgt->val == 0)
+ continue; /* already set to 0 */
+ }
+ if (e->n->ntyp != 'r')
+ { XZ.sym = u->var;
+ fprintf(tm, "\n#ifdef HAS_CODE\n");
+ fprintf(tm, "\t\tif (!readtrail)\n");
+ fprintf(tm, "#endif\n\t\t\t");
+ putname(tm, "", &XZ, 0, " = 0");
+ break;
+ } /* else fall through */
+ case 1: /* dead after read -- add asgn of rval -- needs bup */
+ YZ[YZmax].sym = u->var; /* store for pan.b */
+ CnT[YZcnt]++; /* this step added bups */
+ if (multi_oval)
+ { check_needed();
+ fprintf(tm, "(trpt+1)->bup.ovals[%d] = ",
+ multi_oval-1);
+ multi_oval++;
+ } else
+ fprintf(tm, "(trpt+1)->bup.oval = ");
+ putname(tm, "", &YZ[YZmax], 0, ";\n");
+ fprintf(tm, "#ifdef HAS_CODE\n");
+ fprintf(tm, "\t\tif (!readtrail)\n");
+ fprintf(tm, "#endif\n\t\t\t");
+ putname(tm, "", &YZ[YZmax], 0, " = 0");
+ YZmax++;
+ break;
+ } }
+ fprintf(tm, ";\n\t\t");
+}
+
+static int
+dobackward(Element *e, int casenr)
+{
+ if (!any_undo(e->n) && CnT[YZcnt] == 0)
+ { YZcnt--;
+ return 0;
+ }
+
+ if (!didcase)
+ { fprintf(tb, "\n\tcase %d: ", casenr);
+ fprintf(tb, "/* STATE %d */\n\t\t", e->seqno);
+ didcase++;
+ }
+
+ _isok++;
+ while (CnT[YZcnt] > 0) /* undo dead variable resets */
+ { CnT[YZcnt]--;
+ YZmax--;
+ if (YZmax < 0)
+ fatal("cannot happen, dobackward", (char *)0);
+ fprintf(tb, ";\n\t/* %d */\t", YZmax);
+ putname(tb, "", &YZ[YZmax], 0, " = trpt->bup.oval");
+ if (multi_oval > 0)
+ { multi_oval--;
+ fprintf(tb, "s[%d]", multi_oval-1);
+ }
+ }
+
+ if (e->n->ntyp != '.')
+ { fprintf(tb, ";\n\t\t");
+ undostmnt(e->n, e->seqno);
+ }
+ _isok--;
+
+ YZcnt--;
+ return 1;
+}
+
+static void
+lastfirst(int stopat, Element *fin, int casenr)
+{ Element *f = fin, *g;
+
+ if (f->n->ntyp == GOTO)
+ { g = get_lab(f->n, 1);
+ if (g->seqno == stopat)
+ f = g;
+ else
+ f = huntele(g, f->status, stopat);
+ } else
+ f = f->nxt;
+
+ if (!f || f->seqno == stopat
+ || (!f->merge && !f->merge_single))
+ return;
+ lastfirst(stopat, f, casenr);
+#if 0
+ fprintf(tb, "\n\t/* merge %d -- %d:%d %d:%d:%d (casenr %d) ",
+ YZcnt,
+ f->merge_start, f->merge,
+ f->seqno, f?f->seqno:-1, stopat,
+ casenr);
+ comment(tb, f->n, 0);
+ fprintf(tb, " */\n");
+ fflush(tb);
+#endif
+ dobackward(f, casenr);
+}
+
+static int modifier;
+
+static void
+lab_transfer(Element *to, Element *from)
+{ Symbol *ns, *s = has_lab(from, (1|2|4));
+ Symbol *oc;
+ int ltp, usedit=0;
+
+ if (!s) return;
+
+ /* "from" could have all three labels -- rename
+ * to prevent jumps to the transfered copies
+ */
+ oc = context; /* remember */
+ for (ltp = 1; ltp < 8; ltp *= 2) /* 1, 2, and 4 */
+ if ((s = has_lab(from, ltp)) != (Symbol *) 0)
+ { ns = (Symbol *) emalloc(sizeof(Symbol));
+ ns->name = (char *) emalloc((int) strlen(s->name) + 4);
+ sprintf(ns->name, "%s%d", s->name, modifier);
+
+ context = s->context;
+ set_lab(ns, to);
+ usedit++;
+ }
+ context = oc; /* restore */
+ if (usedit)
+ { if (modifier++ > 990)
+ fatal("modifier overflow error", (char *) 0);
+ }
+}
+
+static int
+case_cache(Element *e, int a)
+{ int bupcase = 0, casenr = uniq, fromcache = 0;
+ CaseCache *Cached = (CaseCache *) 0;
+ Element *f, *g;
+ int j, nrbups, mark, target;
+ extern int ccache;
+
+ mark = (e->status&ATOM); /* could lose atomicity in a merge chain */
+
+ if (e->merge_mark > 0
+ || (merger && e->merge_in == 0))
+ { /* state nominally unreachable (part of merge chains) */
+ if (e->n->ntyp != '.'
+ && e->n->ntyp != GOTO)
+ { fprintf(tt, "\ttrans[%d][%d]\t= ", Pid, e->seqno);
+ fprintf(tt, "settr(0,0,0,0,0,\"");
+ comment(tt, e->n, e->seqno);
+ fprintf(tt, "\",0,0,0);\n");
+ } else
+ { fprintf(tt, "\ttrans[%d][%d]\t= ", Pid, e->seqno);
+ casenr = 1; /* mhs example */
+ j = a;
+ goto haveit; /* pakula's example */
+ }
+
+ return -1;
+ }
+
+ fprintf(tt, "\ttrans[%d][%d]\t= ", Pid, e->seqno);
+
+ if (ccache
+ && Pid != claimnr
+ && Pid != eventmapnr
+ && (Cached = prev_case(e, Pid)))
+ { bupcase = Cached->b;
+ casenr = Cached->m;
+ fromcache = 1;
+
+ fprintf(tm, "/* STATE %d - line %d %s - [",
+ e->seqno, e->n->ln, e->n->fn->name);
+ comment(tm, e->n, 0);
+ fprintf(tm, "] (%d:%d - %d) same as %d (%d:%d - %d) */\n",
+ e->merge_start, e->merge, e->merge_in,
+ casenr,
+ Cached->e->merge_start, Cached->e->merge, Cached->e->merge_in);
+
+ goto gotit;
+ }
+
+ fprintf(tm, "\tcase %d: /* STATE %d - line %d %s - [",
+ uniq++, e->seqno, e->n->ln, e->n->fn->name);
+ comment(tm, e->n, 0);
+ nrbups = (e->merge || e->merge_start) ? nrhops(e) : nr_bup(e);
+ fprintf(tm, "] (%d:%d:%d - %d) */\n\t\t",
+ e->merge_start, e->merge, nrbups, e->merge_in);
+
+ if (nrbups > MAXMERGE-1)
+ fatal("merge requires more than 256 bups", (char *)0);
+
+ if (e->n->ntyp != 'r' && Pid != claimnr && Pid != eventmapnr)
+ fprintf(tm, "IfNotBlocked\n\t\t");
+
+ if (multi_needed != 0 || multi_undo != 0)
+ fatal("cannot happen, case_cache", (char *) 0);
+
+ if (nrbups > 1)
+ { multi_oval = 1;
+ multi_needed = nrbups; /* allocated after edge condition */
+ } else
+ multi_oval = 0;
+
+ memset(CnT, 0, sizeof(CnT));
+ YZmax = YZcnt = 0;
+
+/* NEW 4.2.6 */
+ if (Pid == claimnr)
+ {
+ fprintf(tm, "\n#if defined(VERI) && !defined(NP)\n\t\t");
+ fprintf(tm, "{ static int reported%d = 0;\n\t\t", e->seqno);
+ /* source state changes in retrans and must be looked up in frm_st0[t->forw] */
+ fprintf(tm, " if (verbose && !reported%d)\n\t\t", e->seqno);
+ fprintf(tm, " { printf(\"depth %%d: Claim reached state %%d (line %%d)\\n\",\n\t\t");
+ fprintf(tm, " depth, frm_st0[t->forw], src_claim[%d]);\n\t\t", e->seqno);
+ fprintf(tm, " reported%d = 1;\n\t\t", e->seqno);
+ fprintf(tm, " fflush(stdout);\n\t\t");
+ fprintf(tm, "} }\n");
+ fprintf(tm, "#endif\n\t\t");
+ }
+/* end */
+
+ /* the src xrefs have the numbers in e->seqno builtin */
+ fprintf(tm, "reached[%d][%d] = 1;\n\t\t", Pid, e->seqno);
+
+ doforward(tm, e);
+
+ if (e->merge_start)
+ target = e->merge_start;
+ else
+ target = e->merge;
+
+ if (target)
+ { f = e;
+
+more: if (f->n->ntyp == GOTO)
+ { g = get_lab(f->n, 1);
+ if (g->seqno == target)
+ f = g;
+ else
+ f = huntele(g, f->status, target);
+ } else
+ f = f->nxt;
+
+
+ if (f && f->seqno != target)
+ { if (!f->merge && !f->merge_single)
+ { fprintf(tm, "/* stop at bad hop %d, %d */\n\t\t",
+ f->seqno, target);
+ goto out;
+ }
+ fprintf(tm, "/* merge: ");
+ comment(tm, f->n, 0);
+ fprintf(tm, "(%d, %d, %d) */\n\t\t", f->merge, f->seqno, target);
+ fprintf(tm, "reached[%d][%d] = 1;\n\t\t", Pid, f->seqno);
+ YZcnt++;
+ lab_transfer(e, f);
+ mark = f->status&(ATOM|L_ATOM); /* last step wins */
+ doforward(tm, f);
+ if (f->merge_in == 1) f->merge_mark++;
+
+ goto more;
+ } }
+out:
+ fprintf(tm, "_m = %d", getweight(e->n));
+ if (m_loss && e->n->ntyp == 's') fprintf(tm, "+delta_m; delta_m = 0");
+ fprintf(tm, "; goto P999; /* %d */\n", YZcnt);
+
+ multi_needed = 0;
+ didcase = 0;
+
+ if (target)
+ lastfirst(target, e, casenr); /* mergesteps only */
+
+ dobackward(e, casenr); /* the original step */
+
+ fprintf(tb, ";\n\t\t");
+
+ if (e->merge || e->merge_start)
+ { if (!didcase)
+ { fprintf(tb, "\n\tcase %d: ", casenr);
+ fprintf(tb, "/* STATE %d */", e->seqno);
+ didcase++;
+ } else
+ fprintf(tb, ";");
+ } else
+ fprintf(tb, ";");
+ fprintf(tb, "\n\t\t");
+
+ if (multi_undo)
+ { fprintf(tb, "ungrab_ints(trpt->bup.ovals, %d);\n\t\t",
+ multi_undo);
+ multi_undo = 0;
+ }
+ if (didcase)
+ { fprintf(tb, "goto R999;\n");
+ bupcase = casenr;
+ }
+
+ if (!e->merge && !e->merge_start)
+ new_case(e, casenr, bupcase, Pid);
+
+gotit:
+ j = a;
+ if (e->merge_start)
+ j = e->merge_start;
+ else if (e->merge)
+ j = e->merge;
+haveit:
+ fprintf(tt, "%ssettr(%d,%d,%d,%d,%d,\"", fromcache?"/* c */ ":"",
+ e->Seqno, mark, j, casenr, bupcase);
+
+ return (fromcache)?0:casenr;
+}
+
+static void
+put_el(Element *e, int Tt0, int Tt1)
+{ int a, casenr, Global_ref;
+ Element *g = ZE;
+
+ if (e->n->ntyp == GOTO)
+ { g = get_lab(e->n, 1);
+ g = huntele(g, e->status, -1);
+ cross_dsteps(e->n, g->n);
+ a = g->seqno;
+ } else if (e->nxt)
+ { g = huntele(e->nxt, e->status, -1);
+ a = g->seqno;
+ } else
+ a = 0;
+ if (g
+ && (g->status&CHECK2 /* entering remotely ref'd state */
+ || e->status&CHECK2)) /* leaving remotely ref'd state */
+ e->status |= I_GLOB;
+
+ /* don't remove dead edges in here, to preserve structure of fsm */
+ if (e->merge_start || e->merge)
+ goto non_generic;
+
+ /*** avoid duplicate or redundant cases in pan.m ***/
+ switch (e->n->ntyp) {
+ case ELSE:
+ casenr = 2; /* standard else */
+ putskip(e->seqno);
+ goto generic_case;
+ /* break; */
+ case '.':
+ case GOTO:
+ case BREAK:
+ putskip(e->seqno);
+ casenr = 1; /* standard goto */
+generic_case: fprintf(tt, "\ttrans[%d][%d]\t= ", Pid, e->seqno);
+ fprintf(tt, "settr(%d,%d,%d,%d,0,\"",
+ e->Seqno, e->status&ATOM, a, casenr);
+ break;
+#ifndef PRINTF
+ case PRINT:
+ goto non_generic;
+ case PRINTM:
+ goto non_generic;
+#endif
+ case 'c':
+ if (e->n->lft->ntyp == CONST
+ && e->n->lft->val == 1) /* skip or true */
+ { casenr = 1;
+ putskip(e->seqno);
+ goto generic_case;
+ }
+ goto non_generic;
+
+ default:
+non_generic:
+ casenr = case_cache(e, a);
+ if (casenr < 0) return; /* unreachable state */
+ break;
+ }
+ /* tailend of settr(...); */
+ Global_ref = (e->status&I_GLOB)?1:has_global(e->n);
+ comment(tt, e->n, e->seqno);
+ fprintf(tt, "\", %d, ", Global_ref);
+ if (Tt0 != 2)
+ { fprintf(tt, "%d, %d);", Tt0, Tt1);
+ } else
+ { Tpe(e->n); /* sets EPT */
+ fprintf(tt, "%d, %d);", EPT[0], EPT[1]);
+ }
+ if ((e->merge_start && e->merge_start != a)
+ || (e->merge && e->merge != a))
+ { fprintf(tt, " /* m: %d -> %d,%d */\n",
+ a, e->merge_start, e->merge);
+ fprintf(tt, " reached%d[%d] = 1;",
+ Pid, a); /* Sheinman's example */
+ }
+ fprintf(tt, "\n");
+
+ if (casenr > 2)
+ tr_map(casenr, e);
+ put_escp(e);
+}
+
+static void
+nested_unless(Element *e, Element *g)
+{ struct SeqList *y = e->esc, *z = g->esc;
+
+ for ( ; y && z; y = y->nxt, z = z->nxt)
+ if (z->this != y->this)
+ break;
+ if (!y && !z)
+ return;
+
+ if (g->n->ntyp != GOTO
+ && g->n->ntyp != '.'
+ && e->sub->nxt)
+ { printf("error: (%s:%d) saw 'unless' on a guard:\n",
+ (e->n)?e->n->fn->name:"-",
+ (e->n)?e->n->ln:0);
+ printf("=====>instead of\n");
+ printf(" do (or if)\n");
+ printf(" :: ...\n");
+ printf(" :: stmnt1 unless stmnt2\n");
+ printf(" od (of fi)\n");
+ printf("=====>use\n");
+ printf(" do (or if)\n");
+ printf(" :: ...\n");
+ printf(" :: stmnt1\n");
+ printf(" od (or fi) unless stmnt2\n");
+ printf("=====>or rewrite\n");
+ }
+}
+
+static void
+put_seq(Sequence *s, int Tt0, int Tt1)
+{ SeqList *h;
+ Element *e, *g;
+ int a, deadlink;
+
+ if (0) printf("put_seq %d\n", s->frst->seqno);
+
+ for (e = s->frst; e; e = e->nxt)
+ {
+ if (0) printf(" step %d\n", e->seqno);
+ if (e->status & DONE)
+ {
+ if (0) printf(" done before\n");
+ goto checklast;
+ }
+ e->status |= DONE;
+
+ if (e->n->ln)
+ putsrc(e);
+
+ if (e->n->ntyp == UNLESS)
+ {
+ if (0) printf(" an unless\n");
+ put_seq(e->sub->this, Tt0, Tt1);
+ } else if (e->sub)
+ {
+ if (0) printf(" has sub\n");
+ fprintf(tt, "\tT = trans[%d][%d] = ",
+ Pid, e->seqno);
+ fprintf(tt, "settr(%d,%d,0,0,0,\"",
+ e->Seqno, e->status&ATOM);
+ comment(tt, e->n, e->seqno);
+ if (e->status&CHECK2)
+ e->status |= I_GLOB;
+ fprintf(tt, "\", %d, %d, %d);",
+ (e->status&I_GLOB)?1:0, Tt0, Tt1);
+ blurb(tt, e);
+ for (h = e->sub; h; h = h->nxt)
+ { putskip(h->this->frst->seqno);
+ g = huntstart(h->this->frst);
+ if (g->esc)
+ nested_unless(e, g);
+ a = g->seqno;
+
+ if (g->n->ntyp == 'c'
+ && g->n->lft->ntyp == CONST
+ && g->n->lft->val == 0 /* 0 or false */
+ && !g->esc)
+ { fprintf(tt, "#if 0\n\t/* dead link: */\n");
+ deadlink = 1;
+ if (verbose&32)
+ printf("spin: line %3d %s, Warning: condition is always false\n",
+ g->n->ln, g->n->fn?g->n->fn->name:"");
+ } else
+ deadlink = 0;
+ if (0) printf(" settr %d %d\n", a, 0);
+ if (h->nxt)
+ fprintf(tt, "\tT = T->nxt\t= ");
+ else
+ fprintf(tt, "\t T->nxt\t= ");
+ fprintf(tt, "settr(%d,%d,%d,0,0,\"",
+ e->Seqno, e->status&ATOM, a);
+ comment(tt, e->n, e->seqno);
+ if (g->status&CHECK2)
+ h->this->frst->status |= I_GLOB;
+ fprintf(tt, "\", %d, %d, %d);",
+ (h->this->frst->status&I_GLOB)?1:0,
+ Tt0, Tt1);
+ blurb(tt, e);
+ if (deadlink)
+ fprintf(tt, "#endif\n");
+ }
+ for (h = e->sub; h; h = h->nxt)
+ put_seq(h->this, Tt0, Tt1);
+ } else
+ {
+ if (0) printf(" [non]atomic %d\n", e->n->ntyp);
+ if (e->n->ntyp == ATOMIC
+ || e->n->ntyp == D_STEP
+ || e->n->ntyp == NON_ATOMIC)
+ put_sub(e, Tt0, Tt1);
+ else
+ {
+ if (0) printf(" put_el %d\n", e->seqno);
+ put_el(e, Tt0, Tt1);
+ }
+ }
+checklast: if (e == s->last)
+ break;
+ }
+ if (0) printf("put_seq done\n");
+}
+
+static void
+patch_atomic(Sequence *s) /* catch goto's that break the chain */
+{ Element *f, *g;
+ SeqList *h;
+
+ for (f = s->frst; f ; f = f->nxt)
+ {
+ if (f->n && f->n->ntyp == GOTO)
+ { g = get_lab(f->n,1);
+ cross_dsteps(f->n, g->n);
+ if ((f->status & (ATOM|L_ATOM))
+ && !(g->status & (ATOM|L_ATOM)))
+ { f->status &= ~ATOM;
+ f->status |= L_ATOM;
+ }
+ /* bridge atomics */
+ if ((f->status & L_ATOM)
+ && (g->status & (ATOM|L_ATOM)))
+ { f->status &= ~L_ATOM;
+ f->status |= ATOM;
+ }
+ } else
+ for (h = f->sub; h; h = h->nxt)
+ patch_atomic(h->this);
+ if (f == s->extent)
+ break;
+ }
+}
+
+static void
+mark_seq(Sequence *s)
+{ Element *f;
+ SeqList *h;
+
+ for (f = s->frst; f; f = f->nxt)
+ { f->status |= I_GLOB;
+
+ if (f->n->ntyp == ATOMIC
+ || f->n->ntyp == NON_ATOMIC
+ || f->n->ntyp == D_STEP)
+ mark_seq(f->n->sl->this);
+
+ for (h = f->sub; h; h = h->nxt)
+ mark_seq(h->this);
+ if (f == s->last)
+ return;
+ }
+}
+
+static Element *
+find_target(Element *e)
+{ Element *f;
+
+ if (!e) return e;
+
+ if (t_cyc++ > 32)
+ { fatal("cycle of goto jumps", (char *) 0);
+ }
+ switch (e->n->ntyp) {
+ case GOTO:
+ f = get_lab(e->n,1);
+ cross_dsteps(e->n, f->n);
+ f = find_target(f);
+ break;
+ case BREAK:
+ if (e->nxt)
+ { f = find_target(huntele(e->nxt, e->status, -1));
+ break; /* 4.3.0 -- was missing */
+ }
+ /* else fall through */
+ default:
+ f = e;
+ break;
+ }
+ return f;
+}
+
+Element *
+target(Element *e)
+{
+ if (!e) return e;
+ lineno = e->n->ln;
+ Fname = e->n->fn;
+ t_cyc = 0;
+ return find_target(e);
+}
+
+static int
+scan_seq(Sequence *s)
+{ Element *f, *g;
+ SeqList *h;
+
+ for (f = s->frst; f; f = f->nxt)
+ { if ((f->status&CHECK2)
+ || has_global(f->n))
+ return 1;
+ if (f->n->ntyp == GOTO) /* may reach other atomic */
+ {
+#if 0
+ /* if jumping from an atomic without globals into
+ * one with globals, this does the wrong thing
+ * example by Claus Traulsen, 22 June 2007
+ */
+ g = target(f);
+ if (g
+ && !(f->status & L_ATOM)
+ && !(g->status & (ATOM|L_ATOM)))
+#endif
+ { fprintf(tt, " /* mark-down line %d */\n",
+ f->n->ln);
+ return 1; /* assume worst case */
+ } }
+ for (h = f->sub; h; h = h->nxt)
+ if (scan_seq(h->this))
+ return 1;
+ if (f == s->last)
+ break;
+ }
+ return 0;
+}
+
+static int
+glob_args(Lextok *n)
+{ int result = 0;
+ Lextok *v;
+
+ for (v = n->rgt; v; v = v->rgt)
+ { if (v->lft->ntyp == CONST)
+ continue;
+ if (v->lft->ntyp == EVAL)
+ result += has_global(v->lft->lft);
+ else
+ result += has_global(v->lft);
+ }
+ return result;
+}
+
+int
+has_global(Lextok *n)
+{ Lextok *v; extern int runsafe;
+
+ if (!n) return 0;
+ if (AllGlobal) return 1; /* global provided clause */
+
+ switch (n->ntyp) {
+ case ATOMIC:
+ case D_STEP:
+ case NON_ATOMIC:
+ return scan_seq(n->sl->this);
+
+ case '.':
+ case BREAK:
+ case GOTO:
+ case CONST:
+ return 0;
+
+ case ELSE: return n->val; /* true if combined with chan refs */
+
+ case 's': return glob_args(n)!=0 || ((n->sym->xu&(XS|XX)) != XS);
+ case 'r': return glob_args(n)!=0 || ((n->sym->xu&(XR|XX)) != XR);
+ case 'R': return glob_args(n)!=0 || (((n->sym->xu)&(XR|XS|XX)) != (XR|XS));
+ case NEMPTY: return ((n->sym->xu&(XR|XX)) != XR);
+ case NFULL: return ((n->sym->xu&(XS|XX)) != XS);
+ case FULL: return ((n->sym->xu&(XR|XX)) != XR);
+ case EMPTY: return ((n->sym->xu&(XS|XX)) != XS);
+ case LEN: return (((n->sym->xu)&(XR|XS|XX)) != (XR|XS));
+
+ case NAME:
+ if (n->sym->context
+ || (n->sym->hidden&64)
+ || strcmp(n->sym->name, "_pid") == 0
+ || strcmp(n->sym->name, "_") == 0)
+ return 0;
+ return 1;
+
+ case RUN: return 1-runsafe;
+
+ case C_CODE: case C_EXPR:
+ return glob_inline(n->sym->name);
+
+ case ENABLED: case PC_VAL: case NONPROGRESS:
+ case 'p': case 'q':
+ case TIMEOUT:
+ return 1;
+
+ /* @ was 1 (global) since 2.8.5
+ in 3.0 it is considered local and
+ conditionally safe, provided:
+ II is the youngest process
+ and nrprocs < MAXPROCS
+ */
+ case '@': return 0;
+
+ case '!': case UMIN: case '~': case ASSERT:
+ return has_global(n->lft);
+
+ case '/': case '*': case '-': case '+':
+ case '%': case LT: case GT: case '&': case '^':
+ case '|': case LE: case GE: case NE: case '?':
+ case EQ: case OR: case AND: case LSHIFT:
+ case RSHIFT: case 'c': case ASGN:
+ return has_global(n->lft) || has_global(n->rgt);
+
+ case PRINT:
+ for (v = n->lft; v; v = v->rgt)
+ if (has_global(v->lft)) return 1;
+ return 0;
+ case PRINTM:
+ return has_global(n->lft);
+ }
+ return 0;
+}
+
+static void
+Bailout(FILE *fd, char *str)
+{
+ if (!GenCode)
+ fprintf(fd, "continue%s", str);
+ else if (IsGuard)
+ fprintf(fd, "%s%s", NextLab[Level], str);
+ else
+ fprintf(fd, "Uerror(\"block in step seq\")%s", str);
+}
+
+#define cat0(x) putstmnt(fd,now->lft,m); fprintf(fd, x); \
+ putstmnt(fd,now->rgt,m)
+#define cat1(x) fprintf(fd,"("); cat0(x); fprintf(fd,")")
+#define cat2(x,y) fprintf(fd,x); putstmnt(fd,y,m)
+#define cat3(x,y,z) fprintf(fd,x); putstmnt(fd,y,m); fprintf(fd,z)
+
+void
+putstmnt(FILE *fd, Lextok *now, int m)
+{ Lextok *v;
+ int i, j;
+
+ if (!now) { fprintf(fd, "0"); return; }
+ lineno = now->ln;
+ Fname = now->fn;
+
+ switch (now->ntyp) {
+ case CONST: fprintf(fd, "%d", now->val); break;
+ case '!': cat3(" !(", now->lft, ")"); break;
+ case UMIN: cat3(" -(", now->lft, ")"); break;
+ case '~': cat3(" ~(", now->lft, ")"); break;
+
+ case '/': cat1("/"); break;
+ case '*': cat1("*"); break;
+ case '-': cat1("-"); break;
+ case '+': cat1("+"); break;
+ case '%': cat1("%%"); break;
+ case '&': cat1("&"); break;
+ case '^': cat1("^"); break;
+ case '|': cat1("|"); break;
+ case LT: cat1("<"); break;
+ case GT: cat1(">"); break;
+ case LE: cat1("<="); break;
+ case GE: cat1(">="); break;
+ case NE: cat1("!="); break;
+ case EQ: cat1("=="); break;
+ case OR: cat1("||"); break;
+ case AND: cat1("&&"); break;
+ case LSHIFT: cat1("<<"); break;
+ case RSHIFT: cat1(">>"); break;
+
+ case TIMEOUT:
+ if (separate == 2)
+ fprintf(fd, "((tau)&1)");
+ else
+ fprintf(fd, "((trpt->tau)&1)");
+ if (GenCode)
+ printf("spin: line %3d, warning: 'timeout' in d_step sequence\n",
+ lineno);
+ /* is okay as a guard */
+ break;
+
+ case RUN:
+ if (claimproc
+ && strcmp(now->sym->name, claimproc) == 0)
+ fatal("claim %s, (not runnable)", claimproc);
+ if (eventmap
+ && strcmp(now->sym->name, eventmap) == 0)
+ fatal("eventmap %s, (not runnable)", eventmap);
+
+ if (GenCode)
+ fatal("'run' in d_step sequence (use atomic)",
+ (char *)0);
+
+ fprintf(fd,"addproc(%d", fproc(now->sym->name));
+ for (v = now->lft, i = 0; v; v = v->rgt, i++)
+ { cat2(", ", v->lft);
+ }
+ check_param_count(i, now);
+
+ if (i > Npars)
+ { printf("\t%d parameters used, max %d expected\n", i, Npars);
+ fatal("too many parameters in run %s(...)",
+ now->sym->name);
+ }
+ for ( ; i < Npars; i++)
+ fprintf(fd, ", 0");
+ fprintf(fd, ")");
+ break;
+
+ case ENABLED:
+ cat3("enabled(II, ", now->lft, ")");
+ break;
+
+ case NONPROGRESS:
+ /* o_pm&4=progress, tau&128=claim stutter */
+ if (separate == 2)
+ fprintf(fd, "(!(o_pm&4) && !(tau&128))");
+ else
+ fprintf(fd, "(!(trpt->o_pm&4) && !(trpt->tau&128))");
+ break;
+
+ case PC_VAL:
+ cat3("((P0 *) Pptr(", now->lft, "+BASE))->_p");
+ break;
+
+ case LEN:
+ if (!terse && !TestOnly && has_xu)
+ { fprintf(fd, "\n#ifndef XUSAFE\n\t\t");
+ putname(fd, "(!(q_claim[", now->lft, m, "]&1) || ");
+ putname(fd, "q_R_check(", now->lft, m, "");
+ fprintf(fd, ", II)) &&\n\t\t");
+ putname(fd, "(!(q_claim[", now->lft, m, "]&2) || ");
+ putname(fd, "q_S_check(", now->lft, m, ", II)) &&");
+ fprintf(fd, "\n#endif\n\t\t");
+ }
+ putname(fd, "q_len(", now->lft, m, ")");
+ break;
+
+ case FULL:
+ if (!terse && !TestOnly && has_xu)
+ { fprintf(fd, "\n#ifndef XUSAFE\n\t\t");
+ putname(fd, "(!(q_claim[", now->lft, m, "]&1) || ");
+ putname(fd, "q_R_check(", now->lft, m, "");
+ fprintf(fd, ", II)) &&\n\t\t");
+ putname(fd, "(!(q_claim[", now->lft, m, "]&2) || ");
+ putname(fd, "q_S_check(", now->lft, m, ", II)) &&");
+ fprintf(fd, "\n#endif\n\t\t");
+ }
+ putname(fd, "q_full(", now->lft, m, ")");
+ break;
+
+ case EMPTY:
+ if (!terse && !TestOnly && has_xu)
+ { fprintf(fd, "\n#ifndef XUSAFE\n\t\t");
+ putname(fd, "(!(q_claim[", now->lft, m, "]&1) || ");
+ putname(fd, "q_R_check(", now->lft, m, "");
+ fprintf(fd, ", II)) &&\n\t\t");
+ putname(fd, "(!(q_claim[", now->lft, m, "]&2) || ");
+ putname(fd, "q_S_check(", now->lft, m, ", II)) &&");
+ fprintf(fd, "\n#endif\n\t\t");
+ }
+ putname(fd, "(q_len(", now->lft, m, ")==0)");
+ break;
+
+ case NFULL:
+ if (!terse && !TestOnly && has_xu)
+ { fprintf(fd, "\n#ifndef XUSAFE\n\t\t");
+ putname(fd, "(!(q_claim[", now->lft, m, "]&2) || ");
+ putname(fd, "q_S_check(", now->lft, m, ", II)) &&");
+ fprintf(fd, "\n#endif\n\t\t");
+ }
+ putname(fd, "(!q_full(", now->lft, m, "))");
+ break;
+
+ case NEMPTY:
+ if (!terse && !TestOnly && has_xu)
+ { fprintf(fd, "\n#ifndef XUSAFE\n\t\t");
+ putname(fd, "(!(q_claim[", now->lft, m, "]&1) || ");
+ putname(fd, "q_R_check(", now->lft, m, ", II)) &&");
+ fprintf(fd, "\n#endif\n\t\t");
+ }
+ putname(fd, "(q_len(", now->lft, m, ")>0)");
+ break;
+
+ case 's':
+ if (Pid == eventmapnr)
+ { fprintf(fd, "if ((ot == EVENT_TRACE && _tp != 's') ");
+ putname(fd, "|| _qid+1 != ", now->lft, m, "");
+ for (v = now->rgt, i=0; v; v = v->rgt, i++)
+ { if (v->lft->ntyp != CONST
+ && v->lft->ntyp != EVAL)
+ continue;
+ fprintf(fd, " \\\n\t\t|| qrecv(");
+ putname(fd, "", now->lft, m, ", ");
+ putname(fd, "q_len(", now->lft, m, ")-1, ");
+ fprintf(fd, "%d, 0) != ", i);
+ if (v->lft->ntyp == CONST)
+ putstmnt(fd, v->lft, m);
+ else /* EVAL */
+ putstmnt(fd, v->lft->lft, m);
+ }
+ fprintf(fd, ")\n");
+ fprintf(fd, "\t\t continue");
+ putname(th, " || (x_y3_ == ", now->lft, m, ")");
+ break;
+ }
+ if (TestOnly)
+ { if (m_loss)
+ fprintf(fd, "1");
+ else
+ putname(fd, "!q_full(", now->lft, m, ")");
+ break;
+ }
+ if (has_xu)
+ { fprintf(fd, "\n#ifndef XUSAFE\n\t\t");
+ putname(fd, "if (q_claim[", now->lft, m, "]&2) ");
+ putname(fd, "q_S_check(", now->lft, m, ", II);");
+ fprintf(fd, "\n#endif\n\t\t");
+ }
+ fprintf(fd, "if (q_%s",
+ (u_sync > 0 && u_async == 0)?"len":"full");
+ putname(fd, "(", now->lft, m, "))\n");
+
+ if (m_loss)
+ fprintf(fd, "\t\t{ nlost++; delta_m = 1; } else {");
+ else
+ { fprintf(fd, "\t\t\t");
+ Bailout(fd, ";");
+ }
+
+ if (has_enabled)
+ fprintf(fd, "\n\t\tif (TstOnly) return 1;");
+
+ if (u_sync && !u_async && rvopt)
+ fprintf(fd, "\n\n\t\tif (no_recvs(II)) continue;\n");
+
+ fprintf(fd, "\n#ifdef HAS_CODE\n");
+ fprintf(fd, "\t\tif (readtrail && gui) {\n");
+ fprintf(fd, "\t\t\tchar simtmp[32];\n");
+ putname(fd, "\t\t\tsprintf(simvals, \"%%d!\", ", now->lft, m, ");\n");
+ _isok++;
+ for (v = now->rgt, i = 0; v; v = v->rgt, i++)
+ { cat3("\t\tsprintf(simtmp, \"%%d\", ", v->lft, "); strcat(simvals, simtmp);");
+ if (v->rgt)
+ fprintf(fd, "\t\tstrcat(simvals, \",\");\n");
+ }
+ _isok--;
+ fprintf(fd, "\t\t}\n");
+ fprintf(fd, "#endif\n\t\t");
+
+ putname(fd, "\n\t\tqsend(", now->lft, m, "");
+ fprintf(fd, ", %d", now->val);
+ for (v = now->rgt, i = 0; v; v = v->rgt, i++)
+ { cat2(", ", v->lft);
+ }
+ if (i > Mpars)
+ { terse++;
+ putname(stdout, "channel name: ", now->lft, m, "\n");
+ terse--;
+ printf(" %d msg parameters sent, %d expected\n", i, Mpars);
+ fatal("too many pars in send", "");
+ }
+ for ( ; i < Mpars; i++)
+ fprintf(fd, ", 0");
+ fprintf(fd, ")");
+ if (u_sync)
+ { fprintf(fd, ";\n\t\t");
+ if (u_async)
+ putname(fd, "if (q_zero(", now->lft, m, ")) ");
+ putname(fd, "{ boq = ", now->lft, m, "");
+ if (GenCode)
+ fprintf(fd, "; Uerror(\"rv-attempt in d_step\")");
+ fprintf(fd, "; }");
+ }
+ if (m_loss)
+ fprintf(fd, ";\n\t\t}\n\t\t"); /* end of m_loss else */
+ break;
+
+ case 'r':
+ if (Pid == eventmapnr)
+ { fprintf(fd, "if ((ot == EVENT_TRACE && _tp != 'r') ");
+ putname(fd, "|| _qid+1 != ", now->lft, m, "");
+ for (v = now->rgt, i=0; v; v = v->rgt, i++)
+ { if (v->lft->ntyp != CONST
+ && v->lft->ntyp != EVAL)
+ continue;
+ fprintf(fd, " \\\n\t\t|| qrecv(");
+ putname(fd, "", now->lft, m, ", ");
+ fprintf(fd, "0, %d, 0) != ", i);
+ if (v->lft->ntyp == CONST)
+ putstmnt(fd, v->lft, m);
+ else /* EVAL */
+ putstmnt(fd, v->lft->lft, m);
+ }
+ fprintf(fd, ")\n");
+ fprintf(fd, "\t\t continue");
+
+ putname(tc, " || (x_y3_ == ", now->lft, m, ")");
+
+ break;
+ }
+ if (TestOnly)
+ { fprintf(fd, "((");
+ if (u_sync) fprintf(fd, "(boq == -1 && ");
+
+ putname(fd, "q_len(", now->lft, m, ")");
+
+ if (u_sync && now->val <= 1)
+ { putname(fd, ") || (boq == ", now->lft,m," && ");
+ putname(fd, "q_zero(", now->lft,m,"))");
+ }
+
+ fprintf(fd, ")");
+ if (now->val == 0 || now->val == 2)
+ { for (v = now->rgt, i=j=0; v; v = v->rgt, i++)
+ { if (v->lft->ntyp == CONST)
+ { cat3("\n\t\t&& (", v->lft, " == ");
+ putname(fd, "qrecv(", now->lft, m, ", ");
+ fprintf(fd, "0, %d, 0))", i);
+ } else if (v->lft->ntyp == EVAL)
+ { cat3("\n\t\t&& (", v->lft->lft, " == ");
+ putname(fd, "qrecv(", now->lft, m, ", ");
+ fprintf(fd, "0, %d, 0))", i);
+ } else
+ { j++; continue;
+ }
+ }
+ } else
+ { fprintf(fd, "\n\t\t&& Q_has(");
+ putname(fd, "", now->lft, m, "");
+ for (v = now->rgt, i=0; v; v = v->rgt, i++)
+ { if (v->lft->ntyp == CONST)
+ { fprintf(fd, ", 1, ");
+ putstmnt(fd, v->lft, m);
+ } else if (v->lft->ntyp == EVAL)
+ { fprintf(fd, ", 1, ");
+ putstmnt(fd, v->lft->lft, m);
+ } else
+ { fprintf(fd, ", 0, 0");
+ } }
+ for ( ; i < Mpars; i++)
+ fprintf(fd, ", 0, 0");
+ fprintf(fd, ")");
+ }
+ fprintf(fd, ")");
+ break;
+ }
+ if (has_xu)
+ { fprintf(fd, "\n#ifndef XUSAFE\n\t\t");
+ putname(fd, "if (q_claim[", now->lft, m, "]&1) ");
+ putname(fd, "q_R_check(", now->lft, m, ", II);");
+ fprintf(fd, "\n#endif\n\t\t");
+ }
+ if (u_sync)
+ { if (now->val >= 2)
+ { if (u_async)
+ { fprintf(fd, "if (");
+ putname(fd, "q_zero(", now->lft,m,"))");
+ fprintf(fd, "\n\t\t{\t");
+ }
+ fprintf(fd, "uerror(\"polling ");
+ fprintf(fd, "rv chan\");\n\t\t");
+ if (u_async)
+ fprintf(fd, " continue;\n\t\t}\n\t\t");
+ fprintf(fd, "IfNotBlocked\n\t\t");
+ } else
+ { fprintf(fd, "if (");
+ if (u_async == 0)
+ putname(fd, "boq != ", now->lft,m,") ");
+ else
+ { putname(fd, "q_zero(", now->lft,m,"))");
+ fprintf(fd, "\n\t\t{\tif (boq != ");
+ putname(fd, "", now->lft,m,") ");
+ Bailout(fd, ";\n\t\t} else\n\t\t");
+ fprintf(fd, "{\tif (boq != -1) ");
+ }
+ Bailout(fd, ";\n\t\t");
+ if (u_async)
+ fprintf(fd, "}\n\t\t");
+ } }
+ putname(fd, "if (q_len(", now->lft, m, ") == 0) ");
+ Bailout(fd, "");
+
+ for (v = now->rgt, j=0; v; v = v->rgt)
+ { if (v->lft->ntyp != CONST
+ && v->lft->ntyp != EVAL)
+ j++; /* count settables */
+ }
+ fprintf(fd, ";\n\n\t\tXX=1");
+/* test */ if (now->val == 0 || now->val == 2)
+ { for (v = now->rgt, i=0; v; v = v->rgt, i++)
+ { if (v->lft->ntyp == CONST)
+ { fprintf(fd, ";\n\t\t");
+ cat3("if (", v->lft, " != ");
+ putname(fd, "qrecv(", now->lft, m, ", ");
+ fprintf(fd, "0, %d, 0)) ", i);
+ Bailout(fd, "");
+ } else if (v->lft->ntyp == EVAL)
+ { fprintf(fd, ";\n\t\t");
+ cat3("if (", v->lft->lft, " != ");
+ putname(fd, "qrecv(", now->lft, m, ", ");
+ fprintf(fd, "0, %d, 0)) ", i);
+ Bailout(fd, "");
+ } }
+ } else /* random receive: val 1 or 3 */
+ { fprintf(fd, ";\n\t\tif (!(XX = Q_has(");
+ putname(fd, "", now->lft, m, "");
+ for (v = now->rgt, i=0; v; v = v->rgt, i++)
+ { if (v->lft->ntyp == CONST)
+ { fprintf(fd, ", 1, ");
+ putstmnt(fd, v->lft, m);
+ } else if (v->lft->ntyp == EVAL)
+ { fprintf(fd, ", 1, ");
+ putstmnt(fd, v->lft->lft, m);
+ } else
+ { fprintf(fd, ", 0, 0");
+ } }
+ for ( ; i < Mpars; i++)
+ fprintf(fd, ", 0, 0");
+ fprintf(fd, "))) ");
+ Bailout(fd, "");
+ fprintf(fd, ";\n\t\t");
+ if (multi_oval)
+ { check_needed();
+ fprintf(fd, "(trpt+1)->bup.ovals[%d] = ",
+ multi_oval-1);
+ multi_oval++;
+ } else
+ fprintf(fd, "(trpt+1)->bup.oval = ");
+ fprintf(fd, "XX");
+ }
+
+ if (has_enabled)
+ fprintf(fd, ";\n\t\tif (TstOnly) return 1");
+
+ if (j == 0 && now->val >= 2)
+ { fprintf(fd, ";\n\t\t");
+ break; /* poll without side-effect */
+ }
+
+ if (!GenCode)
+ { int jj = 0;
+ fprintf(fd, ";\n\t\t");
+ /* no variables modified */
+ if (j == 0 && now->val == 0)
+ { fprintf(fd, "if (q_flds[((Q0 *)qptr(");
+ putname(fd, "", now->lft, m, "-1))->_t]");
+ fprintf(fd, " != %d)\n\t", i);
+ fprintf(fd, "\t\tUerror(\"wrong nr of msg fields in rcv\");\n\t\t");
+ }
+
+ for (v = now->rgt; v; v = v->rgt)
+ if ((v->lft->ntyp != CONST
+ && v->lft->ntyp != EVAL))
+ jj++; /* nr of vars needing bup */
+
+ if (jj)
+ for (v = now->rgt, i = 0; v; v = v->rgt, i++)
+ { char tempbuf[64];
+
+ if ((v->lft->ntyp == CONST
+ || v->lft->ntyp == EVAL))
+ continue;
+
+ if (multi_oval)
+ { check_needed();
+ sprintf(tempbuf, "(trpt+1)->bup.ovals[%d] = ",
+ multi_oval-1);
+ multi_oval++;
+ } else
+ sprintf(tempbuf, "(trpt+1)->bup.oval = ");
+
+ if (v->lft->sym && !strcmp(v->lft->sym->name, "_"))
+ { fprintf(fd, tempbuf);
+ putname(fd, "qrecv(", now->lft, m, "");
+ fprintf(fd, ", XX-1, %d, 0);\n\t\t", i);
+ } else
+ { _isok++;
+ cat3(tempbuf, v->lft, ";\n\t\t");
+ _isok--;
+ }
+ }
+
+ if (jj) /* check for double entries q?x,x */
+ { Lextok *w;
+
+ for (v = now->rgt; v; v = v->rgt)
+ { if (v->lft->ntyp != CONST
+ && v->lft->ntyp != EVAL
+ && v->lft->sym
+ && v->lft->sym->type != STRUCT /* not a struct */
+ && v->lft->sym->nel == 1 /* not an array */
+ && strcmp(v->lft->sym->name, "_") != 0)
+ for (w = v->rgt; w; w = w->rgt)
+ if (v->lft->sym == w->lft->sym)
+ { fatal("cannot use var ('%s') in multiple msg fields",
+ v->lft->sym->name);
+ } } }
+ }
+/* set */ for (v = now->rgt, i = 0; v; v = v->rgt, i++)
+ { if ((v->lft->ntyp == CONST
+ || v->lft->ntyp == EVAL) && v->rgt)
+ continue;
+ fprintf(fd, ";\n\t\t");
+
+ if (v->lft->ntyp != CONST
+ && v->lft->ntyp != EVAL
+ && strcmp(v->lft->sym->name, "_") != 0)
+ { nocast=1;
+ _isok++;
+ putstmnt(fd, v->lft, m);
+ _isok--;
+ nocast=0;
+ fprintf(fd, " = ");
+ }
+ putname(fd, "qrecv(", now->lft, m, ", ");
+ fprintf(fd, "XX-1, %d, ", i);
+ fprintf(fd, "%d)", (v->rgt || now->val >= 2)?0:1);
+
+ if (v->lft->ntyp != CONST
+ && v->lft->ntyp != EVAL
+ && strcmp(v->lft->sym->name, "_") != 0
+ && (v->lft->ntyp != NAME
+ || v->lft->sym->type != CHAN))
+ { fprintf(fd, ";\n#ifdef VAR_RANGES");
+ fprintf(fd, "\n\t\tlogval(\"");
+ withprocname = terse = nocast = 1;
+ _isok++;
+ putstmnt(fd,v->lft,m);
+ withprocname = terse = nocast = 0;
+ fprintf(fd, "\", ");
+ putstmnt(fd,v->lft,m);
+ _isok--;
+ fprintf(fd, ");\n#endif\n");
+ fprintf(fd, "\t\t");
+ }
+ }
+ fprintf(fd, ";\n\t\t");
+
+ fprintf(fd, "\n#ifdef HAS_CODE\n");
+ fprintf(fd, "\t\tif (readtrail && gui) {\n");
+ fprintf(fd, "\t\t\tchar simtmp[32];\n");
+ putname(fd, "\t\t\tsprintf(simvals, \"%%d?\", ", now->lft, m, ");\n");
+ _isok++;
+ for (v = now->rgt, i = 0; v; v = v->rgt, i++)
+ { if (v->lft->ntyp != EVAL)
+ { cat3("\t\tsprintf(simtmp, \"%%d\", ", v->lft, "); strcat(simvals, simtmp);");
+ } else
+ { cat3("\t\tsprintf(simtmp, \"%%d\", ", v->lft->lft, "); strcat(simvals, simtmp);");
+ }
+ if (v->rgt)
+ fprintf(fd, "\t\tstrcat(simvals, \",\");\n");
+ }
+ _isok--;
+ fprintf(fd, "\t\t}\n");
+ fprintf(fd, "#endif\n\t\t");
+
+ if (u_sync)
+ { putname(fd, "if (q_zero(", now->lft, m, "))");
+ fprintf(fd, "\n\t\t{ boq = -1;\n");
+
+ fprintf(fd, "#ifndef NOFAIR\n"); /* NEW 3.0.8 */
+ fprintf(fd, "\t\t\tif (fairness\n");
+ fprintf(fd, "\t\t\t&& !(trpt->o_pm&32)\n");
+ fprintf(fd, "\t\t\t&& (now._a_t&2)\n");
+ fprintf(fd, "\t\t\t&& now._cnt[now._a_t&1] == II+2)\n");
+ fprintf(fd, "\t\t\t{ now._cnt[now._a_t&1] -= 1;\n");
+ fprintf(fd, "#ifdef VERI\n");
+ fprintf(fd, "\t\t\t if (II == 1)\n");
+ fprintf(fd, "\t\t\t now._cnt[now._a_t&1] = 1;\n");
+ fprintf(fd, "#endif\n");
+ fprintf(fd, "#ifdef DEBUG\n");
+ fprintf(fd, "\t\t\tprintf(\"%%3d: proc %%d fairness \", depth, II);\n");
+ fprintf(fd, "\t\t\tprintf(\"Rule 2: --cnt to %%d (%%d)\\n\",\n");
+ fprintf(fd, "\t\t\t now._cnt[now._a_t&1], now._a_t);\n");
+ fprintf(fd, "#endif\n");
+ fprintf(fd, "\t\t\t trpt->o_pm |= (32|64);\n");
+ fprintf(fd, "\t\t\t}\n");
+ fprintf(fd, "#endif\n");
+
+ fprintf(fd, "\n\t\t}");
+ }
+ break;
+
+ case 'R':
+ if (!terse && !TestOnly && has_xu)
+ { fprintf(fd, "\n#ifndef XUSAFE\n\t\t");
+ putname(fd, "(!(q_claim[", now->lft, m, "]&1) || ");
+ fprintf(fd, "q_R_check(");
+ putname(fd, "", now->lft, m, ", II)) &&\n\t\t");
+ putname(fd, "(!(q_claim[", now->lft, m, "]&2) || ");
+ putname(fd, "q_S_check(", now->lft, m, ", II)) &&");
+ fprintf(fd, "\n#endif\n\t\t");
+ }
+ if (u_sync>0)
+ putname(fd, "not_RV(", now->lft, m, ") && \\\n\t\t");
+
+ for (v = now->rgt, i=j=0; v; v = v->rgt, i++)
+ if (v->lft->ntyp != CONST
+ && v->lft->ntyp != EVAL)
+ { j++; continue;
+ }
+ if (now->val == 0 || i == j)
+ { putname(fd, "(q_len(", now->lft, m, ") > 0");
+ for (v = now->rgt, i=0; v; v = v->rgt, i++)
+ { if (v->lft->ntyp != CONST
+ && v->lft->ntyp != EVAL)
+ continue;
+ fprintf(fd, " \\\n\t\t&& qrecv(");
+ putname(fd, "", now->lft, m, ", ");
+ fprintf(fd, "0, %d, 0) == ", i);
+ if (v->lft->ntyp == CONST)
+ putstmnt(fd, v->lft, m);
+ else /* EVAL */
+ putstmnt(fd, v->lft->lft, m);
+ }
+ fprintf(fd, ")");
+ } else
+ { putname(fd, "Q_has(", now->lft, m, "");
+ for (v = now->rgt, i=0; v; v = v->rgt, i++)
+ { if (v->lft->ntyp == CONST)
+ { fprintf(fd, ", 1, ");
+ putstmnt(fd, v->lft, m);
+ } else if (v->lft->ntyp == EVAL)
+ { fprintf(fd, ", 1, ");
+ putstmnt(fd, v->lft->lft, m);
+ } else
+ fprintf(fd, ", 0, 0");
+ }
+ for ( ; i < Mpars; i++)
+ fprintf(fd, ", 0, 0");
+ fprintf(fd, ")");
+ }
+ break;
+
+ case 'c':
+ preruse(fd, now->lft); /* preconditions */
+ cat3("if (!(", now->lft, "))\n\t\t\t");
+ Bailout(fd, "");
+ break;
+
+ case ELSE:
+ if (!GenCode)
+ { if (separate == 2)
+ fprintf(fd, "if (o_pm&1)\n\t\t\t");
+ else
+ fprintf(fd, "if (trpt->o_pm&1)\n\t\t\t");
+ Bailout(fd, "");
+ } else
+ { fprintf(fd, "/* else */");
+ }
+ break;
+
+ case '?':
+ if (now->lft)
+ { cat3("( (", now->lft, ") ? ");
+ }
+ if (now->rgt)
+ { cat3("(", now->rgt->lft, ") : ");
+ cat3("(", now->rgt->rgt, ") )");
+ }
+ break;
+
+ case ASGN:
+ if (has_enabled)
+ fprintf(fd, "if (TstOnly) return 1;\n\t\t");
+ _isok++;
+
+ if (!GenCode)
+ { if (multi_oval)
+ { char tempbuf[64];
+ check_needed();
+ sprintf(tempbuf, "(trpt+1)->bup.ovals[%d] = ",
+ multi_oval-1);
+ multi_oval++;
+ cat3(tempbuf, now->lft, ";\n\t\t");
+ } else
+ { cat3("(trpt+1)->bup.oval = ", now->lft, ";\n\t\t");
+ } }
+ nocast = 1; putstmnt(fd,now->lft,m); nocast = 0;
+ fprintf(fd," = ");
+ _isok--;
+ putstmnt(fd,now->rgt,m);
+
+ if (now->sym->type != CHAN
+ || verbose > 0)
+ { fprintf(fd, ";\n#ifdef VAR_RANGES");
+ fprintf(fd, "\n\t\tlogval(\"");
+ withprocname = terse = nocast = 1;
+ _isok++;
+ putstmnt(fd,now->lft,m);
+ withprocname = terse = nocast = 0;
+ fprintf(fd, "\", ");
+ putstmnt(fd,now->lft,m);
+ _isok--;
+ fprintf(fd, ");\n#endif\n");
+ fprintf(fd, "\t\t");
+ }
+ break;
+
+ case PRINT:
+ if (has_enabled)
+ fprintf(fd, "if (TstOnly) return 1;\n\t\t");
+#ifdef PRINTF
+ fprintf(fd, "printf(%s", now->sym->name);
+#else
+ fprintf(fd, "Printf(%s", now->sym->name);
+#endif
+ for (v = now->lft; v; v = v->rgt)
+ { cat2(", ", v->lft);
+ }
+ fprintf(fd, ")");
+ break;
+
+ case PRINTM:
+ if (has_enabled)
+ fprintf(fd, "if (TstOnly) return 1;\n\t\t");
+ fprintf(fd, "printm(");
+ if (now->lft && now->lft->ismtyp)
+ fprintf(fd, "%d", now->lft->val);
+ else
+ putstmnt(fd, now->lft, m);
+ fprintf(fd, ")");
+ break;
+
+ case NAME:
+ if (!nocast && now->sym && Sym_typ(now) < SHORT)
+ putname(fd, "((int)", now, m, ")");
+ else
+ putname(fd, "", now, m, "");
+ break;
+
+ case 'p':
+ putremote(fd, now, m);
+ break;
+
+ case 'q':
+ if (terse)
+ fprintf(fd, "%s", now->sym->name);
+ else
+ fprintf(fd, "%d", remotelab(now));
+ break;
+
+ case C_EXPR:
+ fprintf(fd, "(");
+ plunk_expr(fd, now->sym->name);
+#if 1
+ fprintf(fd, ")");
+#else
+ fprintf(fd, ") /* %s */ ", now->sym->name);
+#endif
+ break;
+
+ case C_CODE:
+ fprintf(fd, "/* %s */\n\t\t", now->sym->name);
+ if (has_enabled)
+ fprintf(fd, "if (TstOnly) return 1;\n\t\t");
+ if (!GenCode) /* not in d_step */
+ { fprintf(fd, "sv_save();\n\t\t");
+ /* store the old values for reverse moves */
+ }
+ plunk_inline(fd, now->sym->name, 1);
+ if (!GenCode)
+ { fprintf(fd, "\n"); /* state changed, capture it */
+ fprintf(fd, "#if defined(C_States) && (HAS_TRACK==1)\n");
+ fprintf(fd, "\t\tc_update((uchar *) &(now.c_state[0]));\n");
+ fprintf(fd, "#endif\n");
+ }
+ break;
+
+ case ASSERT:
+ if (has_enabled)
+ fprintf(fd, "if (TstOnly) return 1;\n\t\t");
+
+ cat3("assert(", now->lft, ", ");
+ terse = nocast = 1;
+ cat3("\"", now->lft, "\", II, tt, t)");
+ terse = nocast = 0;
+ break;
+
+ case '.':
+ case BREAK:
+ case GOTO:
+ if (Pid == eventmapnr)
+ fprintf(fd, "Uerror(\"cannot get here\")");
+ putskip(m);
+ break;
+
+ case '@':
+ if (Pid == eventmapnr)
+ { fprintf(fd, "return 0");
+ break;
+ }
+
+ if (has_enabled)
+ { fprintf(fd, "if (TstOnly)\n\t\t\t");
+ fprintf(fd, "return (II+1 == now._nr_pr);\n\t\t");
+ }
+ fprintf(fd, "if (!delproc(1, II)) ");
+ Bailout(fd, "");
+ break;
+
+ default:
+ printf("spin: bad node type %d (.m) - line %d\n",
+ now->ntyp, now->ln);
+ fflush(tm);
+ alldone(1);
+ }
+}
+
+void
+putname(FILE *fd, char *pre, Lextok *n, int m, char *suff) /* varref */
+{ Symbol *s = n->sym;
+ lineno = n->ln; Fname = n->fn;
+
+ if (!s)
+ fatal("no name - putname", (char *) 0);
+
+ if (s->context && context && s->type)
+ s = findloc(s); /* it's a local var */
+
+ if (!s)
+ { fprintf(fd, "%s%s%s", pre, n->sym->name, suff);
+ return;
+ }
+ if (!s->type) /* not a local name */
+ s = lookup(s->name); /* must be a global */
+
+ if (!s->type)
+ { if (strcmp(pre, ".") != 0)
+ non_fatal("undeclared variable '%s'", s->name);
+ s->type = INT;
+ }
+
+ if (s->type == PROCTYPE)
+ fatal("proctype-name '%s' used as array-name", s->name);
+
+ fprintf(fd, pre);
+ if (!terse && !s->owner && evalindex != 1)
+ { if (s->context
+ || strcmp(s->name, "_p") == 0
+ || strcmp(s->name, "_pid") == 0)
+ { fprintf(fd, "((P%d *)this)->", Pid);
+ } else
+ { int x = strcmp(s->name, "_");
+ if (!(s->hidden&1) && x != 0)
+ fprintf(fd, "now.");
+ if (x == 0 && _isok == 0)
+ fatal("attempt to read value of '_'", 0);
+ } }
+
+ if (withprocname
+ && s->context
+ && strcmp(pre, "."))
+ fprintf(fd, "%s:", s->context->name);
+
+ if (evalindex != 1)
+ fprintf(fd, "%s", s->name);
+
+ if (s->nel != 1)
+ { if (no_arrays)
+ {
+ non_fatal("ref to array element invalid in this context",
+ (char *)0);
+ printf("\thint: instead of, e.g., x[rs] qu[3], use\n");
+ printf("\tchan nm_3 = qu[3]; x[rs] nm_3;\n");
+ printf("\tand use nm_3 in sends/recvs instead of qu[3]\n");
+ }
+ /* an xr or xs reference to an array element
+ * becomes an exclusion tag on the array itself -
+ * which could result in invalidly labeling
+ * operations on other elements of this array to
+ * be also safe under the partial order reduction
+ * (see procedure has_global())
+ */
+
+ if (evalindex == 2)
+ { fprintf(fd, "[%%d]");
+ } else if (evalindex == 1)
+ { evalindex = 0; /* no good if index is indexed array */
+ fprintf(fd, ", ");
+ putstmnt(fd, n->lft, m);
+ evalindex = 1;
+ } else
+ { if (terse
+ || (n->lft
+ && n->lft->ntyp == CONST
+ && n->lft->val < s->nel)
+ || (!n->lft && s->nel > 0))
+ { cat3("[", n->lft, "]");
+ } else
+ { cat3("[ Index(", n->lft, ", ");
+ fprintf(fd, "%d) ]", s->nel);
+ }
+ }
+ }
+ if (s->type == STRUCT && n->rgt && n->rgt->lft)
+ { putname(fd, ".", n->rgt->lft, m, "");
+ }
+ fprintf(fd, suff);
+}
+
+void
+putremote(FILE *fd, Lextok *n, int m) /* remote reference */
+{ int promoted = 0;
+ int pt;
+
+ if (terse)
+ { fprintf(fd, "%s", n->lft->sym->name); /* proctype name */
+ if (n->lft->lft)
+ { fprintf(fd, "[");
+ putstmnt(fd, n->lft->lft, m); /* pid */
+ fprintf(fd, "]");
+ }
+ fprintf(fd, ".%s", n->sym->name);
+ } else
+ { if (Sym_typ(n) < SHORT)
+ { promoted = 1;
+ fprintf(fd, "((int)");
+ }
+
+ pt = fproc(n->lft->sym->name);
+ fprintf(fd, "((P%d *)Pptr(", pt);
+ if (n->lft->lft)
+ { fprintf(fd, "BASE+");
+ putstmnt(fd, n->lft->lft, m);
+ } else
+ fprintf(fd, "f_pid(%d)", pt);
+ fprintf(fd, "))->%s", n->sym->name);
+ }
+ if (n->rgt)
+ { fprintf(fd, "[");
+ putstmnt(fd, n->rgt, m); /* array var ref */
+ fprintf(fd, "]");
+ }
+ if (promoted) fprintf(fd, ")");
+}
+
+static int
+getweight(Lextok *n)
+{ /* this piece of code is a remnant of early versions
+ * of the verifier -- in the current version of Spin
+ * only non-zero values matter - so this could probably
+ * simply return 1 in all cases.
+ */
+ switch (n->ntyp) {
+ case 'r': return 4;
+ case 's': return 2;
+ case TIMEOUT: return 1;
+ case 'c': if (has_typ(n->lft, TIMEOUT)) return 1;
+ }
+ return 3;
+}
+
+int
+has_typ(Lextok *n, int m)
+{
+ if (!n) return 0;
+ if (n->ntyp == m) return 1;
+ return (has_typ(n->lft, m) || has_typ(n->rgt, m));
+}
+
+static int runcount, opcount;
+
+static void
+do_count(Lextok *n, int checkop)
+{
+ if (!n) return;
+
+ switch (n->ntyp) {
+ case RUN:
+ runcount++;
+ break;
+ default:
+ if (checkop) opcount++;
+ break;
+ }
+ do_count(n->lft, checkop && (n->ntyp != RUN));
+ do_count(n->rgt, checkop);
+}
+
+void
+count_runs(Lextok *n)
+{
+ runcount = opcount = 0;
+ do_count(n, 1);
+ if (runcount > 1)
+ fatal("more than one run operator in expression", "");
+ if (runcount == 1 && opcount > 1)
+ fatal("use of run operator in compound expression", "");
+}
+
+void
+any_runs(Lextok *n)
+{
+ runcount = opcount = 0;
+ do_count(n, 0);
+ if (runcount >= 1)
+ fatal("run operator used in invalid context", "");
+}
diff --git a/sys/src/cmd/spin/pangen2.h b/sys/src/cmd/spin/pangen2.h
new file mode 100755
index 000000000..2df6a0b42
--- /dev/null
+++ b/sys/src/cmd/spin/pangen2.h
@@ -0,0 +1,858 @@
+/***** spin: pangen2.h *****/
+
+/* Copyright (c) 1989-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 */
+
+static char *Nvr1[] = { /* allow separate compilation */
+ "#ifdef VERI",
+ "void",
+ "check_claim(int st)",
+ "{",
+ " if (st == endclaim)",
+ " uerror(\"claim violated!\");",
+ " if (stopstate[VERI][st])",
+ " uerror(\"end state in claim reached\");",
+ "}",
+ "#endif",
+ 0,
+};
+
+static char *Pre0[] = {
+"#ifdef SC",
+ "#define _FILE_OFFSET_BITS 64", /* to allow file sizes greater than 2Gb */
+"#endif",
+ "#include <stdio.h>",
+ "#include <signal.h>",
+ "#include <stdlib.h>",
+ "#include <stdarg.h>",
+ "#include <string.h>",
+ "#include <ctype.h>",
+ "#include <errno.h>",
+ "#if defined(WIN32) || defined(WIN64)",
+ "#include <time.h>",
+ "#else",
+ "#include <unistd.h>",
+ "#include <sys/times.h>", /* new 4.3.0 */
+ "#endif",
+ "#include <sys/types.h>", /* defines off_t */
+ "#include <sys/stat.h>",
+ "#include <fcntl.h>",
+ "#define Offsetof(X, Y) ((unsigned long)(&(((X *)0)->Y)))",
+ "#ifndef max",
+ "#define max(a,b) (((a)<(b)) ? (b) : (a))",
+ "#endif",
+ "#ifndef PRINTF",
+ "int Printf(const char *fmt, ...); /* prototype only */",
+ "#endif",
+ 0,
+};
+
+static char *Preamble[] = {
+
+ "#ifdef CNTRSTACK",
+ "#define onstack_now() (LL[trpt->j6] && LL[trpt->j7])",
+ "#define onstack_put() LL[trpt->j6]++; LL[trpt->j7]++",
+ "#define onstack_zap() LL[trpt->j6]--; LL[trpt->j7]--",
+ "#endif",
+
+ "#if !defined(SAFETY) && !defined(NOCOMP)",
+ /*
+ * V_A identifies states in the current statespace
+ * A_V identifies states in the 'other' statespace
+ * S_A remembers how many leading bytes in the sv
+ * are used for these markers + fairness bits
+ */
+ "#define V_A (((now._a_t&1)?2:1) << (now._a_t&2))",
+ "#define A_V (((now._a_t&1)?1:2) << (now._a_t&2))",
+ "int S_A = 0;",
+ "#else",
+ "#define V_A 0",
+ "#define A_V 0",
+ "#define S_A 0",
+ "#endif",
+
+"#ifdef MA",
+ "#undef onstack_now",
+ "#undef onstack_put",
+ "#undef onstack_zap",
+ "#define onstack_put() ;",
+ "#define onstack_zap() gstore((char *) &now, vsize, 4)",
+"#else",
+ "#if defined(FULLSTACK) && !defined(BITSTATE)",
+ "#define onstack_put() trpt->ostate = Lstate",
+ "#define onstack_zap() { \\",
+ " if (trpt->ostate) \\",
+ " trpt->ostate->tagged = \\",
+ " (S_A)? (trpt->ostate->tagged&~V_A) : 0; \\",
+ " }",
+ "#endif",
+"#endif",
+ "struct H_el {",
+ " struct H_el *nxt;",
+ "#ifdef FULLSTACK",
+ " unsigned int tagged;",
+ "#if defined(BITSTATE) && !defined(NOREDUCE) && !defined(SAFETY)",
+ " unsigned int proviso;", /* uses just 1 bit 0/1 */
+ "#endif",
+ "#endif",
+ "#if defined(CHECK) || (defined(COLLAPSE) && !defined(FULLSTACK))",
+ " unsigned long st_id;",
+ "#endif",
+ "#ifdef COLLAPSE",
+ "#if VECTORSZ<65536",
+ " unsigned short ln;", /* length of vector */
+ "#else",
+ " unsigned long ln;", /* length of vector */
+ "#endif",
+ "#endif",
+ "#if !defined(SAFETY) || defined(REACH)",
+ " unsigned int D;",
+ "#endif",
+ " unsigned state;",
+ "} **H_tab, **S_Tab;\n",
+
+ "typedef struct Trail {",
+ " int st; /* current state */",
+ " uchar pr; /* process id */",
+ " uchar tau; /* 8 bit-flags */",
+ " uchar o_pm; /* 8 more bit-flags */",
+ "#if 0",
+ " Meaning of bit-flags:",
+ " tau&1 -> timeout enabled",
+ " tau&2 -> request to enable timeout 1 level up (in claim)",
+ " tau&4 -> current transition is a claim move",
+ " tau&8 -> current transition is an atomic move",
+ " tau&16 -> last move was truncated on stack",
+ " tau&32 -> current transition is a preselected move",
+ " tau&64 -> at least one next state is not on the stack",
+ " tau&128 -> current transition is a stutter move",
+
+ " o_pm&1 -> the current pid moved -- implements else",
+ " o_pm&2 -> this is an acceptance state",
+ " o_pm&4 -> this is a progress state",
+ " o_pm&8 -> fairness alg rule 1 undo mark",
+ " o_pm&16 -> fairness alg rule 3 undo mark",
+ " o_pm&32 -> fairness alg rule 2 undo mark",
+ " o_pm&64 -> the current proc applied rule2",
+ " o_pm&128 -> a fairness, dummy move - all procs blocked",
+ "#endif",
+ "#if defined(FULLSTACK) && defined(MA) && !defined(BFS)",
+ " uchar proviso;",
+ "#endif",
+ "#ifndef BFS",
+ " uchar o_n, o_ot; /* to save locals */",
+ "#endif",
+ " uchar o_m;",
+ "#ifdef EVENT_TRACE",
+ "#if nstates_event<256",
+ " uchar o_event;",
+ "#else",
+ " unsigned short o_event;",
+ "#endif",
+ "#endif",
+ " int o_tt;",
+ "#ifndef BFS",
+ " short o_To;",
+ "#ifdef RANDOMIZE",
+ " short oo_i;",
+ "#endif",
+ "#endif",
+ "#if defined(HAS_UNLESS) && !defined(BFS)",
+ " int e_state; /* if escape trans - state of origin */",
+ "#endif",
+ "#if (defined(FULLSTACK) && !defined(MA)) || defined(BFS)",
+ " struct H_el *ostate; /* pointer to stored state */",
+ "#endif",
+ /* CNTRSTACK when !NOREDUCE && BITSTATE && SAFETY, uses LL[] */
+ "#if defined(CNTRSTACK) && !defined(BFS)",
+ " long j6, j7;",
+ "#endif",
+ " Trans *o_t;", /* transition fct, next state */
+ "#ifdef HAS_SORTED",
+ " short ipt;", /* insertion slot in q */
+ "#endif",
+ " union {",
+ " int oval;", /* single backup value of variable */
+ " int *ovals;", /* ptr to multiple values */
+ " } bup;",
+ "} Trail;",
+ "Trail *trail, *trpt;",
+
+ "FILE *efd;",
+ "uchar *this;",
+ "long maxdepth=10000;",
+ "long omaxdepth=10000;",
+ "#ifdef SC", /* stack cycling */
+ "char *stackfile;",
+ "#endif",
+ "uchar *SS, *LL;",
+ "uchar HASH_NR = 0;",
+ "",
+ "double memcnt = (double) 0;",
+ "double memlim = (double) (1<<30);",
+ "",
+ "/* for emalloc: */",
+ "static char *have;",
+ "static long left = 0L;",
+ "static double fragment = (double) 0;",
+ "static unsigned long grow;",
+ "",
+ "unsigned int HASH_CONST[] = {",
+ " /* asuming 4 bytes per int */",
+ " 0x88888EEF, 0x00400007,",
+ " 0x04c11db7, 0x100d4e63,",
+ " 0x0fc22f87, 0x3ff0c3ff,",
+ " 0x38e84cd7, 0x02b148e9,",
+ " 0x98b2e49d, 0xb616d379,",
+ " 0xa5247fd9, 0xbae92a15,",
+ " 0xb91c8bc5, 0x8e5880f3,",
+ " 0xacd7c069, 0xb4c44bb3,",
+ " 0x2ead1fb7, 0x8e428171,",
+ " 0xdbebd459, 0x828ae611,",
+ " 0x6cb25933, 0x86cdd651,",
+ " 0x9e8f5f21, 0xd5f8d8e7,",
+ " 0x9c4e956f, 0xb5cf2c71,",
+ " 0x2e805a6d, 0x33fc3a55,",
+ " 0xaf203ed1, 0xe31f5909,",
+ " 0x5276db35, 0x0c565ef7,",
+ " 0x273d1aa5, 0x8923b1dd,",
+ " 0",
+ "};",
+ "int mreached=0, done=0, errors=0, Nrun=1;",
+ "double nstates=0, nlinks=0, truncs=0, truncs2=0;",
+ "double nlost=0, nShadow=0, hcmp=0, ngrabs=0;",
+ "#ifdef BFS",
+ "double midrv=0, failedrv=0, revrv=0;",
+ "#endif",
+ "unsigned long nr_states=0; /* nodes in DFA */",
+ "long Fa=0, Fh=0, Zh=0, Zn=0;",
+ "long PUT=0, PROBE=0, ZAPS=0;",
+ "long Ccheck=0, Cholds=0;",
+ "int a_cycles=0, upto=1, strict=0, verbose = 0, signoff = 0;",
+ "#ifdef HAS_CODE",
+ "int gui = 0, coltrace = 0, readtrail = 0, whichtrail = 0, onlyproc = -1, silent = 0;",
+ "#endif",
+ "int state_tables=0, fairness=0, no_rck=0, Nr_Trails=0;",
+ "char simvals[128];",
+ "#ifndef INLINE",
+ "int TstOnly=0;",
+ "#endif",
+ "unsigned long mask, nmask;",
+ "#ifdef BITSTATE",
+ "int ssize=23; /* 1 Mb */",
+ "#else",
+ "int ssize=19; /* 512K slots */",
+ "#endif",
+ "int hmax=0, svmax=0, smax=0;",
+ "int Maxbody=0, XX;",
+ "uchar *noptr; /* used by macro Pptr(x) */",
+ "#ifdef VAR_RANGES",
+ "void logval(char *, int);",
+ "void dumpranges(void);",
+ "#endif",
+
+ "#ifdef MA",
+ "#define INLINE_REV",
+ "extern void dfa_init(unsigned short);",
+ "extern int dfa_member(unsigned long);",
+ "extern int dfa_store(uchar *);",
+ "unsigned int maxgs = 0;",
+ "#endif",
+
+ "State comp_now; /* compressed state vector */",
+ "State comp_msk;",
+ "uchar *Mask = (uchar *) &comp_msk;",
+ "#ifdef COLLAPSE",
+ "State comp_tmp;",
+ "static char *scratch = (char *) &comp_tmp;",
+ "#endif",
+
+ "Stack *stack; /* for queues, processes */",
+ "Svtack *svtack; /* for old state vectors */",
+ "#ifdef BITSTATE",
+ "static unsigned hfns = 3; /* new default */",
+ "#endif",
+ "static unsigned long j1;",
+ "static unsigned long K1, K2;",
+ "static unsigned long j2, j3, j4;",
+ "#ifdef BITSTATE",
+#ifndef POWOW
+ "static long udmem;",
+#endif
+ "#endif",
+ "static long A_depth = 0;",
+ "long depth = 0;", /* not static to support -S2 option, but possible clash with embedded code */
+ "static uchar warned = 0, iterative = 0, like_java = 0, every_error = 0;",
+ "static uchar noasserts = 0, noends = 0, bounded = 0;",
+ "#if SYNC>0 && ASYNC==0",
+ "void set_recvs(void);",
+ "int no_recvs(int);",
+ "#endif",
+ "#if SYNC",
+ "#define IfNotBlocked if (boq != -1) continue;",
+ "#define UnBlock boq = -1",
+ "#else",
+ "#define IfNotBlocked /* cannot block */",
+ "#define UnBlock /* don't bother */",
+ "#endif\n",
+ "#ifdef BITSTATE",
+ "int (*bstore)(char *, int);",
+ "int bstore_reg(char *, int);",
+#ifndef POWOW
+ "int bstore_mod(char *, int);",
+#endif
+ "#endif",
+ "void active_procs(void);",
+ "void cleanup(void);",
+ "void do_the_search(void);",
+ "void find_shorter(int);",
+ "void iniglobals(void);",
+ "void stopped(int);",
+ "void wrapup(void);",
+ "int *grab_ints(int);",
+ "void ungrab_ints(int *, int);",
+ 0,
+};
+
+static char *Tail[] = {
+ "Trans *",
+ "settr( int t_id, int a, int b, int c, int d,",
+ " char *t, int g, int tpe0, int tpe1)",
+ "{ Trans *tmp = (Trans *) emalloc(sizeof(Trans));\n",
+ " tmp->atom = a&(6|32); /* only (2|8|32) have meaning */",
+ " if (!g) tmp->atom |= 8; /* no global references */",
+ " tmp->st = b;",
+ " tmp->tpe[0] = tpe0;",
+ " tmp->tpe[1] = tpe1;",
+ " tmp->tp = t;",
+ " tmp->t_id = t_id;",
+ " tmp->forw = c;",
+ " tmp->back = d;",
+ " return tmp;",
+ "}\n",
+ "Trans *",
+ "cpytr(Trans *a)",
+ "{ Trans *tmp = (Trans *) emalloc(sizeof(Trans));\n",
+ " int i;",
+ " tmp->atom = a->atom;",
+ " tmp->st = a->st;",
+ "#ifdef HAS_UNLESS",
+ " tmp->e_trans = a->e_trans;",
+ " for (i = 0; i < HAS_UNLESS; i++)",
+ " tmp->escp[i] = a->escp[i];",
+ "#endif",
+ " tmp->tpe[0] = a->tpe[0];",
+ " tmp->tpe[1] = a->tpe[1];",
+ " for (i = 0; i < 6; i++)",
+ " { tmp->qu[i] = a->qu[i];",
+ " tmp->ty[i] = a->ty[i];",
+ " }",
+ " tmp->tp = (char *) emalloc(strlen(a->tp)+1);",
+ " strcpy(tmp->tp, a->tp);",
+ " tmp->t_id = a->t_id;",
+ " tmp->forw = a->forw;",
+ " tmp->back = a->back;",
+ " return tmp;",
+ "}\n",
+ "#ifndef NOREDUCE",
+ "int",
+ "srinc_set(int n)",
+ "{ if (n <= 2) return LOCAL;",
+ " if (n <= 2+ DELTA) return Q_FULL_F; /* 's' or nfull */",
+ " if (n <= 2+2*DELTA) return Q_EMPT_F; /* 'r' or nempty */",
+ " if (n <= 2+3*DELTA) return Q_EMPT_T; /* empty */",
+ " if (n <= 2+4*DELTA) return Q_FULL_T; /* full */",
+ " if (n == 5*DELTA) return GLOBAL;",
+ " if (n == 6*DELTA) return TIMEOUT_F;",
+ " if (n == 7*DELTA) return ALPHA_F;",
+ " Uerror(\"cannot happen srinc_class\");",
+ " return BAD;",
+ "}",
+ "int",
+ "srunc(int n, int m)",
+ "{ switch(m) {",
+ " case Q_FULL_F: return n-2;",
+ " case Q_EMPT_F: return n-2-DELTA;",
+ " case Q_EMPT_T: return n-2-2*DELTA;",
+ " case Q_FULL_T: return n-2-3*DELTA;",
+ " case ALPHA_F:",
+ " case TIMEOUT_F: return 257; /* non-zero, and > MAXQ */",
+ " }",
+ " Uerror(\"cannot happen srunc\");",
+ " return 0;",
+ "}",
+ "#endif",
+ "int cnt;",
+ "#ifdef HAS_UNLESS",
+ "int",
+ "isthere(Trans *a, int b)", /* is b already in a's list? */
+ "{ Trans *t;",
+ " for (t = a; t; t = t->nxt)",
+ " if (t->t_id == b)",
+ " return 1;",
+ " return 0;",
+ "}",
+ "#endif",
+ "#ifndef NOREDUCE",
+ "int",
+ "mark_safety(Trans *t) /* for conditional safety */",
+ "{ int g = 0, i, j, k;",
+ "",
+ " if (!t) return 0;",
+ " if (t->qu[0])",
+ " return (t->qu[1])?2:1; /* marked */",
+ "",
+ " for (i = 0; i < 2; i++)",
+ " { j = srinc_set(t->tpe[i]);",
+ " if (j >= GLOBAL && j != ALPHA_F)",
+ " return -1;",
+ " if (j != LOCAL)",
+ " { k = srunc(t->tpe[i], j);",
+ " if (g == 0",
+ " || t->qu[0] != k",
+ " || t->ty[0] != j)",
+ " { t->qu[g] = k;",
+ " t->ty[g] = j;",
+ " g++;",
+ " } } }",
+ " return g;",
+ "}",
+ "#endif",
+ "void",
+ "retrans(int n, int m, int is, short srcln[], uchar reach[])",
+ " /* process n, with m states, is=initial state */",
+ "{ Trans *T0, *T1, *T2, *T3;",
+ " int i, k;",
+ "#ifndef NOREDUCE",
+ " int g, h, j, aa;",
+ "#endif",
+ "#ifdef HAS_UNLESS",
+ " int p;",
+ "#endif",
+ " if (state_tables >= 4)",
+ " { printf(\"STEP 1 proctype %%s\\n\", ",
+ " procname[n]);",
+ " for (i = 1; i < m; i++)",
+ " for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
+ " crack(n, i, T0, srcln);",
+ " return;",
+ " }",
+ " do {",
+ " for (i = 1, cnt = 0; i < m; i++)",
+ " { T2 = trans[n][i];",
+ " T1 = T2?T2->nxt:(Trans *)0;",
+ "/* prescan: */ for (T0 = T1; T0; T0 = T0->nxt)",
+ "/* choice in choice */ { if (T0->st && trans[n][T0->st]",
+ " && trans[n][T0->st]->nxt)",
+ " break;",
+ " }",
+ "#if 0",
+ " if (T0)",
+ " printf(\"\\tstate %%d / %%d: choice in choice\\n\",",
+ " i, T0->st);",
+ "#endif",
+ " if (T0)",
+ " for (T0 = T1; T0; T0 = T0->nxt)",
+ " { T3 = trans[n][T0->st];",
+ " if (!T3->nxt)",
+ " { T2->nxt = cpytr(T0);",
+ " T2 = T2->nxt;",
+ " imed(T2, T0->st, n, i);",
+ " continue;",
+ " }",
+ " do { T3 = T3->nxt;",
+ " T2->nxt = cpytr(T3);",
+ " T2 = T2->nxt;",
+ " imed(T2, T0->st, n, i);",
+ " } while (T3->nxt);",
+ " cnt++;",
+ " }",
+ " }",
+ " } while (cnt);",
+
+ " if (state_tables >= 3)",
+ " { printf(\"STEP 2 proctype %%s\\n\", ",
+ " procname[n]);",
+ " for (i = 1; i < m; i++)",
+ " for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
+ " crack(n, i, T0, srcln);",
+ " return;",
+ " }",
+ " for (i = 1; i < m; i++)",
+ " { if (trans[n][i] && trans[n][i]->nxt) /* optimize */",
+ " { T1 = trans[n][i]->nxt;",
+ "#if 0",
+ " printf(\"\\t\\tpull %%d (%%d) to %%d\\n\",",
+ " T1->st, T1->forw, i);",
+ "#endif",
+ " if (!trans[n][T1->st]) continue;",
+ " T0 = cpytr(trans[n][T1->st]);",
+ " trans[n][i] = T0;",
+ " reach[T1->st] = 1;",
+ " imed(T0, T1->st, n, i);",
+ " for (T1 = T1->nxt; T1; T1 = T1->nxt)",
+ " {",
+ "#if 0",
+ " printf(\"\\t\\tpull %%d (%%d) to %%d\\n\",",
+ " T1->st, T1->forw, i);",
+ "#endif",
+ " if (!trans[n][T1->st]) continue;",
+ " T0->nxt = cpytr(trans[n][T1->st]);",
+ " T0 = T0->nxt;",
+ " reach[T1->st] = 1;",
+ " imed(T0, T1->st, n, i);",
+ " } } }",
+ " if (state_tables >= 2)",
+ " { printf(\"STEP 3 proctype %%s\\n\", ",
+ " procname[n]);",
+ " for (i = 1; i < m; i++)",
+ " for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
+ " crack(n, i, T0, srcln);",
+ " return;",
+ " }",
+ "#ifdef HAS_UNLESS",
+ " for (i = 1; i < m; i++)",
+ " { if (!trans[n][i]) continue;",
+ " /* check for each state i if an",
+ " * escape to some state p is defined",
+ " * if so, copy and mark p's transitions",
+ " * and prepend them to the transition-",
+ " * list of state i",
+ " */",
+ " if (!like_java) /* the default */",
+ " { for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
+ " for (k = HAS_UNLESS-1; k >= 0; k--)",
+ " { if (p = T0->escp[k])",
+ " for (T1 = trans[n][p]; T1; T1 = T1->nxt)",
+ " { if (isthere(trans[n][i], T1->t_id))",
+ " continue;",
+ " T2 = cpytr(T1);",
+ " T2->e_trans = p;",
+ " T2->nxt = trans[n][i];",
+ " trans[n][i] = T2;",
+ " } }",
+ " } else /* outermost unless checked first */",
+ " { Trans *T4;",
+ " T4 = T3 = (Trans *) 0;",
+ " for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
+ " for (k = HAS_UNLESS-1; k >= 0; k--)",
+ " { if (p = T0->escp[k])",
+ " for (T1 = trans[n][p]; T1; T1 = T1->nxt)",
+ " { if (isthere(trans[n][i], T1->t_id))",
+ " continue;",
+ " T2 = cpytr(T1);",
+ " T2->nxt = (Trans *) 0;",
+ " T2->e_trans = p;",
+ " if (T3) T3->nxt = T2;",
+ " else T4 = T2;",
+ " T3 = T2;",
+ " } }",
+ " if (T4)",
+ " { T3->nxt = trans[n][i];",
+ " trans[n][i] = T4;",
+ " }",
+ " }",
+ " }",
+ "#endif",
+
+ "#ifndef NOREDUCE",
+ " for (i = 1; i < m; i++)",
+ " {",
+ " if (a_cycles)",
+ " { /* moves through these states are visible */",
+ "#if PROG_LAB>0 && defined(HAS_NP)",
+ " if (progstate[n][i])",
+ " goto degrade;",
+ " for (T1 = trans[n][i]; T1; T1 = T1->nxt)",
+ " if (progstate[n][T1->st])",
+ " goto degrade;",
+ "#endif",
+ " if (accpstate[n][i] || visstate[n][i])",
+ " goto degrade;",
+ " for (T1 = trans[n][i]; T1; T1 = T1->nxt)",
+ " if (accpstate[n][T1->st])",
+ " goto degrade;",
+ " }",
+ " T1 = trans[n][i];",
+ " if (!T1) continue;",
+ " g = mark_safety(T1); /* V3.3.1 */",
+ " if (g < 0) goto degrade; /* global */",
+ " /* check if mixing of guards preserves reduction */",
+ " if (T1->nxt)",
+ " { k = 0;",
+ " for (T0 = T1; T0; T0 = T0->nxt)",
+ " { if (!(T0->atom&8))",
+ " goto degrade;",
+ " for (aa = 0; aa < 2; aa++)",
+ " { j = srinc_set(T0->tpe[aa]);",
+ " if (j >= GLOBAL && j != ALPHA_F)",
+ " goto degrade;",
+ " if (T0->tpe[aa]",
+ " && T0->tpe[aa]",
+ " != T1->tpe[0])",
+ " k = 1;",
+ " } }",
+ " /* g = 0; V3.3.1 */",
+ " if (k) /* non-uniform selection */",
+ " for (T0 = T1; T0; T0 = T0->nxt)",
+ " for (aa = 0; aa < 2; aa++)",
+ " { j = srinc_set(T0->tpe[aa]);",
+ " if (j != LOCAL)",
+ " { k = srunc(T0->tpe[aa], j);",
+ " for (h = 0; h < 6; h++)",
+ " if (T1->qu[h] == k",
+ " && T1->ty[h] == j)",
+ " break;",
+ " if (h >= 6)",
+ " { T1->qu[g%%6] = k;",
+ " T1->ty[g%%6] = j;",
+ " g++;",
+ " } } }",
+ " if (g > 6)",
+ " { T1->qu[0] = 0; /* turn it off */",
+ " printf(\"pan: warning, line %%d, \",",
+ " srcln[i]);",
+ " printf(\"too many stmnt types (%%d)\",",
+ " g);",
+ " printf(\" in selection\\n\");",
+ " goto degrade;",
+ " }",
+ " }",
+ " /* mark all options global if >=1 is global */",
+ " for (T1 = trans[n][i]; T1; T1 = T1->nxt)",
+ " if (!(T1->atom&8)) break;",
+ " if (T1)",
+ "degrade: for (T1 = trans[n][i]; T1; T1 = T1->nxt)",
+ " T1->atom &= ~8; /* mark as unsafe */",
+
+ " /* can only mix 'r's or 's's if on same chan */",
+ " /* and not mixed with other local operations */",
+ " T1 = trans[n][i];",
+
+ " if (!T1 || T1->qu[0]) continue;",
+
+ " j = T1->tpe[0];",
+ " if (T1->nxt && T1->atom&8)",
+ " { if (j == 5*DELTA)",
+ " { printf(\"warning: line %%d \", srcln[i]);",
+ " printf(\"mixed condition \");",
+ " printf(\"(defeats reduction)\\n\");",
+ " goto degrade;",
+ " }",
+ " for (T0 = T1; T0; T0 = T0->nxt)",
+ " for (aa = 0; aa < 2; aa++)",
+ " if (T0->tpe[aa] && T0->tpe[aa] != j)",
+ " { printf(\"warning: line %%d \", srcln[i]);",
+ " printf(\"[%%d-%%d] mixed %%stion \",",
+ " T0->tpe[aa], j, ",
+ " (j==5*DELTA)?\"condi\":\"selec\");",
+ " printf(\"(defeats reduction)\\n\");",
+ " printf(\" '%%s' <-> '%%s'\\n\",",
+ " T1->tp, T0->tp);",
+ " goto degrade;",
+ " } }",
+ " }",
+ "#endif",
+ " for (i = 1; i < m; i++)", /* R */
+ " { T2 = trans[n][i];",
+ " if (!T2",
+ " || T2->nxt",
+ " || strncmp(T2->tp, \".(goto)\", 7)",
+ " || !stopstate[n][i])",
+ " continue;",
+ " stopstate[n][T2->st] = 1;",
+ " }",
+ " if (state_tables)",
+ " { printf(\"proctype \");",
+ " if (!strcmp(procname[n], \":init:\"))",
+ " printf(\"init\\n\");",
+ " else",
+ " printf(\"%%s\\n\", procname[n]);",
+ " for (i = 1; i < m; i++)",
+ " reach[i] = 1;",
+ " tagtable(n, m, is, srcln, reach);",
+ " } else",
+ " for (i = 1; i < m; i++)",
+ " { int nrelse;",
+ " if (strcmp(procname[n], \":never:\") != 0)",
+ " { for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
+ " { if (T0->st == i",
+ " && strcmp(T0->tp, \"(1)\") == 0)",
+ " { printf(\"error: proctype '%%s' \",",
+ " procname[n]);",
+ " printf(\"line %%d, state %%d: has un\",",
+ " srcln[i], i);",
+ " printf(\"conditional self-loop\\n\");",
+ " pan_exit(1);",
+ " } } }",
+ " nrelse = 0;",
+ " for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
+ " { if (strcmp(T0->tp, \"else\") == 0)",
+ " nrelse++;",
+ " }",
+ " if (nrelse > 1)",
+ " { printf(\"error: proctype '%%s' state\",",
+ " procname[n]);",
+ " printf(\" %%d, inherits %%d\", i, nrelse);",
+ " printf(\" 'else' stmnts\\n\");",
+ " pan_exit(1);",
+ " } }",
+ " if (!state_tables && strcmp(procname[n], \":never:\") == 0)",
+ " { int h = 0;",
+ " for (i = 1; i < m; i++)",
+ " for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
+ " if (T0->forw > h) h = T0->forw;",
+ " h++;",
+ " frm_st0 = (short *) emalloc(h * sizeof(short));",
+ " for (i = 1; i < m; i++)",
+ " for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
+ " frm_st0[T0->forw] = i;",
+ " }",
+ "}",
+ "void",
+ "imed(Trans *T, int v, int n, int j) /* set intermediate state */",
+ "{ progstate[n][T->st] |= progstate[n][v];",
+ " accpstate[n][T->st] |= accpstate[n][v];",
+ " stopstate[n][T->st] |= stopstate[n][v];",
+ " mapstate[n][j] = T->st;",
+ "}",
+ "void",
+ "tagtable(int n, int m, int is, short srcln[], uchar reach[])",
+ "{ Trans *z;\n",
+ " if (is >= m || !trans[n][is]",
+ " || is <= 0 || reach[is] == 0)",
+ " return;",
+ " reach[is] = 0;",
+ " if (state_tables)",
+ " for (z = trans[n][is]; z; z = z->nxt)",
+ " crack(n, is, z, srcln);",
+ " for (z = trans[n][is]; z; z = z->nxt)",
+ " {",
+ "#ifdef HAS_UNLESS",
+ " int i, j;",
+ "#endif",
+ " tagtable(n, m, z->st, srcln, reach);",
+ "#ifdef HAS_UNLESS",
+ " for (i = 0; i < HAS_UNLESS; i++)",
+ " { j = trans[n][is]->escp[i];",
+ " if (!j) break;",
+ " tagtable(n, m, j, srcln, reach);",
+ " }",
+ "#endif",
+ " }",
+ "}",
+ "void",
+ "crack(int n, int j, Trans *z, short srcln[])",
+ "{ int i;\n",
+ " if (!z) return;",
+ " printf(\"\tstate %%3d -(tr %%3d)-> state %%3d \",",
+ " j, z->forw, z->st);",
+ " printf(\"[id %%3d tp %%3d\", z->t_id, z->tpe[0]);",
+ " if (z->tpe[1]) printf(\",%%d\", z->tpe[1]);",
+ "#ifdef HAS_UNLESS",
+ " if (z->e_trans)",
+ " printf(\" org %%3d\", z->e_trans);",
+ " else if (state_tables >= 2)",
+ " for (i = 0; i < HAS_UNLESS; i++)",
+ " { if (!z->escp[i]) break;",
+ " printf(\" esc %%d\", z->escp[i]);",
+ " }",
+ "#endif",
+ " printf(\"]\");",
+ " printf(\" [%%s%%s%%s%%s%%s] line %%d => \",",
+ " z->atom&6?\"A\":z->atom&32?\"D\":\"-\",",
+ " accpstate[n][j]?\"a\" :\"-\",",
+ " stopstate[n][j]?\"e\" : \"-\",",
+ " progstate[n][j]?\"p\" : \"-\",",
+ " z->atom & 8 ?\"L\":\"G\",",
+ " srcln[j]);",
+ " for (i = 0; z->tp[i]; i++)",
+ " if (z->tp[i] == \'\\n\')",
+ " printf(\"\\\\n\");",
+ " else",
+ " putchar(z->tp[i]);",
+ " if (z->qu[0])",
+ " { printf(\"\\t[\");",
+ " for (i = 0; i < 6; i++)",
+ " if (z->qu[i])",
+ " printf(\"(%%d,%%d)\",",
+ " z->qu[i], z->ty[i]);",
+ " printf(\"]\");",
+ " }",
+ " printf(\"\\n\");",
+ " fflush(stdout);",
+ "}",
+ "",
+ "#ifdef VAR_RANGES",
+ "#define BYTESIZE 32 /* 2^8 : 2^3 = 256:8 = 32 */",
+ "",
+ "typedef struct Vr_Ptr {",
+ " char *nm;",
+ " uchar vals[BYTESIZE];",
+ " struct Vr_Ptr *nxt;",
+ "} Vr_Ptr;",
+ "Vr_Ptr *ranges = (Vr_Ptr *) 0;",
+ "",
+ "void",
+ "logval(char *s, int v)",
+ "{ Vr_Ptr *tmp;",
+ "",
+ " if (v<0 || v > 255) return;",
+ " for (tmp = ranges; tmp; tmp = tmp->nxt)",
+ " if (!strcmp(tmp->nm, s))",
+ " goto found;",
+ " tmp = (Vr_Ptr *) emalloc(sizeof(Vr_Ptr));",
+ " tmp->nxt = ranges;",
+ " ranges = tmp;",
+ " tmp->nm = s;",
+ "found:",
+ " tmp->vals[(v)/8] |= 1<<((v)%%8);",
+ "}",
+ "",
+ "void",
+ "dumpval(uchar X[], int range)",
+ "{ int w, x, i, j = -1;",
+ "",
+ " for (w = i = 0; w < range; w++)",
+ " for (x = 0; x < 8; x++, i++)",
+ " {",
+ "from: if ((X[w] & (1<<x)))",
+ " { printf(\"%%d\", i);",
+ " j = i;",
+ " goto upto;",
+ " } }",
+ " return;",
+ " for (w = 0; w < range; w++)",
+ " for (x = 0; x < 8; x++, i++)",
+ " {",
+ "upto: if (!(X[w] & (1<<x)))",
+ " { if (i-1 == j)",
+ " printf(\", \");",
+ " else",
+ " printf(\"-%%d, \", i-1);",
+ " goto from;",
+ " } }",
+ " if (j >= 0 && j != 255)",
+ " printf(\"-255\");",
+ "}",
+ "",
+ "void",
+ "dumpranges(void)",
+ "{ Vr_Ptr *tmp;",
+ " printf(\"\\nValues assigned within \");",
+ " printf(\"interval [0..255]:\\n\");",
+ " for (tmp = ranges; tmp; tmp = tmp->nxt)",
+ " { printf(\"\\t%%s\\t: \", tmp->nm);",
+ " dumpval(tmp->vals, BYTESIZE);",
+ " printf(\"\\n\");",
+ " }",
+ "}",
+ "#endif",
+ 0,
+};
diff --git a/sys/src/cmd/spin/pangen3.c b/sys/src/cmd/spin/pangen3.c
new file mode 100755
index 000000000..4feb80ab1
--- /dev/null
+++ b/sys/src/cmd/spin/pangen3.c
@@ -0,0 +1,391 @@
+/***** spin: pangen3.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include "spin.h"
+#include "y.tab.h"
+
+extern FILE *th;
+extern int claimnr, eventmapnr;
+
+typedef struct SRC {
+ short ln, st; /* linenr, statenr */
+ Symbol *fn; /* filename */
+ struct SRC *nxt;
+} SRC;
+
+static int col;
+static Symbol *lastfnm;
+static Symbol lastdef;
+static int lastfrom;
+static SRC *frst = (SRC *) 0;
+static SRC *skip = (SRC *) 0;
+
+extern void sr_mesg(FILE *, int, int);
+
+static void
+putnr(int n)
+{
+ if (col++ == 8)
+ { fprintf(th, "\n\t");
+ col = 1;
+ }
+ fprintf(th, "%3d, ", n);
+}
+
+static void
+putfnm(int j, Symbol *s)
+{
+ if (lastfnm && lastfnm == s && j != -1)
+ return;
+
+ if (lastfnm)
+ fprintf(th, "{ %s, %d, %d },\n\t",
+ lastfnm->name,
+ lastfrom,
+ j-1);
+ lastfnm = s;
+ lastfrom = j;
+}
+
+static void
+putfnm_flush(int j)
+{
+ if (lastfnm)
+ fprintf(th, "{ %s, %d, %d }\n",
+ lastfnm->name,
+ lastfrom, j);
+}
+
+void
+putskip(int m) /* states that need not be reached */
+{ SRC *tmp;
+
+ for (tmp = skip; tmp; tmp = tmp->nxt)
+ if (tmp->st == m)
+ return;
+ tmp = (SRC *) emalloc(sizeof(SRC));
+ tmp->st = (short) m;
+ tmp->nxt = skip;
+ skip = tmp;
+}
+
+void
+unskip(int m) /* a state that needs to be reached after all */
+{ SRC *tmp, *lst=(SRC *)0;
+
+ for (tmp = skip; tmp; lst = tmp, tmp = tmp->nxt)
+ if (tmp->st == m)
+ { if (tmp == skip)
+ skip = skip->nxt;
+ else
+ lst->nxt = tmp->nxt;
+ break;
+ }
+}
+
+void
+putsrc(Element *e) /* match states to source lines */
+{ SRC *tmp;
+ int n, m;
+
+ if (!e || !e->n) return;
+
+ n = e->n->ln;
+ m = e->seqno;
+
+ for (tmp = frst; tmp; tmp = tmp->nxt)
+ if (tmp->st == m)
+ { if (tmp->ln != n || tmp->fn != e->n->fn)
+ printf("putsrc mismatch %d - %d, file %s\n", n,
+ tmp->ln, tmp->fn->name);
+ return;
+ }
+ tmp = (SRC *) emalloc(sizeof(SRC));
+ tmp->ln = (short) n;
+ tmp->st = (short) m;
+ tmp->fn = e->n->fn;
+ tmp->nxt = frst;
+ frst = tmp;
+}
+
+static void
+dumpskip(int n, int m)
+{ SRC *tmp, *lst;
+ int j;
+
+ fprintf(th, "uchar reached%d [] = {\n\t", m);
+ for (j = 0, col = 0; j <= n; j++)
+ { lst = (SRC *) 0;
+ for (tmp = skip; tmp; lst = tmp, tmp = tmp->nxt)
+ if (tmp->st == j)
+ { putnr(1);
+ if (lst)
+ lst->nxt = tmp->nxt;
+ else
+ skip = tmp->nxt;
+ break;
+ }
+ if (!tmp)
+ putnr(0);
+ }
+ fprintf(th, "};\n");
+ if (m == claimnr)
+ fprintf(th, "#define reached_claim reached%d\n", m);
+ if (m == eventmapnr)
+ fprintf(th, "#define reached_event reached%d\n", m);
+
+ skip = (SRC *) 0;
+}
+
+void
+dumpsrc(int n, int m)
+{ SRC *tmp, *lst;
+ int j;
+
+ fprintf(th, "short src_ln%d [] = {\n\t", m);
+ for (j = 0, col = 0; j <= n; j++)
+ { lst = (SRC *) 0;
+ for (tmp = frst; tmp; lst = tmp, tmp = tmp->nxt)
+ if (tmp->st == j)
+ { putnr(tmp->ln);
+ break;
+ }
+ if (!tmp)
+ putnr(0);
+ }
+ fprintf(th, "};\n");
+
+ lastfnm = (Symbol *) 0;
+ lastdef.name = "\"-\"";
+ fprintf(th, "S_F_MAP src_file%d [] = {\n\t", m);
+ for (j = 0, col = 0; j <= n; j++)
+ { lst = (SRC *) 0;
+ for (tmp = frst; tmp; lst = tmp, tmp = tmp->nxt)
+ if (tmp->st == j)
+ { putfnm(j, tmp->fn);
+ if (lst)
+ lst->nxt = tmp->nxt;
+ else
+ frst = tmp->nxt;
+ break;
+ }
+ if (!tmp)
+ putfnm(j, &lastdef);
+ }
+ putfnm_flush(j);
+ fprintf(th, "};\n");
+
+ if (m == claimnr)
+ fprintf(th, "#define src_claim src_ln%d\n", m);
+ if (m == eventmapnr)
+ fprintf(th, "#define src_event src_ln%d\n", m);
+
+ frst = (SRC *) 0;
+ dumpskip(n, m);
+}
+
+#define Cat0(x) comwork(fd,now->lft,m); fprintf(fd, x); \
+ comwork(fd,now->rgt,m)
+#define Cat1(x) fprintf(fd,"("); Cat0(x); fprintf(fd,")")
+#define Cat2(x,y) fprintf(fd,x); comwork(fd,y,m)
+#define Cat3(x,y,z) fprintf(fd,x); comwork(fd,y,m); fprintf(fd,z)
+
+static int
+symbolic(FILE *fd, Lextok *tv)
+{ Lextok *n; extern Lextok *Mtype;
+ int cnt = 1;
+
+ if (tv->ismtyp)
+ for (n = Mtype; n; n = n->rgt, cnt++)
+ if (cnt == tv->val)
+ { fprintf(fd, "%s", n->lft->sym->name);
+ return 1;
+ }
+ return 0;
+}
+
+static void
+comwork(FILE *fd, Lextok *now, int m)
+{ Lextok *v;
+ int i, j;
+
+ if (!now) { fprintf(fd, "0"); return; }
+ switch (now->ntyp) {
+ case CONST: sr_mesg(fd, now->val, now->ismtyp); break;
+ case '!': Cat3("!(", now->lft, ")"); break;
+ case UMIN: Cat3("-(", now->lft, ")"); break;
+ case '~': Cat3("~(", now->lft, ")"); break;
+
+ case '/': Cat1("/"); break;
+ case '*': Cat1("*"); break;
+ case '-': Cat1("-"); break;
+ case '+': Cat1("+"); break;
+ case '%': Cat1("%%"); break;
+ case '&': Cat1("&"); break;
+ case '^': Cat1("^"); break;
+ case '|': Cat1("|"); break;
+ case LE: Cat1("<="); break;
+ case GE: Cat1(">="); break;
+ case GT: Cat1(">"); break;
+ case LT: Cat1("<"); break;
+ case NE: Cat1("!="); break;
+ case EQ: Cat1("=="); break;
+ case OR: Cat1("||"); break;
+ case AND: Cat1("&&"); break;
+ case LSHIFT: Cat1("<<"); break;
+ case RSHIFT: Cat1(">>"); break;
+
+ case RUN: fprintf(fd, "run %s(", now->sym->name);
+ for (v = now->lft; v; v = v->rgt)
+ if (v == now->lft)
+ { comwork(fd, v->lft, m);
+ } else
+ { Cat2(",", v->lft);
+ }
+ fprintf(fd, ")");
+ break;
+
+ case LEN: putname(fd, "len(", now->lft, m, ")");
+ break;
+ case FULL: putname(fd, "full(", now->lft, m, ")");
+ break;
+ case EMPTY: putname(fd, "empty(", now->lft, m, ")");
+ break;
+ case NFULL: putname(fd, "nfull(", now->lft, m, ")");
+ break;
+ case NEMPTY: putname(fd, "nempty(", now->lft, m, ")");
+ break;
+
+ case 's': putname(fd, "", now->lft, m, now->val?"!!":"!");
+ for (v = now->rgt, i=0; v; v = v->rgt, i++)
+ { if (v != now->rgt) fprintf(fd,",");
+ if (!symbolic(fd, v->lft))
+ comwork(fd,v->lft,m);
+ }
+ break;
+ case 'r': putname(fd, "", now->lft, m, "?");
+ switch (now->val) {
+ case 0: break;
+ case 1: fprintf(fd, "?"); break;
+ case 2: fprintf(fd, "<"); break;
+ case 3: fprintf(fd, "?<"); break;
+ }
+ for (v = now->rgt, i=0; v; v = v->rgt, i++)
+ { if (v != now->rgt) fprintf(fd,",");
+ if (!symbolic(fd, v->lft))
+ comwork(fd,v->lft,m);
+ }
+ if (now->val >= 2)
+ fprintf(fd, ">");
+ break;
+ case 'R': putname(fd, "", now->lft, m, now->val?"??[":"?[");
+ for (v = now->rgt, i=0; v; v = v->rgt, i++)
+ { if (v != now->rgt) fprintf(fd,",");
+ if (!symbolic(fd, v->lft))
+ comwork(fd,v->lft,m);
+ }
+ fprintf(fd, "]");
+ break;
+
+ case ENABLED: Cat3("enabled(", now->lft, ")");
+ break;
+
+ case EVAL: Cat3("eval(", now->lft, ")");
+ break;
+
+ case NONPROGRESS:
+ fprintf(fd, "np_");
+ break;
+
+ case PC_VAL: Cat3("pc_value(", now->lft, ")");
+ break;
+
+ case 'c': Cat3("(", now->lft, ")");
+ break;
+
+ case '?': if (now->lft)
+ { Cat3("( (", now->lft, ") -> ");
+ }
+ if (now->rgt)
+ { Cat3("(", now->rgt->lft, ") : ");
+ Cat3("(", now->rgt->rgt, ") )");
+ }
+ break;
+
+ case ASGN: comwork(fd,now->lft,m);
+ fprintf(fd," = ");
+ comwork(fd,now->rgt,m);
+ break;
+
+ case PRINT: { char c, buf[512];
+ strncpy(buf, now->sym->name, 510);
+ for (i = j = 0; i < 510; i++, j++)
+ { c = now->sym->name[i];
+ buf[j] = c;
+ if (c == '\\') buf[++j] = c;
+ if (c == '\"') buf[j] = '\'';
+ if (c == '\0') break;
+ }
+ if (now->ntyp == PRINT)
+ fprintf(fd, "printf");
+ else
+ fprintf(fd, "annotate");
+ fprintf(fd, "(%s", buf);
+ }
+ for (v = now->lft; v; v = v->rgt)
+ { Cat2(",", v->lft);
+ }
+ fprintf(fd, ")");
+ break;
+ case PRINTM: fprintf(fd, "printm(");
+ comwork(fd, now->lft, m);
+ fprintf(fd, ")");
+ break;
+ case NAME: putname(fd, "", now, m, "");
+ break;
+ case 'p': putremote(fd, now, m);
+ break;
+ case 'q': fprintf(fd, "%s", now->sym->name);
+ break;
+ case C_EXPR:
+ case C_CODE: fprintf(fd, "{%s}", now->sym->name);
+ break;
+ case ASSERT: Cat3("assert(", now->lft, ")");
+ break;
+ case '.': fprintf(fd, ".(goto)"); break;
+ case GOTO: fprintf(fd, "goto %s", now->sym->name); break;
+ case BREAK: fprintf(fd, "break"); break;
+ case ELSE: fprintf(fd, "else"); break;
+ case '@': fprintf(fd, "-end-"); break;
+
+ case D_STEP: fprintf(fd, "D_STEP"); break;
+ case ATOMIC: fprintf(fd, "ATOMIC"); break;
+ case NON_ATOMIC: fprintf(fd, "sub-sequence"); break;
+ case IF: fprintf(fd, "IF"); break;
+ case DO: fprintf(fd, "DO"); break;
+ case UNLESS: fprintf(fd, "unless"); break;
+ case TIMEOUT: fprintf(fd, "timeout"); break;
+ default: if (isprint(now->ntyp))
+ fprintf(fd, "'%c'", now->ntyp);
+ else
+ fprintf(fd, "%d", now->ntyp);
+ break;
+ }
+}
+
+void
+comment(FILE *fd, Lextok *now, int m)
+{ extern short terse, nocast;
+
+ terse=nocast=1;
+ comwork(fd, now, m);
+ terse=nocast=0;
+}
diff --git a/sys/src/cmd/spin/pangen3.h b/sys/src/cmd/spin/pangen3.h
new file mode 100755
index 000000000..931a598f5
--- /dev/null
+++ b/sys/src/cmd/spin/pangen3.h
@@ -0,0 +1,940 @@
+/***** spin: pangen3.h *****/
+
+/* Copyright (c) 1989-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 */
+
+static char *Head0[] = {
+ "#if defined(BFS) && defined(REACH)",
+ "#undef REACH", /* redundant with bfs */
+ "#endif",
+ "#ifdef VERI",
+ "#define BASE 1",
+ "#else",
+ "#define BASE 0",
+ "#endif",
+ "typedef struct Trans {",
+ " short atom; /* if &2 = atomic trans; if &8 local */",
+ "#ifdef HAS_UNLESS",
+ " short escp[HAS_UNLESS]; /* lists the escape states */",
+ " short e_trans; /* if set, this is an escp-trans */",
+ "#endif",
+ " short tpe[2]; /* class of operation (for reduction) */",
+ " short qu[6]; /* for conditional selections: qid's */",
+ " uchar ty[6]; /* ditto: type's */",
+ "#ifdef NIBIS",
+ " short om; /* completion status of preselects */",
+ "#endif",
+ " char *tp; /* src txt of statement */",
+ " int st; /* the nextstate */",
+ " int t_id; /* transition id, unique within proc */",
+ " int forw; /* index forward transition */",
+ " int back; /* index return transition */",
+ " struct Trans *nxt;",
+ "} Trans;\n",
+ "#define qptr(x) (((uchar *)&now)+(int)q_offset[x])",
+ "#define pptr(x) (((uchar *)&now)+(int)proc_offset[x])",
+/* "#define Pptr(x) ((proc_offset[x])?pptr(x):noptr)", */
+ "extern uchar *Pptr(int);",
+
+ "#define q_sz(x) (((Q0 *)qptr(x))->Qlen)\n",
+ "#ifndef VECTORSZ",
+ "#define VECTORSZ 1024 /* sv size in bytes */",
+ "#endif\n",
+ 0,
+};
+
+static char *Header[] = {
+ "#ifdef VERBOSE",
+ "#ifndef CHECK",
+ "#define CHECK",
+ "#endif",
+ "#ifndef DEBUG",
+ "#define DEBUG",
+ "#endif",
+ "#endif",
+ "#ifdef SAFETY",
+ "#ifndef NOFAIR",
+ "#define NOFAIR",
+ "#endif",
+ "#endif",
+ "#ifdef NOREDUCE",
+ "#ifndef XUSAFE",
+ "#define XUSAFE",
+ "#endif",
+ "#if !defined(SAFETY) && !defined(MA)",
+ "#define FULLSTACK",
+ "#endif",
+ "#else",
+ "#ifdef BITSTATE",
+ "#ifdef SAFETY && !defined(HASH64)",
+ "#define CNTRSTACK",
+ "#else",
+ "#define FULLSTACK",
+ "#endif",
+ "#else",
+ "#define FULLSTACK",
+ "#endif",
+ "#endif",
+ "#ifdef BITSTATE",
+ "#ifndef NOCOMP",
+ "#define NOCOMP",
+ "#endif",
+ "#if !defined(LC) && defined(SC)",
+ "#define LC",
+ "#endif",
+ "#endif",
+ "#if defined(COLLAPSE2) || defined(COLLAPSE3) || defined(COLLAPSE4)",
+ "/* accept the above for backward compatibility */",
+ "#define COLLAPSE",
+ "#endif",
+ "#ifdef HC",
+ "#undef HC",
+ "#define HC4",
+ "#endif",
+ "#ifdef HC0", /* 32 bits */
+ "#define HC 0",
+ "#endif",
+ "#ifdef HC1", /* 32+8 bits */
+ "#define HC 1",
+ "#endif",
+ "#ifdef HC2", /* 32+16 bits */
+ "#define HC 2",
+ "#endif",
+ "#ifdef HC3", /* 32+24 bits */
+ "#define HC 3",
+ "#endif",
+ "#ifdef HC4", /* 32+32 bits - combine with -DMA=8 */
+ "#define HC 4",
+ "#endif",
+ "#ifdef COLLAPSE",
+ "unsigned long ncomps[256+2];",
+ "#endif",
+
+ "#define MAXQ 255",
+ "#define MAXPROC 255",
+ "#define WS sizeof(long) /* word size in bytes */",
+ "typedef struct Stack { /* for queues and processes */",
+ "#if VECTORSZ>32000",
+ " int o_delta;",
+ " int o_offset;",
+ " int o_skip;",
+ " int o_delqs;",
+ "#else",
+ " short o_delta;",
+ " short o_offset;",
+ " short o_skip;",
+ " short o_delqs;",
+ "#endif",
+ " short o_boq;",
+ "#ifndef XUSAFE",
+ " char *o_name;",
+ "#endif",
+ " char *body;",
+ " struct Stack *nxt;",
+ " struct Stack *lst;",
+ "} Stack;\n",
+ "typedef struct Svtack { /* for complete state vector */",
+ "#if VECTORSZ>32000",
+ " int o_delta;",
+ " int m_delta;",
+ "#else",
+ " short o_delta; /* current size of frame */",
+ " short m_delta; /* maximum size of frame */",
+ "#endif",
+ "#if SYNC",
+ " short o_boq;",
+ "#endif",
+ 0,
+};
+
+static char *Header0[] = {
+ " char *body;",
+ " struct Svtack *nxt;",
+ " struct Svtack *lst;",
+ "} Svtack;\n",
+ "Trans ***trans; /* 1 ptr per state per proctype */\n",
+ "#if defined(FULLSTACK) || defined(BFS)",
+ "struct H_el *Lstate;",
+ "#endif",
+ "int depthfound = -1; /* loop detection */",
+ "#if VECTORSZ>32000",
+ "int proc_offset[MAXPROC];",
+ "int q_offset[MAXQ];",
+ "#else",
+ "short proc_offset[MAXPROC];",
+ "short q_offset[MAXQ];",
+ "#endif",
+ "uchar proc_skip[MAXPROC];",
+ "uchar q_skip[MAXQ];",
+ "unsigned long vsize; /* vector size in bytes */",
+ "#ifdef SVDUMP",
+ "int vprefix=0, svfd; /* runtime option -pN */",
+ "#endif",
+ "char *tprefix = \"trail\"; /* runtime option -tsuffix */",
+ "short boq = -1; /* blocked_on_queue status */",
+ 0,
+};
+
+static char *Head1[] = {
+ "typedef struct State {",
+ " uchar _nr_pr;",
+ " uchar _nr_qs;",
+ " uchar _a_t; /* cycle detection */",
+#if 0
+ in _a_t: bits 0,4, and 5 =(1|16|32) are set during a 2nd dfs
+ bit 1 is used as the A-bit for fairness
+ bit 7 (128) is the proviso bit, for reduced 2nd dfs (acceptance)
+#endif
+ "#ifndef NOFAIR",
+ " uchar _cnt[NFAIR]; /* counters, weak fairness */",
+ "#endif",
+
+ "#ifndef NOVSZ",
+#ifdef SOLARIS
+ "#if 0",
+ /* v3.4
+ * noticed alignment problems with some Solaris
+ * compilers, if widest field isn't wordsized
+ */
+#else
+ "#if VECTORSZ<65536",
+#endif
+ " unsigned short _vsz;",
+ "#else",
+ " unsigned long _vsz;",
+ "#endif",
+ "#endif",
+
+ "#ifdef HAS_LAST", /* cannot go before _cnt - see hstore() */
+ " uchar _last; /* pid executed in last step */",
+ "#endif",
+ "#ifdef EVENT_TRACE",
+ "#if nstates_event<256",
+ " uchar _event;",
+ "#else",
+ " unsigned short _event;",
+ "#endif",
+ "#endif",
+ 0,
+};
+
+static char *Addp0[] = {
+ /* addproc(....parlist... */ ")",
+ "{ int j, h = now._nr_pr;",
+ "#ifndef NOCOMP",
+ " int k;",
+ "#endif",
+ " uchar *o_this = this;\n",
+ "#ifndef INLINE",
+ " if (TstOnly) return (h < MAXPROC);",
+ "#endif",
+ "#ifndef NOBOUNDCHECK",
+ "/* redefine Index only within this procedure */",
+ "#undef Index",
+ "#define Index(x, y) Boundcheck(x, y, 0, 0, 0)",
+ "#endif",
+ " if (h >= MAXPROC)",
+ " Uerror(\"too many processes\");",
+ " switch (n) {",
+ " case 0: j = sizeof(P0); break;",
+ 0,
+};
+
+static char *Addp1[] = {
+ " default: Uerror(\"bad proc - addproc\");",
+ " }",
+ " if (vsize%%WS)",
+ " proc_skip[h] = WS-(vsize%%WS);",
+ " else",
+ " proc_skip[h] = 0;",
+ "#ifndef NOCOMP",
+ " for (k = vsize + (int) proc_skip[h]; k > vsize; k--)",
+ " Mask[k-1] = 1; /* align */",
+ "#endif",
+ " vsize += (int) proc_skip[h];",
+ " proc_offset[h] = vsize;",
+ "#ifdef SVDUMP",
+ " if (vprefix > 0)",
+ " { int dummy = 0;",
+ " write(svfd, (uchar *) &dummy, sizeof(int)); /* mark */",
+ " write(svfd, (uchar *) &h, sizeof(int));",
+ " write(svfd, (uchar *) &n, sizeof(int));",
+ "#if VECTORSZ>32000",
+ " write(svfd, (uchar *) &proc_offset[h], sizeof(int));",
+ "#else",
+ " write(svfd, (uchar *) &proc_offset[h], sizeof(short));",
+ "#endif",
+ " write(svfd, (uchar *) &now, vprefix-4*sizeof(int)); /* padd */",
+ " }",
+ "#endif",
+ " now._nr_pr += 1;",
+ " if (fairness && ((int) now._nr_pr + 1 >= (8*NFAIR)/2))",
+ " { printf(\"pan: error: too many processes -- current\");",
+ " printf(\" max is %%d procs (-DNFAIR=%%d)\\n\",",
+ " (8*NFAIR)/2 - 2, NFAIR);",
+ " printf(\"\\trecompile with -DNFAIR=%%d\\n\",",
+ " NFAIR+1);",
+ " pan_exit(1);",
+ " }",
+
+ " vsize += j;",
+ "#ifndef NOVSZ",
+ " now._vsz = vsize;",
+ "#endif",
+ "#ifndef NOCOMP",
+ " for (k = 1; k <= Air[n]; k++)",
+ " Mask[vsize - k] = 1; /* pad */",
+ " Mask[vsize-j] = 1; /* _pid */",
+ "#endif",
+ " hmax = max(hmax, vsize);",
+ " if (vsize >= VECTORSZ)",
+ " { printf(\"pan: error, VECTORSZ too small, recompile pan.c\");",
+ " printf(\" with -DVECTORSZ=N with N>%%d\\n\", vsize);",
+ " Uerror(\"aborting\");",
+ " }",
+ " memset((char *)pptr(h), 0, j);",
+ " this = pptr(h);",
+ " if (BASE > 0 && h > 0)",
+ " ((P0 *)this)->_pid = h-BASE;",
+ " else",
+ " ((P0 *)this)->_pid = h;",
+ " switch (n) {",
+ 0,
+};
+
+static char *Addq0[] = {
+ "int",
+ "addqueue(int n, int is_rv)",
+ "{ int j=0, i = now._nr_qs;",
+ "#ifndef NOCOMP",
+ " int k;",
+ "#endif",
+ " if (i >= MAXQ)",
+ " Uerror(\"too many queues\");",
+ " switch (n) {",
+ 0,
+};
+
+static char *Addq1[] = {
+ " default: Uerror(\"bad queue - addqueue\");",
+ " }",
+ " if (vsize%%WS)",
+ " q_skip[i] = WS-(vsize%%WS);",
+ " else",
+ " q_skip[i] = 0;",
+ "#ifndef NOCOMP",
+ " k = vsize;",
+ "#ifndef BFS",
+ " if (is_rv) k += j;",
+ "#endif",
+ " for (k += (int) q_skip[i]; k > vsize; k--)",
+ " Mask[k-1] = 1;",
+ "#endif",
+ " vsize += (int) q_skip[i];",
+ " q_offset[i] = vsize;",
+ " now._nr_qs += 1;",
+ " vsize += j;",
+ "#ifndef NOVSZ",
+ " now._vsz = vsize;",
+ "#endif",
+ " hmax = max(hmax, vsize);",
+ " if (vsize >= VECTORSZ)",
+ " Uerror(\"VECTORSZ is too small, edit pan.h\");",
+ " memset((char *)qptr(i), 0, j);",
+ " ((Q0 *)qptr(i))->_t = n;",
+ " return i+1;",
+ "}\n",
+ 0,
+};
+
+static char *Addq11[] = {
+ "{ int j; uchar *z;\n",
+ "#ifdef HAS_SORTED",
+ " int k;",
+ "#endif",
+ " if (!into--)",
+ " uerror(\"ref to uninitialized chan name (sending)\");",
+ " if (into >= (int) now._nr_qs || into < 0)",
+ " Uerror(\"qsend bad queue#\");",
+ " z = qptr(into);",
+ " j = ((Q0 *)qptr(into))->Qlen;",
+ " switch (((Q0 *)qptr(into))->_t) {",
+ 0,
+};
+
+static char *Addq2[] = {
+ " case 0: printf(\"queue %%d was deleted\\n\", into+1);",
+ " default: Uerror(\"bad queue - qsend\");",
+ " }",
+ "#ifdef EVENT_TRACE",
+ " if (in_s_scope(into+1))",
+ " require('s', into);",
+ "#endif",
+ "}",
+ "#endif\n",
+ "#if SYNC",
+ "int",
+ "q_zero(int from)",
+ "{ if (!from--)",
+ " { uerror(\"ref to uninitialized chan name (q_zero)\");",
+ " return 0;",
+ " }",
+ " switch(((Q0 *)qptr(from))->_t) {",
+ 0,
+};
+
+static char *Addq3[] = {
+ " case 0: printf(\"queue %%d was deleted\\n\", from+1);",
+ " }",
+ " Uerror(\"bad queue q-zero\");",
+ " return -1;",
+ "}",
+ "int",
+ "not_RV(int from)",
+ "{ if (q_zero(from))",
+ " { printf(\"==>> a test of the contents of a rv \");",
+ " printf(\"channel always returns FALSE\\n\");",
+ " uerror(\"error to poll rendezvous channel\");",
+ " }",
+ " return 1;",
+ "}",
+ "#endif",
+ "#ifndef XUSAFE",
+ "void",
+ "setq_claim(int x, int m, char *s, int y, char *p)",
+ "{ if (x == 0)",
+ " uerror(\"x[rs] claim on uninitialized channel\");",
+ " if (x < 0 || x > MAXQ)",
+ " Uerror(\"cannot happen setq_claim\");",
+ " q_claim[x] |= m;",
+ " p_name[y] = p;",
+ " q_name[x] = s;",
+ " if (m&2) q_S_check(x, y);",
+ " if (m&1) q_R_check(x, y);",
+ "}",
+ "short q_sender[MAXQ+1];",
+ "int",
+ "q_S_check(int x, int who)",
+ "{ if (!q_sender[x])",
+ " { q_sender[x] = who+1;",
+ "#if SYNC",
+ " if (q_zero(x))",
+ " { printf(\"chan %%s (%%d), \",",
+ " q_name[x], x-1);",
+ " printf(\"sndr proc %%s (%%d)\\n\",",
+ " p_name[who], who);",
+ " uerror(\"xs chans cannot be used for rv\");",
+ " }",
+ "#endif",
+ " } else",
+ " if (q_sender[x] != who+1)",
+ " { printf(\"pan: xs assertion violated: \");",
+ " printf(\"access to chan <%%s> (%%d)\\npan: by \",",
+ " q_name[x], x-1);",
+ " if (q_sender[x] > 0 && p_name[q_sender[x]-1])",
+ " printf(\"%%s (proc %%d) and by \",",
+ " p_name[q_sender[x]-1], q_sender[x]-1);",
+ " printf(\"%%s (proc %%d)\\n\",",
+ " p_name[who], who);",
+ " uerror(\"error, partial order reduction invalid\");",
+ " }",
+ " return 1;",
+ "}",
+ "short q_recver[MAXQ+1];",
+ "int",
+ "q_R_check(int x, int who)",
+ "{ if (!q_recver[x])",
+ " { q_recver[x] = who+1;",
+ "#if SYNC",
+ " if (q_zero(x))",
+ " { printf(\"chan %%s (%%d), \",",
+ " q_name[x], x-1);",
+ " printf(\"recv proc %%s (%%d)\\n\",",
+ " p_name[who], who);",
+ " uerror(\"xr chans cannot be used for rv\");",
+ " }",
+ "#endif",
+ " } else",
+ " if (q_recver[x] != who+1)",
+ " { printf(\"pan: xr assertion violated: \");",
+ " printf(\"access to chan %%s (%%d)\\npan: \",",
+ " q_name[x], x-1);",
+ " if (q_recver[x] > 0 && p_name[q_recver[x]-1])",
+ " printf(\"by %%s (proc %%d) and \",",
+ " p_name[q_recver[x]-1], q_recver[x]-1);",
+ " printf(\"by %%s (proc %%d)\\n\",",
+ " p_name[who], who);",
+ " uerror(\"error, partial order reduction invalid\");",
+ " }",
+ " return 1;",
+ "}",
+ "#endif",
+ "int",
+ "q_len(int x)",
+ "{ if (!x--)",
+ " uerror(\"ref to uninitialized chan name (len)\");",
+ " return ((Q0 *)qptr(x))->Qlen;",
+ "}\n",
+ "int",
+ "q_full(int from)",
+ "{ if (!from--)",
+ " uerror(\"ref to uninitialized chan name (qfull)\");",
+ " switch(((Q0 *)qptr(from))->_t) {",
+ 0,
+};
+
+static char *Addq4[] = {
+ " case 0: printf(\"queue %%d was deleted\\n\", from+1);",
+ " }",
+ " Uerror(\"bad queue - q_full\");",
+ " return 0;",
+ "}\n",
+ "#ifdef HAS_UNLESS",
+ "int",
+ "q_e_f(int from)",
+ "{ /* empty or full */",
+ " return !q_len(from) || q_full(from);",
+ "}",
+ "#endif",
+ "#if NQS>0",
+ "int",
+ "qrecv(int from, int slot, int fld, int done)",
+ "{ uchar *z;",
+ " int j, k, r=0;\n",
+ " if (!from--)",
+ " uerror(\"ref to uninitialized chan name (receiving)\");",
+ " if (from >= (int) now._nr_qs || from < 0)",
+ " Uerror(\"qrecv bad queue#\");",
+ " z = qptr(from);",
+ "#ifdef EVENT_TRACE",
+ " if (done && (in_r_scope(from+1)))",
+ " require('r', from);",
+ "#endif",
+ " switch (((Q0 *)qptr(from))->_t) {",
+ 0,
+};
+
+static char *Addq5[] = {
+ " case 0: printf(\"queue %%d was deleted\\n\", from+1);",
+ " default: Uerror(\"bad queue - qrecv\");",
+ " }",
+ " return r;",
+ "}",
+ "#endif\n",
+ "#ifndef BITSTATE",
+ "#ifdef COLLAPSE",
+ "long",
+ "col_q(int i, char *z)",
+ "{ int j=0, k;",
+ " char *x, *y;",
+ " Q0 *ptr = (Q0 *) qptr(i);",
+ " switch (ptr->_t) {",
+ 0,
+};
+
+static char *Code0[] = {
+ "void",
+ "run(void)",
+ "{ /* int i; */",
+ " memset((char *)&now, 0, sizeof(State));",
+ " vsize = (unsigned long) (sizeof(State) - VECTORSZ);",
+ "#ifndef NOVSZ",
+ " now._vsz = vsize;",
+ "#endif",
+ "/* optional provisioning statements, e.g. to */",
+ "/* set hidden variables, used as constants */",
+ "#ifdef PROV",
+ "#include PROV",
+ "#endif",
+ " settable();",
+ 0,
+};
+
+static char *R0[] = {
+ " Maxbody = max(Maxbody, sizeof(P%d));",
+ " reached[%d] = reached%d;",
+ " accpstate[%d] = (uchar *) emalloc(nstates%d);",
+ " progstate[%d] = (uchar *) emalloc(nstates%d);",
+ " stopstate[%d] = (uchar *) emalloc(nstates%d);",
+ " visstate[%d] = (uchar *) emalloc(nstates%d);",
+ " mapstate[%d] = (short *) emalloc(nstates%d * sizeof(short));",
+ "#ifdef HAS_CODE",
+ " NrStates[%d] = nstates%d;",
+ "#endif",
+ " stopstate[%d][endstate%d] = 1;",
+ 0,
+};
+
+static char *R0a[] = {
+ " retrans(%d, nstates%d, start%d, src_ln%d, reached%d);",
+ 0,
+};
+static char *R0b[] = {
+ " if (state_tables)",
+ " { printf(\"\\nTransition Type: \");",
+ " printf(\"A=atomic; D=d_step; L=local; G=global\\n\");",
+ " printf(\"Source-State Labels: \");",
+ " printf(\"p=progress; e=end; a=accept;\\n\");",
+ "#ifdef MERGED",
+ " printf(\"Note: statement merging was used. Only the first\\n\");",
+ " printf(\" stmnt executed in each merge sequence is shown\\n\");",
+ " printf(\" (use spin -a -o3 to disable statement merging)\\n\");",
+ "#endif",
+ " pan_exit(0);",
+ " }",
+ 0,
+};
+
+static char *Code1[] = {
+ "#ifdef NP",
+ "#define ACCEPT_LAB 1 /* at least 1 in np_ */",
+ "#else",
+ "#define ACCEPT_LAB %d /* user-defined accept labels */",
+ "#endif",
+ 0,
+};
+
+static char *Code3[] = {
+ "#define PROG_LAB %d /* progress labels */",
+ 0,
+};
+
+static char *R2[] = {
+ "uchar *accpstate[%d];",
+ "uchar *progstate[%d];",
+ "uchar *reached[%d];",
+ "uchar *stopstate[%d];",
+ "uchar *visstate[%d];",
+ "short *mapstate[%d];",
+ "#ifdef HAS_CODE",
+ "int NrStates[%d];",
+ "#endif",
+ 0,
+};
+static char *R3[] = {
+ " Maxbody = max(Maxbody, sizeof(Q%d));",
+ 0,
+};
+static char *R4[] = {
+ " r_ck(reached%d, nstates%d, %d, src_ln%d, src_file%d);",
+ 0,
+};
+static char *R5[] = {
+ " case %d: j = sizeof(P%d); break;",
+ 0,
+};
+static char *R6[] = {
+ " }",
+ " this = o_this;",
+ " return h-BASE;",
+ "#ifndef NOBOUNDCHECK",
+ "#undef Index",
+ "#define Index(x, y) Boundcheck(x, y, II, tt, t)",
+ "#endif",
+ "}\n",
+ "#if defined(BITSTATE) && defined(COLLAPSE)",
+ "/* just to allow compilation, to generate the error */",
+ "long col_p(int i, char *z) { return 0; }",
+ "long col_q(int i, char *z) { return 0; }",
+ "#endif",
+ "#ifndef BITSTATE",
+ "#ifdef COLLAPSE",
+ "long",
+ "col_p(int i, char *z)",
+ "{ int j, k; unsigned long ordinal(char *, long, short);",
+ " char *x, *y;",
+ " P0 *ptr = (P0 *) pptr(i);",
+ " switch (ptr->_t) {",
+ " case 0: j = sizeof(P0); break;",
+ 0,
+};
+static char *R8a[] = {
+ " default: Uerror(\"bad proctype - collapse\");",
+ " }",
+ " if (z) x = z; else x = scratch;",
+ " y = (char *) ptr; k = proc_offset[i];",
+
+ " for ( ; j > 0; j--, y++)",
+ " if (!Mask[k++]) *x++ = *y;",
+
+ " for (j = 0; j < WS-1; j++)",
+ " *x++ = 0;",
+ " x -= j;",
+ " if (z) return (long) (x - z);",
+ " return ordinal(scratch, x-scratch, (short) (2+ptr->_t));",
+ "}",
+ "#endif",
+ "#endif",
+ 0,
+};
+static char *R8b[] = {
+ " default: Uerror(\"bad qtype - collapse\");",
+ " }",
+ " if (z) x = z; else x = scratch;",
+ " y = (char *) ptr; k = q_offset[i];",
+
+ " /* no need to store the empty slots at the end */",
+ " j -= (q_max[ptr->_t] - ptr->Qlen) * ((j - 2)/q_max[ptr->_t]);",
+
+ " for ( ; j > 0; j--, y++)",
+ " if (!Mask[k++]) *x++ = *y;",
+
+ " for (j = 0; j < WS-1; j++)",
+ " *x++ = 0;",
+ " x -= j;",
+ " if (z) return (long) (x - z);",
+ " return ordinal(scratch, x-scratch, 1); /* chan */",
+ "}",
+ "#endif",
+ "#endif",
+ 0,
+};
+
+static char *R12[] = {
+ "\t\tcase %d: r = ((Q%d *)z)->contents[slot].fld%d; break;",
+ 0,
+};
+char *R13[] = {
+ "int ",
+ "unsend(int into)",
+ "{ int _m=0, j; uchar *z;\n",
+ "#ifdef HAS_SORTED",
+ " int k;",
+ "#endif",
+ " if (!into--)",
+ " uerror(\"ref to uninitialized chan (unsend)\");",
+ " z = qptr(into);",
+ " j = ((Q0 *)z)->Qlen;",
+ " ((Q0 *)z)->Qlen = --j;",
+ " switch (((Q0 *)qptr(into))->_t) {",
+ 0,
+};
+char *R14[] = {
+ " default: Uerror(\"bad queue - unsend\");",
+ " }",
+ " return _m;",
+ "}\n",
+ "void",
+ "unrecv(int from, int slot, int fld, int fldvar, int strt)",
+ "{ int j; uchar *z;\n",
+ " if (!from--)",
+ " uerror(\"ref to uninitialized chan (unrecv)\");",
+ " z = qptr(from);",
+ " j = ((Q0 *)z)->Qlen;",
+ " if (strt) ((Q0 *)z)->Qlen = j+1;",
+ " switch (((Q0 *)qptr(from))->_t) {",
+ 0,
+};
+char *R15[] = {
+ " default: Uerror(\"bad queue - qrecv\");",
+ " }",
+ "}",
+ 0,
+};
+static char *Proto[] = {
+ "",
+ "/** function prototypes **/",
+ "char *emalloc(unsigned long);",
+ "char *Malloc(unsigned long);",
+ "int Boundcheck(int, int, int, int, Trans *);",
+ "int addqueue(int, int);",
+ "/* int atoi(char *); */",
+ "/* int abort(void); */",
+ "int close(int);", /* should probably remove this */
+#if 0
+ "#ifndef SC",
+ "int creat(char *, unsigned short);",
+ "int write(int, void *, unsigned);",
+ "#endif",
+#endif
+ "int delproc(int, int);",
+ "int endstate(void);",
+ "int hstore(char *, int);",
+"#ifdef MA",
+ "int gstore(char *, int, uchar);",
+"#endif",
+ "int q_cond(short, Trans *);",
+ "int q_full(int);",
+ "int q_len(int);",
+ "int q_zero(int);",
+ "int qrecv(int, int, int, int);",
+ "int unsend(int);",
+ "/* void *sbrk(int); */",
+ "void Uerror(char *);",
+ "void assert(int, char *, int, int, Trans *);",
+ "void c_chandump(int);",
+ "void c_globals(void);",
+ "void c_locals(int, int);",
+ "void checkcycles(void);",
+ "void crack(int, int, Trans *, short *);",
+ "void d_hash(uchar *, int);",
+ "void s_hash(uchar *, int);",
+ "void r_hash(uchar *, int);",
+ "void delq(int);",
+ "void do_reach(void);",
+ "void pan_exit(int);",
+ "void exit(int);",
+ "void hinit(void);",
+ "void imed(Trans *, int, int, int);",
+ "void new_state(void);",
+ "void p_restor(int);",
+ "void putpeg(int, int);",
+ "void putrail(void);",
+ "void q_restor(void);",
+ "void retrans(int, int, int, short *, uchar *);",
+ "void settable(void);",
+ "void setq_claim(int, int, char *, int, char *);",
+ "void sv_restor(void);",
+ "void sv_save(void);",
+ "void tagtable(int, int, int, short *, uchar *);",
+ "void uerror(char *);",
+ "void unrecv(int, int, int, int, int);",
+ "void usage(FILE *);",
+ "void wrap_stats(void);",
+ "#if defined(FULLSTACK) && defined(BITSTATE)",
+ "int onstack_now(void);",
+ "void onstack_init(void);",
+ "void onstack_put(void);",
+ "void onstack_zap(void);",
+ "#endif",
+ "#ifndef XUSAFE",
+ "int q_S_check(int, int);",
+ "int q_R_check(int, int);",
+ "uchar q_claim[MAXQ+1];",
+ "char *q_name[MAXQ+1];",
+ "char *p_name[MAXPROC+1];",
+ "#endif",
+ 0,
+};
+
+static char *SvMap[] = {
+ "void",
+ "to_compile(void)",
+ "{ char ctd[1024], carg[64];",
+ "#ifdef BITSTATE",
+ " strcpy(ctd, \"-DBITSTATE \");",
+ "#else",
+ " strcpy(ctd, \"\");",
+ "#endif",
+ "#ifdef NOVSZ",
+ " strcat(ctd, \"-DNOVSZ \");",
+ "#endif",
+ "#ifdef MEMLIM",
+ " sprintf(carg, \"-DMEMLIM=%%d \", MEMLIM);",
+ " strcat(ctd, carg);",
+ "#else",
+ "#ifdef MEMCNT",
+ " sprintf(carg, \"-DMEMCNT=%%d \", MEMCNT);",
+ " strcat(ctd, carg);",
+ "#endif",
+ "#endif",
+ "#ifdef NOCLAIM",
+ " strcat(ctd, \"-DNOCLAIM \");",
+ "#endif",
+ "#ifdef SAFETY",
+ " strcat(ctd, \"-DSAFETY \");",
+ "#else",
+ "#ifdef NOFAIR",
+ " strcat(ctd, \"-DNOFAIR \");",
+ "#else",
+ "#ifdef NFAIR",
+ " if (NFAIR != 2)",
+ " { sprintf(carg, \"-DNFAIR=%%d \", NFAIR);",
+ " strcat(ctd, carg);",
+ " }",
+ "#endif",
+ "#endif",
+ "#endif",
+ "#ifdef NOREDUCE",
+ " strcat(ctd, \"-DNOREDUCE \");",
+ "#else",
+ "#ifdef XUSAFE",
+ " strcat(ctd, \"-DXUSAFE \");",
+ "#endif",
+ "#endif",
+ "#ifdef NP",
+ " strcat(ctd, \"-DNP \");",
+ "#endif",
+ "#ifdef PEG",
+ " strcat(ctd, \"-DPEG \");",
+ "#endif",
+ "#ifdef VAR_RANGES",
+ " strcat(ctd, \"-DVAR_RANGES \");",
+ "#endif",
+ "#ifdef HC0",
+ " strcat(ctd, \"-DHC0 \");",
+ "#endif",
+ "#ifdef HC1",
+ " strcat(ctd, \"-DHC1 \");",
+ "#endif",
+ "#ifdef HC2",
+ " strcat(ctd, \"-DHC2 \");",
+ "#endif",
+ "#ifdef HC3",
+ " strcat(ctd, \"-DHC3 \");",
+ "#endif",
+ "#ifdef HC4",
+ " strcat(ctd, \"-DHC4 \");",
+ "#endif",
+ "#ifdef CHECK",
+ " strcat(ctd, \"-DCHECK \");",
+ "#endif",
+ "#ifdef CTL",
+ " strcat(ctd, \"-DCTL \");",
+ "#endif",
+ "#ifdef NIBIS",
+ " strcat(ctd, \"-DNIBIS \");",
+ "#endif",
+ "#ifdef NOBOUNDCHECK",
+ " strcat(ctd, \"-DNOBOUNDCHECK \");",
+ "#endif",
+ "#ifdef NOSTUTTER",
+ " strcat(ctd, \"-DNOSTUTTER \");",
+ "#endif",
+ "#ifdef REACH",
+ " strcat(ctd, \"-DREACH \");",
+ "#endif",
+ "#ifdef PRINTF",
+ " strcat(ctd, \"-DPRINTF \");",
+ "#endif",
+ "#ifdef OTIM",
+ " strcat(ctd, \"-DOTIM \");",
+ "#endif",
+ "#ifdef COLLAPSE",
+ " strcat(ctd, \"-DCOLLAPSE \");",
+ "#endif",
+ "#ifdef MA",
+ " sprintf(carg, \"-DMA=%%d \", MA);",
+ " strcat(ctd, carg);",
+ "#endif",
+ "#ifdef SVDUMP",
+ " strcat(ctd, \"-DSVDUMP \");",
+ "#endif",
+ "#ifdef VECTORSZ",
+ " if (VECTORSZ != 1024)",
+ " { sprintf(carg, \"-DVECTORSZ=%%d \", VECTORSZ);",
+ " strcat(ctd, carg);",
+ " }",
+ "#endif",
+ "#ifdef VERBOSE",
+ " strcat(ctd, \"-DVERBOSE \");",
+ "#endif",
+ "#ifdef CHECK",
+ " strcat(ctd, \"-DCHECK \");",
+ "#endif",
+ "#ifdef SDUMP",
+ " strcat(ctd, \"-DSDUMP \");",
+ "#endif",
+ "#ifdef COVEST",
+ " strcat(ctd, \"-DCOVEST \");",
+ "#endif",
+ " printf(\"Compiled as: cc -o pan %%span.c\\n\", ctd);",
+ "}",
+ 0,
+};
diff --git a/sys/src/cmd/spin/pangen4.c b/sys/src/cmd/spin/pangen4.c
new file mode 100755
index 000000000..777371fc7
--- /dev/null
+++ b/sys/src/cmd/spin/pangen4.c
@@ -0,0 +1,344 @@
+/***** spin: pangen4.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include "spin.h"
+#include "y.tab.h"
+
+extern FILE *tc, *tb;
+extern Queue *qtab;
+extern Symbol *Fname;
+extern int lineno, m_loss, Pid, eventmapnr, multi_oval;
+extern short nocast, has_provided, has_sorted;
+extern char *R13[], *R14[], *R15[];
+
+static void check_proc(Lextok *, int);
+
+void
+undostmnt(Lextok *now, int m)
+{ Lextok *v;
+ int i, j;
+
+ if (!now)
+ { fprintf(tb, "0");
+ return;
+ }
+ lineno = now->ln;
+ Fname = now->fn;
+ switch (now->ntyp) {
+ case CONST: case '!': case UMIN:
+ case '~': case '/': case '*':
+ case '-': case '+': case '%':
+ case LT: case GT: case '&':
+ case '|': case LE: case GE:
+ case NE: case EQ: case OR:
+ case AND: case LSHIFT: case RSHIFT:
+ case TIMEOUT: case LEN: case NAME:
+ case FULL: case EMPTY: case 'R':
+ case NFULL: case NEMPTY: case ENABLED:
+ case '?': case PC_VAL: case '^':
+ case C_EXPR:
+ case NONPROGRESS:
+ putstmnt(tb, now, m);
+ break;
+
+ case RUN:
+ fprintf(tb, "delproc(0, now._nr_pr-1)");
+ break;
+
+ case 's':
+ if (Pid == eventmapnr) break;
+
+ if (m_loss)
+ fprintf(tb, "if (_m == 2) ");
+ putname(tb, "_m = unsend(", now->lft, m, ")");
+ break;
+
+ case 'r':
+ if (Pid == eventmapnr) break;
+
+ for (v = now->rgt, i=j=0; v; v = v->rgt, i++)
+ if (v->lft->ntyp != CONST
+ && v->lft->ntyp != EVAL)
+ j++;
+ if (j == 0 && now->val >= 2)
+ break; /* poll without side-effect */
+
+ { int ii = 0, jj;
+
+ for (v = now->rgt; v; v = v->rgt)
+ if ((v->lft->ntyp != CONST
+ && v->lft->ntyp != EVAL))
+ ii++; /* nr of things bupped */
+ if (now->val == 1)
+ { ii++;
+ jj = multi_oval - ii - 1;
+ fprintf(tb, "XX = trpt->bup.oval");
+ if (multi_oval > 0)
+ { fprintf(tb, "s[%d]", jj);
+ jj++;
+ }
+ fprintf(tb, ";\n\t\t");
+ } else
+ { fprintf(tb, "XX = 1;\n\t\t");
+ jj = multi_oval - ii - 1;
+ }
+
+ if (now->val < 2) /* not for channel poll */
+ for (v = now->rgt, i = 0; v; v = v->rgt, i++)
+ { switch(v->lft->ntyp) {
+ case CONST:
+ case EVAL:
+ fprintf(tb, "unrecv");
+ putname(tb, "(", now->lft, m, ", XX-1, ");
+ fprintf(tb, "%d, ", i);
+ if (v->lft->ntyp == EVAL)
+ undostmnt(v->lft->lft, m);
+ else
+ undostmnt(v->lft, m);
+ fprintf(tb, ", %d);\n\t\t", (i==0)?1:0);
+ break;
+ default:
+ fprintf(tb, "unrecv");
+ putname(tb, "(", now->lft, m, ", XX-1, ");
+ fprintf(tb, "%d, ", i);
+ if (v->lft->sym
+ && !strcmp(v->lft->sym->name, "_"))
+ { fprintf(tb, "trpt->bup.oval");
+ if (multi_oval > 0)
+ fprintf(tb, "s[%d]", jj);
+ } else
+ putstmnt(tb, v->lft, m);
+
+ fprintf(tb, ", %d);\n\t\t", (i==0)?1:0);
+ if (multi_oval > 0)
+ jj++;
+ break;
+ } }
+ jj = multi_oval - ii - 1;
+
+ if (now->val == 1 && multi_oval > 0)
+ jj++; /* new 3.4.0 */
+
+ for (v = now->rgt, i = 0; v; v = v->rgt, i++)
+ { switch(v->lft->ntyp) {
+ case CONST:
+ case EVAL:
+ break;
+ default:
+ if (!v->lft->sym
+ || strcmp(v->lft->sym->name, "_") != 0)
+ { nocast=1; putstmnt(tb,v->lft,m);
+ nocast=0; fprintf(tb, " = trpt->bup.oval");
+ if (multi_oval > 0)
+ fprintf(tb, "s[%d]", jj);
+ fprintf(tb, ";\n\t\t");
+ }
+ if (multi_oval > 0)
+ jj++;
+ break;
+ } }
+ multi_oval -= ii;
+ }
+ break;
+
+ case '@':
+ fprintf(tb, "p_restor(II);\n\t\t");
+ break;
+
+ case ASGN:
+ nocast=1; putstmnt(tb,now->lft,m);
+ nocast=0; fprintf(tb, " = trpt->bup.oval");
+ if (multi_oval > 0)
+ { multi_oval--;
+ fprintf(tb, "s[%d]", multi_oval-1);
+ }
+ check_proc(now->rgt, m);
+ break;
+
+ case 'c':
+ check_proc(now->lft, m);
+ break;
+
+ case '.':
+ case GOTO:
+ case ELSE:
+ case BREAK:
+ break;
+
+ case C_CODE:
+ fprintf(tb, "sv_restor();\n");
+ break;
+
+ case ASSERT:
+ case PRINT:
+ check_proc(now, m);
+ break;
+ case PRINTM:
+ break;
+
+ default:
+ printf("spin: bad node type %d (.b)\n", now->ntyp);
+ alldone(1);
+ }
+}
+
+int
+any_undo(Lextok *now)
+{ /* is there anything to undo on a return move? */
+ if (!now) return 1;
+ switch (now->ntyp) {
+ case 'c': return any_oper(now->lft, RUN);
+ case ASSERT:
+ case PRINT: return any_oper(now, RUN);
+
+ case PRINTM:
+ case '.':
+ case GOTO:
+ case ELSE:
+ case BREAK: return 0;
+ default: return 1;
+ }
+}
+
+int
+any_oper(Lextok *now, int oper)
+{ /* check if an expression contains oper operator */
+ if (!now) return 0;
+ if (now->ntyp == oper)
+ return 1;
+ return (any_oper(now->lft, oper) || any_oper(now->rgt, oper));
+}
+
+static void
+check_proc(Lextok *now, int m)
+{
+ if (!now)
+ return;
+ if (now->ntyp == '@' || now->ntyp == RUN)
+ { fprintf(tb, ";\n\t\t");
+ undostmnt(now, m);
+ }
+ check_proc(now->lft, m);
+ check_proc(now->rgt, m);
+}
+
+void
+genunio(void)
+{ char buf1[256];
+ Queue *q; int i;
+
+ ntimes(tc, 0, 1, R13);
+ for (q = qtab; q; q = q->nxt)
+ { fprintf(tc, "\tcase %d:\n", q->qid);
+
+ if (has_sorted)
+ { sprintf(buf1, "((Q%d *)z)->contents", q->qid);
+ fprintf(tc, "#ifdef HAS_SORTED\n");
+ fprintf(tc, "\t\tj = trpt->ipt;\n"); /* ipt was bup.oval */
+ fprintf(tc, "#endif\n");
+ fprintf(tc, "\t\tfor (k = j; k < ((Q%d *)z)->Qlen; k++)\n",
+ q->qid);
+ fprintf(tc, "\t\t{\n");
+ for (i = 0; i < q->nflds; i++)
+ fprintf(tc, "\t\t\t%s[k].fld%d = %s[k+1].fld%d;\n",
+ buf1, i, buf1, i);
+ fprintf(tc, "\t\t}\n");
+ fprintf(tc, "\t\tj = ((Q0 *)z)->Qlen;\n");
+ }
+
+ sprintf(buf1, "((Q%d *)z)->contents[j].fld", q->qid);
+ for (i = 0; i < q->nflds; i++)
+ fprintf(tc, "\t\t%s%d = 0;\n", buf1, i);
+ if (q->nslots==0)
+ { /* check if rendezvous succeeded, 1 level down */
+ fprintf(tc, "\t\t_m = (trpt+1)->o_m;\n");
+ fprintf(tc, "\t\tif (_m) (trpt-1)->o_pm |= 1;\n");
+ fprintf(tc, "\t\tUnBlock;\n");
+ } else
+ fprintf(tc, "\t\t_m = trpt->o_m;\n");
+
+ fprintf(tc, "\t\tbreak;\n");
+ }
+ ntimes(tc, 0, 1, R14);
+ for (q = qtab; q; q = q->nxt)
+ { sprintf(buf1, "((Q%d *)z)->contents", q->qid);
+ fprintf(tc, " case %d:\n", q->qid);
+ if (q->nslots == 0)
+ fprintf(tc, "\t\tif (strt) boq = from+1;\n");
+ else if (q->nslots > 1) /* shift */
+ { fprintf(tc, "\t\tif (strt && slot<%d)\n",
+ q->nslots-1);
+ fprintf(tc, "\t\t{\tfor (j--; j>=slot; j--)\n");
+ fprintf(tc, "\t\t\t{");
+ for (i = 0; i < q->nflds; i++)
+ { fprintf(tc, "\t%s[j+1].fld%d =\n\t\t\t",
+ buf1, i);
+ fprintf(tc, "\t%s[j].fld%d;\n\t\t\t",
+ buf1, i);
+ }
+ fprintf(tc, "}\n\t\t}\n");
+ }
+ strcat(buf1, "[slot].fld");
+ fprintf(tc, "\t\tif (strt) {\n");
+ for (i = 0; i < q->nflds; i++)
+ fprintf(tc, "\t\t\t%s%d = 0;\n", buf1, i);
+ fprintf(tc, "\t\t}\n");
+ if (q->nflds == 1) /* set */
+ fprintf(tc, "\t\tif (fld == 0) %s0 = fldvar;\n",
+ buf1);
+ else
+ { fprintf(tc, "\t\tswitch (fld) {\n");
+ for (i = 0; i < q->nflds; i++)
+ { fprintf(tc, "\t\tcase %d:\t%s", i, buf1);
+ fprintf(tc, "%d = fldvar; break;\n", i);
+ }
+ fprintf(tc, "\t\t}\n");
+ }
+ fprintf(tc, "\t\tbreak;\n");
+ }
+ ntimes(tc, 0, 1, R15);
+}
+
+int
+proper_enabler(Lextok *n)
+{
+ if (!n) return 1;
+ switch (n->ntyp) {
+ case NEMPTY: case FULL:
+ case NFULL: case EMPTY:
+ case LEN: case 'R':
+ case NAME:
+ has_provided = 1;
+ if (strcmp(n->sym->name, "_pid") == 0)
+ return 1;
+ return (!(n->sym->context));
+
+ case CONST: case TIMEOUT:
+ has_provided = 1;
+ return 1;
+
+ case ENABLED: case PC_VAL:
+ return proper_enabler(n->lft);
+
+ case '!': case UMIN: case '~':
+ return proper_enabler(n->lft);
+
+ case '/': case '*': case '-': case '+':
+ case '%': case LT: case GT: case '&': case '^':
+ case '|': case LE: case GE: case NE: case '?':
+ case EQ: case OR: case AND: case LSHIFT:
+ case RSHIFT: case 'c':
+ return proper_enabler(n->lft) && proper_enabler(n->rgt);
+ default:
+ break;
+ }
+ return 0;
+}
diff --git a/sys/src/cmd/spin/pangen4.h b/sys/src/cmd/spin/pangen4.h
new file mode 100755
index 000000000..d80bdeaac
--- /dev/null
+++ b/sys/src/cmd/spin/pangen4.h
@@ -0,0 +1,727 @@
+/***** spin: pangen4.h *****/
+
+/* 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 */
+
+/* The DFA code below was written by Anuj Puri and Gerard J. Holzmann in */
+/* May 1997, and was inspired by earlier work on data compression using */
+/* sharing tree data structures and graph-encoded sets by J-Ch. Gregoire */
+/* (INRS Telecom, Quebec, Canada) and D.Zampunieris (Univ.Namur, Belgium) */
+
+/* The splay routine code included here is based on the public domain */
+/* version written by D. Sleator <sleator@cs.cmu.edu> in 1992. */
+
+static char *Dfa[] = {
+ "#ifdef MA",
+ "/*",
+ "#include <stdio.h>",
+ "#define uchar unsigned char",
+ "*/",
+ "#define ulong unsigned long",
+ "#define ushort unsigned short",
+ "",
+ "#define TWIDTH 256",
+ "#define HASH(y,n) (n)*(((long)y))",
+ "#define INRANGE(e,h) ((h>=e->From && h<=e->To)||(e->s==1 && e->S==h))",
+ "",
+ "extern char *emalloc(unsigned long); /* imported routine */",
+ "extern void dfa_init(ushort); /* 4 exported routines */",
+ "extern int dfa_member(ulong);",
+ "extern int dfa_store(uchar *);",
+ "extern void dfa_stats(void);",
+ "",
+ "typedef struct Edge {",
+ " uchar From, To; /* max range 0..255 */",
+ " uchar s, S; /* if s=1, S is singleton */",
+ " struct Vertex *Dst;",
+ " struct Edge *Nxt;",
+ "} Edge;",
+ "",
+ "typedef struct Vertex {",
+ " ulong key, num; /* key for splay tree, nr incoming edges */",
+ " uchar from[2], to[2]; /* in-node predefined edge info */",
+ " struct Vertex *dst[2];/* most nodes have 2 or more edges */",
+ " struct Edge *Succ; /* in case there are more edges */",
+ " struct Vertex *lnk, *left, *right; /* splay tree plumbing */",
+ "} Vertex;",
+ "",
+ "static Edge *free_edges;",
+ "static Vertex *free_vertices;",
+ "static Vertex **layers; /* one splay tree of nodes per layer */",
+ "static Vertex **path; /* run of word in the DFA */",
+ "static Vertex *R, *F, *NF; /* Root, Final, Not-Final */",
+ "static uchar *word, *lastword;/* string, and last string inserted */",
+ "static int dfa_depth, iv=0, nv=0, pfrst=0, Tally;",
+ "",
+ "static void insert_it(Vertex *, int); /* splay-tree code */",
+ "static void delete_it(Vertex *, int);",
+ "static Vertex *find_it(Vertex *, Vertex *, uchar, int);",
+ "",
+ "static void",
+ "recyc_edges(Edge *e)",
+ "{",
+ " if (!e) return;",
+ " recyc_edges(e->Nxt);",
+ " e->Nxt = free_edges;",
+ " free_edges = e;",
+ "}",
+ "",
+ "static Edge *",
+ "new_edge(Vertex *dst)",
+ "{ Edge *e;",
+ "",
+ " if (free_edges)",
+ " { e = free_edges;",
+ " free_edges = e->Nxt;",
+ " e->From = e->To = e->s = e->S = 0;",
+ " e->Nxt = (Edge *) 0;",
+ " } else",
+ " e = (Edge *) emalloc(sizeof(Edge));",
+ " e->Dst = dst;",
+ "",
+ " return e;",
+ "}",
+ "",
+ "static void",
+ "recyc_vertex(Vertex *v)",
+ "{",
+ " recyc_edges(v->Succ);",
+ " v->Succ = (Edge *) free_vertices;",
+ " free_vertices = v;",
+ " nr_states--;",
+ "}",
+ "",
+ "static Vertex *",
+ "new_vertex(void)",
+ "{ Vertex *v;",
+ "",
+ " if (free_vertices)",
+ " { v = free_vertices;",
+ " free_vertices = (Vertex *) v->Succ;",
+ " v->Succ = (Edge *) 0;",
+ " v->num = 0;",
+ " } else",
+ " v = (Vertex *) emalloc(sizeof(Vertex));",
+ "",
+ " nr_states++;",
+ " return v; ",
+ "}",
+ "",
+ "static Vertex *",
+ "allDelta(Vertex *v, int n)",
+ "{ Vertex *dst = new_vertex();",
+ "",
+ " v->from[0] = 0;",
+ " v->to[0] = 255;",
+ " v->dst[0] = dst;",
+ " dst->num = 256;",
+ " insert_it(v, n);",
+ " return dst;",
+ "}",
+ "",
+ "static void",
+ "insert_edge(Vertex *v, Edge *e)",
+ "{ /* put new edge first */",
+ " if (!v->dst[0])",
+ " { v->dst[0] = e->Dst;",
+ " v->from[0] = e->From;",
+ " v->to[0] = e->To;",
+ " recyc_edges(e);",
+ " return;",
+ " }",
+ " if (!v->dst[1])",
+ " { v->from[1] = v->from[0]; v->from[0] = e->From;",
+ " v->to[1] = v->to[0]; v->to[0] = e->To;",
+ " v->dst[1] = v->dst[0]; v->dst[0] = e->Dst;",
+ " recyc_edges(e);",
+ " return;",
+ " } /* shift */",
+ " { int f = v->from[1];",
+ " int t = v->to[1];",
+ " Vertex *d = v->dst[1];",
+ " v->from[1] = v->from[0]; v->from[0] = e->From;",
+ " v->to[1] = v->to[0]; v->to[0] = e->To;",
+ " v->dst[1] = v->dst[0]; v->dst[0] = e->Dst;",
+ " e->From = f;",
+ " e->To = t;",
+ " e->Dst = d;",
+ " }",
+ " e->Nxt = v->Succ;",
+ " v->Succ = e;",
+ "}",
+ "",
+ "static void",
+ "copyRecursive(Vertex *v, Edge *e)",
+ "{ Edge *f;",
+ " if (e->Nxt) copyRecursive(v, e->Nxt);",
+ " f = new_edge(e->Dst);",
+ " f->From = e->From;",
+ " f->To = e->To;",
+ " f->s = e->s;",
+ " f->S = e->S;",
+ " f->Nxt = v->Succ;",
+ " v->Succ = f;",
+ "}",
+ "",
+ "static void",
+ "copyEdges(Vertex *to, Vertex *from)",
+ "{ int i;",
+ " for (i = 0; i < 2; i++)",
+ " { to->from[i] = from->from[i];",
+ " to->to[i] = from->to[i];",
+ " to->dst[i] = from->dst[i];",
+ " }",
+ " if (from->Succ) copyRecursive(to, from->Succ);",
+ "}",
+ "",
+ "static Edge *",
+ "cacheDelta(Vertex *v, int h, int first)",
+ "{ static Edge *ov, tmp; int i;",
+ "",
+ " if (!first && INRANGE(ov,h))",
+ " return ov; /* intercepts about 10%% */",
+ " for (i = 0; i < 2; i++)",
+ " if (v->dst[i] && h >= v->from[i] && h <= v->to[i])",
+ " { tmp.From = v->from[i];",
+ " tmp.To = v->to[i];",
+ " tmp.Dst = v->dst[i];",
+ " tmp.s = tmp.S = 0;",
+ " ov = &tmp;",
+ " return ov;",
+ " }",
+ " for (ov = v->Succ; ov; ov = ov->Nxt)",
+ " if (INRANGE(ov,h)) return ov;",
+ "",
+ " Uerror(\"cannot get here, cacheDelta\");",
+ " return (Edge *) 0;",
+ "}",
+ "",
+ "static Vertex *",
+ "Delta(Vertex *v, int h) /* v->delta[h] */",
+ "{ Edge *e;",
+ "",
+ " if (v->dst[0] && h >= v->from[0] && h <= v->to[0])",
+ " return v->dst[0]; /* oldest edge */",
+ " if (v->dst[1] && h >= v->from[1] && h <= v->to[1])",
+ " return v->dst[1];",
+ " for (e = v->Succ; e; e = e->Nxt)",
+ " if (INRANGE(e,h))",
+ " return e->Dst;",
+ " Uerror(\"cannot happen Delta\");",
+ " return (Vertex *) 0;",
+ "}",
+ "",
+ "static void",
+ "numDelta(Vertex *v, int d)",
+ "{ Edge *e;",
+ " ulong cnt;",
+ " int i;",
+ "",
+ " for (i = 0; i < 2; i++)",
+ " if (v->dst[i])",
+ " { cnt = v->dst[i]->num + d*(1 + v->to[i] - v->from[i]);",
+ " if (d == 1 && cnt < v->dst[i]->num) goto bad;",
+ " v->dst[i]->num = cnt;",
+ " }",
+ " for (e = v->Succ; e; e = e->Nxt)",
+ " { cnt = e->Dst->num + d*(1 + e->To - e->From + e->s);",
+ " if (d == 1 && cnt < e->Dst->num)",
+ "bad: Uerror(\"too many incoming edges\");",
+ " e->Dst->num = cnt;",
+ " }",
+ "}",
+ "",
+ "static void",
+ "setDelta(Vertex *v, int h, Vertex *newdst) /* v->delta[h] = newdst; */",
+ "{ Edge *e, *f = (Edge *) 0, *g;",
+ " int i;",
+ "",
+ " /* remove the old entry, if there */",
+ " for (i = 0; i < 2; i++)",
+ " if (v->dst[i] && h >= v->from[i] && h <= v->to[i])",
+ " { if (h == v->from[i])",
+ " { if (h == v->to[i])",
+ " { v->dst[i] = (Vertex *) 0;",
+ " v->from[i] = v->to[i] = 0;",
+ " } else",
+ " v->from[i]++;",
+ " } else if (h == v->to[i])",
+ " { v->to[i]--;",
+ " } else",
+ " { g = new_edge(v->dst[i]);/* same dst */",
+ " g->From = v->from[i];",
+ " g->To = h-1; /* left half */",
+ " v->from[i] = h+1; /* right half */",
+ " insert_edge(v, g);",
+ " }",
+ " goto part2;",
+ " }",
+ " for (e = v->Succ; e; f = e, e = e->Nxt)",
+ " { if (e->s == 1 && e->S == h)",
+ " { e->s = e->S = 0;",
+ " goto rem_tst;",
+ " }",
+ " if (h >= e->From && h <= e->To)",
+ " { if (h == e->From)",
+ " { if (h == e->To)",
+ " { if (e->s)",
+ " { e->From = e->To = e->S;",
+ " e->s = 0;",
+ " break;",
+ " } else",
+ " goto rem_do;",
+ " } else",
+ " e->From++;",
+ " } else if (h == e->To)",
+ " { e->To--;",
+ " } else /* split */",
+ " { g = new_edge(e->Dst); /* same dst */",
+ " g->From = e->From;",
+ " g->To = h-1; /* g=left half */",
+ " e->From = h+1; /* e=right half */",
+ " g->Nxt = e->Nxt; /* insert g */",
+ " e->Nxt = g; /* behind e */",
+ " break; /* done */",
+ " }",
+ "",
+ "rem_tst: if (e->From > e->To)",
+ " { if (e->s == 0) {",
+ "rem_do: if (f)",
+ " f->Nxt = e->Nxt;",
+ " else",
+ " v->Succ = e->Nxt;",
+ " e->Nxt = (Edge *) 0;",
+ " recyc_edges(e);",
+ " } else",
+ " { e->From = e->To = e->S;",
+ " e->s = 0;",
+ " } }",
+ " break;",
+ " } }",
+ "part2:",
+ " /* check if newdst is already there */",
+ " for (i = 0; i < 2; i++)",
+ " if (v->dst[i] == newdst)",
+ " { if (h+1 == (int) v->from[i])",
+ " { v->from[i] = h;",
+ " return;",
+ " }",
+ " if (h == (int) v->to[i]+1)",
+ " { v->to[i] = h;",
+ " return;",
+ " } }",
+ " for (e = v->Succ; e; e = e->Nxt)",
+ " { if (e->Dst == newdst)",
+ " { if (h+1 == (int) e->From)",
+ " { e->From = h;",
+ " if (e->s == 1 && e->S+1 == e->From)",
+ " { e->From = e->S;",
+ " e->s = e->S = 0;",
+ " }",
+ " return;",
+ " }",
+ " if (h == (int) e->To+1)",
+ " { e->To = h;",
+ " if (e->s == 1 && e->S == e->To+1)",
+ " { e->To = e->S;",
+ " e->s = e->S = 0;",
+ " }",
+ " return;",
+ " }",
+ " if (e->s == 0)",
+ " { e->s = 1;",
+ " e->S = h;",
+ " return;",
+ " } } }",
+ " /* add as a new edge */",
+ " e = new_edge(newdst);",
+ " e->From = e->To = h;",
+ " insert_edge(v, e);",
+ "}",
+ "",
+ "static ulong",
+ "cheap_key(Vertex *v)",
+ "{ ulong vk2 = 0;",
+ "",
+ " if (v->dst[0])",
+ " { vk2 = (ulong) v->dst[0];",
+ " if ((ulong) v->dst[1] > vk2)",
+ " vk2 = (ulong) v->dst[1];",
+ " } else if (v->dst[1])",
+ " vk2 = (ulong) v->dst[1]; ",
+ " if (v->Succ)",
+ " { Edge *e;",
+ " for (e = v->Succ; e; e = e->Nxt)",
+ " if ((ulong) e->Dst > vk2)",
+ " vk2 = (ulong) e->Dst;",
+ " }",
+ " Tally = (vk2>>2)&(TWIDTH-1);",
+ " return v->key;",
+ "}",
+ "",
+ "static ulong",
+ "mk_key(Vertex *v) /* not sensitive to order */",
+ "{ ulong m = 0, vk2 = 0;",
+ " Edge *e;",
+ "",
+ " if (v->dst[0])",
+ " { m += HASH(v->dst[0], v->to[0] - v->from[0] + 1);",
+ " vk2 = (ulong) v->dst[0]; ",
+ " }",
+ " if (v->dst[1])",
+ " { m += HASH(v->dst[1], v->to[1] - v->from[1] + 1);",
+ " if ((ulong) v->dst[1] > vk2) vk2 = (ulong) v->dst[1]; ",
+ " }",
+ " for (e = v->Succ; e; e = e->Nxt)",
+ " { m += HASH(e->Dst, e->To - e->From + 1 + e->s);",
+ " if ((ulong) e->Dst > vk2) vk2 = (ulong) e->Dst; ",
+ " }",
+ " Tally = (vk2>>2)&(TWIDTH-1);",
+ " return m;",
+ "}",
+ "",
+ "static ulong",
+ "mk_special(int sigma, Vertex *n, Vertex *v)",
+ "{ ulong m = 0, vk2 = 0;",
+ " Edge *f;",
+ " int i;",
+ "",
+ " for (i = 0; i < 2; i++)",
+ " if (v->dst[i])",
+ " { if (sigma >= v->from[i] && sigma <= v->to[i])",
+ " { m += HASH(v->dst[i], v->to[i]-v->from[i]);",
+ " if ((ulong) v->dst[i] > vk2",
+ " && v->to[i] > v->from[i])",
+ " vk2 = (ulong) v->dst[i]; ",
+ " } else",
+ " { m += HASH(v->dst[i], v->to[i]-v->from[i]+1);",
+ " if ((ulong) v->dst[i] > vk2)",
+ " vk2 = (ulong) v->dst[i]; ",
+ " } }",
+ " for (f = v->Succ; f; f = f->Nxt)",
+ " { if (sigma >= f->From && sigma <= f->To)",
+ " { m += HASH(f->Dst, f->To - f->From + f->s);",
+ " if ((ulong) f->Dst > vk2",
+ " && f->To - f->From + f->s > 0)",
+ " vk2 = (ulong) f->Dst; ",
+ " } else if (f->s == 1 && sigma == f->S)",
+ " { m += HASH(f->Dst, f->To - f->From + 1);",
+ " if ((ulong) f->Dst > vk2) vk2 = (ulong) f->Dst; ",
+ " } else",
+ " { m += HASH(f->Dst, f->To - f->From + 1 + f->s);",
+ " if ((ulong) f->Dst > vk2) vk2 = (ulong) f->Dst; ",
+ " } }",
+ "",
+ " if ((ulong) n > vk2) vk2 = (ulong) n; ",
+ " Tally = (vk2>>2)&(TWIDTH-1);",
+ " m += HASH(n, 1);",
+ " return m;",
+ "}",
+ "",
+ "void ",
+ "dfa_init(ushort nr_layers)",
+ "{ int i; Vertex *r, *t;",
+ "",
+ " dfa_depth = nr_layers; /* one byte per layer */",
+ " path = (Vertex **) emalloc((dfa_depth+1)*sizeof(Vertex *));",
+ " layers = (Vertex **) emalloc(TWIDTH*(dfa_depth+1)*sizeof(Vertex *));",
+ " lastword = (uchar *) emalloc((dfa_depth+1)*sizeof(uchar));",
+ " lastword[dfa_depth] = lastword[0] = 255;",
+ " path[0] = R = new_vertex(); F = new_vertex();",
+ "",
+ " for (i = 1, r = R; i < dfa_depth; i++, r = t)",
+ " t = allDelta(r, i-1);",
+ " NF = allDelta(r, i-1);",
+ "}",
+ "",
+ "#if 0",
+ "static void complement_dfa(void) { Vertex *tmp = F; F = NF; NF = tmp; }",
+ "#endif",
+ "",
+ "double",
+ "tree_stats(Vertex *t)",
+ "{ Edge *e; double cnt=0.0;",
+ " if (!t) return 0;",
+ " if (!t->key) return 0;",
+ " t->key = 0; /* precaution */",
+ " if (t->dst[0]) cnt++;",
+ " if (t->dst[1]) cnt++;",
+ " for (e = t->Succ; e; e = e->Nxt)",
+ " cnt++;",
+ " cnt += tree_stats(t->lnk);",
+ " cnt += tree_stats(t->left);",
+ " cnt += tree_stats(t->right);",
+ " return cnt;",
+ "}",
+ "",
+ "void",
+ "dfa_stats(void)",
+ "{ int i, j; double cnt = 0.0;",
+ " for (j = 0; j < TWIDTH; j++)",
+ " for (i = 0; i < dfa_depth+1; i++)",
+ " cnt += tree_stats(layers[i*TWIDTH+j]);",
+ " printf(\"Minimized Automaton:\t%%6d nodes and %%6g edges\\n\",",
+ " nr_states, cnt);",
+ "}",
+ "",
+ "int",
+ "dfa_member(ulong n)",
+ "{ Vertex **p, **q;",
+ " uchar *w = &word[n];",
+ " int i;",
+ "",
+ " p = &path[n]; q = (p+1);",
+ " for (i = n; i < dfa_depth; i++)",
+ " *q++ = Delta(*p++, *w++);",
+ " return (*p == F);",
+ "}",
+ "",
+ "int",
+ "dfa_store(uchar *sv)",
+ "{ Vertex **p, **q, *s, *y, *old, *new = F;",
+ " uchar *w, *u = lastword;",
+ " int i, j, k;",
+ "",
+ " w = word = sv;",
+ " while (*w++ == *u++) /* find first byte that differs */",
+ " ;",
+ " pfrst = (int) (u - lastword) - 1;",
+ " memcpy(&lastword[pfrst], &sv[pfrst], dfa_depth-pfrst);",
+ " if (pfrst > iv) pfrst = iv;",
+ " if (pfrst > nv) pfrst = nv;",
+ "/* phase1: */",
+ " p = &path[pfrst]; q = (p+1); w = &word[pfrst];",
+ " for (i = pfrst; i < dfa_depth; i++)",
+ " *q++ = Delta(*p++, *w++); /* (*p)->delta[*w++]; */",
+ "",
+ " if (*p == F) return 1; /* it's already there */",
+ "/* phase2: */",
+ " iv = dfa_depth;",
+ " do { iv--;",
+ " old = new;",
+ " new = find_it(path[iv], old, word[iv], iv);",
+ " } while (new && iv > 0);",
+ "",
+ "/* phase3: */",
+ " nv = k = 0; s = path[0];",
+ " for (j = 1; j <= iv; ++j) ",
+ " if (path[j]->num > 1)",
+ " { y = new_vertex();",
+ " copyEdges(y, path[j]);",
+ " insert_it(y, j);",
+ " numDelta(y, 1);",
+ " delete_it(s, j-1);",
+ " setDelta(s, word[j-1], y);",
+ " insert_it(s, j-1);",
+ " y->num = 1; /* initial value 1 */",
+ " s = y;",
+ " path[j]->num--; /* only 1 moved from j to y */",
+ " k = 1;",
+ " } else",
+ " { s = path[j];",
+ " if (!k) nv = j;",
+ " }",
+ " y = Delta(s, word[iv]);",
+ " y->num--;",
+ " delete_it(s, iv); ",
+ " setDelta(s, word[iv], old);",
+ " insert_it(s, iv); ",
+ " old->num++;",
+ "",
+ " for (j = iv+1; j < dfa_depth; j++)",
+ " if (path[j]->num == 0)",
+ " { numDelta(path[j], -1);",
+ " delete_it(path[j], j);",
+ " recyc_vertex(path[j]);",
+ " } else",
+ " break;",
+ " return 0;",
+ "}",
+ "",
+ "static Vertex *",
+ "splay(ulong i, Vertex *t)",
+ "{ Vertex N, *l, *r, *y;",
+ "",
+ " if (!t) return t;",
+ " N.left = N.right = (Vertex *) 0;",
+ " l = r = &N;",
+ " for (;;)",
+ " { if (i < t->key)",
+ " { if (!t->left) break;",
+ " if (i < t->left->key)",
+ " { y = t->left;",
+ " t->left = y->right;",
+ " y->right = t;",
+ " t = y;",
+ " if (!t->left) break;",
+ " }",
+ " r->left = t;",
+ " r = t;",
+ " t = t->left;",
+ " } else if (i > t->key)",
+ " { if (!t->right) break;",
+ " if (i > t->right->key)",
+ " { y = t->right;",
+ " t->right = y->left;",
+ " y->left = t;",
+ " t = y;",
+ " if (!t->right) break;",
+ " }",
+ " l->right = t;",
+ " l = t;",
+ " t = t->right;",
+ " } else",
+ " break;",
+ " }",
+ " l->right = t->left;",
+ " r->left = t->right;",
+ " t->left = N.right;",
+ " t->right = N.left;",
+ " return t;",
+ "}",
+ "",
+ "static void",
+ "insert_it(Vertex *v, int L)",
+ "{ Vertex *new, *t;",
+ " ulong i; int nr;",
+ "",
+ " i = mk_key(v);",
+ " nr = ((L*TWIDTH)+Tally);",
+ " t = layers[nr];",
+ "",
+ " v->key = i; ",
+ " if (!t)",
+ " { layers[nr] = v;",
+ " return;",
+ " }",
+ " t = splay(i, t);",
+ " if (i < t->key)",
+ " { new = v;",
+ " new->left = t->left;",
+ " new->right = t;",
+ " t->left = (Vertex *) 0;",
+ " } else if (i > t->key)",
+ " { new = v;",
+ " new->right = t->right;",
+ " new->left = t;",
+ " t->right = (Vertex *) 0;",
+ " } else /* it's already there */",
+ " { v->lnk = t->lnk; /* put in linked list off v */",
+ " t->lnk = v;",
+ " new = t;",
+ " }",
+ " layers[nr] = new;",
+ "}",
+ "",
+ "static int",
+ "checkit(Vertex *h, Vertex *v, Vertex *n, uchar sigma)",
+ "{ Edge *g, *f;",
+ " int i, k, j = 1;",
+ "",
+ " for (k = 0; k < 2; k++)",
+ " if (h->dst[k])",
+ " { if (sigma >= h->from[k] && sigma <= h->to[k])",
+ " { if (h->dst[k] != n) goto no_match;",
+ " }",
+ " for (i = h->from[k]; i <= h->to[k]; i++)",
+ " { if (i == sigma) continue;",
+ " g = cacheDelta(v, i, j); j = 0;",
+ " if (h->dst[k] != g->Dst)",
+ " goto no_match;",
+ " if (g->s == 0 || g->S != i)",
+ " i = g->To;",
+ " } }",
+ " for (f = h->Succ; f; f = f->Nxt)",
+ " { if (INRANGE(f,sigma))",
+ " { if (f->Dst != n) goto no_match;",
+ " }",
+ " for (i = f->From; i <= f->To; i++)",
+ " { if (i == sigma) continue;",
+ " g = cacheDelta(v, i, j); j = 0;",
+ " if (f->Dst != g->Dst)",
+ " goto no_match;",
+ " if (g->s == 1 && i == g->S)",
+ " continue;",
+ " i = g->To;",
+ " }",
+ " if (f->s && f->S != sigma)",
+ " { g = cacheDelta(v, f->S, 1);",
+ " if (f->Dst != g->Dst)",
+ " goto no_match;",
+ " }",
+ " }",
+ " if (h->Succ || h->dst[0] || h->dst[1]) return 1;",
+ "no_match:",
+ " return 0;",
+ "}",
+ "",
+ "static Vertex *",
+ "find_it(Vertex *v, Vertex *n, uchar sigma, int L)",
+ "{ Vertex *z, *t;",
+ " ulong i; int nr;",
+ "",
+ " i = mk_special(sigma,n,v);",
+ " nr = ((L*TWIDTH)+Tally);",
+ " t = layers[nr];",
+ "",
+ " if (!t) return (Vertex *) 0;",
+ " layers[nr] = t = splay(i, t);",
+ " if (i == t->key)",
+ " for (z = t; z; z = z->lnk)",
+ " if (checkit(z, v, n, sigma))",
+ " return z;",
+ "",
+ " return (Vertex *) 0;",
+ "}",
+ "",
+ "static void",
+ "delete_it(Vertex *v, int L)",
+ "{ Vertex *x, *t;",
+ " ulong i; int nr;",
+ "",
+ " i = cheap_key(v);",
+ " nr = ((L*TWIDTH)+Tally);",
+ " t = layers[nr];",
+ " if (!t) return;",
+ "",
+ " t = splay(i, t);",
+ " if (i == t->key)",
+ " { Vertex *z, *y = (Vertex *) 0;",
+ " for (z = t; z && z != v; y = z, z = z->lnk)",
+ " ;",
+ " if (z != v) goto bad;",
+ " if (y)",
+ " { y->lnk = z->lnk;",
+ " z->lnk = (Vertex *) 0;",
+ " layers[nr] = t;",
+ " return;",
+ " } else if (z->lnk) /* z == t == v */",
+ " { y = z->lnk;",
+ " y->left = t->left;",
+ " y->right = t->right;",
+ " t->left = t->right = t->lnk = (Vertex *) 0;",
+ " layers[nr] = y;",
+ " return;",
+ " }",
+ " /* delete the node itself */",
+ " if (!t->left)",
+ " { x = t->right;",
+ " } else",
+ " { x = splay(i, t->left);",
+ " x->right = t->right;",
+ " }",
+ " t->left = t->right = t->lnk = (Vertex *) 0;",
+ " layers[nr] = x;",
+ " return;",
+ " }",
+ "bad: Uerror(\"cannot happen delete\");",
+ "}",
+ "#endif", /* MA */
+ 0,
+};
diff --git a/sys/src/cmd/spin/pangen5.c b/sys/src/cmd/spin/pangen5.c
new file mode 100755
index 000000000..25885e19c
--- /dev/null
+++ b/sys/src/cmd/spin/pangen5.c
@@ -0,0 +1,857 @@
+/***** spin: pangen5.c *****/
+
+/* Copyright (c) 1999-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 */
+
+#include "spin.h"
+#include "y.tab.h"
+
+typedef struct BuildStack {
+ FSM_trans *t;
+ struct BuildStack *nxt;
+} BuildStack;
+
+extern ProcList *rdy;
+extern int verbose, eventmapnr, claimnr, rvopt, export_ast, u_sync;
+extern Element *Al_El;
+
+static FSM_state *fsm_free;
+static FSM_trans *trans_free;
+static BuildStack *bs, *bf;
+static int max_st_id;
+static int cur_st_id;
+int o_max;
+FSM_state *fsm;
+FSM_state **fsm_tbl;
+FSM_use *use_free;
+
+static void ana_seq(Sequence *);
+static void ana_stmnt(FSM_trans *, Lextok *, int);
+
+extern void AST_slice(void);
+extern void AST_store(ProcList *, int);
+extern int has_global(Lextok *);
+extern void exit(int);
+
+static void
+fsm_table(void)
+{ FSM_state *f;
+ max_st_id += 2;
+ /* fprintf(stderr, "omax %d, max=%d\n", o_max, max_st_id); */
+ if (o_max < max_st_id)
+ { o_max = max_st_id;
+ fsm_tbl = (FSM_state **) emalloc(max_st_id * sizeof(FSM_state *));
+ } else
+ memset((char *)fsm_tbl, 0, max_st_id * sizeof(FSM_state *));
+ cur_st_id = max_st_id;
+ max_st_id = 0;
+
+ for (f = fsm; f; f = f->nxt)
+ fsm_tbl[f->from] = f;
+}
+
+static int
+FSM_DFS(int from, FSM_use *u)
+{ FSM_state *f;
+ FSM_trans *t;
+ FSM_use *v;
+ int n;
+
+ if (from == 0)
+ return 1;
+
+ f = fsm_tbl[from];
+
+ if (!f)
+ { printf("cannot find state %d\n", from);
+ fatal("fsm_dfs: cannot happen\n", (char *) 0);
+ }
+
+ if (f->seen)
+ return 1;
+ f->seen = 1;
+
+ for (t = f->t; t; t = t->nxt)
+ {
+ for (n = 0; n < 2; n++)
+ for (v = t->Val[n]; v; v = v->nxt)
+ if (u->var == v->var)
+ return n; /* a read or write */
+
+ if (!FSM_DFS(t->to, u))
+ return 0;
+ }
+ return 1;
+}
+
+static void
+new_dfs(void)
+{ int i;
+
+ for (i = 0; i < cur_st_id; i++)
+ if (fsm_tbl[i])
+ fsm_tbl[i]->seen = 0;
+}
+
+static int
+good_dead(Element *e, FSM_use *u)
+{
+ switch (u->special) {
+ case 2: /* ok if it's a receive */
+ if (e->n->ntyp == ASGN
+ && e->n->rgt->ntyp == CONST
+ && e->n->rgt->val == 0)
+ return 0;
+ break;
+ case 1: /* must be able to use oval */
+ if (e->n->ntyp != 'c'
+ && e->n->ntyp != 'r')
+ return 0; /* can't really happen */
+ break;
+ }
+ return 1;
+}
+
+#if 0
+static int howdeep = 0;
+#endif
+
+static int
+eligible(FSM_trans *v)
+{ Element *el = ZE;
+ Lextok *lt = ZN;
+
+ if (v) el = v->step;
+ if (el) lt = v->step->n;
+
+ if (!lt /* dead end */
+ || v->nxt /* has alternatives */
+ || el->esc /* has an escape */
+ || (el->status&CHECK2) /* remotely referenced */
+ || lt->ntyp == ATOMIC
+ || lt->ntyp == NON_ATOMIC /* used for inlines -- should be able to handle this */
+ || lt->ntyp == IF
+ || lt->ntyp == C_CODE
+ || lt->ntyp == C_EXPR
+ || has_lab(el, 0) /* any label at all */
+
+ || lt->ntyp == DO
+ || lt->ntyp == UNLESS
+ || lt->ntyp == D_STEP
+ || lt->ntyp == ELSE
+ || lt->ntyp == '@'
+ || lt->ntyp == 'c'
+ || lt->ntyp == 'r'
+ || lt->ntyp == 's')
+ return 0;
+
+ if (!(el->status&(2|4))) /* not atomic */
+ { int unsafe = (el->status&I_GLOB)?1:has_global(el->n);
+ if (unsafe)
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+canfill_in(FSM_trans *v)
+{ Element *el = v->step;
+ Lextok *lt = v->step->n;
+
+ if (!lt /* dead end */
+ || v->nxt /* has alternatives */
+ || el->esc /* has an escape */
+ || (el->status&CHECK2)) /* remotely referenced */
+ return 0;
+
+ if (!(el->status&(2|4)) /* not atomic */
+ && ((el->status&I_GLOB)
+ || has_global(el->n))) /* and not safe */
+ return 0;
+
+ return 1;
+}
+
+static int
+pushbuild(FSM_trans *v)
+{ BuildStack *b;
+
+ for (b = bs; b; b = b->nxt)
+ if (b->t == v)
+ return 0;
+ if (bf)
+ { b = bf;
+ bf = bf->nxt;
+ } else
+ b = (BuildStack *) emalloc(sizeof(BuildStack));
+ b->t = v;
+ b->nxt = bs;
+ bs = b;
+ return 1;
+}
+
+static void
+popbuild(void)
+{ BuildStack *f;
+ if (!bs)
+ fatal("cannot happen, popbuild", (char *) 0);
+ f = bs;
+ bs = bs->nxt;
+ f->nxt = bf;
+ bf = f; /* freelist */
+}
+
+static int
+build_step(FSM_trans *v)
+{ FSM_state *f;
+ Element *el = v->step;
+#if 0
+ Lextok *lt = ZN;
+#endif
+ int st = v->to;
+ int r;
+
+ if (!el) return -1;
+
+ if (v->step->merge)
+ return v->step->merge; /* already done */
+
+ if (!eligible(v)) /* non-blocking */
+ return -1;
+
+ if (!pushbuild(v)) /* cycle detected */
+ return -1; /* break cycle */
+
+ f = fsm_tbl[st];
+#if 0
+ lt = v->step->n;
+ if (verbose&32)
+ { if (++howdeep == 1)
+ printf("spin: %s, line %3d, merge:\n",
+ lt->fn->name,
+ lt->ln);
+ printf("\t[%d] <seqno %d>\t", howdeep, el->seqno);
+ comment(stdout, lt, 0);
+ printf(";\n");
+ }
+#endif
+ r = build_step(f->t);
+ v->step->merge = (r == -1) ? st : r;
+#if 0
+ if (verbose&32)
+ { printf(" merge value: %d (st=%d,r=%d, line %d)\n",
+ v->step->merge, st, r, el->n->ln);
+ howdeep--;
+ }
+#endif
+ popbuild();
+
+ return v->step->merge;
+}
+
+static void
+FSM_MERGER(char *pname_unused) /* find candidates for safely merging steps */
+{ FSM_state *f, *g;
+ FSM_trans *t;
+ Lextok *lt;
+
+ for (f = fsm; f; f = f->nxt) /* all states */
+ for (t = f->t; t; t = t->nxt) /* all edges */
+ { if (!t->step) continue; /* happens with 'unless' */
+
+ t->step->merge_in = f->in; /* ?? */
+
+ if (t->step->merge)
+ continue;
+ lt = t->step->n;
+
+ if (lt->ntyp == 'c'
+ || lt->ntyp == 'r'
+ || lt->ntyp == 's') /* blocking stmnts */
+ continue; /* handled in 2nd scan */
+
+ if (!eligible(t))
+ continue;
+
+ g = fsm_tbl[t->to];
+ if (!eligible(g->t))
+ {
+#define SINGLES
+#ifdef SINGLES
+ t->step->merge_single = t->to;
+#if 0
+ if ((verbose&32))
+ { printf("spin: %s, line %3d, merge_single:\n\t<seqno %d>\t",
+ t->step->n->fn->name,
+ t->step->n->ln,
+ t->step->seqno);
+ comment(stdout, t->step->n, 0);
+ printf(";\n");
+ }
+#endif
+#endif
+ /* t is an isolated eligible step:
+ *
+ * a merge_start can connect to a proper
+ * merge chain or to a merge_single
+ * a merge chain can be preceded by
+ * a merge_start, but not by a merge_single
+ */
+
+ continue;
+ }
+
+ (void) build_step(t);
+ }
+
+ /* 2nd scan -- find possible merge_starts */
+
+ for (f = fsm; f; f = f->nxt) /* all states */
+ for (t = f->t; t; t = t->nxt) /* all edges */
+ { if (!t->step || t->step->merge)
+ continue;
+
+ lt = t->step->n;
+#if 0
+ 4.1.3:
+ an rv send operation inside an atomic, *loses* atomicity
+ when executed
+ and should therefore never be merged with a subsequent
+ statement within the atomic sequence
+ the same is not true for non-rv send operations
+#endif
+
+ if (lt->ntyp == 'c' /* potentially blocking stmnts */
+ || lt->ntyp == 'r'
+ || (lt->ntyp == 's' && u_sync == 0)) /* added !u_sync in 4.1.3 */
+ { if (!canfill_in(t)) /* atomic, non-global, etc. */
+ continue;
+
+ g = fsm_tbl[t->to];
+ if (!g || !g->t || !g->t->step)
+ continue;
+ if (g->t->step->merge)
+ t->step->merge_start = g->t->step->merge;
+#ifdef SINGLES
+ else if (g->t->step->merge_single)
+ t->step->merge_start = g->t->step->merge_single;
+#endif
+#if 0
+ if ((verbose&32)
+ && t->step->merge_start)
+ { printf("spin: %s, line %3d, merge_START:\n\t<seqno %d>\t",
+ lt->fn->name,
+ lt->ln,
+ t->step->seqno);
+ comment(stdout, lt, 0);
+ printf(";\n");
+ }
+#endif
+ }
+ }
+}
+
+static void
+FSM_ANA(void)
+{ FSM_state *f;
+ FSM_trans *t;
+ FSM_use *u, *v, *w;
+ int n;
+
+ for (f = fsm; f; f = f->nxt) /* all states */
+ for (t = f->t; t; t = t->nxt) /* all edges */
+ for (n = 0; n < 2; n++) /* reads and writes */
+ for (u = t->Val[n]; u; u = u->nxt)
+ { if (!u->var->context /* global */
+ || u->var->type == CHAN
+ || u->var->type == STRUCT)
+ continue;
+ new_dfs();
+ if (FSM_DFS(t->to, u)) /* cannot hit read before hitting write */
+ u->special = n+1; /* means, reset to 0 after use */
+ }
+
+ if (!export_ast)
+ for (f = fsm; f; f = f->nxt)
+ for (t = f->t; t; t = t->nxt)
+ for (n = 0; n < 2; n++)
+ for (u = t->Val[n], w = (FSM_use *) 0; u; )
+ { if (u->special)
+ { v = u->nxt;
+ if (!w) /* remove from list */
+ t->Val[n] = v;
+ else
+ w->nxt = v;
+#if q
+ if (verbose&32)
+ { printf("%s : %3d: %d -> %d \t",
+ t->step->n->fn->name,
+ t->step->n->ln,
+ f->from,
+ t->to);
+ comment(stdout, t->step->n, 0);
+ printf("\t%c%d: %s\n", n==0?'R':'L',
+ u->special, u->var->name);
+ }
+#endif
+ if (good_dead(t->step, u))
+ { u->nxt = t->step->dead; /* insert into dead */
+ t->step->dead = u;
+ }
+ u = v;
+ } else
+ { w = u;
+ u = u->nxt;
+ } }
+}
+
+void
+rel_use(FSM_use *u)
+{
+ if (!u) return;
+ rel_use(u->nxt);
+ u->var = (Symbol *) 0;
+ u->special = 0;
+ u->nxt = use_free;
+ use_free = u;
+}
+
+static void
+rel_trans(FSM_trans *t)
+{
+ if (!t) return;
+ rel_trans(t->nxt);
+ rel_use(t->Val[0]);
+ rel_use(t->Val[1]);
+ t->Val[0] = t->Val[1] = (FSM_use *) 0;
+ t->nxt = trans_free;
+ trans_free = t;
+}
+
+static void
+rel_state(FSM_state *f)
+{
+ if (!f) return;
+ rel_state(f->nxt);
+ rel_trans(f->t);
+ f->t = (FSM_trans *) 0;
+ f->nxt = fsm_free;
+ fsm_free = f;
+}
+
+static void
+FSM_DEL(void)
+{
+ rel_state(fsm);
+ fsm = (FSM_state *) 0;
+}
+
+static FSM_state *
+mkstate(int s)
+{ FSM_state *f;
+
+ /* fsm_tbl isn't allocated yet */
+ for (f = fsm; f; f = f->nxt)
+ if (f->from == s)
+ break;
+ if (!f)
+ { if (fsm_free)
+ { f = fsm_free;
+ memset(f, 0, sizeof(FSM_state));
+ fsm_free = fsm_free->nxt;
+ } else
+ f = (FSM_state *) emalloc(sizeof(FSM_state));
+ f->from = s;
+ f->t = (FSM_trans *) 0;
+ f->nxt = fsm;
+ fsm = f;
+ if (s > max_st_id)
+ max_st_id = s;
+ }
+ return f;
+}
+
+static FSM_trans *
+get_trans(int to)
+{ FSM_trans *t;
+
+ if (trans_free)
+ { t = trans_free;
+ memset(t, 0, sizeof(FSM_trans));
+ trans_free = trans_free->nxt;
+ } else
+ t = (FSM_trans *) emalloc(sizeof(FSM_trans));
+
+ t->to = to;
+ return t;
+}
+
+static void
+FSM_EDGE(int from, int to, Element *e)
+{ FSM_state *f;
+ FSM_trans *t;
+
+ f = mkstate(from); /* find it or else make it */
+ t = get_trans(to);
+
+ t->step = e;
+ t->nxt = f->t;
+ f->t = t;
+
+ f = mkstate(to);
+ f->in++;
+
+ if (export_ast)
+ { t = get_trans(from);
+ t->step = e;
+ t->nxt = f->p; /* from is a predecessor of to */
+ f->p = t;
+ }
+
+ if (t->step)
+ ana_stmnt(t, t->step->n, 0);
+}
+
+#define LVAL 1
+#define RVAL 0
+
+static void
+ana_var(FSM_trans *t, Lextok *now, int usage)
+{ FSM_use *u, *v;
+
+ if (!t || !now || !now->sym)
+ return;
+
+ if (now->sym->name[0] == '_'
+ && (strcmp(now->sym->name, "_") == 0
+ || strcmp(now->sym->name, "_pid") == 0
+ || strcmp(now->sym->name, "_last") == 0))
+ return;
+
+ v = t->Val[usage];
+ for (u = v; u; u = u->nxt)
+ if (u->var == now->sym)
+ return; /* it's already there */
+
+ if (!now->lft)
+ { /* not for array vars -- it's hard to tell statically
+ if the index would, at runtime, evaluate to the
+ same values at lval and rval references
+ */
+ if (use_free)
+ { u = use_free;
+ use_free = use_free->nxt;
+ } else
+ u = (FSM_use *) emalloc(sizeof(FSM_use));
+
+ u->var = now->sym;
+ u->nxt = t->Val[usage];
+ t->Val[usage] = u;
+ } else
+ ana_stmnt(t, now->lft, RVAL); /* index */
+
+ if (now->sym->type == STRUCT
+ && now->rgt
+ && now->rgt->lft)
+ ana_var(t, now->rgt->lft, usage);
+}
+
+static void
+ana_stmnt(FSM_trans *t, Lextok *now, int usage)
+{ Lextok *v;
+
+ if (!t || !now) return;
+
+ switch (now->ntyp) {
+ case '.':
+ case BREAK:
+ case GOTO:
+ case CONST:
+ case TIMEOUT:
+ case NONPROGRESS:
+ case ELSE:
+ case '@':
+ case 'q':
+ case IF:
+ case DO:
+ case ATOMIC:
+ case NON_ATOMIC:
+ case D_STEP:
+ case C_CODE:
+ case C_EXPR:
+ break;
+
+ case '!':
+ case UMIN:
+ case '~':
+ case ENABLED:
+ case PC_VAL:
+ case LEN:
+ case FULL:
+ case EMPTY:
+ case NFULL:
+ case NEMPTY:
+ case ASSERT:
+ case 'c':
+ ana_stmnt(t, now->lft, RVAL);
+ break;
+
+ case '/':
+ case '*':
+ case '-':
+ case '+':
+ case '%':
+ case '&':
+ case '^':
+ case '|':
+ case LT:
+ case GT:
+ case LE:
+ case GE:
+ case NE:
+ case EQ:
+ case OR:
+ case AND:
+ case LSHIFT:
+ case RSHIFT:
+ ana_stmnt(t, now->lft, RVAL);
+ ana_stmnt(t, now->rgt, RVAL);
+ break;
+
+ case ASGN:
+ ana_stmnt(t, now->lft, LVAL);
+ ana_stmnt(t, now->rgt, RVAL);
+ break;
+
+ case PRINT:
+ case RUN:
+ for (v = now->lft; v; v = v->rgt)
+ ana_stmnt(t, v->lft, RVAL);
+ break;
+
+ case PRINTM:
+ if (now->lft && !now->lft->ismtyp)
+ ana_stmnt(t, now->lft, RVAL);
+ break;
+
+ case 's':
+ ana_stmnt(t, now->lft, RVAL);
+ for (v = now->rgt; v; v = v->rgt)
+ ana_stmnt(t, v->lft, RVAL);
+ break;
+
+ case 'R':
+ case 'r':
+ ana_stmnt(t, now->lft, RVAL);
+ for (v = now->rgt; v; v = v->rgt)
+ { if (v->lft->ntyp == EVAL)
+ ana_stmnt(t, v->lft->lft, RVAL);
+ else
+ if (v->lft->ntyp != CONST
+ && now->ntyp != 'R') /* was v->lft->ntyp */
+ ana_stmnt(t, v->lft, LVAL);
+ }
+ break;
+
+ case '?':
+ ana_stmnt(t, now->lft, RVAL);
+ if (now->rgt)
+ { ana_stmnt(t, now->rgt->lft, RVAL);
+ ana_stmnt(t, now->rgt->rgt, RVAL);
+ }
+ break;
+
+ case NAME:
+ ana_var(t, now, usage);
+ break;
+
+ case 'p': /* remote ref */
+ ana_stmnt(t, now->lft->lft, RVAL); /* process id */
+ ana_var(t, now, RVAL);
+ ana_var(t, now->rgt, RVAL);
+ break;
+
+ default:
+ printf("spin: bad node type %d line %d (ana_stmnt)\n", now->ntyp, now->ln);
+ fatal("aborting", (char *) 0);
+ }
+}
+
+void
+ana_src(int dataflow, int merger) /* called from main.c and guided.c */
+{ ProcList *p;
+ Element *e;
+#if 0
+ int counter = 1;
+#endif
+ for (p = rdy; p; p = p->nxt)
+ { if (p->tn == eventmapnr
+ || p->tn == claimnr)
+ continue;
+
+ ana_seq(p->s);
+ fsm_table();
+
+ e = p->s->frst;
+#if 0
+ if (dataflow || merger)
+ { printf("spin: %d, optimizing '%s'",
+ counter++, p->n->name);
+ fflush(stdout);
+ }
+#endif
+ if (dataflow)
+ { FSM_ANA();
+ }
+ if (merger)
+ { FSM_MERGER(p->n->name);
+ huntele(e, e->status, -1)->merge_in = 1; /* start-state */
+#if 0
+ printf("\n");
+#endif
+ }
+ if (export_ast)
+ AST_store(p, huntele(e, e->status, -1)->seqno);
+
+ FSM_DEL();
+ }
+ for (e = Al_El; e; e = e->Nxt)
+ {
+ if (!(e->status&DONE) && (verbose&32))
+ { printf("unreachable code: ");
+ printf("%s, line %3d: ",
+ e->n->fn->name, e->n->ln);
+ comment(stdout, e->n, 0);
+ printf("\n");
+ }
+ e->status &= ~DONE;
+ }
+ if (export_ast)
+ { AST_slice();
+ exit(0);
+ }
+}
+
+void
+spit_recvs(FILE *f1, FILE *f2) /* called from pangen2.c */
+{ Element *e;
+ Sequence *s;
+ extern int Unique;
+
+ fprintf(f1, "unsigned char Is_Recv[%d];\n", Unique);
+
+ fprintf(f2, "void\nset_recvs(void)\n{\n");
+ for (e = Al_El; e; e = e->Nxt)
+ { if (!e->n) continue;
+
+ switch (e->n->ntyp) {
+ case 'r':
+markit: fprintf(f2, "\tIs_Recv[%d] = 1;\n", e->Seqno);
+ break;
+ case D_STEP:
+ s = e->n->sl->this;
+ switch (s->frst->n->ntyp) {
+ case DO:
+ fatal("unexpected: do at start of d_step", (char *) 0);
+ case IF: /* conservative: fall through */
+ case 'r': goto markit;
+ }
+ break;
+ }
+ }
+ fprintf(f2, "}\n");
+
+ if (rvopt)
+ {
+ fprintf(f2, "int\nno_recvs(int me)\n{\n");
+ fprintf(f2, " int h; uchar ot; short tt;\n");
+ fprintf(f2, " Trans *t;\n");
+ fprintf(f2, " for (h = BASE; h < (int) now._nr_pr; h++)\n");
+ fprintf(f2, " { if (h == me) continue;\n");
+ fprintf(f2, " tt = (short) ((P0 *)pptr(h))->_p;\n");
+ fprintf(f2, " ot = (uchar) ((P0 *)pptr(h))->_t;\n");
+ fprintf(f2, " for (t = trans[ot][tt]; t; t = t->nxt)\n");
+ fprintf(f2, " if (Is_Recv[t->t_id]) return 0;\n");
+ fprintf(f2, " }\n");
+ fprintf(f2, " return 1;\n");
+ fprintf(f2, "}\n");
+ }
+}
+
+static void
+ana_seq(Sequence *s)
+{ SeqList *h;
+ Sequence *t;
+ Element *e, *g;
+ int From, To;
+
+ for (e = s->frst; e; e = e->nxt)
+ { if (e->status & DONE)
+ goto checklast;
+
+ e->status |= DONE;
+
+ From = e->seqno;
+
+ if (e->n->ntyp == UNLESS)
+ ana_seq(e->sub->this);
+ else if (e->sub)
+ { for (h = e->sub; h; h = h->nxt)
+ { g = huntstart(h->this->frst);
+ To = g->seqno;
+
+ if (g->n->ntyp != 'c'
+ || g->n->lft->ntyp != CONST
+ || g->n->lft->val != 0
+ || g->esc)
+ FSM_EDGE(From, To, e);
+ /* else it's a dead link */
+ }
+ for (h = e->sub; h; h = h->nxt)
+ ana_seq(h->this);
+ } else if (e->n->ntyp == ATOMIC
+ || e->n->ntyp == D_STEP
+ || e->n->ntyp == NON_ATOMIC)
+ {
+ t = e->n->sl->this;
+ g = huntstart(t->frst);
+ t->last->nxt = e->nxt;
+ To = g->seqno;
+ FSM_EDGE(From, To, e);
+
+ ana_seq(t);
+ } else
+ { if (e->n->ntyp == GOTO)
+ { g = get_lab(e->n, 1);
+ g = huntele(g, e->status, -1);
+ To = g->seqno;
+ } else if (e->nxt)
+ { g = huntele(e->nxt, e->status, -1);
+ To = g->seqno;
+ } else
+ To = 0;
+
+ FSM_EDGE(From, To, e);
+
+ if (e->esc
+ && e->n->ntyp != GOTO
+ && e->n->ntyp != '.')
+ for (h = e->esc; h; h = h->nxt)
+ { g = huntstart(h->this->frst);
+ To = g->seqno;
+ FSM_EDGE(From, To, ZE);
+ ana_seq(h->this);
+ }
+ }
+
+checklast: if (e == s->last)
+ break;
+ }
+}
diff --git a/sys/src/cmd/spin/pangen5.h b/sys/src/cmd/spin/pangen5.h
new file mode 100755
index 000000000..5313e73b2
--- /dev/null
+++ b/sys/src/cmd/spin/pangen5.h
@@ -0,0 +1,424 @@
+/***** spin: pangen5.h *****/
+
+/* 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 */
+
+static char *Xpt[] = {
+ "#if defined(MA) && (defined(W_XPT) || defined(R_XPT))",
+ "static Vertex **temptree;",
+ "static char wbuf[4096];",
+ "static int WCNT = 4096, wcnt=0;",
+ "static uchar stacker[MA+1];",
+ "static ulong stackcnt = 0;",
+ "extern double nstates, nlinks, truncs, truncs2;",
+ "",
+ "static void",
+ "xwrite(int fd, char *b, int n)",
+ "{",
+ " if (wcnt+n >= 4096)",
+ " { write(fd, wbuf, wcnt);",
+ " wcnt = 0;",
+ " }",
+ " memcpy(&wbuf[wcnt], b, n);",
+ " wcnt += n;",
+ "}",
+ "",
+ "static void",
+ "wclose(fd)",
+ "{",
+ " if (wcnt > 0)",
+ " write(fd, wbuf, wcnt);",
+ " wcnt = 0;",
+ " close(fd);",
+ "}",
+ "",
+ "static void",
+ "w_vertex(int fd, Vertex *v)",
+ "{ char t[3]; int i; Edge *e;",
+ "",
+ " xwrite(fd, (char *) &v, sizeof(Vertex *));",
+ " t[0] = 0;",
+ " for (i = 0; i < 2; i++)",
+ " if (v->dst[i])",
+ " { t[1] = v->from[i], t[2] = v->to[i];",
+ " xwrite(fd, t, 3);",
+ " xwrite(fd, (char *) &(v->dst[i]), sizeof(Vertex *));",
+ " }",
+ " for (e = v->Succ; e; e = e->Nxt)",
+ " { t[1] = e->From, t[2] = e->To;",
+ " xwrite(fd, t, 3);",
+ " xwrite(fd, (char *) &(e->Dst), sizeof(Vertex *));",
+ "",
+ " if (e->s)",
+ " { t[1] = t[2] = e->S;",
+ " xwrite(fd, t, 3);",
+ " xwrite(fd, (char *) &(e->Dst), sizeof(Vertex *));",
+ " } }",
+ "}",
+ "",
+ "static void",
+ "w_layer(int fd, Vertex *v)",
+ "{ uchar c=1;",
+ "",
+ " if (!v) return;",
+ " xwrite(fd, (char *) &c, 1);",
+ " w_vertex(fd, v);",
+ " w_layer(fd, v->lnk);",
+ " w_layer(fd, v->left);",
+ " w_layer(fd, v->right);",
+ "}",
+ "",
+ "void",
+ "w_xpoint(void)",
+ "{ int fd; char nm[64];",
+ " int i, j; uchar c;",
+ " static uchar xwarned = 0;",
+ "",
+ " sprintf(nm, \"%%s.xpt\", Source);",
+ " if ((fd = creat(nm, 0666)) <= 0)",
+ " if (!xwarned)",
+ " { xwarned = 1;",
+ " printf(\"cannot creat checkpoint file\\n\");",
+ " return;",
+ " }",
+ " xwrite(fd, (char *) &nstates, sizeof(double));",
+ " xwrite(fd, (char *) &truncs, sizeof(double));",
+ " xwrite(fd, (char *) &truncs2, sizeof(double));",
+ " xwrite(fd, (char *) &nlinks, sizeof(double));",
+ " xwrite(fd, (char *) &dfa_depth, sizeof(int));",
+ " xwrite(fd, (char *) &R, sizeof(Vertex *));",
+ " xwrite(fd, (char *) &F, sizeof(Vertex *));",
+ " xwrite(fd, (char *) &NF, sizeof(Vertex *));",
+ "",
+ " for (j = 0; j < TWIDTH; j++)",
+ " for (i = 0; i < dfa_depth+1; i++)",
+ " { w_layer(fd, layers[i*TWIDTH+j]);",
+ " c = 2; xwrite(fd, (char *) &c, 1);",
+ " }",
+ " wclose(fd);",
+ "}",
+ "",
+ "static void",
+ "xread(int fd, char *b, int n)",
+ "{ int m = wcnt; int delta = 0;",
+ " if (m < n)",
+ " { if (m > 0) memcpy(b, &wbuf[WCNT-m], m);",
+ " delta = m;",
+ " WCNT = wcnt = read(fd, wbuf, 4096);",
+ " if (wcnt < n-m)",
+ " Uerror(\"xread failed -- insufficient data\");",
+ " n -= m;",
+ " }",
+ " memcpy(&b[delta], &wbuf[WCNT-wcnt], n);",
+ " wcnt -= n;",
+ "}",
+ "",
+ "static void",
+ "x_cleanup(Vertex *c)",
+ "{ Edge *e; /* remove the tree and edges from c */",
+ " if (!c) return;",
+ " for (e = c->Succ; e; e = e->Nxt)",
+ " x_cleanup(e->Dst);",
+ " recyc_vertex(c);",
+ "}",
+ "",
+ "static void",
+ "x_remove(void)",
+ "{ Vertex *tmp; int i, s;",
+ " int r, j;",
+ " /* double-check: */",
+ " stacker[dfa_depth-1] = 0; r = dfa_store(stacker);",
+ " stacker[dfa_depth-1] = 4; j = dfa_member(dfa_depth-1);",
+ " if (r != 1 || j != 0)",
+ " { printf(\"%%d: \", stackcnt);",
+ " for (i = 0; i < dfa_depth; i++)",
+ " printf(\"%%d,\", stacker[i]);",
+ " printf(\" -- not a stackstate <o:%%d,4:%%d>\\n\", r, j);",
+ " return;",
+ " }",
+ " stacker[dfa_depth-1] = 1;",
+ " s = dfa_member(dfa_depth-1);",
+ "",
+ " { tmp = F; F = NF; NF = tmp; } /* complement */",
+ " if (s) dfa_store(stacker);",
+ " stacker[dfa_depth-1] = 0;",
+ " dfa_store(stacker);",
+ " stackcnt++;",
+ " { tmp = F; F = NF; NF = tmp; }",
+ "}",
+ "",
+ "static void",
+ "x_rm_stack(Vertex *t, int k)",
+ "{ int j; Edge *e;",
+ "",
+ " if (k == 0)",
+ " { x_remove();",
+ " return;",
+ " }",
+ " if (t)",
+ " for (e = t->Succ; e; e = e->Nxt)",
+ " { for (j = e->From; j <= (int) e->To; j++)",
+ " { stacker[k] = (uchar) j;",
+ " x_rm_stack(e->Dst, k-1);",
+ " }",
+ " if (e->s)",
+ " { stacker[k] = e->S;",
+ " x_rm_stack(e->Dst, k-1);",
+ " } }",
+ "}",
+ "",
+ "static Vertex *",
+ "insert_withkey(Vertex *v, int L)",
+ "{ Vertex *new, *t = temptree[L];",
+ "",
+ " if (!t) { temptree[L] = v; return v; }",
+ " t = splay(v->key, t);",
+ " if (v->key < t->key)",
+ " { new = v;",
+ " new->left = t->left;",
+ " new->right = t;",
+ " t->left = (Vertex *) 0;",
+ " } else if (v->key > t->key)",
+ " { new = v;",
+ " new->right = t->right;",
+ " new->left = t;",
+ " t->right = (Vertex *) 0;",
+ " } else",
+ " { if (t != R && t != F && t != NF)",
+ " Uerror(\"double insert, bad checkpoint data\");",
+ " else",
+ " { recyc_vertex(v);",
+ " new = t;",
+ " } }",
+ " temptree[L] = new;",
+ "",
+ " return new;",
+ "}",
+ "",
+ "static Vertex *",
+ "find_withkey(Vertex *v, int L)",
+ "{ Vertex *t = temptree[L];",
+ " if (t)",
+ " { temptree[L] = t = splay((ulong) v, t);",
+ " if (t->key == (ulong) v)",
+ " return t;",
+ " }",
+ " Uerror(\"not found error, bad checkpoint data\");",
+ " return (Vertex *) 0;",
+ "}",
+ "",
+ "void",
+ "r_layer(int fd, int n)",
+ "{ Vertex *v;",
+ " Edge *e;",
+ " char c, t[2];",
+ "",
+ " for (;;)",
+ " { xread(fd, &c, 1);",
+ " if (c == 2) break;",
+ " if (c == 1)",
+ " { v = new_vertex();",
+ " xread(fd, (char *) &(v->key), sizeof(Vertex *));",
+ " v = insert_withkey(v, n);",
+ " } else /* c == 0 */",
+ " { e = new_edge((Vertex *) 0);",
+ " xread(fd, t, 2);",
+ " e->From = t[0];",
+ " e->To = t[1];",
+ " xread(fd, (char *) &(e->Dst), sizeof(Vertex *));",
+ " insert_edge(v, e);",
+ " } }",
+ "}",
+ "",
+ "static void",
+ "v_fix(Vertex *t, int nr)",
+ "{ int i; Edge *e;",
+ "",
+ " if (!t) return;",
+ "",
+ " for (i = 0; i < 2; i++)",
+ " if (t->dst[i])",
+ " t->dst[i] = find_withkey(t->dst[i], nr);",
+ "",
+ " for (e = t->Succ; e; e = e->Nxt)",
+ " e->Dst = find_withkey(e->Dst, nr);",
+ " ",
+ " v_fix(t->left, nr);",
+ " v_fix(t->right, nr);",
+ "}",
+ "",
+ "static void",
+ "v_insert(Vertex *t, int nr)",
+ "{ Edge *e; int i;",
+ "",
+ " if (!t) return;",
+ " v_insert(t->left, nr);",
+ " v_insert(t->right, nr);",
+ "",
+ " /* remove only leafs from temptree */",
+ " t->left = t->right = t->lnk = (Vertex *) 0;",
+ " insert_it(t, nr); /* into layers */",
+ " for (i = 0; i < 2; i++)",
+ " if (t->dst[i])",
+ " t->dst[i]->num += (t->to[i] - t->from[i] + 1);",
+ " for (e = t->Succ; e; e = e->Nxt)",
+ " e->Dst->num += (e->To - e->From + 1 + e->s);",
+ "}",
+ "",
+ "static void",
+ "x_fixup(void)",
+ "{ int i;",
+ "",
+ " for (i = 0; i < dfa_depth; i++)",
+ " v_fix(temptree[i], (i+1));",
+ "",
+ " for (i = dfa_depth; i >= 0; i--)",
+ " v_insert(temptree[i], i);",
+ "}",
+ "",
+ "static Vertex *",
+ "x_tail(Vertex *t, ulong want)",
+ "{ int i, yes, no; Edge *e; Vertex *v = (Vertex *) 0;",
+ "",
+ " if (!t) return v;",
+ "",
+ " yes = no = 0;",
+ " for (i = 0; i < 2; i++)",
+ " if ((ulong) t->dst[i] == want)",
+ " { /* was t->from[i] <= 0 && t->to[i] >= 0 */",
+ " /* but from and to are uchar */",
+ " if (t->from[i] == 0)",
+ " yes = 1;",
+ " else",
+ " if (t->from[i] <= 4 && t->to[i] >= 4)",
+ " no = 1;",
+ " }",
+ "",
+ " for (e = t->Succ; e; e = e->Nxt)",
+ " if ((ulong) e->Dst == want)",
+ " { /* was INRANGE(e,0) but From and To are uchar */",
+ " if ((e->From == 0) || (e->s==1 && e->S==0))",
+ " yes = 1;",
+ " else if (INRANGE(e, 4))",
+ " no = 1;",
+ " }",
+ " if (yes && !no) return t;",
+ " v = x_tail(t->left, want); if (v) return v;",
+ " v = x_tail(t->right, want); if (v) return v;",
+ " return (Vertex *) 0;",
+ "}",
+ "",
+ "static void",
+ "x_anytail(Vertex *t, Vertex *c, int nr)",
+ "{ int i; Edge *e, *f; Vertex *v;",
+ "",
+ " if (!t) return;",
+ "",
+ " for (i = 0; i < 2; i++)",
+ " if ((ulong) t->dst[i] == c->key)",
+ " { v = new_vertex(); v->key = t->key;",
+ " f = new_edge(v);",
+ " f->From = t->from[i];",
+ " f->To = t->to[i];",
+ " f->Nxt = c->Succ;",
+ " c->Succ = f;",
+ " if (nr > 0)",
+ " x_anytail(temptree[nr-1], v, nr-1);",
+ " }",
+ "",
+ " for (e = t->Succ; e; e = e->Nxt)",
+ " if ((ulong) e->Dst == c->key)",
+ " { v = new_vertex(); v->key = t->key;",
+ " f = new_edge(v);",
+ " f->From = e->From;",
+ " f->To = e->To;",
+ " f->s = e->s;",
+ " f->S = e->S;",
+ " f->Nxt = c->Succ;",
+ " c->Succ = f;",
+ " x_anytail(temptree[nr-1], v, nr-1);",
+ " }",
+ "",
+ " x_anytail(t->left, c, nr);",
+ " x_anytail(t->right, c, nr);",
+ "}",
+ "",
+ "static Vertex *",
+ "x_cpy_rev(void)",
+ "{ Vertex *c, *v; /* find 0 and !4 predecessor of F */",
+ "",
+ " v = x_tail(temptree[dfa_depth-1], F->key);",
+ " if (!v) return (Vertex *) 0;",
+ "",
+ " c = new_vertex(); c->key = v->key;",
+ "",
+ " /* every node on dfa_depth-2 that has v->key as succ */",
+ " /* make copy and let c point to these (reversing ptrs) */",
+ "",
+ " x_anytail(temptree[dfa_depth-2], c, dfa_depth-2);",
+ " ",
+ " return c;",
+ "}",
+ "",
+ "void",
+ "r_xpoint(void)",
+ "{ int fd; char nm[64]; Vertex *d;",
+ " int i, j;",
+ "",
+ " wcnt = 0;",
+ " sprintf(nm, \"%%s.xpt\", Source);",
+ " if ((fd = open(nm, 0)) < 0) /* O_RDONLY */",
+ " Uerror(\"cannot open checkpoint file\");",
+ "",
+ " xread(fd, (char *) &nstates, sizeof(double));",
+ " xread(fd, (char *) &truncs, sizeof(double));",
+ " xread(fd, (char *) &truncs2, sizeof(double));",
+ " xread(fd, (char *) &nlinks, sizeof(double));",
+ " xread(fd, (char *) &dfa_depth, sizeof(int));",
+ "",
+ " if (dfa_depth != MA+a_cycles)",
+ " Uerror(\"bad dfa_depth in checkpoint file\");",
+ "",
+ " path = (Vertex **) emalloc((dfa_depth+1)*sizeof(Vertex *));",
+ " layers = (Vertex **) emalloc(TWIDTH*(dfa_depth+1)*sizeof(Vertex *));",
+ " temptree = (Vertex **) emalloc((dfa_depth+2)*sizeof(Vertex *));",
+ " lastword = (uchar *) emalloc((dfa_depth+1)*sizeof(uchar));",
+ " lastword[dfa_depth] = lastword[0] = 255; ",
+ "",
+ " path[0] = R = new_vertex();",
+ " xread(fd, (char *) &R->key, sizeof(Vertex *));",
+ " R = insert_withkey(R, 0);",
+ "",
+ " F = new_vertex();",
+ " xread(fd, (char *) &F->key, sizeof(Vertex *));",
+ " F = insert_withkey(F, dfa_depth);",
+ "",
+ " NF = new_vertex();",
+ " xread(fd, (char *) &NF->key, sizeof(Vertex *));",
+ " NF = insert_withkey(NF, dfa_depth);",
+ "",
+ " for (j = 0; j < TWIDTH; j++)",
+ " for (i = 0; i < dfa_depth+1; i++)",
+ " r_layer(fd, i);",
+ "",
+ " if (wcnt != 0) Uerror(\"bad count in checkpoint file\");",
+ "",
+ " d = x_cpy_rev();",
+ " x_fixup();",
+ " stacker[dfa_depth-1] = 0;",
+ " x_rm_stack(d, dfa_depth-2);",
+ " x_cleanup(d);",
+ " close(fd);",
+ "",
+ " printf(\"pan: removed %%d stackstates\\n\", stackcnt);",
+ " nstates -= (double) stackcnt;",
+ "}",
+ "#endif",
+ 0,
+};
diff --git a/sys/src/cmd/spin/pangen6.c b/sys/src/cmd/spin/pangen6.c
new file mode 100755
index 000000000..50b587749
--- /dev/null
+++ b/sys/src/cmd/spin/pangen6.c
@@ -0,0 +1,2352 @@
+/***** spin: pangen6.c *****/
+
+/* Copyright (c) 2000-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 */
+
+/* Abstract syntax tree analysis / slicing (spin option -A) */
+/* AST_store stores the fsms's for each proctype */
+/* AST_track keeps track of variables used in properties */
+/* AST_slice starts the slicing algorithm */
+/* it first collects more info and then calls */
+/* AST_criteria to process the slice criteria */
+
+#include "spin.h"
+#include "y.tab.h"
+
+extern Ordered *all_names;
+extern FSM_use *use_free;
+extern FSM_state **fsm_tbl;
+extern FSM_state *fsm;
+extern int verbose, o_max;
+
+static FSM_trans *cur_t;
+static FSM_trans *expl_par;
+static FSM_trans *expl_var;
+static FSM_trans *explicit;
+
+extern void rel_use(FSM_use *);
+
+#define ulong unsigned long
+
+typedef struct Pair {
+ FSM_state *h;
+ int b;
+ struct Pair *nxt;
+} Pair;
+
+typedef struct AST {
+ ProcList *p; /* proctype decl */
+ int i_st; /* start state */
+ int nstates, nwords;
+ int relevant;
+ Pair *pairs; /* entry and exit nodes of proper subgraphs */
+ FSM_state *fsm; /* proctype body */
+ struct AST *nxt; /* linked list */
+} AST;
+
+typedef struct RPN { /* relevant proctype names */
+ Symbol *rn;
+ struct RPN *nxt;
+} RPN;
+
+typedef struct ALIAS { /* channel aliasing info */
+ Lextok *cnm; /* this chan */
+ int origin; /* debugging - origin of the alias */
+ struct ALIAS *alias; /* can be an alias for these other chans */
+ struct ALIAS *nxt; /* linked list */
+} ALIAS;
+
+typedef struct ChanList {
+ Lextok *s; /* containing stmnt */
+ Lextok *n; /* point of reference - could be struct */
+ struct ChanList *nxt; /* linked list */
+} ChanList;
+
+/* a chan alias can be created in one of three ways:
+ assignement to chan name
+ a = b -- a is now an alias for b
+ passing chan name as parameter in run
+ run x(b) -- proctype x(chan a)
+ passing chan name through channel
+ x!b -- x?a
+ */
+
+#define USE 1
+#define DEF 2
+#define DEREF_DEF 4
+#define DEREF_USE 8
+
+static AST *ast;
+static ALIAS *chalcur;
+static ALIAS *chalias;
+static ChanList *chanlist;
+static Slicer *slicer;
+static Slicer *rel_vars; /* all relevant variables */
+static int AST_Changes;
+static int AST_Round;
+static FSM_state no_state;
+static RPN *rpn;
+static int in_recv = 0;
+
+static int AST_mutual(Lextok *, Lextok *, int);
+static void AST_dominant(void);
+static void AST_hidden(void);
+static void AST_setcur(Lextok *);
+static void check_slice(Lextok *, int);
+static void curtail(AST *);
+static void def_use(Lextok *, int);
+static void name_AST_track(Lextok *, int);
+static void show_expl(void);
+
+static int
+AST_isini(Lextok *n) /* is this an initialized channel */
+{ Symbol *s;
+
+ if (!n || !n->sym) return 0;
+
+ s = n->sym;
+
+ if (s->type == CHAN)
+ return (s->ini->ntyp == CHAN); /* freshly instantiated */
+
+ if (s->type == STRUCT && n->rgt)
+ return AST_isini(n->rgt->lft);
+
+ return 0;
+}
+
+static void
+AST_var(Lextok *n, Symbol *s, int toplevel)
+{
+ if (!s) return;
+
+ if (toplevel)
+ { if (s->context && s->type)
+ printf(":%s:L:", s->context->name);
+ else
+ printf("G:");
+ }
+ printf("%s", s->name); /* array indices ignored */
+
+ if (s->type == STRUCT && n && n->rgt && n->rgt->lft)
+ { printf(":");
+ AST_var(n->rgt->lft, n->rgt->lft->sym, 0);
+ }
+}
+
+static void
+name_def_indices(Lextok *n, int code)
+{
+ if (!n || !n->sym) return;
+
+ if (n->sym->nel != 1)
+ def_use(n->lft, code); /* process the index */
+
+ if (n->sym->type == STRUCT /* and possible deeper ones */
+ && n->rgt)
+ name_def_indices(n->rgt->lft, code);
+}
+
+static void
+name_def_use(Lextok *n, int code)
+{ FSM_use *u;
+
+ if (!n) return;
+
+ if ((code&USE)
+ && cur_t->step
+ && cur_t->step->n)
+ { switch (cur_t->step->n->ntyp) {
+ case 'c': /* possible predicate abstraction? */
+ n->sym->colnr |= 2; /* yes */
+ break;
+ default:
+ n->sym->colnr |= 1; /* no */
+ break;
+ }
+ }
+
+ for (u = cur_t->Val[0]; u; u = u->nxt)
+ if (AST_mutual(n, u->n, 1)
+ && u->special == code)
+ return;
+
+ if (use_free)
+ { u = use_free;
+ use_free = use_free->nxt;
+ } else
+ u = (FSM_use *) emalloc(sizeof(FSM_use));
+
+ u->n = n;
+ u->special = code;
+ u->nxt = cur_t->Val[0];
+ cur_t->Val[0] = u;
+
+ name_def_indices(n, USE|(code&(~DEF))); /* not def, but perhaps deref */
+}
+
+static void
+def_use(Lextok *now, int code)
+{ Lextok *v;
+
+ if (now)
+ switch (now->ntyp) {
+ case '!':
+ case UMIN:
+ case '~':
+ case 'c':
+ case ENABLED:
+ case ASSERT:
+ case EVAL:
+ def_use(now->lft, USE|code);
+ break;
+
+ case LEN:
+ case FULL:
+ case EMPTY:
+ case NFULL:
+ case NEMPTY:
+ def_use(now->lft, DEREF_USE|USE|code);
+ break;
+
+ case '/':
+ case '*':
+ case '-':
+ case '+':
+ case '%':
+ case '&':
+ case '^':
+ case '|':
+ case LE:
+ case GE:
+ case GT:
+ case LT:
+ case NE:
+ case EQ:
+ case OR:
+ case AND:
+ case LSHIFT:
+ case RSHIFT:
+ def_use(now->lft, USE|code);
+ def_use(now->rgt, USE|code);
+ break;
+
+ case ASGN:
+ def_use(now->lft, DEF|code);
+ def_use(now->rgt, USE|code);
+ break;
+
+ case TYPE: /* name in parameter list */
+ name_def_use(now, code);
+ break;
+
+ case NAME:
+ name_def_use(now, code);
+ break;
+
+ case RUN:
+ name_def_use(now, USE); /* procname - not really needed */
+ for (v = now->lft; v; v = v->rgt)
+ def_use(v->lft, USE); /* params */
+ break;
+
+ case 's':
+ def_use(now->lft, DEREF_DEF|DEREF_USE|USE|code);
+ for (v = now->rgt; v; v = v->rgt)
+ def_use(v->lft, USE|code);
+ break;
+
+ case 'r':
+ def_use(now->lft, DEREF_DEF|DEREF_USE|USE|code);
+ for (v = now->rgt; v; v = v->rgt)
+ { if (v->lft->ntyp == EVAL)
+ def_use(v->lft, code); /* will add USE */
+ else if (v->lft->ntyp != CONST)
+ def_use(v->lft, DEF|code);
+ }
+ break;
+
+ case 'R':
+ def_use(now->lft, DEREF_USE|USE|code);
+ for (v = now->rgt; v; v = v->rgt)
+ { if (v->lft->ntyp == EVAL)
+ def_use(v->lft, code); /* will add USE */
+ }
+ break;
+
+ case '?':
+ def_use(now->lft, USE|code);
+ if (now->rgt)
+ { def_use(now->rgt->lft, code);
+ def_use(now->rgt->rgt, code);
+ }
+ break;
+
+ case PRINT:
+ for (v = now->lft; v; v = v->rgt)
+ def_use(v->lft, USE|code);
+ break;
+
+ case PRINTM:
+ def_use(now->lft, USE);
+ break;
+
+ case CONST:
+ case ELSE: /* ? */
+ case NONPROGRESS:
+ case PC_VAL:
+ case 'p':
+ case 'q':
+ break;
+
+ case '.':
+ case GOTO:
+ case BREAK:
+ case '@':
+ case D_STEP:
+ case ATOMIC:
+ case NON_ATOMIC:
+ case IF:
+ case DO:
+ case UNLESS:
+ case TIMEOUT:
+ case C_CODE:
+ case C_EXPR:
+ default:
+ break;
+ }
+}
+
+static int
+AST_add_alias(Lextok *n, int nr)
+{ ALIAS *ca;
+ int res;
+
+ for (ca = chalcur->alias; ca; ca = ca->nxt)
+ if (AST_mutual(ca->cnm, n, 1))
+ { res = (ca->origin&nr);
+ ca->origin |= nr; /* 1, 2, or 4 - run, asgn, or rcv */
+ return (res == 0); /* 0 if already there with same origin */
+ }
+
+ ca = (ALIAS *) emalloc(sizeof(ALIAS));
+ ca->cnm = n;
+ ca->origin = nr;
+ ca->nxt = chalcur->alias;
+ chalcur->alias = ca;
+ return 1;
+}
+
+static void
+AST_run_alias(char *pn, char *s, Lextok *t, int parno)
+{ Lextok *v;
+ int cnt;
+
+ if (!t) return;
+
+ if (t->ntyp == RUN)
+ { if (strcmp(t->sym->name, s) == 0)
+ for (v = t->lft, cnt = 1; v; v = v->rgt, cnt++)
+ if (cnt == parno)
+ { AST_add_alias(v->lft, 1); /* RUN */
+ break;
+ }
+ } else
+ { AST_run_alias(pn, s, t->lft, parno);
+ AST_run_alias(pn, s, t->rgt, parno);
+ }
+}
+
+static void
+AST_findrun(char *s, int parno)
+{ FSM_state *f;
+ FSM_trans *t;
+ AST *a;
+
+ for (a = ast; a; a = a->nxt) /* automata */
+ for (f = a->fsm; f; f = f->nxt) /* control states */
+ for (t = f->t; t; t = t->nxt) /* transitions */
+ { if (t->step)
+ AST_run_alias(a->p->n->name, s, t->step->n, parno);
+ }
+}
+
+static void
+AST_par_chans(ProcList *p) /* find local chan's init'd to chan passed as param */
+{ Ordered *walk;
+ Symbol *sp;
+
+ for (walk = all_names; walk; walk = walk->next)
+ { sp = walk->entry;
+ if (sp
+ && sp->context
+ && strcmp(sp->context->name, p->n->name) == 0
+ && sp->Nid >= 0 /* not itself a param */
+ && sp->type == CHAN
+ && sp->ini->ntyp == NAME) /* != CONST and != CHAN */
+ { Lextok *x = nn(ZN, 0, ZN, ZN);
+ x->sym = sp;
+ AST_setcur(x);
+ AST_add_alias(sp->ini, 2); /* ASGN */
+ } }
+}
+
+static void
+AST_para(ProcList *p)
+{ Lextok *f, *t, *c;
+ int cnt = 0;
+
+ AST_par_chans(p);
+
+ for (f = p->p; f; f = f->rgt) /* list of types */
+ for (t = f->lft; t; t = t->rgt)
+ { if (t->ntyp != ',')
+ c = t;
+ else
+ c = t->lft; /* expanded struct */
+
+ cnt++;
+ if (Sym_typ(c) == CHAN)
+ { ALIAS *na = (ALIAS *) emalloc(sizeof(ALIAS));
+
+ na->cnm = c;
+ na->nxt = chalias;
+ chalcur = chalias = na;
+#if 0
+ printf("%s -- (par) -- ", p->n->name);
+ AST_var(c, c->sym, 1);
+ printf(" => <<");
+#endif
+ AST_findrun(p->n->name, cnt);
+#if 0
+ printf(">>\n");
+#endif
+ }
+ }
+}
+
+static void
+AST_haschan(Lextok *c)
+{
+ if (!c) return;
+ if (Sym_typ(c) == CHAN)
+ { AST_add_alias(c, 2); /* ASGN */
+#if 0
+ printf("<<");
+ AST_var(c, c->sym, 1);
+ printf(">>\n");
+#endif
+ } else
+ { AST_haschan(c->rgt);
+ AST_haschan(c->lft);
+ }
+}
+
+static int
+AST_nrpar(Lextok *n) /* 's' or 'r' */
+{ Lextok *m;
+ int j = 0;
+
+ for (m = n->rgt; m; m = m->rgt)
+ j++;
+ return j;
+}
+
+static int
+AST_ord(Lextok *n, Lextok *s)
+{ Lextok *m;
+ int j = 0;
+
+ for (m = n->rgt; m; m = m->rgt)
+ { j++;
+ if (s->sym == m->lft->sym)
+ return j;
+ }
+ return 0;
+}
+
+#if 0
+static void
+AST_ownership(Symbol *s)
+{
+ if (!s) return;
+ printf("%s:", s->name);
+ AST_ownership(s->owner);
+}
+#endif
+
+static int
+AST_mutual(Lextok *a, Lextok *b, int toplevel)
+{ Symbol *as, *bs;
+
+ if (!a && !b) return 1;
+
+ if (!a || !b) return 0;
+
+ as = a->sym;
+ bs = b->sym;
+
+ if (!as || !bs) return 0;
+
+ if (toplevel && as->context != bs->context)
+ return 0;
+
+ if (as->type != bs->type)
+ return 0;
+
+ if (strcmp(as->name, bs->name) != 0)
+ return 0;
+
+ if (as->type == STRUCT && a->rgt && b->rgt)
+ return AST_mutual(a->rgt->lft, b->rgt->lft, 0);
+
+ return 1;
+}
+
+static void
+AST_setcur(Lextok *n) /* set chalcur */
+{ ALIAS *ca;
+
+ for (ca = chalias; ca; ca = ca->nxt)
+ if (AST_mutual(ca->cnm, n, 1)) /* if same chan */
+ { chalcur = ca;
+ return;
+ }
+
+ ca = (ALIAS *) emalloc(sizeof(ALIAS));
+ ca->cnm = n;
+ ca->nxt = chalias;
+ chalcur = chalias = ca;
+}
+
+static void
+AST_other(AST *a) /* check chan params in asgns and recvs */
+{ FSM_state *f;
+ FSM_trans *t;
+ FSM_use *u;
+ ChanList *cl;
+
+ for (f = a->fsm; f; f = f->nxt) /* control states */
+ for (t = f->t; t; t = t->nxt) /* transitions */
+ for (u = t->Val[0]; u; u = u->nxt) /* def/use info */
+ if (Sym_typ(u->n) == CHAN
+ && (u->special&DEF)) /* def of chan-name */
+ { AST_setcur(u->n);
+ switch (t->step->n->ntyp) {
+ case ASGN:
+ AST_haschan(t->step->n->rgt);
+ break;
+ case 'r':
+ /* guess sends where name may originate */
+ for (cl = chanlist; cl; cl = cl->nxt) /* all sends */
+ { int a = AST_nrpar(cl->s);
+ int b = AST_nrpar(t->step->n);
+ if (a != b) /* matching nrs of params */
+ continue;
+
+ a = AST_ord(cl->s, cl->n);
+ b = AST_ord(t->step->n, u->n);
+ if (a != b) /* same position in parlist */
+ continue;
+
+ AST_add_alias(cl->n, 4); /* RCV assume possible match */
+ }
+ break;
+ default:
+ printf("type = %d\n", t->step->n->ntyp);
+ non_fatal("unexpected chan def type", (char *) 0);
+ break;
+ } }
+}
+
+static void
+AST_aliases(void)
+{ ALIAS *na, *ca;
+
+ for (na = chalias; na; na = na->nxt)
+ { printf("\npossible aliases of ");
+ AST_var(na->cnm, na->cnm->sym, 1);
+ printf("\n\t");
+ for (ca = na->alias; ca; ca = ca->nxt)
+ { if (!ca->cnm->sym)
+ printf("no valid name ");
+ else
+ AST_var(ca->cnm, ca->cnm->sym, 1);
+ printf("<");
+ if (ca->origin & 1) printf("RUN ");
+ if (ca->origin & 2) printf("ASGN ");
+ if (ca->origin & 4) printf("RCV ");
+ printf("[%s]", AST_isini(ca->cnm)?"Initzd":"Name");
+ printf(">");
+ if (ca->nxt) printf(", ");
+ }
+ printf("\n");
+ }
+ printf("\n");
+}
+
+static void
+AST_indirect(FSM_use *uin, FSM_trans *t, char *cause, char *pn)
+{ FSM_use *u;
+
+ /* this is a newly discovered relevant statement */
+ /* all vars it uses to contribute to its DEF are new criteria */
+
+ if (!(t->relevant&1)) AST_Changes++;
+
+ t->round = AST_Round;
+ t->relevant = 1;
+
+ if ((verbose&32) && t->step)
+ { printf("\tDR %s [[ ", pn);
+ comment(stdout, t->step->n, 0);
+ printf("]]\n\t\tfully relevant %s", cause);
+ if (uin) { printf(" due to "); AST_var(uin->n, uin->n->sym, 1); }
+ printf("\n");
+ }
+ for (u = t->Val[0]; u; u = u->nxt)
+ if (u != uin
+ && (u->special&(USE|DEREF_USE)))
+ { if (verbose&32)
+ { printf("\t\t\tuses(%d): ", u->special);
+ AST_var(u->n, u->n->sym, 1);
+ printf("\n");
+ }
+ name_AST_track(u->n, u->special); /* add to slice criteria */
+ }
+}
+
+static void
+def_relevant(char *pn, FSM_trans *t, Lextok *n, int ischan)
+{ FSM_use *u;
+ ALIAS *na, *ca;
+ int chanref;
+
+ /* look for all DEF's of n
+ * mark those stmnts relevant
+ * mark all var USEs in those stmnts as criteria
+ */
+
+ if (n->ntyp != ELSE)
+ for (u = t->Val[0]; u; u = u->nxt)
+ { chanref = (Sym_typ(u->n) == CHAN);
+
+ if (ischan != chanref /* no possible match */
+ || !(u->special&(DEF|DEREF_DEF))) /* not a def */
+ continue;
+
+ if (AST_mutual(u->n, n, 1))
+ { AST_indirect(u, t, "(exact match)", pn);
+ continue;
+ }
+
+ if (chanref)
+ for (na = chalias; na; na = na->nxt)
+ { if (!AST_mutual(u->n, na->cnm, 1))
+ continue;
+ for (ca = na->alias; ca; ca = ca->nxt)
+ if (AST_mutual(ca->cnm, n, 1)
+ && AST_isini(ca->cnm))
+ { AST_indirect(u, t, "(alias match)", pn);
+ break;
+ }
+ if (ca) break;
+ } }
+}
+
+static void
+AST_relevant(Lextok *n)
+{ AST *a;
+ FSM_state *f;
+ FSM_trans *t;
+ int ischan;
+
+ /* look for all DEF's of n
+ * mark those stmnts relevant
+ * mark all var USEs in those stmnts as criteria
+ */
+
+ if (!n) return;
+ ischan = (Sym_typ(n) == CHAN);
+
+ if (verbose&32)
+ { printf("<<ast_relevant (ntyp=%d) ", n->ntyp);
+ AST_var(n, n->sym, 1);
+ printf(">>\n");
+ }
+
+ for (t = expl_par; t; t = t->nxt) /* param assignments */
+ { if (!(t->relevant&1))
+ def_relevant(":params:", t, n, ischan);
+ }
+
+ for (t = expl_var; t; t = t->nxt)
+ { if (!(t->relevant&1)) /* var inits */
+ def_relevant(":vars:", t, n, ischan);
+ }
+
+ for (a = ast; a; a = a->nxt) /* all other stmnts */
+ { if (strcmp(a->p->n->name, ":never:") != 0
+ && strcmp(a->p->n->name, ":trace:") != 0
+ && strcmp(a->p->n->name, ":notrace:") != 0)
+ for (f = a->fsm; f; f = f->nxt)
+ for (t = f->t; t; t = t->nxt)
+ { if (!(t->relevant&1))
+ def_relevant(a->p->n->name, t, n, ischan);
+ } }
+}
+
+static int
+AST_relpar(char *s)
+{ FSM_trans *t, *T;
+ FSM_use *u;
+
+ for (T = expl_par; T; T = (T == expl_par)?expl_var: (FSM_trans *) 0)
+ for (t = T; t; t = t->nxt)
+ { if (t->relevant&1)
+ for (u = t->Val[0]; u; u = u->nxt)
+ { if (u->n->sym->type
+ && u->n->sym->context
+ && strcmp(u->n->sym->context->name, s) == 0)
+ {
+ if (verbose&32)
+ { printf("proctype %s relevant, due to symbol ", s);
+ AST_var(u->n, u->n->sym, 1);
+ printf("\n");
+ }
+ return 1;
+ } } }
+ return 0;
+}
+
+static void
+AST_dorelevant(void)
+{ AST *a;
+ RPN *r;
+
+ for (r = rpn; r; r = r->nxt)
+ { for (a = ast; a; a = a->nxt)
+ if (strcmp(a->p->n->name, r->rn->name) == 0)
+ { a->relevant |= 1;
+ break;
+ }
+ if (!a)
+ fatal("cannot find proctype %s", r->rn->name);
+ }
+}
+
+static void
+AST_procisrelevant(Symbol *s)
+{ RPN *r;
+ for (r = rpn; r; r = r->nxt)
+ if (strcmp(r->rn->name, s->name) == 0)
+ return;
+ r = (RPN *) emalloc(sizeof(RPN));
+ r->rn = s;
+ r->nxt = rpn;
+ rpn = r;
+}
+
+static int
+AST_proc_isrel(char *s)
+{ AST *a;
+
+ for (a = ast; a; a = a->nxt)
+ if (strcmp(a->p->n->name, s) == 0)
+ return (a->relevant&1);
+ non_fatal("cannot happen, missing proc in ast", (char *) 0);
+ return 0;
+}
+
+static int
+AST_scoutrun(Lextok *t)
+{
+ if (!t) return 0;
+
+ if (t->ntyp == RUN)
+ return AST_proc_isrel(t->sym->name);
+ return (AST_scoutrun(t->lft) || AST_scoutrun(t->rgt));
+}
+
+static void
+AST_tagruns(void)
+{ AST *a;
+ FSM_state *f;
+ FSM_trans *t;
+
+ /* if any stmnt inside a proctype is relevant
+ * or any parameter passed in a run
+ * then so are all the run statements on that proctype
+ */
+
+ for (a = ast; a; a = a->nxt)
+ { if (strcmp(a->p->n->name, ":never:") == 0
+ || strcmp(a->p->n->name, ":trace:") == 0
+ || strcmp(a->p->n->name, ":notrace:") == 0
+ || strcmp(a->p->n->name, ":init:") == 0)
+ { a->relevant |= 1; /* the proctype is relevant */
+ continue;
+ }
+ if (AST_relpar(a->p->n->name))
+ a->relevant |= 1;
+ else
+ { for (f = a->fsm; f; f = f->nxt)
+ for (t = f->t; t; t = t->nxt)
+ if (t->relevant)
+ goto yes;
+yes: if (f)
+ a->relevant |= 1;
+ }
+ }
+
+ for (a = ast; a; a = a->nxt)
+ for (f = a->fsm; f; f = f->nxt)
+ for (t = f->t; t; t = t->nxt)
+ if (t->step
+ && AST_scoutrun(t->step->n))
+ { AST_indirect((FSM_use *)0, t, ":run:", a->p->n->name);
+ /* BUT, not all actual params are relevant */
+ }
+}
+
+static void
+AST_report(AST *a, Element *e) /* ALSO deduce irrelevant vars */
+{
+ if (!(a->relevant&2))
+ { a->relevant |= 2;
+ printf("spin: redundant in proctype %s (for given property):\n",
+ a->p->n->name);
+ }
+ printf(" line %3d %s (state %d)",
+ e->n?e->n->ln:-1,
+ e->n?e->n->fn->name:"-",
+ e->seqno);
+ printf(" [");
+ comment(stdout, e->n, 0);
+ printf("]\n");
+}
+
+static int
+AST_always(Lextok *n)
+{
+ if (!n) return 0;
+
+ if (n->ntyp == '@' /* -end */
+ || n->ntyp == 'p') /* remote reference */
+ return 1;
+ return AST_always(n->lft) || AST_always(n->rgt);
+}
+
+static void
+AST_edge_dump(AST *a, FSM_state *f)
+{ FSM_trans *t;
+ FSM_use *u;
+
+ for (t = f->t; t; t = t->nxt) /* edges */
+ {
+ if (t->step && AST_always(t->step->n))
+ t->relevant |= 1; /* always relevant */
+
+ if (verbose&32)
+ { switch (t->relevant) {
+ case 0: printf(" "); break;
+ case 1: printf("*%3d ", t->round); break;
+ case 2: printf("+%3d ", t->round); break;
+ case 3: printf("#%3d ", t->round); break;
+ default: printf("? "); break;
+ }
+
+ printf("%d\t->\t%d\t", f->from, t->to);
+ if (t->step)
+ comment(stdout, t->step->n, 0);
+ else
+ printf("Unless");
+
+ for (u = t->Val[0]; u; u = u->nxt)
+ { printf(" <");
+ AST_var(u->n, u->n->sym, 1);
+ printf(":%d>", u->special);
+ }
+ printf("\n");
+ } else
+ { if (t->relevant)
+ continue;
+
+ if (t->step)
+ switch(t->step->n->ntyp) {
+ case ASGN:
+ case 's':
+ case 'r':
+ case 'c':
+ if (t->step->n->lft->ntyp != CONST)
+ AST_report(a, t->step);
+ break;
+
+ case PRINT: /* don't report */
+ case PRINTM:
+ case ASSERT:
+ case C_CODE:
+ case C_EXPR:
+ default:
+ break;
+ } } }
+}
+
+static void
+AST_dfs(AST *a, int s, int vis)
+{ FSM_state *f;
+ FSM_trans *t;
+
+ f = fsm_tbl[s];
+ if (f->seen) return;
+
+ f->seen = 1;
+ if (vis) AST_edge_dump(a, f);
+
+ for (t = f->t; t; t = t->nxt)
+ AST_dfs(a, t->to, vis);
+}
+
+static void
+AST_dump(AST *a)
+{ FSM_state *f;
+
+ for (f = a->fsm; f; f = f->nxt)
+ { f->seen = 0;
+ fsm_tbl[f->from] = f;
+ }
+
+ if (verbose&32)
+ printf("AST_START %s from %d\n", a->p->n->name, a->i_st);
+
+ AST_dfs(a, a->i_st, 1);
+}
+
+static void
+AST_sends(AST *a)
+{ FSM_state *f;
+ FSM_trans *t;
+ FSM_use *u;
+ ChanList *cl;
+
+ for (f = a->fsm; f; f = f->nxt) /* control states */
+ for (t = f->t; t; t = t->nxt) /* transitions */
+ { if (t->step
+ && t->step->n
+ && t->step->n->ntyp == 's')
+ for (u = t->Val[0]; u; u = u->nxt)
+ { if (Sym_typ(u->n) == CHAN
+ && ((u->special&USE) && !(u->special&DEREF_USE)))
+ {
+#if 0
+ printf("%s -- (%d->%d) -- ",
+ a->p->n->name, f->from, t->to);
+ AST_var(u->n, u->n->sym, 1);
+ printf(" -> chanlist\n");
+#endif
+ cl = (ChanList *) emalloc(sizeof(ChanList));
+ cl->s = t->step->n;
+ cl->n = u->n;
+ cl->nxt = chanlist;
+ chanlist = cl;
+} } } }
+
+static ALIAS *
+AST_alfind(Lextok *n)
+{ ALIAS *na;
+
+ for (na = chalias; na; na = na->nxt)
+ if (AST_mutual(na->cnm, n, 1))
+ return na;
+ return (ALIAS *) 0;
+}
+
+static void
+AST_trans(void)
+{ ALIAS *na, *ca, *da, *ea;
+ int nchanges;
+
+ do {
+ nchanges = 0;
+ for (na = chalias; na; na = na->nxt)
+ { chalcur = na;
+ for (ca = na->alias; ca; ca = ca->nxt)
+ { da = AST_alfind(ca->cnm);
+ if (da)
+ for (ea = da->alias; ea; ea = ea->nxt)
+ { nchanges += AST_add_alias(ea->cnm,
+ ea->origin|ca->origin);
+ } } }
+ } while (nchanges > 0);
+
+ chalcur = (ALIAS *) 0;
+}
+
+static void
+AST_def_use(AST *a)
+{ FSM_state *f;
+ FSM_trans *t;
+
+ for (f = a->fsm; f; f = f->nxt) /* control states */
+ for (t = f->t; t; t = t->nxt) /* all edges */
+ { cur_t = t;
+ rel_use(t->Val[0]); /* redo Val; doesn't cover structs */
+ rel_use(t->Val[1]);
+ t->Val[0] = t->Val[1] = (FSM_use *) 0;
+
+ if (!t->step) continue;
+
+ def_use(t->step->n, 0); /* def/use info, including structs */
+ }
+ cur_t = (FSM_trans *) 0;
+}
+
+static void
+name_AST_track(Lextok *n, int code)
+{ extern int nr_errs;
+#if 0
+ printf("AST_name: ");
+ AST_var(n, n->sym, 1);
+ printf(" -- %d\n", code);
+#endif
+ if (in_recv && (code&DEF) && (code&USE))
+ { printf("spin: error: DEF and USE of same var in rcv stmnt: ");
+ AST_var(n, n->sym, 1);
+ printf(" -- %d\n", code);
+ nr_errs++;
+ }
+ check_slice(n, code);
+}
+
+void
+AST_track(Lextok *now, int code) /* called from main.c */
+{ Lextok *v; extern int export_ast;
+
+ if (!export_ast) return;
+
+ if (now)
+ switch (now->ntyp) {
+ case LEN:
+ case FULL:
+ case EMPTY:
+ case NFULL:
+ case NEMPTY:
+ AST_track(now->lft, DEREF_USE|USE|code);
+ break;
+
+ case '/':
+ case '*':
+ case '-':
+ case '+':
+ case '%':
+ case '&':
+ case '^':
+ case '|':
+ case LE:
+ case GE:
+ case GT:
+ case LT:
+ case NE:
+ case EQ:
+ case OR:
+ case AND:
+ case LSHIFT:
+ case RSHIFT:
+ AST_track(now->rgt, USE|code);
+ /* fall through */
+ case '!':
+ case UMIN:
+ case '~':
+ case 'c':
+ case ENABLED:
+ case ASSERT:
+ AST_track(now->lft, USE|code);
+ break;
+
+ case EVAL:
+ AST_track(now->lft, USE|(code&(~DEF)));
+ break;
+
+ case NAME:
+ name_AST_track(now, code);
+ if (now->sym->nel != 1)
+ AST_track(now->lft, USE|code); /* index */
+ break;
+
+ case 'R':
+ AST_track(now->lft, DEREF_USE|USE|code);
+ for (v = now->rgt; v; v = v->rgt)
+ AST_track(v->lft, code); /* a deeper eval can add USE */
+ break;
+
+ case '?':
+ AST_track(now->lft, USE|code);
+ if (now->rgt)
+ { AST_track(now->rgt->lft, code);
+ AST_track(now->rgt->rgt, code);
+ }
+ break;
+
+/* added for control deps: */
+ case TYPE:
+ name_AST_track(now, code);
+ break;
+ case ASGN:
+ AST_track(now->lft, DEF|code);
+ AST_track(now->rgt, USE|code);
+ break;
+ case RUN:
+ name_AST_track(now, USE);
+ for (v = now->lft; v; v = v->rgt)
+ AST_track(v->lft, USE|code);
+ break;
+ case 's':
+ AST_track(now->lft, DEREF_DEF|DEREF_USE|USE|code);
+ for (v = now->rgt; v; v = v->rgt)
+ AST_track(v->lft, USE|code);
+ break;
+ case 'r':
+ AST_track(now->lft, DEREF_DEF|DEREF_USE|USE|code);
+ for (v = now->rgt; v; v = v->rgt)
+ { in_recv++;
+ AST_track(v->lft, DEF|code);
+ in_recv--;
+ }
+ break;
+ case PRINT:
+ for (v = now->lft; v; v = v->rgt)
+ AST_track(v->lft, USE|code);
+ break;
+ case PRINTM:
+ AST_track(now->lft, USE);
+ break;
+/* end add */
+ case 'p':
+#if 0
+ 'p' -sym-> _p
+ /
+ '?' -sym-> a (proctype)
+ /
+ b (pid expr)
+#endif
+ AST_track(now->lft->lft, USE|code);
+ AST_procisrelevant(now->lft->sym);
+ break;
+
+ case CONST:
+ case ELSE:
+ case NONPROGRESS:
+ case PC_VAL:
+ case 'q':
+ break;
+
+ case '.':
+ case GOTO:
+ case BREAK:
+ case '@':
+ case D_STEP:
+ case ATOMIC:
+ case NON_ATOMIC:
+ case IF:
+ case DO:
+ case UNLESS:
+ case TIMEOUT:
+ case C_CODE:
+ case C_EXPR:
+ break;
+
+ default:
+ printf("AST_track, NOT EXPECTED ntyp: %d\n", now->ntyp);
+ break;
+ }
+}
+
+static int
+AST_dump_rel(void)
+{ Slicer *rv;
+ Ordered *walk;
+ char buf[64];
+ int banner=0;
+
+ if (verbose&32)
+ { printf("Relevant variables:\n");
+ for (rv = rel_vars; rv; rv = rv->nxt)
+ { printf("\t");
+ AST_var(rv->n, rv->n->sym, 1);
+ printf("\n");
+ }
+ return 1;
+ }
+ for (rv = rel_vars; rv; rv = rv->nxt)
+ rv->n->sym->setat = 1; /* mark it */
+
+ for (walk = all_names; walk; walk = walk->next)
+ { Symbol *s;
+ s = walk->entry;
+ if (!s->setat
+ && (s->type != MTYPE || s->ini->ntyp != CONST)
+ && s->type != STRUCT /* report only fields */
+ && s->type != PROCTYPE
+ && !s->owner
+ && sputtype(buf, s->type))
+ { if (!banner)
+ { banner = 1;
+ printf("spin: redundant vars (for given property):\n");
+ }
+ printf("\t");
+ symvar(s);
+ } }
+ return banner;
+}
+
+static void
+AST_suggestions(void)
+{ Symbol *s;
+ Ordered *walk;
+ FSM_state *f;
+ FSM_trans *t;
+ AST *a;
+ int banner=0;
+ int talked=0;
+
+ for (walk = all_names; walk; walk = walk->next)
+ { s = walk->entry;
+ if (s->colnr == 2 /* only used in conditionals */
+ && (s->type == BYTE
+ || s->type == SHORT
+ || s->type == INT
+ || s->type == MTYPE))
+ { if (!banner)
+ { banner = 1;
+ printf("spin: consider using predicate");
+ printf(" abstraction to replace:\n");
+ }
+ printf("\t");
+ symvar(s);
+ } }
+
+ /* look for source and sink processes */
+
+ for (a = ast; a; a = a->nxt) /* automata */
+ { banner = 0;
+ for (f = a->fsm; f; f = f->nxt) /* control states */
+ for (t = f->t; t; t = t->nxt) /* transitions */
+ { if (t->step)
+ switch (t->step->n->ntyp) {
+ case 's':
+ banner |= 1;
+ break;
+ case 'r':
+ banner |= 2;
+ break;
+ case '.':
+ case D_STEP:
+ case ATOMIC:
+ case NON_ATOMIC:
+ case IF:
+ case DO:
+ case UNLESS:
+ case '@':
+ case GOTO:
+ case BREAK:
+ case PRINT:
+ case PRINTM:
+ case ASSERT:
+ case C_CODE:
+ case C_EXPR:
+ break;
+ default:
+ banner |= 4;
+ goto no_good;
+ }
+ }
+no_good: if (banner == 1 || banner == 2)
+ { printf("spin: proctype %s defines a %s process\n",
+ a->p->n->name,
+ banner==1?"source":"sink");
+ talked |= banner;
+ } else if (banner == 3)
+ { printf("spin: proctype %s mimics a buffer\n",
+ a->p->n->name);
+ talked |= 4;
+ }
+ }
+ if (talked&1)
+ { printf("\tto reduce complexity, consider merging the code of\n");
+ printf("\teach source process into the code of its target\n");
+ }
+ if (talked&2)
+ { printf("\tto reduce complexity, consider merging the code of\n");
+ printf("\teach sink process into the code of its source\n");
+ }
+ if (talked&4)
+ printf("\tto reduce complexity, avoid buffer processes\n");
+}
+
+static void
+AST_preserve(void)
+{ Slicer *sc, *nx, *rv;
+
+ for (sc = slicer; sc; sc = nx)
+ { if (!sc->used)
+ break; /* done */
+
+ nx = sc->nxt;
+
+ for (rv = rel_vars; rv; rv = rv->nxt)
+ if (AST_mutual(sc->n, rv->n, 1))
+ break;
+
+ if (!rv) /* not already there */
+ { sc->nxt = rel_vars;
+ rel_vars = sc;
+ } }
+ slicer = sc;
+}
+
+static void
+check_slice(Lextok *n, int code)
+{ Slicer *sc;
+
+ for (sc = slicer; sc; sc = sc->nxt)
+ if (AST_mutual(sc->n, n, 1)
+ && sc->code == code)
+ return; /* already there */
+
+ sc = (Slicer *) emalloc(sizeof(Slicer));
+ sc->n = n;
+
+ sc->code = code;
+ sc->used = 0;
+ sc->nxt = slicer;
+ slicer = sc;
+}
+
+static void
+AST_data_dep(void)
+{ Slicer *sc;
+
+ /* mark all def-relevant transitions */
+ for (sc = slicer; sc; sc = sc->nxt)
+ { sc->used = 1;
+ if (verbose&32)
+ { printf("spin: slice criterion ");
+ AST_var(sc->n, sc->n->sym, 1);
+ printf(" type=%d\n", Sym_typ(sc->n));
+ }
+ AST_relevant(sc->n);
+ }
+ AST_tagruns(); /* mark 'run's relevant if target proctype is relevant */
+}
+
+static int
+AST_blockable(AST *a, int s)
+{ FSM_state *f;
+ FSM_trans *t;
+
+ f = fsm_tbl[s];
+
+ for (t = f->t; t; t = t->nxt)
+ { if (t->relevant&2)
+ return 1;
+
+ if (t->step && t->step->n)
+ switch (t->step->n->ntyp) {
+ case IF:
+ case DO:
+ case ATOMIC:
+ case NON_ATOMIC:
+ case D_STEP:
+ if (AST_blockable(a, t->to))
+ { t->round = AST_Round;
+ t->relevant |= 2;
+ return 1;
+ }
+ /* else fall through */
+ default:
+ break;
+ }
+ else if (AST_blockable(a, t->to)) /* Unless */
+ { t->round = AST_Round;
+ t->relevant |= 2;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void
+AST_spread(AST *a, int s)
+{ FSM_state *f;
+ FSM_trans *t;
+
+ f = fsm_tbl[s];
+
+ for (t = f->t; t; t = t->nxt)
+ { if (t->relevant&2)
+ continue;
+
+ if (t->step && t->step->n)
+ switch (t->step->n->ntyp) {
+ case IF:
+ case DO:
+ case ATOMIC:
+ case NON_ATOMIC:
+ case D_STEP:
+ AST_spread(a, t->to);
+ /* fall thru */
+ default:
+ t->round = AST_Round;
+ t->relevant |= 2;
+ break;
+ }
+ else /* Unless */
+ { AST_spread(a, t->to);
+ t->round = AST_Round;
+ t->relevant |= 2;
+ }
+ }
+}
+
+static int
+AST_notrelevant(Lextok *n)
+{ Slicer *s;
+
+ for (s = rel_vars; s; s = s->nxt)
+ if (AST_mutual(s->n, n, 1))
+ return 0;
+ for (s = slicer; s; s = s->nxt)
+ if (AST_mutual(s->n, n, 1))
+ return 0;
+ return 1;
+}
+
+static int
+AST_withchan(Lextok *n)
+{
+ if (!n) return 0;
+ if (Sym_typ(n) == CHAN)
+ return 1;
+ return AST_withchan(n->lft) || AST_withchan(n->rgt);
+}
+
+static int
+AST_suspect(FSM_trans *t)
+{ FSM_use *u;
+ /* check for possible overkill */
+ if (!t || !t->step || !AST_withchan(t->step->n))
+ return 0;
+ for (u = t->Val[0]; u; u = u->nxt)
+ if (AST_notrelevant(u->n))
+ return 1;
+ return 0;
+}
+
+static void
+AST_shouldconsider(AST *a, int s)
+{ FSM_state *f;
+ FSM_trans *t;
+
+ f = fsm_tbl[s];
+ for (t = f->t; t; t = t->nxt)
+ { if (t->step && t->step->n)
+ switch (t->step->n->ntyp) {
+ case IF:
+ case DO:
+ case ATOMIC:
+ case NON_ATOMIC:
+ case D_STEP:
+ AST_shouldconsider(a, t->to);
+ break;
+ default:
+ AST_track(t->step->n, 0);
+/*
+ AST_track is called here for a blockable stmnt from which
+ a relevant stmnmt was shown to be reachable
+ for a condition this makes all USEs relevant
+ but for a channel operation it only makes the executability
+ relevant -- in those cases, parameters that aren't already
+ relevant may be replaceable with arbitrary tokens
+ */
+ if (AST_suspect(t))
+ { printf("spin: possibly redundant parameters in: ");
+ comment(stdout, t->step->n, 0);
+ printf("\n");
+ }
+ break;
+ }
+ else /* an Unless */
+ AST_shouldconsider(a, t->to);
+ }
+}
+
+static int
+FSM_critical(AST *a, int s)
+{ FSM_state *f;
+ FSM_trans *t;
+
+ /* is a 1-relevant stmnt reachable from this state? */
+
+ f = fsm_tbl[s];
+ if (f->seen)
+ goto done;
+ f->seen = 1;
+ f->cr = 0;
+ for (t = f->t; t; t = t->nxt)
+ if ((t->relevant&1)
+ || FSM_critical(a, t->to))
+ { f->cr = 1;
+
+ if (verbose&32)
+ { printf("\t\t\t\tcritical(%d) ", t->relevant);
+ comment(stdout, t->step->n, 0);
+ printf("\n");
+ }
+ break;
+ }
+#if 0
+ else {
+ if (verbose&32)
+ { printf("\t\t\t\tnot-crit ");
+ comment(stdout, t->step->n, 0);
+ printf("\n");
+ }
+ }
+#endif
+done:
+ return f->cr;
+}
+
+static void
+AST_ctrl(AST *a)
+{ FSM_state *f;
+ FSM_trans *t;
+ int hit;
+
+ /* add all blockable transitions
+ * from which relevant transitions can be reached
+ */
+ if (verbose&32)
+ printf("CTL -- %s\n", a->p->n->name);
+
+ /* 1 : mark all blockable edges */
+ for (f = a->fsm; f; f = f->nxt)
+ { if (!(f->scratch&2)) /* not part of irrelevant subgraph */
+ for (t = f->t; t; t = t->nxt)
+ { if (t->step && t->step->n)
+ switch (t->step->n->ntyp) {
+ case 'r':
+ case 's':
+ case 'c':
+ case ELSE:
+ t->round = AST_Round;
+ t->relevant |= 2; /* mark for next phases */
+ if (verbose&32)
+ { printf("\tpremark ");
+ comment(stdout, t->step->n, 0);
+ printf("\n");
+ }
+ break;
+ default:
+ break;
+ } } }
+
+ /* 2: keep only 2-marked stmnts from which 1-marked stmnts can be reached */
+ for (f = a->fsm; f; f = f->nxt)
+ { fsm_tbl[f->from] = f;
+ f->seen = 0; /* used in dfs from FSM_critical */
+ }
+ for (f = a->fsm; f; f = f->nxt)
+ { if (!FSM_critical(a, f->from))
+ for (t = f->t; t; t = t->nxt)
+ if (t->relevant&2)
+ { t->relevant &= ~2; /* clear mark */
+ if (verbose&32)
+ { printf("\t\tnomark ");
+ comment(stdout, t->step->n, 0);
+ printf("\n");
+ } } }
+
+ /* 3 : lift marks across IF/DO etc. */
+ for (f = a->fsm; f; f = f->nxt)
+ { hit = 0;
+ for (t = f->t; t; t = t->nxt)
+ { if (t->step && t->step->n)
+ switch (t->step->n->ntyp) {
+ case IF:
+ case DO:
+ case ATOMIC:
+ case NON_ATOMIC:
+ case D_STEP:
+ if (AST_blockable(a, t->to))
+ hit = 1;
+ break;
+ default:
+ break;
+ }
+ else if (AST_blockable(a, t->to)) /* Unless */
+ hit = 1;
+
+ if (hit) break;
+ }
+ if (hit) /* at least one outgoing trans can block */
+ for (t = f->t; t; t = t->nxt)
+ { t->round = AST_Round;
+ t->relevant |= 2; /* lift */
+ if (verbose&32)
+ { printf("\t\t\tliftmark ");
+ comment(stdout, t->step->n, 0);
+ printf("\n");
+ }
+ AST_spread(a, t->to); /* and spread to all guards */
+ } }
+
+ /* 4: nodes with 2-marked out-edges contribute new slice criteria */
+ for (f = a->fsm; f; f = f->nxt)
+ for (t = f->t; t; t = t->nxt)
+ if (t->relevant&2)
+ { AST_shouldconsider(a, f->from);
+ break; /* inner loop */
+ }
+}
+
+static void
+AST_control_dep(void)
+{ AST *a;
+
+ for (a = ast; a; a = a->nxt)
+ if (strcmp(a->p->n->name, ":never:") != 0
+ && strcmp(a->p->n->name, ":trace:") != 0
+ && strcmp(a->p->n->name, ":notrace:") != 0)
+ AST_ctrl(a);
+}
+
+static void
+AST_prelabel(void)
+{ AST *a;
+ FSM_state *f;
+ FSM_trans *t;
+
+ for (a = ast; a; a = a->nxt)
+ { if (strcmp(a->p->n->name, ":never:") != 0
+ && strcmp(a->p->n->name, ":trace:") != 0
+ && strcmp(a->p->n->name, ":notrace:") != 0)
+ for (f = a->fsm; f; f = f->nxt)
+ for (t = f->t; t; t = t->nxt)
+ { if (t->step
+ && t->step->n
+ && t->step->n->ntyp == ASSERT
+ )
+ { t->relevant |= 1;
+ } } }
+}
+
+static void
+AST_criteria(void)
+{ /*
+ * remote labels are handled separately -- by making
+ * sure they are not pruned away during optimization
+ */
+ AST_Changes = 1; /* to get started */
+ for (AST_Round = 1; slicer && AST_Changes; AST_Round++)
+ { AST_Changes = 0;
+ AST_data_dep();
+ AST_preserve(); /* moves processed vars from slicer to rel_vars */
+ AST_dominant(); /* mark data-irrelevant subgraphs */
+ AST_control_dep(); /* can add data deps, which add control deps */
+
+ if (verbose&32)
+ printf("\n\nROUND %d -- changes %d\n",
+ AST_Round, AST_Changes);
+ }
+}
+
+static void
+AST_alias_analysis(void) /* aliasing of promela channels */
+{ AST *a;
+
+ for (a = ast; a; a = a->nxt)
+ AST_sends(a); /* collect chan-names that are send across chans */
+
+ for (a = ast; a; a = a->nxt)
+ AST_para(a->p); /* aliasing of chans thru proctype parameters */
+
+ for (a = ast; a; a = a->nxt)
+ AST_other(a); /* chan params in asgns and recvs */
+
+ AST_trans(); /* transitive closure of alias table */
+
+ if (verbose&32)
+ AST_aliases(); /* show channel aliasing info */
+}
+
+void
+AST_slice(void)
+{ AST *a;
+ int spurious = 0;
+
+ if (!slicer)
+ { non_fatal("no slice criteria (or no claim) specified",
+ (char *) 0);
+ spurious = 1;
+ }
+ AST_dorelevant(); /* mark procs refered to in remote refs */
+
+ for (a = ast; a; a = a->nxt)
+ AST_def_use(a); /* compute standard def/use information */
+
+ AST_hidden(); /* parameter passing and local var inits */
+
+ AST_alias_analysis(); /* channel alias analysis */
+
+ AST_prelabel(); /* mark all 'assert(...)' stmnts as relevant */
+ AST_criteria(); /* process the slice criteria from
+ * asserts and from the never claim
+ */
+ if (!spurious || (verbose&32))
+ { spurious = 1;
+ for (a = ast; a; a = a->nxt)
+ { AST_dump(a); /* marked up result */
+ if (a->relevant&2) /* it printed something */
+ spurious = 0;
+ }
+ if (!AST_dump_rel() /* relevant variables */
+ && spurious)
+ printf("spin: no redundancies found (for given property)\n");
+ }
+ AST_suggestions();
+
+ if (verbose&32)
+ show_expl();
+}
+
+void
+AST_store(ProcList *p, int start_state)
+{ AST *n_ast;
+
+ if (strcmp(p->n->name, ":never:") != 0
+ && strcmp(p->n->name, ":trace:") != 0
+ && strcmp(p->n->name, ":notrace:") != 0)
+ { n_ast = (AST *) emalloc(sizeof(AST));
+ n_ast->p = p;
+ n_ast->i_st = start_state;
+ n_ast->relevant = 0;
+ n_ast->fsm = fsm;
+ n_ast->nxt = ast;
+ ast = n_ast;
+ }
+ fsm = (FSM_state *) 0; /* hide it from FSM_DEL */
+}
+
+static void
+AST_add_explicit(Lextok *d, Lextok *u)
+{ FSM_trans *e = (FSM_trans *) emalloc(sizeof(FSM_trans));
+
+ e->to = 0; /* or start_state ? */
+ e->relevant = 0; /* to be determined */
+ e->step = (Element *) 0; /* left blank */
+ e->Val[0] = e->Val[1] = (FSM_use *) 0;
+
+ cur_t = e;
+
+ def_use(u, USE);
+ def_use(d, DEF);
+
+ cur_t = (FSM_trans *) 0;
+
+ e->nxt = explicit;
+ explicit = e;
+}
+
+static void
+AST_fp1(char *s, Lextok *t, Lextok *f, int parno)
+{ Lextok *v;
+ int cnt;
+
+ if (!t) return;
+
+ if (t->ntyp == RUN)
+ { if (strcmp(t->sym->name, s) == 0)
+ for (v = t->lft, cnt = 1; v; v = v->rgt, cnt++)
+ if (cnt == parno)
+ { AST_add_explicit(f, v->lft);
+ break;
+ }
+ } else
+ { AST_fp1(s, t->lft, f, parno);
+ AST_fp1(s, t->rgt, f, parno);
+ }
+}
+
+static void
+AST_mk1(char *s, Lextok *c, int parno)
+{ AST *a;
+ FSM_state *f;
+ FSM_trans *t;
+
+ /* concoct an extra FSM_trans *t with the asgn of
+ * formal par c to matching actual pars made explicit
+ */
+
+ for (a = ast; a; a = a->nxt) /* automata */
+ for (f = a->fsm; f; f = f->nxt) /* control states */
+ for (t = f->t; t; t = t->nxt) /* transitions */
+ { if (t->step)
+ AST_fp1(s, t->step->n, c, parno);
+ }
+}
+
+static void
+AST_par_init(void) /* parameter passing -- hidden assignments */
+{ AST *a;
+ Lextok *f, *t, *c;
+ int cnt;
+
+ for (a = ast; a; a = a->nxt)
+ { if (strcmp(a->p->n->name, ":never:") == 0
+ || strcmp(a->p->n->name, ":trace:") == 0
+ || strcmp(a->p->n->name, ":notrace:") == 0
+ || strcmp(a->p->n->name, ":init:") == 0)
+ continue; /* have no params */
+
+ cnt = 0;
+ for (f = a->p->p; f; f = f->rgt) /* types */
+ for (t = f->lft; t; t = t->rgt) /* formals */
+ { cnt++; /* formal par count */
+ c = (t->ntyp != ',')? t : t->lft; /* the formal parameter */
+ AST_mk1(a->p->n->name, c, cnt); /* all matching run statements */
+ } }
+}
+
+static void
+AST_var_init(void) /* initialized vars (not chans) - hidden assignments */
+{ Ordered *walk;
+ Lextok *x;
+ Symbol *sp;
+ AST *a;
+
+ for (walk = all_names; walk; walk = walk->next)
+ { sp = walk->entry;
+ if (sp
+ && !sp->context /* globals */
+ && sp->type != PROCTYPE
+ && sp->ini
+ && (sp->type != MTYPE || sp->ini->ntyp != CONST) /* not mtype defs */
+ && sp->ini->ntyp != CHAN)
+ { x = nn(ZN, TYPE, ZN, ZN);
+ x->sym = sp;
+ AST_add_explicit(x, sp->ini);
+ } }
+
+ for (a = ast; a; a = a->nxt)
+ { if (strcmp(a->p->n->name, ":never:") != 0
+ && strcmp(a->p->n->name, ":trace:") != 0
+ && strcmp(a->p->n->name, ":notrace:") != 0) /* claim has no locals */
+ for (walk = all_names; walk; walk = walk->next)
+ { sp = walk->entry;
+ if (sp
+ && sp->context
+ && strcmp(sp->context->name, a->p->n->name) == 0
+ && sp->Nid >= 0 /* not a param */
+ && sp->type != LABEL
+ && sp->ini
+ && sp->ini->ntyp != CHAN)
+ { x = nn(ZN, TYPE, ZN, ZN);
+ x->sym = sp;
+ AST_add_explicit(x, sp->ini);
+ } } }
+}
+
+static void
+show_expl(void)
+{ FSM_trans *t, *T;
+ FSM_use *u;
+
+ printf("\nExplicit List:\n");
+ for (T = expl_par; T; T = (T == expl_par)?expl_var: (FSM_trans *) 0)
+ { for (t = T; t; t = t->nxt)
+ { if (!t->Val[0]) continue;
+ printf("%s", t->relevant?"*":" ");
+ printf("%3d", t->round);
+ for (u = t->Val[0]; u; u = u->nxt)
+ { printf("\t<");
+ AST_var(u->n, u->n->sym, 1);
+ printf(":%d>, ", u->special);
+ }
+ printf("\n");
+ }
+ printf("==\n");
+ }
+ printf("End\n");
+}
+
+static void
+AST_hidden(void) /* reveal all hidden assignments */
+{
+ AST_par_init();
+ expl_par = explicit;
+ explicit = (FSM_trans *) 0;
+
+ AST_var_init();
+ expl_var = explicit;
+ explicit = (FSM_trans *) 0;
+}
+
+#define BPW (8*sizeof(ulong)) /* bits per word */
+
+static int
+bad_scratch(FSM_state *f, int upto)
+{ FSM_trans *t;
+#if 0
+ 1. all internal branch-points have else-s
+ 2. all non-branchpoints have non-blocking out-edge
+ 3. all internal edges are non-relevant
+ subgraphs like this need NOT contribute control-dependencies
+#endif
+
+ if (!f->seen
+ || (f->scratch&4))
+ return 0;
+
+ if (f->scratch&8)
+ return 1;
+
+ f->scratch |= 4;
+
+ if (verbose&32) printf("X[%d:%d:%d] ", f->from, upto, f->scratch);
+
+ if (f->scratch&1)
+ { if (verbose&32)
+ printf("\tbad scratch: %d\n", f->from);
+bad: f->scratch &= ~4;
+ /* f->scratch |= 8; wrong */
+ return 1;
+ }
+
+ if (f->from != upto)
+ for (t = f->t; t; t = t->nxt)
+ if (bad_scratch(fsm_tbl[t->to], upto))
+ goto bad;
+
+ return 0;
+}
+
+static void
+mark_subgraph(FSM_state *f, int upto)
+{ FSM_trans *t;
+
+ if (f->from == upto
+ || !f->seen
+ || (f->scratch&2))
+ return;
+
+ f->scratch |= 2;
+
+ for (t = f->t; t; t = t->nxt)
+ mark_subgraph(fsm_tbl[t->to], upto);
+}
+
+static void
+AST_pair(AST *a, FSM_state *h, int y)
+{ Pair *p;
+
+ for (p = a->pairs; p; p = p->nxt)
+ if (p->h == h
+ && p->b == y)
+ return;
+
+ p = (Pair *) emalloc(sizeof(Pair));
+ p->h = h;
+ p->b = y;
+ p->nxt = a->pairs;
+ a->pairs = p;
+}
+
+static void
+AST_checkpairs(AST *a)
+{ Pair *p;
+
+ for (p = a->pairs; p; p = p->nxt)
+ { if (verbose&32)
+ printf(" inspect pair %d %d\n", p->b, p->h->from);
+ if (!bad_scratch(p->h, p->b)) /* subgraph is clean */
+ { if (verbose&32)
+ printf("subgraph: %d .. %d\n", p->b, p->h->from);
+ mark_subgraph(p->h, p->b);
+ }
+ }
+}
+
+static void
+subgraph(AST *a, FSM_state *f, int out)
+{ FSM_state *h;
+ int i, j;
+ ulong *g;
+#if 0
+ reverse dominance suggests that this is a possible
+ entry and exit node for a proper subgraph
+#endif
+ h = fsm_tbl[out];
+
+ i = f->from / BPW;
+ j = f->from % BPW;
+ g = h->mod;
+
+ if (verbose&32)
+ printf("possible pair %d %d -- %d\n",
+ f->from, h->from, (g[i]&(1<<j))?1:0);
+
+ if (g[i]&(1<<j)) /* also a forward dominance pair */
+ AST_pair(a, h, f->from); /* record this pair */
+}
+
+static void
+act_dom(AST *a)
+{ FSM_state *f;
+ FSM_trans *t;
+ int i, j, cnt;
+
+ for (f = a->fsm; f; f = f->nxt)
+ { if (!f->seen) continue;
+#if 0
+ f->from is the exit-node of a proper subgraph, with
+ the dominator its entry-node, if:
+ a. this node has more than 1 reachable predecessor
+ b. the dominator has more than 1 reachable successor
+ (need reachability - in case of reverse dominance)
+ d. the dominator is reachable, and not equal to this node
+#endif
+ for (t = f->p, i = 0; t; t = t->nxt)
+ i += fsm_tbl[t->to]->seen;
+ if (i <= 1) continue; /* a. */
+
+ for (cnt = 1; cnt < a->nstates; cnt++) /* 0 is endstate */
+ { if (cnt == f->from
+ || !fsm_tbl[cnt]->seen)
+ continue; /* c. */
+
+ i = cnt / BPW;
+ j = cnt % BPW;
+ if (!(f->dom[i]&(1<<j)))
+ continue;
+
+ for (t = fsm_tbl[cnt]->t, i = 0; t; t = t->nxt)
+ i += fsm_tbl[t->to]->seen;
+ if (i <= 1)
+ continue; /* b. */
+
+ if (f->mod) /* final check in 2nd phase */
+ subgraph(a, f, cnt); /* possible entry-exit pair */
+ }
+ }
+}
+
+static void
+reachability(AST *a)
+{ FSM_state *f;
+
+ for (f = a->fsm; f; f = f->nxt)
+ f->seen = 0; /* clear */
+ AST_dfs(a, a->i_st, 0); /* mark 'seen' */
+}
+
+static int
+see_else(FSM_state *f)
+{ FSM_trans *t;
+
+ for (t = f->t; t; t = t->nxt)
+ { if (t->step
+ && t->step->n)
+ switch (t->step->n->ntyp) {
+ case ELSE:
+ return 1;
+ case IF:
+ case DO:
+ case ATOMIC:
+ case NON_ATOMIC:
+ case D_STEP:
+ if (see_else(fsm_tbl[t->to]))
+ return 1;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+static int
+is_guard(FSM_state *f)
+{ FSM_state *g;
+ FSM_trans *t;
+
+ for (t = f->p; t; t = t->nxt)
+ { g = fsm_tbl[t->to];
+ if (!g->seen)
+ continue;
+
+ if (t->step
+ && t->step->n)
+ switch(t->step->n->ntyp) {
+ case IF:
+ case DO:
+ return 1;
+ case ATOMIC:
+ case NON_ATOMIC:
+ case D_STEP:
+ if (is_guard(g))
+ return 1;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+static void
+curtail(AST *a)
+{ FSM_state *f, *g;
+ FSM_trans *t;
+ int i, haselse, isrel, blocking;
+#if 0
+ mark nodes that do not satisfy these requirements:
+ 1. all internal branch-points have else-s
+ 2. all non-branchpoints have non-blocking out-edge
+ 3. all internal edges are non-data-relevant
+#endif
+ if (verbose&32)
+ printf("Curtail %s:\n", a->p->n->name);
+
+ for (f = a->fsm; f; f = f->nxt)
+ { if (!f->seen
+ || (f->scratch&(1|2)))
+ continue;
+
+ isrel = haselse = i = blocking = 0;
+
+ for (t = f->t; t; t = t->nxt)
+ { g = fsm_tbl[t->to];
+
+ isrel |= (t->relevant&1); /* data relevant */
+ i += g->seen;
+
+ if (t->step
+ && t->step->n)
+ { switch (t->step->n->ntyp) {
+ case IF:
+ case DO:
+ haselse |= see_else(g);
+ break;
+ case 'c':
+ case 's':
+ case 'r':
+ blocking = 1;
+ break;
+ } } }
+#if 0
+ if (verbose&32)
+ printf("prescratch %d -- %d %d %d %d -- %d\n",
+ f->from, i, isrel, blocking, haselse, is_guard(f));
+#endif
+ if (isrel /* 3. */
+ || (i == 1 && blocking) /* 2. */
+ || (i > 1 && !haselse)) /* 1. */
+ { if (!is_guard(f))
+ { f->scratch |= 1;
+ if (verbose&32)
+ printf("scratch %d -- %d %d %d %d\n",
+ f->from, i, isrel, blocking, haselse);
+ }
+ }
+ }
+}
+
+static void
+init_dom(AST *a)
+{ FSM_state *f;
+ int i, j, cnt;
+#if 0
+ (1) D(s0) = {s0}
+ (2) for s in S - {s0} do D(s) = S
+#endif
+
+ for (f = a->fsm; f; f = f->nxt)
+ { if (!f->seen) continue;
+
+ f->dom = (ulong *)
+ emalloc(a->nwords * sizeof(ulong));
+
+ if (f->from == a->i_st)
+ { i = a->i_st / BPW;
+ j = a->i_st % BPW;
+ f->dom[i] = (1<<j); /* (1) */
+ } else /* (2) */
+ { for (i = 0; i < a->nwords; i++)
+ f->dom[i] = (ulong) ~0; /* all 1's */
+
+ if (a->nstates % BPW)
+ for (i = (a->nstates % BPW); i < (int) BPW; i++)
+ f->dom[a->nwords-1] &= ~(1<<i); /* clear tail */
+
+ for (cnt = 0; cnt < a->nstates; cnt++)
+ if (!fsm_tbl[cnt]->seen)
+ { i = cnt / BPW;
+ j = cnt % BPW;
+ f->dom[i] &= ~(1<<j);
+ } } }
+}
+
+static int
+dom_perculate(AST *a, FSM_state *f)
+{ static ulong *ndom = (ulong *) 0;
+ static int on = 0;
+ int i, j, cnt = 0;
+ FSM_state *g;
+ FSM_trans *t;
+
+ if (on < a->nwords)
+ { on = a->nwords;
+ ndom = (ulong *)
+ emalloc(on * sizeof(ulong));
+ }
+
+ for (i = 0; i < a->nwords; i++)
+ ndom[i] = (ulong) ~0;
+
+ for (t = f->p; t; t = t->nxt) /* all reachable predecessors */
+ { g = fsm_tbl[t->to];
+ if (g->seen)
+ for (i = 0; i < a->nwords; i++)
+ ndom[i] &= g->dom[i]; /* (5b) */
+ }
+
+ i = f->from / BPW;
+ j = f->from % BPW;
+ ndom[i] |= (1<<j); /* (5a) */
+
+ for (i = 0; i < a->nwords; i++)
+ if (f->dom[i] != ndom[i])
+ { cnt++;
+ f->dom[i] = ndom[i];
+ }
+
+ return cnt;
+}
+
+static void
+dom_forward(AST *a)
+{ FSM_state *f;
+ int cnt;
+
+ init_dom(a); /* (1,2) */
+ do {
+ cnt = 0;
+ for (f = a->fsm; f; f = f->nxt)
+ { if (f->seen
+ && f->from != a->i_st) /* (4) */
+ cnt += dom_perculate(a, f); /* (5) */
+ }
+ } while (cnt); /* (3) */
+ dom_perculate(a, fsm_tbl[a->i_st]);
+}
+
+static void
+AST_dominant(void)
+{ FSM_state *f;
+ FSM_trans *t;
+ AST *a;
+ int oi;
+#if 0
+ find dominators
+ Aho, Sethi, & Ullman, Compilers - principles, techniques, and tools
+ Addison-Wesley, 1986, p.671.
+
+ (1) D(s0) = {s0}
+ (2) for s in S - {s0} do D(s) = S
+
+ (3) while any D(s) changes do
+ (4) for s in S - {s0} do
+ (5) D(s) = {s} union with intersection of all D(p)
+ where p are the immediate predecessors of s
+
+ the purpose is to find proper subgraphs
+ (one entry node, one exit node)
+#endif
+ if (AST_Round == 1) /* computed once, reused in every round */
+ for (a = ast; a; a = a->nxt)
+ { a->nstates = 0;
+ for (f = a->fsm; f; f = f->nxt)
+ { a->nstates++; /* count */
+ fsm_tbl[f->from] = f; /* fast lookup */
+ f->scratch = 0; /* clear scratch marks */
+ }
+ for (oi = 0; oi < a->nstates; oi++)
+ if (!fsm_tbl[oi])
+ fsm_tbl[oi] = &no_state;
+
+ a->nwords = (a->nstates + BPW - 1) / BPW; /* round up */
+
+ if (verbose&32)
+ { printf("%s (%d): ", a->p->n->name, a->i_st);
+ printf("states=%d (max %d), words = %d, bpw %d, overflow %d\n",
+ a->nstates, o_max, a->nwords,
+ (int) BPW, (int) (a->nstates % BPW));
+ }
+
+ reachability(a);
+ dom_forward(a); /* forward dominance relation */
+
+ curtail(a); /* mark ineligible edges */
+ for (f = a->fsm; f; f = f->nxt)
+ { t = f->p;
+ f->p = f->t;
+ f->t = t; /* invert edges */
+
+ f->mod = f->dom;
+ f->dom = (ulong *) 0;
+ }
+ oi = a->i_st;
+ if (fsm_tbl[0]->seen) /* end-state reachable - else leave it */
+ a->i_st = 0; /* becomes initial state */
+
+ dom_forward(a); /* reverse dominance -- don't redo reachability! */
+ act_dom(a); /* mark proper subgraphs, if any */
+ AST_checkpairs(a); /* selectively place 2 scratch-marks */
+
+ for (f = a->fsm; f; f = f->nxt)
+ { t = f->p;
+ f->p = f->t;
+ f->t = t; /* restore */
+ }
+ a->i_st = oi; /* restore */
+ } else
+ for (a = ast; a; a = a->nxt)
+ { for (f = a->fsm; f; f = f->nxt)
+ { fsm_tbl[f->from] = f;
+ f->scratch &= 1; /* preserve 1-marks */
+ }
+ for (oi = 0; oi < a->nstates; oi++)
+ if (!fsm_tbl[oi])
+ fsm_tbl[oi] = &no_state;
+
+ curtail(a); /* mark ineligible edges */
+
+ for (f = a->fsm; f; f = f->nxt)
+ { t = f->p;
+ f->p = f->t;
+ f->t = t; /* invert edges */
+ }
+
+ AST_checkpairs(a); /* recompute 2-marks */
+
+ for (f = a->fsm; f; f = f->nxt)
+ { t = f->p;
+ f->p = f->t;
+ f->t = t; /* restore */
+ } }
+}
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
diff --git a/sys/src/cmd/spin/ps_msc.c b/sys/src/cmd/spin/ps_msc.c
new file mode 100755
index 000000000..0aa764be9
--- /dev/null
+++ b/sys/src/cmd/spin/ps_msc.c
@@ -0,0 +1,448 @@
+/***** spin: ps_msc.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 */
+
+/* The Postscript generation code below was written by Gerard J. Holzmann */
+/* in June 1997. Parts of the prolog template are based on similar boiler */
+/* plate in the Tcl/Tk distribution. This code is used to support Spin's */
+/* option M for generating a Postscript file from a simulation run. */
+
+#include "spin.h"
+#include "version.h"
+
+#ifdef PC
+extern void free(void *);
+#endif
+
+static char *PsPre[] = {
+ "%%%%Pages: (atend)",
+ "%%%%PageOrder: Ascend",
+ "%%%%DocumentData: Clean7Bit",
+ "%%%%Orientation: Portrait",
+ "%%%%DocumentNeededResources: font Courier-Bold",
+ "%%%%EndComments",
+ "",
+ "%%%%BeginProlog",
+ "50 dict begin",
+ "",
+ "/baseline 0 def",
+ "/height 0 def",
+ "/justify 0 def",
+ "/lineLength 0 def",
+ "/spacing 0 def",
+ "/stipple 0 def",
+ "/strings 0 def",
+ "/xoffset 0 def",
+ "/yoffset 0 def",
+ "",
+ "/ISOEncode {",
+ " dup length dict begin",
+ " {1 index /FID ne {def} {pop pop} ifelse} forall",
+ " /Encoding ISOLatin1Encoding def",
+ " currentdict",
+ " end",
+ " /Temporary exch definefont",
+ "} bind def",
+ "",
+ "/AdjustColor {",
+ " CL 2 lt {",
+ " currentgray",
+ " CL 0 eq {",
+ " .5 lt {0} {1} ifelse",
+ " } if",
+ " setgray",
+ " } if",
+ "} bind def",
+ "",
+ "/DrawText {",
+ " /stipple exch def",
+ " /justify exch def",
+ " /yoffset exch def",
+ " /xoffset exch def",
+ " /spacing exch def",
+ " /strings exch def",
+ " /lineLength 0 def",
+ " strings {",
+ " stringwidth pop",
+ " dup lineLength gt {/lineLength exch def} {pop} ifelse",
+ " newpath",
+ " } forall",
+ " 0 0 moveto (TXygqPZ) false charpath",
+ " pathbbox dup /baseline exch def",
+ " exch pop exch sub /height exch def pop",
+ " newpath",
+ " translate",
+ " lineLength xoffset mul",
+ " strings length 1 sub spacing mul height add yoffset mul translate",
+ " justify lineLength mul baseline neg translate",
+ " strings {",
+ " dup stringwidth pop",
+ " justify neg mul 0 moveto",
+ " stipple {",
+ " gsave",
+ " /char (X) def",
+ " {",
+ " char 0 3 -1 roll put",
+ " currentpoint",
+ " gsave",
+ " char true charpath clip StippleText",
+ " grestore",
+ " char stringwidth translate",
+ " moveto",
+ " } forall",
+ " grestore",
+ " } {show} ifelse",
+ " 0 spacing neg translate",
+ " } forall",
+ "} bind def",
+ "%%%%EndProlog",
+ "%%%%BeginSetup",
+ "/CL 2 def",
+ "%%%%IncludeResource: font Courier-Bold",
+ "%%%%EndSetup",
+ 0,
+};
+
+int MH = 600; /* page height - can be scaled */
+int oMH = 600; /* page height - not scaled */
+#define MW 500 /* page width */
+#define LH 100 /* bottom margin */
+#define RH 100 /* right margin */
+#define WW 50 /* distance between process lines */
+#define HH 8 /* vertical distance between steps */
+#define PH 14 /* height of process-tag headers */
+
+static FILE *pfd;
+static char **I; /* initial procs */
+static int *D,*R; /* maps between depth and ldepth */
+static short *M; /* x location of each box at index y */
+static short *T; /* y index of match for each box at index y */
+static char **L; /* text labels */
+static char *ProcLine; /* active processes */
+static int pspno = 0; /* postscript page */
+static int ldepth = 1;
+static int maxx, TotSteps = 2*4096; /* max nr of steps, about 40 pages */
+static float Scaler = (float) 1.0;
+
+extern int ntrail, s_trail, pno, depth;
+extern Symbol *oFname;
+extern void exit(int);
+void putpages(void);
+void spitbox(int, int, int, char *);
+
+void
+putlegend(void)
+{
+ fprintf(pfd, "gsave\n");
+ fprintf(pfd, "/Courier-Bold findfont 8 scalefont ");
+ fprintf(pfd, "ISOEncode setfont\n");
+ fprintf(pfd, "0.000 0.000 0.000 setrgbcolor AdjustColor\n");
+ fprintf(pfd, "%d %d [\n", MW/2, LH+oMH+ 5*HH);
+ fprintf(pfd, " (%s -- %s -- MSC -- %d)\n] 10 -0.5 0.5 0 ",
+ Version, oFname?oFname->name:"", pspno);
+ fprintf(pfd, "false DrawText\ngrestore\n");
+}
+
+void
+startpage(void)
+{ int i;
+
+ pspno++;
+ fprintf(pfd, "%%%%Page: %d %d\n", pspno, pspno);
+ putlegend();
+
+ for (i = TotSteps-1; i >= 0; i--)
+ { if (!I[i]) continue;
+ spitbox(i, RH, -PH, I[i]);
+ }
+
+ fprintf(pfd, "save\n");
+ fprintf(pfd, "10 %d moveto\n", LH+oMH+5);
+ fprintf(pfd, "%d %d lineto\n", RH+MW, LH+oMH+5);
+ fprintf(pfd, "%d %d lineto\n", RH+MW, LH);
+ fprintf(pfd, "10 %d lineto\n", LH);
+ fprintf(pfd, "closepath clip newpath\n");
+ fprintf(pfd, "%f %f translate\n",
+ (float) RH, (float) LH);
+ memset(ProcLine, 0, 256*sizeof(char));
+ if (Scaler != 1.0)
+ fprintf(pfd, "%f %f scale\n", Scaler, Scaler);
+}
+
+void
+putprelude(void)
+{ char snap[256]; FILE *fd;
+
+ sprintf(snap, "%s.ps", oFname?oFname->name:"msc");
+ if (!(pfd = fopen(snap, "w")))
+ fatal("cannot create file '%s'", snap);
+
+ fprintf(pfd, "%%!PS-Adobe-2.0\n");
+ fprintf(pfd, "%%%%Creator: %s\n", Version);
+ fprintf(pfd, "%%%%Title: MSC %s\n", oFname?oFname->name:"--");
+ fprintf(pfd, "%%%%BoundingBox: 119 154 494 638\n");
+ ntimes(pfd, 0, 1, PsPre);
+
+ if (s_trail)
+ { if (ntrail)
+ sprintf(snap, "%s%d.trail", oFname?oFname->name:"msc", ntrail);
+ else
+ sprintf(snap, "%s.trail", oFname?oFname->name:"msc");
+ if (!(fd = fopen(snap, "r")))
+ { snap[strlen(snap)-2] = '\0';
+ if (!(fd = fopen(snap, "r")))
+ fatal("cannot open trail file", (char *) 0);
+ }
+ TotSteps = 1;
+ while (fgets(snap, 256, fd)) TotSteps++;
+ fclose(fd);
+ }
+ R = (int *) emalloc(TotSteps * sizeof(int));
+ D = (int *) emalloc(TotSteps * sizeof(int));
+ M = (short *) emalloc(TotSteps * sizeof(short));
+ T = (short *) emalloc(TotSteps * sizeof(short));
+ L = (char **) emalloc(TotSteps * sizeof(char *));
+ I = (char **) emalloc(TotSteps * sizeof(char *));
+ ProcLine = (char *) emalloc(1024 * sizeof(char));
+ startpage();
+}
+
+void
+putpostlude(void)
+{ putpages();
+ fprintf(pfd, "%%%%Trailer\n");
+ fprintf(pfd, "end\n");
+ fprintf(pfd, "%%%%Pages: %d\n", pspno);
+ fprintf(pfd, "%%%%EOF\n");
+ fclose(pfd);
+ /* stderr, in case user redirected output */
+ fprintf(stderr, "spin: wrote %d pages into '%s.ps'\n",
+ pspno, oFname?oFname->name:"msc");
+ exit(0);
+}
+void
+psline(int x0, int iy0, int x1, int iy1, float r, float g, float b, int w)
+{ int y0 = MH-iy0;
+ int y1 = MH-iy1;
+
+ if (y1 > y0) y1 -= MH;
+
+ fprintf(pfd, "gsave\n");
+ fprintf(pfd, "%d %d moveto\n", x0*WW, y0);
+ fprintf(pfd, "%d %d lineto\n", x1*WW, y1);
+ fprintf(pfd, "%d setlinewidth\n", w);
+ fprintf(pfd, "0 setlinecap\n");
+ fprintf(pfd, "1 setlinejoin\n");
+ fprintf(pfd, "%f %f %f setrgbcolor AdjustColor\n", r,g,b);
+ fprintf(pfd, "stroke\ngrestore\n");
+}
+
+void
+colbox(int x, int y, int w, int h, float r, float g, float b)
+{ fprintf(pfd, "%d %d moveto\n", x - w, y-h);
+ fprintf(pfd, "%d %d lineto\n", x + w, y-h);
+ fprintf(pfd, "%d %d lineto\n", x + w, y+h);
+ fprintf(pfd, "%d %d lineto\n", x - w, y+h);
+ fprintf(pfd, "%d %d lineto\n", x - w, y-h);
+ fprintf(pfd, "%f %f %f setrgbcolor AdjustColor\n", r,g,b);
+ fprintf(pfd, "closepath fill\n");
+}
+
+void
+putgrid(int p)
+{ int i;
+
+ for (i = p ; i >= 0; i--)
+ if (!ProcLine[i])
+ { psline(i,0, i,MH-1,
+ (float) 0.4, (float) 0.4, (float) 1.0, 1);
+ ProcLine[i] = 1;
+ }
+}
+
+void
+putarrow(int from, int to)
+{
+ T[D[from]] = D[to];
+}
+
+void
+stepnumber(int i)
+{ int y = MH-(i*HH)%MH;
+
+ fprintf(pfd, "gsave\n");
+ fprintf(pfd, "/Courier-Bold findfont 6 scalefont ");
+ fprintf(pfd, "ISOEncode setfont\n");
+ fprintf(pfd, "0.000 0.000 0.000 setrgbcolor AdjustColor\n");
+ fprintf(pfd, "%d %d [\n", -40, y);
+ fprintf(pfd, " (%d)\n] 10 -0.5 0.5 0 ", R[i]);
+ fprintf(pfd, "false DrawText\ngrestore\n");
+ fprintf(pfd, "%d %d moveto\n", -20, y);
+ fprintf(pfd, "%d %d lineto\n", M[i]*WW, y);
+ fprintf(pfd, "1 setlinewidth\n0 setlinecap\n1 setlinejoin\n");
+ fprintf(pfd, "0.92 0.92 0.92 setrgbcolor AdjustColor\n");
+ fprintf(pfd, "stroke\n");
+}
+
+void
+spitbox(int x, int dx, int y, char *s)
+{ float r,g,b, bw; int a; char d[256];
+
+ if (!dx)
+ { stepnumber(y);
+ putgrid(x);
+ }
+ bw = (float)2.7*(float)strlen(s);
+ colbox(x*WW+dx, MH-(y*HH)%MH, (int) (bw+1.0),
+ 5, (float) 0.,(float) 0.,(float) 0.);
+ if (s[0] == '~')
+ { switch (s[1]) {
+ case 'B': r = (float) 0.2; g = (float) 0.2; b = (float) 1.;
+ break;
+ case 'G': r = (float) 0.2; g = (float) 1.; b = (float) 0.2;
+ break;
+ case 'R':
+ default : r = (float) 1.; g = (float) 0.2; b = (float) 0.2;
+ break;
+ }
+ s += 2;
+ } else if (strchr(s, '!'))
+ { r = (float) 1.; g = (float) 1.; b = (float) 1.;
+ } else if (strchr(s, '?'))
+ { r = (float) 0.; g = (float) 1.; b = (float) 1.;
+ } else
+ { r = (float) 1.; g = (float) 1.; b = (float) 0.;
+ if (!dx
+ && sscanf(s, "%d:%s", &a, d) == 2 /* was &d */
+ && a >= 0 && a < TotSteps)
+ { if (!I[a]
+ || strlen(I[a]) <= strlen(s))
+ I[a] = emalloc((int) strlen(s)+1);
+ strcpy(I[a], s);
+ } }
+ colbox(x*WW+dx, MH-(y*HH)%MH, (int) bw, 4, r,g,b);
+ fprintf(pfd, "gsave\n");
+ fprintf(pfd, "/Courier-Bold findfont 8 scalefont ");
+ fprintf(pfd, "ISOEncode setfont\n");
+ fprintf(pfd, "0.000 0.000 0.000 setrgbcolor AdjustColor\n");
+ fprintf(pfd, "%d %d [\n", x*WW+dx, MH-(y*HH)%MH);
+ fprintf(pfd, " (%s)\n] 10 -0.5 0.5 0 ", s);
+ fprintf(pfd, "false DrawText\ngrestore\n");
+}
+
+void
+putpages(void)
+{ int i, lasti=0; float nmh;
+
+ if (maxx*WW > MW-RH/2)
+ { Scaler = (float) (MW-RH/2) / (float) (maxx*WW);
+ fprintf(pfd, "%f %f scale\n", Scaler, Scaler);
+ nmh = (float) MH; nmh /= Scaler; MH = (int) nmh;
+ }
+
+ for (i = TotSteps-1; i >= 0; i--)
+ { if (!I[i]) continue;
+ spitbox(i, 0, 0, I[i]);
+ }
+ if (ldepth >= TotSteps) ldepth = TotSteps-1;
+ for (i = 0; i <= ldepth; i++)
+ { if (!M[i] && !L[i]) continue; /* no box here */
+ if (6+i*HH >= MH*pspno)
+ { fprintf(pfd, "showpage\nrestore\n"); startpage(); }
+ if (T[i] > 0) /* red arrow */
+ { int reali = i*HH;
+ int realt = T[i]*HH;
+ int topop = (reali)/MH; topop *= MH;
+ reali -= topop; realt -= topop;
+
+ if (M[i] == M[T[i]] && reali == realt)
+ /* an rv handshake */
+ psline( M[lasti], reali+2-3*HH/2,
+ M[i], reali,
+ (float) 1.,(float) 0.,(float) 0., 2);
+ else
+ psline( M[i], reali,
+ M[T[i]], realt,
+ (float) 1.,(float) 0.,(float) 0., 2);
+
+ if (realt >= MH) T[T[i]] = -i;
+
+ } else if (T[i] < 0) /* arrow from prev page */
+ { int reali = (-T[i])*HH;
+ int realt = i*HH;
+ int topop = (realt)/MH; topop *= MH;
+ reali -= topop; realt -= topop;
+
+ psline( M[-T[i]], reali,
+ M[i], realt,
+ (float) 1., (float) 0., (float) 0., 2);
+ }
+ if (L[i])
+ { spitbox(M[i], 0, i, L[i]);
+ free(L[i]);
+ lasti = i;
+ }
+ }
+ fprintf(pfd, "showpage\nrestore\n");
+}
+
+void
+putbox(int x)
+{
+ if (ldepth >= TotSteps)
+ { putpostlude();
+ fprintf(stderr, "max length of %d steps exceeded\n",
+ TotSteps);
+ fatal("postscript file truncated", (char *) 0);
+ }
+ M[ldepth] = x;
+ if (x > maxx) maxx = x;
+}
+
+void
+pstext(int x, char *s)
+{ char *tmp = emalloc((int) strlen(s)+1);
+
+ strcpy(tmp, s);
+ if (depth == 0)
+ I[x] = tmp;
+ else
+ { putbox(x);
+ if (depth >= TotSteps || ldepth >= TotSteps)
+ { fprintf(stderr, "max nr of %d steps exceeded\n",
+ TotSteps);
+ fatal("aborting", (char *) 0);
+ }
+
+ D[depth] = ldepth;
+ R[ldepth] = depth;
+ L[ldepth] = tmp;
+ ldepth += 2;
+ }
+}
+
+void
+dotag(FILE *fd, char *s)
+{ extern int columns, notabs; extern RunList *X;
+ int i = (!strncmp(s, "MSC: ", 5))?5:0;
+ int pid = s_trail ? pno : (X?X->pid:0);
+
+ if (columns == 2)
+ pstext(pid, &s[i]);
+ else
+ { if (!notabs)
+ { printf(" ");
+ for (i = 0; i <= pid; i++)
+ printf(" ");
+ }
+ fprintf(fd, "%s", s);
+ fflush(fd);
+ }
+}
diff --git a/sys/src/cmd/spin/reprosrc.c b/sys/src/cmd/spin/reprosrc.c
new file mode 100755
index 000000000..0d4ba6be7
--- /dev/null
+++ b/sys/src/cmd/spin/reprosrc.c
@@ -0,0 +1,136 @@
+/***** spin: reprosrc.c *****/
+
+/* Copyright (c) 2002-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 */
+
+#include <stdio.h>
+#include "spin.h"
+#include "y.tab.h"
+
+static int indent = 1;
+
+extern ProcList *rdy;
+void repro_seq(Sequence *);
+
+void
+doindent(void)
+{ int i;
+ for (i = 0; i < indent; i++)
+ printf(" ");
+}
+
+void
+repro_sub(Element *e)
+{
+ doindent();
+ switch (e->n->ntyp) {
+ case D_STEP:
+ printf("d_step {\n");
+ break;
+ case ATOMIC:
+ printf("atomic {\n");
+ break;
+ case NON_ATOMIC:
+ printf(" {\n");
+ break;
+ }
+ indent++;
+ repro_seq(e->n->sl->this);
+ indent--;
+
+ doindent();
+ printf(" };\n");
+}
+
+void
+repro_seq(Sequence *s)
+{ Element *e;
+ Symbol *v;
+ SeqList *h;
+
+ for (e = s->frst; e; e = e->nxt)
+ {
+ v = has_lab(e, 0);
+ if (v) printf("%s:\n", v->name);
+
+ if (e->n->ntyp == UNLESS)
+ { printf("/* normal */ {\n");
+ repro_seq(e->n->sl->this);
+ doindent();
+ printf("} unless {\n");
+ repro_seq(e->n->sl->nxt->this);
+ doindent();
+ printf("}; /* end unless */\n");
+ } else if (e->sub)
+ {
+ switch (e->n->ntyp) {
+ case DO: doindent(); printf("do\n"); indent++; break;
+ case IF: doindent(); printf("if\n"); indent++; break;
+ }
+
+ for (h = e->sub; h; h = h->nxt)
+ { indent--; doindent(); indent++; printf("::\n");
+ repro_seq(h->this);
+ printf("\n");
+ }
+
+ switch (e->n->ntyp) {
+ case DO: indent--; doindent(); printf("od;\n"); break;
+ case IF: indent--; doindent(); printf("fi;\n"); break;
+ }
+ } else
+ { if (e->n->ntyp == ATOMIC
+ || e->n->ntyp == D_STEP
+ || e->n->ntyp == NON_ATOMIC)
+ repro_sub(e);
+ else if (e->n->ntyp != '.'
+ && e->n->ntyp != '@'
+ && e->n->ntyp != BREAK)
+ {
+ doindent();
+ if (e->n->ntyp == C_CODE)
+ { printf("c_code ");
+ plunk_inline(stdout, e->n->sym->name, 1);
+ } else if (e->n->ntyp == 'c'
+ && e->n->lft->ntyp == C_EXPR)
+ { printf("c_expr { ");
+ plunk_expr(stdout, e->n->lft->sym->name);
+ printf("} ->\n");
+ } else
+ { comment(stdout, e->n, 0);
+ printf(";\n");
+ } }
+ }
+ if (e == s->last)
+ break;
+ }
+}
+
+void
+repro_proc(ProcList *p)
+{
+ if (!p) return;
+ if (p->nxt) repro_proc(p->nxt);
+
+ if (p->det) printf("D"); /* deterministic */
+ printf("proctype %s()", p->n->name);
+ if (p->prov)
+ { printf(" provided ");
+ comment(stdout, p->prov, 0);
+ }
+ printf("\n{\n");
+ repro_seq(p->s);
+ printf("}\n");
+}
+
+void
+repro_src(void)
+{
+ repro_proc(rdy);
+}
diff --git a/sys/src/cmd/spin/run.c b/sys/src/cmd/spin/run.c
new file mode 100755
index 000000000..c336feef2
--- /dev/null
+++ b/sys/src/cmd/spin/run.c
@@ -0,0 +1,602 @@
+/***** spin: run.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include <stdlib.h>
+#include "spin.h"
+#include "y.tab.h"
+
+extern RunList *X, *run;
+extern Symbol *Fname;
+extern Element *LastStep;
+extern int Rvous, lineno, Tval, interactive, MadeChoice;
+extern int TstOnly, verbose, s_trail, xspin, jumpsteps, depth;
+extern int nproc, nstop, no_print, like_java;
+
+static long Seed = 1;
+static int E_Check = 0, Escape_Check = 0;
+
+static int eval_sync(Element *);
+static int pc_enabled(Lextok *n);
+extern void sr_buf(int, int);
+
+void
+Srand(unsigned int s)
+{ Seed = s;
+}
+
+long
+Rand(void)
+{ /* CACM 31(10), Oct 1988 */
+ Seed = 16807*(Seed%127773) - 2836*(Seed/127773);
+ if (Seed <= 0) Seed += 2147483647;
+ return Seed;
+}
+
+Element *
+rev_escape(SeqList *e)
+{ Element *r;
+
+ if (!e)
+ return (Element *) 0;
+
+ if ((r = rev_escape(e->nxt)) != ZE) /* reversed order */
+ return r;
+
+ return eval_sub(e->this->frst);
+}
+
+Element *
+eval_sub(Element *e)
+{ Element *f, *g;
+ SeqList *z;
+ int i, j, k;
+
+ if (!e->n)
+ return ZE;
+#ifdef DEBUG
+ printf("\n\teval_sub(%d %s: line %d) ",
+ e->Seqno, e->esc?"+esc":"", e->n?e->n->ln:0);
+ comment(stdout, e->n, 0);
+ printf("\n");
+#endif
+ if (e->n->ntyp == GOTO)
+ { if (Rvous) return ZE;
+ LastStep = e; f = get_lab(e->n, 1);
+ cross_dsteps(e->n, f->n);
+ return f;
+ }
+ if (e->n->ntyp == UNLESS)
+ { /* escapes were distributed into sequence */
+ return eval_sub(e->sub->this->frst);
+ } else if (e->sub) /* true for IF, DO, and UNLESS */
+ { Element *has_else = ZE;
+ Element *bas_else = ZE;
+ int nr_else = 0, nr_choices = 0;
+
+ if (interactive
+ && !MadeChoice && !E_Check
+ && !Escape_Check
+ && !(e->status&(D_ATOM))
+ && depth >= jumpsteps)
+ { printf("Select stmnt (");
+ whoruns(0); printf(")\n");
+ if (nproc-nstop > 1)
+ printf("\tchoice 0: other process\n");
+ }
+ for (z = e->sub, j=0; z; z = z->nxt)
+ { j++;
+ if (interactive
+ && !MadeChoice && !E_Check
+ && !Escape_Check
+ && !(e->status&(D_ATOM))
+ && depth >= jumpsteps
+ && z->this->frst
+ && (xspin || (verbose&32) || Enabled0(z->this->frst)))
+ { if (z->this->frst->n->ntyp == ELSE)
+ { has_else = (Rvous)?ZE:z->this->frst->nxt;
+ nr_else = j;
+ continue;
+ }
+ printf("\tchoice %d: ", j);
+#if 0
+ if (z->this->frst->n)
+ printf("line %d, ", z->this->frst->n->ln);
+#endif
+ if (!Enabled0(z->this->frst))
+ printf("unexecutable, ");
+ else
+ nr_choices++;
+ comment(stdout, z->this->frst->n, 0);
+ printf("\n");
+ } }
+
+ if (nr_choices == 0 && has_else)
+ printf("\tchoice %d: (else)\n", nr_else);
+
+ if (interactive && depth >= jumpsteps
+ && !Escape_Check
+ && !(e->status&(D_ATOM))
+ && !E_Check)
+ { if (!MadeChoice)
+ { char buf[256];
+ if (xspin)
+ printf("Make Selection %d\n\n", j);
+ else
+ printf("Select [0-%d]: ", j);
+ fflush(stdout);
+ scanf("%s", buf);
+ if (isdigit(buf[0]))
+ k = atoi(buf);
+ else
+ { if (buf[0] == 'q')
+ alldone(0);
+ k = -1;
+ }
+ } else
+ { k = MadeChoice;
+ MadeChoice = 0;
+ }
+ if (k < 1 || k > j)
+ { if (k != 0) printf("\tchoice outside range\n");
+ return ZE;
+ }
+ k--;
+ } else
+ { if (e->n && e->n->indstep >= 0)
+ k = 0; /* select 1st executable guard */
+ else
+ k = Rand()%j; /* nondeterminism */
+ }
+ has_else = ZE;
+ bas_else = ZE;
+ for (i = 0, z = e->sub; i < j+k; i++)
+ { if (z->this->frst
+ && z->this->frst->n->ntyp == ELSE)
+ { bas_else = z->this->frst;
+ has_else = (Rvous)?ZE:bas_else->nxt;
+ if (!interactive || depth < jumpsteps
+ || Escape_Check
+ || (e->status&(D_ATOM)))
+ { z = (z->nxt)?z->nxt:e->sub;
+ continue;
+ }
+ }
+ if (z->this->frst
+ && ((z->this->frst->n->ntyp == ATOMIC
+ || z->this->frst->n->ntyp == D_STEP)
+ && z->this->frst->n->sl->this->frst->n->ntyp == ELSE))
+ { bas_else = z->this->frst->n->sl->this->frst;
+ has_else = (Rvous)?ZE:bas_else->nxt;
+ if (!interactive || depth < jumpsteps
+ || Escape_Check
+ || (e->status&(D_ATOM)))
+ { z = (z->nxt)?z->nxt:e->sub;
+ continue;
+ }
+ }
+ if (i >= k)
+ { if ((f = eval_sub(z->this->frst)) != ZE)
+ return f;
+ else if (interactive && depth >= jumpsteps
+ && !(e->status&(D_ATOM)))
+ { if (!E_Check && !Escape_Check)
+ printf("\tunexecutable\n");
+ return ZE;
+ } }
+ z = (z->nxt)?z->nxt:e->sub;
+ }
+ LastStep = bas_else;
+ return has_else;
+ } else
+ { if (e->n->ntyp == ATOMIC
+ || e->n->ntyp == D_STEP)
+ { f = e->n->sl->this->frst;
+ g = e->n->sl->this->last;
+ g->nxt = e->nxt;
+ if (!(g = eval_sub(f))) /* atomic guard */
+ return ZE;
+ return g;
+ } else if (e->n->ntyp == NON_ATOMIC)
+ { f = e->n->sl->this->frst;
+ g = e->n->sl->this->last;
+ g->nxt = e->nxt; /* close it */
+ return eval_sub(f);
+ } else if (e->n->ntyp == '.')
+ { if (!Rvous) return e->nxt;
+ return eval_sub(e->nxt);
+ } else
+ { SeqList *x;
+ if (!(e->status & (D_ATOM))
+ && e->esc && verbose&32)
+ { printf("Stmnt [");
+ comment(stdout, e->n, 0);
+ printf("] has escape(s): ");
+ for (x = e->esc; x; x = x->nxt)
+ { printf("[");
+ g = x->this->frst;
+ if (g->n->ntyp == ATOMIC
+ || g->n->ntyp == NON_ATOMIC)
+ g = g->n->sl->this->frst;
+ comment(stdout, g->n, 0);
+ printf("] ");
+ }
+ printf("\n");
+ }
+#if 0
+ if (!(e->status & D_ATOM)) /* escapes don't reach inside d_steps */
+ /* 4.2.4: only the guard of a d_step can have an escape */
+#endif
+ { Escape_Check++;
+ if (like_java)
+ { if ((g = rev_escape(e->esc)) != ZE)
+ { if (verbose&4)
+ printf("\tEscape taken\n");
+ Escape_Check--;
+ return g;
+ }
+ } else
+ { for (x = e->esc; x; x = x->nxt)
+ { if ((g = eval_sub(x->this->frst)) != ZE)
+ { if (verbose&4)
+ printf("\tEscape taken\n");
+ Escape_Check--;
+ return g;
+ } } }
+ Escape_Check--;
+ }
+
+ switch (e->n->ntyp) {
+ case TIMEOUT: case RUN:
+ case PRINT: case PRINTM:
+ case C_CODE: case C_EXPR:
+ case ASGN: case ASSERT:
+ case 's': case 'r': case 'c':
+ /* toplevel statements only */
+ LastStep = e;
+ default:
+ break;
+ }
+ if (Rvous)
+ {
+ return (eval_sync(e))?e->nxt:ZE;
+ }
+ return (eval(e->n))?e->nxt:ZE;
+ }
+ }
+ return ZE; /* not reached */
+}
+
+static int
+eval_sync(Element *e)
+{ /* allow only synchronous receives
+ and related node types */
+ Lextok *now = (e)?e->n:ZN;
+
+ if (!now
+ || now->ntyp != 'r'
+ || now->val >= 2 /* no rv with a poll */
+ || !q_is_sync(now))
+ {
+ return 0;
+ }
+
+ LastStep = e;
+ return eval(now);
+}
+
+static int
+assign(Lextok *now)
+{ int t;
+
+ if (TstOnly) return 1;
+
+ switch (now->rgt->ntyp) {
+ case FULL: case NFULL:
+ case EMPTY: case NEMPTY:
+ case RUN: case LEN:
+ t = BYTE;
+ break;
+ default:
+ t = Sym_typ(now->rgt);
+ break;
+ }
+ typ_ck(Sym_typ(now->lft), t, "assignment");
+ return setval(now->lft, eval(now->rgt));
+}
+
+static int
+nonprogress(void) /* np_ */
+{ RunList *r;
+
+ for (r = run; r; r = r->nxt)
+ { if (has_lab(r->pc, 4)) /* 4=progress */
+ return 0;
+ }
+ return 1;
+}
+
+int
+eval(Lextok *now)
+{
+ if (now) {
+ lineno = now->ln;
+ Fname = now->fn;
+#ifdef DEBUG
+ printf("eval ");
+ comment(stdout, now, 0);
+ printf("\n");
+#endif
+ switch (now->ntyp) {
+ case CONST: return now->val;
+ case '!': return !eval(now->lft);
+ case UMIN: return -eval(now->lft);
+ case '~': return ~eval(now->lft);
+
+ case '/': return (eval(now->lft) / eval(now->rgt));
+ case '*': return (eval(now->lft) * eval(now->rgt));
+ case '-': return (eval(now->lft) - eval(now->rgt));
+ case '+': return (eval(now->lft) + eval(now->rgt));
+ case '%': return (eval(now->lft) % eval(now->rgt));
+ case LT: return (eval(now->lft) < eval(now->rgt));
+ case GT: return (eval(now->lft) > eval(now->rgt));
+ case '&': return (eval(now->lft) & eval(now->rgt));
+ case '^': return (eval(now->lft) ^ eval(now->rgt));
+ case '|': return (eval(now->lft) | eval(now->rgt));
+ case LE: return (eval(now->lft) <= eval(now->rgt));
+ case GE: return (eval(now->lft) >= eval(now->rgt));
+ case NE: return (eval(now->lft) != eval(now->rgt));
+ case EQ: return (eval(now->lft) == eval(now->rgt));
+ case OR: return (eval(now->lft) || eval(now->rgt));
+ case AND: return (eval(now->lft) && eval(now->rgt));
+ case LSHIFT: return (eval(now->lft) << eval(now->rgt));
+ case RSHIFT: return (eval(now->lft) >> eval(now->rgt));
+ case '?': return (eval(now->lft) ? eval(now->rgt->lft)
+ : eval(now->rgt->rgt));
+
+ case 'p': return remotevar(now); /* _p for remote reference */
+ case 'q': return remotelab(now);
+ case 'R': return qrecv(now, 0); /* test only */
+ case LEN: return qlen(now);
+ case FULL: return (qfull(now));
+ case EMPTY: return (qlen(now)==0);
+ case NFULL: return (!qfull(now));
+ case NEMPTY: return (qlen(now)>0);
+ case ENABLED: if (s_trail) return 1;
+ return pc_enabled(now->lft);
+ case EVAL: return eval(now->lft);
+ case PC_VAL: return pc_value(now->lft);
+ case NONPROGRESS: return nonprogress();
+ case NAME: return getval(now);
+
+ case TIMEOUT: return Tval;
+ case RUN: return TstOnly?1:enable(now);
+
+ case 's': return qsend(now); /* send */
+ case 'r': return qrecv(now, 1); /* receive or poll */
+ case 'c': return eval(now->lft); /* condition */
+ case PRINT: return TstOnly?1:interprint(stdout, now);
+ case PRINTM: return TstOnly?1:printm(stdout, now);
+ case ASGN: return assign(now);
+
+ case C_CODE: printf("%s:\t", now->sym->name);
+ plunk_inline(stdout, now->sym->name, 0);
+ return 1; /* uninterpreted */
+
+ case C_EXPR: printf("%s:\t", now->sym->name);
+ plunk_expr(stdout, now->sym->name);
+ printf("\n");
+ return 1; /* uninterpreted */
+
+ case ASSERT: if (TstOnly || eval(now->lft)) return 1;
+ non_fatal("assertion violated", (char *) 0);
+ printf("spin: text of failed assertion: assert(");
+ comment(stdout, now->lft, 0);
+ printf(")\n");
+ if (s_trail && !xspin) return 1;
+ wrapup(1); /* doesn't return */
+
+ case IF: case DO: case BREAK: case UNLESS: /* compound */
+ case '.': return 1; /* return label for compound */
+ case '@': return 0; /* stop state */
+ case ELSE: return 1; /* only hit here in guided trails */
+ default : printf("spin: bad node type %d (run)\n", now->ntyp);
+ if (s_trail) printf("spin: trail file doesn't match spec?\n");
+ fatal("aborting", 0);
+ }}
+ return 0;
+}
+
+int
+printm(FILE *fd, Lextok *n)
+{ extern char Buf[];
+ int j;
+
+ Buf[0] = '\0';
+ if (!no_print)
+ if (!s_trail || depth >= jumpsteps) {
+ if (n->lft->ismtyp)
+ j = n->lft->val;
+ else
+ j = eval(n->lft);
+ Buf[0] = '\0';
+ sr_buf(j, 1);
+ dotag(fd, Buf);
+ }
+ return 1;
+}
+
+int
+interprint(FILE *fd, Lextok *n)
+{ Lextok *tmp = n->lft;
+ char c, *s = n->sym->name;
+ int i, j; char lbuf[512];
+ extern char Buf[];
+ char tBuf[4096];
+
+ Buf[0] = '\0';
+ if (!no_print)
+ if (!s_trail || depth >= jumpsteps) {
+ for (i = 0; i < (int) strlen(s); i++)
+ switch (s[i]) {
+ case '\"': break; /* ignore */
+ case '\\':
+ switch(s[++i]) {
+ case 't': strcat(Buf, "\t"); break;
+ case 'n': strcat(Buf, "\n"); break;
+ default: goto onechar;
+ }
+ break;
+ case '%':
+ if ((c = s[++i]) == '%')
+ { strcat(Buf, "%"); /* literal */
+ break;
+ }
+ if (!tmp)
+ { non_fatal("too few print args %s", s);
+ break;
+ }
+ j = eval(tmp->lft);
+ tmp = tmp->rgt;
+ switch(c) {
+ case 'c': sprintf(lbuf, "%c", j); break;
+ case 'd': sprintf(lbuf, "%d", j); break;
+
+ case 'e': strcpy(tBuf, Buf); /* event name */
+ Buf[0] = '\0';
+ sr_buf(j, 1);
+ strcpy(lbuf, Buf);
+ strcpy(Buf, tBuf);
+ break;
+
+ case 'o': sprintf(lbuf, "%o", j); break;
+ case 'u': sprintf(lbuf, "%u", (unsigned) j); break;
+ case 'x': sprintf(lbuf, "%x", j); break;
+ default: non_fatal("bad print cmd: '%s'", &s[i-1]);
+ lbuf[0] = '\0'; break;
+ }
+ goto append;
+ default:
+onechar: lbuf[0] = s[i]; lbuf[1] = '\0';
+append: strcat(Buf, lbuf);
+ break;
+ }
+ dotag(fd, Buf);
+ }
+ if (strlen(Buf) > 4096) fatal("printf string too long", 0);
+ return 1;
+}
+
+static int
+Enabled1(Lextok *n)
+{ int i; int v = verbose;
+
+ if (n)
+ switch (n->ntyp) {
+ case 'c':
+ if (has_typ(n->lft, RUN))
+ return 1; /* conservative */
+ /* else fall through */
+ default: /* side-effect free */
+ verbose = 0;
+ E_Check++;
+ i = eval(n);
+ E_Check--;
+ verbose = v;
+ return i;
+
+ case C_CODE: case C_EXPR:
+ case PRINT: case PRINTM:
+ case ASGN: case ASSERT:
+ return 1;
+
+ case 's':
+ if (q_is_sync(n))
+ { if (Rvous) return 0;
+ TstOnly = 1; verbose = 0;
+ E_Check++;
+ i = eval(n);
+ E_Check--;
+ TstOnly = 0; verbose = v;
+ return i;
+ }
+ return (!qfull(n));
+ case 'r':
+ if (q_is_sync(n))
+ return 0; /* it's never a user-choice */
+ n->ntyp = 'R'; verbose = 0;
+ E_Check++;
+ i = eval(n);
+ E_Check--;
+ n->ntyp = 'r'; verbose = v;
+ return i;
+ }
+ return 0;
+}
+
+int
+Enabled0(Element *e)
+{ SeqList *z;
+
+ if (!e || !e->n)
+ return 0;
+
+ switch (e->n->ntyp) {
+ case '@':
+ return X->pid == (nproc-nstop-1);
+ case '.':
+ return 1;
+ case GOTO:
+ if (Rvous) return 0;
+ return 1;
+ case UNLESS:
+ return Enabled0(e->sub->this->frst);
+ case ATOMIC:
+ case D_STEP:
+ case NON_ATOMIC:
+ return Enabled0(e->n->sl->this->frst);
+ }
+ if (e->sub) /* true for IF, DO, and UNLESS */
+ { for (z = e->sub; z; z = z->nxt)
+ if (Enabled0(z->this->frst))
+ return 1;
+ return 0;
+ }
+ for (z = e->esc; z; z = z->nxt)
+ { if (Enabled0(z->this->frst))
+ return 1;
+ }
+#if 0
+ printf("enabled1 ");
+ comment(stdout, e->n, 0);
+ printf(" ==> %s\n", Enabled1(e->n)?"yes":"nope");
+#endif
+ return Enabled1(e->n);
+}
+
+int
+pc_enabled(Lextok *n)
+{ int i = nproc - nstop;
+ int pid = eval(n);
+ int result = 0;
+ RunList *Y, *oX;
+
+ if (pid == X->pid)
+ fatal("used: enabled(pid=thisproc) [%s]", X->n->name);
+
+ for (Y = run; Y; Y = Y->nxt)
+ if (--i == pid)
+ { oX = X; X = Y;
+ result = Enabled0(Y->pc);
+ X = oX;
+ break;
+ }
+ return result;
+}
diff --git a/sys/src/cmd/spin/sched.c b/sys/src/cmd/spin/sched.c
new file mode 100755
index 000000000..ee5b87403
--- /dev/null
+++ b/sys/src/cmd/spin/sched.c
@@ -0,0 +1,1025 @@
+/***** spin: sched.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include <stdlib.h>
+#include "spin.h"
+#include "y.tab.h"
+
+extern int verbose, s_trail, analyze, no_wrapup;
+extern char *claimproc, *eventmap, Buf[];
+extern Ordered *all_names;
+extern Symbol *Fname, *context;
+extern int lineno, nr_errs, dumptab, xspin, jumpsteps, columns;
+extern int u_sync, Elcnt, interactive, TstOnly, cutoff;
+extern short has_enabled;
+extern int limited_vis;
+
+RunList *X = (RunList *) 0;
+RunList *run = (RunList *) 0;
+RunList *LastX = (RunList *) 0; /* previous executing proc */
+ProcList *rdy = (ProcList *) 0;
+Element *LastStep = ZE;
+int nproc=0, nstop=0, Tval=0;
+int Rvous=0, depth=0, nrRdy=0, MadeChoice;
+short Have_claim=0, Skip_claim=0;
+
+static int Priority_Sum = 0;
+static void setlocals(RunList *);
+static void setparams(RunList *, ProcList *, Lextok *);
+static void talk(RunList *);
+
+void
+runnable(ProcList *p, int weight, int noparams)
+{ RunList *r = (RunList *) emalloc(sizeof(RunList));
+
+ r->n = p->n;
+ r->tn = p->tn;
+ r->pid = nproc++ - nstop + Skip_claim;
+
+ if ((verbose&4) || (verbose&32))
+ printf("Starting %s with pid %d\n", p->n->name, r->pid);
+
+ if (!p->s)
+ fatal("parsing error, no sequence %s", p->n?p->n->name:"--");
+
+ r->pc = huntele(p->s->frst, p->s->frst->status, -1);
+ r->ps = p->s;
+
+ if (p->s->last)
+ p->s->last->status |= ENDSTATE; /* normal end state */
+
+ r->nxt = run;
+ r->prov = p->prov;
+ r->priority = weight;
+ if (noparams) setlocals(r);
+ Priority_Sum += weight;
+ run = r;
+}
+
+ProcList *
+ready(Symbol *n, Lextok *p, Sequence *s, int det, Lextok *prov)
+ /* n=name, p=formals, s=body det=deterministic prov=provided */
+{ ProcList *r = (ProcList *) emalloc(sizeof(ProcList));
+ Lextok *fp, *fpt; int j; extern int Npars;
+
+ r->n = n;
+ r->p = p;
+ r->s = s;
+ r->prov = prov;
+ r->tn = nrRdy++;
+ r->det = (short) det;
+ r->nxt = rdy;
+ rdy = r;
+
+ for (fp = p, j = 0; fp; fp = fp->rgt)
+ for (fpt = fp->lft; fpt; fpt = fpt->rgt)
+ j++; /* count # of parameters */
+ Npars = max(Npars, j);
+
+ return rdy;
+}
+
+int
+find_maxel(Symbol *s)
+{ ProcList *p;
+
+ for (p = rdy; p; p = p->nxt)
+ if (p->n == s)
+ return p->s->maxel++;
+ return Elcnt++;
+}
+
+static void
+formdump(void)
+{ ProcList *p;
+ Lextok *f, *t;
+ int cnt;
+
+ for (p = rdy; p; p = p->nxt)
+ { if (!p->p) continue;
+ cnt = -1;
+ for (f = p->p; f; f = f->rgt) /* types */
+ for (t = f->lft; t; t = t->rgt) /* formals */
+ { if (t->ntyp != ',')
+ t->sym->Nid = cnt--; /* overload Nid */
+ else
+ t->lft->sym->Nid = cnt--;
+ }
+ }
+}
+
+void
+announce(char *w)
+{
+ if (columns)
+ { extern char Buf[];
+ extern int firstrow;
+ firstrow = 1;
+ if (columns == 2)
+ { sprintf(Buf, "%d:%s",
+ run->pid - Have_claim, run->n->name);
+ pstext(run->pid - Have_claim, Buf);
+ } else
+ printf("proc %d = %s\n",
+ run->pid - Have_claim, run->n->name);
+ return;
+ }
+
+ if (dumptab
+ || analyze
+ || s_trail
+ || !(verbose&4))
+ return;
+
+ if (w)
+ printf(" 0: proc - (%s) ", w);
+ else
+ whoruns(1);
+ printf("creates proc %2d (%s)",
+ run->pid - Have_claim,
+ run->n->name);
+ if (run->priority > 1)
+ printf(" priority %d", run->priority);
+ printf("\n");
+}
+
+#ifndef MAXP
+#define MAXP 255 /* matches max nr of processes in verifier */
+#endif
+
+int
+enable(Lextok *m)
+{ ProcList *p;
+ Symbol *s = m->sym; /* proctype name */
+ Lextok *n = m->lft; /* actual parameters */
+
+ if (m->val < 1) m->val = 1; /* minimum priority */
+ for (p = rdy; p; p = p->nxt)
+ if (strcmp(s->name, p->n->name) == 0)
+ { if (nproc-nstop >= MAXP)
+ { printf("spin: too many processes (%d max)\n", MAXP);
+ break;
+ }
+ runnable(p, m->val, 0);
+ announce((char *) 0);
+ setparams(run, p, n);
+ setlocals(run); /* after setparams */
+ return run->pid - Have_claim + Skip_claim; /* effective simu pid */
+ }
+ return 0; /* process not found */
+}
+
+void
+check_param_count(int i, Lextok *m)
+{ ProcList *p;
+ Symbol *s = m->sym; /* proctype name */
+ Lextok *f, *t; /* formal pars */
+ int cnt = 0;
+
+ for (p = rdy; p; p = p->nxt)
+ { if (strcmp(s->name, p->n->name) == 0)
+ { if (m->lft) /* actual param list */
+ { lineno = m->lft->ln;
+ Fname = m->lft->fn;
+ }
+ for (f = p->p; f; f = f->rgt) /* one type at a time */
+ for (t = f->lft; t; t = t->rgt) /* count formal params */
+ { cnt++;
+ }
+ if (i != cnt)
+ { printf("spin: saw %d parameters, expected %d\n", i, cnt);
+ non_fatal("wrong number of parameters", "");
+ }
+ break;
+ } }
+}
+
+void
+start_claim(int n)
+{ ProcList *p;
+ RunList *r, *q = (RunList *) 0;
+
+ for (p = rdy; p; p = p->nxt)
+ if (p->tn == n
+ && strcmp(p->n->name, ":never:") == 0)
+ { runnable(p, 1, 1);
+ goto found;
+ }
+ printf("spin: couldn't find claim (ignored)\n");
+ Skip_claim = 1;
+ goto done;
+found:
+ /* move claim to far end of runlist, and reassign it pid 0 */
+ if (columns == 2)
+ { depth = 0;
+ pstext(0, "0::never:");
+ for (r = run; r; r = r->nxt)
+ { if (!strcmp(r->n->name, ":never:"))
+ continue;
+ sprintf(Buf, "%d:%s",
+ r->pid+1, r->n->name);
+ pstext(r->pid+1, Buf);
+ } }
+
+ if (run->pid == 0) return; /* it is the first process started */
+
+ q = run; run = run->nxt;
+ q->pid = 0; q->nxt = (RunList *) 0; /* remove */
+done:
+ Have_claim = 1;
+ for (r = run; r; r = r->nxt)
+ { r->pid = r->pid+Have_claim; /* adjust */
+ if (!r->nxt)
+ { r->nxt = q;
+ break;
+ } }
+}
+
+int
+f_pid(char *n)
+{ RunList *r;
+ int rval = -1;
+
+ for (r = run; r; r = r->nxt)
+ if (strcmp(n, r->n->name) == 0)
+ { if (rval >= 0)
+ { printf("spin: remote ref to proctype %s, ", n);
+ printf("has more than one match: %d and %d\n",
+ rval, r->pid);
+ } else
+ rval = r->pid;
+ }
+ return rval;
+}
+
+void
+wrapup(int fini)
+{
+ limited_vis = 0;
+ if (columns)
+ { extern void putpostlude(void);
+ if (columns == 2) putpostlude();
+ if (!no_wrapup)
+ printf("-------------\nfinal state:\n-------------\n");
+ }
+ if (no_wrapup)
+ goto short_cut;
+ if (nproc != nstop)
+ { int ov = verbose;
+ printf("#processes: %d\n", nproc-nstop - Have_claim + Skip_claim);
+ verbose &= ~4;
+ dumpglobals();
+ verbose = ov;
+ verbose &= ~1; /* no more globals */
+ verbose |= 32; /* add process states */
+ for (X = run; X; X = X->nxt)
+ talk(X);
+ verbose = ov; /* restore */
+ }
+ printf("%d process%s created\n",
+ nproc - Have_claim + Skip_claim,
+ (xspin || nproc!=1)?"es":"");
+short_cut:
+ if (xspin) alldone(0); /* avoid an abort from xspin */
+ if (fini) alldone(1);
+}
+
+static char is_blocked[256];
+
+static int
+p_blocked(int p)
+{ int i, j;
+
+ is_blocked[p%256] = 1;
+ for (i = j = 0; i < nproc - nstop; i++)
+ j += is_blocked[i];
+ if (j >= nproc - nstop)
+ { memset(is_blocked, 0, 256);
+ return 1;
+ }
+ return 0;
+}
+
+static Element *
+silent_moves(Element *e)
+{ Element *f;
+
+ if (e->n)
+ switch (e->n->ntyp) {
+ case GOTO:
+ if (Rvous) break;
+ f = get_lab(e->n, 1);
+ cross_dsteps(e->n, f->n);
+ return f; /* guard against goto cycles */
+ case UNLESS:
+ return silent_moves(e->sub->this->frst);
+ case NON_ATOMIC:
+ case ATOMIC:
+ case D_STEP:
+ e->n->sl->this->last->nxt = e->nxt;
+ return silent_moves(e->n->sl->this->frst);
+ case '.':
+ return silent_moves(e->nxt);
+ }
+ return e;
+}
+
+static RunList *
+pickproc(RunList *Y)
+{ SeqList *z; Element *has_else;
+ short Choices[256];
+ int j, k, nr_else = 0;
+
+ if (nproc <= nstop+1)
+ { X = run;
+ return NULL;
+ }
+ if (!interactive || depth < jumpsteps)
+ { /* was: j = (int) Rand()%(nproc-nstop); */
+ if (Priority_Sum < nproc-nstop)
+ fatal("cannot happen - weights", (char *)0);
+ j = (int) Rand()%Priority_Sum;
+
+ while (j - X->priority >= 0)
+ { j -= X->priority;
+ Y = X;
+ X = X->nxt;
+ if (!X) { Y = NULL; X = run; }
+ }
+ } else
+ { int only_choice = -1;
+ int no_choice = 0, proc_no_ch, proc_k;
+
+ Tval = 0; /* new 4.2.6 */
+try_again: printf("Select a statement\n");
+try_more: for (X = run, k = 1; X; X = X->nxt)
+ { if (X->pid > 255) break;
+
+ Choices[X->pid] = (short) k;
+
+ if (!X->pc
+ || (X->prov && !eval(X->prov)))
+ { if (X == run)
+ Choices[X->pid] = 0;
+ continue;
+ }
+ X->pc = silent_moves(X->pc);
+ if (!X->pc->sub && X->pc->n)
+ { int unex;
+ unex = !Enabled0(X->pc);
+ if (unex)
+ no_choice++;
+ else
+ only_choice = k;
+ if (!xspin && unex && !(verbose&32))
+ { k++;
+ continue;
+ }
+ printf("\tchoice %d: ", k++);
+ p_talk(X->pc, 0);
+ if (unex)
+ printf(" unexecutable,");
+ printf(" [");
+ comment(stdout, X->pc->n, 0);
+ if (X->pc->esc) printf(" + Escape");
+ printf("]\n");
+ } else {
+ has_else = ZE;
+ proc_no_ch = no_choice;
+ proc_k = k;
+ for (z = X->pc->sub, j=0; z; z = z->nxt)
+ { Element *y = silent_moves(z->this->frst);
+ int unex;
+ if (!y) continue;
+
+ if (y->n->ntyp == ELSE)
+ { has_else = (Rvous)?ZE:y;
+ nr_else = k++;
+ continue;
+ }
+
+ unex = !Enabled0(y);
+ if (unex)
+ no_choice++;
+ else
+ only_choice = k;
+ if (!xspin && unex && !(verbose&32))
+ { k++;
+ continue;
+ }
+ printf("\tchoice %d: ", k++);
+ p_talk(X->pc, 0);
+ if (unex)
+ printf(" unexecutable,");
+ printf(" [");
+ comment(stdout, y->n, 0);
+ printf("]\n");
+ }
+ if (has_else)
+ { if (no_choice-proc_no_ch >= (k-proc_k)-1)
+ { only_choice = nr_else;
+ printf("\tchoice %d: ", nr_else);
+ p_talk(X->pc, 0);
+ printf(" [else]\n");
+ } else
+ { no_choice++;
+ printf("\tchoice %d: ", nr_else);
+ p_talk(X->pc, 0);
+ printf(" unexecutable, [else]\n");
+ } }
+ } }
+ X = run;
+ if (k - no_choice < 2 && Tval == 0)
+ { Tval = 1;
+ no_choice = 0; only_choice = -1;
+ goto try_more;
+ }
+ if (xspin)
+ printf("Make Selection %d\n\n", k-1);
+ else
+ { if (k - no_choice < 2)
+ { printf("no executable choices\n");
+ alldone(0);
+ }
+ printf("Select [1-%d]: ", k-1);
+ }
+ if (!xspin && k - no_choice == 2)
+ { printf("%d\n", only_choice);
+ j = only_choice;
+ } else
+ { char buf[256];
+ fflush(stdout);
+ scanf("%s", buf);
+ j = -1;
+ if (isdigit(buf[0]))
+ j = atoi(buf);
+ else
+ { if (buf[0] == 'q')
+ alldone(0);
+ }
+ if (j < 1 || j >= k)
+ { printf("\tchoice is outside range\n");
+ goto try_again;
+ } }
+ MadeChoice = 0;
+ Y = NULL;
+ for (X = run; X; Y = X, X = X->nxt)
+ { if (!X->nxt
+ || X->nxt->pid > 255
+ || j < Choices[X->nxt->pid])
+ {
+ MadeChoice = 1+j-Choices[X->pid];
+ break;
+ } }
+ }
+ return Y;
+}
+
+void
+sched(void)
+{ Element *e;
+ RunList *Y = NULL; /* previous process in run queue */
+ RunList *oX;
+ int go, notbeyond = 0;
+#ifdef PC
+ int bufmax = 100;
+#endif
+ if (dumptab)
+ { formdump();
+ symdump();
+ dumplabels();
+ return;
+ }
+
+ if (has_enabled && u_sync > 0)
+ { printf("spin: error, cannot use 'enabled()' in ");
+ printf("models with synchronous channels.\n");
+ nr_errs++;
+ }
+ if (analyze)
+ { gensrc();
+ return;
+ } else if (s_trail)
+ { match_trail();
+ return;
+ }
+ if (claimproc)
+ printf("warning: never claim not used in random simulation\n");
+ if (eventmap)
+ printf("warning: trace assertion not used in random simulation\n");
+
+ X = run;
+ Y = pickproc(Y);
+
+ while (X)
+ { context = X->n;
+ if (X->pc && X->pc->n)
+ { lineno = X->pc->n->ln;
+ Fname = X->pc->n->fn;
+ }
+ if (cutoff > 0 && depth >= cutoff)
+ { printf("-------------\n");
+ printf("depth-limit (-u%d steps) reached\n", cutoff);
+ break;
+ }
+#ifdef PC
+ if (xspin && !interactive && --bufmax <= 0)
+ { int c; /* avoid buffer overflow on pc's */
+ printf("spin: type return to proceed\n");
+ fflush(stdout);
+ c = getc(stdin);
+ if (c == 'q') wrapup(0);
+ bufmax = 100;
+ }
+#endif
+ depth++; LastStep = ZE;
+ oX = X; /* a rendezvous could change it */
+ go = 1;
+ if (X && X->prov && X->pc
+ && !(X->pc->status & D_ATOM)
+ && !eval(X->prov))
+ { if (!xspin && ((verbose&32) || (verbose&4)))
+ { p_talk(X->pc, 1);
+ printf("\t<<Not Enabled>>\n");
+ }
+ go = 0;
+ }
+ if (go && (e = eval_sub(X->pc)))
+ { if (depth >= jumpsteps
+ && ((verbose&32) || (verbose&4)))
+ { if (X == oX)
+ if (!(e->status & D_ATOM) || (verbose&32)) /* no talking in d_steps */
+ { p_talk(X->pc, 1);
+ printf(" [");
+ if (!LastStep) LastStep = X->pc;
+ comment(stdout, LastStep->n, 0);
+ printf("]\n");
+ }
+ if (verbose&1) dumpglobals();
+ if (verbose&2) dumplocal(X);
+
+ if (!(e->status & D_ATOM))
+ if (xspin)
+ printf("\n");
+ }
+ if (oX != X)
+ { e = silent_moves(e);
+ notbeyond = 0;
+ }
+ oX->pc = e; LastX = X;
+
+ if (!interactive) Tval = 0;
+ memset(is_blocked, 0, 256);
+
+ if (X->pc && (X->pc->status & (ATOM|L_ATOM))
+ && (notbeyond == 0 || oX != X))
+ { if ((X->pc->status & L_ATOM))
+ notbeyond = 1;
+ continue; /* no process switch */
+ }
+ } else
+ { depth--;
+ if (oX->pc->status & D_ATOM)
+ non_fatal("stmnt in d_step blocks", (char *)0);
+
+ if (X->pc->n->ntyp == '@'
+ && X->pid == (nproc-nstop-1))
+ { if (X != run && Y != NULL)
+ Y->nxt = X->nxt;
+ else
+ run = X->nxt;
+ nstop++;
+ Priority_Sum -= X->priority;
+ if (verbose&4)
+ { whoruns(1);
+ dotag(stdout, "terminates\n");
+ }
+ LastX = X;
+ if (!interactive) Tval = 0;
+ if (nproc == nstop) break;
+ memset(is_blocked, 0, 256);
+ /* proc X is no longer in runlist */
+ X = (X->nxt) ? X->nxt : run;
+ } else
+ { if (p_blocked(X->pid))
+ { if (Tval) break;
+ Tval = 1;
+ if (depth >= jumpsteps)
+ { oX = X;
+ X = (RunList *) 0; /* to suppress indent */
+ dotag(stdout, "timeout\n");
+ X = oX;
+ } } } }
+ Y = pickproc(X);
+ notbeyond = 0;
+ }
+ context = ZS;
+ wrapup(0);
+}
+
+int
+complete_rendez(void)
+{ RunList *orun = X, *tmp;
+ Element *s_was = LastStep;
+ Element *e;
+ int j, ointer = interactive;
+
+ if (s_trail)
+ return 1;
+ if (orun->pc->status & D_ATOM)
+ fatal("rv-attempt in d_step sequence", (char *)0);
+ Rvous = 1;
+ interactive = 0;
+
+ j = (int) Rand()%Priority_Sum; /* randomize start point */
+ X = run;
+ while (j - X->priority >= 0)
+ { j -= X->priority;
+ X = X->nxt;
+ if (!X) X = run;
+ }
+ for (j = nproc - nstop; j > 0; j--)
+ { if (X != orun
+ && (!X->prov || eval(X->prov))
+ && (e = eval_sub(X->pc)))
+ { if (TstOnly)
+ { X = orun;
+ Rvous = 0;
+ goto out;
+ }
+ if ((verbose&32) || (verbose&4))
+ { tmp = orun; orun = X; X = tmp;
+ if (!s_was) s_was = X->pc;
+ p_talk(s_was, 1);
+ printf(" [");
+ comment(stdout, s_was->n, 0);
+ printf("]\n");
+ tmp = orun; orun = X; X = tmp;
+ if (!LastStep) LastStep = X->pc;
+ p_talk(LastStep, 1);
+ printf(" [");
+ comment(stdout, LastStep->n, 0);
+ printf("]\n");
+ }
+ Rvous = 0; /* before silent_moves */
+ X->pc = silent_moves(e);
+out: interactive = ointer;
+ return 1;
+ }
+
+ X = X->nxt;
+ if (!X) X = run;
+ }
+ Rvous = 0;
+ X = orun;
+ interactive = ointer;
+ return 0;
+}
+
+/***** Runtime - Local Variables *****/
+
+static void
+addsymbol(RunList *r, Symbol *s)
+{ Symbol *t;
+ int i;
+
+ for (t = r->symtab; t; t = t->next)
+ if (strcmp(t->name, s->name) == 0)
+ return; /* it's already there */
+
+ t = (Symbol *) emalloc(sizeof(Symbol));
+ t->name = s->name;
+ t->type = s->type;
+ t->hidden = s->hidden;
+ t->nbits = s->nbits;
+ t->nel = s->nel;
+ t->ini = s->ini;
+ t->setat = depth;
+ t->context = r->n;
+ if (s->type != STRUCT)
+ { if (s->val) /* if already initialized, copy info */
+ { t->val = (int *) emalloc(s->nel*sizeof(int));
+ for (i = 0; i < s->nel; i++)
+ t->val[i] = s->val[i];
+ } else
+ (void) checkvar(t, 0); /* initialize it */
+ } else
+ { if (s->Sval)
+ fatal("saw preinitialized struct %s", s->name);
+ t->Slst = s->Slst;
+ t->Snm = s->Snm;
+ t->owner = s->owner;
+ /* t->context = r->n; */
+ }
+ t->next = r->symtab; /* add it */
+ r->symtab = t;
+}
+
+static void
+setlocals(RunList *r)
+{ Ordered *walk;
+ Symbol *sp;
+ RunList *oX = X;
+
+ X = r;
+ for (walk = all_names; walk; walk = walk->next)
+ { sp = walk->entry;
+ if (sp
+ && sp->context
+ && strcmp(sp->context->name, r->n->name) == 0
+ && sp->Nid >= 0
+ && (sp->type == UNSIGNED
+ || sp->type == BIT
+ || sp->type == MTYPE
+ || sp->type == BYTE
+ || sp->type == CHAN
+ || sp->type == SHORT
+ || sp->type == INT
+ || sp->type == STRUCT))
+ { if (!findloc(sp))
+ non_fatal("setlocals: cannot happen '%s'",
+ sp->name);
+ }
+ }
+ X = oX;
+}
+
+static void
+oneparam(RunList *r, Lextok *t, Lextok *a, ProcList *p)
+{ int k; int at, ft;
+ RunList *oX = X;
+
+ if (!a)
+ fatal("missing actual parameters: '%s'", p->n->name);
+ if (t->sym->nel != 1)
+ fatal("array in parameter list, %s", t->sym->name);
+ k = eval(a->lft);
+
+ at = Sym_typ(a->lft);
+ X = r; /* switch context */
+ ft = Sym_typ(t);
+
+ if (at != ft && (at == CHAN || ft == CHAN))
+ { char buf[128], tag1[64], tag2[64];
+ (void) sputtype(tag1, ft);
+ (void) sputtype(tag2, at);
+ sprintf(buf, "type-clash in params of %s(..), (%s<-> %s)",
+ p->n->name, tag1, tag2);
+ non_fatal("%s", buf);
+ }
+ t->ntyp = NAME;
+ addsymbol(r, t->sym);
+ (void) setval(t, k);
+
+ X = oX;
+}
+
+static void
+setparams(RunList *r, ProcList *p, Lextok *q)
+{ Lextok *f, *a; /* formal and actual pars */
+ Lextok *t; /* list of pars of 1 type */
+
+ if (q)
+ { lineno = q->ln;
+ Fname = q->fn;
+ }
+ for (f = p->p, a = q; f; f = f->rgt) /* one type at a time */
+ for (t = f->lft; t; t = t->rgt, a = (a)?a->rgt:a)
+ { if (t->ntyp != ',')
+ oneparam(r, t, a, p); /* plain var */
+ else
+ oneparam(r, t->lft, a, p); /* expanded struct */
+ }
+}
+
+Symbol *
+findloc(Symbol *s)
+{ Symbol *r;
+
+ if (!X)
+ { /* fatal("error, cannot eval '%s' (no proc)", s->name); */
+ return ZS;
+ }
+ for (r = X->symtab; r; r = r->next)
+ if (strcmp(r->name, s->name) == 0)
+ break;
+ if (!r)
+ { addsymbol(X, s);
+ r = X->symtab;
+ }
+ return r;
+}
+
+int
+in_bound(Symbol *r, int n)
+{
+ if (!r) return 0;
+
+ if (n >= r->nel || n < 0)
+ { printf("spin: indexing %s[%d] - size is %d\n",
+ r->name, n, r->nel);
+ non_fatal("indexing array \'%s\'", r->name);
+ return 0;
+ }
+ return 1;
+}
+
+int
+getlocal(Lextok *sn)
+{ Symbol *r, *s = sn->sym;
+ int n = eval(sn->lft);
+
+ r = findloc(s);
+ if (r && r->type == STRUCT)
+ return Rval_struct(sn, r, 1); /* 1 = check init */
+ if (in_bound(r, n))
+ return cast_val(r->type, r->val[n], r->nbits);
+ return 0;
+}
+
+int
+setlocal(Lextok *p, int m)
+{ Symbol *r = findloc(p->sym);
+ int n = eval(p->lft);
+
+ if (in_bound(r, n))
+ { if (r->type == STRUCT)
+ (void) Lval_struct(p, r, 1, m); /* 1 = check init */
+ else
+ {
+#if 0
+ if (r->nbits > 0)
+ m = (m & ((1<<r->nbits)-1));
+ r->val[n] = m;
+#else
+ r->val[n] = cast_val(r->type, m, r->nbits);
+#endif
+ r->setat = depth;
+ } }
+
+ return 1;
+}
+
+void
+whoruns(int lnr)
+{ if (!X) return;
+
+ if (lnr) printf("%3d: ", depth);
+ printf("proc ");
+ if (Have_claim && X->pid == 0)
+ printf(" -");
+ else
+ printf("%2d", X->pid - Have_claim);
+ printf(" (%s) ", X->n->name);
+}
+
+static void
+talk(RunList *r)
+{
+ if ((verbose&32) || (verbose&4))
+ { p_talk(r->pc, 1);
+ printf("\n");
+ if (verbose&1) dumpglobals();
+ if (verbose&2) dumplocal(r);
+ }
+}
+
+void
+p_talk(Element *e, int lnr)
+{ static int lastnever = -1;
+ int newnever = -1;
+
+ if (e && e->n)
+ newnever = e->n->ln;
+
+ if (Have_claim && X && X->pid == 0
+ && lastnever != newnever && e)
+ { if (xspin)
+ { printf("MSC: ~G line %d\n", newnever);
+#if 0
+ printf("%3d: proc - (NEVER) line %d \"never\" ",
+ depth, newnever);
+ printf("(state 0)\t[printf('MSC: never\\\\n')]\n");
+ } else
+ { printf("%3d: proc - (NEVER) line %d \"never\"\n",
+ depth, newnever);
+#endif
+ }
+ lastnever = newnever;
+ }
+
+ whoruns(lnr);
+ if (e)
+ { printf("line %3d %s (state %d)",
+ e->n?e->n->ln:-1,
+ e->n?e->n->fn->name:"-",
+ e->seqno);
+ if (!xspin
+ && ((e->status&ENDSTATE) || has_lab(e, 2))) /* 2=end */
+ { printf(" <valid end state>");
+ }
+ }
+}
+
+int
+remotelab(Lextok *n)
+{ int i;
+
+ lineno = n->ln;
+ Fname = n->fn;
+ if (n->sym->type != 0 && n->sym->type != LABEL)
+ { printf("spin: error, type: %d\n", n->sym->type);
+ fatal("not a labelname: '%s'", n->sym->name);
+ }
+ if (n->indstep >= 0)
+ { fatal("remote ref to label '%s' inside d_step",
+ n->sym->name);
+ }
+ if ((i = find_lab(n->sym, n->lft->sym, 1)) == 0)
+ fatal("unknown labelname: %s", n->sym->name);
+ return i;
+}
+
+int
+remotevar(Lextok *n)
+{ int prno, i, added=0;
+ RunList *Y, *oX;
+ Lextok *onl;
+ Symbol *os;
+
+ lineno = n->ln;
+ Fname = n->fn;
+
+ if (!n->lft->lft)
+ prno = f_pid(n->lft->sym->name);
+ else
+ { prno = eval(n->lft->lft); /* pid - can cause recursive call */
+#if 0
+ if (n->lft->lft->ntyp == CONST) /* user-guessed pid */
+#endif
+ { prno += Have_claim;
+ added = Have_claim;
+ } }
+
+ if (prno < 0)
+ return 0; /* non-existing process */
+#if 0
+ i = nproc - nstop;
+ for (Y = run; Y; Y = Y->nxt)
+ { --i;
+ printf(" %s: i=%d, prno=%d, ->pid=%d\n", Y->n->name, i, prno, Y->pid);
+ }
+#endif
+ i = nproc - nstop;
+ for (Y = run; Y; Y = Y->nxt)
+ if (--i == prno)
+ { if (strcmp(Y->n->name, n->lft->sym->name) != 0)
+ { printf("spin: remote reference error on '%s[%d]'\n",
+ n->lft->sym->name, prno-added);
+ non_fatal("refers to wrong proctype '%s'", Y->n->name);
+ }
+ if (strcmp(n->sym->name, "_p") == 0)
+ { if (Y->pc)
+ return Y->pc->seqno;
+ /* harmless, can only happen with -t */
+ return 0;
+ }
+#if 1
+ /* new 4.0 allow remote variables */
+ oX = X;
+ X = Y;
+
+ onl = n->lft;
+ n->lft = n->rgt;
+
+ os = n->sym;
+ n->sym = findloc(n->sym);
+
+ i = getval(n);
+
+ n->sym = os;
+ n->lft = onl;
+ X = oX;
+ return i;
+#else
+ break;
+#endif
+ }
+ printf("remote ref: %s[%d] ", n->lft->sym->name, prno-added);
+ non_fatal("%s not found", n->sym->name);
+ printf("have only:\n");
+ i = nproc - nstop - 1;
+ for (Y = run; Y; Y = Y->nxt, i--)
+ if (!strcmp(Y->n->name, n->lft->sym->name))
+ printf("\t%d\t%s\n", i, Y->n->name);
+
+ return 0;
+}
diff --git a/sys/src/cmd/spin/spin.h b/sys/src/cmd/spin/spin.h
new file mode 100755
index 000000000..327ec6871
--- /dev/null
+++ b/sys/src/cmd/spin/spin.h
@@ -0,0 +1,399 @@
+/***** spin: spin.h *****/
+
+/* Copyright (c) 1989-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 */
+
+#ifndef SEEN_SPIN_H
+#define SEEN_SPIN_H
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+typedef struct Lextok {
+ unsigned short ntyp; /* node type */
+ short ismtyp; /* CONST derived from MTYP */
+ int val; /* value attribute */
+ int ln; /* line number */
+ int indstep; /* part of d_step sequence */
+ struct Symbol *fn; /* file name */
+ struct Symbol *sym; /* symbol reference */
+ struct Sequence *sq; /* sequence */
+ struct SeqList *sl; /* sequence list */
+ struct Lextok *lft, *rgt; /* children in parse tree */
+} Lextok;
+
+typedef struct Slicer {
+ Lextok *n; /* global var, usable as slice criterion */
+ short code; /* type of use: DEREF_USE or normal USE */
+ short used; /* set when handled */
+ struct Slicer *nxt; /* linked list */
+} Slicer;
+
+typedef struct Access {
+ struct Symbol *who; /* proctype name of accessor */
+ struct Symbol *what; /* proctype name of accessed */
+ int cnt, typ; /* parameter nr and, e.g., 's' or 'r' */
+ struct Access *lnk; /* linked list */
+} Access;
+
+typedef struct Symbol {
+ char *name;
+ int Nid; /* unique number for the name */
+ unsigned short type; /* bit,short,.., chan,struct */
+ unsigned char hidden; /* bit-flags:
+ 1=hide, 2=show,
+ 4=bit-equiv, 8=byte-equiv,
+ 16=formal par, 32=inline par,
+ 64=treat as if local; 128=read at least once
+ */
+ unsigned char colnr; /* for use with xspin during simulation */
+ int nbits; /* optional width specifier */
+ int nel; /* 1 if scalar, >1 if array */
+ int setat; /* last depth value changed */
+ int *val; /* runtime value(s), initl 0 */
+ Lextok **Sval; /* values for structures */
+
+ int xu; /* exclusive r or w by 1 pid */
+ struct Symbol *xup[2]; /* xr or xs proctype */
+ struct Access *access;/* e.g., senders and receives of chan */
+ Lextok *ini; /* initial value, or chan-def */
+ Lextok *Slst; /* template for structure if struct */
+ struct Symbol *Snm; /* name of the defining struct */
+ struct Symbol *owner; /* set for names of subfields in typedefs */
+ struct Symbol *context; /* 0 if global, or procname */
+ struct Symbol *next; /* linked list */
+} Symbol;
+
+typedef struct Ordered { /* links all names in Symbol table */
+ struct Symbol *entry;
+ struct Ordered *next;
+} Ordered;
+
+typedef struct Queue {
+ short qid; /* runtime q index */
+ int qlen; /* nr messages stored */
+ int nslots, nflds; /* capacity, flds/slot */
+ int setat; /* last depth value changed */
+ int *fld_width; /* type of each field */
+ int *contents; /* the values stored */
+ int *stepnr; /* depth when each msg was sent */
+ struct Queue *nxt; /* linked list */
+} Queue;
+
+typedef struct FSM_state { /* used in pangen5.c - dataflow */
+ int from; /* state number */
+ int seen; /* used for dfs */
+ int in; /* nr of incoming edges */
+ int cr; /* has reachable 1-relevant successor */
+ int scratch;
+ unsigned long *dom, *mod; /* to mark dominant nodes */
+ struct FSM_trans *t; /* outgoing edges */
+ struct FSM_trans *p; /* incoming edges, predecessors */
+ struct FSM_state *nxt; /* linked list of all states */
+} FSM_state;
+
+typedef struct FSM_trans { /* used in pangen5.c - dataflow */
+ int to;
+ short relevant; /* when sliced */
+ short round; /* ditto: iteration when marked */
+ struct FSM_use *Val[2]; /* 0=reads, 1=writes */
+ struct Element *step;
+ struct FSM_trans *nxt;
+} FSM_trans;
+
+typedef struct FSM_use { /* used in pangen5.c - dataflow */
+ Lextok *n;
+ Symbol *var;
+ int special;
+ struct FSM_use *nxt;
+} FSM_use;
+
+typedef struct Element {
+ Lextok *n; /* defines the type & contents */
+ int Seqno; /* identifies this el within system */
+ int seqno; /* identifies this el within a proc */
+ int merge; /* set by -O if step can be merged */
+ int merge_start;
+ int merge_single;
+ short merge_in; /* nr of incoming edges */
+ short merge_mark; /* state was generated in merge sequence */
+ unsigned char status; /* used by analyzer generator */
+ struct FSM_use *dead; /* optional dead variable list */
+ struct SeqList *sub; /* subsequences, for compounds */
+ struct SeqList *esc; /* zero or more escape sequences */
+ struct Element *Nxt; /* linked list - for global lookup */
+ struct Element *nxt; /* linked list - program structure */
+} Element;
+
+typedef struct Sequence {
+ Element *frst;
+ Element *last; /* links onto continuations */
+ Element *extent; /* last element in original */
+ int maxel; /* 1+largest id in sequence */
+} Sequence;
+
+typedef struct SeqList {
+ Sequence *this; /* one sequence */
+ struct SeqList *nxt; /* linked list */
+} SeqList;
+
+typedef struct Label {
+ Symbol *s;
+ Symbol *c;
+ Element *e;
+ int visible; /* label referenced in claim (slice relevant) */
+ struct Label *nxt;
+} Label;
+
+typedef struct Lbreak {
+ Symbol *l;
+ struct Lbreak *nxt;
+} Lbreak;
+
+typedef struct RunList {
+ Symbol *n; /* name */
+ int tn; /* ordinal of type */
+ int pid; /* process id */
+ int priority; /* for simulations only */
+ Element *pc; /* current stmnt */
+ Sequence *ps; /* used by analyzer generator */
+ Lextok *prov; /* provided clause */
+ Symbol *symtab; /* local variables */
+ struct RunList *nxt; /* linked list */
+} RunList;
+
+typedef struct ProcList {
+ Symbol *n; /* name */
+ Lextok *p; /* parameters */
+ Sequence *s; /* body */
+ Lextok *prov; /* provided clause */
+ short tn; /* ordinal number */
+ short det; /* deterministic */
+ struct ProcList *nxt; /* linked list */
+} ProcList;
+
+typedef Lextok *Lexptr;
+
+#define YYSTYPE Lexptr
+
+#define ZN (Lextok *)0
+#define ZS (Symbol *)0
+#define ZE (Element *)0
+
+#define DONE 1 /* status bits of elements */
+#define ATOM 2 /* part of an atomic chain */
+#define L_ATOM 4 /* last element in a chain */
+#define I_GLOB 8 /* inherited global ref */
+#define DONE2 16 /* used in putcode and main*/
+#define D_ATOM 32 /* deterministic atomic */
+#define ENDSTATE 64 /* normal endstate */
+#define CHECK2 128
+
+#define Nhash 255 /* slots in symbol hash-table */
+
+#define XR 1 /* non-shared receive-only */
+#define XS 2 /* non-shared send-only */
+#define XX 4 /* overrides XR or XS tag */
+
+#define CODE_FRAG 2 /* auto-numbered code-fragment */
+#define CODE_DECL 4 /* auto-numbered c_decl */
+#define PREDEF 3 /* predefined name: _p, _last */
+
+#define UNSIGNED 5 /* val defines width in bits */
+#define BIT 1 /* also equal to width in bits */
+#define BYTE 8 /* ditto */
+#define SHORT 16 /* ditto */
+#define INT 32 /* ditto */
+#define CHAN 64 /* not */
+#define STRUCT 128 /* user defined structure name */
+
+#define SOMETHINGBIG 65536
+#define RATHERSMALL 512
+
+#ifndef max
+#define max(a,b) (((a)<(b)) ? (b) : (a))
+#endif
+
+enum { INIV, PUTV, LOGV }; /* for pangen[14].c */
+
+/***** prototype definitions *****/
+Element *eval_sub(Element *);
+Element *get_lab(Lextok *, int);
+Element *huntele(Element *, int, int);
+Element *huntstart(Element *);
+Element *target(Element *);
+
+Lextok *do_unless(Lextok *, Lextok *);
+Lextok *expand(Lextok *, int);
+Lextok *getuname(Symbol *);
+Lextok *mk_explicit(Lextok *, int, int);
+Lextok *nn(Lextok *, int, Lextok *, Lextok *);
+Lextok *rem_lab(Symbol *, Lextok *, Symbol *);
+Lextok *rem_var(Symbol *, Lextok *, Symbol *, Lextok *);
+Lextok *tail_add(Lextok *, Lextok *);
+
+ProcList *ready(Symbol *, Lextok *, Sequence *, int, Lextok *);
+
+SeqList *seqlist(Sequence *, SeqList *);
+Sequence *close_seq(int);
+
+Symbol *break_dest(void);
+Symbol *findloc(Symbol *);
+Symbol *has_lab(Element *, int);
+Symbol *lookup(char *);
+Symbol *prep_inline(Symbol *, Lextok *);
+
+char *emalloc(int);
+long Rand(void);
+
+int any_oper(Lextok *, int);
+int any_undo(Lextok *);
+int c_add_sv(FILE *);
+int cast_val(int, int, int);
+int checkvar(Symbol *, int);
+int Cnt_flds(Lextok *);
+int cnt_mpars(Lextok *);
+int complete_rendez(void);
+int enable(Lextok *);
+int Enabled0(Element *);
+int eval(Lextok *);
+int find_lab(Symbol *, Symbol *, int);
+int find_maxel(Symbol *);
+int full_name(FILE *, Lextok *, Symbol *, int);
+int getlocal(Lextok *);
+int getval(Lextok *);
+int glob_inline(char *);
+int has_typ(Lextok *, int);
+int in_bound(Symbol *, int);
+int interprint(FILE *, Lextok *);
+int printm(FILE *, Lextok *);
+int ismtype(char *);
+int isproctype(char *);
+int isutype(char *);
+int Lval_struct(Lextok *, Symbol *, int, int);
+int main(int, char **);
+int pc_value(Lextok *);
+int proper_enabler(Lextok *);
+int putcode(FILE *, Sequence *, Element *, int, int, int);
+int q_is_sync(Lextok *);
+int qlen(Lextok *);
+int qfull(Lextok *);
+int qmake(Symbol *);
+int qrecv(Lextok *, int);
+int qsend(Lextok *);
+int remotelab(Lextok *);
+int remotevar(Lextok *);
+int Rval_struct(Lextok *, Symbol *, int);
+int setlocal(Lextok *, int);
+int setval(Lextok *, int);
+int sputtype(char *, int);
+int Sym_typ(Lextok *);
+int tl_main(int, char *[]);
+int Width_set(int *, int, Lextok *);
+int yyparse(void);
+int yywrap(void);
+int yylex(void);
+
+void AST_track(Lextok *, int);
+void add_seq(Lextok *);
+void alldone(int);
+void announce(char *);
+void c_state(Symbol *, Symbol *, Symbol *);
+void c_add_def(FILE *);
+void c_add_loc(FILE *, char *);
+void c_add_locinit(FILE *, int, char *);
+void c_add_use(FILE *);
+void c_chandump(FILE *);
+void c_preview(void);
+void c_struct(FILE *, char *, Symbol *);
+void c_track(Symbol *, Symbol *, Symbol *);
+void c_var(FILE *, char *, Symbol *);
+void c_wrapper(FILE *);
+void chanaccess(void);
+void check_param_count(int, Lextok *);
+void checkrun(Symbol *, int);
+void comment(FILE *, Lextok *, int);
+void cross_dsteps(Lextok *, Lextok *);
+void doq(Symbol *, int, RunList *);
+void dotag(FILE *, char *);
+void do_locinits(FILE *);
+void do_var(FILE *, int, char *, Symbol *, char *, char *, char *);
+void dump_struct(Symbol *, char *, RunList *);
+void dumpclaims(FILE *, int, char *);
+void dumpglobals(void);
+void dumplabels(void);
+void dumplocal(RunList *);
+void dumpsrc(int, int);
+void fatal(char *, char *);
+void fix_dest(Symbol *, Symbol *);
+void genaddproc(void);
+void genaddqueue(void);
+void gencodetable(FILE *);
+void genheader(void);
+void genother(void);
+void gensrc(void);
+void gensvmap(void);
+void genunio(void);
+void ini_struct(Symbol *);
+void loose_ends(void);
+void make_atomic(Sequence *, int);
+void match_trail(void);
+void no_side_effects(char *);
+void nochan_manip(Lextok *, Lextok *, int);
+void non_fatal(char *, char *);
+void ntimes(FILE *, int, int, char *c[]);
+void open_seq(int);
+void p_talk(Element *, int);
+void pickup_inline(Symbol *, Lextok *);
+void plunk_c_decls(FILE *);
+void plunk_c_fcts(FILE *);
+void plunk_expr(FILE *, char *);
+void plunk_inline(FILE *, char *, int);
+void prehint(Symbol *);
+void preruse(FILE *, Lextok *);
+void prune_opts(Lextok *);
+void pstext(int, char *);
+void pushbreak(void);
+void putname(FILE *, char *, Lextok *, int, char *);
+void putremote(FILE *, Lextok *, int);
+void putskip(int);
+void putsrc(Element *);
+void putstmnt(FILE *, Lextok *, int);
+void putunames(FILE *);
+void rem_Seq(void);
+void runnable(ProcList *, int, int);
+void sched(void);
+void setaccess(Symbol *, Symbol *, int, int);
+void set_lab(Symbol *, Element *);
+void setmtype(Lextok *);
+void setpname(Lextok *);
+void setptype(Lextok *, int, Lextok *);
+void setuname(Lextok *);
+void setutype(Lextok *, Symbol *, Lextok *);
+void setxus(Lextok *, int);
+void Srand(unsigned);
+void start_claim(int);
+void struct_name(Lextok *, Symbol *, int, char *);
+void symdump(void);
+void symvar(Symbol *);
+void trackchanuse(Lextok *, Lextok *, int);
+void trackvar(Lextok *, Lextok *);
+void trackrun(Lextok *);
+void trapwonly(Lextok *, char *); /* spin.y and main.c */
+void typ2c(Symbol *);
+void typ_ck(int, int, char *);
+void undostmnt(Lextok *, int);
+void unrem_Seq(void);
+void unskip(int);
+void varcheck(Element *, Element *);
+void whoruns(int);
+void wrapup(int);
+void yyerror(char *, ...);
+#endif
diff --git a/sys/src/cmd/spin/spin.y b/sys/src/cmd/spin/spin.y
new file mode 100755
index 000000000..20c391a89
--- /dev/null
+++ b/sys/src/cmd/spin/spin.y
@@ -0,0 +1,722 @@
+/***** spin: spin.y *****/
+
+/* Copyright (c) 1989-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 */
+
+%{
+#include "spin.h"
+#include <stdarg.h>
+
+#define YYDEBUG 0
+#define Stop nn(ZN,'@',ZN,ZN)
+
+extern Symbol *context, *owner;
+extern int u_sync, u_async, dumptab;
+extern short has_sorted, has_random, has_enabled, has_pcvalue, has_np;
+extern short has_code, has_state, has_io;
+extern void count_runs(Lextok *);
+extern void no_internals(Lextok *);
+extern void any_runs(Lextok *);
+extern void validref(Lextok *, Lextok *);
+extern char yytext[];
+
+int Mpars = 0; /* max nr of message parameters */
+int runsafe = 1; /* 1 if all run stmnts are in init */
+int Expand_Ok = 0, realread = 1, IArgs = 0, NamesNotAdded = 0;
+char *claimproc = (char *) 0;
+char *eventmap = (char *) 0;
+
+static int Embedded = 0, inEventMap = 0, has_ini = 0;
+
+%}
+
+%token ASSERT PRINT PRINTM
+%token C_CODE C_DECL C_EXPR C_STATE C_TRACK
+%token RUN LEN ENABLED EVAL PC_VAL
+%token TYPEDEF MTYPE INLINE LABEL OF
+%token GOTO BREAK ELSE SEMI
+%token IF FI DO OD SEP
+%token ATOMIC NON_ATOMIC D_STEP UNLESS
+%token TIMEOUT NONPROGRESS
+%token ACTIVE PROCTYPE D_PROCTYPE
+%token HIDDEN SHOW ISLOCAL
+%token PRIORITY PROVIDED
+%token FULL EMPTY NFULL NEMPTY
+%token CONST TYPE XU /* val */
+%token NAME UNAME PNAME INAME /* sym */
+%token STRING CLAIM TRACE INIT /* sym */
+
+%right ASGN
+%left SND O_SND RCV R_RCV /* SND doubles as boolean negation */
+%left OR
+%left AND
+%left '|'
+%left '^'
+%left '&'
+%left EQ NE
+%left GT LT GE LE
+%left LSHIFT RSHIFT
+%left '+' '-'
+%left '*' '/' '%'
+%left INCR DECR
+%right '~' UMIN NEG
+%left DOT
+%%
+
+/** PROMELA Grammar Rules **/
+
+program : units { yytext[0] = '\0'; }
+ ;
+
+units : unit
+ | units unit
+ ;
+
+unit : proc /* proctype { } */
+ | init /* init { } */
+ | claim /* never claim */
+ | events /* event assertions */
+ | one_decl /* variables, chans */
+ | utype /* user defined types */
+ | c_fcts /* c functions etc. */
+ | ns /* named sequence */
+ | SEMI /* optional separator */
+ | error
+ ;
+
+proc : inst /* optional instantiator */
+ proctype NAME {
+ setptype($3, PROCTYPE, ZN);
+ setpname($3);
+ context = $3->sym;
+ context->ini = $2; /* linenr and file */
+ Expand_Ok++; /* expand struct names in decl */
+ has_ini = 0;
+ }
+ '(' decl ')' { Expand_Ok--;
+ if (has_ini)
+ fatal("initializer in parameter list", (char *) 0);
+ }
+ Opt_priority
+ Opt_enabler
+ body { ProcList *rl;
+ rl = ready($3->sym, $6, $11->sq, $2->val, $10);
+ if ($1 != ZN && $1->val > 0)
+ { int j;
+ for (j = 0; j < $1->val; j++)
+ runnable(rl, $9?$9->val:1, 1);
+ announce(":root:");
+ if (dumptab) $3->sym->ini = $1;
+ }
+ context = ZS;
+ }
+ ;
+
+proctype: PROCTYPE { $$ = nn(ZN,CONST,ZN,ZN); $$->val = 0; }
+ | D_PROCTYPE { $$ = nn(ZN,CONST,ZN,ZN); $$->val = 1; }
+ ;
+
+inst : /* empty */ { $$ = ZN; }
+ | ACTIVE { $$ = nn(ZN,CONST,ZN,ZN); $$->val = 1; }
+ | ACTIVE '[' CONST ']' {
+ $$ = nn(ZN,CONST,ZN,ZN); $$->val = $3->val;
+ if ($3->val > 255)
+ non_fatal("max nr of processes is 255\n", "");
+ }
+ | ACTIVE '[' NAME ']' {
+ $$ = nn(ZN,CONST,ZN,ZN);
+ $$->val = 0;
+ if (!$3->sym->type)
+ non_fatal("undeclared variable %s",
+ $3->sym->name);
+ else if ($3->sym->ini->ntyp != CONST)
+ non_fatal("need constant initializer for %s\n",
+ $3->sym->name);
+ else
+ $$->val = $3->sym->ini->val;
+ }
+ ;
+
+init : INIT { context = $1->sym; }
+ Opt_priority
+ body { ProcList *rl;
+ rl = ready(context, ZN, $4->sq, 0, ZN);
+ runnable(rl, $3?$3->val:1, 1);
+ announce(":root:");
+ context = ZS;
+ }
+ ;
+
+claim : CLAIM { context = $1->sym;
+ if (claimproc)
+ non_fatal("claim %s redefined", claimproc);
+ claimproc = $1->sym->name;
+ }
+ body { (void) ready($1->sym, ZN, $3->sq, 0, ZN);
+ context = ZS;
+ }
+ ;
+
+events : TRACE { context = $1->sym;
+ if (eventmap)
+ non_fatal("trace %s redefined", eventmap);
+ eventmap = $1->sym->name;
+ inEventMap++;
+ }
+ body { (void) ready($1->sym, ZN, $3->sq, 0, ZN);
+ context = ZS;
+ inEventMap--;
+ }
+ ;
+
+utype : TYPEDEF NAME { if (context)
+ fatal("typedef %s must be global",
+ $2->sym->name);
+ owner = $2->sym;
+ }
+ '{' decl_lst '}' { setuname($5); owner = ZS; }
+ ;
+
+nm : NAME { $$ = $1; }
+ | INAME { $$ = $1;
+ if (IArgs)
+ fatal("invalid use of '%s'", $1->sym->name);
+ }
+ ;
+
+ns : INLINE nm '(' { NamesNotAdded++; }
+ args ')' { prep_inline($2->sym, $5);
+ NamesNotAdded--;
+ }
+ ;
+
+c_fcts : ccode { /* leaves pseudo-inlines with sym of
+ * type CODE_FRAG or CODE_DECL in global context
+ */
+ }
+ | cstate
+ ;
+
+cstate : C_STATE STRING STRING {
+ c_state($2->sym, $3->sym, ZS);
+ has_code = has_state = 1;
+ }
+ | C_TRACK STRING STRING {
+ c_track($2->sym, $3->sym, ZS);
+ has_code = has_state = 1;
+ }
+ | C_STATE STRING STRING STRING {
+ c_state($2->sym, $3->sym, $4->sym);
+ has_code = has_state = 1;
+ }
+ | C_TRACK STRING STRING STRING {
+ c_track($2->sym, $3->sym, $4->sym);
+ has_code = has_state = 1;
+ }
+ ;
+
+ccode : C_CODE { Symbol *s;
+ NamesNotAdded++;
+ s = prep_inline(ZS, ZN);
+ NamesNotAdded--;
+ $$ = nn(ZN, C_CODE, ZN, ZN);
+ $$->sym = s;
+ has_code = 1;
+ }
+ | C_DECL { Symbol *s;
+ NamesNotAdded++;
+ s = prep_inline(ZS, ZN);
+ NamesNotAdded--;
+ s->type = CODE_DECL;
+ $$ = nn(ZN, C_CODE, ZN, ZN);
+ $$->sym = s;
+ has_code = 1;
+ }
+ ;
+cexpr : C_EXPR { Symbol *s;
+ NamesNotAdded++;
+ s = prep_inline(ZS, ZN);
+ NamesNotAdded--;
+ $$ = nn(ZN, C_EXPR, ZN, ZN);
+ $$->sym = s;
+ no_side_effects(s->name);
+ has_code = 1;
+ }
+ ;
+
+body : '{' { open_seq(1); }
+ sequence OS { add_seq(Stop); }
+ '}' { $$->sq = close_seq(0); }
+ ;
+
+sequence: step { if ($1) add_seq($1); }
+ | sequence MS step { if ($3) add_seq($3); }
+ ;
+
+step : one_decl { $$ = ZN; }
+ | XU vref_lst { setxus($2, $1->val); $$ = ZN; }
+ | NAME ':' one_decl { fatal("label preceding declaration,", (char *)0); }
+ | NAME ':' XU { fatal("label predecing xr/xs claim,", 0); }
+ | stmnt { $$ = $1; }
+ | stmnt UNLESS stmnt { $$ = do_unless($1, $3); }
+ ;
+
+vis : /* empty */ { $$ = ZN; }
+ | HIDDEN { $$ = $1; }
+ | SHOW { $$ = $1; }
+ | ISLOCAL { $$ = $1; }
+ ;
+
+asgn: /* empty */
+ | ASGN
+ ;
+
+one_decl: vis TYPE var_list { setptype($3, $2->val, $1); $$ = $3; }
+ | vis UNAME var_list { setutype($3, $2->sym, $1);
+ $$ = expand($3, Expand_Ok);
+ }
+ | vis TYPE asgn '{' nlst '}' {
+ if ($2->val != MTYPE)
+ fatal("malformed declaration", 0);
+ setmtype($5);
+ if ($1)
+ non_fatal("cannot %s mtype (ignored)",
+ $1->sym->name);
+ if (context != ZS)
+ fatal("mtype declaration must be global", 0);
+ }
+ ;
+
+decl_lst: one_decl { $$ = nn(ZN, ',', $1, ZN); }
+ | one_decl SEMI
+ decl_lst { $$ = nn(ZN, ',', $1, $3); }
+ ;
+
+decl : /* empty */ { $$ = ZN; }
+ | decl_lst { $$ = $1; }
+ ;
+
+vref_lst: varref { $$ = nn($1, XU, $1, ZN); }
+ | varref ',' vref_lst { $$ = nn($1, XU, $1, $3); }
+ ;
+
+var_list: ivar { $$ = nn($1, TYPE, ZN, ZN); }
+ | ivar ',' var_list { $$ = nn($1, TYPE, ZN, $3); }
+ ;
+
+ivar : vardcl { $$ = $1;
+ $1->sym->ini = nn(ZN,CONST,ZN,ZN);
+ $1->sym->ini->val = 0;
+ }
+ | vardcl ASGN expr { $1->sym->ini = $3; $$ = $1;
+ trackvar($1,$3); has_ini = 1;
+ }
+ | vardcl ASGN ch_init { $1->sym->ini = $3;
+ $$ = $1; has_ini = 1;
+ }
+ ;
+
+ch_init : '[' CONST ']' OF
+ '{' typ_list '}' { if ($2->val) u_async++;
+ else u_sync++;
+ { int i = cnt_mpars($6);
+ Mpars = max(Mpars, i);
+ }
+ $$ = nn(ZN, CHAN, ZN, $6);
+ $$->val = $2->val;
+ }
+ ;
+
+vardcl : NAME { $1->sym->nel = 1; $$ = $1; }
+ | NAME ':' CONST { $1->sym->nbits = $3->val;
+ if ($3->val >= 8*sizeof(long))
+ { non_fatal("width-field %s too large",
+ $1->sym->name);
+ $3->val = 8*sizeof(long)-1;
+ }
+ $1->sym->nel = 1; $$ = $1;
+ }
+ | NAME '[' CONST ']' { $1->sym->nel = $3->val; $$ = $1; }
+ ;
+
+varref : cmpnd { $$ = mk_explicit($1, Expand_Ok, NAME); }
+ ;
+
+pfld : NAME { $$ = nn($1, NAME, ZN, ZN); }
+ | NAME { owner = ZS; }
+ '[' expr ']' { $$ = nn($1, NAME, $4, ZN); }
+ ;
+
+cmpnd : pfld { Embedded++;
+ if ($1->sym->type == STRUCT)
+ owner = $1->sym->Snm;
+ }
+ sfld { $$ = $1; $$->rgt = $3;
+ if ($3 && $1->sym->type != STRUCT)
+ $1->sym->type = STRUCT;
+ Embedded--;
+ if (!Embedded && !NamesNotAdded
+ && !$1->sym->type)
+ non_fatal("undeclared variable: %s",
+ $1->sym->name);
+ if ($3) validref($1, $3->lft);
+ owner = ZS;
+ }
+ ;
+
+sfld : /* empty */ { $$ = ZN; }
+ | '.' cmpnd %prec DOT { $$ = nn(ZN, '.', $2, ZN); }
+ ;
+
+stmnt : Special { $$ = $1; }
+ | Stmnt { $$ = $1;
+ if (inEventMap)
+ non_fatal("not an event", (char *)0);
+ }
+ ;
+
+Special : varref RCV { Expand_Ok++; }
+ rargs { Expand_Ok--; has_io++;
+ $$ = nn($1, 'r', $1, $4);
+ trackchanuse($4, ZN, 'R');
+ }
+ | varref SND { Expand_Ok++; }
+ margs { Expand_Ok--; has_io++;
+ $$ = nn($1, 's', $1, $4);
+ $$->val=0; trackchanuse($4, ZN, 'S');
+ any_runs($4);
+ }
+ | IF options FI { $$ = nn($1, IF, ZN, ZN);
+ $$->sl = $2->sl;
+ prune_opts($$);
+ }
+ | DO { pushbreak(); }
+ options OD { $$ = nn($1, DO, ZN, ZN);
+ $$->sl = $3->sl;
+ prune_opts($$);
+ }
+ | BREAK { $$ = nn(ZN, GOTO, ZN, ZN);
+ $$->sym = break_dest();
+ }
+ | GOTO NAME { $$ = nn($2, GOTO, ZN, ZN);
+ if ($2->sym->type != 0
+ && $2->sym->type != LABEL) {
+ non_fatal("bad label-name %s",
+ $2->sym->name);
+ }
+ $2->sym->type = LABEL;
+ }
+ | NAME ':' stmnt { $$ = nn($1, ':',$3, ZN);
+ if ($1->sym->type != 0
+ && $1->sym->type != LABEL) {
+ non_fatal("bad label-name %s",
+ $1->sym->name);
+ }
+ $1->sym->type = LABEL;
+ }
+ ;
+
+Stmnt : varref ASGN expr { $$ = nn($1, ASGN, $1, $3);
+ trackvar($1, $3);
+ nochan_manip($1, $3, 0);
+ no_internals($1);
+ }
+ | varref INCR { $$ = nn(ZN,CONST, ZN, ZN); $$->val = 1;
+ $$ = nn(ZN, '+', $1, $$);
+ $$ = nn($1, ASGN, $1, $$);
+ trackvar($1, $1);
+ no_internals($1);
+ if ($1->sym->type == CHAN)
+ fatal("arithmetic on chan", (char *)0);
+ }
+ | varref DECR { $$ = nn(ZN,CONST, ZN, ZN); $$->val = 1;
+ $$ = nn(ZN, '-', $1, $$);
+ $$ = nn($1, ASGN, $1, $$);
+ trackvar($1, $1);
+ no_internals($1);
+ if ($1->sym->type == CHAN)
+ fatal("arithmetic on chan id's", (char *)0);
+ }
+ | PRINT '(' STRING { realread = 0; }
+ prargs ')' { $$ = nn($3, PRINT, $5, ZN); realread = 1; }
+ | PRINTM '(' varref ')' { $$ = nn(ZN, PRINTM, $3, ZN); }
+ | PRINTM '(' CONST ')' { $$ = nn(ZN, PRINTM, $3, ZN); }
+ | ASSERT full_expr { $$ = nn(ZN, ASSERT, $2, ZN); AST_track($2, 0); }
+ | ccode { $$ = $1; }
+ | varref R_RCV { Expand_Ok++; }
+ rargs { Expand_Ok--; has_io++;
+ $$ = nn($1, 'r', $1, $4);
+ $$->val = has_random = 1;
+ trackchanuse($4, ZN, 'R');
+ }
+ | varref RCV { Expand_Ok++; }
+ LT rargs GT { Expand_Ok--; has_io++;
+ $$ = nn($1, 'r', $1, $5);
+ $$->val = 2; /* fifo poll */
+ trackchanuse($5, ZN, 'R');
+ }
+ | varref R_RCV { Expand_Ok++; }
+ LT rargs GT { Expand_Ok--; has_io++; /* rrcv poll */
+ $$ = nn($1, 'r', $1, $5);
+ $$->val = 3; has_random = 1;
+ trackchanuse($5, ZN, 'R');
+ }
+ | varref O_SND { Expand_Ok++; }
+ margs { Expand_Ok--; has_io++;
+ $$ = nn($1, 's', $1, $4);
+ $$->val = has_sorted = 1;
+ trackchanuse($4, ZN, 'S');
+ any_runs($4);
+ }
+ | full_expr { $$ = nn(ZN, 'c', $1, ZN); count_runs($$); }
+ | ELSE { $$ = nn(ZN,ELSE,ZN,ZN);
+ }
+ | ATOMIC '{' { open_seq(0); }
+ sequence OS '}' { $$ = nn($1, ATOMIC, ZN, ZN);
+ $$->sl = seqlist(close_seq(3), 0);
+ make_atomic($$->sl->this, 0);
+ }
+ | D_STEP '{' { open_seq(0); rem_Seq(); }
+ sequence OS '}' { $$ = nn($1, D_STEP, ZN, ZN);
+ $$->sl = seqlist(close_seq(4), 0);
+ make_atomic($$->sl->this, D_ATOM);
+ unrem_Seq();
+ }
+ | '{' { open_seq(0); }
+ sequence OS '}' { $$ = nn(ZN, NON_ATOMIC, ZN, ZN);
+ $$->sl = seqlist(close_seq(5), 0);
+ }
+ | INAME { IArgs++; }
+ '(' args ')' { pickup_inline($1->sym, $4); IArgs--; }
+ Stmnt { $$ = $7; }
+ ;
+
+options : option { $$->sl = seqlist($1->sq, 0); }
+ | option options { $$->sl = seqlist($1->sq, $2->sl); }
+ ;
+
+option : SEP { open_seq(0); }
+ sequence OS { $$ = nn(ZN,0,ZN,ZN);
+ $$->sq = close_seq(6); }
+ ;
+
+OS : /* empty */
+ | SEMI { /* redundant semi at end of sequence */ }
+ ;
+
+MS : SEMI { /* at least one semi-colon */ }
+ | MS SEMI { /* but more are okay too */ }
+ ;
+
+aname : NAME { $$ = $1; }
+ | PNAME { $$ = $1; }
+ ;
+
+expr : '(' expr ')' { $$ = $2; }
+ | expr '+' expr { $$ = nn(ZN, '+', $1, $3); }
+ | expr '-' expr { $$ = nn(ZN, '-', $1, $3); }
+ | expr '*' expr { $$ = nn(ZN, '*', $1, $3); }
+ | expr '/' expr { $$ = nn(ZN, '/', $1, $3); }
+ | expr '%' expr { $$ = nn(ZN, '%', $1, $3); }
+ | expr '&' expr { $$ = nn(ZN, '&', $1, $3); }
+ | expr '^' expr { $$ = nn(ZN, '^', $1, $3); }
+ | expr '|' expr { $$ = nn(ZN, '|', $1, $3); }
+ | expr GT expr { $$ = nn(ZN, GT, $1, $3); }
+ | expr LT expr { $$ = nn(ZN, LT, $1, $3); }
+ | expr GE expr { $$ = nn(ZN, GE, $1, $3); }
+ | expr LE expr { $$ = nn(ZN, LE, $1, $3); }
+ | expr EQ expr { $$ = nn(ZN, EQ, $1, $3); }
+ | expr NE expr { $$ = nn(ZN, NE, $1, $3); }
+ | expr AND expr { $$ = nn(ZN, AND, $1, $3); }
+ | expr OR expr { $$ = nn(ZN, OR, $1, $3); }
+ | expr LSHIFT expr { $$ = nn(ZN, LSHIFT,$1, $3); }
+ | expr RSHIFT expr { $$ = nn(ZN, RSHIFT,$1, $3); }
+ | '~' expr { $$ = nn(ZN, '~', $2, ZN); }
+ | '-' expr %prec UMIN { $$ = nn(ZN, UMIN, $2, ZN); }
+ | SND expr %prec NEG { $$ = nn(ZN, '!', $2, ZN); }
+
+ | '(' expr SEMI expr ':' expr ')' {
+ $$ = nn(ZN, OR, $4, $6);
+ $$ = nn(ZN, '?', $2, $$);
+ }
+
+ | RUN aname { Expand_Ok++;
+ if (!context)
+ fatal("used 'run' outside proctype",
+ (char *) 0);
+ if (strcmp(context->name, ":init:") != 0)
+ runsafe = 0;
+ }
+ '(' args ')'
+ Opt_priority { Expand_Ok--;
+ $$ = nn($2, RUN, $5, ZN);
+ $$->val = ($7) ? $7->val : 1;
+ trackchanuse($5, $2, 'A'); trackrun($$);
+ }
+ | LEN '(' varref ')' { $$ = nn($3, LEN, $3, ZN); }
+ | ENABLED '(' expr ')' { $$ = nn(ZN, ENABLED, $3, ZN);
+ has_enabled++;
+ }
+ | varref RCV { Expand_Ok++; }
+ '[' rargs ']' { Expand_Ok--; has_io++;
+ $$ = nn($1, 'R', $1, $5);
+ }
+ | varref R_RCV { Expand_Ok++; }
+ '[' rargs ']' { Expand_Ok--; has_io++;
+ $$ = nn($1, 'R', $1, $5);
+ $$->val = has_random = 1;
+ }
+ | varref { $$ = $1; trapwonly($1, "varref"); }
+ | cexpr { $$ = $1; }
+ | CONST { $$ = nn(ZN,CONST,ZN,ZN);
+ $$->ismtyp = $1->ismtyp;
+ $$->val = $1->val;
+ }
+ | TIMEOUT { $$ = nn(ZN,TIMEOUT, ZN, ZN); }
+ | NONPROGRESS { $$ = nn(ZN,NONPROGRESS, ZN, ZN);
+ has_np++;
+ }
+ | PC_VAL '(' expr ')' { $$ = nn(ZN, PC_VAL, $3, ZN);
+ has_pcvalue++;
+ }
+ | PNAME '[' expr ']' '@' NAME
+ { $$ = rem_lab($1->sym, $3, $6->sym); }
+ | PNAME '[' expr ']' ':' pfld
+ { $$ = rem_var($1->sym, $3, $6->sym, $6->lft); }
+ | PNAME '@' NAME { $$ = rem_lab($1->sym, ZN, $3->sym); }
+ | PNAME ':' pfld { $$ = rem_var($1->sym, ZN, $3->sym, $3->lft); }
+ ;
+
+Opt_priority: /* none */ { $$ = ZN; }
+ | PRIORITY CONST { $$ = $2; }
+ ;
+
+full_expr: expr { $$ = $1; }
+ | Expr { $$ = $1; }
+ ;
+
+Opt_enabler: /* none */ { $$ = ZN; }
+ | PROVIDED '(' full_expr ')' { if (!proper_enabler($3))
+ { non_fatal("invalid PROVIDED clause",
+ (char *)0);
+ $$ = ZN;
+ } else
+ $$ = $3;
+ }
+ | PROVIDED error { $$ = ZN;
+ non_fatal("usage: provided ( ..expr.. )",
+ (char *)0);
+ }
+ ;
+
+ /* an Expr cannot be negated - to protect Probe expressions */
+Expr : Probe { $$ = $1; }
+ | '(' Expr ')' { $$ = $2; }
+ | Expr AND Expr { $$ = nn(ZN, AND, $1, $3); }
+ | Expr AND expr { $$ = nn(ZN, AND, $1, $3); }
+ | Expr OR Expr { $$ = nn(ZN, OR, $1, $3); }
+ | Expr OR expr { $$ = nn(ZN, OR, $1, $3); }
+ | expr AND Expr { $$ = nn(ZN, AND, $1, $3); }
+ | expr OR Expr { $$ = nn(ZN, OR, $1, $3); }
+ ;
+
+Probe : FULL '(' varref ')' { $$ = nn($3, FULL, $3, ZN); }
+ | NFULL '(' varref ')' { $$ = nn($3, NFULL, $3, ZN); }
+ | EMPTY '(' varref ')' { $$ = nn($3, EMPTY, $3, ZN); }
+ | NEMPTY '(' varref ')' { $$ = nn($3,NEMPTY, $3, ZN); }
+ ;
+
+basetype: TYPE { $$->sym = ZS;
+ $$->val = $1->val;
+ if ($$->val == UNSIGNED)
+ fatal("unsigned cannot be used as mesg type", 0);
+ }
+ | UNAME { $$->sym = $1->sym;
+ $$->val = STRUCT;
+ }
+ | error /* e.g., unsigned ':' const */
+ ;
+
+typ_list: basetype { $$ = nn($1, $1->val, ZN, ZN); }
+ | basetype ',' typ_list { $$ = nn($1, $1->val, ZN, $3); }
+ ;
+
+args : /* empty */ { $$ = ZN; }
+ | arg { $$ = $1; }
+ ;
+
+prargs : /* empty */ { $$ = ZN; }
+ | ',' arg { $$ = $2; }
+ ;
+
+margs : arg { $$ = $1; }
+ | expr '(' arg ')' { if ($1->ntyp == ',')
+ $$ = tail_add($1, $3);
+ else
+ $$ = nn(ZN, ',', $1, $3);
+ }
+ ;
+
+arg : expr { if ($1->ntyp == ',')
+ $$ = $1;
+ else
+ $$ = nn(ZN, ',', $1, ZN);
+ }
+ | expr ',' arg { if ($1->ntyp == ',')
+ $$ = tail_add($1, $3);
+ else
+ $$ = nn(ZN, ',', $1, $3);
+ }
+ ;
+
+rarg : varref { $$ = $1; trackvar($1, $1);
+ trapwonly($1, "rarg"); }
+ | EVAL '(' expr ')' { $$ = nn(ZN,EVAL,$3,ZN);
+ trapwonly($1, "eval rarg"); }
+ | CONST { $$ = nn(ZN,CONST,ZN,ZN);
+ $$->ismtyp = $1->ismtyp;
+ $$->val = $1->val;
+ }
+ | '-' CONST %prec UMIN { $$ = nn(ZN,CONST,ZN,ZN);
+ $$->val = - ($2->val);
+ }
+ ;
+
+rargs : rarg { if ($1->ntyp == ',')
+ $$ = $1;
+ else
+ $$ = nn(ZN, ',', $1, ZN);
+ }
+ | rarg ',' rargs { if ($1->ntyp == ',')
+ $$ = tail_add($1, $3);
+ else
+ $$ = nn(ZN, ',', $1, $3);
+ }
+ | rarg '(' rargs ')' { if ($1->ntyp == ',')
+ $$ = tail_add($1, $3);
+ else
+ $$ = nn(ZN, ',', $1, $3);
+ }
+ | '(' rargs ')' { $$ = $2; }
+ ;
+
+nlst : NAME { $$ = nn($1, NAME, ZN, ZN);
+ $$ = nn(ZN, ',', $$, ZN); }
+ | nlst NAME { $$ = nn($2, NAME, ZN, ZN);
+ $$ = nn(ZN, ',', $$, $1);
+ }
+ | nlst ',' { $$ = $1; /* commas optional */ }
+ ;
+%%
+
+void
+yyerror(char *fmt, ...)
+{
+ non_fatal(fmt, (char *) 0);
+}
diff --git a/sys/src/cmd/spin/spinlex.c b/sys/src/cmd/spin/spinlex.c
new file mode 100755
index 000000000..48c431f72
--- /dev/null
+++ b/sys/src/cmd/spin/spinlex.c
@@ -0,0 +1,1384 @@
+/***** spin: spinlex.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include <stdlib.h>
+#include "spin.h"
+#include "y.tab.h"
+
+#define MAXINL 16 /* max recursion depth inline fcts */
+#define MAXPAR 32 /* max params to an inline call */
+#define MAXLEN 512 /* max len of an actual parameter text */
+
+typedef struct IType {
+ Symbol *nm; /* name of the type */
+ Lextok *cn; /* contents */
+ Lextok *params; /* formal pars if any */
+ char **anms; /* literal text for actual pars */
+ char *prec; /* precondition for c_code or c_expr */
+ int dln, cln; /* def and call linenr */
+ Symbol *dfn, *cfn; /* def and call filename */
+ struct IType *nxt; /* linked list */
+} IType;
+
+typedef struct C_Added {
+ Symbol *s;
+ Symbol *t;
+ Symbol *ival;
+ struct C_Added *nxt;
+} C_Added;
+
+extern RunList *X;
+extern ProcList *rdy;
+extern Symbol *Fname;
+extern Symbol *context, *owner;
+extern YYSTYPE yylval;
+extern short has_last, has_code;
+extern int verbose, IArgs, hastrack, separate;
+
+short has_stack = 0;
+int lineno = 1;
+char yytext[2048];
+FILE *yyin, *yyout;
+
+static C_Added *c_added, *c_tracked;
+static IType *Inline_stub[MAXINL];
+static char *ReDiRect;
+static char *Inliner[MAXINL], IArg_cont[MAXPAR][MAXLEN];
+static unsigned char in_comment=0;
+static int IArgno = 0, Inlining = -1;
+static int check_name(char *);
+
+#if 1
+#define Token(y) { if (in_comment) goto again; \
+ yylval = nn(ZN,0,ZN,ZN); return y; }
+
+#define ValToken(x, y) { if (in_comment) goto again; \
+ yylval = nn(ZN,0,ZN,ZN); yylval->val = x; return y; }
+
+#define SymToken(x, y) { if (in_comment) goto again; \
+ yylval = nn(ZN,0,ZN,ZN); yylval->sym = x; return y; }
+#else
+#define Token(y) { yylval = nn(ZN,0,ZN,ZN); \
+ if (!in_comment) return y; else goto again; }
+
+#define ValToken(x, y) { yylval = nn(ZN,0,ZN,ZN); yylval->val = x; \
+ if (!in_comment) return y; else goto again; }
+
+#define SymToken(x, y) { yylval = nn(ZN,0,ZN,ZN); yylval->sym = x; \
+ if (!in_comment) return y; else goto again; }
+#endif
+
+static int getinline(void);
+static void uninline(void);
+
+#if 1
+#define Getchar() ((Inlining<0)?getc(yyin):getinline())
+#define Ungetch(c) {if (Inlining<0) ungetc(c,yyin); else uninline(); }
+
+#else
+
+static int
+Getchar(void)
+{ int c;
+ if (Inlining<0)
+ c = getc(yyin);
+ else
+ c = getinline();
+#if 1
+ printf("<%c>", c);
+#endif
+ return c;
+}
+
+static void
+Ungetch(int c)
+{
+ if (Inlining<0)
+ ungetc(c,yyin);
+ else
+ uninline();
+#if 1
+ printf("<bs>");
+#endif
+}
+#endif
+
+static int
+notquote(int c)
+{ return (c != '\"' && c != '\n');
+}
+
+int
+isalnum_(int c)
+{ return (isalnum(c) || c == '_');
+}
+
+static int
+isalpha_(int c)
+{ return isalpha(c); /* could be macro */
+}
+
+static int
+isdigit_(int c)
+{ return isdigit(c); /* could be macro */
+}
+
+static void
+getword(int first, int (*tst)(int))
+{ int i=0; char c;
+
+ yytext[i++]= (char) first;
+ while (tst(c = Getchar()))
+ { yytext[i++] = c;
+ if (c == '\\')
+ yytext[i++] = Getchar(); /* no tst */
+ }
+ yytext[i] = '\0';
+ Ungetch(c);
+}
+
+static int
+follow(int tok, int ifyes, int ifno)
+{ int c;
+
+ if ((c = Getchar()) == tok)
+ return ifyes;
+ Ungetch(c);
+
+ return ifno;
+}
+
+static IType *seqnames;
+
+static void
+def_inline(Symbol *s, int ln, char *ptr, char *prc, Lextok *nms)
+{ IType *tmp;
+ char *nw = (char *) emalloc((int) strlen(ptr)+1);
+ strcpy(nw, ptr);
+
+ for (tmp = seqnames; tmp; tmp = tmp->nxt)
+ if (!strcmp(s->name, tmp->nm->name))
+ { non_fatal("procedure name %s redefined",
+ tmp->nm->name);
+ tmp->cn = (Lextok *) nw;
+ tmp->params = nms;
+ tmp->dln = ln;
+ tmp->dfn = Fname;
+ return;
+ }
+ tmp = (IType *) emalloc(sizeof(IType));
+ tmp->nm = s;
+ tmp->cn = (Lextok *) nw;
+ tmp->params = nms;
+ if (strlen(prc) > 0)
+ { tmp->prec = (char *) emalloc((int) strlen(prc)+1);
+ strcpy(tmp->prec, prc);
+ }
+ tmp->dln = ln;
+ tmp->dfn = Fname;
+ tmp->nxt = seqnames;
+ seqnames = tmp;
+}
+
+void
+gencodetable(FILE *fd)
+{ IType *tmp;
+ char *q;
+ int cnt;
+
+ if (separate == 2) return;
+
+ fprintf(fd, "struct {\n");
+ fprintf(fd, " char *c; char *t;\n");
+ fprintf(fd, "} code_lookup[] = {\n");
+
+ if (has_code)
+ for (tmp = seqnames; tmp; tmp = tmp->nxt)
+ if (tmp->nm->type == CODE_FRAG
+ || tmp->nm->type == CODE_DECL)
+ { fprintf(fd, "\t{ \"%s\", ",
+ tmp->nm->name);
+ q = (char *) tmp->cn;
+
+ while (*q == '\n' || *q == '\r' || *q == '\\')
+ q++;
+
+ fprintf(fd, "\"");
+ cnt = 0;
+ while (*q && cnt < 1024) /* pangen1.h allows 2048 */
+ { switch (*q) {
+ case '"':
+ fprintf(fd, "\\\"");
+ break;
+ case '%':
+ fprintf(fd, "%%");
+ break;
+ case '\n':
+ fprintf(fd, "\\n");
+ break;
+ default:
+ putc(*q, fd);
+ break;
+ }
+ q++; cnt++;
+ }
+ if (*q) fprintf(fd, "...");
+ fprintf(fd, "\"");
+ fprintf(fd, " },\n");
+ }
+
+ fprintf(fd, " { (char *) 0, \"\" }\n");
+ fprintf(fd, "};\n");
+}
+
+static int
+iseqname(char *t)
+{ IType *tmp;
+
+ for (tmp = seqnames; tmp; tmp = tmp->nxt)
+ { if (!strcmp(t, tmp->nm->name))
+ return 1;
+ }
+ return 0;
+}
+
+static int
+getinline(void)
+{ int c;
+
+ if (ReDiRect)
+ { c = *ReDiRect++;
+ if (c == '\0')
+ { ReDiRect = (char *) 0;
+ c = *Inliner[Inlining]++;
+ }
+ } else
+ c = *Inliner[Inlining]++;
+
+ if (c == '\0')
+ { lineno = Inline_stub[Inlining]->cln;
+ Fname = Inline_stub[Inlining]->cfn;
+ Inlining--;
+#if 0
+ if (verbose&32)
+ printf("spin: line %d, done inlining %s\n",
+ lineno, Inline_stub[Inlining+1]->nm->name);
+#endif
+ return Getchar();
+ }
+ return c;
+}
+
+static void
+uninline(void)
+{
+ if (ReDiRect)
+ ReDiRect--;
+ else
+ Inliner[Inlining]--;
+}
+
+IType *
+find_inline(char *s)
+{ IType *tmp;
+
+ for (tmp = seqnames; tmp; tmp = tmp->nxt)
+ if (!strcmp(s, tmp->nm->name))
+ break;
+ if (!tmp)
+ fatal("cannot happen, missing inline def %s", s);
+ return tmp;
+}
+
+void
+c_state(Symbol *s, Symbol *t, Symbol *ival) /* name, scope, ival */
+{ C_Added *r;
+
+ r = (C_Added *) emalloc(sizeof(C_Added));
+ r->s = s; /* pointer to a data object */
+ r->t = t; /* size of object, or "global", or "local proctype_name" */
+ r->ival = ival;
+ r->nxt = c_added;
+ c_added = r;
+}
+
+void
+c_track(Symbol *s, Symbol *t, Symbol *stackonly) /* name, size */
+{ C_Added *r;
+
+ r = (C_Added *) emalloc(sizeof(C_Added));
+ r->s = s;
+ r->t = t;
+ r->ival = stackonly; /* abuse of name */
+ r->nxt = c_tracked;
+ c_tracked = r;
+
+ if (stackonly != ZS)
+ { if (strcmp(stackonly->name, "\"Matched\"") == 0)
+ r->ival = ZS; /* the default */
+ else if (strcmp(stackonly->name, "\"UnMatched\"") != 0
+ && strcmp(stackonly->name, "\"unMatched\"") != 0
+ && strcmp(stackonly->name, "\"StackOnly\"") != 0)
+ non_fatal("expecting '[Un]Matched', saw %s", stackonly->name);
+ else
+ has_stack = 1;
+ }
+}
+
+char *
+jump_etc(char *op)
+{ char *p = op;
+
+ /* kludgy - try to get the type separated from the name */
+
+ while (*p == ' ' || *p == '\t')
+ p++; /* initial white space */
+ while (*p != ' ' && *p != '\t')
+ p++; /* type name */
+ while (*p == ' ' || *p == '\t')
+ p++; /* white space */
+ while (*p == '*')
+ p++; /* decorations */
+ while (*p == ' ' || *p == '\t')
+ p++; /* white space */
+
+ if (*p == '\0')
+ fatal("c_state format (%s)", op);
+
+ if (strchr(p, '[')
+ && !strchr(p, '{'))
+ { non_fatal("array initialization error, c_state (%s)", p);
+ return (char *) 0;
+ }
+
+ return p;
+}
+
+void
+c_add_globinit(FILE *fd)
+{ C_Added *r;
+ char *p, *q;
+
+ fprintf(fd, "void\nglobinit(void)\n{\n");
+ for (r = c_added; r; r = r->nxt)
+ { if (r->ival == ZS)
+ continue;
+
+ if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0)
+ { for (q = r->ival->name; *q; q++)
+ { if (*q == '\"')
+ *q = ' ';
+ if (*q == '\\')
+ *q++ = ' '; /* skip over the next */
+ }
+ p = jump_etc(r->s->name); /* e.g., "int **q" */
+ if (p)
+ fprintf(fd, " now.%s = %s;\n", p, r->ival->name);
+
+ } else
+ if (strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0)
+ { for (q = r->ival->name; *q; q++)
+ { if (*q == '\"')
+ *q = ' ';
+ if (*q == '\\')
+ *q++ = ' '; /* skip over the next */
+ }
+ p = jump_etc(r->s->name); /* e.g., "int **q" */
+ if (p)
+ fprintf(fd, " %s = %s;\n", p, r->ival->name); /* no now. prefix */
+
+ } }
+ fprintf(fd, "}\n");
+}
+
+void
+c_add_locinit(FILE *fd, int tpnr, char *pnm)
+{ C_Added *r;
+ char *p, *q, *s;
+ int frst = 1;
+
+ fprintf(fd, "void\nlocinit%d(int h)\n{\n", tpnr);
+ for (r = c_added; r; r = r->nxt)
+ if (r->ival != ZS
+ && strncmp(r->t->name, " Local", strlen(" Local")) == 0)
+ { for (q = r->ival->name; *q; q++)
+ if (*q == '\"')
+ *q = ' ';
+
+ p = jump_etc(r->s->name); /* e.g., "int **q" */
+
+ q = r->t->name + strlen(" Local");
+ while (*q == ' ' || *q == '\t')
+ q++; /* process name */
+
+ s = (char *) emalloc(strlen(q)+1);
+ strcpy(s, q);
+
+ q = &s[strlen(s)-1];
+ while (*q == ' ' || *q == '\t')
+ *q-- = '\0';
+
+ if (strcmp(pnm, s) != 0)
+ continue;
+
+ if (frst)
+ { fprintf(fd, "\tuchar *this = pptr(h);\n");
+ frst = 0;
+ }
+
+ if (p)
+ fprintf(fd, " ((P%d *)this)->%s = %s;\n",
+ tpnr, p, r->ival->name);
+
+ }
+ fprintf(fd, "}\n");
+}
+
+/* tracking:
+ 1. for non-global and non-local c_state decls: add up all the sizes in c_added
+ 2. add a global char array of that size into now
+ 3. generate a routine that memcpy's the required values into that array
+ 4. generate a call to that routine
+ */
+
+void
+c_preview(void)
+{ C_Added *r;
+
+ hastrack = 0;
+ if (c_tracked)
+ hastrack = 1;
+ else
+ for (r = c_added; r; r = r->nxt)
+ if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0
+ && strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0
+ && strncmp(r->t->name, " Local", strlen(" Local")) != 0)
+ { hastrack = 1; /* c_state variant now obsolete */
+ break;
+ }
+}
+
+int
+c_add_sv(FILE *fd) /* 1+2 -- called in pangen1.c */
+{ C_Added *r;
+ int cnt = 0;
+
+ if (!c_added && !c_tracked) return 0;
+
+ for (r = c_added; r; r = r->nxt) /* pickup global decls */
+ if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0)
+ fprintf(fd, " %s;\n", r->s->name);
+
+ for (r = c_added; r; r = r->nxt)
+ if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0
+ && strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0
+ && strncmp(r->t->name, " Local", strlen(" Local")) != 0)
+ { cnt++; /* obsolete use */
+ }
+
+ for (r = c_tracked; r; r = r->nxt)
+ cnt++; /* preferred use */
+
+ if (cnt == 0) return 0;
+
+ cnt = 0;
+ fprintf(fd, " uchar c_state[");
+ for (r = c_added; r; r = r->nxt)
+ if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0
+ && strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0
+ && strncmp(r->t->name, " Local", strlen(" Local")) != 0)
+ { fprintf(fd, "%ssizeof(%s)",
+ (cnt==0)?"":"+", r->t->name);
+ cnt++;
+ }
+
+ for (r = c_tracked; r; r = r->nxt)
+ { if (r->ival != ZS) continue;
+
+ fprintf(fd, "%s%s",
+ (cnt==0)?"":"+", r->t->name);
+ cnt++;
+ }
+
+ if (cnt == 0) fprintf(fd, "4"); /* now redundant */
+ fprintf(fd, "];\n");
+ return 1;
+}
+
+void
+c_add_stack(FILE *fd)
+{ C_Added *r;
+ int cnt = 0;
+
+ if ((!c_added && !c_tracked) || !has_stack) return;
+
+
+ for (r = c_tracked; r; r = r->nxt)
+ if (r->ival != ZS)
+ cnt++;
+
+ if (cnt == 0) return;
+
+ fprintf(fd, " uchar c_stack[");
+
+ cnt = 0;
+ for (r = c_tracked; r; r = r->nxt)
+ { if (r->ival == ZS) continue;
+
+ fprintf(fd, "%s%s",
+ (cnt==0)?"":"+", r->t->name);
+ cnt++;
+ }
+
+ if (cnt == 0) fprintf(fd, "WS"); /* can't happen */
+ fprintf(fd, "];\n");
+}
+
+void
+c_add_hidden(FILE *fd)
+{ C_Added *r;
+
+ for (r = c_added; r; r = r->nxt) /* pickup hidden decls */
+ if (strncmp(r->t->name, "\"Hidden\"", strlen("\"Hidden\"")) == 0)
+ { r->s->name[strlen(r->s->name)-1] = ' ';
+ fprintf(fd, "%s; /* Hidden */\n", &r->s->name[1]);
+ r->s->name[strlen(r->s->name)-1] = '"';
+ }
+ /* called before c_add_def - quotes are still there */
+}
+
+void
+c_add_loc(FILE *fd, char *s) /* state vector entries for proctype s */
+{ C_Added *r;
+ static char buf[1024];
+ char *p;
+
+ if (!c_added) return;
+
+ strcpy(buf, s);
+ strcat(buf, " ");
+ for (r = c_added; r; r = r->nxt) /* pickup local decls */
+ if (strncmp(r->t->name, " Local", strlen(" Local")) == 0)
+ { p = r->t->name + strlen(" Local");
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (strcmp(p, buf) == 0)
+ fprintf(fd, " %s;\n", r->s->name);
+ }
+}
+void
+c_add_def(FILE *fd) /* 3 - called in plunk_c_fcts() */
+{ C_Added *r;
+
+ fprintf(fd, "#if defined(C_States) && defined(HAS_TRACK)\n");
+ for (r = c_added; r; r = r->nxt)
+ { r->s->name[strlen(r->s->name)-1] = ' ';
+ r->s->name[0] = ' '; /* remove the "s */
+
+ r->t->name[strlen(r->t->name)-1] = ' ';
+ r->t->name[0] = ' ';
+
+ if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0
+ || strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0
+ || strncmp(r->t->name, " Local", strlen(" Local")) == 0)
+ continue;
+
+ if (strchr(r->s->name, '&'))
+ fatal("dereferencing state object: %s", r->s->name);
+
+ fprintf(fd, "extern %s %s;\n", r->t->name, r->s->name);
+ }
+ for (r = c_tracked; r; r = r->nxt)
+ { r->s->name[strlen(r->s->name)-1] = ' ';
+ r->s->name[0] = ' '; /* remove " */
+
+ r->t->name[strlen(r->t->name)-1] = ' ';
+ r->t->name[0] = ' ';
+ }
+
+ if (separate == 2)
+ { fprintf(fd, "#endif\n");
+ return;
+ }
+
+ if (has_stack)
+ { fprintf(fd, "void\nc_stack(uchar *p_t_r)\n{\n");
+ fprintf(fd, "#ifdef VERBOSE\n");
+ fprintf(fd, " printf(\"c_stack %%u\\n\", p_t_r);\n");
+ fprintf(fd, "#endif\n");
+ for (r = c_tracked; r; r = r->nxt)
+ { if (r->ival == ZS) continue;
+
+ fprintf(fd, "\tif(%s)\n", r->s->name);
+ fprintf(fd, "\t\tmemcpy(p_t_r, %s, %s);\n",
+ r->s->name, r->t->name);
+ fprintf(fd, "\telse\n");
+ fprintf(fd, "\t\tmemset(p_t_r, 0, %s);\n",
+ r->t->name);
+ fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
+ }
+ fprintf(fd, "}\n\n");
+ }
+
+ fprintf(fd, "void\nc_update(uchar *p_t_r)\n{\n");
+ fprintf(fd, "#ifdef VERBOSE\n");
+ fprintf(fd, " printf(\"c_update %%u\\n\", p_t_r);\n");
+ fprintf(fd, "#endif\n");
+ for (r = c_added; r; r = r->nxt)
+ { if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0
+ || strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0
+ || strncmp(r->t->name, " Local", strlen(" Local")) == 0)
+ continue;
+
+ fprintf(fd, "\tmemcpy(p_t_r, &%s, sizeof(%s));\n",
+ r->s->name, r->t->name);
+ fprintf(fd, "\tp_t_r += sizeof(%s);\n", r->t->name);
+ }
+
+ for (r = c_tracked; r; r = r->nxt)
+ { if (r->ival) continue;
+
+ fprintf(fd, "\tif(%s)\n", r->s->name);
+ fprintf(fd, "\t\tmemcpy(p_t_r, %s, %s);\n",
+ r->s->name, r->t->name);
+ fprintf(fd, "\telse\n");
+ fprintf(fd, "\t\tmemset(p_t_r, 0, %s);\n",
+ r->t->name);
+ fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
+ }
+
+ fprintf(fd, "}\n");
+
+ if (has_stack)
+ { fprintf(fd, "void\nc_unstack(uchar *p_t_r)\n{\n");
+ fprintf(fd, "#ifdef VERBOSE\n");
+ fprintf(fd, " printf(\"c_unstack %%u\\n\", p_t_r);\n");
+ fprintf(fd, "#endif\n");
+ for (r = c_tracked; r; r = r->nxt)
+ { if (r->ival == ZS) continue;
+
+ fprintf(fd, "\tif(%s)\n", r->s->name);
+ fprintf(fd, "\t\tmemcpy(%s, p_t_r, %s);\n",
+ r->s->name, r->t->name);
+ fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
+ }
+ fprintf(fd, "}\n");
+ }
+
+ fprintf(fd, "void\nc_revert(uchar *p_t_r)\n{\n");
+ fprintf(fd, "#ifdef VERBOSE\n");
+ fprintf(fd, " printf(\"c_revert %%u\\n\", p_t_r);\n");
+ fprintf(fd, "#endif\n");
+ for (r = c_added; r; r = r->nxt)
+ { if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0
+ || strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0
+ || strncmp(r->t->name, " Local", strlen(" Local")) == 0)
+ continue;
+
+ fprintf(fd, "\tmemcpy(&%s, p_t_r, sizeof(%s));\n",
+ r->s->name, r->t->name);
+ fprintf(fd, "\tp_t_r += sizeof(%s);\n", r->t->name);
+ }
+ for (r = c_tracked; r; r = r->nxt)
+ { if (r->ival != ZS) continue;
+
+ fprintf(fd, "\tif(%s)\n", r->s->name);
+ fprintf(fd, "\t\tmemcpy(%s, p_t_r, %s);\n",
+ r->s->name, r->t->name);
+ fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
+ }
+
+ fprintf(fd, "}\n");
+ fprintf(fd, "#endif\n");
+}
+
+void
+plunk_reverse(FILE *fd, IType *p, int matchthis)
+{ char *y, *z;
+
+ if (!p) return;
+ plunk_reverse(fd, p->nxt, matchthis);
+
+ if (!p->nm->context
+ && p->nm->type == matchthis)
+ { fprintf(fd, "\n/* start of %s */\n", p->nm->name);
+ z = (char *) p->cn;
+ while (*z == '\n' || *z == '\r' || *z == '\\')
+ z++;
+ /* e.g.: \#include "..." */
+
+ y = z;
+ while ((y = strstr(y, "\\#")) != NULL)
+ { *y = '\n'; y++;
+ }
+
+ fprintf(fd, "%s\n", z);
+ fprintf(fd, "\n/* end of %s */\n", p->nm->name);
+ }
+}
+
+void
+plunk_c_decls(FILE *fd)
+{
+ plunk_reverse(fd, seqnames, CODE_DECL);
+}
+
+void
+plunk_c_fcts(FILE *fd)
+{
+ if (separate == 2 && hastrack)
+ { c_add_def(fd);
+ return;
+ }
+
+ c_add_hidden(fd);
+ plunk_reverse(fd, seqnames, CODE_FRAG);
+
+ if (c_added || c_tracked) /* enables calls to c_revert and c_update */
+ fprintf(fd, "#define C_States 1\n");
+ else
+ fprintf(fd, "#undef C_States\n");
+
+ if (hastrack)
+ c_add_def(fd);
+
+ c_add_globinit(fd);
+ do_locinits(fd);
+}
+
+static void
+check_inline(IType *tmp)
+{ char buf[128];
+ ProcList *p;
+
+ if (!X) return;
+
+ for (p = rdy; p; p = p->nxt)
+ { if (strcmp(p->n->name, X->n->name) == 0)
+ continue;
+ sprintf(buf, "P%s->", p->n->name);
+ if (strstr((char *)tmp->cn, buf))
+ { printf("spin: in proctype %s, ref to object in proctype %s\n",
+ X->n->name, p->n->name);
+ fatal("invalid variable ref in '%s'", tmp->nm->name);
+ } }
+}
+
+void
+plunk_expr(FILE *fd, char *s)
+{ IType *tmp;
+
+ tmp = find_inline(s);
+ check_inline(tmp);
+
+ fprintf(fd, "%s", (char *) tmp->cn);
+}
+
+void
+preruse(FILE *fd, Lextok *n) /* check a condition for c_expr with preconditions */
+{ IType *tmp;
+
+ if (!n) return;
+ if (n->ntyp == C_EXPR)
+ { tmp = find_inline(n->sym->name);
+ if (tmp->prec)
+ { fprintf(fd, "if (!(%s)) { if (!readtrail) { depth++; ", tmp->prec);
+ fprintf(fd, "trpt++; trpt->pr = II; trpt->o_t = t;");
+ fprintf(fd, "trpt->st = tt; Uerror(\"%s\"); } ", tmp->prec);
+ fprintf(fd, "else { printf(\"pan: precondition false: %s\\n\"); ", tmp->prec);
+ fprintf(fd, "_m = 3; goto P999; } } \n\t\t");
+ }
+ } else
+ { preruse(fd, n->rgt);
+ preruse(fd, n->lft);
+ }
+}
+
+int
+glob_inline(char *s)
+{ IType *tmp;
+ char *bdy;
+
+ tmp = find_inline(s);
+ bdy = (char *) tmp->cn;
+ return (strstr(bdy, "now.") /* global ref or */
+ || strchr(bdy, '(') > bdy); /* possible C-function call */
+}
+
+void
+plunk_inline(FILE *fd, char *s, int how) /* c_code with precondition */
+{ IType *tmp;
+
+ tmp = find_inline(s);
+ check_inline(tmp);
+
+ fprintf(fd, "{ ");
+ if (how && tmp->prec)
+ { fprintf(fd, "if (!(%s)) { if (!readtrail) { depth++; ", tmp->prec);
+ fprintf(fd, "trpt++; trpt->pr = II; trpt->o_t = t;");
+ fprintf(fd, "trpt->st = tt; Uerror(\"%s\"); } ", tmp->prec);
+ fprintf(fd, "else { printf(\"pan: precondition false: %s\\n\"); ", tmp->prec);
+ fprintf(fd, "_m = 3; goto P999; } } ");
+ }
+ fprintf(fd, "%s", (char *) tmp->cn);
+ fprintf(fd, " }\n");
+}
+
+void
+no_side_effects(char *s)
+{ IType *tmp;
+ char *t;
+
+ /* could still defeat this check via hidden
+ * side effects in function calls,
+ * but this will catch at least some cases
+ */
+
+ tmp = find_inline(s);
+ t = (char *) tmp->cn;
+
+ if (strchr(t, ';')
+ || strstr(t, "++")
+ || strstr(t, "--"))
+ {
+bad: lineno = tmp->dln;
+ Fname = tmp->dfn;
+ non_fatal("c_expr %s has side-effects", s);
+ return;
+ }
+ while ((t = strchr(t, '=')) != NULL)
+ { if (*(t-1) == '!'
+ || *(t-1) == '>'
+ || *(t-1) == '<')
+ { t++;
+ continue;
+ }
+ t++;
+ if (*t != '=')
+ goto bad;
+ t++;
+ }
+}
+
+void
+pickup_inline(Symbol *t, Lextok *apars)
+{ IType *tmp; Lextok *p, *q; int j;
+
+ tmp = find_inline(t->name);
+
+ if (++Inlining >= MAXINL)
+ fatal("inline fcts too deeply nested", 0);
+
+ tmp->cln = lineno; /* remember calling point */
+ tmp->cfn = Fname; /* and filename */
+
+ for (p = apars, q = tmp->params, j = 0; p && q; p = p->rgt, q = q->rgt)
+ j++; /* count them */
+ if (p || q)
+ fatal("wrong nr of params on call of '%s'", t->name);
+
+ tmp->anms = (char **) emalloc(j * sizeof(char *));
+ for (p = apars, j = 0; p; p = p->rgt, j++)
+ { tmp->anms[j] = (char *) emalloc((int) strlen(IArg_cont[j])+1);
+ strcpy(tmp->anms[j], IArg_cont[j]);
+ }
+
+ lineno = tmp->dln; /* linenr of def */
+ Fname = tmp->dfn; /* filename of same */
+ Inliner[Inlining] = (char *)tmp->cn;
+ Inline_stub[Inlining] = tmp;
+#if 0
+ if (verbose&32)
+ printf("spin: line %d, file %s, inlining '%s' (from line %d, file %s)\n",
+ tmp->cln, tmp->cfn->name, t->name, tmp->dln, tmp->dfn->name);
+#endif
+ for (j = 0; j < Inlining; j++)
+ if (Inline_stub[j] == Inline_stub[Inlining])
+ fatal("cyclic inline attempt on: %s", t->name);
+}
+
+static void
+do_directive(int first)
+{ int c = first; /* handles lines starting with pound */
+
+ getword(c, isalpha_);
+
+ if (strcmp(yytext, "#ident") == 0)
+ goto done;
+
+ if ((c = Getchar()) != ' ')
+ fatal("malformed preprocessor directive - # .", 0);
+
+ if (!isdigit_(c = Getchar()))
+ fatal("malformed preprocessor directive - # .lineno", 0);
+
+ getword(c, isdigit_);
+ lineno = atoi(yytext); /* pickup the line number */
+
+ if ((c = Getchar()) == '\n')
+ return; /* no filename */
+
+ if (c != ' ')
+ fatal("malformed preprocessor directive - .fname", 0);
+
+ if ((c = Getchar()) != '\"')
+ fatal("malformed preprocessor directive - .fname", 0);
+
+ getword(c, notquote);
+ if (Getchar() != '\"')
+ fatal("malformed preprocessor directive - fname.", 0);
+
+ strcat(yytext, "\"");
+ Fname = lookup(yytext);
+done:
+ while (Getchar() != '\n')
+ ;
+}
+
+void
+precondition(char *q)
+{ int c, nest = 1;
+
+ for (;;)
+ { c = Getchar();
+ *q++ = c;
+ switch (c) {
+ case '\n':
+ lineno++;
+ break;
+ case '[':
+ nest++;
+ break;
+ case ']':
+ if (--nest <= 0)
+ { *--q = '\0';
+ return;
+ }
+ break;
+ }
+ }
+ fatal("cannot happen", (char *) 0);
+}
+
+Symbol *
+prep_inline(Symbol *s, Lextok *nms)
+{ int c, nest = 1, dln, firstchar, cnr;
+ char *p, buf[SOMETHINGBIG], buf2[RATHERSMALL];
+ Lextok *t;
+ static int c_code = 1;
+
+ for (t = nms; t; t = t->rgt)
+ if (t->lft)
+ { if (t->lft->ntyp != NAME)
+ fatal("bad param to inline %s", s->name);
+ t->lft->sym->hidden |= 32;
+ }
+
+ if (!s) /* C_Code fragment */
+ { s = (Symbol *) emalloc(sizeof(Symbol));
+ s->name = (char *) emalloc((int) strlen("c_code")+26);
+ sprintf(s->name, "c_code%d", c_code++);
+ s->context = context;
+ s->type = CODE_FRAG;
+ } else
+ s->type = PREDEF;
+
+ p = &buf[0];
+ buf2[0] = '\0';
+ for (;;)
+ { c = Getchar();
+ switch (c) {
+ case '[':
+ if (s->type != CODE_FRAG)
+ goto bad;
+ precondition(&buf2[0]); /* e.g., c_code [p] { r = p-r; } */
+ continue;
+ case '{':
+ break;
+ case '\n':
+ lineno++;
+ /* fall through */
+ case ' ': case '\t': case '\f': case '\r':
+ continue;
+ default :
+ printf("spin: saw char '%c'\n", c);
+bad: fatal("bad inline: %s", s->name);
+ }
+ break;
+ }
+ dln = lineno;
+ if (s->type == CODE_FRAG)
+ { if (verbose&32)
+ sprintf(buf, "\t/* line %d %s */\n\t\t",
+ lineno, Fname->name);
+ else
+ strcpy(buf, "");
+ } else
+ sprintf(buf, "\n#line %d %s\n{", lineno, Fname->name);
+ p += strlen(buf);
+ firstchar = 1;
+
+ cnr = 1; /* not zero */
+more:
+ *p++ = c = Getchar();
+ if (p - buf >= SOMETHINGBIG)
+ fatal("inline text too long", 0);
+ switch (c) {
+ case '\n':
+ lineno++;
+ cnr = 0;
+ break;
+ case '{':
+ cnr++;
+ nest++;
+ break;
+ case '}':
+ cnr++;
+ if (--nest <= 0)
+ { *p = '\0';
+ if (s->type == CODE_FRAG)
+ *--p = '\0'; /* remove trailing '}' */
+ def_inline(s, dln, &buf[0], &buf2[0], nms);
+ if (firstchar && s)
+ printf("%3d: %s, warning: empty inline definition (%s)\n",
+ dln, Fname->name, s->name);
+ return s; /* normal return */
+ }
+ break;
+ case '#':
+ if (cnr == 0)
+ { p--;
+ do_directive(c); /* reads to newline */
+ break;
+ } /* else fall through */
+ default:
+ firstchar = 0;
+ case '\t':
+ case ' ':
+ case '\f':
+ cnr++;
+ break;
+ }
+ goto more;
+}
+
+static int
+lex(void)
+{ int c;
+
+again:
+ c = Getchar();
+ yytext[0] = (char) c;
+ yytext[1] = '\0';
+ switch (c) {
+ case '\n': /* newline */
+ lineno++;
+ case '\r': /* carriage return */
+ goto again;
+
+ case ' ': case '\t': case '\f': /* white space */
+ goto again;
+
+ case '#': /* preprocessor directive */
+ if (in_comment) goto again;
+ do_directive(c);
+ goto again;
+
+ case '\"':
+ getword(c, notquote);
+ if (Getchar() != '\"')
+ fatal("string not terminated", yytext);
+ strcat(yytext, "\"");
+ SymToken(lookup(yytext), STRING)
+
+ case '\'': /* new 3.0.9 */
+ c = Getchar();
+ if (c == '\\')
+ { c = Getchar();
+ if (c == 'n') c = '\n';
+ else if (c == 'r') c = '\r';
+ else if (c == 't') c = '\t';
+ else if (c == 'f') c = '\f';
+ }
+ if (Getchar() != '\'' && !in_comment)
+ fatal("character quote missing: %s", yytext);
+ ValToken(c, CONST)
+
+ default:
+ break;
+ }
+
+ if (isdigit_(c))
+ { getword(c, isdigit_);
+ ValToken(atoi(yytext), CONST)
+ }
+
+ if (isalpha_(c) || c == '_')
+ { getword(c, isalnum_);
+ if (!in_comment)
+ { c = check_name(yytext);
+ if (c) return c;
+ /* else fall through */
+ }
+ goto again;
+ }
+
+ switch (c) {
+ case '/': c = follow('*', 0, '/');
+ if (!c) { in_comment = 1; goto again; }
+ break;
+ case '*': c = follow('/', 0, '*');
+ if (!c) { in_comment = 0; goto again; }
+ break;
+ case ':': c = follow(':', SEP, ':'); break;
+ case '-': c = follow('>', SEMI, follow('-', DECR, '-')); break;
+ case '+': c = follow('+', INCR, '+'); break;
+ case '<': c = follow('<', LSHIFT, follow('=', LE, LT)); break;
+ case '>': c = follow('>', RSHIFT, follow('=', GE, GT)); break;
+ case '=': c = follow('=', EQ, ASGN); break;
+ case '!': c = follow('=', NE, follow('!', O_SND, SND)); break;
+ case '?': c = follow('?', R_RCV, RCV); break;
+ case '&': c = follow('&', AND, '&'); break;
+ case '|': c = follow('|', OR, '|'); break;
+ case ';': c = SEMI; break;
+ default : break;
+ }
+ Token(c)
+}
+
+static struct {
+ char *s; int tok; int val; char *sym;
+} Names[] = {
+ {"active", ACTIVE, 0, 0},
+ {"assert", ASSERT, 0, 0},
+ {"atomic", ATOMIC, 0, 0},
+ {"bit", TYPE, BIT, 0},
+ {"bool", TYPE, BIT, 0},
+ {"break", BREAK, 0, 0},
+ {"byte", TYPE, BYTE, 0},
+ {"c_code", C_CODE, 0, 0},
+ {"c_decl", C_DECL, 0, 0},
+ {"c_expr", C_EXPR, 0, 0},
+ {"c_state", C_STATE, 0, 0},
+ {"c_track", C_TRACK, 0, 0},
+ {"D_proctype", D_PROCTYPE, 0, 0},
+ {"do", DO, 0, 0},
+ {"chan", TYPE, CHAN, 0},
+ {"else", ELSE, 0, 0},
+ {"empty", EMPTY, 0, 0},
+ {"enabled", ENABLED, 0, 0},
+ {"eval", EVAL, 0, 0},
+ {"false", CONST, 0, 0},
+ {"fi", FI, 0, 0},
+ {"full", FULL, 0, 0},
+ {"goto", GOTO, 0, 0},
+ {"hidden", HIDDEN, 0, ":hide:"},
+ {"if", IF, 0, 0},
+ {"init", INIT, 0, ":init:"},
+ {"int", TYPE, INT, 0},
+ {"len", LEN, 0, 0},
+ {"local", ISLOCAL, 0, ":local:"},
+ {"mtype", TYPE, MTYPE, 0},
+ {"nempty", NEMPTY, 0, 0},
+ {"never", CLAIM, 0, ":never:"},
+ {"nfull", NFULL, 0, 0},
+ {"notrace", TRACE, 0, ":notrace:"},
+ {"np_", NONPROGRESS, 0, 0},
+ {"od", OD, 0, 0},
+ {"of", OF, 0, 0},
+ {"pc_value", PC_VAL, 0, 0},
+ {"pid", TYPE, BYTE, 0},
+ {"printf", PRINT, 0, 0},
+ {"printm", PRINTM, 0, 0},
+ {"priority", PRIORITY, 0, 0},
+ {"proctype", PROCTYPE, 0, 0},
+ {"provided", PROVIDED, 0, 0},
+ {"run", RUN, 0, 0},
+ {"d_step", D_STEP, 0, 0},
+ {"inline", INLINE, 0, 0},
+ {"short", TYPE, SHORT, 0},
+ {"skip", CONST, 1, 0},
+ {"timeout", TIMEOUT, 0, 0},
+ {"trace", TRACE, 0, ":trace:"},
+ {"true", CONST, 1, 0},
+ {"show", SHOW, 0, ":show:"},
+ {"typedef", TYPEDEF, 0, 0},
+ {"unless", UNLESS, 0, 0},
+ {"unsigned", TYPE, UNSIGNED, 0},
+ {"xr", XU, XR, 0},
+ {"xs", XU, XS, 0},
+ {0, 0, 0, 0},
+};
+
+static int
+check_name(char *s)
+{ int i;
+
+ yylval = nn(ZN, 0, ZN, ZN);
+ for (i = 0; Names[i].s; i++)
+ if (strcmp(s, Names[i].s) == 0)
+ { yylval->val = Names[i].val;
+ if (Names[i].sym)
+ yylval->sym = lookup(Names[i].sym);
+ return Names[i].tok;
+ }
+
+ if ((yylval->val = ismtype(s)) != 0)
+ { yylval->ismtyp = 1;
+ return CONST;
+ }
+
+ if (strcmp(s, "_last") == 0)
+ has_last++;
+
+ if (Inlining >= 0 && !ReDiRect)
+ { Lextok *tt, *t = Inline_stub[Inlining]->params;
+
+ for (i = 0; t; t = t->rgt, i++) /* formal pars */
+ if (!strcmp(s, t->lft->sym->name) /* varname matches formal */
+ && strcmp(s, Inline_stub[Inlining]->anms[i]) != 0) /* actual pars */
+ {
+#if 0
+ if (verbose&32)
+ printf("\tline %d, replace %s in call of '%s' with %s\n",
+ lineno, s,
+ Inline_stub[Inlining]->nm->name,
+ Inline_stub[Inlining]->anms[i]);
+#endif
+
+ for (tt = Inline_stub[Inlining]->params; tt; tt = tt->rgt)
+ if (!strcmp(Inline_stub[Inlining]->anms[i],
+ tt->lft->sym->name))
+ { /* would be cyclic if not caught */
+ printf("spin: line %d replacement value: %s\n",
+ lineno, tt->lft->sym->name);
+ fatal("formal par of %s matches replacement value",
+ Inline_stub[Inlining]->nm->name);
+ yylval->ntyp = tt->lft->ntyp;
+ yylval->sym = lookup(tt->lft->sym->name);
+ return NAME;
+ }
+ ReDiRect = Inline_stub[Inlining]->anms[i];
+ return 0;
+ } }
+
+ yylval->sym = lookup(s); /* symbol table */
+ if (isutype(s))
+ return UNAME;
+ if (isproctype(s))
+ return PNAME;
+ if (iseqname(s))
+ return INAME;
+
+ return NAME;
+}
+
+int
+yylex(void)
+{ static int last = 0;
+ static int hold = 0;
+ int c;
+ /*
+ * repair two common syntax mistakes with
+ * semi-colons before or after a '}'
+ */
+ if (hold)
+ { c = hold;
+ hold = 0;
+ } else
+ { c = lex();
+ if (last == ELSE
+ && c != SEMI
+ && c != FI)
+ { hold = c;
+ last = 0;
+ return SEMI;
+ }
+ if (last == '}'
+ && c != PROCTYPE
+ && c != INIT
+ && c != CLAIM
+ && c != SEP
+ && c != FI
+ && c != OD
+ && c != '}'
+ && c != UNLESS
+ && c != SEMI
+ && c != EOF)
+ { hold = c;
+ last = 0;
+ return SEMI; /* insert ';' */
+ }
+ if (c == SEMI)
+ { /* if context, we're not in a typedef
+ * because they're global.
+ * if owner, we're at the end of a ref
+ * to a struct field -- prevent that the
+ * lookahead is interpreted as a field of
+ * the same struct...
+ */
+ if (context) owner = ZS;
+ hold = lex(); /* look ahead */
+ if (hold == '}'
+ || hold == SEMI)
+ { c = hold; /* omit ';' */
+ hold = 0;
+ }
+ }
+ }
+ last = c;
+
+ if (IArgs)
+ { static int IArg_nst = 0;
+
+ if (strcmp(yytext, ",") == 0)
+ { IArg_cont[++IArgno][0] = '\0';
+ } else if (strcmp(yytext, "(") == 0)
+ { if (IArg_nst++ == 0)
+ { IArgno = 0;
+ IArg_cont[0][0] = '\0';
+ } else
+ strcat(IArg_cont[IArgno], yytext);
+ } else if (strcmp(yytext, ")") == 0)
+ { if (--IArg_nst > 0)
+ strcat(IArg_cont[IArgno], yytext);
+ } else if (c == CONST && yytext[0] == '\'')
+ { sprintf(yytext, "'%c'", yylval->val);
+ strcat(IArg_cont[IArgno], yytext);
+ } else
+ {
+ switch (c) {
+ case SEP: strcpy(yytext, "::"); break;
+ case SEMI: strcpy(yytext, ";"); break;
+ case DECR: strcpy(yytext, "--"); break;
+ case INCR: strcpy(yytext, "++"); break;
+ case LSHIFT: strcpy(yytext, "<<"); break;
+ case RSHIFT: strcpy(yytext, ">>"); break;
+ case LE: strcpy(yytext, "<="); break;
+ case LT: strcpy(yytext, "<"); break;
+ case GE: strcpy(yytext, ">="); break;
+ case GT: strcpy(yytext, ">"); break;
+ case EQ: strcpy(yytext, "=="); break;
+ case ASGN: strcpy(yytext, "="); break;
+ case NE: strcpy(yytext, "!="); break;
+ case R_RCV: strcpy(yytext, "??"); break;
+ case RCV: strcpy(yytext, "?"); break;
+ case O_SND: strcpy(yytext, "!!"); break;
+ case SND: strcpy(yytext, "!"); break;
+ case AND: strcpy(yytext, "&&"); break;
+ case OR: strcpy(yytext, "||"); break;
+ }
+ strcat(IArg_cont[IArgno], yytext);
+ }
+ }
+
+ return c;
+}
diff --git a/sys/src/cmd/spin/structs.c b/sys/src/cmd/spin/structs.c
new file mode 100755
index 000000000..5ade6054e
--- /dev/null
+++ b/sys/src/cmd/spin/structs.c
@@ -0,0 +1,659 @@
+/***** spin: structs.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include "spin.h"
+#include "y.tab.h"
+
+typedef struct UType {
+ Symbol *nm; /* name of the type */
+ Lextok *cn; /* contents */
+ struct UType *nxt; /* linked list */
+} UType;
+
+extern Symbol *Fname;
+extern int lineno, depth, Expand_Ok;
+
+Symbol *owner;
+
+static UType *Unames = 0;
+static UType *Pnames = 0;
+
+static Lextok *cpnn(Lextok *, int, int, int);
+extern void sr_mesg(FILE *, int, int);
+
+void
+setuname(Lextok *n)
+{ UType *tmp;
+
+ for (tmp = Unames; tmp; tmp = tmp->nxt)
+ if (!strcmp(owner->name, tmp->nm->name))
+ { non_fatal("typename %s was defined before",
+ tmp->nm->name);
+ return;
+ }
+ if (!owner) fatal("illegal reference inside typedef",
+ (char *) 0);
+ tmp = (UType *) emalloc(sizeof(UType));
+ tmp->nm = owner;
+ tmp->cn = n;
+ tmp->nxt = Unames;
+ Unames = tmp;
+}
+
+static void
+putUname(FILE *fd, UType *tmp)
+{ Lextok *fp, *tl;
+
+ if (!tmp) return;
+ putUname(fd, tmp->nxt); /* postorder */
+ fprintf(fd, "struct %s { /* user defined type */\n",
+ tmp->nm->name);
+ for (fp = tmp->cn; fp; fp = fp->rgt)
+ for (tl = fp->lft; tl; tl = tl->rgt)
+ typ2c(tl->sym);
+ fprintf(fd, "};\n");
+}
+
+void
+putunames(FILE *fd)
+{
+ putUname(fd, Unames);
+}
+
+int
+isutype(char *t)
+{ UType *tmp;
+
+ for (tmp = Unames; tmp; tmp = tmp->nxt)
+ { if (!strcmp(t, tmp->nm->name))
+ return 1;
+ }
+ return 0;
+}
+
+Lextok *
+getuname(Symbol *t)
+{ UType *tmp;
+
+ for (tmp = Unames; tmp; tmp = tmp->nxt)
+ { if (!strcmp(t->name, tmp->nm->name))
+ return tmp->cn;
+ }
+ fatal("%s is not a typename", t->name);
+ return (Lextok *)0;
+}
+
+void
+setutype(Lextok *p, Symbol *t, Lextok *vis) /* user-defined types */
+{ int oln = lineno;
+ Symbol *ofn = Fname;
+ Lextok *m, *n;
+
+ m = getuname(t);
+ for (n = p; n; n = n->rgt)
+ { lineno = n->ln;
+ Fname = n->fn;
+ if (n->sym->type)
+ non_fatal("redeclaration of '%s'", n->sym->name);
+
+ if (n->sym->nbits > 0)
+ non_fatal("(%s) only an unsigned can have width-field",
+ n->sym->name);
+
+ if (Expand_Ok)
+ n->sym->hidden |= (4|8|16); /* formal par */
+
+ if (vis)
+ { if (strncmp(vis->sym->name, ":hide:", 6) == 0)
+ n->sym->hidden |= 1;
+ else if (strncmp(vis->sym->name, ":show:", 6) == 0)
+ n->sym->hidden |= 2;
+ else if (strncmp(vis->sym->name, ":local:", 7) == 0)
+ n->sym->hidden |= 64;
+ }
+ n->sym->type = STRUCT; /* classification */
+ n->sym->Slst = m; /* structure itself */
+ n->sym->Snm = t; /* name of typedef */
+ n->sym->Nid = 0; /* this is no chan */
+ n->sym->hidden |= 4;
+ if (n->sym->nel <= 0)
+ non_fatal("bad array size for '%s'", n->sym->name);
+ }
+ lineno = oln;
+ Fname = ofn;
+}
+
+static Symbol *
+do_same(Lextok *n, Symbol *v, int xinit)
+{ Lextok *tmp, *fp, *tl;
+ int ix = eval(n->lft);
+ int oln = lineno;
+ Symbol *ofn = Fname;
+
+ lineno = n->ln;
+ Fname = n->fn;
+
+ /* n->sym->type == STRUCT
+ * index: n->lft
+ * subfields: n->rgt
+ * structure template: n->sym->Slst
+ * runtime values: n->sym->Sval
+ */
+ if (xinit) ini_struct(v); /* once, at top level */
+
+ if (ix >= v->nel || ix < 0)
+ { printf("spin: indexing %s[%d] - size is %d\n",
+ v->name, ix, v->nel);
+ fatal("indexing error \'%s\'", v->name);
+ }
+ if (!n->rgt || !n->rgt->lft)
+ { non_fatal("no subfields %s", v->name); /* i.e., wants all */
+ lineno = oln; Fname = ofn;
+ return ZS;
+ }
+
+ if (n->rgt->ntyp != '.')
+ { printf("bad subfield type %d\n", n->rgt->ntyp);
+ alldone(1);
+ }
+
+ tmp = n->rgt->lft;
+ if (tmp->ntyp != NAME && tmp->ntyp != TYPE)
+ { printf("bad subfield entry %d\n", tmp->ntyp);
+ alldone(1);
+ }
+ for (fp = v->Sval[ix]; fp; fp = fp->rgt)
+ for (tl = fp->lft; tl; tl = tl->rgt)
+ if (!strcmp(tl->sym->name, tmp->sym->name))
+ { lineno = oln; Fname = ofn;
+ return tl->sym;
+ }
+ fatal("cannot locate subfield %s", tmp->sym->name);
+ return ZS;
+}
+
+int
+Rval_struct(Lextok *n, Symbol *v, int xinit) /* n varref, v valref */
+{ Symbol *tl;
+ Lextok *tmp;
+ int ix;
+
+ if (!n || !(tl = do_same(n, v, xinit)))
+ return 0;
+
+ tmp = n->rgt->lft;
+ if (tmp->sym->type == STRUCT)
+ { return Rval_struct(tmp, tl, 0);
+ } else if (tmp->rgt)
+ fatal("non-zero 'rgt' on non-structure", 0);
+
+ ix = eval(tmp->lft);
+ if (ix >= tl->nel || ix < 0)
+ fatal("indexing error \'%s\'", tl->name);
+
+ return cast_val(tl->type, tl->val[ix], tl->nbits);
+}
+
+int
+Lval_struct(Lextok *n, Symbol *v, int xinit, int a) /* a = assigned value */
+{ Symbol *tl;
+ Lextok *tmp;
+ int ix;
+
+ if (!(tl = do_same(n, v, xinit)))
+ return 1;
+
+ tmp = n->rgt->lft;
+ if (tmp->sym->type == STRUCT)
+ return Lval_struct(tmp, tl, 0, a);
+ else if (tmp->rgt)
+ fatal("non-zero 'rgt' on non-structure", 0);
+
+ ix = eval(tmp->lft);
+ if (ix >= tl->nel || ix < 0)
+ fatal("indexing error \'%s\'", tl->name);
+
+ if (tl->nbits > 0)
+ a = (a & ((1<<tl->nbits)-1));
+ tl->val[ix] = a;
+ tl->setat = depth;
+
+ return 1;
+}
+
+int
+Cnt_flds(Lextok *m)
+{ Lextok *fp, *tl, *n;
+ int cnt = 0;
+
+ if (m->ntyp == ',')
+ { n = m;
+ goto is_lst;
+ }
+ if (!m->sym || m->ntyp != STRUCT)
+ return 1;
+
+ n = getuname(m->sym);
+is_lst:
+ for (fp = n; fp; fp = fp->rgt)
+ for (tl = fp->lft; tl; tl = tl->rgt)
+ { if (tl->sym->type == STRUCT)
+ { if (tl->sym->nel != 1)
+ fatal("array of structures in param list, %s",
+ tl->sym->name);
+ cnt += Cnt_flds(tl->sym->Slst);
+ } else
+ cnt += tl->sym->nel;
+ }
+ return cnt;
+}
+
+int
+Sym_typ(Lextok *t)
+{ Symbol *s = t->sym;
+
+ if (!s) return 0;
+
+ if (s->type != STRUCT)
+ return s->type;
+
+ if (!t->rgt
+ || !t->rgt->ntyp == '.'
+ || !t->rgt->lft)
+ return STRUCT; /* not a field reference */
+
+ return Sym_typ(t->rgt->lft);
+}
+
+int
+Width_set(int *wdth, int i, Lextok *n)
+{ Lextok *fp, *tl;
+ int j = i, k;
+
+ for (fp = n; fp; fp = fp->rgt)
+ for (tl = fp->lft; tl; tl = tl->rgt)
+ { if (tl->sym->type == STRUCT)
+ j = Width_set(wdth, j, tl->sym->Slst);
+ else
+ { for (k = 0; k < tl->sym->nel; k++, j++)
+ wdth[j] = tl->sym->type;
+ } }
+ return j;
+}
+
+void
+ini_struct(Symbol *s)
+{ int i; Lextok *fp, *tl;
+
+ if (s->type != STRUCT) /* last step */
+ { (void) checkvar(s, 0);
+ return;
+ }
+ if (s->Sval == (Lextok **) 0)
+ { s->Sval = (Lextok **) emalloc(s->nel * sizeof(Lextok *));
+ for (i = 0; i < s->nel; i++)
+ { s->Sval[i] = cpnn(s->Slst, 1, 1, 1);
+
+ for (fp = s->Sval[i]; fp; fp = fp->rgt)
+ for (tl = fp->lft; tl; tl = tl->rgt)
+ ini_struct(tl->sym);
+ } }
+}
+
+static Lextok *
+cpnn(Lextok *s, int L, int R, int S)
+{ Lextok *d; extern int Nid;
+
+ if (!s) return ZN;
+
+ d = (Lextok *) emalloc(sizeof(Lextok));
+ d->ntyp = s->ntyp;
+ d->val = s->val;
+ d->ln = s->ln;
+ d->fn = s->fn;
+ d->sym = s->sym;
+ if (L) d->lft = cpnn(s->lft, 1, 1, S);
+ if (R) d->rgt = cpnn(s->rgt, 1, 1, S);
+
+ if (S && s->sym)
+ { d->sym = (Symbol *) emalloc(sizeof(Symbol));
+ memcpy(d->sym, s->sym, sizeof(Symbol));
+ if (d->sym->type == CHAN)
+ d->sym->Nid = ++Nid;
+ }
+ if (s->sq || s->sl)
+ fatal("cannot happen cpnn", (char *) 0);
+
+ return d;
+}
+
+int
+full_name(FILE *fd, Lextok *n, Symbol *v, int xinit)
+{ Symbol *tl;
+ Lextok *tmp;
+ int hiddenarrays = 0;
+
+ fprintf(fd, "%s", v->name);
+
+ if (!n || !(tl = do_same(n, v, xinit)))
+ return 0;
+ tmp = n->rgt->lft;
+
+ if (tmp->sym->type == STRUCT)
+ { fprintf(fd, ".");
+ hiddenarrays = full_name(fd, tmp, tl, 0);
+ goto out;
+ }
+ fprintf(fd, ".%s", tl->name);
+out: if (tmp->sym->nel > 1)
+ { fprintf(fd, "[%d]", eval(tmp->lft));
+ hiddenarrays = 1;
+ }
+ return hiddenarrays;
+}
+
+void
+validref(Lextok *p, Lextok *c)
+{ Lextok *fp, *tl;
+ char lbuf[512];
+
+ for (fp = p->sym->Slst; fp; fp = fp->rgt)
+ for (tl = fp->lft; tl; tl = tl->rgt)
+ if (strcmp(tl->sym->name, c->sym->name) == 0)
+ return;
+
+ sprintf(lbuf, "no field '%s' defined in structure '%s'\n",
+ c->sym->name, p->sym->name);
+ non_fatal(lbuf, (char *) 0);
+}
+
+void
+struct_name(Lextok *n, Symbol *v, int xinit, char *buf)
+{ Symbol *tl;
+ Lextok *tmp;
+ char lbuf[512];
+
+ if (!n || !(tl = do_same(n, v, xinit)))
+ return;
+ tmp = n->rgt->lft;
+ if (tmp->sym->type == STRUCT)
+ { strcat(buf, ".");
+ struct_name(tmp, tl, 0, buf);
+ return;
+ }
+ sprintf(lbuf, ".%s", tl->name);
+ strcat(buf, lbuf);
+ if (tmp->sym->nel > 1)
+ { sprintf(lbuf, "[%d]", eval(tmp->lft));
+ strcat(buf, lbuf);
+ }
+}
+
+void
+walk2_struct(char *s, Symbol *z)
+{ Lextok *fp, *tl;
+ char eprefix[128];
+ int ix;
+ extern void Done_case(char *, Symbol *);
+
+ ini_struct(z);
+ if (z->nel == 1)
+ sprintf(eprefix, "%s%s.", s, z->name);
+ for (ix = 0; ix < z->nel; ix++)
+ { if (z->nel > 1)
+ sprintf(eprefix, "%s%s[%d].", s, z->name, ix);
+ for (fp = z->Sval[ix]; fp; fp = fp->rgt)
+ for (tl = fp->lft; tl; tl = tl->rgt)
+ { if (tl->sym->type == STRUCT)
+ walk2_struct(eprefix, tl->sym);
+ else if (tl->sym->type == CHAN)
+ Done_case(eprefix, tl->sym);
+ } }
+}
+
+void
+walk_struct(FILE *ofd, int dowhat, char *s, Symbol *z, char *a, char *b, char *c)
+{ Lextok *fp, *tl;
+ char eprefix[128];
+ int ix;
+
+ ini_struct(z);
+ if (z->nel == 1)
+ sprintf(eprefix, "%s%s.", s, z->name);
+ for (ix = 0; ix < z->nel; ix++)
+ { if (z->nel > 1)
+ sprintf(eprefix, "%s%s[%d].", s, z->name, ix);
+ for (fp = z->Sval[ix]; fp; fp = fp->rgt)
+ for (tl = fp->lft; tl; tl = tl->rgt)
+ { if (tl->sym->type == STRUCT)
+ walk_struct(ofd, dowhat, eprefix, tl->sym, a,b,c);
+ else
+ do_var(ofd, dowhat, eprefix, tl->sym, a,b,c);
+ } }
+}
+
+void
+c_struct(FILE *fd, char *ipref, Symbol *z)
+{ Lextok *fp, *tl;
+ char pref[256], eprefix[256];
+ int ix;
+
+ ini_struct(z);
+
+ for (ix = 0; ix < z->nel; ix++)
+ for (fp = z->Sval[ix]; fp; fp = fp->rgt)
+ for (tl = fp->lft; tl; tl = tl->rgt)
+ { strcpy(eprefix, ipref);
+ if (z->nel > 1)
+ { /* insert index before last '.' */
+ eprefix[strlen(eprefix)-1] = '\0';
+ sprintf(pref, "[ %d ].", ix);
+ strcat(eprefix, pref);
+ }
+ if (tl->sym->type == STRUCT)
+ { strcat(eprefix, tl->sym->name);
+ strcat(eprefix, ".");
+ c_struct(fd, eprefix, tl->sym);
+ } else
+ c_var(fd, eprefix, tl->sym);
+ }
+}
+
+void
+dump_struct(Symbol *z, char *prefix, RunList *r)
+{ Lextok *fp, *tl;
+ char eprefix[256];
+ int ix, jx;
+
+ ini_struct(z);
+
+ for (ix = 0; ix < z->nel; ix++)
+ { if (z->nel > 1)
+ sprintf(eprefix, "%s[%d]", prefix, ix);
+ else
+ strcpy(eprefix, prefix);
+
+ for (fp = z->Sval[ix]; fp; fp = fp->rgt)
+ for (tl = fp->lft; tl; tl = tl->rgt)
+ { if (tl->sym->type == STRUCT)
+ { char pref[256];
+ strcpy(pref, eprefix);
+ strcat(pref, ".");
+ strcat(pref, tl->sym->name);
+ dump_struct(tl->sym, pref, r);
+ } else
+ for (jx = 0; jx < tl->sym->nel; jx++)
+ { if (tl->sym->type == CHAN)
+ doq(tl->sym, jx, r);
+ else
+ { printf("\t\t");
+ if (r)
+ printf("%s(%d):", r->n->name, r->pid);
+ printf("%s.%s", eprefix, tl->sym->name);
+ if (tl->sym->nel > 1)
+ printf("[%d]", jx);
+ printf(" = ");
+ sr_mesg(stdout, tl->sym->val[jx],
+ tl->sym->type == MTYPE);
+ printf("\n");
+ } } }
+ }
+}
+
+static int
+retrieve(Lextok **targ, int i, int want, Lextok *n, int Ntyp)
+{ Lextok *fp, *tl;
+ int j = i, k;
+
+ for (fp = n; fp; fp = fp->rgt)
+ for (tl = fp->lft; tl; tl = tl->rgt)
+ { if (tl->sym->type == STRUCT)
+ { j = retrieve(targ, j, want, tl->sym->Slst, Ntyp);
+ if (j < 0)
+ { Lextok *x = cpnn(tl, 1, 0, 0);
+ x->rgt = nn(ZN, '.', (*targ), ZN);
+ (*targ) = x;
+ return -1;
+ }
+ } else
+ { for (k = 0; k < tl->sym->nel; k++, j++)
+ { if (j == want)
+ { *targ = cpnn(tl, 1, 0, 0);
+ (*targ)->lft = nn(ZN, CONST, ZN, ZN);
+ (*targ)->lft->val = k;
+ if (Ntyp)
+ (*targ)->ntyp = (short) Ntyp;
+ return -1;
+ }
+ } } }
+ return j;
+}
+
+static int
+is_explicit(Lextok *n)
+{
+ if (!n) return 0;
+ if (!n->sym) fatal("unexpected - no symbol", 0);
+ if (n->sym->type != STRUCT) return 1;
+ if (!n->rgt) return 0;
+ if (n->rgt->ntyp != '.')
+ { lineno = n->ln;
+ Fname = n->fn;
+ printf("ntyp %d\n", n->rgt->ntyp);
+ fatal("unexpected %s, no '.'", n->sym->name);
+ }
+ return is_explicit(n->rgt->lft);
+}
+
+Lextok *
+expand(Lextok *n, int Ok)
+ /* turn rgt-lnked list of struct nms, into ',' list of flds */
+{ Lextok *x = ZN, *y;
+
+ if (!Ok) return n;
+
+ while (n)
+ { y = mk_explicit(n, 1, 0);
+ if (x)
+ (void) tail_add(x, y);
+ else
+ x = y;
+
+ n = n->rgt;
+ }
+ return x;
+}
+
+Lextok *
+mk_explicit(Lextok *n, int Ok, int Ntyp)
+ /* produce a single ',' list of fields */
+{ Lextok *bld = ZN, *x;
+ int i, cnt; extern int IArgs;
+
+ if (n->sym->type != STRUCT
+ || is_explicit(n))
+ return n;
+
+ if (n->rgt
+ && n->rgt->ntyp == '.'
+ && n->rgt->lft
+ && n->rgt->lft->sym
+ && n->rgt->lft->sym->type == STRUCT)
+ { Lextok *y;
+ bld = mk_explicit(n->rgt->lft, Ok, Ntyp);
+ for (x = bld; x; x = x->rgt)
+ { y = cpnn(n, 1, 0, 0);
+ y->rgt = nn(ZN, '.', x->lft, ZN);
+ x->lft = y;
+ }
+
+ return bld;
+ }
+
+ if (!Ok || !n->sym->Slst)
+ { if (IArgs) return n;
+ printf("spin: saw '");
+ comment(stdout, n, 0);
+ printf("'\n");
+ fatal("incomplete structure ref '%s'", n->sym->name);
+ }
+
+ cnt = Cnt_flds(n->sym->Slst);
+ for (i = cnt-1; i >= 0; i--)
+ { bld = nn(ZN, ',', ZN, bld);
+ if (retrieve(&(bld->lft), 0, i, n->sym->Slst, Ntyp) >= 0)
+ { printf("cannot retrieve field %d\n", i);
+ fatal("bad structure %s", n->sym->name);
+ }
+ x = cpnn(n, 1, 0, 0);
+ x->rgt = nn(ZN, '.', bld->lft, ZN);
+ bld->lft = x;
+ }
+ return bld;
+}
+
+Lextok *
+tail_add(Lextok *a, Lextok *b)
+{ Lextok *t;
+
+ for (t = a; t->rgt; t = t->rgt)
+ if (t->ntyp != ',')
+ fatal("unexpected type - tail_add", 0);
+ t->rgt = b;
+ return a;
+}
+
+void
+setpname(Lextok *n)
+{ UType *tmp;
+
+ for (tmp = Pnames; tmp; tmp = tmp->nxt)
+ if (!strcmp(n->sym->name, tmp->nm->name))
+ { non_fatal("proctype %s redefined",
+ n->sym->name);
+ return;
+ }
+ tmp = (UType *) emalloc(sizeof(UType));
+ tmp->nm = n->sym;
+ tmp->nxt = Pnames;
+ Pnames = tmp;
+}
+
+int
+isproctype(char *t)
+{ UType *tmp;
+
+ for (tmp = Pnames; tmp; tmp = tmp->nxt)
+ { if (!strcmp(t, tmp->nm->name))
+ return 1;
+ }
+ return 0;
+}
diff --git a/sys/src/cmd/spin/sym.c b/sys/src/cmd/spin/sym.c
new file mode 100755
index 000000000..0001d2f5f
--- /dev/null
+++ b/sys/src/cmd/spin/sym.c
@@ -0,0 +1,534 @@
+/***** spin: sym.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include "spin.h"
+#include "y.tab.h"
+
+extern Symbol *Fname, *owner;
+extern int lineno, depth, verbose, NamesNotAdded, deadvar;
+extern short has_xu;
+
+Symbol *context = ZS;
+Ordered *all_names = (Ordered *)0;
+int Nid = 0;
+
+static Ordered *last_name = (Ordered *)0;
+static Symbol *symtab[Nhash+1];
+
+static int
+samename(Symbol *a, Symbol *b)
+{
+ if (!a && !b) return 1;
+ if (!a || !b) return 0;
+ return !strcmp(a->name, b->name);
+}
+
+int
+hash(char *s)
+{ int h=0;
+
+ while (*s)
+ { h += *s++;
+ h <<= 1;
+ if (h&(Nhash+1))
+ h |= 1;
+ }
+ return h&Nhash;
+}
+
+Symbol *
+lookup(char *s)
+{ Symbol *sp; Ordered *no;
+ int h = hash(s);
+
+ for (sp = symtab[h]; sp; sp = sp->next)
+ if (strcmp(sp->name, s) == 0
+ && samename(sp->context, context)
+ && samename(sp->owner, owner))
+ return sp; /* found */
+
+ if (context) /* in proctype */
+ for (sp = symtab[h]; sp; sp = sp->next)
+ if (strcmp(sp->name, s) == 0
+ && !sp->context
+ && samename(sp->owner, owner))
+ return sp; /* global */
+
+ sp = (Symbol *) emalloc(sizeof(Symbol));
+ sp->name = (char *) emalloc((int) strlen(s) + 1);
+ strcpy(sp->name, s);
+ sp->nel = 1;
+ sp->setat = depth;
+ sp->context = context;
+ sp->owner = owner; /* if fld in struct */
+
+ if (NamesNotAdded == 0)
+ { sp->next = symtab[h];
+ symtab[h] = sp;
+ no = (Ordered *) emalloc(sizeof(Ordered));
+ no->entry = sp;
+ if (!last_name)
+ last_name = all_names = no;
+ else
+ { last_name->next = no;
+ last_name = no;
+ } }
+
+ return sp;
+}
+
+void
+trackvar(Lextok *n, Lextok *m)
+{ Symbol *sp = n->sym;
+
+ if (!sp) return; /* a structure list */
+ switch (m->ntyp) {
+ case NAME:
+ if (m->sym->type != BIT)
+ { sp->hidden |= 4;
+ if (m->sym->type != BYTE)
+ sp->hidden |= 8;
+ }
+ break;
+ case CONST:
+ if (m->val != 0 && m->val != 1)
+ sp->hidden |= 4;
+ if (m->val < 0 || m->val > 256)
+ sp->hidden |= 8; /* ditto byte-equiv */
+ break;
+ default: /* unknown */
+ sp->hidden |= (4|8); /* not known bit-equiv */
+ }
+}
+
+Lextok *runstmnts = ZN;
+
+void
+trackrun(Lextok *n)
+{
+ runstmnts = nn(ZN, 0, n, runstmnts);
+}
+
+void
+checkrun(Symbol *parnm, int posno)
+{ Lextok *n, *now, *v; int i, m;
+ int res = 0; char buf[16], buf2[16];
+
+ for (n = runstmnts; n; n = n->rgt)
+ { now = n->lft;
+ if (now->sym != parnm->context)
+ continue;
+ for (v = now->lft, i = 0; v; v = v->rgt, i++)
+ if (i == posno)
+ { m = v->lft->ntyp;
+ if (m == CONST)
+ { m = v->lft->val;
+ if (m != 0 && m != 1)
+ res |= 4;
+ if (m < 0 || m > 256)
+ res |= 8;
+ } else if (m == NAME)
+ { m = v->lft->sym->type;
+ if (m != BIT)
+ { res |= 4;
+ if (m != BYTE)
+ res |= 8;
+ }
+ } else
+ res |= (4|8); /* unknown */
+ break;
+ } }
+ if (!(res&4) || !(res&8))
+ { if (!(verbose&32)) return;
+ strcpy(buf2, (!(res&4))?"bit":"byte");
+ sputtype(buf, parnm->type);
+ i = (int) strlen(buf);
+ while (buf[--i] == ' ') buf[i] = '\0';
+ if (strcmp(buf, buf2) == 0) return;
+ prehint(parnm);
+ printf("proctype %s, '%s %s' could be declared",
+ parnm->context->name, buf, parnm->name);
+ printf(" '%s %s'\n", buf2, parnm->name);
+ }
+}
+
+void
+trackchanuse(Lextok *m, Lextok *w, int t)
+{ Lextok *n = m; int cnt = 1;
+ while (n)
+ { if (n->lft
+ && n->lft->sym
+ && n->lft->sym->type == CHAN)
+ setaccess(n->lft->sym, w?w->sym:ZS, cnt, t);
+ n = n->rgt; cnt++;
+ }
+}
+
+void
+setptype(Lextok *n, int t, Lextok *vis) /* predefined types */
+{ int oln = lineno, cnt = 1; extern int Expand_Ok;
+
+ while (n)
+ { if (n->sym->type && !(n->sym->hidden&32))
+ { lineno = n->ln; Fname = n->fn;
+ non_fatal("redeclaration of '%s'", n->sym->name);
+ lineno = oln;
+ }
+ n->sym->type = (short) t;
+
+ if (Expand_Ok)
+ { n->sym->hidden |= (4|8|16); /* formal par */
+ if (t == CHAN)
+ setaccess(n->sym, ZS, cnt, 'F');
+ }
+ if (t == UNSIGNED)
+ { if (n->sym->nbits < 0 || n->sym->nbits >= 32)
+ fatal("(%s) has invalid width-field", n->sym->name);
+ if (n->sym->nbits == 0)
+ { n->sym->nbits = 16;
+ non_fatal("unsigned without width-field", 0);
+ }
+ } else if (n->sym->nbits > 0)
+ { non_fatal("(%s) only an unsigned can have width-field",
+ n->sym->name);
+ }
+ if (vis)
+ { if (strncmp(vis->sym->name, ":hide:", 6) == 0)
+ { n->sym->hidden |= 1;
+ if (t == BIT)
+ fatal("bit variable (%s) cannot be hidden",
+ n->sym->name);
+ } else if (strncmp(vis->sym->name, ":show:", 6) == 0)
+ { n->sym->hidden |= 2;
+ } else if (strncmp(vis->sym->name, ":local:", 7) == 0)
+ { n->sym->hidden |= 64;
+ }
+ }
+ if (t == CHAN)
+ n->sym->Nid = ++Nid;
+ else
+ { n->sym->Nid = 0;
+ if (n->sym->ini
+ && n->sym->ini->ntyp == CHAN)
+ { Fname = n->fn;
+ lineno = n->ln;
+ fatal("chan initializer for non-channel %s",
+ n->sym->name);
+ }
+ }
+ if (n->sym->nel <= 0)
+ { lineno = n->ln; Fname = n->fn;
+ non_fatal("bad array size for '%s'", n->sym->name);
+ lineno = oln;
+ }
+ n = n->rgt; cnt++;
+ }
+}
+
+static void
+setonexu(Symbol *sp, int t)
+{
+ sp->xu |= t;
+ if (t == XR || t == XS)
+ { if (sp->xup[t-1]
+ && strcmp(sp->xup[t-1]->name, context->name))
+ { printf("error: x[rs] claims from %s and %s\n",
+ sp->xup[t-1]->name, context->name);
+ non_fatal("conflicting claims on chan '%s'",
+ sp->name);
+ }
+ sp->xup[t-1] = context;
+ }
+}
+
+static void
+setallxu(Lextok *n, int t)
+{ Lextok *fp, *tl;
+
+ for (fp = n; fp; fp = fp->rgt)
+ for (tl = fp->lft; tl; tl = tl->rgt)
+ { if (tl->sym->type == STRUCT)
+ setallxu(tl->sym->Slst, t);
+ else if (tl->sym->type == CHAN)
+ setonexu(tl->sym, t);
+ }
+}
+
+Lextok *Xu_List = (Lextok *) 0;
+
+void
+setxus(Lextok *p, int t)
+{ Lextok *m, *n;
+
+ has_xu = 1;
+ if (!context)
+ { lineno = p->ln;
+ Fname = p->fn;
+ fatal("non-local x[rs] assertion", (char *)0);
+ }
+ for (m = p; m; m = m->rgt)
+ { Lextok *Xu_new = (Lextok *) emalloc(sizeof(Lextok));
+ Xu_new->val = t;
+ Xu_new->lft = m->lft;
+ Xu_new->sym = context;
+ Xu_new->rgt = Xu_List;
+ Xu_List = Xu_new;
+
+ n = m->lft;
+ if (n->sym->type == STRUCT)
+ setallxu(n->sym->Slst, t);
+ else if (n->sym->type == CHAN)
+ setonexu(n->sym, t);
+ else
+ { int oln = lineno;
+ lineno = n->ln; Fname = n->fn;
+ non_fatal("xr or xs of non-chan '%s'",
+ n->sym->name);
+ lineno = oln;
+ }
+ }
+}
+
+Lextok *Mtype = (Lextok *) 0;
+
+void
+setmtype(Lextok *m)
+{ Lextok *n;
+ int cnt, oln = lineno;
+
+ if (m) { lineno = m->ln; Fname = m->fn; }
+
+ if (!Mtype)
+ Mtype = m;
+ else
+ { for (n = Mtype; n->rgt; n = n->rgt)
+ ;
+ n->rgt = m; /* concatenate */
+ }
+
+ for (n = Mtype, cnt = 1; n; n = n->rgt, cnt++) /* syntax check */
+ { if (!n->lft || !n->lft->sym
+ || n->lft->ntyp != NAME
+ || n->lft->lft) /* indexed variable */
+ fatal("bad mtype definition", (char *)0);
+
+ /* label the name */
+ if (n->lft->sym->type != MTYPE)
+ { n->lft->sym->hidden |= 128; /* is used */
+ n->lft->sym->type = MTYPE;
+ n->lft->sym->ini = nn(ZN,CONST,ZN,ZN);
+ n->lft->sym->ini->val = cnt;
+ } else if (n->lft->sym->ini->val != cnt)
+ non_fatal("name %s appears twice in mtype declaration",
+ n->lft->sym->name);
+ }
+ lineno = oln;
+ if (cnt > 256)
+ fatal("too many mtype elements (>255)", (char *)0);
+}
+
+int
+ismtype(char *str) /* name to number */
+{ Lextok *n;
+ int cnt = 1;
+
+ for (n = Mtype; n; n = n->rgt)
+ { if (strcmp(str, n->lft->sym->name) == 0)
+ return cnt;
+ cnt++;
+ }
+ return 0;
+}
+
+int
+sputtype(char *foo, int m)
+{
+ switch (m) {
+ case UNSIGNED: strcpy(foo, "unsigned "); break;
+ case BIT: strcpy(foo, "bit "); break;
+ case BYTE: strcpy(foo, "byte "); break;
+ case CHAN: strcpy(foo, "chan "); break;
+ case SHORT: strcpy(foo, "short "); break;
+ case INT: strcpy(foo, "int "); break;
+ case MTYPE: strcpy(foo, "mtype "); break;
+ case STRUCT: strcpy(foo, "struct"); break;
+ case PROCTYPE: strcpy(foo, "proctype"); break;
+ case LABEL: strcpy(foo, "label "); return 0;
+ default: strcpy(foo, "value "); return 0;
+ }
+ return 1;
+}
+
+
+static int
+puttype(int m)
+{ char buf[128];
+
+ if (sputtype(buf, m))
+ { printf("%s", buf);
+ return 1;
+ }
+ return 0;
+}
+
+void
+symvar(Symbol *sp)
+{ Lextok *m;
+
+ if (!puttype(sp->type))
+ return;
+
+ printf("\t");
+ if (sp->owner) printf("%s.", sp->owner->name);
+ printf("%s", sp->name);
+ if (sp->nel > 1) printf("[%d]", sp->nel);
+
+ if (sp->type == CHAN)
+ printf("\t%d", (sp->ini)?sp->ini->val:0);
+ else if (sp->type == STRUCT) /* Frank Weil, 2.9.8 */
+ printf("\t%s", sp->Snm->name);
+ else
+ printf("\t%d", eval(sp->ini));
+
+ if (sp->owner)
+ printf("\t<:struct-field:>");
+ else
+ if (!sp->context)
+ printf("\t<:global:>");
+ else
+ printf("\t<%s>", sp->context->name);
+
+ if (sp->Nid < 0) /* formal parameter */
+ printf("\t<parameter %d>", -(sp->Nid));
+ else
+ printf("\t<variable>");
+ if (sp->type == CHAN && sp->ini)
+ { int i;
+ for (m = sp->ini->rgt, i = 0; m; m = m->rgt)
+ i++;
+ printf("\t%d\t", i);
+ for (m = sp->ini->rgt; m; m = m->rgt)
+ { if (m->ntyp == STRUCT)
+ printf("struct %s", m->sym->name);
+ else
+ (void) puttype(m->ntyp);
+ if (m->rgt) printf("\t");
+ }
+ }
+ printf("\n");
+}
+
+void
+symdump(void)
+{ Ordered *walk;
+
+ for (walk = all_names; walk; walk = walk->next)
+ symvar(walk->entry);
+}
+
+void
+chname(Symbol *sp)
+{ printf("chan ");
+ if (sp->context) printf("%s-", sp->context->name);
+ if (sp->owner) printf("%s.", sp->owner->name);
+ printf("%s", sp->name);
+ if (sp->nel > 1) printf("[%d]", sp->nel);
+ printf("\t");
+}
+
+
+static struct X {
+ int typ; char *nm;
+} xx[] = {
+ { 'A', "exported as run parameter" },
+ { 'F', "imported as proctype parameter" },
+ { 'L', "used as l-value in asgnmnt" },
+ { 'V', "used as r-value in asgnmnt" },
+ { 'P', "polled in receive stmnt" },
+ { 'R', "used as parameter in receive stmnt" },
+ { 'S', "used as parameter in send stmnt" },
+ { 'r', "received from" },
+ { 's', "sent to" },
+};
+
+static void
+chan_check(Symbol *sp)
+{ Access *a; int i, b=0, d;
+
+ if (verbose&1) goto report; /* -C -g */
+
+ for (a = sp->access; a; a = a->lnk)
+ if (a->typ == 'r')
+ b |= 1;
+ else if (a->typ == 's')
+ b |= 2;
+ if (b == 3 || (sp->hidden&16)) /* balanced or formal par */
+ return;
+report:
+ chname(sp);
+ for (i = d = 0; i < (int) (sizeof(xx)/sizeof(struct X)); i++)
+ { b = 0;
+ for (a = sp->access; a; a = a->lnk)
+ if (a->typ == xx[i].typ) b++;
+ if (b == 0) continue; d++;
+ printf("\n\t%s by: ", xx[i].nm);
+ for (a = sp->access; a; a = a->lnk)
+ if (a->typ == xx[i].typ)
+ { printf("%s", a->who->name);
+ if (a->what) printf(" to %s", a->what->name);
+ if (a->cnt) printf(" par %d", a->cnt);
+ if (--b > 0) printf(", ");
+ }
+ }
+ printf("%s\n", (!d)?"\n\tnever used under this name":"");
+}
+
+void
+chanaccess(void)
+{ Ordered *walk;
+ char buf[128];
+ extern int Caccess, separate;
+ extern short has_code;
+
+ for (walk = all_names; walk; walk = walk->next)
+ { if (!walk->entry->owner)
+ switch (walk->entry->type) {
+ case CHAN:
+ if (Caccess) chan_check(walk->entry);
+ break;
+ case MTYPE:
+ case BIT:
+ case BYTE:
+ case SHORT:
+ case INT:
+ case UNSIGNED:
+ if ((walk->entry->hidden&128)) /* was: 32 */
+ continue;
+
+ if (!separate
+ && !walk->entry->context
+ && !has_code
+ && deadvar)
+ walk->entry->hidden |= 1; /* auto-hide */
+
+ if (!(verbose&32) || has_code) continue;
+
+ printf("spin: warning, %s, ", Fname->name);
+ sputtype(buf, walk->entry->type);
+ if (walk->entry->context)
+ printf("proctype %s",
+ walk->entry->context->name);
+ else
+ printf("global");
+ printf(", '%s%s' variable is never used\n",
+ buf, walk->entry->name);
+ } }
+}
diff --git a/sys/src/cmd/spin/tl.h b/sys/src/cmd/spin/tl.h
new file mode 100755
index 000000000..eaa2056c8
--- /dev/null
+++ b/sys/src/cmd/spin/tl.h
@@ -0,0 +1,128 @@
+/***** tl_spin: tl.h *****/
+
+/* Copyright (c) 1995-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 */
+
+/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
+/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
+
+#include <stdio.h>
+#include <string.h>
+
+typedef struct Symbol {
+ char *name;
+ struct Symbol *next; /* linked list, symbol table */
+} Symbol;
+
+typedef struct Node {
+ short ntyp; /* node type */
+ struct Symbol *sym;
+ struct Node *lft; /* tree */
+ struct Node *rgt; /* tree */
+ struct Node *nxt; /* if linked list */
+} Node;
+
+typedef struct Graph {
+ Symbol *name;
+ Symbol *incoming;
+ Symbol *outgoing;
+ Symbol *oldstring;
+ Symbol *nxtstring;
+ Node *New;
+ Node *Old;
+ Node *Other;
+ Node *Next;
+ unsigned char isred[64], isgrn[64];
+ unsigned char redcnt, grncnt;
+ unsigned char reachable;
+ struct Graph *nxt;
+} Graph;
+
+typedef struct Mapping {
+ char *from;
+ Graph *to;
+ struct Mapping *nxt;
+} Mapping;
+
+enum {
+ ALWAYS=257,
+ AND, /* 258 */
+ EQUIV, /* 259 */
+ EVENTUALLY, /* 260 */
+ FALSE, /* 261 */
+ IMPLIES, /* 262 */
+ NOT, /* 263 */
+ OR, /* 264 */
+ PREDICATE, /* 265 */
+ TRUE, /* 266 */
+ U_OPER, /* 267 */
+ V_OPER /* 268 */
+#ifdef NXT
+ , NEXT /* 269 */
+#endif
+};
+
+Node *Canonical(Node *);
+Node *canonical(Node *);
+Node *cached(Node *);
+Node *dupnode(Node *);
+Node *getnode(Node *);
+Node *in_cache(Node *);
+Node *push_negation(Node *);
+Node *right_linked(Node *);
+Node *tl_nn(int, Node *, Node *);
+
+Symbol *tl_lookup(char *);
+Symbol *getsym(Symbol *);
+Symbol *DoDump(Node *);
+
+char *emalloc(int); /* in main.c */
+
+int anywhere(int, Node *, Node *);
+int dump_cond(Node *, Node *, int);
+int hash(char *); /* in sym.c */
+int isalnum_(int); /* in spinlex.c */
+int isequal(Node *, Node *);
+int tl_Getchar(void);
+
+void *tl_emalloc(int);
+void a_stats(void);
+void addtrans(Graph *, char *, Node *, char *);
+void cache_stats(void);
+void dump(Node *);
+void exit(int);
+void Fatal(char *, char *);
+void fatal(char *, char *);
+void fsm_print(void);
+void releasenode(int, Node *);
+void tfree(void *);
+void tl_explain(int);
+void tl_UnGetchar(void);
+void tl_parse(void);
+void tl_yyerror(char *);
+void trans(Node *);
+
+#define ZN (Node *)0
+#define ZS (Symbol *)0
+#define Nhash 255 /* must match size in spin.h */
+#define True tl_nn(TRUE, ZN, ZN)
+#define False tl_nn(FALSE, ZN, ZN)
+#define Not(a) push_negation(tl_nn(NOT, a, ZN))
+#define rewrite(n) canonical(right_linked(n))
+
+typedef Node *Nodeptr;
+#define YYSTYPE Nodeptr
+
+#define Debug(x) { if (tl_verbose) printf(x); }
+#define Debug2(x,y) { if (tl_verbose) printf(x,y); }
+#define Dump(x) { if (tl_verbose) dump(x); }
+#define Explain(x) { if (tl_verbose) tl_explain(x); }
+
+#define Assert(x, y) { if (!(x)) { tl_explain(y); \
+ Fatal(": assertion failed\n",(char *)0); } }
diff --git a/sys/src/cmd/spin/tl_buchi.c b/sys/src/cmd/spin/tl_buchi.c
new file mode 100755
index 000000000..161661950
--- /dev/null
+++ b/sys/src/cmd/spin/tl_buchi.c
@@ -0,0 +1,666 @@
+/***** tl_spin: tl_buchi.c *****/
+
+/* Copyright (c) 1995-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 */
+
+/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
+/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
+
+#include "tl.h"
+
+extern int tl_verbose, tl_clutter, Total, Max_Red;
+
+FILE *tl_out; /* if standalone: = stdout; */
+
+typedef struct Transition {
+ Symbol *name;
+ Node *cond;
+ int redundant, merged, marked;
+ struct Transition *nxt;
+} Transition;
+
+typedef struct State {
+ Symbol *name;
+ Transition *trans;
+ Graph *colors;
+ unsigned char redundant;
+ unsigned char accepting;
+ unsigned char reachable;
+ struct State *nxt;
+} State;
+
+static State *never = (State *) 0;
+static int hitsall;
+
+static int
+sametrans(Transition *s, Transition *t)
+{
+ if (strcmp(s->name->name, t->name->name) != 0)
+ return 0;
+ return isequal(s->cond, t->cond);
+}
+
+static Node *
+Prune(Node *p)
+{
+ if (p)
+ switch (p->ntyp) {
+ case PREDICATE:
+ case NOT:
+ case FALSE:
+ case TRUE:
+#ifdef NXT
+ case NEXT:
+#endif
+ return p;
+ case OR:
+ p->lft = Prune(p->lft);
+ if (!p->lft)
+ { releasenode(1, p->rgt);
+ return ZN;
+ }
+ p->rgt = Prune(p->rgt);
+ if (!p->rgt)
+ { releasenode(1, p->lft);
+ return ZN;
+ }
+ return p;
+ case AND:
+ p->lft = Prune(p->lft);
+ if (!p->lft)
+ return Prune(p->rgt);
+ p->rgt = Prune(p->rgt);
+ if (!p->rgt)
+ return p->lft;
+ return p;
+ }
+ releasenode(1, p);
+ return ZN;
+}
+
+static State *
+findstate(char *nm)
+{ State *b;
+ for (b = never; b; b = b->nxt)
+ if (!strcmp(b->name->name, nm))
+ return b;
+ if (strcmp(nm, "accept_all"))
+ { if (strncmp(nm, "accept", 6))
+ { int i; char altnm[64];
+ for (i = 0; i < 64; i++)
+ if (nm[i] == '_')
+ break;
+ if (i >= 64)
+ Fatal("name too long %s", nm);
+ sprintf(altnm, "accept%s", &nm[i]);
+ return findstate(altnm);
+ }
+ /* Fatal("buchi: no state %s", nm); */
+ }
+ return (State *) 0;
+}
+
+static void
+Dfs(State *b)
+{ Transition *t;
+
+ if (!b || b->reachable) return;
+ b->reachable = 1;
+
+ if (b->redundant)
+ printf("/* redundant state %s */\n",
+ b->name->name);
+ for (t = b->trans; t; t = t->nxt)
+ { if (!t->redundant)
+ { Dfs(findstate(t->name->name));
+ if (!hitsall
+ && strcmp(t->name->name, "accept_all") == 0)
+ hitsall = 1;
+ }
+ }
+}
+
+void
+retarget(char *from, char *to)
+{ State *b;
+ Transition *t;
+ Symbol *To = tl_lookup(to);
+
+ if (tl_verbose) printf("replace %s with %s\n", from, to);
+
+ for (b = never; b; b = b->nxt)
+ { if (!strcmp(b->name->name, from))
+ b->redundant = 1;
+ else
+ for (t = b->trans; t; t = t->nxt)
+ { if (!strcmp(t->name->name, from))
+ t->name = To;
+ } }
+}
+
+#ifdef NXT
+static Node *
+nonxt(Node *n)
+{
+ switch (n->ntyp) {
+ case U_OPER:
+ case V_OPER:
+ case NEXT:
+ return ZN;
+ case OR:
+ n->lft = nonxt(n->lft);
+ n->rgt = nonxt(n->rgt);
+ if (!n->lft || !n->rgt)
+ return True;
+ return n;
+ case AND:
+ n->lft = nonxt(n->lft);
+ n->rgt = nonxt(n->rgt);
+ if (!n->lft)
+ { if (!n->rgt)
+ n = ZN;
+ else
+ n = n->rgt;
+ } else if (!n->rgt)
+ n = n->lft;
+ return n;
+ }
+ return n;
+}
+#endif
+
+static Node *
+combination(Node *s, Node *t)
+{ Node *nc;
+#ifdef NXT
+ Node *a = nonxt(s);
+ Node *b = nonxt(t);
+
+ if (tl_verbose)
+ { printf("\tnonxtA: "); dump(a);
+ printf("\n\tnonxtB: "); dump(b);
+ printf("\n");
+ }
+ /* if there's only a X(f), its equivalent to true */
+ if (!a || !b)
+ nc = True;
+ else
+ nc = tl_nn(OR, a, b);
+#else
+ nc = tl_nn(OR, s, t);
+#endif
+ if (tl_verbose)
+ { printf("\tcombo: "); dump(nc);
+ printf("\n");
+ }
+ return nc;
+}
+
+Node *
+unclutter(Node *n, char *snm)
+{ Node *t, *s, *v, *u;
+ Symbol *w;
+
+ /* check only simple cases like !q && q */
+ for (t = n; t; t = t->rgt)
+ { if (t->rgt)
+ { if (t->ntyp != AND || !t->lft)
+ return n;
+ if (t->lft->ntyp != PREDICATE
+#ifdef NXT
+ && t->lft->ntyp != NEXT
+#endif
+ && t->lft->ntyp != NOT)
+ return n;
+ } else
+ { if (t->ntyp != PREDICATE
+#ifdef NXT
+ && t->ntyp != NEXT
+#endif
+ && t->ntyp != NOT)
+ return n;
+ }
+ }
+
+ for (t = n; t; t = t->rgt)
+ { if (t->rgt)
+ v = t->lft;
+ else
+ v = t;
+ if (v->ntyp == NOT
+ && v->lft->ntyp == PREDICATE)
+ { w = v->lft->sym;
+ for (s = n; s; s = s->rgt)
+ { if (s == t) continue;
+ if (s->rgt)
+ u = s->lft;
+ else
+ u = s;
+ if (u->ntyp == PREDICATE
+ && strcmp(u->sym->name, w->name) == 0)
+ { if (tl_verbose)
+ { printf("BINGO %s:\t", snm);
+ dump(n);
+ printf("\n");
+ }
+ return False;
+ }
+ }
+ } }
+ return n;
+}
+
+static void
+clutter(void)
+{ State *p;
+ Transition *s;
+
+ for (p = never; p; p = p->nxt)
+ for (s = p->trans; s; s = s->nxt)
+ { s->cond = unclutter(s->cond, p->name->name);
+ if (s->cond
+ && s->cond->ntyp == FALSE)
+ { if (s != p->trans
+ || s->nxt)
+ s->redundant = 1;
+ }
+ }
+}
+
+static void
+showtrans(State *a)
+{ Transition *s;
+
+ for (s = a->trans; s; s = s->nxt)
+ { printf("%s ", s->name?s->name->name:"-");
+ dump(s->cond);
+ printf(" %d %d %d\n", s->redundant, s->merged, s->marked);
+ }
+}
+
+static int
+mergetrans(void)
+{ State *b;
+ Transition *s, *t;
+ Node *nc; int cnt = 0;
+
+ for (b = never; b; b = b->nxt)
+ { if (!b->reachable) continue;
+
+ for (s = b->trans; s; s = s->nxt)
+ { if (s->redundant) continue;
+
+ for (t = s->nxt; t; t = t->nxt)
+ if (!t->redundant
+ && !strcmp(s->name->name, t->name->name))
+ { if (tl_verbose)
+ { printf("===\nstate %s, trans to %s redundant\n",
+ b->name->name, s->name->name);
+ showtrans(b);
+ printf(" conditions ");
+ dump(s->cond); printf(" <-> ");
+ dump(t->cond); printf("\n");
+ }
+
+ if (!s->cond) /* same as T */
+ { releasenode(1, t->cond); /* T or t */
+ nc = True;
+ } else if (!t->cond)
+ { releasenode(1, s->cond);
+ nc = True;
+ } else
+ { nc = combination(s->cond, t->cond);
+ }
+ t->cond = rewrite(nc);
+ t->merged = 1;
+ s->redundant = 1;
+ cnt++;
+ break;
+ } } }
+ return cnt;
+}
+
+static int
+all_trans_match(State *a, State *b)
+{ Transition *s, *t;
+ int found, result = 0;
+
+ if (a->accepting != b->accepting)
+ goto done;
+
+ for (s = a->trans; s; s = s->nxt)
+ { if (s->redundant) continue;
+ found = 0;
+ for (t = b->trans; t; t = t->nxt)
+ { if (t->redundant) continue;
+ if (sametrans(s, t))
+ { found = 1;
+ t->marked = 1;
+ break;
+ } }
+ if (!found)
+ goto done;
+ }
+ for (s = b->trans; s; s = s->nxt)
+ { if (s->redundant || s->marked) continue;
+ found = 0;
+ for (t = a->trans; t; t = t->nxt)
+ { if (t->redundant) continue;
+ if (sametrans(s, t))
+ { found = 1;
+ break;
+ } }
+ if (!found)
+ goto done;
+ }
+ result = 1;
+done:
+ for (s = b->trans; s; s = s->nxt)
+ s->marked = 0;
+ return result;
+}
+
+#ifndef NO_OPT
+#define BUCKY
+#endif
+
+#ifdef BUCKY
+static int
+all_bucky(State *a, State *b)
+{ Transition *s, *t;
+ int found, result = 0;
+
+ for (s = a->trans; s; s = s->nxt)
+ { if (s->redundant) continue;
+ found = 0;
+ for (t = b->trans; t; t = t->nxt)
+ { if (t->redundant) continue;
+
+ if (isequal(s->cond, t->cond))
+ { if (strcmp(s->name->name, b->name->name) == 0
+ && strcmp(t->name->name, a->name->name) == 0)
+ { found = 1; /* they point to each other */
+ t->marked = 1;
+ break;
+ }
+ if (strcmp(s->name->name, t->name->name) == 0
+ && strcmp(s->name->name, "accept_all") == 0)
+ { found = 1;
+ t->marked = 1;
+ break;
+ /* same exit from which there is no return */
+ }
+ }
+ }
+ if (!found)
+ goto done;
+ }
+ for (s = b->trans; s; s = s->nxt)
+ { if (s->redundant || s->marked) continue;
+ found = 0;
+ for (t = a->trans; t; t = t->nxt)
+ { if (t->redundant) continue;
+
+ if (isequal(s->cond, t->cond))
+ { if (strcmp(s->name->name, a->name->name) == 0
+ && strcmp(t->name->name, b->name->name) == 0)
+ { found = 1;
+ t->marked = 1;
+ break;
+ }
+ if (strcmp(s->name->name, t->name->name) == 0
+ && strcmp(s->name->name, "accept_all") == 0)
+ { found = 1;
+ t->marked = 1;
+ break;
+ }
+ }
+ }
+ if (!found)
+ goto done;
+ }
+ result = 1;
+done:
+ for (s = b->trans; s; s = s->nxt)
+ s->marked = 0;
+ return result;
+}
+
+static int
+buckyballs(void)
+{ State *a, *b, *c, *d;
+ int m, cnt=0;
+
+ do {
+ m = 0; cnt++;
+ for (a = never; a; a = a->nxt)
+ { if (!a->reachable) continue;
+
+ if (a->redundant) continue;
+
+ for (b = a->nxt; b; b = b->nxt)
+ { if (!b->reachable) continue;
+
+ if (b->redundant) continue;
+
+ if (all_bucky(a, b))
+ { m++;
+ if (tl_verbose)
+ { printf("%s bucky match %s\n",
+ a->name->name, b->name->name);
+ }
+
+ if (a->accepting && !b->accepting)
+ { if (strcmp(b->name->name, "T0_init") == 0)
+ { c = a; d = b;
+ b->accepting = 1;
+ } else
+ { c = b; d = a;
+ }
+ } else
+ { c = a; d = b;
+ }
+
+ retarget(c->name->name, d->name->name);
+ if (!strncmp(c->name->name, "accept", 6)
+ && Max_Red == 0)
+ { char buf[64];
+ sprintf(buf, "T0%s", &(c->name->name[6]));
+ retarget(buf, d->name->name);
+ }
+ break;
+ }
+ } }
+ } while (m && cnt < 10);
+ return cnt-1;
+}
+#endif
+
+static int
+mergestates(int v)
+{ State *a, *b;
+ int m, cnt=0;
+
+ if (tl_verbose)
+ return 0;
+
+ do {
+ m = 0; cnt++;
+ for (a = never; a; a = a->nxt)
+ { if (v && !a->reachable) continue;
+
+ if (a->redundant) continue; /* 3.3.10 */
+
+ for (b = a->nxt; b; b = b->nxt)
+ { if (v && !b->reachable) continue;
+
+ if (b->redundant) continue; /* 3.3.10 */
+
+ if (all_trans_match(a, b))
+ { m++;
+ if (tl_verbose)
+ { printf("%d: state %s equals state %s\n",
+ cnt, a->name->name, b->name->name);
+ showtrans(a);
+ printf("==\n");
+ showtrans(b);
+ }
+ retarget(a->name->name, b->name->name);
+ if (!strncmp(a->name->name, "accept", 6)
+ && Max_Red == 0)
+ { char buf[64];
+ sprintf(buf, "T0%s", &(a->name->name[6]));
+ retarget(buf, b->name->name);
+ }
+ break;
+ }
+#if 0
+ else if (tl_verbose)
+ { printf("\n%d: state %s differs from state %s [%d,%d]\n",
+ cnt, a->name->name, b->name->name,
+ a->accepting, b->accepting);
+ showtrans(a);
+ printf("==\n");
+ showtrans(b);
+ printf("\n");
+ }
+#endif
+ } }
+ } while (m && cnt < 10);
+ return cnt-1;
+}
+
+static int tcnt;
+
+static void
+rev_trans(Transition *t) /* print transitions in reverse order... */
+{
+ if (!t) return;
+ rev_trans(t->nxt);
+
+ if (t->redundant && !tl_verbose) return;
+ fprintf(tl_out, "\t:: (");
+ if (dump_cond(t->cond, t->cond, 1))
+ fprintf(tl_out, "1");
+ fprintf(tl_out, ") -> goto %s\n", t->name->name);
+ tcnt++;
+}
+
+static void
+printstate(State *b)
+{
+ if (!b || (!tl_verbose && !b->reachable)) return;
+
+ b->reachable = 0; /* print only once */
+ fprintf(tl_out, "%s:\n", b->name->name);
+
+ if (tl_verbose)
+ { fprintf(tl_out, " /* ");
+ dump(b->colors->Other);
+ fprintf(tl_out, " */\n");
+ }
+
+ if (strncmp(b->name->name, "accept", 6) == 0
+ && Max_Red == 0)
+ fprintf(tl_out, "T0%s:\n", &(b->name->name[6]));
+
+ fprintf(tl_out, "\tif\n");
+ tcnt = 0;
+ rev_trans(b->trans);
+ if (!tcnt) fprintf(tl_out, "\t:: false\n");
+ fprintf(tl_out, "\tfi;\n");
+ Total++;
+}
+
+void
+addtrans(Graph *col, char *from, Node *op, char *to)
+{ State *b;
+ Transition *t;
+
+ t = (Transition *) tl_emalloc(sizeof(Transition));
+ t->name = tl_lookup(to);
+ t->cond = Prune(dupnode(op));
+
+ if (tl_verbose)
+ { printf("\n%s <<\t", from); dump(op);
+ printf("\n\t"); dump(t->cond);
+ printf(">> %s\n", t->name->name);
+ }
+ if (t->cond) t->cond = rewrite(t->cond);
+
+ for (b = never; b; b = b->nxt)
+ if (!strcmp(b->name->name, from))
+ { t->nxt = b->trans;
+ b->trans = t;
+ return;
+ }
+ b = (State *) tl_emalloc(sizeof(State));
+ b->name = tl_lookup(from);
+ b->colors = col;
+ b->trans = t;
+ if (!strncmp(from, "accept", 6))
+ b->accepting = 1;
+ b->nxt = never;
+ never = b;
+}
+
+static void
+clr_reach(void)
+{ State *p;
+ for (p = never; p; p = p->nxt)
+ p->reachable = 0;
+ hitsall = 0;
+}
+
+void
+fsm_print(void)
+{ State *b; int cnt1, cnt2=0;
+ extern void put_uform(void);
+
+ if (tl_clutter) clutter();
+
+ b = findstate("T0_init");
+ if (Max_Red == 0)
+ b->accepting = 1;
+
+ mergestates(0);
+ b = findstate("T0_init");
+
+ fprintf(tl_out, "never { /* ");
+ put_uform();
+ fprintf(tl_out, " */\n");
+
+ do {
+ clr_reach();
+ Dfs(b);
+ cnt1 = mergetrans();
+ cnt2 = mergestates(1);
+ if (tl_verbose)
+ printf("/* >>%d,%d<< */\n", cnt1, cnt2);
+ } while (cnt2 > 0);
+
+#ifdef BUCKY
+ buckyballs();
+ clr_reach();
+ Dfs(b);
+#endif
+ if (b && b->accepting)
+ fprintf(tl_out, "accept_init:\n");
+
+ if (!b && !never)
+ { fprintf(tl_out, " 0 /* false */;\n");
+ } else
+ { printstate(b); /* init state must be first */
+ for (b = never; b; b = b->nxt)
+ printstate(b);
+ }
+ if (hitsall)
+ fprintf(tl_out, "accept_all:\n skip\n");
+ fprintf(tl_out, "}\n");
+}
diff --git a/sys/src/cmd/spin/tl_cache.c b/sys/src/cmd/spin/tl_cache.c
new file mode 100755
index 000000000..fc902dcb0
--- /dev/null
+++ b/sys/src/cmd/spin/tl_cache.c
@@ -0,0 +1,328 @@
+/***** tl_spin: tl_cache.c *****/
+
+/* Copyright (c) 1995-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 */
+
+/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
+/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
+
+#include "tl.h"
+
+typedef struct Cache {
+ Node *before;
+ Node *after;
+ int same;
+ struct Cache *nxt;
+} Cache;
+
+static Cache *stored = (Cache *) 0;
+static unsigned long Caches, CacheHits;
+
+static int ismatch(Node *, Node *);
+extern void fatal(char *, char *);
+int sameform(Node *, Node *);
+
+#if 0
+void
+cache_dump(void)
+{ Cache *d; int nr=0;
+
+ printf("\nCACHE DUMP:\n");
+ for (d = stored; d; d = d->nxt, nr++)
+ { if (d->same) continue;
+ printf("B%3d: ", nr); dump(d->before); printf("\n");
+ printf("A%3d: ", nr); dump(d->after); printf("\n");
+ }
+ printf("============\n");
+}
+#endif
+
+Node *
+in_cache(Node *n)
+{ Cache *d; int nr=0;
+
+ for (d = stored; d; d = d->nxt, nr++)
+ if (isequal(d->before, n))
+ { CacheHits++;
+ if (d->same && ismatch(n, d->before)) return n;
+ return dupnode(d->after);
+ }
+ return ZN;
+}
+
+Node *
+cached(Node *n)
+{ Cache *d;
+ Node *m;
+
+ if (!n) return n;
+ if ((m = in_cache(n)) != ZN)
+ return m;
+
+ Caches++;
+ d = (Cache *) tl_emalloc(sizeof(Cache));
+ d->before = dupnode(n);
+ d->after = Canonical(n); /* n is released */
+
+ if (ismatch(d->before, d->after))
+ { d->same = 1;
+ releasenode(1, d->after);
+ d->after = d->before;
+ }
+ d->nxt = stored;
+ stored = d;
+ return dupnode(d->after);
+}
+
+void
+cache_stats(void)
+{
+ printf("cache stores : %9ld\n", Caches);
+ printf("cache hits : %9ld\n", CacheHits);
+}
+
+void
+releasenode(int all_levels, Node *n)
+{
+ if (!n) return;
+
+ if (all_levels)
+ { releasenode(1, n->lft);
+ n->lft = ZN;
+ releasenode(1, n->rgt);
+ n->rgt = ZN;
+ }
+ tfree((void *) n);
+}
+
+Node *
+tl_nn(int t, Node *ll, Node *rl)
+{ Node *n = (Node *) tl_emalloc(sizeof(Node));
+
+ n->ntyp = (short) t;
+ n->lft = ll;
+ n->rgt = rl;
+
+ return n;
+}
+
+Node *
+getnode(Node *p)
+{ Node *n;
+
+ if (!p) return p;
+
+ n = (Node *) tl_emalloc(sizeof(Node));
+ n->ntyp = p->ntyp;
+ n->sym = p->sym; /* same name */
+ n->lft = p->lft;
+ n->rgt = p->rgt;
+
+ return n;
+}
+
+Node *
+dupnode(Node *n)
+{ Node *d;
+
+ if (!n) return n;
+ d = getnode(n);
+ d->lft = dupnode(n->lft);
+ d->rgt = dupnode(n->rgt);
+ return d;
+}
+
+int
+one_lft(int ntyp, Node *x, Node *in)
+{
+ if (!x) return 1;
+ if (!in) return 0;
+
+ if (sameform(x, in))
+ return 1;
+
+ if (in->ntyp != ntyp)
+ return 0;
+
+ if (one_lft(ntyp, x, in->lft))
+ return 1;
+
+ return one_lft(ntyp, x, in->rgt);
+}
+
+int
+all_lfts(int ntyp, Node *from, Node *in)
+{
+ if (!from) return 1;
+
+ if (from->ntyp != ntyp)
+ return one_lft(ntyp, from, in);
+
+ if (!one_lft(ntyp, from->lft, in))
+ return 0;
+
+ return all_lfts(ntyp, from->rgt, in);
+}
+
+int
+sametrees(int ntyp, Node *a, Node *b)
+{ /* toplevel is an AND or OR */
+ /* both trees are right-linked, but the leafs */
+ /* can be in different places in the two trees */
+
+ if (!all_lfts(ntyp, a, b))
+ return 0;
+
+ return all_lfts(ntyp, b, a);
+}
+
+int /* a better isequal() */
+sameform(Node *a, Node *b)
+{
+ if (!a && !b) return 1;
+ if (!a || !b) return 0;
+ if (a->ntyp != b->ntyp) return 0;
+
+ if (a->sym
+ && b->sym
+ && strcmp(a->sym->name, b->sym->name) != 0)
+ return 0;
+
+ switch (a->ntyp) {
+ case TRUE:
+ case FALSE:
+ return 1;
+ case PREDICATE:
+ if (!a->sym || !b->sym) fatal("sameform...", (char *) 0);
+ return !strcmp(a->sym->name, b->sym->name);
+
+ case NOT:
+#ifdef NXT
+ case NEXT:
+#endif
+ return sameform(a->lft, b->lft);
+ case U_OPER:
+ case V_OPER:
+ if (!sameform(a->lft, b->lft))
+ return 0;
+ if (!sameform(a->rgt, b->rgt))
+ return 0;
+ return 1;
+
+ case AND:
+ case OR: /* the hard case */
+ return sametrees(a->ntyp, a, b);
+
+ default:
+ printf("type: %d\n", a->ntyp);
+ fatal("cannot happen, sameform", (char *) 0);
+ }
+
+ return 0;
+}
+
+int
+isequal(Node *a, Node *b)
+{
+ if (!a && !b)
+ return 1;
+
+ if (!a || !b)
+ { if (!a)
+ { if (b->ntyp == TRUE)
+ return 1;
+ } else
+ { if (a->ntyp == TRUE)
+ return 1;
+ }
+ return 0;
+ }
+ if (a->ntyp != b->ntyp)
+ return 0;
+
+ if (a->sym
+ && b->sym
+ && strcmp(a->sym->name, b->sym->name) != 0)
+ return 0;
+
+ if (isequal(a->lft, b->lft)
+ && isequal(a->rgt, b->rgt))
+ return 1;
+
+ return sameform(a, b);
+}
+
+static int
+ismatch(Node *a, Node *b)
+{
+ if (!a && !b) return 1;
+ if (!a || !b) return 0;
+ if (a->ntyp != b->ntyp) return 0;
+
+ if (a->sym
+ && b->sym
+ && strcmp(a->sym->name, b->sym->name) != 0)
+ return 0;
+
+ if (ismatch(a->lft, b->lft)
+ && ismatch(a->rgt, b->rgt))
+ return 1;
+
+ return 0;
+}
+
+int
+any_term(Node *srch, Node *in)
+{
+ if (!in) return 0;
+
+ if (in->ntyp == AND)
+ return any_term(srch, in->lft) ||
+ any_term(srch, in->rgt);
+
+ return isequal(in, srch);
+}
+
+int
+any_and(Node *srch, Node *in)
+{
+ if (!in) return 0;
+
+ if (srch->ntyp == AND)
+ return any_and(srch->lft, in) &&
+ any_and(srch->rgt, in);
+
+ return any_term(srch, in);
+}
+
+int
+any_lor(Node *srch, Node *in)
+{
+ if (!in) return 0;
+
+ if (in->ntyp == OR)
+ return any_lor(srch, in->lft) ||
+ any_lor(srch, in->rgt);
+
+ return isequal(in, srch);
+}
+
+int
+anywhere(int tok, Node *srch, Node *in)
+{
+ if (!in) return 0;
+
+ switch (tok) {
+ case AND: return any_and(srch, in);
+ case OR: return any_lor(srch, in);
+ case 0: return any_term(srch, in);
+ }
+ fatal("cannot happen, anywhere", (char *) 0);
+ return 0;
+}
diff --git a/sys/src/cmd/spin/tl_lex.c b/sys/src/cmd/spin/tl_lex.c
new file mode 100755
index 000000000..110e06eae
--- /dev/null
+++ b/sys/src/cmd/spin/tl_lex.c
@@ -0,0 +1,148 @@
+/***** tl_spin: tl_lex.c *****/
+
+/* Copyright (c) 1995-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 */
+
+/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
+/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include "tl.h"
+
+static Symbol *symtab[Nhash+1];
+static int tl_lex(void);
+
+extern YYSTYPE tl_yylval;
+extern char yytext[];
+
+#define Token(y) tl_yylval = tl_nn(y,ZN,ZN); return y
+
+static void
+tl_getword(int first, int (*tst)(int))
+{ int i=0; char c;
+
+ yytext[i++] = (char ) first;
+ while (tst(c = tl_Getchar()))
+ yytext[i++] = c;
+ yytext[i] = '\0';
+ tl_UnGetchar();
+}
+
+static int
+tl_follow(int tok, int ifyes, int ifno)
+{ int c;
+ char buf[32];
+ extern int tl_yychar;
+
+ if ((c = tl_Getchar()) == tok)
+ return ifyes;
+ tl_UnGetchar();
+ tl_yychar = c;
+ sprintf(buf, "expected '%c'", tok);
+ tl_yyerror(buf); /* no return from here */
+ return ifno;
+}
+
+int
+tl_yylex(void)
+{ int c = tl_lex();
+#if 0
+ printf("c = %d\n", c);
+#endif
+ return c;
+}
+
+static int
+tl_lex(void)
+{ int c;
+
+ do {
+ c = tl_Getchar();
+ yytext[0] = (char ) c;
+ yytext[1] = '\0';
+
+ if (c <= 0)
+ { Token(';');
+ }
+
+ } while (c == ' '); /* '\t' is removed in tl_main.c */
+
+ if (islower(c))
+ { tl_getword(c, isalnum_);
+ if (strcmp("true", yytext) == 0)
+ { Token(TRUE);
+ }
+ if (strcmp("false", yytext) == 0)
+ { Token(FALSE);
+ }
+ tl_yylval = tl_nn(PREDICATE,ZN,ZN);
+ tl_yylval->sym = tl_lookup(yytext);
+ return PREDICATE;
+ }
+ if (c == '<')
+ { c = tl_Getchar();
+ if (c == '>')
+ { Token(EVENTUALLY);
+ }
+ if (c != '-')
+ { tl_UnGetchar();
+ tl_yyerror("expected '<>' or '<->'");
+ }
+ c = tl_Getchar();
+ if (c == '>')
+ { Token(EQUIV);
+ }
+ tl_UnGetchar();
+ tl_yyerror("expected '<->'");
+ }
+
+ switch (c) {
+ case '/' : c = tl_follow('\\', AND, '/'); break;
+ case '\\': c = tl_follow('/', OR, '\\'); break;
+ case '&' : c = tl_follow('&', AND, '&'); break;
+ case '|' : c = tl_follow('|', OR, '|'); break;
+ case '[' : c = tl_follow(']', ALWAYS, '['); break;
+ case '-' : c = tl_follow('>', IMPLIES, '-'); break;
+ case '!' : c = NOT; break;
+ case 'U' : c = U_OPER; break;
+ case 'V' : c = V_OPER; break;
+#ifdef NXT
+ case 'X' : c = NEXT; break;
+#endif
+ default : break;
+ }
+ Token(c);
+}
+
+Symbol *
+tl_lookup(char *s)
+{ Symbol *sp;
+ int h = hash(s);
+
+ for (sp = symtab[h]; sp; sp = sp->next)
+ if (strcmp(sp->name, s) == 0)
+ return sp;
+
+ sp = (Symbol *) tl_emalloc(sizeof(Symbol));
+ sp->name = (char *) tl_emalloc((int) strlen(s) + 1);
+ strcpy(sp->name, s);
+ sp->next = symtab[h];
+ symtab[h] = sp;
+
+ return sp;
+}
+
+Symbol *
+getsym(Symbol *s)
+{ Symbol *n = (Symbol *) tl_emalloc(sizeof(Symbol));
+
+ n->name = s->name;
+ return n;
+}
diff --git a/sys/src/cmd/spin/tl_main.c b/sys/src/cmd/spin/tl_main.c
new file mode 100755
index 000000000..10ab0e9bd
--- /dev/null
+++ b/sys/src/cmd/spin/tl_main.c
@@ -0,0 +1,234 @@
+/***** tl_spin: tl_main.c *****/
+
+/* Copyright (c) 1995-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 */
+
+/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
+/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
+
+#include "tl.h"
+
+extern FILE *tl_out;
+
+int newstates = 0; /* debugging only */
+int tl_errs = 0;
+int tl_verbose = 0;
+int tl_terse = 0;
+int tl_clutter = 0;
+unsigned long All_Mem = 0;
+
+static char uform[4096];
+static int hasuform=0, cnt=0;
+
+extern void cache_stats(void);
+extern void a_stats(void);
+
+int
+tl_Getchar(void)
+{
+ if (cnt < hasuform)
+ return uform[cnt++];
+ cnt++;
+ return -1;
+}
+
+void
+tl_balanced(void)
+{ int i;
+ int k = 0;
+
+ for (i = 0; i < hasuform; i++)
+ { if (uform[i] == '(')
+ { k++;
+ } else if (uform[i] == ')')
+ { k--;
+ } }
+ if (k != 0)
+ { tl_errs++;
+ tl_yyerror("parentheses not balanced");
+ }
+}
+
+void
+put_uform(void)
+{
+ fprintf(tl_out, "%s", uform);
+}
+
+void
+tl_UnGetchar(void)
+{
+ if (cnt > 0) cnt--;
+}
+
+static void
+tl_stats(void)
+{ extern int Stack_mx;
+ printf("total memory used: %9ld\n", All_Mem);
+ printf("largest stack sze: %9d\n", Stack_mx);
+ cache_stats();
+ a_stats();
+}
+
+int
+tl_main(int argc, char *argv[])
+{ int i;
+ extern int verbose, xspin;
+ tl_verbose = verbose;
+ tl_clutter = 1-xspin; /* use -X -f to turn off uncluttering */
+
+ while (argc > 1 && argv[1][0] == '-')
+ { switch (argv[1][1]) {
+ case 'd': newstates = 1; /* debugging mode */
+ break;
+ case 'f': argc--; argv++;
+ for (i = 0; i < argv[1][i]; i++)
+ { if (argv[1][i] == '\t'
+ || argv[1][i] == '\"'
+ || argv[1][i] == '\n')
+ argv[1][i] = ' ';
+ }
+ strcpy(uform, argv[1]);
+ hasuform = (int) strlen(uform);
+ break;
+ case 'v': tl_verbose++;
+ break;
+ case 'n': tl_terse = 1;
+ break;
+ default : printf("spin -f: saw '-%c'\n", argv[1][1]);
+ goto nogood;
+ }
+ argc--; argv++;
+ }
+ if (hasuform == 0)
+ {
+nogood: printf("usage:\tspin [-v] [-n] -f formula\n");
+ printf(" -v verbose translation\n");
+ printf(" -n normalize tl formula and exit\n");
+ exit(1);
+ }
+ tl_balanced();
+
+ if (tl_errs == 0)
+ tl_parse();
+
+ if (tl_verbose) tl_stats();
+ return tl_errs;
+}
+
+#define Binop(a) \
+ fprintf(tl_out, "("); \
+ dump(n->lft); \
+ fprintf(tl_out, a); \
+ dump(n->rgt); \
+ fprintf(tl_out, ")")
+
+void
+dump(Node *n)
+{
+ if (!n) return;
+
+ switch(n->ntyp) {
+ case OR: Binop(" || "); break;
+ case AND: Binop(" && "); break;
+ case U_OPER: Binop(" U "); break;
+ case V_OPER: Binop(" V "); break;
+#ifdef NXT
+ case NEXT:
+ fprintf(tl_out, "X");
+ fprintf(tl_out, " (");
+ dump(n->lft);
+ fprintf(tl_out, ")");
+ break;
+#endif
+ case NOT:
+ fprintf(tl_out, "!");
+ fprintf(tl_out, " (");
+ dump(n->lft);
+ fprintf(tl_out, ")");
+ break;
+ case FALSE:
+ fprintf(tl_out, "false");
+ break;
+ case TRUE:
+ fprintf(tl_out, "true");
+ break;
+ case PREDICATE:
+ fprintf(tl_out, "(%s)", n->sym->name);
+ break;
+ case -1:
+ fprintf(tl_out, " D ");
+ break;
+ default:
+ printf("Unknown token: ");
+ tl_explain(n->ntyp);
+ break;
+ }
+}
+
+void
+tl_explain(int n)
+{
+ switch (n) {
+ case ALWAYS: printf("[]"); break;
+ case EVENTUALLY: printf("<>"); break;
+ case IMPLIES: printf("->"); break;
+ case EQUIV: printf("<->"); break;
+ case PREDICATE: printf("predicate"); break;
+ case OR: printf("||"); break;
+ case AND: printf("&&"); break;
+ case NOT: printf("!"); break;
+ case U_OPER: printf("U"); break;
+ case V_OPER: printf("V"); break;
+#ifdef NXT
+ case NEXT: printf("X"); break;
+#endif
+ case TRUE: printf("true"); break;
+ case FALSE: printf("false"); break;
+ case ';': printf("end of formula"); break;
+ default: printf("%c", n); break;
+ }
+}
+
+static void
+tl_non_fatal(char *s1, char *s2)
+{ extern int tl_yychar;
+ int i;
+
+ printf("tl_spin: ");
+ if (s2)
+ printf(s1, s2);
+ else
+ printf(s1);
+ if (tl_yychar != -1 && tl_yychar != 0)
+ { printf(", saw '");
+ tl_explain(tl_yychar);
+ printf("'");
+ }
+ printf("\ntl_spin: %s\n---------", uform);
+ for (i = 0; i < cnt; i++)
+ printf("-");
+ printf("^\n");
+ fflush(stdout);
+ tl_errs++;
+}
+
+void
+tl_yyerror(char *s1)
+{
+ Fatal(s1, (char *) 0);
+}
+
+void
+Fatal(char *s1, char *s2)
+{
+ tl_non_fatal(s1, s2);
+ /* tl_stats(); */
+ exit(1);
+}
diff --git a/sys/src/cmd/spin/tl_mem.c b/sys/src/cmd/spin/tl_mem.c
new file mode 100755
index 000000000..52021e466
--- /dev/null
+++ b/sys/src/cmd/spin/tl_mem.c
@@ -0,0 +1,120 @@
+/***** tl_spin: tl_mem.c *****/
+
+/* Copyright (c) 1995-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 */
+
+/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
+/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
+
+#include "tl.h"
+
+#if 1
+#define log(e, u, d) event[e][(int) u] += (long) d;
+#else
+#define log(e, u, d)
+#endif
+
+#define A_LARGE 80
+#define A_USER 0x55000000
+#define NOTOOBIG 32768
+
+#define POOL 0
+#define ALLOC 1
+#define FREE 2
+#define NREVENT 3
+
+extern unsigned long All_Mem;
+extern int tl_verbose;
+
+union M {
+ long size;
+ union M *link;
+};
+
+static union M *freelist[A_LARGE];
+static long req[A_LARGE];
+static long event[NREVENT][A_LARGE];
+
+void *
+tl_emalloc(int U)
+{ union M *m;
+ long r, u;
+ void *rp;
+
+ u = (long) ((U-1)/sizeof(union M) + 2);
+
+ if (u >= A_LARGE)
+ { log(ALLOC, 0, 1);
+ if (tl_verbose)
+ printf("tl_spin: memalloc %ld bytes\n", u);
+ m = (union M *) emalloc((int) u*sizeof(union M));
+ All_Mem += (unsigned long) u*sizeof(union M);
+ } else
+ { if (!freelist[u])
+ { r = req[u] += req[u] ? req[u] : 1;
+ if (r >= NOTOOBIG)
+ r = req[u] = NOTOOBIG;
+ log(POOL, u, r);
+ freelist[u] = (union M *)
+ emalloc((int) r*u*sizeof(union M));
+ All_Mem += (unsigned long) r*u*sizeof(union M);
+ m = freelist[u] + (r-2)*u;
+ for ( ; m >= freelist[u]; m -= u)
+ m->link = m+u;
+ }
+ log(ALLOC, u, 1);
+ m = freelist[u];
+ freelist[u] = m->link;
+ }
+ m->size = (u|A_USER);
+
+ for (r = 1; r < u; )
+ (&m->size)[r++] = 0;
+
+ rp = (void *) (m+1);
+ memset(rp, 0, U);
+ return rp;
+}
+
+void
+tfree(void *v)
+{ union M *m = (union M *) v;
+ long u;
+
+ --m;
+ if ((m->size&0xFF000000) != A_USER)
+ Fatal("releasing a free block", (char *)0);
+
+ u = (m->size &= 0xFFFFFF);
+ if (u >= A_LARGE)
+ { log(FREE, 0, 1);
+ /* free(m); */
+ } else
+ { log(FREE, u, 1);
+ m->link = freelist[u];
+ freelist[u] = m;
+ }
+}
+
+void
+a_stats(void)
+{ long p, a, f;
+ int i;
+
+ printf(" size\t pool\tallocs\t frees\n");
+ for (i = 0; i < A_LARGE; i++)
+ { p = event[POOL][i];
+ a = event[ALLOC][i];
+ f = event[FREE][i];
+
+ if(p|a|f)
+ printf("%5d\t%6ld\t%6ld\t%6ld\n",
+ i, p, a, f);
+ }
+}
diff --git a/sys/src/cmd/spin/tl_parse.c b/sys/src/cmd/spin/tl_parse.c
new file mode 100755
index 000000000..6206a0d99
--- /dev/null
+++ b/sys/src/cmd/spin/tl_parse.c
@@ -0,0 +1,400 @@
+/***** tl_spin: tl_parse.c *****/
+
+/* Copyright (c) 1995-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 */
+
+/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
+/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
+
+#include "tl.h"
+
+extern int tl_yylex(void);
+extern int tl_verbose, tl_errs;
+
+int tl_yychar = 0;
+YYSTYPE tl_yylval;
+
+static Node *tl_formula(void);
+static Node *tl_factor(void);
+static Node *tl_level(int);
+
+static int prec[2][4] = {
+ { U_OPER, V_OPER, 0, 0 }, /* left associative */
+ { OR, AND, IMPLIES, EQUIV, }, /* left associative */
+};
+
+static Node *
+tl_factor(void)
+{ Node *ptr = ZN;
+
+ switch (tl_yychar) {
+ case '(':
+ ptr = tl_formula();
+ if (tl_yychar != ')')
+ tl_yyerror("expected ')'");
+ tl_yychar = tl_yylex();
+ break;
+ case NOT:
+ ptr = tl_yylval;
+ tl_yychar = tl_yylex();
+ ptr->lft = tl_factor();
+ ptr = push_negation(ptr);
+ break;
+ case ALWAYS:
+ tl_yychar = tl_yylex();
+
+ ptr = tl_factor();
+#ifndef NO_OPT
+ if (ptr->ntyp == FALSE
+ || ptr->ntyp == TRUE)
+ break; /* [] false == false */
+
+ if (ptr->ntyp == V_OPER)
+ { if (ptr->lft->ntyp == FALSE)
+ break; /* [][]p = []p */
+
+ ptr = ptr->rgt; /* [] (p V q) = [] q */
+ }
+#endif
+ ptr = tl_nn(V_OPER, False, ptr);
+ break;
+#ifdef NXT
+ case NEXT:
+ tl_yychar = tl_yylex();
+ ptr = tl_factor();
+ if (ptr->ntyp == TRUE)
+ break; /* X true = true */
+ ptr = tl_nn(NEXT, ptr, ZN);
+ break;
+#endif
+ case EVENTUALLY:
+ tl_yychar = tl_yylex();
+
+ ptr = tl_factor();
+#ifndef NO_OPT
+ if (ptr->ntyp == TRUE
+ || ptr->ntyp == FALSE)
+ break; /* <> true == true */
+
+ if (ptr->ntyp == U_OPER
+ && ptr->lft->ntyp == TRUE)
+ break; /* <><>p = <>p */
+
+ if (ptr->ntyp == U_OPER)
+ { /* <> (p U q) = <> q */
+ ptr = ptr->rgt;
+ /* fall thru */
+ }
+#endif
+ ptr = tl_nn(U_OPER, True, ptr);
+
+ break;
+ case PREDICATE:
+ ptr = tl_yylval;
+ tl_yychar = tl_yylex();
+ break;
+ case TRUE:
+ case FALSE:
+ ptr = tl_yylval;
+ tl_yychar = tl_yylex();
+ break;
+ }
+ if (!ptr) tl_yyerror("expected predicate");
+#if 0
+ printf("factor: ");
+ tl_explain(ptr->ntyp);
+ printf("\n");
+#endif
+ return ptr;
+}
+
+static Node *
+bin_simpler(Node *ptr)
+{ Node *a, *b;
+
+ if (ptr)
+ switch (ptr->ntyp) {
+ case U_OPER:
+#ifndef NO_OPT
+ if (ptr->rgt->ntyp == TRUE
+ || ptr->rgt->ntyp == FALSE
+ || ptr->lft->ntyp == FALSE)
+ { ptr = ptr->rgt;
+ break;
+ }
+ if (isequal(ptr->lft, ptr->rgt))
+ { /* p U p = p */
+ ptr = ptr->rgt;
+ break;
+ }
+ if (ptr->lft->ntyp == U_OPER
+ && isequal(ptr->lft->lft, ptr->rgt))
+ { /* (p U q) U p = (q U p) */
+ ptr->lft = ptr->lft->rgt;
+ break;
+ }
+ if (ptr->rgt->ntyp == U_OPER
+ && ptr->rgt->lft->ntyp == TRUE)
+ { /* p U (T U q) = (T U q) */
+ ptr = ptr->rgt;
+ break;
+ }
+#ifdef NXT
+ /* X p U X q == X (p U q) */
+ if (ptr->rgt->ntyp == NEXT
+ && ptr->lft->ntyp == NEXT)
+ { ptr = tl_nn(NEXT,
+ tl_nn(U_OPER,
+ ptr->lft->lft,
+ ptr->rgt->lft), ZN);
+ }
+#endif
+#endif
+ break;
+ case V_OPER:
+#ifndef NO_OPT
+ if (ptr->rgt->ntyp == FALSE
+ || ptr->rgt->ntyp == TRUE
+ || ptr->lft->ntyp == TRUE)
+ { ptr = ptr->rgt;
+ break;
+ }
+ if (isequal(ptr->lft, ptr->rgt))
+ { /* p V p = p */
+ ptr = ptr->rgt;
+ break;
+ }
+ /* F V (p V q) == F V q */
+ if (ptr->lft->ntyp == FALSE
+ && ptr->rgt->ntyp == V_OPER)
+ { ptr->rgt = ptr->rgt->rgt;
+ break;
+ }
+ /* p V (F V q) == F V q */
+ if (ptr->rgt->ntyp == V_OPER
+ && ptr->rgt->lft->ntyp == FALSE)
+ { ptr->lft = False;
+ ptr->rgt = ptr->rgt->rgt;
+ break;
+ }
+#endif
+ break;
+ case IMPLIES:
+#ifndef NO_OPT
+ if (isequal(ptr->lft, ptr->rgt))
+ { ptr = True;
+ break;
+ }
+#endif
+ ptr = tl_nn(OR, Not(ptr->lft), ptr->rgt);
+ ptr = rewrite(ptr);
+ break;
+ case EQUIV:
+#ifndef NO_OPT
+ if (isequal(ptr->lft, ptr->rgt))
+ { ptr = True;
+ break;
+ }
+#endif
+ a = rewrite(tl_nn(AND,
+ dupnode(ptr->lft),
+ dupnode(ptr->rgt)));
+ b = rewrite(tl_nn(AND,
+ Not(ptr->lft),
+ Not(ptr->rgt)));
+ ptr = tl_nn(OR, a, b);
+ ptr = rewrite(ptr);
+ break;
+ case AND:
+#ifndef NO_OPT
+ /* p && (q U p) = p */
+ if (ptr->rgt->ntyp == U_OPER
+ && isequal(ptr->rgt->rgt, ptr->lft))
+ { ptr = ptr->lft;
+ break;
+ }
+ if (ptr->lft->ntyp == U_OPER
+ && isequal(ptr->lft->rgt, ptr->rgt))
+ { ptr = ptr->rgt;
+ break;
+ }
+
+ /* p && (q V p) == q V p */
+ if (ptr->rgt->ntyp == V_OPER
+ && isequal(ptr->rgt->rgt, ptr->lft))
+ { ptr = ptr->rgt;
+ break;
+ }
+ if (ptr->lft->ntyp == V_OPER
+ && isequal(ptr->lft->rgt, ptr->rgt))
+ { ptr = ptr->lft;
+ break;
+ }
+
+ /* (p U q) && (r U q) = (p && r) U q*/
+ if (ptr->rgt->ntyp == U_OPER
+ && ptr->lft->ntyp == U_OPER
+ && isequal(ptr->rgt->rgt, ptr->lft->rgt))
+ { ptr = tl_nn(U_OPER,
+ tl_nn(AND, ptr->lft->lft, ptr->rgt->lft),
+ ptr->lft->rgt);
+ break;
+ }
+
+ /* (p V q) && (p V r) = p V (q && r) */
+ if (ptr->rgt->ntyp == V_OPER
+ && ptr->lft->ntyp == V_OPER
+ && isequal(ptr->rgt->lft, ptr->lft->lft))
+ { ptr = tl_nn(V_OPER,
+ ptr->rgt->lft,
+ tl_nn(AND, ptr->lft->rgt, ptr->rgt->rgt));
+ break;
+ }
+#ifdef NXT
+ /* X p && X q == X (p && q) */
+ if (ptr->rgt->ntyp == NEXT
+ && ptr->lft->ntyp == NEXT)
+ { ptr = tl_nn(NEXT,
+ tl_nn(AND,
+ ptr->rgt->lft,
+ ptr->lft->lft), ZN);
+ break;
+ }
+#endif
+
+ if (isequal(ptr->lft, ptr->rgt) /* (p && p) == p */
+ || ptr->rgt->ntyp == FALSE /* (p && F) == F */
+ || ptr->lft->ntyp == TRUE) /* (T && p) == p */
+ { ptr = ptr->rgt;
+ break;
+ }
+ if (ptr->rgt->ntyp == TRUE /* (p && T) == p */
+ || ptr->lft->ntyp == FALSE) /* (F && p) == F */
+ { ptr = ptr->lft;
+ break;
+ }
+
+ /* (p V q) && (r U q) == p V q */
+ if (ptr->rgt->ntyp == U_OPER
+ && ptr->lft->ntyp == V_OPER
+ && isequal(ptr->lft->rgt, ptr->rgt->rgt))
+ { ptr = ptr->lft;
+ break;
+ }
+#endif
+ break;
+
+ case OR:
+#ifndef NO_OPT
+ /* p || (q U p) == q U p */
+ if (ptr->rgt->ntyp == U_OPER
+ && isequal(ptr->rgt->rgt, ptr->lft))
+ { ptr = ptr->rgt;
+ break;
+ }
+
+ /* p || (q V p) == p */
+ if (ptr->rgt->ntyp == V_OPER
+ && isequal(ptr->rgt->rgt, ptr->lft))
+ { ptr = ptr->lft;
+ break;
+ }
+
+ /* (p U q) || (p U r) = p U (q || r) */
+ if (ptr->rgt->ntyp == U_OPER
+ && ptr->lft->ntyp == U_OPER
+ && isequal(ptr->rgt->lft, ptr->lft->lft))
+ { ptr = tl_nn(U_OPER,
+ ptr->rgt->lft,
+ tl_nn(OR, ptr->lft->rgt, ptr->rgt->rgt));
+ break;
+ }
+
+ if (isequal(ptr->lft, ptr->rgt) /* (p || p) == p */
+ || ptr->rgt->ntyp == FALSE /* (p || F) == p */
+ || ptr->lft->ntyp == TRUE) /* (T || p) == T */
+ { ptr = ptr->lft;
+ break;
+ }
+ if (ptr->rgt->ntyp == TRUE /* (p || T) == T */
+ || ptr->lft->ntyp == FALSE) /* (F || p) == p */
+ { ptr = ptr->rgt;
+ break;
+ }
+
+ /* (p V q) || (r V q) = (p || r) V q */
+ if (ptr->rgt->ntyp == V_OPER
+ && ptr->lft->ntyp == V_OPER
+ && isequal(ptr->lft->rgt, ptr->rgt->rgt))
+ { ptr = tl_nn(V_OPER,
+ tl_nn(OR, ptr->lft->lft, ptr->rgt->lft),
+ ptr->rgt->rgt);
+ break;
+ }
+
+ /* (p V q) || (r U q) == r U q */
+ if (ptr->rgt->ntyp == U_OPER
+ && ptr->lft->ntyp == V_OPER
+ && isequal(ptr->lft->rgt, ptr->rgt->rgt))
+ { ptr = ptr->rgt;
+ break;
+ }
+#endif
+ break;
+ }
+ return ptr;
+}
+
+static Node *
+tl_level(int nr)
+{ int i; Node *ptr = ZN;
+
+ if (nr < 0)
+ return tl_factor();
+
+ ptr = tl_level(nr-1);
+again:
+ for (i = 0; i < 4; i++)
+ if (tl_yychar == prec[nr][i])
+ { tl_yychar = tl_yylex();
+ ptr = tl_nn(prec[nr][i],
+ ptr, tl_level(nr-1));
+ ptr = bin_simpler(ptr);
+ goto again;
+ }
+ if (!ptr) tl_yyerror("syntax error");
+#if 0
+ printf("level %d: ", nr);
+ tl_explain(ptr->ntyp);
+ printf("\n");
+#endif
+ return ptr;
+}
+
+static Node *
+tl_formula(void)
+{ tl_yychar = tl_yylex();
+ return tl_level(1); /* 2 precedence levels, 1 and 0 */
+}
+
+void
+tl_parse(void)
+{ Node *n = tl_formula();
+ if (tl_verbose)
+ { printf("formula: ");
+ dump(n);
+ printf("\n");
+ }
+ if (tl_Getchar() != -1)
+ { tl_yyerror("syntax error");
+ tl_errs++;
+ return;
+ }
+ trans(n);
+}
diff --git a/sys/src/cmd/spin/tl_rewrt.c b/sys/src/cmd/spin/tl_rewrt.c
new file mode 100755
index 000000000..6e00d9ac0
--- /dev/null
+++ b/sys/src/cmd/spin/tl_rewrt.c
@@ -0,0 +1,301 @@
+/***** tl_spin: tl_rewrt.c *****/
+
+/* Copyright (c) 1995-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 */
+
+/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
+/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
+
+#include "tl.h"
+
+extern int tl_verbose;
+
+static Node *can = ZN;
+
+Node *
+right_linked(Node *n)
+{
+ if (!n) return n;
+
+ if (n->ntyp == AND || n->ntyp == OR)
+ while (n->lft && n->lft->ntyp == n->ntyp)
+ { Node *tmp = n->lft;
+ n->lft = tmp->rgt;
+ tmp->rgt = n;
+ n = tmp;
+ }
+
+ n->lft = right_linked(n->lft);
+ n->rgt = right_linked(n->rgt);
+
+ return n;
+}
+
+Node *
+canonical(Node *n)
+{ Node *m; /* assumes input is right_linked */
+
+ if (!n) return n;
+ if ((m = in_cache(n)) != ZN)
+ return m;
+
+ n->rgt = canonical(n->rgt);
+ n->lft = canonical(n->lft);
+
+ return cached(n);
+}
+
+Node *
+push_negation(Node *n)
+{ Node *m;
+
+ Assert(n->ntyp == NOT, n->ntyp);
+
+ switch (n->lft->ntyp) {
+ case TRUE:
+ Debug("!true => false\n");
+ releasenode(0, n->lft);
+ n->lft = ZN;
+ n->ntyp = FALSE;
+ break;
+ case FALSE:
+ Debug("!false => true\n");
+ releasenode(0, n->lft);
+ n->lft = ZN;
+ n->ntyp = TRUE;
+ break;
+ case NOT:
+ Debug("!!p => p\n");
+ m = n->lft->lft;
+ releasenode(0, n->lft);
+ n->lft = ZN;
+ releasenode(0, n);
+ n = m;
+ break;
+ case V_OPER:
+ Debug("!(p V q) => (!p U !q)\n");
+ n->ntyp = U_OPER;
+ goto same;
+ case U_OPER:
+ Debug("!(p U q) => (!p V !q)\n");
+ n->ntyp = V_OPER;
+ goto same;
+#ifdef NXT
+ case NEXT:
+ Debug("!X -> X!\n");
+ n->ntyp = NEXT;
+ n->lft->ntyp = NOT;
+ n->lft = push_negation(n->lft);
+ break;
+#endif
+ case AND:
+ Debug("!(p && q) => !p || !q\n");
+ n->ntyp = OR;
+ goto same;
+ case OR:
+ Debug("!(p || q) => !p && !q\n");
+ n->ntyp = AND;
+
+same: m = n->lft->rgt;
+ n->lft->rgt = ZN;
+
+ n->rgt = Not(m);
+ n->lft->ntyp = NOT;
+ m = n->lft;
+ n->lft = push_negation(m);
+ break;
+ }
+
+ return rewrite(n);
+}
+
+static void
+addcan(int tok, Node *n)
+{ Node *m, *prev = ZN;
+ Node **ptr;
+ Node *N;
+ Symbol *s, *t; int cmp;
+
+ if (!n) return;
+
+ if (n->ntyp == tok)
+ { addcan(tok, n->rgt);
+ addcan(tok, n->lft);
+ return;
+ }
+
+ N = dupnode(n);
+ if (!can)
+ { can = N;
+ return;
+ }
+
+ s = DoDump(N);
+ if (can->ntyp != tok) /* only one element in list so far */
+ { ptr = &can;
+ goto insert;
+ }
+
+ /* there are at least 2 elements in list */
+ prev = ZN;
+ for (m = can; m->ntyp == tok && m->rgt; prev = m, m = m->rgt)
+ { t = DoDump(m->lft);
+ cmp = strcmp(s->name, t->name);
+ if (cmp == 0) /* duplicate */
+ return;
+ if (cmp < 0)
+ { if (!prev)
+ { can = tl_nn(tok, N, can);
+ return;
+ } else
+ { ptr = &(prev->rgt);
+ goto insert;
+ } } }
+
+ /* new entry goes at the end of the list */
+ ptr = &(prev->rgt);
+insert:
+ t = DoDump(*ptr);
+ cmp = strcmp(s->name, t->name);
+ if (cmp == 0) /* duplicate */
+ return;
+ if (cmp < 0)
+ *ptr = tl_nn(tok, N, *ptr);
+ else
+ *ptr = tl_nn(tok, *ptr, N);
+}
+
+static void
+marknode(int tok, Node *m)
+{
+ if (m->ntyp != tok)
+ { releasenode(0, m->rgt);
+ m->rgt = ZN;
+ }
+ m->ntyp = -1;
+}
+
+Node *
+Canonical(Node *n)
+{ Node *m, *p, *k1, *k2, *prev, *dflt = ZN;
+ int tok;
+
+ if (!n) return n;
+
+ tok = n->ntyp;
+ if (tok != AND && tok != OR)
+ return n;
+
+ can = ZN;
+ addcan(tok, n);
+#if 0
+ Debug("\nA0: "); Dump(can);
+ Debug("\nA1: "); Dump(n); Debug("\n");
+#endif
+ releasenode(1, n);
+
+ /* mark redundant nodes */
+ if (tok == AND)
+ { for (m = can; m; m = (m->ntyp == AND) ? m->rgt : ZN)
+ { k1 = (m->ntyp == AND) ? m->lft : m;
+ if (k1->ntyp == TRUE)
+ { marknode(AND, m);
+ dflt = True;
+ continue;
+ }
+ if (k1->ntyp == FALSE)
+ { releasenode(1, can);
+ can = False;
+ goto out;
+ } }
+ for (m = can; m; m = (m->ntyp == AND) ? m->rgt : ZN)
+ for (p = can; p; p = (p->ntyp == AND) ? p->rgt : ZN)
+ { if (p == m
+ || p->ntyp == -1
+ || m->ntyp == -1)
+ continue;
+ k1 = (m->ntyp == AND) ? m->lft : m;
+ k2 = (p->ntyp == AND) ? p->lft : p;
+
+ if (isequal(k1, k2))
+ { marknode(AND, p);
+ continue;
+ }
+ if (anywhere(OR, k1, k2))
+ { marknode(AND, p);
+ continue;
+ }
+ } }
+ if (tok == OR)
+ { for (m = can; m; m = (m->ntyp == OR) ? m->rgt : ZN)
+ { k1 = (m->ntyp == OR) ? m->lft : m;
+ if (k1->ntyp == FALSE)
+ { marknode(OR, m);
+ dflt = False;
+ continue;
+ }
+ if (k1->ntyp == TRUE)
+ { releasenode(1, can);
+ can = True;
+ goto out;
+ } }
+ for (m = can; m; m = (m->ntyp == OR) ? m->rgt : ZN)
+ for (p = can; p; p = (p->ntyp == OR) ? p->rgt : ZN)
+ { if (p == m
+ || p->ntyp == -1
+ || m->ntyp == -1)
+ continue;
+ k1 = (m->ntyp == OR) ? m->lft : m;
+ k2 = (p->ntyp == OR) ? p->lft : p;
+
+ if (isequal(k1, k2))
+ { marknode(OR, p);
+ continue;
+ }
+ if (anywhere(AND, k1, k2))
+ { marknode(OR, p);
+ continue;
+ }
+ } }
+ for (m = can, prev = ZN; m; ) /* remove marked nodes */
+ { if (m->ntyp == -1)
+ { k2 = m->rgt;
+ releasenode(0, m);
+ if (!prev)
+ { m = can = can->rgt;
+ } else
+ { m = prev->rgt = k2;
+ /* if deleted the last node in a chain */
+ if (!prev->rgt && prev->lft
+ && (prev->ntyp == AND || prev->ntyp == OR))
+ { k1 = prev->lft;
+ prev->ntyp = prev->lft->ntyp;
+ prev->sym = prev->lft->sym;
+ prev->rgt = prev->lft->rgt;
+ prev->lft = prev->lft->lft;
+ releasenode(0, k1);
+ }
+ }
+ continue;
+ }
+ prev = m;
+ m = m->rgt;
+ }
+out:
+#if 0
+ Debug("A2: "); Dump(can); Debug("\n");
+#endif
+ if (!can)
+ { if (!dflt)
+ fatal("cannot happen, Canonical", (char *) 0);
+ return dflt;
+ }
+
+ return can;
+}
diff --git a/sys/src/cmd/spin/tl_trans.c b/sys/src/cmd/spin/tl_trans.c
new file mode 100755
index 000000000..72964ca6b
--- /dev/null
+++ b/sys/src/cmd/spin/tl_trans.c
@@ -0,0 +1,875 @@
+/***** tl_spin: tl_trans.c *****/
+
+/* Copyright (c) 1995-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 */
+
+/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
+/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
+
+#include "tl.h"
+
+extern FILE *tl_out;
+extern int tl_errs, tl_verbose, tl_terse, newstates;
+
+int Stack_mx=0, Max_Red=0, Total=0;
+
+static Mapping *Mapped = (Mapping *) 0;
+static Graph *Nodes_Set = (Graph *) 0;
+static Graph *Nodes_Stack = (Graph *) 0;
+
+static char dumpbuf[2048];
+static int Red_cnt = 0;
+static int Lab_cnt = 0;
+static int Base = 0;
+static int Stack_sz = 0;
+
+static Graph *findgraph(char *);
+static Graph *pop_stack(void);
+static Node *Duplicate(Node *);
+static Node *flatten(Node *);
+static Symbol *catSlist(Symbol *, Symbol *);
+static Symbol *dupSlist(Symbol *);
+static char *newname(void);
+static int choueka(Graph *, int);
+static int not_new(Graph *);
+static int set_prefix(char *, int, Graph *);
+static void Addout(char *, char *);
+static void fsm_trans(Graph *, int, char *);
+static void mkbuchi(void);
+static void expand_g(Graph *);
+static void fixinit(Node *);
+static void liveness(Node *);
+static void mk_grn(Node *);
+static void mk_red(Node *);
+static void ng(Symbol *, Symbol *, Node *, Node *, Node *);
+static void push_stack(Graph *);
+static void sdump(Node *);
+
+static void
+dump_graph(Graph *g)
+{ Node *n1;
+
+ printf("\n\tnew:\t");
+ for (n1 = g->New; n1; n1 = n1->nxt)
+ { dump(n1); printf(", "); }
+ printf("\n\told:\t");
+ for (n1 = g->Old; n1; n1 = n1->nxt)
+ { dump(n1); printf(", "); }
+ printf("\n\tnxt:\t");
+ for (n1 = g->Next; n1; n1 = n1->nxt)
+ { dump(n1); printf(", "); }
+ printf("\n\tother:\t");
+ for (n1 = g->Other; n1; n1 = n1->nxt)
+ { dump(n1); printf(", "); }
+ printf("\n");
+}
+
+static void
+push_stack(Graph *g)
+{
+ if (!g) return;
+
+ g->nxt = Nodes_Stack;
+ Nodes_Stack = g;
+ if (tl_verbose)
+ { Symbol *z;
+ printf("\nPush %s, from ", g->name->name);
+ for (z = g->incoming; z; z = z->next)
+ printf("%s, ", z->name);
+ dump_graph(g);
+ }
+ Stack_sz++;
+ if (Stack_sz > Stack_mx) Stack_mx = Stack_sz;
+}
+
+static Graph *
+pop_stack(void)
+{ Graph *g = Nodes_Stack;
+
+ if (g) Nodes_Stack = g->nxt;
+
+ Stack_sz--;
+
+ return g;
+}
+
+static char *
+newname(void)
+{ static int cnt = 0;
+ static char buf[32];
+ sprintf(buf, "S%d", cnt++);
+ return buf;
+}
+
+static int
+has_clause(int tok, Graph *p, Node *n)
+{ Node *q, *qq;
+
+ switch (n->ntyp) {
+ case AND:
+ return has_clause(tok, p, n->lft) &&
+ has_clause(tok, p, n->rgt);
+ case OR:
+ return has_clause(tok, p, n->lft) ||
+ has_clause(tok, p, n->rgt);
+ }
+
+ for (q = p->Other; q; q = q->nxt)
+ { qq = right_linked(q);
+ if (anywhere(tok, n, qq))
+ return 1;
+ }
+ return 0;
+}
+
+static void
+mk_grn(Node *n)
+{ Graph *p;
+
+ n = right_linked(n);
+more:
+ for (p = Nodes_Set; p; p = p->nxt)
+ if (p->outgoing
+ && has_clause(AND, p, n))
+ { p->isgrn[p->grncnt++] =
+ (unsigned char) Red_cnt;
+ Lab_cnt++;
+ }
+
+ if (n->ntyp == U_OPER) /* 3.4.0 */
+ { n = n->rgt;
+ goto more;
+ }
+}
+
+static void
+mk_red(Node *n)
+{ Graph *p;
+
+ n = right_linked(n);
+ for (p = Nodes_Set; p; p = p->nxt)
+ { if (p->outgoing
+ && has_clause(0, p, n))
+ { if (p->redcnt >= 63)
+ Fatal("too many Untils", (char *)0);
+ p->isred[p->redcnt++] =
+ (unsigned char) Red_cnt;
+ Lab_cnt++; Max_Red = Red_cnt;
+ } }
+}
+
+static void
+liveness(Node *n)
+{
+ if (n)
+ switch (n->ntyp) {
+#ifdef NXT
+ case NEXT:
+ liveness(n->lft);
+ break;
+#endif
+ case U_OPER:
+ Red_cnt++;
+ mk_red(n);
+ mk_grn(n->rgt);
+ /* fall through */
+ case V_OPER:
+ case OR: case AND:
+ liveness(n->lft);
+ liveness(n->rgt);
+ break;
+ }
+}
+
+static Graph *
+findgraph(char *nm)
+{ Graph *p;
+ Mapping *m;
+
+ for (p = Nodes_Set; p; p = p->nxt)
+ if (!strcmp(p->name->name, nm))
+ return p;
+ for (m = Mapped; m; m = m->nxt)
+ if (strcmp(m->from, nm) == 0)
+ return m->to;
+
+ printf("warning: node %s not found\n", nm);
+ return (Graph *) 0;
+}
+
+static void
+Addout(char *to, char *from)
+{ Graph *p = findgraph(from);
+ Symbol *s;
+
+ if (!p) return;
+ s = getsym(tl_lookup(to));
+ s->next = p->outgoing;
+ p->outgoing = s;
+}
+
+#ifdef NXT
+int
+only_nxt(Node *n)
+{
+ switch (n->ntyp) {
+ case NEXT:
+ return 1;
+ case OR:
+ case AND:
+ return only_nxt(n->rgt) && only_nxt(n->lft);
+ default:
+ return 0;
+ }
+}
+#endif
+
+int
+dump_cond(Node *pp, Node *r, int first)
+{ Node *q;
+ int frst = first;
+
+ if (!pp) return frst;
+
+ q = dupnode(pp);
+ q = rewrite(q);
+
+ if (q->ntyp == PREDICATE
+ || q->ntyp == NOT
+#ifndef NXT
+ || q->ntyp == OR
+#endif
+ || q->ntyp == FALSE)
+ { if (!frst) fprintf(tl_out, " && ");
+ dump(q);
+ frst = 0;
+#ifdef NXT
+ } else if (q->ntyp == OR)
+ { if (!frst) fprintf(tl_out, " && ");
+ fprintf(tl_out, "((");
+ frst = dump_cond(q->lft, r, 1);
+
+ if (!frst)
+ fprintf(tl_out, ") || (");
+ else
+ { if (only_nxt(q->lft))
+ { fprintf(tl_out, "1))");
+ return 0;
+ }
+ }
+
+ frst = dump_cond(q->rgt, r, 1);
+
+ if (frst)
+ { if (only_nxt(q->rgt))
+ fprintf(tl_out, "1");
+ else
+ fprintf(tl_out, "0");
+ frst = 0;
+ }
+
+ fprintf(tl_out, "))");
+#endif
+ } else if (q->ntyp == V_OPER
+ && !anywhere(AND, q->rgt, r))
+ { frst = dump_cond(q->rgt, r, frst);
+ } else if (q->ntyp == AND)
+ {
+ frst = dump_cond(q->lft, r, frst);
+ frst = dump_cond(q->rgt, r, frst);
+ }
+
+ return frst;
+}
+
+static int
+choueka(Graph *p, int count)
+{ int j, k, incr_cnt = 0;
+
+ for (j = count; j <= Max_Red; j++) /* for each acceptance class */
+ { int delta = 0;
+
+ /* is state p labeled Grn-j OR not Red-j ? */
+
+ for (k = 0; k < (int) p->grncnt; k++)
+ if (p->isgrn[k] == j)
+ { delta = 1;
+ break;
+ }
+ if (delta)
+ { incr_cnt++;
+ continue;
+ }
+ for (k = 0; k < (int) p->redcnt; k++)
+ if (p->isred[k] == j)
+ { delta = 1;
+ break;
+ }
+
+ if (delta) break;
+
+ incr_cnt++;
+ }
+ return incr_cnt;
+}
+
+static int
+set_prefix(char *pref, int count, Graph *r2)
+{ int incr_cnt = 0; /* acceptance class 'count' */
+
+ if (Lab_cnt == 0
+ || Max_Red == 0)
+ sprintf(pref, "accept"); /* new */
+ else if (count >= Max_Red)
+ sprintf(pref, "T0"); /* cycle */
+ else
+ { incr_cnt = choueka(r2, count+1);
+ if (incr_cnt + count >= Max_Red)
+ sprintf(pref, "accept"); /* last hop */
+ else
+ sprintf(pref, "T%d", count+incr_cnt);
+ }
+ return incr_cnt;
+}
+
+static void
+fsm_trans(Graph *p, int count, char *curnm)
+{ Graph *r;
+ Symbol *s;
+ char prefix[128], nwnm[128];
+
+ if (!p->outgoing)
+ addtrans(p, curnm, False, "accept_all");
+
+ for (s = p->outgoing; s; s = s->next)
+ { r = findgraph(s->name);
+ if (!r) continue;
+ if (r->outgoing)
+ { (void) set_prefix(prefix, count, r);
+ sprintf(nwnm, "%s_%s", prefix, s->name);
+ } else
+ strcpy(nwnm, "accept_all");
+
+ if (tl_verbose)
+ { printf("maxred=%d, count=%d, curnm=%s, nwnm=%s ",
+ Max_Red, count, curnm, nwnm);
+ printf("(greencnt=%d,%d, redcnt=%d,%d)\n",
+ r->grncnt, r->isgrn[0],
+ r->redcnt, r->isred[0]);
+ }
+ addtrans(p, curnm, r->Old, nwnm);
+ }
+}
+
+static void
+mkbuchi(void)
+{ Graph *p;
+ int k;
+ char curnm[64];
+
+ for (k = 0; k <= Max_Red; k++)
+ for (p = Nodes_Set; p; p = p->nxt)
+ { if (!p->outgoing)
+ continue;
+ if (k != 0
+ && !strcmp(p->name->name, "init")
+ && Max_Red != 0)
+ continue;
+
+ if (k == Max_Red
+ && strcmp(p->name->name, "init") != 0)
+ strcpy(curnm, "accept_");
+ else
+ sprintf(curnm, "T%d_", k);
+
+ strcat(curnm, p->name->name);
+
+ fsm_trans(p, k, curnm);
+ }
+ fsm_print();
+}
+
+static Symbol *
+dupSlist(Symbol *s)
+{ Symbol *p1, *p2, *p3, *d = ZS;
+
+ for (p1 = s; p1; p1 = p1->next)
+ { for (p3 = d; p3; p3 = p3->next)
+ { if (!strcmp(p3->name, p1->name))
+ break;
+ }
+ if (p3) continue; /* a duplicate */
+
+ p2 = getsym(p1);
+ p2->next = d;
+ d = p2;
+ }
+ return d;
+}
+
+static Symbol *
+catSlist(Symbol *a, Symbol *b)
+{ Symbol *p1, *p2, *p3, *tmp;
+
+ /* remove duplicates from b */
+ for (p1 = a; p1; p1 = p1->next)
+ { p3 = ZS;
+ for (p2 = b; p2; p2 = p2->next)
+ { if (strcmp(p1->name, p2->name))
+ { p3 = p2;
+ continue;
+ }
+ tmp = p2->next;
+ tfree((void *) p2);
+ if (p3)
+ p3->next = tmp;
+ else
+ b = tmp;
+ } }
+ if (!a) return b;
+ if (!b) return a;
+ if (!b->next)
+ { b->next = a;
+ return b;
+ }
+ /* find end of list */
+ for (p1 = a; p1->next; p1 = p1->next)
+ ;
+ p1->next = b;
+ return a;
+}
+
+static void
+fixinit(Node *orig)
+{ Graph *p1, *g;
+ Symbol *q1, *q2 = ZS;
+
+ ng(tl_lookup("init"), ZS, ZN, ZN, ZN);
+ p1 = pop_stack();
+ p1->nxt = Nodes_Set;
+ p1->Other = p1->Old = orig;
+ Nodes_Set = p1;
+
+ for (g = Nodes_Set; g; g = g->nxt)
+ { for (q1 = g->incoming; q1; q1 = q2)
+ { q2 = q1->next;
+ Addout(g->name->name, q1->name);
+ tfree((void *) q1);
+ }
+ g->incoming = ZS;
+ }
+}
+
+static Node *
+flatten(Node *p)
+{ Node *q, *r, *z = ZN;
+
+ for (q = p; q; q = q->nxt)
+ { r = dupnode(q);
+ if (z)
+ z = tl_nn(AND, r, z);
+ else
+ z = r;
+ }
+ if (!z) return z;
+ z = rewrite(z);
+ return z;
+}
+
+static Node *
+Duplicate(Node *n)
+{ Node *n1, *n2, *lst = ZN, *d = ZN;
+
+ for (n1 = n; n1; n1 = n1->nxt)
+ { n2 = dupnode(n1);
+ if (lst)
+ { lst->nxt = n2;
+ lst = n2;
+ } else
+ d = lst = n2;
+ }
+ return d;
+}
+
+static void
+ng(Symbol *s, Symbol *in, Node *isnew, Node *isold, Node *next)
+{ Graph *g = (Graph *) tl_emalloc(sizeof(Graph));
+
+ if (s) g->name = s;
+ else g->name = tl_lookup(newname());
+
+ if (in) g->incoming = dupSlist(in);
+ if (isnew) g->New = flatten(isnew);
+ if (isold) g->Old = Duplicate(isold);
+ if (next) g->Next = flatten(next);
+
+ push_stack(g);
+}
+
+static void
+sdump(Node *n)
+{
+ switch (n->ntyp) {
+ case PREDICATE: strcat(dumpbuf, n->sym->name);
+ break;
+ case U_OPER: strcat(dumpbuf, "U");
+ goto common2;
+ case V_OPER: strcat(dumpbuf, "V");
+ goto common2;
+ case OR: strcat(dumpbuf, "|");
+ goto common2;
+ case AND: strcat(dumpbuf, "&");
+common2: sdump(n->rgt);
+common1: sdump(n->lft);
+ break;
+#ifdef NXT
+ case NEXT: strcat(dumpbuf, "X");
+ goto common1;
+#endif
+ case NOT: strcat(dumpbuf, "!");
+ goto common1;
+ case TRUE: strcat(dumpbuf, "T");
+ break;
+ case FALSE: strcat(dumpbuf, "F");
+ break;
+ default: strcat(dumpbuf, "?");
+ break;
+ }
+}
+
+Symbol *
+DoDump(Node *n)
+{
+ if (!n) return ZS;
+
+ if (n->ntyp == PREDICATE)
+ return n->sym;
+
+ dumpbuf[0] = '\0';
+ sdump(n);
+ return tl_lookup(dumpbuf);
+}
+
+static int
+not_new(Graph *g)
+{ Graph *q1; Node *tmp, *n1, *n2;
+ Mapping *map;
+
+ tmp = flatten(g->Old); /* duplicate, collapse, normalize */
+ g->Other = g->Old; /* non normalized full version */
+ g->Old = tmp;
+
+ g->oldstring = DoDump(g->Old);
+
+ tmp = flatten(g->Next);
+ g->nxtstring = DoDump(tmp);
+
+ if (tl_verbose) dump_graph(g);
+
+ Debug2("\tformula-old: [%s]\n", g->oldstring?g->oldstring->name:"true");
+ Debug2("\tformula-nxt: [%s]\n", g->nxtstring?g->nxtstring->name:"true");
+ for (q1 = Nodes_Set; q1; q1 = q1->nxt)
+ { Debug2(" compare old to: %s", q1->name->name);
+ Debug2(" [%s]", q1->oldstring?q1->oldstring->name:"true");
+
+ Debug2(" compare nxt to: %s", q1->name->name);
+ Debug2(" [%s]", q1->nxtstring?q1->nxtstring->name:"true");
+
+ if (q1->oldstring != g->oldstring
+ || q1->nxtstring != g->nxtstring)
+ { Debug(" => different\n");
+ continue;
+ }
+ Debug(" => match\n");
+
+ if (g->incoming)
+ q1->incoming = catSlist(g->incoming, q1->incoming);
+
+ /* check if there's anything in g->Other that needs
+ adding to q1->Other
+ */
+ for (n2 = g->Other; n2; n2 = n2->nxt)
+ { for (n1 = q1->Other; n1; n1 = n1->nxt)
+ if (isequal(n1, n2))
+ break;
+ if (!n1)
+ { Node *n3 = dupnode(n2);
+ /* don't mess up n2->nxt */
+ n3->nxt = q1->Other;
+ q1->Other = n3;
+ } }
+
+ map = (Mapping *) tl_emalloc(sizeof(Mapping));
+ map->from = g->name->name;
+ map->to = q1;
+ map->nxt = Mapped;
+ Mapped = map;
+
+ for (n1 = g->Other; n1; n1 = n2)
+ { n2 = n1->nxt;
+ releasenode(1, n1);
+ }
+ for (n1 = g->Old; n1; n1 = n2)
+ { n2 = n1->nxt;
+ releasenode(1, n1);
+ }
+ for (n1 = g->Next; n1; n1 = n2)
+ { n2 = n1->nxt;
+ releasenode(1, n1);
+ }
+ return 1;
+ }
+
+ if (newstates) tl_verbose=1;
+ Debug2(" New Node %s [", g->name->name);
+ for (n1 = g->Old; n1; n1 = n1->nxt)
+ { Dump(n1); Debug(", "); }
+ Debug2("] nr %d\n", Base);
+ if (newstates) tl_verbose=0;
+
+ Base++;
+ g->nxt = Nodes_Set;
+ Nodes_Set = g;
+
+ return 0;
+}
+
+static void
+expand_g(Graph *g)
+{ Node *now, *n1, *n2, *nx;
+ int can_release;
+
+ if (!g->New)
+ { Debug2("\nDone with %s", g->name->name);
+ if (tl_verbose) dump_graph(g);
+ if (not_new(g))
+ { if (tl_verbose) printf("\tIs Not New\n");
+ return;
+ }
+ if (g->Next)
+ { Debug(" Has Next [");
+ for (n1 = g->Next; n1; n1 = n1->nxt)
+ { Dump(n1); Debug(", "); }
+ Debug("]\n");
+
+ ng(ZS, getsym(g->name), g->Next, ZN, ZN);
+ }
+ return;
+ }
+
+ if (tl_verbose)
+ { Symbol *z;
+ printf("\nExpand %s, from ", g->name->name);
+ for (z = g->incoming; z; z = z->next)
+ printf("%s, ", z->name);
+ printf("\n\thandle:\t"); Explain(g->New->ntyp);
+ dump_graph(g);
+ }
+
+ if (g->New->ntyp == AND)
+ { if (g->New->nxt)
+ { n2 = g->New->rgt;
+ while (n2->nxt)
+ n2 = n2->nxt;
+ n2->nxt = g->New->nxt;
+ }
+ n1 = n2 = g->New->lft;
+ while (n2->nxt)
+ n2 = n2->nxt;
+ n2->nxt = g->New->rgt;
+
+ releasenode(0, g->New);
+
+ g->New = n1;
+ push_stack(g);
+ return;
+ }
+
+ can_release = 0; /* unless it need not go into Old */
+ now = g->New;
+ g->New = g->New->nxt;
+ now->nxt = ZN;
+
+ if (now->ntyp != TRUE)
+ { if (g->Old)
+ { for (n1 = g->Old; n1->nxt; n1 = n1->nxt)
+ if (isequal(now, n1))
+ { can_release = 1;
+ goto out;
+ }
+ n1->nxt = now;
+ } else
+ g->Old = now;
+ }
+out:
+ switch (now->ntyp) {
+ case FALSE:
+ push_stack(g);
+ break;
+ case TRUE:
+ releasenode(1, now);
+ push_stack(g);
+ break;
+ case PREDICATE:
+ case NOT:
+ if (can_release) releasenode(1, now);
+ push_stack(g);
+ break;
+ case V_OPER:
+ Assert(now->rgt->nxt == ZN, now->ntyp);
+ Assert(now->lft->nxt == ZN, now->ntyp);
+ n1 = now->rgt;
+ n1->nxt = g->New;
+
+ if (can_release)
+ nx = now;
+ else
+ nx = getnode(now); /* now also appears in Old */
+ nx->nxt = g->Next;
+
+ n2 = now->lft;
+ n2->nxt = getnode(now->rgt);
+ n2->nxt->nxt = g->New;
+ g->New = flatten(n2);
+ push_stack(g);
+ ng(ZS, g->incoming, n1, g->Old, nx);
+ break;
+
+ case U_OPER:
+ Assert(now->rgt->nxt == ZN, now->ntyp);
+ Assert(now->lft->nxt == ZN, now->ntyp);
+ n1 = now->lft;
+
+ if (can_release)
+ nx = now;
+ else
+ nx = getnode(now); /* now also appears in Old */
+ nx->nxt = g->Next;
+
+ n2 = now->rgt;
+ n2->nxt = g->New;
+
+ goto common;
+
+#ifdef NXT
+ case NEXT:
+ nx = dupnode(now->lft);
+ nx->nxt = g->Next;
+ g->Next = nx;
+ if (can_release) releasenode(0, now);
+ push_stack(g);
+ break;
+#endif
+
+ case OR:
+ Assert(now->rgt->nxt == ZN, now->ntyp);
+ Assert(now->lft->nxt == ZN, now->ntyp);
+ n1 = now->lft;
+ nx = g->Next;
+
+ n2 = now->rgt;
+ n2->nxt = g->New;
+common:
+ n1->nxt = g->New;
+
+ ng(ZS, g->incoming, n1, g->Old, nx);
+ g->New = flatten(n2);
+
+ if (can_release) releasenode(1, now);
+
+ push_stack(g);
+ break;
+ }
+}
+
+Node *
+twocases(Node *p)
+{ Node *q;
+ /* 1: ([]p1 && []p2) == [](p1 && p2) */
+ /* 2: (<>p1 || <>p2) == <>(p1 || p2) */
+
+ if (!p) return p;
+
+ switch(p->ntyp) {
+ case AND:
+ case OR:
+ case U_OPER:
+ case V_OPER:
+ p->lft = twocases(p->lft);
+ p->rgt = twocases(p->rgt);
+ break;
+#ifdef NXT
+ case NEXT:
+#endif
+ case NOT:
+ p->lft = twocases(p->lft);
+ break;
+
+ default:
+ break;
+ }
+ if (p->ntyp == AND /* 1 */
+ && p->lft->ntyp == V_OPER
+ && p->lft->lft->ntyp == FALSE
+ && p->rgt->ntyp == V_OPER
+ && p->rgt->lft->ntyp == FALSE)
+ { q = tl_nn(V_OPER, False,
+ tl_nn(AND, p->lft->rgt, p->rgt->rgt));
+ } else
+ if (p->ntyp == OR /* 2 */
+ && p->lft->ntyp == U_OPER
+ && p->lft->lft->ntyp == TRUE
+ && p->rgt->ntyp == U_OPER
+ && p->rgt->lft->ntyp == TRUE)
+ { q = tl_nn(U_OPER, True,
+ tl_nn(OR, p->lft->rgt, p->rgt->rgt));
+ } else
+ q = p;
+ return q;
+}
+
+void
+trans(Node *p)
+{ Node *op;
+ Graph *g;
+
+ if (!p || tl_errs) return;
+
+ p = twocases(p);
+
+ if (tl_verbose || tl_terse)
+ { fprintf(tl_out, "\t/* Normlzd: ");
+ dump(p);
+ fprintf(tl_out, " */\n");
+ }
+ if (tl_terse)
+ return;
+
+ op = dupnode(p);
+
+ ng(ZS, getsym(tl_lookup("init")), p, ZN, ZN);
+ while ((g = Nodes_Stack) != (Graph *) 0)
+ { Nodes_Stack = g->nxt;
+ expand_g(g);
+ }
+ if (newstates)
+ return;
+
+ fixinit(p);
+ liveness(flatten(op)); /* was: liveness(op); */
+
+ mkbuchi();
+ if (tl_verbose)
+ { printf("/*\n");
+ printf(" * %d states in Streett automaton\n", Base);
+ printf(" * %d Streett acceptance conditions\n", Max_Red);
+ printf(" * %d Buchi states\n", Total);
+ printf(" */\n");
+ }
+}
diff --git a/sys/src/cmd/spin/vars.c b/sys/src/cmd/spin/vars.c
new file mode 100755
index 000000000..e83d74f57
--- /dev/null
+++ b/sys/src/cmd/spin/vars.c
@@ -0,0 +1,347 @@
+/***** spin: vars.c *****/
+
+/* Copyright (c) 1989-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 */
+
+#include "spin.h"
+#include "y.tab.h"
+
+extern Ordered *all_names;
+extern RunList *X, *LastX;
+extern Symbol *Fname;
+extern char Buf[];
+extern int lineno, depth, verbose, xspin, limited_vis;
+extern int analyze, jumpsteps, nproc, nstop, columns;
+extern short no_arrays, Have_claim;
+extern void sr_mesg(FILE *, int, int);
+extern void sr_buf(int, int);
+
+static int getglobal(Lextok *);
+static int setglobal(Lextok *, int);
+static int maxcolnr = 1;
+
+int
+getval(Lextok *sn)
+{ Symbol *s = sn->sym;
+
+ if (strcmp(s->name, "_") == 0)
+ { non_fatal("attempt to read value of '_'", 0);
+ return 0;
+ }
+ if (strcmp(s->name, "_last") == 0)
+ return (LastX)?LastX->pid:0;
+ if (strcmp(s->name, "_p") == 0)
+ return (X && X->pc)?X->pc->seqno:0;
+ if (strcmp(s->name, "_pid") == 0)
+ { if (!X) return 0;
+ return X->pid - Have_claim;
+ }
+ if (strcmp(s->name, "_nr_pr") == 0)
+ return nproc-nstop; /* new 3.3.10 */
+
+ if (s->context && s->type)
+ return getlocal(sn);
+
+ if (!s->type) /* not declared locally */
+ { s = lookup(s->name); /* try global */
+ sn->sym = s; /* fix it */
+ }
+ return getglobal(sn);
+}
+
+int
+setval(Lextok *v, int n)
+{
+ if (v->sym->context && v->sym->type)
+ return setlocal(v, n);
+ if (!v->sym->type)
+ v->sym = lookup(v->sym->name);
+ return setglobal(v, n);
+}
+
+void
+rm_selfrefs(Symbol *s, Lextok *i)
+{
+ if (!i) return;
+
+ if (i->ntyp == NAME
+ && strcmp(i->sym->name, s->name) == 0
+ && ( (!i->sym->context && !s->context)
+ || ( i->sym->context && s->context
+ && strcmp(i->sym->context->name, s->context->name) == 0)))
+ { lineno = i->ln;
+ Fname = i->fn;
+ non_fatal("self-reference initializing '%s'", s->name);
+ i->ntyp = CONST;
+ i->val = 0;
+ } else
+ { rm_selfrefs(s, i->lft);
+ rm_selfrefs(s, i->rgt);
+ }
+}
+
+int
+checkvar(Symbol *s, int n)
+{ int i, oln = lineno; /* calls on eval() change it */
+ Symbol *ofnm = Fname;
+
+ if (!in_bound(s, n))
+ return 0;
+
+ if (s->type == 0)
+ { non_fatal("undecl var %s (assuming int)", s->name);
+ s->type = INT;
+ }
+ /* not a STRUCT */
+ if (s->val == (int *) 0) /* uninitialized */
+ { s->val = (int *) emalloc(s->nel*sizeof(int));
+ for (i = 0; i < s->nel; i++)
+ { if (s->type != CHAN)
+ { rm_selfrefs(s, s->ini);
+ s->val[i] = eval(s->ini);
+ } else if (!analyze)
+ s->val[i] = qmake(s);
+ } }
+ lineno = oln;
+ Fname = ofnm;
+ return 1;
+}
+
+static int
+getglobal(Lextok *sn)
+{ Symbol *s = sn->sym;
+ int i, n = eval(sn->lft);
+
+ if (s->type == 0 && X && (i = find_lab(s, X->n, 0)))
+ { printf("findlab through getglobal on %s\n", s->name);
+ return i; /* can this happen? */
+ }
+ if (s->type == STRUCT)
+ return Rval_struct(sn, s, 1); /* 1 = check init */
+ if (checkvar(s, n))
+ return cast_val(s->type, s->val[n], s->nbits);
+ return 0;
+}
+
+int
+cast_val(int t, int v, int w)
+{ int i=0; short s=0; unsigned int u=0;
+
+ if (t == PREDEF || t == INT || t == CHAN) i = v; /* predef means _ */
+ else if (t == SHORT) s = (short) v;
+ else if (t == BYTE || t == MTYPE) u = (unsigned char)v;
+ else if (t == BIT) u = (unsigned char)(v&1);
+ else if (t == UNSIGNED)
+ { if (w == 0)
+ fatal("cannot happen, cast_val", (char *)0);
+ /* u = (unsigned)(v& ((1<<w)-1)); problem when w=32 */
+ u = (unsigned)(v& (~0u>>(8*sizeof(unsigned)-w))); /* doug */
+ }
+
+ if (v != i+s+ (int) u)
+ { char buf[32]; sprintf(buf, "%d->%d (%d)", v, i+s+u, t);
+ non_fatal("value (%s) truncated in assignment", buf);
+ }
+ return (int)(i+s+u);
+}
+
+static int
+setglobal(Lextok *v, int m)
+{
+ if (v->sym->type == STRUCT)
+ (void) Lval_struct(v, v->sym, 1, m);
+ else
+ { int n = eval(v->lft);
+ if (checkvar(v->sym, n))
+ { v->sym->val[n] = cast_val(v->sym->type, m, v->sym->nbits);
+ v->sym->setat = depth;
+ } }
+ return 1;
+}
+
+void
+dumpclaims(FILE *fd, int pid, char *s)
+{ extern Lextok *Xu_List; extern int Pid;
+ extern short terse;
+ Lextok *m; int cnt = 0; int oPid = Pid;
+
+ for (m = Xu_List; m; m = m->rgt)
+ if (strcmp(m->sym->name, s) == 0)
+ { cnt=1;
+ break;
+ }
+ if (cnt == 0) return;
+
+ Pid = pid;
+ fprintf(fd, "#ifndef XUSAFE\n");
+ for (m = Xu_List; m; m = m->rgt)
+ { if (strcmp(m->sym->name, s) != 0)
+ continue;
+ no_arrays = 1;
+ putname(fd, "\t\tsetq_claim(", m->lft, 0, "");
+ no_arrays = 0;
+ fprintf(fd, ", %d, ", m->val);
+ terse = 1;
+ putname(fd, "\"", m->lft, 0, "\", h, ");
+ terse = 0;
+ fprintf(fd, "\"%s\");\n", s);
+ }
+ fprintf(fd, "#endif\n");
+ Pid = oPid;
+}
+
+void
+dumpglobals(void)
+{ Ordered *walk;
+ static Lextok *dummy = ZN;
+ Symbol *sp;
+ int j;
+
+ if (!dummy)
+ dummy = nn(ZN, NAME, nn(ZN,CONST,ZN,ZN), ZN);
+
+ for (walk = all_names; walk; walk = walk->next)
+ { sp = walk->entry;
+ if (!sp->type || sp->context || sp->owner
+ || sp->type == PROCTYPE || sp->type == PREDEF
+ || sp->type == CODE_FRAG || sp->type == CODE_DECL
+ || (sp->type == MTYPE && ismtype(sp->name)))
+ continue;
+
+ if (sp->type == STRUCT)
+ { dump_struct(sp, sp->name, 0);
+ continue;
+ }
+ for (j = 0; j < sp->nel; j++)
+ { int prefetch;
+ if (sp->type == CHAN)
+ { doq(sp, j, 0);
+ continue;
+ }
+ if ((verbose&4) && !(verbose&64)
+ && (sp->setat < depth
+ && jumpsteps != depth))
+ continue;
+ dummy->sym = sp;
+ dummy->lft->val = j;
+ /* in case of cast_val warnings, do this first: */
+ prefetch = getglobal(dummy);
+ printf("\t\t%s", sp->name);
+ if (sp->nel > 1) printf("[%d]", j);
+ printf(" = ");
+ sr_mesg(stdout, prefetch,
+ sp->type == MTYPE);
+ printf("\n");
+ if (limited_vis && (sp->hidden&2))
+ { int colpos;
+ Buf[0] = '\0';
+ if (!xspin)
+ { if (columns == 2)
+ sprintf(Buf, "~G%s = ", sp->name);
+ else
+ sprintf(Buf, "%s = ", sp->name);
+ }
+ sr_buf(prefetch, sp->type == MTYPE);
+ if (sp->colnr == 0)
+ { sp->colnr = maxcolnr;
+ maxcolnr = 1+(maxcolnr%10);
+ }
+ colpos = nproc+sp->colnr-1;
+ if (columns == 2)
+ { pstext(colpos, Buf);
+ continue;
+ }
+ if (!xspin)
+ { printf("\t\t%s\n", Buf);
+ continue;
+ }
+ printf("MSC: ~G %s %s\n", sp->name, Buf);
+ printf("%3d:\tproc %3d (TRACK) line 1 \"var\" ",
+ depth, colpos);
+ printf("(state 0)\t[printf('MSC: globvar\\\\n')]\n");
+ printf("\t\t%s", sp->name);
+ if (sp->nel > 1) printf("[%d]", j);
+ printf(" = %s\n", Buf);
+ } } }
+}
+
+void
+dumplocal(RunList *r)
+{ static Lextok *dummy = ZN;
+ Symbol *z, *s;
+ int i;
+
+ if (!r) return;
+
+ s = r->symtab;
+
+ if (!dummy)
+ dummy = nn(ZN, NAME, nn(ZN,CONST,ZN,ZN), ZN);
+
+ for (z = s; z; z = z->next)
+ { if (z->type == STRUCT)
+ { dump_struct(z, z->name, r);
+ continue;
+ }
+ for (i = 0; i < z->nel; i++)
+ { if (z->type == CHAN)
+ { doq(z, i, r);
+ continue;
+ }
+ if ((verbose&4) && !(verbose&64)
+ && (z->setat < depth
+ && jumpsteps != depth))
+ continue;
+
+ dummy->sym = z;
+ dummy->lft->val = i;
+
+ printf("\t\t%s(%d):%s",
+ r->n->name, r->pid, z->name);
+ if (z->nel > 1) printf("[%d]", i);
+ printf(" = ");
+ sr_mesg(stdout, getval(dummy), z->type == MTYPE);
+ printf("\n");
+ if (limited_vis && (z->hidden&2))
+ { int colpos;
+ Buf[0] = '\0';
+ if (!xspin)
+ { if (columns == 2)
+ sprintf(Buf, "~G%s(%d):%s = ",
+ r->n->name, r->pid, z->name);
+ else
+ sprintf(Buf, "%s(%d):%s = ",
+ r->n->name, r->pid, z->name);
+ }
+ sr_buf(getval(dummy), z->type==MTYPE);
+ if (z->colnr == 0)
+ { z->colnr = maxcolnr;
+ maxcolnr = 1+(maxcolnr%10);
+ }
+ colpos = nproc+z->colnr-1;
+ if (columns == 2)
+ { pstext(colpos, Buf);
+ continue;
+ }
+ if (!xspin)
+ { printf("\t\t%s\n", Buf);
+ continue;
+ }
+ printf("MSC: ~G %s(%d):%s %s\n",
+ r->n->name, r->pid, z->name, Buf);
+
+ printf("%3d:\tproc %3d (TRACK) line 1 \"var\" ",
+ depth, colpos);
+ printf("(state 0)\t[printf('MSC: locvar\\\\n')]\n");
+ printf("\t\t%s(%d):%s",
+ r->n->name, r->pid, z->name);
+ if (z->nel > 1) printf("[%d]", i);
+ printf(" = %s\n", Buf);
+ } } }
+}
diff --git a/sys/src/cmd/spin/version.h b/sys/src/cmd/spin/version.h
new file mode 100755
index 000000000..4ad23fa4a
--- /dev/null
+++ b/sys/src/cmd/spin/version.h
@@ -0,0 +1 @@
+#define Version "Spin Version 4.3.0 -- 22 June 2007"