9front - general discussion about 9front
 help / color / mirror / Atom feed
* [Patch] Update Spin to most recent version.
@ 2017-11-22  8:23 Ori Bernstein
  0 siblings, 0 replies; only message in thread
From: Ori Bernstein @ 2017-11-22  8:23 UTC (permalink / raw)
  To: 9front

I decided it's time to learn what spin is all about, and saw that
the version shipped with 9front is rather old. It turned out to
be trivial to build newer versions of spin, so I updated it.

There were a small number of changes needed from the tarball
on spinroot.org:

  - The mkfile needed to be updated
  - Memory.h needed to not be included
  - It needed to invoke /bin/cpp instead of gcc -E
  - It depended on `yychar`, which our yacc doesn't
    provide.

I'm still figuring out how to use spin, but it seems to do
the right thing when testing a few of the examples:

	% cd $home/src/Spin/Examples/
	% spin -a peterson.pml
	% pcc pan.c -D_POSIX_SOURCE
	% ./6.out

	(Spin Version 6.4.7 -- 19 August 2017)
		+ Partial Order Reduction

	Full statespace search for:
		never claim         	- (none specified)
		assertion violations	+
		acceptance   cycles 	- (not selected)
		invalid end states	+

	State-vector 32 byte, depth reached 24, errors: 0
	40 states, stored
	27 states, matched
	67 transitions (= stored+matched)
		0 atomic steps
	hash conflicts:         0 (resolved)

	Stats on memory usage (in Megabytes):
	0.002	equivalent memory usage for states (stored*(State-vector + overhead))
	0.292	actual memory usage for states
	128.000	memory used for hash table (-w24)
	0.534	memory used for DFS stack (-m10000)
	128.730	total actual memory usage


	unreached in proctype user
		/tmp/Spin/Examples/peterson.pml:20, state 10, "-end-"
		(1 of 10 states)

	pan: elapsed time 1.25 seconds
	pan: rate        32 states/second

The diff is attached, if there's interest in updating.


--- a/sys/src/cmd/spin/dstep.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/dstep.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,27 +1,25 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
+#include <assert.h>
 #include "spin.h"
 #include "y.tab.h"
 
-#define MAXDSTEP	1024	/* was 512 */
+#define MAXDSTEP	2048	/* was 512 */
 
-char	*NextLab[64];
+char	*NextLab[64];	/* must match value in pangen2.c:41 */
 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;
+extern int	Pid, separate, OkBreak;
 
 static void
 Sourced(int n, int special)
@@ -59,7 +57,7 @@
 			if (Tojump[j] == Jumpto[i])
 				break;
 		if (j == Tj)
-		{	char buf[12];
+		{	char buf[16];
 			if (Jumpto[i] == OkBreak)
 			{	if (!LastGoto)
 				fprintf(fd, "S_%.3d_0:	/* break-dest */\n",
@@ -80,10 +78,11 @@
 	}
 	for (j = i = 0; j < Tj; j++)
 		if (Special[j])
-		{	Tojump[i] = Tojump[j];
+		{	if (i >= MAXDSTEP)
+			{	fatal("cannot happen (dstep.c)", (char *)0);
+			}
+			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 */
@@ -164,7 +163,7 @@
 			break;
 		case ELSE:
 			if (inh++ > 0) fprintf(fd, " || ");
-/* 4.2.5 */		if (Pid != claimnr)
+/* 4.2.5 */		if (!pid_is_claim(Pid))
 				fprintf(fd, "(boq == -1 /* else */)");
 			else
 				fprintf(fd, "(1 /* else */)");
@@ -184,17 +183,17 @@
 		case 's':
 			if (inh++ > 0) fprintf(fd, " || ");
 			fprintf(fd, "("); TestOnly=1;
-/* 4.2.1 */		if (Pid != claimnr) fprintf(fd, "(boq == -1) && ");
+/* 4.2.1 */		if (!pid_is_claim(Pid)) 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)
+			if (!pid_is_claim(Pid))
 				fprintf(fd, "(boq == -1 && ");
 			putstmnt(fd, ee->n->lft, e->seqno);
-			if (Pid != claimnr)
+			if (!pid_is_claim(Pid))
 				fprintf(fd, ")");
 			fprintf(fd, ")"); TestOnly=0;
 			break;
@@ -204,7 +203,8 @@
 
 int
 putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno)
-{	int isg=0; char buf[64];
+{	int isg=0;
+	static char buf[64];
 
 	NextLab[0] = "continue";
 	filterbad(s->frst);
@@ -215,6 +215,7 @@
 		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);
+		if (justguards) return 0;	/* 6.2.5 */
 		break;
 	case IF:
 		fprintf(fd, "if (!(");
@@ -245,7 +246,7 @@
 	case 's':
 		fprintf(fd, "if (");
 #if 1
-/* 4.2.1 */	if (Pid != claimnr) fprintf(fd, "(boq != -1) || ");
+/* 4.2.1 */	if (!pid_is_claim(Pid)) fprintf(fd, "(boq != -1) || ");
 #endif
 		fprintf(fd, "!("); TestOnly=1;
 		putstmnt(fd, s->frst->n, s->frst->seqno);
@@ -253,7 +254,7 @@
 		break;
 	case 'c':
 		fprintf(fd, "if (!(");
-		if (Pid != claimnr) fprintf(fd, "boq == -1 && ");
+		if (!pid_is_claim(Pid)) fprintf(fd, "boq == -1 && ");
 		TestOnly=1;
 		putstmnt(fd, s->frst->n->lft, s->frst->seqno);
 		fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
@@ -262,19 +263,31 @@
 		fprintf(fd, "if (boq != -1 || (");
 		if (separate != 2) fprintf(fd, "trpt->");
 		fprintf(fd, "o_pm&1))\n\t\t\tcontinue;");
+		{	extern FILE *th;
+			fprintf(th, "#ifndef ELSE_IN_GUARD\n");
+			fprintf(th, "	#define ELSE_IN_GUARD\n");
+			fprintf(th, "#endif\n");
+		}
 		break;
 	case ASGN:	/* new 3.0.8 */
 		fprintf(fd, "IfNotBlocked");
 		break;
+	default:
+		fprintf(fd, "/* default %d */\n\t\t", s->frst->n->ntyp);
 	}
+
+	/* 6.2.5 : before TstOnly */
+	fprintf(fd, "\n\n\t\treached[%d][%d] = 1;\n\t\t", Pid, seqno);
+	fprintf(fd, "reached[%d][t->st] = 1;\n\t\t", Pid); /* next state */
+	fprintf(fd, "reached[%d][tt] = 1;\n", Pid);	/* current state */
+
+	/* 6.2.5 : before sv_save() */
+	if (s->frst->n->ntyp != NON_ATOMIC)
+	fprintf(fd, "\n\t\tif (TstOnly) return 1;\n"); /* if called from enabled() */
+
 	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);
@@ -359,7 +372,7 @@
 			case '.':
 				if (LastGoto) break;
 				if (e->nxt && (e->nxt->status & DONE2))
-				{	i = e->nxt?e->nxt->Seqno:0;
+				{	i = e->nxt->Seqno;
 					fprintf(fd, "\t\tgoto S_%.3d_0;", i);
 					fprintf(fd, " /* '.' */\n");
 					Dested(i);
@@ -375,7 +388,7 @@
 				break;
 			}
 			i = e->nxt?e->nxt->Seqno:0;
-			if (e->nxt && e->nxt->status & DONE2 && !LastGoto)
+			if (e->nxt && (e->nxt->status & DONE2) && !LastGoto)
 			{	fprintf(fd, "\t\tgoto S_%.3d_0; ", i);
 				fprintf(fd, "/* ';' */\n");
 				Dested(i);
diff -r 51b3bf8bc61b sys/src/cmd/spin/flow.c
--- a/sys/src/cmd/spin/flow.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/flow.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,24 +1,24 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include "spin.h"
 #include "y.tab.h"
 
 extern Symbol	*Fname;
-extern int	nr_errs, lineno, verbose;
-extern short	has_unless, has_badelse;
+extern int	nr_errs, lineno, verbose, in_for, old_scope_rules, s_trail;
+extern short	has_unless, has_badelse, has_xu;
+extern char CurScope[MAXSCOPESZ];
 
 Element *Al_El = ZE;
 Label	*labtab = (Label *) 0;
-int	Unique=0, Elcnt=0, DstepStart = -1;
+int	Unique = 0, Elcnt = 0, DstepStart = -1;
+int	initialization_ok = 1;
+short	has_accept;
 
 static Lbreak	*breakstack = (Lbreak *) 0;
 static Lextok	*innermost;
@@ -37,10 +37,16 @@
 open_seq(int top)
 {	SeqList *t;
 	Sequence *s = (Sequence *) emalloc(sizeof(Sequence));
+	s->minel = -1;
 
 	t = seqlist(s, cur_s);
 	cur_s = t;
-	if (top) Elcnt = 1;
+	if (top)
+	{	Elcnt = 1;
+		initialization_ok = 1;
+	} else
+	{	initialization_ok = 0;
+	}
 }
 
 void
@@ -84,6 +90,7 @@
 	&&  a->indstep != b->indstep)
 	{	lineno = a->ln;
 		Fname  = a->fn;
+		if (!s_trail)
 		fatal("jump into d_step sequence", (char *) 0);
 	}
 }
@@ -113,8 +120,8 @@
 			&&  n->ntyp != PRINT
 			&&  n->ntyp != PRINTM)
 			{	if (verbose&32)
-					printf("spin: line %d %s, redundant skip\n",
-						n->ln, n->fn->name);
+					printf("spin: %s:%d, redundant skip\n",
+						n->fn->name, n->ln);
 				if (e != s->frst
 				&&  e != s->last
 				&&  e != s->extent)
@@ -147,7 +154,11 @@
 {	Sequence *s = cur_s->this;
 	Symbol *z;
 
-	if (nottop > 0 && (z = has_lab(s->frst, 0)))
+	if (nottop == 0)	/* end of proctype body */
+	{	initialization_ok = 1;
+	}
+
+	if (nottop > 0 && s->frst && (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,
@@ -183,12 +194,12 @@
 			printf("\"Label: { statement ... }\"\n");
 			break;
 		case 6:
-			printf("=====>instead of\n");
+			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("=====> use\n");
 			printf("Label:	do (or if)\n");
 			printf("	:: ...\n");
 			printf("	:: statement\n");
@@ -198,8 +209,9 @@
 			printf("cannot happen - labels\n");
 			break;
 		}
-		alldone(1);
-	}
+		if (nottop != 6)
+		{	alldone(1);
+	}	}
 
 	if (nottop == 4
 	&& !Rjumpslocal(s->frst, s->last))
@@ -217,13 +229,14 @@
 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++;
 
-	has_unless++;
 	if (Es->ntyp == NON_ATOMIC)
-		Sl = Es->sl;
-	else
+	{	Sl = Es->sl;
+	} else
 	{	open_seq(0); add_seq(Es);
 		Sl = seqlist(close_seq(1), 0);
 	}
@@ -348,6 +361,31 @@
 	}	}
 }
 
+void
+popbreak(void)
+{
+	if (!breakstack)
+		fatal("cannot happen, breakstack", (char *) 0);
+
+	breakstack = breakstack->nxt;	/* pop stack */
+}
+
+static Lbreak *ob = (Lbreak *) 0;
+
+void
+safe_break(void)
+{
+	ob = breakstack;
+	popbreak();
+}
+
+void
+restore_break(void)
+{
+	breakstack = ob;
+	ob = (Lbreak *) 0;
+}
+
 static Element *
 if_seq(Lextok *n)
 {	int	tok = n->ntyp;
@@ -388,21 +426,26 @@
 	&&  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);
+		if (has_xu)
+		{	fatal("invalid use of 'else' combined with i/o and xr/xs assertions,",
+				(char *)0);
+		} else
+		{	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)
+	for (z = s; 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 */
+		popbreak();
 	}
 	add_el(e, cur_s->this);
 	add_el(t, cur_s->this);
@@ -563,33 +606,86 @@
 void
 set_lab(Symbol *s, Element *e)
 {	Label *l; extern Symbol *context;
+	int cur_uiid = is_inline();
 
 	if (!s) return;
+
 	for (l = labtab; l; l = l->nxt)
-		if (l->s == s && l->c == context)
+	{	if (strcmp(l->s->name, s->name) == 0
+		&&  l->c == context
+		&&  (old_scope_rules || strcmp((const char *) s->bscp, (const char *) l->s->bscp) == 0)
+		&&  l->uiid == cur_uiid)
 		{	non_fatal("label %s redeclared", s->name);
 			break;
-		}
+	}	}
+
+	if (strncmp(s->name, "accept", 6) == 0
+	&&  strncmp(s->name, "accept_all", 10) != 0)
+	{	has_accept = 1;
+	}
+
 	l = (Label *) emalloc(sizeof(Label));
 	l->s = s;
 	l->c = context;
 	l->e = e;
+	l->uiid = cur_uiid;
 	l->nxt = labtab;
 	labtab = l;
 }
 
+static Label *
+get_labspec(Lextok *n)
+{	Symbol *s = n->sym;
+	Label  *l, *anymatch = (Label *) 0;
+	int ln;
+	/*
+	 * try to find a label with the same inline id (uiid)
+	 * but if it doesn't exist, return any other match
+	 * within the same scope
+	 */
+	for (l = labtab; l; l = l->nxt)
+	{	if (strcmp(l->s->name, s->name) == 0	/* labelname matches */
+		&&  s->context == l->s->context)	/* same scope */
+		{
+#if 0
+			if (anymatch && n->uiid == anymatch->uiid)
+			{	if (0) non_fatal("label %s re-declared", s->name);
+			}
+			if (0)
+			{	printf("Label %s uiid now::then %d :: %d bcsp %s :: %s\n",
+					s->name, n->uiid, l->uiid, s->bscp, l->s->bscp);
+				printf("get_labspec match on %s %s (bscp goto %s - label %s)\n",
+					s->name, s->context->name,  s->bscp, l->s->bscp);
+			}
+#endif
+			/* same block scope */
+			if (strcmp((const char *) s->bscp, (const char *) l->s->bscp) == 0)
+			{	return l;	/* definite match */
+			}
+			/* higher block scope */
+			ln = strlen((const char *) l->s->bscp);
+			if (strncmp((const char *) s->bscp, (const char *) l->s->bscp, ln) == 0)
+			{	anymatch = l;	/* possible match */
+			} else if (!anymatch)
+			{	anymatch = l;	/* somewhere else in same context */
+	}	}	}
+
+	return anymatch; /* return best match */
+}
+
 Element *
 get_lab(Lextok *n, int md)
-{	Label *l;
-	Symbol *s = n->sym;
+{	Label *l = get_labspec(n);
 
-	for (l = labtab; l; l = l->nxt)
-		if (s == l->s)
-			return (l->e);
+	if (l != (Label *) 0)
+	{	return (l->e);
+	}
 
-	lineno = n->ln;
-	Fname = n->fn;
-	if (md) fatal("undefined label %s", s->name);
+	if (md)
+	{	lineno = n->ln;
+		Fname  = n->fn;
+		fatal("undefined label %s", n->sym->name);
+	}
 	return ZE;
 }
 
@@ -670,21 +766,46 @@
 	}
 	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);
+	{	printf("spin: %s:%d, warning, reference to label ",
+			Fname->name, lineno);
+		printf("from inside atomic or d_step (%s)\n", c->name);
 	}
 }
 
 int
 find_lab(Symbol *s, Symbol *c, int markit)
-{	Label *l;
+{	Label *l, *pm = (Label *) 0, *apm = (Label *) 0;
+	int ln;
 
+	/* generally called for remote references in never claims */
 	for (l = labtab; l; l = l->nxt)
-	{	if (strcmp(s->name, l->s->name) == 0
+	{
+		if (strcmp(s->name, l->s->name) == 0
 		&&  strcmp(c->name, l->c->name) == 0)
-		{	l->visible |= markit;
-			return (l->e->seqno);
-	}	}
+		{	ln = strlen((const char *) l->s->bscp);
+			if (0)
+			{	printf("want '%s' in context '%s', scope ref '%s' - label '%s'\n",
+					s->name, c->name, s->bscp, l->s->bscp);
+			}
+			/* same or higher block scope */
+			if (strcmp((const char *)  s->bscp, (const char *) l->s->bscp) == 0)
+			{	pm = l;	/* definite match */
+				break;
+			}
+			if (strncmp((const char *) s->bscp, (const char *) l->s->bscp, ln) == 0)
+			{	pm = l;	/* possible match */
+			} else
+			{	apm = l;	/* remote */
+	}	}	}
+
+	if (pm)
+	{	pm->visible |= markit;
+		return pm->e->seqno;
+	}
+	if (apm)
+	{	apm->visible |= markit;
+		return apm->e->seqno;
+	} /* else printf("Not Found\n"); */
 	return 0;
 }
 
@@ -735,6 +856,226 @@
 	}
 }
 
+#if 0
+static int depth = 0;
+void dump_sym(Symbol *, char *);
+
+void
+dump_lex(Lextok *t, char *s)
+{	int i;
+
+	depth++;
+	printf(s);
+	for (i = 0; i < depth; i++)
+		printf("\t");
+	explain(t->ntyp);
+	if (t->ntyp == NAME) printf(" %s ", t->sym->name);
+	if (t->ntyp == CONST) printf(" %d ", t->val);
+	if (t->ntyp == STRUCT)
+	{	dump_sym(t->sym, "\n:Z:");
+	}
+	if (t->lft)
+	{	dump_lex(t->lft, "\nL");
+	}
+	if (t->rgt)
+	{	dump_lex(t->rgt, "\nR");
+	}	
+	depth--;
+}
+void
+dump_sym(Symbol *z, char *s)
+{	int i;
+	char txt[64];
+	depth++;
+	printf(s);
+	for (i = 0; i < depth; i++)
+		printf("\t");
+
+	if (z->type == CHAN)
+	{	if (z->ini && z->ini->rgt && z->ini->rgt->sym)
+		{	/* dump_sym(z->ini->rgt->sym, "\n:I:"); -- could also be longer list */
+			if (z->ini->rgt->rgt
+			|| !z->ini->rgt->sym)
+			fatal("chan %s in for should have only one field (a typedef)", z->name);
+			printf(" -- %s %p -- ", z->ini->rgt->sym->name, z->ini->rgt->sym);
+		}
+	} else if (z->type == STRUCT)
+	{	if (z->Snm)
+			printf(" == %s %p == ", z->Snm->name, z->Snm);
+		else
+		{	if (z->Slst)
+				dump_lex(z->Slst, "\n:X:");
+			if (z->ini)
+				dump_lex(z->ini, "\n:I:");
+		}
+	}
+	depth--;
+
+}
+#endif
+
+int
+match_struct(Symbol *s, Symbol *t)
+{
+	if (!t
+	||  !t->ini
+	||  !t->ini->rgt
+	||  !t->ini->rgt->sym
+	||   t->ini->rgt->rgt)
+	{	fatal("chan %s in for should have only one field (a typedef)", t?t->name:"--");
+	}
+	/* we already know that s is a STRUCT */
+	if (0)
+	{	printf("index type %s %p ==\n", s->Snm->name, s->Snm);
+		printf("chan type  %s %p --\n\n", t->ini->rgt->sym->name, t->ini->rgt->sym);
+	}
+
+	return (s->Snm == t->ini->rgt->sym);
+}
+
+void
+valid_name(Lextok *a3, Lextok *a5, Lextok *a8, char *tp)
+{
+	if (a3->ntyp != NAME)
+	{	fatal("%s ( .name : from .. to ) { ... }", tp);
+	}
+	if (a3->sym->type == CHAN
+	||  a3->sym->type == STRUCT
+	||  a3->sym->isarray != 0)
+	{	fatal("bad index in for-construct %s", a3->sym->name);
+	}
+	if (a5->ntyp == CONST && a8->ntyp == CONST && a5->val > a8->val)
+	{	non_fatal("start value for %s exceeds end-value", a3->sym->name);
+	}
+}
+
+void
+for_setup(Lextok *a3, Lextok *a5, Lextok *a8)
+{	/* for ( a3 : a5 .. a8 ) */
+
+	valid_name(a3, a5, a8, "for");
+	/* a5->ntyp = a8->ntyp = CONST; */
+	add_seq(nn(a3, ASGN, a3, a5));	/* start value */
+	open_seq(0);
+	add_seq(nn(ZN, 'c', nn(a3, LE, a3, a8), ZN));	/* condition */
+}
+
+Lextok *
+for_index(Lextok *a3, Lextok *a5)
+{	Lextok *z0, *z1, *z2, *z3;
+	Symbol *tmp_cnt;
+	char tmp_nm[MAXSCOPESZ+16];
+	/* for ( a3 in a5 ) { ... } */
+
+	if (a3->ntyp != NAME)
+	{	fatal("for ( .name in name ) { ... }", (char *) 0);
+	}
+
+	if (a5->ntyp != NAME)
+	{	fatal("for ( %s in .name ) { ... }", a3->sym->name);
+	}
+
+	if (a3->sym->type == STRUCT)
+	{	if (a5->sym->type != CHAN)
+		{	fatal("for ( %s in .channel_name ) { ... }",
+				a3->sym->name);
+		}
+		z0 = a5->sym->ini;
+		if (!z0
+		|| z0->val <= 0
+		|| z0->rgt->ntyp != STRUCT
+		|| z0->rgt->rgt != NULL)
+		{	fatal("bad channel type %s in for", a5->sym->name);
+		}
+
+		if (!match_struct(a3->sym, a5->sym))
+		{	fatal("type of %s does not match chan", a3->sym->name);
+		}
+
+		z1 = nn(ZN, CONST, ZN, ZN); z1->val = 0;
+		z2 = nn(a5, LEN, a5, ZN);
+
+		sprintf(tmp_nm, "_f0r_t3mp%s", CurScope); /* make sure it's unique */
+		tmp_cnt = lookup(tmp_nm);
+		if (z0->val > 255)			/* check nr of slots, i.e. max length */
+		{	tmp_cnt->type = SHORT;	/* should be rare */
+		} else
+		{	tmp_cnt->type = BYTE;
+		}
+		z3 = nn(ZN, NAME, ZN, ZN);
+		z3->sym = tmp_cnt;
+
+		add_seq(nn(z3, ASGN, z3, z1));	/* start value 0 */
+
+		open_seq(0);
+
+		add_seq(nn(ZN, 'c', nn(z3, LT, z3, z2), ZN));	/* condition */
+
+		/* retrieve  message from the right slot -- for now: rotate contents */
+		in_for = 0;
+		add_seq(nn(a5, 'r', a5, expand(a3, 1)));	/* receive */
+		add_seq(nn(a5, 's', a5, expand(a3, 1)));	/* put back in to rotate */
+		in_for = 1;
+		return z3;
+	} else
+	{	if (a5->sym->isarray == 0
+		||  a5->sym->nel <= 0)
+		{	fatal("bad arrayname %s", a5->sym->name);
+		}
+		z1 = nn(ZN, CONST, ZN, ZN); z1->val = 0;
+		z2 = nn(ZN, CONST, ZN, ZN); z2->val = a5->sym->nel - 1;
+		for_setup(a3, z1, z2);
+		return a3;
+	}
+}
+
+Lextok *
+for_body(Lextok *a3, int with_else)
+{	Lextok *t1, *t2, *t0, *rv;
+
+	rv = nn(ZN, CONST, ZN, ZN); rv->val = 1;
+	rv = nn(ZN,  '+', a3, rv);
+	rv = nn(a3, ASGN, a3, rv);
+	add_seq(rv);	/* initial increment */
+
+	/* completed loop body, main sequence */
+	t1 = nn(ZN, 0, ZN, ZN);
+	t1->sq = close_seq(8);
+
+	open_seq(0);		/* add else -> break sequence */
+	if (with_else)
+	{	add_seq(nn(ZN, ELSE, ZN, ZN));
+	}
+	t2 = nn(ZN, GOTO, ZN, ZN);
+	t2->sym = break_dest();
+	add_seq(t2);
+	t2 = nn(ZN, 0, ZN, ZN);
+	t2->sq = close_seq(9);
+
+	t0 = nn(ZN, 0, ZN, ZN);
+	t0->sl = seqlist(t2->sq, seqlist(t1->sq, 0));
+
+	rv = nn(ZN, DO, ZN, ZN);
+	rv->sl = t0->sl;
+
+	return rv;
+}
+
+Lextok *
+sel_index(Lextok *a3, Lextok *a5, Lextok *a7)
+{	/* select ( a3 : a5 .. a7 ) */
+
+	valid_name(a3, a5, a7, "select");
+	/* a5->ntyp = a7->ntyp = CONST; */
+
+	add_seq(nn(a3, ASGN, a3, a5));	/* start value */
+	open_seq(0);
+	add_seq(nn(ZN, 'c', nn(a3, LT, a3, a7), ZN));	/* condition */
+
+	pushbreak(); /* new 6.2.1 */
+	return for_body(a3, 0);	/* no else, just a non-deterministic break */
+}
+
 static void
 walk_atomic(Element *a, Element *b, int added)
 {	Element *f; Symbol *ofn; int oln;
@@ -747,16 +1088,16 @@
 		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");
+			  printf("spin: %s:%d, warning, atomic inside %s (ignored)\n",
+			  f->n->fn->name, f->n->ln, (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);
+			printf("spin: %s:%d, warning, d_step inside ",
+			 f->n->fn->name, f->n->ln);
 			if (added)
 			{	printf("d_step (ignored)\n");
 				goto mknonat;
@@ -770,8 +1111,8 @@
 			break;
 		case UNLESS:
 			if (added)
-			{ printf("spin: error, line %3d %s, unless in d_step (ignored)\n",
-			 	 f->n->ln, f->n->fn->name);
+			{ printf("spin: error, %s:%d, unless in d_step (ignored)\n",
+			 	 f->n->fn->name, f->n->ln);
 			}
 		}
 		for (h = f->sub; h; h = h->nxt)
@@ -789,6 +1130,15 @@
 
 	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);
+		{	printf("label	%s	%d	",
+				l->s->name, l->e->seqno);
+			if (l->uiid == 0)
+				printf("<%s>", l->c->name);
+			else
+				printf("<%s i%d>", l->c->name, l->uiid);
+			if (!old_scope_rules)
+			{	printf("\t{scope %s}", l->s->bscp);
+			}
+			printf("\n");
+		}
 }
diff -r 51b3bf8bc61b sys/src/cmd/spin/guided.c
--- a/sys/src/cmd/spin/guided.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/guided.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,17 +1,15 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include "spin.h"
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <limits.h>
 #include "y.tab.h"
 
 extern RunList	*run, *X;
@@ -19,8 +17,9 @@
 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 short	Have_claim, Skip_claim, has_code;
 extern void ana_src(int, int);
+extern char	**trailfilename;
 
 int	TstOnly = 0, pno;
 
@@ -73,12 +72,70 @@
 	return (!Have_claim || !X || X->pid != 0);
 }
 
+int globmin = INT_MAX;
+int globmax = 0;
+
+int
+find_min(Sequence *s)
+{	SeqList *l;
+	Element *e;
+
+	if (s->minel < 0)
+	{	s->minel = INT_MAX;
+		for (e = s->frst; e; e = e->nxt)
+		{	if (e->status & 512)
+			{	continue;
+			}
+			e->status |= 512;
+
+			if (e->n->ntyp == ATOMIC
+			||  e->n->ntyp == NON_ATOMIC
+			||  e->n->ntyp == D_STEP)
+			{	int n = find_min(e->n->sl->this);
+				if (n < s->minel)
+				{	s->minel = n;
+				}
+			} else if (e->Seqno < s->minel)
+			{	s->minel = e->Seqno;
+			}
+			for (l = e->sub; l; l = l->nxt)
+			{	int n = find_min(l->this);
+				if (n < s->minel)
+				{	s->minel = n;
+		}	}	}
+	}
+	if (s->minel < globmin)
+	{	globmin = s->minel;
+	}
+	return s->minel;
+}
+
+int
+find_max(Sequence *s)
+{
+	if (s->last->Seqno > globmax)
+	{	globmax = s->last->Seqno;
+	}
+	return s->last->Seqno;
+}
+
 void
 match_trail(void)
 {	int i, a, nst;
 	Element *dothis;
 	char snap[512], *q;
 
+	if (has_code)
+	{	printf("spin: important:\n");
+		printf("  =======================================warning====\n");
+		printf("  this model contains embedded c code statements\n");
+		printf("  these statements will not be executed when the trail\n");
+		printf("  is replayed in this way -- they are just printed,\n");
+		printf("  which will likely lead to inaccurate variable values.\n");
+		printf("  for an accurate replay use: ./pan -r\n");
+		printf("  =======================================warning====\n\n");
+	}
+
 	/*
 	 * if source model name is leader.pml
 	 * look for the trail file under these names:
@@ -88,10 +145,18 @@
 	 *	leader.tra
 	 */
 
-	if (ntrail)
-		sprintf(snap, "%s%d.trail", oFname->name, ntrail);
-	else
-		sprintf(snap, "%s.trail", oFname->name);
+	if (trailfilename)
+	{	if (strlen(*trailfilename) < sizeof(snap))
+		{	strcpy(snap, (const char *) *trailfilename);
+		} else
+		{	fatal("filename %s too long", *trailfilename);
+		}
+	} else
+	{	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 */
@@ -118,9 +183,9 @@
 	}	}
 okay:		
 	if (xspin == 0 && newer(oFname->name, snap))
-	printf("spin: warning, \"%s\" is newer than %s\n",
-		oFname->name, snap);
-
+	{	printf("spin: warning, \"%s\" is newer than %s\n",
+			oFname->name, snap);
+	}
 	Tval = 1;
 
 	/*
@@ -132,10 +197,23 @@
 	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 == -2)
+		{	if (verbose)
+			{	printf("starting claim %d\n", pno);
+			}
+			start_claim(pno);
+			continue;
+		}
+		if (depth == -4)
+		{	if (verbose)
+			{	printf("using statement merging\n");
+			}
+			merger = 1;
+			ana_src(0, 1);
+			continue;
+		}
 		if (depth == -1)
-		{	if (verbose)
+		{	if (1 || verbose)
 			{	if (columns == 2)
 				dotag(stdout, " CYCLE>\n");
 				else
@@ -188,16 +266,50 @@
 				pno - Have_claim, i, nst, dothis->n->ntyp);
 			lost_trail();
 		}
+
+		if (0 && !xspin && (verbose&32))
+		{	printf("step %d i=%d pno %d stmnt %d\n", depth, i, pno, nst);
+		}
+
 		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();
+		{	if (verbose&32)
+			{	printf("%3d: no process %d (stmnt %d)\n", depth, pno - Have_claim, nst);
+				printf(" max %d (%d - %d + %d) claim %d ",
+					nproc - nstop + Skip_claim,
+					nproc, nstop, Skip_claim, Have_claim);
+				printf("active processes:\n");
+				for (X = run; X; X = X->nxt)
+				{	printf("\tpid %d\tproctype %s\n", X->pid, X->n->name);
+				}
+				printf("\n");
+				continue;	
+			} else
+			{	printf("%3d:\tproc  %d (?) ", depth, pno);
+				lost_trail();
+			}
+		} else
+		{	int min_seq = find_min(X->ps);
+			int max_seq = find_max(X->ps);
+
+
+			if (nst < min_seq || nst > max_seq)
+			{	printf("%3d: error: invalid statement", depth);
+				if (verbose&32)
+				{	printf(": pid %d:%d (%s:%d:%d) stmnt %d (valid range %d .. %d)",
+					pno, X->pid, X->n->name, X->tn, X->b, nst, min_seq, max_seq);
+				}
+				printf("\n");
+				continue;
+				/* lost_trail(); */
+			}
+			X->pc  = dothis;
 		}
-		X->pc  = dothis;
+
 		lineno = dothis->n->ln;
 		Fname  = dothis->n->fn;
 
@@ -271,7 +383,7 @@
 		}	}
 
 		if (Have_claim && X && X->pid == 0
-		&&  dothis && dothis->n
+		&&  dothis->n
 		&&  lastclaim != dothis->n->ln)
 		{	lastclaim = dothis->n->ln;
 			if (columns == 2)
diff -r 51b3bf8bc61b sys/src/cmd/spin/main.c
--- a/sys/src/cmd/spin/main.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/main.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,25 +1,23 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include <stdlib.h>
+#include <assert.h>
 #include "spin.h"
 #include "version.h"
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <signal.h>
-/* #include <malloc.h> */
 #include <time.h>
 #ifdef PC
-#include <io.h>
-extern int unlink(const char *);
+ #include <io.h>
 #else
-#include <unistd.h>
+ #include <unistd.h>
 #endif
 #include "y.tab.h"
 
@@ -29,6 +27,12 @@
 extern char	*claimproc;
 extern void	repro_src(void);
 extern void	qhide(int);
+extern char	CurScope[MAXSCOPESZ];
+extern short	has_provided, has_code, has_ltl, has_accept;
+extern int	realread, buzzed;
+
+static void	add_comptime(char *);
+static void	add_runtime(char *);
 
 Symbol	*Fname, *oFname;
 
@@ -40,12 +44,19 @@
 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	norecompile;	/* main.c */
+int	old_scope_rules;	/* use pre 5.3.0 rules */
+int	old_priority_rules;	/* use pre 6.2.0 rules */
+int	product, Strict;
+short	replay;
 
-int	dataflow = 1, merger = 1, deadvar = 1, ccache = 1;
+int	merger = 1, deadvar = 1, implied_semis = 1;
+int	ccache = 0; /* oyvind teig: 5.2.0 case caching off by default */
 
-static int preprocessonly, SeedUsed;
+static int preprocessonly, SeedUsed, itsr, itsr_n;
+static int seedy;	/* be verbose about chosen seed */
+static int inlineonly;	/* show inlined code */
+static int dataflow = 1;
 
 #if 0
 meaning of flags on verbose:
@@ -61,99 +72,515 @@
 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	**add_ltl  = (char **) 0;
+static char	**ltl_file = (char **) 0;
+static char	**nvr_file = (char **) 0;
+static char	*ltl_claims = (char *) 0;
+static char	*pan_runtime = "";
+static char	*pan_comptime = "";
+static char	formula[4096];
+static FILE	*fd_ltl = (FILE *) 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
+char	**trailfilename;	/* new option 'k' */
 
-#endif
-static char	*PreProc = CPP;
+void	explain(int);
+
+#define CPP	"/bin/cpp"	/* sometimes: "/lib/cpp" */
+
+static char	PreProc[512];
 extern int	depth; /* at least some steps were made */
 
+int
+WhatSeed(void)
+{
+	return SeedUsed;
+}
+
+void
+final_fiddle(void)
+{	char *has_a, *has_l, *has_f;
+
+	/* no -a or -l but has_accept: add -a */
+	/* no -a or -l in pan_runtime: add -DSAFETY to pan_comptime */
+	/* -a or -l but no -f then add -DNOFAIR */
+
+	has_a = strstr(pan_runtime, "-a");
+	has_l = strstr(pan_runtime, "-l");
+	has_f = strstr(pan_runtime, "-f");
+
+	if (!has_l && !has_a && strstr(pan_comptime, "-DNP"))
+	{	add_runtime("-l");
+		has_l = strstr(pan_runtime, "-l");
+	}
+
+	if (!has_a && !has_l
+	&&  !strstr(pan_comptime, "-DSAFETY"))
+	{	if (has_accept
+		&& !strstr(pan_comptime, "-DBFS")
+		&& !strstr(pan_comptime, "-DNOCLAIM"))
+		{	add_runtime("-a");
+			has_a = pan_runtime;
+		} else
+		{	add_comptime("-DSAFETY");
+	}	}
+
+	if ((has_a || has_l) && !has_f
+	&&  !strstr(pan_comptime, "-DNOFAIR"))
+	{	add_comptime("-DNOFAIR");
+	}
+}
+
+static int
+change_param(char *t, char *what, int range, int bottom)
+{	char *ptr;
+	int v;
+
+	assert(range < 1000 && range > 0);
+	if ((ptr = strstr(t, what)) != NULL)
+	{	ptr += strlen(what);
+		if (!isdigit((int) *ptr))
+		{	return 0;
+		}
+		v = atoi(ptr) + 1;	/* was: v = (atoi(ptr)+1)%range */
+		if (v >= range)
+		{	v = bottom;
+		}
+		if (v >= 100)
+		{	*ptr++ = '0' + (v/100); v %= 100;
+			*ptr++ = '0' + (v/10);
+			*ptr   = '0' + (v%10);
+		} else if (v >= 10)
+		{	*ptr++ = '0' + (v/10);
+			*ptr++ = '0' + (v%10);
+			*ptr   = ' ';
+		} else
+		{	*ptr++ = '0' + v;
+			*ptr++ = ' ';
+			*ptr   = ' ';
+	}	}
+	return 1;
+}
+
+static void
+change_rs(char *t)
+{	char *ptr;
+	int cnt = 0;
+	long v;
+
+	if ((ptr = strstr(t, "-RS")) != NULL)
+	{	ptr += 3;
+		/* room for at least 10 digits */
+		v = Rand()%1000000000L;
+		while (v/10 > 0)
+		{	*ptr++ = '0' + v%10;
+			v /= 10;
+			cnt++;
+		}
+		*ptr++ = '0' + v;
+		cnt++;
+		while (cnt++ < 10)
+		{	*ptr++ = ' ';
+	}	}
+}
+
+int
+omit_str(char *in, char *s)
+{	char *ptr = strstr(in, s);
+	int i, nr = -1;
+
+	if (ptr)
+	{	for (i = 0; i < (int) strlen(s); i++)
+		{	*ptr++ = ' ';
+		}
+		if (isdigit((int) *ptr))
+		{	nr = atoi(ptr);
+			while (isdigit((int) *ptr))
+			{	*ptr++ = ' ';
+	}	}	}
+	return nr;
+}
+
+void
+string_trim(char *t)
+{	int n = strlen(t) - 1;
+
+	while (n > 0 && t[n] == ' ')
+	{	t[n--] = '\0';
+	}
+}
+
+int
+e_system(int v, const char *s)
+{	static int count = 1;
+	/* v == 0 : checks to find non-linked version of gcc */
+	/* v == 1 : all other commands */
+	/* v == 2 : preprocessing the promela input */
+
+	if (v == 1)
+	{	if (verbose&(32|64))	/* -v or -w */
+		{	printf("cmd%02d: %s\n", count++, s);
+			fflush(stdout);
+		}
+		if (verbose&64)		/* only -w */
+		{	return 0;	/* suppress the call to system(s) */
+	}	}
+	return system(s);
+}
+
 void
 alldone(int estatus)
-{
-	if (preprocessonly == 0
-	&&  strlen(out1) > 0)
-		(void) unlink((const char *)out1);
+{	char *ptr;
+#if defined(WIN32) || defined(WIN64)
+	struct _stat x;
+#else
+	struct stat x;
+#endif
+	if (preprocessonly == 0 &&  strlen(out1) > 0)
+	{	(void) unlink((const char *) out1);
+	}
 
-	if (seedy && !analyze && !export_ast
+	(void) unlink(TMP_FILE1);
+	(void) unlink(TMP_FILE2);
+
+	if (!buzzed && seedy && !analyze && !export_ast
 	&& !s_trail && !preprocessonly && depth > 0)
-		printf("seed used: %d\n", SeedUsed);
+	{	printf("seed used: %d\n", SeedUsed);
+	}
 
-	if (xspin && (analyze || s_trail))
+	if (!buzzed && xspin && (analyze || s_trail))
 	{	if (estatus)
-			printf("spin: %d error(s) - aborting\n",
-			estatus);
-		else
-			printf("Exit-Status 0\n");
+		{	printf("spin: %d error(s) - aborting\n",
+				estatus);
+		} else
+		{	printf("Exit-Status 0\n");
+	}	}
+
+	if (buzzed && replay && !has_code && !estatus)
+	{	extern QH *qh;
+		QH *j;
+		int i;
+		char *tmp = (char *) emalloc(strlen("spin -t") +
+				strlen(pan_runtime) + strlen(Fname->name) + 8);
+		pan_runtime = (char *) emalloc(2048);	/* more than enough */
+		sprintf(pan_runtime, "-n%d ", SeedUsed);
+		if (jumpsteps)
+		{	sprintf(&pan_runtime[strlen(pan_runtime)], "-j%d ", jumpsteps);
+		}
+		if (trailfilename)
+		{	sprintf(&pan_runtime[strlen(pan_runtime)], "-k%s ", *trailfilename);
+		}
+		if (cutoff)
+		{	sprintf(&pan_runtime[strlen(pan_runtime)], "-u%d ", cutoff);
+		}
+		for (i = 1; i <= PreCnt; i++)
+		{	strcat(pan_runtime, PreArg[i]);
+			strcat(pan_runtime, " ");
+		}
+		for (j = qh; j; j = j->nxt)
+		{	sprintf(&pan_runtime[strlen(pan_runtime)], "-q%d ", j->n);
+		}
+		if (strcmp(PreProc, CPP) != 0)
+		{	sprintf(&pan_runtime[strlen(pan_runtime)], "\"-P%s\" ", PreProc);
+		}
+		/* -oN options 1..5 are ignored in simulations */
+		if (old_priority_rules) strcat(pan_runtime, "-o6 ");
+		if (!implied_semis)  strcat(pan_runtime, "-o7 ");
+		if (no_print)        strcat(pan_runtime, "-b ");
+		if (no_wrapup)       strcat(pan_runtime, "-B ");
+		if (columns == 1)    strcat(pan_runtime, "-c ");
+		if (columns == 2)    strcat(pan_runtime, "-M ");
+		if (seedy == 1)      strcat(pan_runtime, "-h ");
+		if (like_java == 1)  strcat(pan_runtime, "-J ");
+		if (old_scope_rules) strcat(pan_runtime, "-O ");
+		if (notabs)          strcat(pan_runtime, "-T ");
+		if (verbose&1)       strcat(pan_runtime, "-g ");
+		if (verbose&2)       strcat(pan_runtime, "-l ");
+		if (verbose&4)       strcat(pan_runtime, "-p ");
+		if (verbose&8)       strcat(pan_runtime, "-r ");
+		if (verbose&16)      strcat(pan_runtime, "-s ");
+		if (verbose&32)      strcat(pan_runtime, "-v ");
+		if (verbose&64)      strcat(pan_runtime, "-w ");
+		if (m_loss)          strcat(pan_runtime, "-m ");
+		sprintf(tmp, "spin -t %s %s", pan_runtime, Fname->name);
+		estatus = e_system(1, tmp);	/* replay */
+		exit(estatus);	/* replay without c_code */
+	}
+
+	if (buzzed && (!replay || has_code) && !estatus)
+	{	char *tmp, *tmp2 = NULL, *P_X;
+		char *C_X = (buzzed == 2) ? "-O" : "";
+
+		if (replay && strlen(pan_comptime) == 0)
+		{
+#if defined(WIN32) || defined(WIN64)
+			P_X = "pan";
+#else
+			P_X = "./pan";
+#endif
+			if (stat(P_X, (struct stat *)&x) < 0)
+			{	goto recompile;	/* no executable pan for replay */
+			}
+			tmp = (char *) emalloc(8 + strlen(P_X) + strlen(pan_runtime) +4);
+			/* the final +4 is too allow adding " &" in some cases */
+			sprintf(tmp, "%s %s", P_X, pan_runtime);
+			goto runit;
+		}
+#if defined(WIN32) || defined(WIN64)
+		P_X = "-o pan pan.c && pan";
+#else
+		P_X = "-o pan pan.c && ./pan";
+#endif
+		/* swarm and biterate randomization additions */
+		if (!replay && itsr)	/* iterative search refinement */
+		{	if (!strstr(pan_comptime, "-DBITSTATE"))
+			{	add_comptime("-DBITSTATE");
+			}
+			if (!strstr(pan_comptime, "-DPUTPID"))
+			{	add_comptime("-DPUTPID");
+			}
+			if (!strstr(pan_comptime, "-DT_RAND")
+			&&  !strstr(pan_comptime, "-DT_REVERSE"))
+			{	add_runtime("-T0  ");	/* controls t_reverse */
+			}
+			if (!strstr(pan_runtime, "-P")	/* runtime flag */
+			||   pan_runtime[2] < '0'
+			||   pan_runtime[2] > '1') /* no -P0 or -P1 */
+			{	add_runtime("-P0  ");	/* controls p_reverse */
+			}
+			if (!strstr(pan_runtime, "-w"))
+			{	add_runtime("-w18 ");	/* -w18 = 256K */
+			} else
+			{	char nv[32];
+				int x;
+				x = omit_str(pan_runtime, "-w");
+				if (x >= 0)
+				{	sprintf(nv, "-w%d  ", x);
+					add_runtime(nv); /* added spaces */
+			}	}
+			if (!strstr(pan_runtime, "-h"))
+			{	add_runtime("-h0  ");	/* 0..499 */
+				/* leave 2 spaces for increments up to -h499 */
+			} else if (!strstr(pan_runtime, "-hash"))
+			{	char nv[32];
+				int x;
+				x = omit_str(pan_runtime, "-h");
+				if (x >= 0)
+				{	sprintf(nv, "-h%d  ", x%500);
+					add_runtime(nv); /* added spaces */
+			}	}
+			if (!strstr(pan_runtime, "-k"))
+			{	add_runtime("-k1  ");	/* 1..3 */
+			} else
+			{	char nv[32];
+				int x;
+				x = omit_str(pan_runtime, "-k");
+				if (x >= 0)
+				{	sprintf(nv, "-k%d  ", x%4);
+					add_runtime(nv); /* added spaces */
+			}	}
+			if (strstr(pan_runtime, "-p_rotate"))
+			{	char nv[32];
+				int x;
+				x = omit_str(pan_runtime, "-p_rotate");
+				if (x < 0)
+				{	x = 0;
+				}
+				sprintf(nv, "-p_rotate%d  ", x%256);
+				add_runtime(nv); /* added spaces */
+			} else if (strstr(pan_runtime, "-p_permute") == 0)
+			{	add_runtime("-p_rotate0  ");
+			}
+			if (strstr(pan_runtime, "-RS"))
+			{	(void) omit_str(pan_runtime, "-RS");
+			}
+			/* need room for at least 10 digits */
+			add_runtime("-RS1234567890 ");
+			change_rs(pan_runtime);
+		}
+recompile:
+		if (strstr(PreProc, "cpp"))	/* unix/linux */
+		{	strcpy(PreProc, "gcc");	/* need compiler */
+		} else if ((tmp = strstr(PreProc, "-E")) != NULL)
+		{	*tmp = '\0'; /* strip preprocessing flags */
+		}
+
+		final_fiddle();
+		tmp = (char *) emalloc(8 +	/* account for alignment */
+				strlen(PreProc) +
+				strlen(C_X) +
+				strlen(pan_comptime) +
+				strlen(P_X) +
+				strlen(pan_runtime) +
+				strlen(" -p_reverse & "));
+		tmp2 = tmp;
+
+		/* P_X ends with " && ./pan " */
+		sprintf(tmp, "%s %s %s %s %s",
+			PreProc, C_X, pan_comptime, P_X, pan_runtime);
+
+		if (!replay)
+		{	if (itsr < 0)		/* swarm only */
+			{	strcat(tmp, " &"); /* after ./pan */
+				itsr = -itsr;	/* now same as biterate */
+			}
+			/* do compilation first
+			 * split cc command from run command
+			 * leave cc in tmp, and set tmp2 to run
+			 */
+			if ((ptr = strstr(tmp, " && ")) != NULL)
+			{	tmp2 = ptr + 4;	/* first run */
+				*ptr = '\0';
+		}	}
+
+		if (has_ltl)
+		{	(void) unlink("_spin_nvr.tmp");
+		}
+		if (!norecompile)
+		{
+#ifdef PC
+		/* make sure that if compilation fails we do not continue */
+		(void) unlink("./pan.exe");
+#else
+		(void) unlink("./pan");
+#endif
+		}
+runit:
+		if (norecompile && tmp != tmp2)
+		{	estatus = 0;
+		} else
+		{	if (itsr > 0)	/* else it happens below */
+			{	estatus = e_system(1, tmp);	/* compile or run */
+		}	}
+		if (replay || estatus < 0)
+		{	goto skipahead;
+		}
+		/* !replay */
+		if (itsr == 0)			/* single run */
+		{	estatus = e_system(1, tmp2);
+		} else if (itsr > 0)	/* iterative search refinement */
+		{	int is_swarm = 0;
+			if (tmp2 != tmp)	/* swarm: did only compilation so far */
+			{	tmp = tmp2;	/* now we point to the run command */
+				estatus = e_system(1, tmp);	/* first run */
+			}
+			itsr--;			/* count down */
+
+			/* the following are added back randomly later */
+			(void) omit_str(tmp, "-p_reverse");	/* replaced by spaces */
+			(void) omit_str(tmp, "-p_normal");
+
+			if (strstr(tmp, " &") != NULL)
+			{	(void) omit_str(tmp, " &");
+				is_swarm = 1;
+			}
+
+			/* increase -w every itsr_n-th run */
+			if ((itsr_n > 0 && (itsr == 0 || (itsr%itsr_n) != 0))
+			||  (change_param(tmp, "-w", 36, 18) >= 0))	/* max 4G bit statespace */
+			{	(void) change_param(tmp, "-h", 500, 0);	/* hash function 0.499 */
+				(void) change_param(tmp, "-p_rotate", 256, 0); /* if defined */
+				(void) change_param(tmp, "-k", 4, 1);	/* nr bits per state 0->1,2,3 */
+				(void) change_param(tmp, "-T", 2, 0);	/* with or without t_reverse*/
+				(void) change_param(tmp, "-P", 2, 0);	/* -P 0..1 != p_reverse */
+				change_rs(tmp);			/* change random seed */
+				string_trim(tmp);
+				if (rand()%5 == 0)		/* 20% of all runs */
+				{	strcat(tmp, " -p_reverse ");
+					/* at end, so this overrides -p_rotateN, if there */
+					/* but -P0..1 disable this in 50% of the cases */
+					/* so its really activated in 10% of all runs */
+				} else if (rand()%6 == 0) /* override p_rotate and p_reverse */
+				{	strcat(tmp, " -p_normal ");
+				}
+				if (is_swarm)
+				{	strcat(tmp, " &");
+				}
+				goto runit;
+		}	}
+skipahead:
+		(void) unlink("pan.b");
+		(void) unlink("pan.c");
+		(void) unlink("pan.h");
+		(void) unlink("pan.m");
+		(void) unlink("pan.p");
+		(void) unlink("pan.t");
 	}
 	exit(estatus);
 }
+#if 0
+	-P0	normal active process creation
+	-P1	reversed order for *active* process creation != p_reverse
+
+	-T0	normal transition exploration
+	-T1	reversed order of transition exploration
+
+	-DP_RAND	(random starting point +- -DP_REVERSE)
+	-DPERMUTED	(also enables -p_rotateN and -p_reverse)
+	-DP_REVERSE	(same as -DPERMUTED with -p_reverse, but 7% faster)
+
+	-DT_RAND	(random starting point -- optionally with -T0..1)
+	-DT_REVERSE	(superseded by -T0..1 options)
+
+	 -hash generates new hash polynomial for -h0
+
+	permutation modes:
+	 -permuted (adds -DPERMUTED) -- this is also the default with -swarm
+	 -t_reverse (same as -T1)
+	 -p_reverse (similar to -P1)
+	 -p_rotateN
+	 -p_normal
+
+	less useful would be (since there is less non-determinism in transitions):
+		-t_rotateN -- a controlled version of -DT_RAND
+
+	compiling with -DPERMUTED enables a number of new runtime options,
+	that -swarmN,M will also exploit:
+		-p_permute (default)
+		-p_rotateN
+		-p_reverse
+#endif
 
 void
 preprocess(char *a, char *b, int a_tmp)
-{	char precmd[512], cmd[1024]; int i;
+{	char precmd[1024], cmd[2048];
+	int i;
 #ifdef PC
-	extern int try_zpp(char *, char *);
-	if (PreCnt == 0 && try_zpp(a, b)) goto out;
+	/* gcc is sometimes a symbolic link to gcc-4
+	   that does not work well in cygwin, so we try
+	   to use the actual executable that is used.
+	   the code below assumes we are on a cygwin-like system
+	 */
+	if (strncmp(PreProc, "gcc ", strlen("gcc ")) == 0)
+	{	if (e_system(0, "gcc-4 --version > pan.pre") == 0)
+		{	strcpy(PreProc, "gcc-4 -std=gnu99 -E -x c");
+		} else if (e_system(0, "gcc-3 --version > pan.pre") == 0)
+		{	strcpy(PreProc, "gcc-3 -std=gnu99 -E -x c");
+	}	}
 #endif
+
+	assert(strlen(PreProc) < sizeof(precmd));
 	strcpy(precmd, PreProc);
 	for (i = 1; i <= PreCnt; i++)
 	{	strcat(precmd, " ");
 		strcat(precmd, PreArg[i]);
 	}
+	if (strlen(precmd) > sizeof(precmd))
+	{	fprintf(stdout, "spin: too many -D args, aborting\n");
+		alldone(1);
+	}
 	sprintf(cmd, "%s %s > %s", precmd, a, b);
-	if (system((const char *)cmd))
+	if (e_system(2, (const char *)cmd))		/* preprocessing */
 	{	(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)
 {
@@ -168,33 +595,73 @@
 	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-e compute synchronous product of multiple never claims (modified by -L)\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-F file  like -f, but with the LTL 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-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-k fname use the trailfile stored in file fname, see also -t\n");
+	printf("\t-L when using -e, use strict language intersection\n");
 	printf("\t-l print all local variables\n");
-	printf("\t-M print msc-flow in Postscript\n");
+	printf("\t-M generate msc-flow in tcl/tk format\n");
 	printf("\t-m lose msgs sent to full queues\n");
-	printf("\t-N file use never claim stored in file\n");
+	printf("\t-N fname use never claim stored in file fname\n");
 	printf("\t-nN seed for random nr generator\n");
+	printf("\t-O use old scope rules (pre 5.3.0)\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-o4 turn on rendezvous optiomizations in verifier\n");
+	printf("\t-o5 turn on case caching (reduces size of pan.m, but affects reachability reports)\n");
+	printf("\t-o6 revert to the old rules for interpreting priority tags (pre version 6.2)\n");
+	printf("\t-o7 revert to the old rules for semi-colon usage (pre version 6.3)\n");
 	printf("\t-Pxxx use xxx for preprocessing\n");
 	printf("\t-p print all statements\n");
+	printf("\t-pp pretty-print (reformat) stdin, write stdout\n");
 	printf("\t-qN suppress io for queue N in printouts\n");
 	printf("\t-r print receive events\n");
+	printf("\t-replay  replay an error trail-file found earlier\n");
+	printf("\t	if the model contains embedded c-code, the ./pan executable is used\n");
+	printf("\t	otherwise spin itself is used to replay the trailfile\n");
+	printf("\t	note that pan recognizes different runtime options than spin itself\n");
+	printf("\t-search  (or -run) generate a verifier, and compile and run it\n");
+	printf("\t      options before -search are interpreted by spin to parse the input\n");
+	printf("\t      options following a -search are used to compile and run the verifier pan\n");
+	printf("\t	    valid options that can follow a -search argument include:\n");
+	printf("\t	    -bfs	perform a breadth-first search\n");
+	printf("\t	    -bfspar	perform a parallel breadth-first search\n");
+	printf("\t	    -bcs	use the bounded-context-switching algorithm\n");
+	printf("\t	    -bitstate	or -bit, use bitstate storage\n");
+	printf("\t	    -biterate	use bitstate with iterative search refinement (-w18..-w35)\n");
+	printf("\t	    -swarmN,M like -biterate, but running all iterations in parallel\n");
+	printf("\t			perform N parallel runs and increment -w every M runs\n");
+	printf("\t			default value for N is 10, default for M is 1\n");
+	printf("\t			(add -w to see which commands will be executed)\n");
+	printf("\t			(add -W if ./pan exists and need not be recompiled)\n");
+	printf("\t	    -link file.c  link executable pan to file.c\n");
+	printf("\t	    -collapse	use collapse state compression\n");
+	printf("\t	    -hc  	use hash-compact storage\n");
+	printf("\t	    -noclaim	ignore all ltl and never claims\n");
+	printf("\t	    -p_permute	use process scheduling order random permutation\n");
+	printf("\t	    -p_rotateN	use process scheduling order rotation by N\n");
+	printf("\t	    -p_reverse	use process scheduling order reversal\n");
+	printf("\t	    -ltl p	verify the ltl property named p\n");
+	printf("\t	    -safety	compile for safety properties only\n");
+	printf("\t	    -i	    	use the dfs iterative shortening algorithm\n");
+	printf("\t	    -a	    	search for acceptance cycles\n");
+	printf("\t	    -l	    	search for non-progress cycles\n");
+	printf("\t	similarly, a -D... parameter can be specified to modify the compilation\n");
+	printf("\t	and any valid runtime pan argument can be specified for the verification\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-t[N] follow [Nth] simulation trail, see also -k\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");
@@ -204,8 +671,8 @@
 	alldone(1);
 }
 
-void
-optimizations(char nr)
+int
+optimizations(int nr)
 {
 	switch (nr) {
 	case '1':
@@ -243,37 +710,114 @@
 		printf("spin: case caching turned %s\n",
 			ccache?"on":"off");
 		break;
+	case '6':
+		old_priority_rules = 1;
+		if (verbose&32)
+		printf("spin: using old priority rules (pre version 6.2)\n");
+		return 0; /* no break */
+	case '7':
+		implied_semis = 0;
+		if (verbose&32)
+		printf("spin: no implied semi-colons (pre version 6.3)\n");
+		return 0; /* no break */
 	default:
 		printf("spin: bad or missing parameter on -o\n");
 		usage();
 		break;
 	}
+	return 1;
 }
 
-#if 0
-static int
-Rename(const char *old, char *new)
-{	FILE *fo, *fn;
-	char buf[1024];
+static void
+add_comptime(char *s)
+{	char *tmp;
 
-	if ((fo = fopen(old, "r")) == NULL)
-	{	printf("spin: cannot open %s\n", old);
-		return 1;
+	if (!s || strstr(pan_comptime, s))
+	{	return;
 	}
-	if ((fn = fopen(new, "w")) == NULL)
-	{	printf("spin: cannot create %s\n", new);
-		fclose(fo);
-		return 2;
+
+	tmp = (char *) emalloc(strlen(pan_comptime)+strlen(s)+2);
+	sprintf(tmp, "%s %s", pan_comptime, s);
+	pan_comptime = tmp;
+}
+
+static struct {
+	char *ifsee, *thendo;
+	int keeparg;
+} pats[] = {
+	{ "-bfspar",	"-DBFS_PAR",	0 },
+	{ "-bfs",	"-DBFS",	0 },
+	{ "-bcs",	"-DBCS",	0 },
+	{ "-bitstate",	"-DBITSTATE",	0 },
+	{ "-bit",	"-DBITSTATE",	0 },
+	{ "-hc",	"-DHC4",	0 },
+	{ "-collapse",	"-DCOLLAPSE",	0 },
+	{ "-noclaim",	"-DNOCLAIM",	0 },
+	{ "-permuted",	"-DPERMUTED",	0 },
+	{ "-p_permute", "-DPERMUTED",	1 },
+	{ "-p_rotate",	"-DPERMUTED",	1 },
+	{ "-p_reverse",	"-DPERMUTED",	1 },
+	{ "-safety",	"-DSAFETY",	0 },
+	{ "-i",		"-DREACH",	1 },
+	{ "-l",		"-DNP",		1 },
+	{ 0, 0 }
+};
+
+static void
+set_itsr_n(char *s)	/* e.g., -swarm12,3 */
+{	char *tmp;
+
+	if ((tmp = strchr(s, ',')) != NULL)
+	{	tmp++;
+		if (*tmp != '\0' && isdigit((int) *tmp))
+		{	itsr_n = atoi(tmp);
+			if (itsr_n < 2)
+			{	itsr_n = 0;
+	}	}	}
+}
+
+static void
+add_runtime(char *s)
+{	char *tmp;
+	int i;
+
+	if (strncmp(s, "-biterate", strlen("-biterate")) == 0)
+	{	itsr = 10;	/* default nr of sequential iterations */
+		if (isdigit((int) s[9]))
+		{	itsr = atoi(&s[9]);
+			if (itsr < 1)
+			{	itsr = 1;
+			}
+			set_itsr_n(s);
+		}
+		return;
 	}
-	while (fgets(buf, 1024, fo))
-		fputs(buf, fn);
+	if (strncmp(s, "-swarm", strlen("-swarm")) == 0)
+	{	itsr = -10;	/* parallel iterations */
+		if (isdigit((int) s[6]))
+		{	itsr = atoi(&s[6]);
+			if (itsr < 1)
+			{	itsr = 1;
+			}
+			itsr = -itsr;
+			set_itsr_n(s);
+		}
+		return;
+	}
 
-	fclose(fo);
-	fclose(fn);
+	for (i = 0; pats[i].ifsee; i++)
+	{	if (strncmp(s, pats[i].ifsee, strlen(pats[i].ifsee)) == 0)
+		{	add_comptime(pats[i].thendo);
+			if (pats[i].keeparg)
+			{	break;
+			}
+			return;
+	}	}
 
-	return 0;	/* success */
+	tmp = (char *) emalloc(strlen(pan_runtime)+strlen(s)+2);
+	sprintf(tmp, "%s %s", pan_runtime, s);
+	pan_runtime = tmp;
 }
-#endif
 
 int
 main(int argc, char *argv[])
@@ -285,17 +829,16 @@
 	yyin  = stdin;
 	yyout = stdout;
 	tl_out = stdout;
+	strcpy(CurScope, "_");
 
-	/* unused flags: e, w, x, y, z, A, G, I, L, O, Q, R, S, T, W */
+	assert(strlen(CPP) < sizeof(PreProc));
+	strcpy(PreProc, CPP);
+
+	/* unused flags: y, z, G, L, Q, R, 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 'a': analyze = 1; break;
 		case 'B': no_wrapup = 1; break;
 		case 'b': no_print = 1; break;
 		case 'C': Caccess = 1; break;
@@ -305,6 +848,7 @@
 		case 'd': dumptab =  1; break;
 		case 'E': PreArg[++PreCnt] = (char *) &argv[1][2];
 			  break;
+		case 'e': product++; break; /* see also 'L' */
 		case 'F': ltl_file = (char **) (argv+2);
 			  argc--; argv++; break;
 		case 'f': add_ltl = (char **) argv;
@@ -315,34 +859,110 @@
 		case 'I': inlineonly = 1; break;
 		case 'J': like_java = 1; break;
 		case 'j': jumpsteps = atoi(&argv[1][2]); break;
+		case 'k': s_trail = 1;
+			  trailfilename = (char **) (argv+2);
+			  argc--; argv++; break;
+		case 'L': Strict++; break; /* modified -e */
 		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]))
+		case 'O': old_scope_rules = 1; break;
+		case 'o': usedopts += optimizations(argv[1][2]); break;
+		case 'P': assert(strlen((const char *) &argv[1][2]) < sizeof(PreProc));
+			  strcpy(PreProc, (const char *) &argv[1][2]);
+			  break;
+		case 'p': if (argv[1][2] == 'p')
+			  {	pretty_print();
+				alldone(0);
+			  }
+			  verbose +=  4; break;
+		case 'q': if (isdigit((int) argv[1][2]))
 				qhide(atoi(&argv[1][2]));
 			  break;
-		case 'r': verbose +=  8; break;
-		case 's': verbose += 16; break;
+		case 'r':
+			  if (strcmp(&argv[1][1], "run") == 0)
+			  {	Srand((unsigned int) T);
+samecase:			if (buzzed != 0)
+				{ fatal("cannot combine -x with -run -replay or -search", (char *)0);
+				}
+				buzzed  = 2;
+				analyze = 1;
+				argc--; argv++;
+				/* process all remaining arguments as relating to pan: */
+				while (argc > 1 && argv[1][0] == '-')
+				{ switch (argv[1][1]) {
+				  case 'D': /* eg -DNP */
+			/*	  case 'E': conflicts with runtime arg */
+				  case 'O': /* eg -O2 */
+				  case 'U': /* to undefine a macro */
+					add_comptime(argv[1]);
+					break;
+				  case 'l':
+					if (strcmp(&argv[1][1], "ltl") == 0)
+					{	add_runtime("-N");
+						argc--; argv++;
+						add_runtime(argv[1]); /* prop name */
+						break;
+					}
+					if (strcmp(&argv[1][1], "link") == 0)
+					{	argc--; argv++;
+						add_comptime(argv[1]);
+						break;
+					}
+					/* else fall through */
+				  default:
+					add_runtime(argv[1]); /* -bfs etc. */
+					break;
+				  }
+				  argc--; argv++;
+				}
+				argc++; argv--;
+			  } else if (strcmp(&argv[1][1], "replay") == 0)
+			  {	replay = 1;
+				add_runtime("-r");
+				goto samecase;
+			  } else
+			  {	verbose +=  8;
+			  }
+			  break;
+		case 'S': separate = atoi(&argv[1][2]); /* S1 or S2 */
+			  /* generate code for separate compilation */
+			  analyze = 1; break;
+		case 's': 
+			  if (strcmp(&argv[1][1], "simulate") == 0)
+			  {	break; /* ignore */
+			  }
+			  if (strcmp(&argv[1][1], "search") == 0)
+			  {	goto samecase;
+			  }
+			  verbose += 16; break;
 		case 'T': notabs = 1; break;
 		case 't': s_trail  =  1;
-			  if (isdigit(argv[1][2]))
-				ntrail = atoi(&argv[1][2]);
+			  if (isdigit((int)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 'u': cutoff = atoi(&argv[1][2]); break;
 		case 'v': verbose += 32; break;
-		case 'V': printf("%s\n", Version);
+		case 'V': printf("%s\n", SpinVersion);
 			  alldone(0);
 			  break;
 		case 'w': verbose += 64; break;
+		case 'W': norecompile = 1; break;	/* 6.4.7: for swarm/biterate */
+		case 'x': /* internal - reserved use */
+			  if (buzzed != 0)
+			  {	fatal("cannot combine -x with -run -search or -replay", (char *)0);
+			  }
+			  buzzed = 1;	/* implies also -a -o3 */
+			  pan_runtime = "-d";
+			  analyze = 1; 
+			  usedopts += optimizations('3');
+			  break;
 		case 'X': xspin = notabs = 1;
 #ifndef PC
 			  signal(SIGPIPE, alldone); /* not posix... */
@@ -355,65 +975,75 @@
 		}
 		argc--; argv++;
 	}
+
+	if (columns == 2 && !cutoff)
+	{	cutoff = 1024;
+	}
+
 	if (usedopts && !analyze)
-		printf("spin: warning -o[123] option ignored in simulations\n");
-	
+		printf("spin: warning -o[1..5] option ignored in simulations\n");
+
 	if (ltl_file)
-	{	char formula[4096];
-		add_ltl = ltl_file-2; add_ltl[1][1] = 'f';
+	{	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);
+		if (!fgets(formula, 4096, tl_out))
+		{	printf("spin: cannot read %s\n", *ltl_file);
+		}
 		fclose(tl_out);
 		tl_out = stdout;
 		*ltl_file = (char *) formula;
 	}
 	if (argc > 1)
-	{	char cmd[128], out2[64];
+	{	FILE *fd = stdout;
+		char cmd[512], out2[512];
 
 		/* must remain in current dir */
 		strcpy(out1, "pan.pre");
 
 		if (add_ltl || nvr_file)
-			strcpy(out2, "pan.___");
+		{	assert(strlen(argv[1]) < sizeof(out2));
+			sprintf(out2, "%s.nvr", argv[1]);
+			if ((fd = fopen(out2, MFLAGS)) == NULL)
+			{	printf("spin: cannot create tmp file %s\n",
+					out2);
+				alldone(1);
+			}
+			fprintf(fd, "#include \"%s\"\n", argv[1]);
+		}
 
 		if (add_ltl)
-		{	tl_out = cpyfile(argv[1], out2);
-			nr_errs = tl_main(2, add_ltl);	/* in tl_main.c */
-			fclose(tl_out);
+		{	tl_out = fd;
+			nr_errs = tl_main(2, add_ltl);
+			fclose(fd);
 			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);
+		{	fprintf(fd, "#include \"%s\"\n", *nvr_file);
 			fclose(fd);
 			preprocess(out2, out1, 1);
 		} else
-			preprocess(argv[1], out1, 0);
+		{	preprocess(argv[1], out1, 0);
+		}
 
 		if (preprocessonly)
-			alldone(0);
+		{	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]);
+		assert(strlen(argv[1])+1 < sizeof(cmd));
+
+		if (strncmp(argv[1], "progress", (size_t) 8) == 0
+		||  strncmp(argv[1], "accept", (size_t) 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);
@@ -428,32 +1058,54 @@
 			printf("spin: missing argument to -f\n");
 			alldone(1);
 		}
-		printf("%s\n", Version);
-		printf("reading input from stdin:\n");
+		printf("%s\n", SpinVersion);
+		fprintf(stderr, "spin: error, no filename specified\n");
 		fflush(stdout);
+		alldone(1);
 	}
 	if (columns == 2)
 	{	extern void putprelude(void);
-		if (xspin || verbose&(1|4|8|16|32))
+		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);
+	{	verbose += (8+16);
+	}
 	if (columns == 2 && limited_vis)
-		verbose += (1+4);
-	Srand(T);	/* defined in run.c */
+	{	verbose += (1+4);
+	}
+
+	Srand((unsigned int) 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 */
+	s = lookup("_priority"); s->type = PREDEF; /* new 6.2.0 */
 
 	yyparse();
 	fclose(yyin);
+
+	if (ltl_claims)
+	{	Symbol *r;
+		fclose(fd_ltl);
+		if (!(yyin = fopen(ltl_claims, "r")))
+		{	fatal("cannot open %s", ltl_claims);
+		}
+		r = oFname;
+		oFname = Fname = lookup(ltl_claims);
+		lineno = 0;
+		yyparse();
+		fclose(yyin);
+		oFname = Fname = r;
+		if (0)
+		{	(void) unlink(ltl_claims);
+	}	}
+
 	loose_ends();
 
 	if (inlineonly)
@@ -463,31 +1115,73 @@
 
 	chanaccess();
 	if (!Caccess)
-	{	if (!s_trail && (dataflow || merger))
-			ana_src(dataflow, merger);
+	{	if (has_provided && merger)
+		{	merger = 0;	/* cannot use statement merging in this case */
+		}
+		if (!s_trail && (dataflow || merger) && (!replay || has_code))
+		{	ana_src(dataflow, merger);
+		}
 		sched();
 		alldone(nr_errs);
 	}
+
 	return 0;
 }
 
-int
-yywrap(void)	/* dummy routine */
+void
+ltl_list(char *nm, char *fm)
 {
-	return 1;
+	if (s_trail
+	||  analyze
+	||  dumptab)	/* when generating pan.c or replaying a trace */
+	{	if (!ltl_claims)
+		{	ltl_claims = "_spin_nvr.tmp";
+			if ((fd_ltl = fopen(ltl_claims, MFLAGS)) == NULL)
+			{	fatal("cannot open tmp file %s", ltl_claims);
+			}
+			tl_out = fd_ltl;
+		}
+
+		add_ltl = (char **) emalloc(5 * sizeof(char *));
+		add_ltl[1] = "-c";
+		add_ltl[2] = nm;
+		add_ltl[3] = "-f";
+		add_ltl[4] = (char *) emalloc(strlen(fm)+4);
+		strcpy(add_ltl[4], "!(");
+		strcat(add_ltl[4], fm);
+		strcat(add_ltl[4], ")");
+		/* add_ltl[4] = fm; */
+		nr_errs += tl_main(4, add_ltl);
+
+		fflush(tl_out);
+		/* should read this file after the main file is read */
+	}
 }
 
 void
 non_fatal(char *s1, char *s2)
-{	extern char yytext[];
+{	extern int yychar; extern char yytext[];
 
-	printf("spin: line %3d %s, Error: ",
-		lineno, Fname?Fname->name:"nofilename");
+	printf("spin: %s:%d, Error: ",
+		Fname?Fname->name:(oFname?oFname->name:"nofilename"), lineno);
+#if 1
+	printf(s1, s2); /* avoids a gcc warning */
+#else
 	if (s2)
 		printf(s1, s2);
 	else
 		printf(s1);
-	if (yytext && strlen(yytext)>1)
+	if (yychar > 0)
+	{	if (yychar == SEMI)
+		{	printf(" statement separator");
+		} else
+		{	printf("	saw '");
+			explain(yychar);
+			printf("'");
+	}	}
+#endif
+
+	if (strlen(yytext)>1)
 		printf(" near '%s'", yytext);
 	printf("\n");
 	nr_errs++;
@@ -497,37 +1191,52 @@
 fatal(char *s1, char *s2)
 {
 	non_fatal(s1, s2);
+	(void) unlink("pan.b");
+	(void) unlink("pan.c");
+	(void) unlink("pan.h");
+	(void) unlink("pan.m");
+	(void) unlink("pan.t");
+	(void) unlink("pan.p");
+	(void) unlink("pan.pre");
+	if (!(verbose&32))
+	{	(void) unlink("_spin_nvr.tmp");
+	}
 	alldone(1);
 }
 
 char *
-emalloc(int n)
+emalloc(size_t n)
 {	char *tmp;
+	static unsigned long cnt = 0;
 
 	if (n == 0)
 		return NULL;	/* robert shelton 10/20/06 */
 
 	if (!(tmp = (char *) malloc(n)))
+	{	printf("spin: allocated %ld Gb, wanted %d bytes more\n",
+			cnt/(1024*1024*1024), (int) n);
 		fatal("not enough memory", (char *)0);
+	}
+	cnt += (unsigned long) n;
 	memset(tmp, 0, n);
 	return tmp;
 }
 
 void
-trapwonly(Lextok *n, char *unused)
-{	extern int realread;
-	short i = (n->sym)?n->sym->type:0;
+trapwonly(Lextok *n /* , char *unused */)
+{	short i = (n->sym)?n->sym->type:0;
 
-	if (i != MTYPE
-	&&  i != BIT
-	&&  i != BYTE
-	&&  i != SHORT
-	&&  i != INT
-	&&  i != UNSIGNED)
-		return;
+	/* printf("%s	realread %d type %d\n", n->sym?n->sym->name:"--", realread, i); */
 
-	if (realread)
-	n->sym->hidden |= 128;	/* var is read at least once */
+	if (realread
+	&& (i == MTYPE
+	||  i == BIT
+	||  i == BYTE
+	||  i == SHORT
+	||  i == INT
+	||  i == UNSIGNED))
+	{	n->sym->hidden |= 128;	/* var is read at least once */
+	}
 }
 
 void
@@ -555,7 +1264,8 @@
 {	Lextok *n = (Lextok *) emalloc(sizeof(Lextok));
 	static int warn_nn = 0;
 
-	n->ntyp = (short) t;
+	n->uiid = is_inline();	/* record origin of the statement */
+	n->ntyp = (unsigned short) t;
 	if (s && s->fn)
 	{	n->ln = s->ln;
 		n->fn = s->fn;
@@ -679,13 +1389,13 @@
 #endif
 }
 
-static void
+void
 explain(int n)
 {	FILE *fd = stdout;
 	switch (n) {
 	default:	if (n > 0 && n < 256)
-				fprintf(fd, "'%c' = '", n);
-			fprintf(fd, "%d'", n);
+				fprintf(fd, "'%c' = ", n);
+			fprintf(fd, "%d", n);
 			break;
 	case '\b':	fprintf(fd, "\\b"); break;
 	case '\t':	fprintf(fd, "\\t"); break;
@@ -698,6 +1408,16 @@
 	case 'R':	fprintf(fd, "recv poll %s", Operator); break;
 	case '@':	fprintf(fd, "@"); break;
 	case '?':	fprintf(fd, "(x->y:z)"); break;
+#if 1
+	case NEXT:	fprintf(fd, "X"); break;
+	case ALWAYS:	fprintf(fd, "[]"); break;
+	case EVENTUALLY: fprintf(fd, "<>"); break;
+	case IMPLIES:	fprintf(fd, "->"); break;
+	case EQUIV:	fprintf(fd, "<->"); break;
+	case UNTIL:	fprintf(fd, "U"); break;
+	case WEAK_UNTIL: fprintf(fd, "W"); break;
+	case IN: fprintf(fd, "%sin", Keyword); break;
+#endif
 	case ACTIVE:	fprintf(fd, "%sactive",	Keyword); break;
 	case AND:	fprintf(fd, "%s&&",	Operator); break;
 	case ASGN:	fprintf(fd, "%s=",	Operator); break;
@@ -724,6 +1444,7 @@
 	case FI:	fprintf(fd, "%sfi",	Keyword); break;
 	case FULL:	fprintf(fd, "%sfull",	Function); break;
 	case GE:	fprintf(fd, "%s>=",	Operator); break;
+	case GET_P:	fprintf(fd, "%sget_priority",Function); break;
 	case GOTO:	fprintf(fd, "%sgoto",	Keyword); break;
 	case GT:	fprintf(fd, "%s>",	Operator); break;
 	case HIDDEN:	fprintf(fd, "%shidden",	Keyword); break;
@@ -763,6 +1484,8 @@
 	case RUN:	fprintf(fd, "%srun",	Operator); break;
 	case SEP:	fprintf(fd, "token: ::"); break;
 	case SEMI:	fprintf(fd, ";"); break;
+	case ARROW:	fprintf(fd, "->"); break;
+	case SET_P:	fprintf(fd, "%sset_priority",Function); break;
 	case SHOW:	fprintf(fd, "%sshow", Keyword); break;
 	case SND:	fprintf(fd, "%s!",	Operator); break;
 	case STRING:	fprintf(fd, "a string"); break;
@@ -776,3 +1499,5 @@
 	case UNLESS:	fprintf(fd, "%sunless",	Keyword); break;
 	}
 }
+
+
diff -r 51b3bf8bc61b sys/src/cmd/spin/mesg.c
--- a/sys/src/cmd/spin/mesg.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/mesg.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,14 +1,12 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
+#include <stdlib.h>
 #include "spin.h"
 #include "y.tab.h"
 
@@ -24,9 +22,10 @@
 extern int	nproc, nstop;
 extern short	Have_claim;
 
+QH	*qh;
 Queue	*qtab = (Queue *) 0;	/* linked list of queues */
 Queue	*ltab[MAXQ];		/* linear list of queues */
-int	nqs = 0, firstrow = 1;
+int	nqs = 0, firstrow = 1, has_stdin = 0;
 char	Buf[4096];
 
 static Lextok	*n_rem = (Lextok *) 0;
@@ -73,7 +72,7 @@
 		return eval(s->ini);
 
 	q = (Queue *) emalloc(sizeof(Queue));
-	q->qid    = ++nqs;
+	q->qid    = (short) ++nqs;
 	q->nslots = s->ini->val;
 	q->nflds  = cnt_mpars(s->ini->rgt);
 	q->setat  = depth;
@@ -130,7 +129,7 @@
 
 	if (whichq == -1)
 	{	printf("Error: sending to an uninitialized chan\n");
-		whichq = 0;
+		/* whichq = 0; */
 		return 0;
 	}
 	if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
@@ -143,6 +142,37 @@
 	return 0;
 }
 
+#ifndef PC
+ #include <termios.h>
+ static struct termios initial_settings, new_settings;
+
+ void
+ peek_ch_init(void)
+ {
+	tcgetattr(0,&initial_settings);
+ 
+	new_settings = initial_settings;
+	new_settings.c_lflag &= ~ICANON;
+	new_settings.c_lflag &= ~ECHO;
+	new_settings.c_lflag &= ~ISIG;
+	new_settings.c_cc[VMIN] = 0;
+	new_settings.c_cc[VTIME] = 0;
+ }
+
+ int
+ peek_ch(void)
+ {	int n;
+
+	has_stdin = 1;
+
+	tcsetattr(0, TCSANOW, &new_settings);
+	n = getchar();
+	tcsetattr(0, TCSANOW, &initial_settings);
+
+	return n;
+ }
+#endif
+
 int
 qrecv(Lextok *n, int full)
 {	int whichq = eval(n->lft)-1;
@@ -150,22 +180,37 @@
 	if (whichq == -1)
 	{	if (n->sym && !strcmp(n->sym->name, "STDIN"))
 		{	Lextok *m;
-
+#ifndef PC
+			static int did_once = 0;
+			if (!did_once) /* 6.2.4 */
+			{	peek_ch_init();
+				did_once = 1;
+			}
+#endif
 			if (TstOnly) return 1;
 
 			for (m = n->rgt; m; m = m->rgt)
 			if (m->lft->ntyp != CONST && m->lft->ntyp != EVAL)
-			{	int c = getchar();
+			{
+#ifdef PC
+				int c = getchar();
+#else
+				int c = peek_ch();	/* 6.2.4, was getchar(); */
+#endif
+				if (c == 27 || c == 3)	/* escape or control-c */
+				{	printf("quit\n");
+					exit(0);
+				} /* else: non-blocking */
+				if (c == EOF) return 0;	/* no char available */
 				(void) setval(m->lft, c);
 			} else
-				fatal("invalid use of STDIN", (char *)0);
-
-			whichq = 0;
+			{	fatal("invalid use of STDIN", (char *)0);
+			}
 			return 1;
 		}
 		printf("Error: receiving from an uninitialized chan %s\n",
 			n->sym?n->sym->name:"");
-		whichq = 0;
+		/* whichq = 0; */
 		return 0;
 	}
 	if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
@@ -185,9 +230,11 @@
 	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;
+		if (New == Old)
+			continue;
+		if (New >  Old)
+			break;	/* inner loop */
+		goto found;	/* New < Old */
 	}
 found:
 	for (j = q->qlen-1; j >= i; j--)
@@ -204,7 +251,8 @@
 typ_ck(int ft, int at, char *s)
 {
 	if ((verbose&32) && ft != at
-	&& (ft == CHAN || at == CHAN))
+	&& (ft == CHAN || at == CHAN)
+	&& (at != PREDEF || strcmp(s, "recv") != 0))
 	{	char buf[128], tag1[64], tag2[64];
 		(void) sputtype(tag1, ft);
 		(void) sputtype(tag2, at);
@@ -383,7 +431,7 @@
 	return 1;
 }
 
-void
+static void
 channm(Lextok *n)
 {	char lbuf[512];
 
@@ -394,7 +442,11 @@
 	else if (n->sym->type == STRUCT)
 	{	Symbol *r = n->sym;
 		if (r->context)
-			r = findloc(r);
+		{	r = findloc(r);
+			if (!r)
+			{	strcat(Buf, "*?*");
+				return;
+		}	}
 		ini_struct(r);
 		printf("%s", r->name);
 		strcpy(lbuf, "");
@@ -422,7 +474,11 @@
 	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 (s_trail)
+		{	cnr = pno;
+		} else
+		{	cnr = X?X->pid - Have_claim:0;
+		}
 		if (tr[0] == '[') strcat(Buf, "]");
 		pstext(cnr, Buf);
 	}
@@ -458,12 +514,6 @@
 	}
 }
 
-typedef struct QH {
-	int	n;
-	struct	QH *nxt;
-} QH;
-QH *qh;
-
 void
 qhide(int q)
 {	QH *p = (QH *) emalloc(sizeof(QH));
@@ -483,7 +533,7 @@
 
 static void
 sr_talk(Lextok *n, int v, char *tr, char *a, int j, Queue *q)
-{	char s[64];
+{	char s[128];
 
 	if (qishidden(eval(n->lft)))
 		return;
@@ -510,9 +560,20 @@
 	}
 
 	if (j == 0)
-	{	whoruns(1);
-		printf("line %3d %s %s",
-			n->ln, n->fn->name, s);
+	{	char snm[128];
+		whoruns(1);
+		{	char *ptr = n->fn->name;
+			char *qtr = snm;
+			while (*ptr != '\0')
+			{	if (*ptr != '\"')
+				{	*qtr++ = *ptr;
+				}
+				ptr++;
+			}
+			*qtr = '\0';
+			printf("%s:%d %s",
+				snm, n->ln, s);
+		}
 	} else
 		printf(",");
 	sr_mesg(stdout, v, q->fld_width[j] == MTYPE);
@@ -554,7 +615,11 @@
 sr_mesg(FILE *fd, int v, int j)
 {	Buf[0] ='\0';
 	sr_buf(v, j);
+#if 1
+	fprintf(fd, Buf, (char *) 0); /* prevent compiler warning */
+#else
 	fprintf(fd, Buf);
+#endif
 }
 
 void
@@ -572,10 +637,15 @@
 			continue;
 		if (q->nslots == 0)
 			continue; /* rv q always empty */
+#if 0
+		if (q->qlen == 0)	/* new 7/10 -- dont show if queue is empty */
+		{	continue;
+		}
+#endif
 		printf("\t\tqueue %d (", q->qid);
 		if (r)
 		printf("%s(%d):", r->n->name, r->pid - Have_claim);
-		if (s->nel != 1)
+		if (s->nel > 1 || s->isarray)
 		  printf("%s[%d]): ", s->name, n);
 		else
 		  printf("%s): ", s->name);
@@ -609,7 +679,11 @@
 		}	
 	}
 
-	if (!n || n->ntyp == LEN || n->ntyp == RUN)
+	/* ok on the rhs of an assignment: */
+	if (!n || n->ntyp == LEN || n->ntyp == RUN
+	||  n->ntyp == FULL  || n->ntyp == NFULL
+	||  n->ntyp == EMPTY || n->ntyp == NEMPTY
+	||  n->ntyp == 'R')
 		return;
 
 	if (n->sym && n->sym->type == CHAN)
@@ -627,6 +701,121 @@
 	nochan_manip(p, n->rgt, 1);
 }
 
+typedef struct BaseName {
+	char *str;
+	int cnt;
+	struct BaseName *nxt;
+} BaseName;
+
+static BaseName *bsn;
+
+void
+newbasename(char *s)
+{	BaseName *b;
+
+/*	printf("+++++++++%s\n", s);	*/
+	for (b = bsn; b; b = b->nxt)
+		if (strcmp(b->str, s) == 0)
+		{	b->cnt++;
+			return;
+		}
+	b = (BaseName *) emalloc(sizeof(BaseName));
+	b->str = emalloc(strlen(s)+1);
+	b->cnt = 1;
+	strcpy(b->str, s);
+	b->nxt = bsn;
+	bsn = b;
+}
+
+void
+delbasename(char *s)
+{	BaseName *b, *prv = (BaseName *) 0;
+
+	for (b = bsn; b; prv = b, b = b->nxt)
+	{	if (strcmp(b->str, s) == 0)
+		{	b->cnt--;
+			if (b->cnt == 0)
+			{	if (prv)
+				{	prv->nxt = b->nxt;
+				} else
+				{	bsn = b->nxt;
+			}	}
+/*	printf("---------%s\n", s);	*/
+			break;
+	}	}
+}
+
+void
+checkindex(char *s, char *t)
+{	BaseName *b;
+
+/*	printf("xxx Check %s (%s)\n", s, t);	*/
+	for (b = bsn; b; b = b->nxt)
+	{
+/*		printf("	%s\n", b->str);	*/
+		if (strcmp(b->str, s) == 0)
+		{	non_fatal("do not index an array with itself (%s)", t);
+			break;
+	}	}
+}
+
+void
+scan_tree(Lextok *t, char *mn, char *mx)
+{	char sv[512];
+	char tmp[32];
+	int oln = lineno;
+
+	if (!t) return;
+
+	lineno = t->ln;
+
+	if (t->ntyp == NAME)
+	{	strcat(mn, t->sym->name);
+		strcat(mx, t->sym->name);
+		if (t->lft)		/* array index */
+		{	strcat(mn, "[]");
+			newbasename(mn);
+				strcpy(sv, mn);		/* save */
+				strcpy(mn, "");		/* clear */
+				strcat(mx, "[");
+				scan_tree(t->lft, mn, mx);	/* index */
+				strcat(mx, "]");
+				checkindex(mn, mx);	/* match against basenames */
+				strcpy(mn, sv);		/* restore */
+			delbasename(mn);
+		}
+		if (t->rgt)	/* structure element */
+		{	scan_tree(t->rgt, mn, mx);
+		}
+	} else if (t->ntyp == CONST)
+	{	strcat(mn, "1"); /* really: t->val */
+		sprintf(tmp, "%d", t->val);
+		strcat(mx, tmp);
+	} else if (t->ntyp == '.')
+	{	strcat(mn, ".");
+		strcat(mx, ".");
+		scan_tree(t->lft, mn, mx);
+	} else
+	{	strcat(mn, "??");
+		strcat(mx, "??");
+	}
+	lineno = oln;
+}
+
+void
+no_nested_array_refs(Lextok *n)	/* a [ a[1] ] with a[1] = 1, causes trouble in pan.b */
+{	char mn[512];
+	char mx[512];
+
+/*	printf("==================================ZAP\n");	*/
+	bsn = (BaseName *) 0;	/* start new list */
+	strcpy(mn, "");
+	strcpy(mx, "");
+
+	scan_tree(n, mn, mx);
+/*	printf("==> %s\n", mn);	*/
+}
+
 void
 no_internals(Lextok *n)
 {	char *sp;
@@ -638,7 +827,10 @@
 	sp = n->sym->name;
 
 	if ((strlen(sp) == strlen("_nr_pr") && strcmp(sp, "_nr_pr") == 0)
+	||  (strlen(sp) == strlen("_pid") && strcmp(sp, "_pid") == 0)
 	||  (strlen(sp) == strlen("_p") && strcmp(sp, "_p") == 0))
-	{	fatal("attempt to assign value to system variable %s", sp);
+	{	fatal("invalid assignment to %s", sp);
 	}
+
+	no_nested_array_refs(n);
 }
diff -r 51b3bf8bc61b sys/src/cmd/spin/mkfile
--- a/sys/src/cmd/spin/mkfile	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/mkfile	Wed Nov 22 00:21:47 2017 -0800
@@ -8,14 +8,14 @@
 	guided.$O\
 	main.$O\
 	mesg.$O\
+	msc_tcl.$O\
 	pangen1.$O\
 	pangen2.$O\
 	pangen3.$O\
 	pangen4.$O\
 	pangen5.$O\
 	pangen6.$O\
-	pc_zpp.$O\
-	ps_msc.$O\
+	pangen7.$O\
 	reprosrc.$O\
 	run.$O\
 	sched.$O\
@@ -45,7 +45,7 @@
 </sys/src/cmd/mkone
 
 CC=pcc -c
-CFLAGS=-B -D_POSIX_SOURCE
+CFLAGS=-B -D_POSIX_SOURCE -D_PLAN9
 YFLAGS=-S -d
 
 $SPIN_OS:	spin.h
diff -r 51b3bf8bc61b sys/src/cmd/spin/msc_tcl.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/cmd/spin/msc_tcl.c	Wed Nov 22 00:21:47 2017 -0800
@@ -0,0 +1,376 @@
+/***** spin: msc_tcl.c *****/
+
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
+
+#include <stdlib.h>
+#include "spin.h"
+#include "version.h"
+
+#define MW	500	/* page width */
+#define RH	100	/* right margin */
+#define WW	 80	/* distance between process lines */
+#define HH	 12	/* vertical distance between steps */
+#define LW	  2	/* line width of message arrows */
+
+#define RVC	"darkred"	/* rendezvous arrows */
+#define MPC	"darkblue"	/* asynchronous message passing arrow */
+#define GRC	"lightgrey"	/* grid lines */
+
+static int	MH = 600;	/* anticipated page-length */
+static FILE	*pfd;
+static char	**I;		/* initial procs */
+static int	*D,*R;		/* maps between depth (stepnr) and ldepth (msc-step) */
+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 int	ProcLine[256];	/* active processes */
+static int	UsedLine[256];	/* process line has at least one entry */
+static int	ldepth = 1;
+static int	maxx, TotSteps = 2*4096; /* max nr of steps for simulation output */
+static float	Scaler = (float) 1.0;
+
+static int	xscale = 2;
+static int	yscale = 1;
+static int	no_box;
+
+extern int	ntrail, s_trail, pno, depth;
+extern Symbol	*oFname;
+
+extern void	exit(int);
+extern void	putpostlude(void);
+
+static void	putpages(void);
+
+static void
+psline(int x0, int y0, int x1, int y1, char *color)
+{	char *side = "last";
+
+	if (x0 == x1)	/* gridline */
+	{	fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags grid -width 1 \n",
+			xscale*(x0+1)*WW-20, yscale*y0+20,
+			xscale*(x1+1)*WW-20, yscale*y1+20, color);
+		fprintf(pfd, ".c lower grid\n");
+	} else
+	{	int xm = xscale*(x0+1)*WW + (xscale*(x1 - x0)*WW)/2 - 20;	/* mid x */
+
+		if (y1 - y0  <= HH+20)
+		{	y1 = y0+20; /* close enough to horizontal - looks better */
+		}
+ 
+		fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags mesg -width %d\n",
+			xscale*(x0+1)*WW-20, yscale*y0+20+10,
+			xm,                  yscale*y0+20+10, color, LW);
+
+		if (y1 != y0+20)
+		{	fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags mesg -width %d\n",
+				xm, yscale*y0+20+10,
+				xm, yscale*y1+20-10, color, LW);
+		}
+
+		fprintf(pfd, ".c create line %d %d %d %d -fill %s -width %d ",
+			xm,                  yscale*y1+20-10,
+			xscale*(x1+1)*WW-20, yscale*y1+20-10, color, LW);
+
+		if (strcmp(color, RVC) == 0)
+		{	side = "both";
+		}
+		fprintf(pfd, "-arrow %s -arrowshape {5 5 5} -tags mesg\n", side);
+		fprintf(pfd, ".c raise mesg\n");
+	}
+}
+
+static void
+colbox(int ix, int iy, int w, int h_unused, char *color)
+{	int x = ix*WW;
+	int y = iy*HH;
+
+	if (ix < 0 || ix > 255)
+	{	fatal("msc_tcl: unexpected\n", (char *) 0);
+	}
+
+	if (ProcLine[ix] < iy)
+	{	/* if (ProcLine[ix] > 0) */
+		{	psline(ix-1, ProcLine[ix]*HH+HH+4,
+			       ix-1, iy*HH-HH, GRC);
+		}
+		fprintf(pfd, "# ProcLine[%d] from %d to %d (Used %d nobox %d)\n",
+			ix, ProcLine[ix], iy, UsedLine[ix], no_box);
+		ProcLine[ix] = iy;
+	} else
+	{	fprintf(pfd, "# ProcLine[%d] stays at %d (Used %d nobox %d)\n",
+			ix, ProcLine[ix], UsedLine[ix], no_box);
+	}
+
+	if (UsedLine[ix])
+	{	no_box = 2;
+	}
+
+	if (strcmp(color, "black") == 0)
+	{	if (no_box == 0)	/* shadow */
+		{	fprintf(pfd, ".c create rectangle %d %d %d %d -fill black\n",
+				xscale*x-(xscale*4*w/3)-20+4, (yscale*y-10)+20+2,
+				xscale*x+(xscale*4*w/3)-20,   (yscale*y+10)+20+2);
+		}
+	} else
+	{	if (no_box == 0)	/* box with outline */
+		{	fprintf(pfd, ".c create rectangle %d %d %d %d -fill ivory\n",
+				xscale*x-(xscale*4*w/3)-20, (yscale*y-10)+20,
+				xscale*x+(xscale*4*w/3)-20, (yscale*y+10)+20);
+			UsedLine[ix]++;
+		} else			/* no outline */
+		{	fprintf(pfd, ".c create rectangle %d %d %d %d -fill white -width 0\n",
+				xscale*x-(xscale*4*w/3)-20, (yscale*y-10)+20,
+				xscale*x+(xscale*4*w/3)-20, (yscale*y+10)+20);
+	}	}
+	if (no_box > 0)
+	{	no_box--;
+	}
+}
+
+static void
+stepnumber(int i)
+{	int y = (yscale*i*HH) + 20;
+
+	fprintf(pfd, ".c create text %d %d -fill #eef -text \"%d\"\n",
+		-10+(xscale*WW)/2, y, i);
+
+	/* horizontal dashed grid line */
+	fprintf(pfd, ".c create line %d %d %d %d -fill #eef -dash {6 4}\n",
+		-20+WW*xscale, y, (maxx+1)*WW*xscale-20, y);
+}
+
+static void
+spitbox(int ix, int y, char *s)
+{	float bw;	/* box width */
+	char d[256], *t, *z;
+	int a, i, x = ix+1;
+	char *color = "black";
+
+	if (y > 0)
+	{	stepnumber(y);
+	}
+
+	bw = (float)1.8*(float)strlen(s);	/* guess at default font width */
+	colbox(x, y, (int) (bw+1.0), 5, "black");
+	if (s[0] == '~')
+	{	switch (s[1]) {
+		default :
+		case 'R': color = "red";   break;
+		case 'B': color = "blue";  break;
+		case 'G': color = "green"; break;
+		}
+		s += 2;
+	} else if (strchr(s, '!'))
+	{	color = "ivory";
+	} else if (strchr(s, '?'))
+	{	color = "azure";
+	} else
+	{	color = "pink";
+		if (sscanf(s, "%d:%250s", &a, d) == 2
+		&&  a >= 0 && a < TotSteps)
+		{	if (!I[a]  || strlen(I[a]) <= strlen(s))
+			{	I[a] = (char *) emalloc((int) strlen(s)+1);
+			}
+			strcpy(I[a], s);
+	}	}
+
+	colbox(x, y, (int) bw, 4, color);
+
+	z = t = (char *) emalloc(2*strlen(s)+1);
+
+	for (i = 0; i < (int) strlen(s); i++)
+	{	if (s[i] == '\n')
+		{	continue;
+		}
+		if (s[i] == '[' || s[i] == ']')
+		{	*t++ = '\\';
+		}
+		*t++ = s[i];
+	}
+
+	fprintf(pfd, ".c create text %d %d -text \"%s\"\n",
+		xscale*x*WW-20, yscale*y*HH+20, z);
+}
+
+static void
+putpages(void)
+{	int i, lasti=0; float nmh;
+
+	if (maxx*xscale*WW > MW-RH/2)
+	{	Scaler = (float) (MW-RH/2) / (float) (maxx*xscale*WW);
+		nmh = (float) MH; nmh /= Scaler; MH = (int) nmh;
+		fprintf(pfd, "# Scaler %f, MH %d\n", Scaler, MH);
+	}
+	if (ldepth >= TotSteps)
+	{	ldepth = TotSteps-1;
+	}
+
+/* W: (maxx+2)*xscale*WW  */
+/* H: ldepth*HH*yscale+50 */
+	fprintf(pfd, "wm title . \"scenario\"\n");
+	fprintf(pfd, "wm geometry . %dx600+650+100\n", (maxx+2)*xscale*WW);
+
+	fprintf(pfd, "canvas .c -width 800 -height 800 \\\n");
+	fprintf(pfd, "	-scrollregion {0c -1c 30c 100c} \\\n");
+	fprintf(pfd, "	-xscrollcommand \".hscroll set\" \\\n");
+	fprintf(pfd, "	-yscrollcommand \".vscroll set\" \\\n");
+	fprintf(pfd, "	-bg white -relief raised -bd 2\n");
+
+	fprintf(pfd, "scrollbar .vscroll -relief sunken ");
+	fprintf(pfd, " -command \".c yview\"\n");
+	fprintf(pfd, "scrollbar .hscroll -relief sunken -orient horiz ");
+	fprintf(pfd, " -command \".c xview\"\n");
+
+	fprintf(pfd, "pack append . \\\n");
+	fprintf(pfd, "	.vscroll {right filly} \\\n");
+	fprintf(pfd, "	.hscroll {bottom fillx} \\\n");
+	fprintf(pfd, "	.c {top expand fill}\n");
+
+	fprintf(pfd, ".c yview moveto 0\n");
+
+	for (i = TotSteps-1; i >= 0; i--)
+	{	if (I[i])
+		{	spitbox(i, -1, I[i]);
+	}	}
+
+	for (i = 0; i <= ldepth; i++)
+	{	if (!M[i] && !L[i])
+		{	continue;	/* no box */
+		}
+		if (T[i] > 0)		/* arrow */
+		{	if (T[i] == i)	/* rv handshake */
+			{	psline(	M[lasti], lasti*HH,
+					M[i],     i*HH, RVC);
+			} else
+			{	psline(	M[i],     i*HH,
+					M[T[i]],  T[i]*HH, MPC);
+		}	}
+		if (L[i])
+		{	spitbox(M[i], i, L[i]);
+			lasti = i;
+	}	}
+}
+
+static void
+putbox(int x)
+{
+	if (ldepth >= TotSteps)
+	{	fprintf(stderr, "max length of %d steps exceeded - ps file truncated\n",
+			TotSteps);
+		putpostlude();
+	}
+	M[ldepth] = x;
+	if (x > maxx)
+	{	maxx = x;
+		fprintf(pfd, "# maxx %d\n", x);
+	}
+}
+
+/* functions called externally: */
+
+extern int WhatSeed(void);
+
+void
+putpostlude(void)
+{	char cmd[512];
+
+	putpages();
+	fprintf(pfd, ".c lower grid\n");
+	fprintf(pfd, ".c raise mesg\n");
+	fclose(pfd);
+
+	fprintf(stderr, "seed used: -n%d\n", WhatSeed());
+	sprintf(cmd, "wish -f %s.tcl &", oFname?oFname->name:"msc");
+	fprintf(stderr, "%s\n", cmd);
+	(void) unlink("pan.pre");
+	exit (system(cmd));
+}
+
+void
+putprelude(void)
+{	char snap[256]; FILE *fd;
+
+	sprintf(snap, "%s.tcl", oFname?oFname->name:"msc");
+	if (!(pfd = fopen(snap, MFLAGS)))
+	{	fatal("cannot create file '%s'", snap);
+	}
+	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);
+	}
+	TotSteps *= 2;
+	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 *));
+}
+
+void
+putarrow(int from, int to)
+{
+	/* from rv if from == to */
+	/* which means that D[from] == D[to] */
+	/* which means that T[x] == x */
+
+	if (from    < TotSteps
+	&&  to      < TotSteps
+	&&  D[from] < TotSteps)
+	{	T[D[from]] = D[to];
+	}
+}
+
+void
+pstext(int x, char *s)
+{	char *tmp = emalloc((int) strlen(s)+1);
+
+	strcpy(tmp, s);
+	if (depth == 0)
+	{	I[x] = tmp;
+	} else
+	{	if (depth >= TotSteps || ldepth >= TotSteps)
+		{	fprintf(stderr, "spin: error: max nr of %d steps exceeded\n",
+				TotSteps);
+			fatal("use -uN to limit steps", (char *) 0);
+		}
+		putbox(x);
+		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 -r 51b3bf8bc61b sys/src/cmd/spin/pangen1.c
--- a/sys/src/cmd/spin/pangen1.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/pangen1.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,18 +1,22 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include "spin.h"
 #include "y.tab.h"
 #include "pangen1.h"
 #include "pangen3.h"
+#include "pangen6.h"
+#include <assert.h>
+#ifdef SOLARIS
+#include <sys/int_limits.h>
+#else
+#include <stdint.h>
+#endif
 
 extern FILE	*tc, *th, *tt;
 extern Label	*labtab;
@@ -20,9 +24,10 @@
 extern ProcList	*rdy;
 extern Queue	*qtab;
 extern Symbol	*Fname;
-extern int	lineno, verbose, Pid, separate;
+extern int	lineno, verbose, Pid, separate, old_scope_rules, nclaims;
 extern int	nrRdy, nqs, mst, Mpars, claimnr, eventmapnr;
-extern short	has_sorted, has_random, has_provided;
+extern short	has_sorted, has_random, has_provided, has_priority;
+extern Queue	*ltab[];
 
 int	Npars=0, u_sync=0, u_async=0, hastrack = 1;
 short	has_io = 0;
@@ -36,9 +41,10 @@
 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	put_ptype(char *, int, int, int, enum btypes);
 static void	tc_predef_np(void);
 static void	put_pinit(ProcList *);
+static void	multi_init(void);
        void	walk_struct(FILE *, int, char *, Symbol *, char *, char *, char *);
 
 static void
@@ -46,7 +52,22 @@
 {
 	if (!p) return;
 	reverse_names(p->nxt);
-	fprintf(th, "   \"%s\",\n", p->n->name);
+	fprintf(tc, "   \"%s\",\n", p->n->name);
+}
+static void
+reverse_types(ProcList *p)
+{
+	if (!p) return;
+	reverse_types(p->nxt);
+	fprintf(tc, "   %d,	/* %s */\n", p->b, p->n->name);
+}
+
+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;
 }
 
 void
@@ -57,37 +78,129 @@
 	{	putunames(th);
 		goto here;
 	}
-
+	/* 5.2.3: gcc 3 no longer seems to compute sizeof at compile time */
+	fprintf(th, "#define WS		%d /* word size in bytes */\n", (int) sizeof(void *));
 	fprintf(th, "#define SYNC	%d\n", u_sync);
 	fprintf(th, "#define ASYNC	%d\n\n", u_async);
+	fprintf(th, "#ifndef NCORE\n");
+	fprintf(th, "	#ifdef DUAL_CORE\n");
+	fprintf(th, "		#define NCORE	2\n");
+	fprintf(th, "	#elif QUAD_CORE\n");
+	fprintf(th, "		#define NCORE	4\n");
+	fprintf(th, "	#else\n");
+	fprintf(th, "		#define NCORE	1\n");
+	fprintf(th, "	#endif\n");
+	fprintf(th, "#endif\n\n");
 
 	putunames(th);
 
-	fprintf(tc, "short Air[] = { ");
+	fprintf(tc, "\nshort 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_ */
+	if (nclaims > 1)
+	{	fprintf(tc, "\n#ifndef NOCLAIM\n");
+		fprintf(tc, "	, (short) Air%d", i+1);	/* Multi */
+		fprintf(tc, "\n#endif\n\t");
+	}
 	fprintf(tc, " };\n");
 
-	fprintf(th, "char *procname[] = {\n");
+	fprintf(tc, "char *procname[] = {\n");
 		reverse_names(rdy);
-	fprintf(th, "   \":np_:\",\n");
-	fprintf(th, "};\n\n");
+	fprintf(tc, "   \":np_:\",\n");
+	fprintf(tc, "	0\n");
+	fprintf(tc, "};\n\n");
+
+	fprintf(tc, "enum btypes { NONE=%d, N_CLAIM=%d,", NONE, N_CLAIM);
+	fprintf(tc, " I_PROC=%d, A_PROC=%d,", I_PROC, A_PROC);
+	fprintf(tc, " P_PROC=%d, E_TRACE=%d, N_TRACE=%d };\n\n",
+		P_PROC, E_TRACE, N_TRACE);
+
+	fprintf(tc, "int Btypes[] = {\n");
+		reverse_types(rdy);
+	fprintf(tc, "   0	/* :np_: */\n");
+	fprintf(tc, "};\n\n");
 
 here:
 	for (p = rdy; p; p = p->nxt)
-		put_ptype(p->n->name, p->tn, mst, nrRdy+1);
+		put_ptype(p->n->name, p->tn, mst, nrRdy+1, p->b);
 		/* +1 for np_ */
-	put_ptype("np_", nrRdy, mst, nrRdy+1);
+	put_ptype("np_", nrRdy, mst, nrRdy+1, 0);
+
+	if (nclaims > 1)
+	{	/* this is the structure that goes into the state-vector
+		 * instead of the actual never claims
+		 * this assumes that the claims do not have any local variables
+		 * this claim records the types and states of all subclaims in an array
+		 * NB: not sure if we need the first 3 fields in this structure
+		 *     it's here for now to avoid breaking some possible dependence
+		 * in the calculations above, we were already taking into account
+		 * that there is one never-claim, which will now be this one
+		 */
+
+		i = blog(mst);
+		fprintf(th, "\n");
+
+		fprintf(th, "#ifndef NOCLAIM\n");
+		fprintf(th, "	#undef VERI\n");
+		fprintf(th, "	#define VERI	%d\n", nrRdy+1);
+		fprintf(th, "	#define Pclaim	P%d\n\n", nrRdy+1);
+		fprintf(th, "typedef struct P%d {\n", nrRdy+1);
+		fprintf(th, "	unsigned _pid : 8; /* always zero */\n");
+		fprintf(th, "	unsigned _t   : %d; /* active-claim type  */\n",
+			blog(nrRdy+1));
+		fprintf(th, "	unsigned _p   : %d; /* active-claim state */\n",
+			i);
+		fprintf(th, "	unsigned _n   : %d; /* active-claim index */\n",
+			blog(nclaims));
+		if (i <= UINT8_MAX)	/* in stdint.h = UCHAR_MAX from limits.h */
+		{	fprintf(th, "	uchar c_cur[NCLAIMS]; /* claim-states */\n");
+		} else if (i <= UINT16_MAX)	/* really USHRT_MAX from limits.h */
+		{	fprintf(th, "	ushort c_cur[NCLAIMS]; /* claim-states */\n");
+		} else	/* the most unlikely case */
+		{	fprintf(th, "	uint c_cur[NCLAIMS]; /* claim-states */\n");
+		}
+		fprintf(th, "} P%d;\n", nrRdy+1);
+
+		fprintf(tc, "#ifndef NOCLAIM\n");
+		fprintf(tc, "uchar spin_c_typ[NCLAIMS]; /* claim-types */\n");
+		fprintf(tc, "#endif\n");
+
+		fprintf(th, "	#define Air%d	(0)\n\n", nrRdy+1);
+		fprintf(th, "#endif\n");
+		/*
+		 * find special states as:
+		 *	stopstate [ claimnr ][ curstate ] == 1
+		 *	accpstate [ claimnr ][ curstate ]
+		 *	progstate [ claimnr ][ curstate ]
+		 *	reached   [ claimnr ][ curstate ]
+		 *	visstate  [ claimnr ][ curstate ]
+		 *	loopstate [ claimnr ][ curstate ]
+		 *	mapstate  [ claimnr ][ curstate ]
+		 */
+	} else
+	{	fprintf(th, "#define Pclaim	P0\n");
+		fprintf(th, "#ifndef NCLAIMS\n");
+		fprintf(th, "	#define NCLAIMS 1\n");
+		fprintf(th, "#endif\n");
+		fprintf(tc, "uchar spin_c_typ[NCLAIMS]; /* claim-types */\n");
+	}
 
 	ntimes(th, 0, 1, Head0);
 
 	if (separate != 2)
 	{	extern void c_add_stack(FILE *);
+		extern void c_stack_size(FILE *);
 
 		ntimes(th, 0, 1, Header);
+		fprintf(th, "#define StackSize	(");
+			c_stack_size(th);
+		fprintf(th, ")\n");
+
 		c_add_stack(th);
 		ntimes(th, 0, 1, Header0);
+	} else
+	{	fprintf(th, "extern char *emalloc(unsigned long);\n");
 	}
 	ntimes(th, 0, 1, Head1);
 
@@ -96,7 +209,13 @@
 
 	hastrack = c_add_sv(th);
 
+	fprintf(th, "#ifdef TRIX\n");
+	fprintf(th, "	/* room for 512 proc+chan ptrs, + safety margin */\n");
+	fprintf(th, "	char *_ids_[MAXPROC+MAXQ+4];\n");
+	fprintf(th, "#else\n");
 	fprintf(th, "	uchar sv[VECTORSZ];\n");
+	fprintf(th, "#endif\n");
+
 	fprintf(th, "} State");
 #ifdef SOLARIS
 	fprintf(th,"\n#ifdef GCC\n");
@@ -105,8 +224,24 @@
 #endif
 	fprintf(th, ";\n\n");
 
+	fprintf(th, "#ifdef TRIX\n");
+	fprintf(th, "typedef struct TRIX_v6 {\n");
+	fprintf(th, "	uchar *body; /* aligned */\n");
+	fprintf(th, "#ifndef BFS\n");
+	fprintf(th, "	short modified;\n");
+	fprintf(th, "#endif\n");
+	fprintf(th, "	short psize;\n");
+	fprintf(th, "	short parent_pid;\n");
+	fprintf(th, "	struct TRIX_v6 *nxt;\n");
+	fprintf(th, "} TRIX_v6;\n");
+	fprintf(th, "#endif\n\n");
+
 	fprintf(th, "#define HAS_TRACK	%d\n", hastrack);
-
+	if (0 && hastrack)	/* not really a problem */
+	{	fprintf(th, "#ifdef BFS_PAR\n");
+		fprintf(th, "	#error cannot use BFS_PAR on models with c_track stmnts\n");
+		fprintf(th, "#endif\n");
+	}
 	if (separate != 2)
 		dohidden();
 }
@@ -116,14 +251,36 @@
 {	ProcList *p;
 	int i = 0;
 
-	if (separate ==2) goto shortcut;
+	if (separate == 2) goto shortcut;
 
-	fprintf(tc, "int\naddproc(int n");
-	for (i = 0; i < Npars; i++)
+	ntimes(tc, nrRdy+1, nrRdy+2, R2); /* +1 for np_ -- was th */
+
+	fprintf(tc, "#ifdef TRIX\n");
+	fprintf(tc, "int what_p_size(int);\n");
+	fprintf(tc, "int what_q_size(int);\n\n");
+
+	/* the number of processes just changed by 1 (up or down) */
+	/* this means that the channel indices move up or down by one slot */
+	/* not all new channels may have a valid index yet, but we move */
+	/* all of them anyway, as if they existed */
+	ntimes(tc, 0, 1, R7a);
+	fprintf(tc, "#endif\n\n");
+
+	ntimes(tc, 0, 1, R7b);
+
+	fprintf(tc, "int\naddproc(int calling_pid, int priority, 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_ */
+
+	if (nclaims > 1)
+	{	fprintf(tc, "#ifndef NOCLAIM\n");
+		ntimes(tc, nrRdy+1, nrRdy+2, R5);
+		fprintf(tc, "#endif\n");
+	}
+
 	ntimes(tc, 0, 1, Addp1);
 
 	if (has_provided)
@@ -132,6 +289,9 @@
 		fprintf(tt, "{\n\tswitch(ot) {\n");
 	}
 shortcut:
+	if (nclaims > 1)
+	{	multi_init();
+	}
 	tc_predef_np();
 	for (p = rdy; p; p = p->nxt)
 	{	Pid = p->tn;
@@ -157,8 +317,17 @@
 do_locinits(FILE *fd)
 {	ProcList *p;
 
+	/* the locinit functions may refer to pptr or qptr */
+	fprintf(fd, "#if VECTORSZ>32000\n");
+	fprintf(fd, "	extern int \n");
+	fprintf(fd, "#else\n");
+	fprintf(fd, "	extern short \n");
+	fprintf(fd, "#endif\n");
+	fprintf(fd, "	*proc_offset, *q_offset;\n");
+
 	for (p = rdy; p; p = p->nxt)
-		c_add_locinit(fd, p->tn, p->n->name);
+	{	c_add_locinit(fd, p->tn, p->n->name);
+	}
 }
 
 void
@@ -167,63 +336,89 @@
 
 	switch (separate) {
 	case 2:
-		if (claimnr >= 0)
-		ntimes(tc, claimnr, claimnr+1, R0); /* claim only */
+		if (nclaims > 0)
+		{	for (p = rdy; p; p = p->nxt)
+			{	if (p->b == N_CLAIM)
+				{	ntimes(tc, p->tn, p->tn+1, R0); /* claims only */
+					fprintf(tc, "#ifdef HAS_CODE\n");
+					ntimes(tc, p->tn, p->tn+1, R00);
+					fprintf(tc, "#endif\n");
+		}	}	}
 		break;
 	case 1:
 		ntimes(tc,     0,    1, Code0);
-		ntimes(tc, 0, claimnr, R0);	/* all except claim */
-		ntimes(tc, claimnr+1, nrRdy, R0);
+		for (p = rdy; p; p = p->nxt)
+		{	if (p->b != N_CLAIM)
+			{	ntimes(tc, p->tn, p->tn+1, R0); /* all except claims */
+				fprintf(tc, "#ifdef HAS_CODE\n");
+				ntimes(tc, p->tn, p->tn+1, R00);
+				fprintf(tc, "#endif\n");
+		}	}
 		break;
 	case 0:
 		ntimes(tc,     0,    1, Code0);
 		ntimes(tc,     0, nrRdy+1, R0); /* +1 for np_ */
+		fprintf(tc, "#ifdef HAS_CODE\n");
+		ntimes(tc,     0, nrRdy+1, R00); /* +1 for np_ */
+		fprintf(tc, "#endif\n");
 		break;
 	}
+	/* new place, make sure Maxbody is set to its final value here */
+	fprintf(tc, "\n");
+
+	if (separate != 2)
+	{	ntimes(tc, 1, u_sync+u_async+1, R3); /* nqs is still 0 */
+		fprintf(tc, "\tMaxbody = max(Maxbody, sizeof(State)-VECTORSZ);\n");
+		fprintf(tc, "\tif ((Maxbody %% WS) != 0)\n");
+		fprintf(tc, "\t	Maxbody += WS - (Maxbody %% WS);\n\n");
+	}
 
 	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 */
+		if (nclaims > 0)
+		{	for (p = rdy; p; p = p->nxt)
+			{	if (p->b == N_CLAIM)
+				{	ntimes(tc, p->tn, p->tn+1, R0a); /* claims only */
+		}	}	}
 		return;
 	case 1:
-		ntimes(tc, 0, claimnr, R0a);	/* all except claim */
-		ntimes(tc, claimnr+1, nrRdy, R0a);
+		for (p = rdy; p; p = p->nxt)
+		{	if (p->b != N_CLAIM)
+			{	ntimes(tc, p->tn, p->tn+1, R0a); /* all except claims */
+		}	}
 		fprintf(tc, "	if (state_tables)\n");
-		fprintf(tc, "		ini_claim(%d, 0);\n", claimnr);
+		fprintf(tc, "		ini_claim(%d, 0);\n", claimnr);	/* the default claim */
+		if (acceptors == 0)
+		{	acceptors = 1;	/* assume at least 1 acceptstate */
+		}
 		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,     1, Code2a);	/* dfs, bfs */
+	ntimes(tc, 0,     1, Code2e);	/* multicore */
+	ntimes(tc, 0,     1, Code2c);	/* multicore */
+	ntimes(tc, 0,     1, Code2d);
+
+	fprintf(tc, "void\ndo_reach(void)\n{\n");
 	ntimes(tc, 0,     nrRdy, R4);
 	fprintf(tc, "}\n\n");
 
-	fprintf(tc, "void\n");
-	fprintf(tc, "iniglobals(void)\n{\n");
+	fprintf(tc, "void\niniglobals(int calling_pid)\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");
+	fprintf(tc, "}\n\n");
 }
 
 void
@@ -248,17 +443,17 @@
 	Label *l;
 	int j; char foo[128];
 
-	if ((i == claimnr && separate == 1)
-	||  (i != claimnr && separate == 2))
+	if ((pid_is_claim(i) && separate == 1)
+	|| (!pid_is_claim(i) && 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
+	{	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;
+			acceptors   += ln[j].m;
 			progressors += ln[j].p;
 			if (l->e->status & D_ATOM)
 			{	sprintf(foo, "%s label inside d_step",
@@ -272,8 +467,7 @@
 				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
@@ -286,7 +480,7 @@
 }
 
 void
-ntimes(FILE *fd, int n, int m, char *c[])
+ntimes(FILE *fd, int n, int m, const char *c[])
 {
 	int i, j;
 	for (j = 0; c[j]; j++)
@@ -305,7 +499,7 @@
 
 	n = (s->context != ZS)?s->context->ini:s->ini;
 	if (n)
-	printf("line %3d %s, ", n->ln, n->fn->name);
+	printf("line %s:%d, ", n->fn->name, n->ln);
 }
 
 void
@@ -338,7 +532,7 @@
 	{	if (!(verbose&32)) return;
 		sputtype(buf, sp->type);
 		i = (int) strlen(buf);
-		while (buf[--i] == ' ') buf[i] = '\0';
+		while (i > 0 && buf[--i] == ' ') buf[i] = '\0';
 		prehint(sp);
 		if (sp->context)
 			printf("proctype %s:", s);
@@ -361,12 +555,12 @@
 	}
 }
 
-int
-dolocal(FILE *ofd, char *pre, int dowhat, int p, char *s)
+static int
+dolocal(FILE *ofd, char *pre, int dowhat, int p, char *s, enum btypes b)
 {	int h, j, k=0; extern int nr_errs;
 	Ordered *walk;
 	Symbol *sp;
-	char buf[64], buf2[128], buf3[128];
+	char buf[128], buf2[128], buf3[128];
 
 	if (dowhat == INIV)
 	{	/* initialize in order of declaration */
@@ -390,7 +584,8 @@
 			if (sp->context
 			&& !sp->owner
 			&&  sp->type == Types[j]
-			&&  ((h == 0 && sp->nel == 1) || (h == 1 && sp->nel > 1))
+			&&  ((h == 0 && (sp->nel == 1 && sp->isarray == 0))
+			||   (h == 1 && (sp->nel  > 1 || sp->isarray == 1)))
 			&&  strcmp(s, sp->context->name) == 0)
 			{	switch (dowhat) {
 				case LOGV:
@@ -409,7 +604,7 @@
 					k++;
 					break;
 				}
-				if (strcmp(s, ":never:") == 0)
+				if (b == N_CLAIM)
 				{	printf("error: %s defines local %s\n",
 						s, sp->name);
 					nr_errs++;
@@ -425,8 +620,8 @@
 	int i;
 
 	if (!qtab)
-	{	fprintf(fd, "void\nc_chandump(int unused) ");
-		fprintf(fd, "{ unused = unused++; /* avoid complaints */ }\n");
+	{	fprintf(fd, "void\nc_chandump(int unused)\n");
+		fprintf(fd, "{\tunused++; /* avoid complaints */\n}\n");
 		return;
 	}
 
@@ -465,9 +660,19 @@
 
 void
 c_var(FILE *fd, char *pref, Symbol *sp)
-{	char buf[256];
+{	char *ptr, buf[256];
 	int i;
 
+	if (!sp)
+	{	fatal("cannot happen - c_var", 0);
+	}
+
+	ptr = sp->name;
+	if (!old_scope_rules)
+	{	while (*ptr == '_' || isdigit((int)*ptr))
+		{	ptr++;
+	}	}
+
 	switch (sp->type) {
 	case STRUCT:
 		/* c_struct(fd, pref, sp); */
@@ -476,34 +681,40 @@
 		sprintf(buf, "%s%s.", pref, sp->name);
 		c_struct(fd, buf, sp);
 		break;
+	case MTYPE:
 	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);
+		if (sp->nel == 1 && sp->isarray == 0)
+		{
+			if (sp->type == MTYPE && ismtype(sp->name))
+			{	fprintf(fd, "\tprintf(\"\t%s %s:\t%d\\n\");\n",
+					buf, ptr, ismtype(sp->name));
+			} else
+			{	fprintf(fd, "\tprintf(\"\t%s %s:\t%%d\\n\", %s%s);\n",
+					buf, ptr, 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);
+						buf, ptr, 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);
+		if (sp->nel == 1 && sp->isarray == 0)
+		{  fprintf(fd, "\tprintf(\"\tchan %s (=%%d):\tlen %%d:\\t\", ", ptr);
 		   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);
+			ptr, 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",
@@ -518,9 +729,7 @@
 {	Ordered *walk;
 	Symbol *sp;
 
-	if (strcmp(p->n->name, ":never:") != 0
-	&&  strcmp(p->n->name, ":trace:") != 0
-	&&  strcmp(p->n->name, ":notrace:") != 0)
+	if (p->b != N_CLAIM && p->b != E_TRACE && p->b != N_TRACE)
 	for (walk = all_names; walk; walk = walk->next)
 	{	sp = walk->entry;
 		if (!sp->context
@@ -541,9 +750,7 @@
 	Symbol *sp;
 	char pref[64];
 
-	if (strcmp(p->n->name, ":never:") != 0
-	&&  strcmp(p->n->name, ":trace:") != 0
-	&&  strcmp(p->n->name, ":notrace:") != 0)
+	if (p->b != N_CLAIM && p->b != E_TRACE && p->b != N_TRACE)
 	for (walk = all_names; walk; walk = walk->next)
 	{	sp = walk->entry;
 		if (!sp->context
@@ -571,10 +778,8 @@
 	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)))
+		if (sp->context || sp->owner || (sp->hidden&1))
 			continue;
-
 		c_var(fd, "now.", sp);
 	}
 	fprintf(fd, "}\n");
@@ -583,8 +788,6 @@
 	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);
@@ -633,8 +836,9 @@
 				checktype(sp, (char *) 0);
 				cnt++; /* fall through */
 			case PUTV:
-				do_var(tc, dowhat, (sp->hidden&1)?"":"now.", sp,
-				"", " = ", ";\n");
+				do_var(tc, dowhat,
+					(sp->hidden&1)?"":"now.", sp,
+					"", " = ", ";\n");
 				break;
 	}	}	}
 	return cnt;
@@ -652,28 +856,37 @@
 		if ((sp->hidden&1)
 		&&  sp->type == Types[j])
 		{	if (sp->context || sp->owner)
-			fatal("cannot hide non-globals (%s)", sp->name);
+			  fatal("cannot hide non-globals (%s)", sp->name);
 			if (sp->type == CHAN)
-			fatal("cannot hide channels (%s)", sp->name);
+			  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;
+	char *ptr = sp?sp->name:"";
+
+	if (!sp)
+	{	fatal("cannot happen - do_var", 0);
+	}
 
 	switch(dowhat) {
 	case PUTV:
-
 		if (sp->hidden&1) break;
 
 		typ2c(sp);
 		break;
+
 	case LOGV:
+		if (!old_scope_rules)
+		{	while (*ptr == '_' || isdigit((int)*ptr))
+			{	ptr++;
+		}	}
+		/* fall thru */
 	case INIV:
 		if (sp->type == STRUCT)
 		{	/* struct may contain a chan */
@@ -682,13 +895,16 @@
 		}
 		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)
+		if (sp->nel == 1 && sp->isarray == 0)
+		{	if (dowhat == LOGV)
+			{	fprintf(ofd, "\t\t%s%s%s%s",
+					pre, s, ptr, sep);
 				fprintf(ofd, "%s%s", s, sp->name);
-			else
+			} else
+			{	fprintf(ofd, "\t\t%s%s%s%s",
+					pre, s, sp->name, sep);
 				do_init(ofd, sp);
+			}
 			fprintf(ofd, "%s", ter);
 		} else
 		{	if (sp->ini && sp->ini->ntyp == CHAN)
@@ -702,77 +918,86 @@
 						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",
+			} else if (sp->ini)
+			{	if (dowhat != LOGV && sp->isarray && sp->ini->ntyp == ',')
+				{	Lextok *z, *y;
+					z = sp->ini;
+					for (i = 0; i < sp->nel; i++)
+					{	if (z && z->ntyp == ',')
+						{	y = z->lft;
+							z = z->rgt;
+						} else
+						{	y = z;
+						}
+						fprintf(ofd, "\t\t%s%s%s[%d]%s",
+							pre, s, sp->name, i, sep);
+						putstmnt(ofd, y, 0);
+						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");
-		}	}
+					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[];
+{	int i; 
 
 	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);
+		{	fprintf(ofd, "addqueue(calling_pid, %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;
+	{	putstmnt(ofd, sp->ini, 0);
+	}
 }
 
 static void
-put_ptype(char *s, int i, int m0, int m1)
+put_ptype(char *s, int i, int m0, int m1, enum btypes b)
 {	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);
+	if (b == I_PROC)
+	{	fprintf(th, "#define Pinit	((P%d *)this)\n", i);
+	} else if (b == P_PROC || b == A_PROC)
+	{	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));
+	fprintf(th, "#ifdef HAS_PRIORITY\n");
+	fprintf(th, "	unsigned _priority : 8; /* 0..255 */\n");
+	fprintf(th, "#endif\n");
 	LstSet = ZS;
 	nBits = 8 + blog(m1) + blog(m0);
-	k = dolocal(tc, "", PUTV, i, s);	/* includes pars */
-
+	k = dolocal(tc, "", PUTV, i, s, b);	/* 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	0\n\n", i);
+	else if (LstSet || k == 0)			/* 5.0, added condition */
 	{	fprintf(th, "#define Air%d	(sizeof(P%d) - ", i, i);
 		if (k == 0)
 		{	fprintf(th, "%d", (nBits+7)/8);
@@ -802,35 +1027,79 @@
 			fatal("cannot happen Air %s",
 				LstSet->name);
 		}
-done:		fprintf(th, ")\n");
+done:		fprintf(th, ")\n\n");
 	}
 }
 
 static void
 tc_predef_np(void)
-{	int i = nrRdy;	/* 1+ highest proctype nr */
+{
+	fprintf(th, "#define _NP_	%d\n", 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", nrRdy);
+	fprintf(th, "#define _endstate%d	2 /* np_ */\n\n", nrRdy);
+	fprintf(th, "#define _start%d	0 /* np_ */\n", nrRdy);
 
-	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", nrRdy);
+	if (separate == 1)
+	{	fprintf(tc, "\t\tini_claim(%d, h);\n", nrRdy);
+	} else
+	{	fprintf(tc, "\t\t((P%d *)pptr(h))->_t = %d;\n", nrRdy, nrRdy);
+		fprintf(tc, "\t\t((P%d *)pptr(h))->_p = 0;\n", nrRdy);
 
-	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, "#ifdef HAS_PRIORITY\n");
+		fprintf(tc, "\t\t((P%d *)pptr(h))->_priority = priority;\n", nrRdy);
+		fprintf(tc, "#endif\n");
+
+		fprintf(tc, "\t\treached%d[0] = 1;\n", nrRdy);
+		fprintf(tc, "\t\taccpstate[%d][1] = 1;\n", nrRdy);
 	}
 	fprintf(tc, "\t\tbreak;\n");
 }
 
 static void
+multi_init(void)
+{	ProcList *p;
+	Element	*e;
+	int i = nrRdy+1;
+	int ini, j;
+	int nrc = nclaims;
+
+	fprintf(tc, "#ifndef NOCLAIM\n");
+	fprintf(tc, "\tcase %d:	/* claim select */\n", i);
+	for (p = rdy, j = 0; p; p = p->nxt, j++)
+	{	if (p->b == N_CLAIM)
+		{	e = p->s->frst;
+			ini = huntele(e, e->status, -1)->seqno;
+
+			fprintf(tc, "\t\tspin_c_typ[%d] = %d; /* %s */\n",
+				j, p->tn, p->n->name);
+			fprintf(tc, "\t\t((P%d *)pptr(h))->c_cur[%d] = %d;\n",
+				i, j, ini);
+			fprintf(tc, "\t\treached%d[%d]=1;\n", p->tn, ini);
+
+			/* the default initial claim is first one in model */
+			if (--nrc == 0)	
+			{ fprintf(tc, "\t\t((P%d *)pptr(h))->_t = %d;\n", i, p->tn);
+			  fprintf(tc, "\t\t((P%d *)pptr(h))->_p = %d;\n", i, ini);
+			  fprintf(tc, "\t\t((P%d *)pptr(h))->_n = %d; /* %s */\n",
+				i, j, p->n->name);
+			  fprintf(tc, "\t\tsrc_claim = src_ln%d;\n", p->tn);
+			  fprintf(tc, "#ifndef BFS\n");
+			  fprintf(tc, "\t\tif (whichclaim == -1 && claimname == NULL)\n");
+			  fprintf(tc, "\t\t\tprintf(\"0: Claim %s (%d), from state %d\\n\");\n",
+				p->n->name, p->tn, ini);
+			  fprintf(tc, "#endif\n");
+			}
+	}	}
+	fprintf(tc, "\t\tif (whichclaim != -1)\n");
+	fprintf(tc, "\t\t{	select_claim(whichclaim);\n");
+	fprintf(tc, "\t\t}\n");
+	fprintf(tc, "\t\tbreak;\n\n");
+	fprintf(tc, "#endif\n");
+}
+
+static void
 put_pinit(ProcList *P)
 {	Lextok	*fp, *fpt, *t;
 	Element	*e = P->s->frst;
@@ -839,29 +1108,36 @@
 	int	 i = P->tn;
 	int	ini, j, k;
 
-	if (i == claimnr
+	if (pid_is_claim(i)
 	&&  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
+	if (!pid_is_claim(i)
 	&&  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);
+	fprintf(th, "#define _start%d	%d\n", i, 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);
+	fprintf(tc, "\t\t((P%d *)pptr(h))->_p = %d;\n", i, ini);
+	fprintf(tc, "#ifdef HAS_PRIORITY\n");
+
+	fprintf(tc, "\t\t((P%d *)pptr(h))->_priority = priority; /* was: %d */\n",
+		i, (P->priority<1)? 1 : P->priority);
+
+	fprintf(tc, "#endif\n");
+	fprintf(tc, "\t\treached%d[%d]=1;\n", i, ini);
+	if (P->b == N_CLAIM)
+	{	fprintf(tc, "\t\tsrc_claim = src_ln%d;\n", i);
+	}
 
 	if (has_provided)
 	{	fprintf(tt, "\tcase %d: /* %s */\n\t\t", i, s->name);
@@ -879,7 +1155,7 @@
 	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)
+		if (t->sym->nel > 1 || t->sym->isarray)
 		{	lineno = t->ln;
 			Fname  = t->fn;
 			fatal("array in parameter list, %s",
@@ -898,10 +1174,10 @@
 		fprintf(tc, " = par%d;\n", j);
 	}
 	fprintf(tc, "\t\t/* locals: */\n");
-	k = dolocal(tc, "", INIV, i, s->name);
+	k = dolocal(tc, "", INIV, i, s->name, P->b);
 	if (k > 0)
 	{	fprintf(tc, "#ifdef VAR_RANGES\n");
-		(void) dolocal(tc, "logval(\"", LOGV, i, s->name);
+		(void) dolocal(tc, "logval(\"", LOGV, i, s->name, P->b);
 		fprintf(tc, "#endif\n");
 	}
 
@@ -929,17 +1205,19 @@
 	}	}
 
 	if (cnt >= 200 || !e)
-		fatal("confusing control structure", (char *) 0);
+	{	lineno = (f && f->n)?f->n->ln:lineno;
+		fatal("confusing control. structure", (char *) 0);
+	}
 	return e;
 }
 
 Element *
-huntele(Element *f, int o, int stopat)
+huntele(Element *f, unsigned 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++)
+	for ( ; cnt < 500 && e->n; cnt++)
 	{
 		if (e->seqno == stopat)
 			break;
@@ -947,6 +1225,10 @@
 		switch (e->n->ntyp) {
 		case GOTO:
 			g = get_lab(e->n,1);
+			if (e == g)
+			{	lineno = (f && f->n)?f->n->ln:lineno;
+				fatal("infinite goto loop", (char *) 0);
+			}
 			cross_dsteps(e->n, g->n);
 			break;
 		case '.':
@@ -957,6 +1239,9 @@
 			break;
 		case UNLESS:
 			g = huntele(e->sub->this->frst, o, stopat);
+			if (!g)
+			{	fatal("unexpected error 1", (char *) 0);
+			}
 			break;
 		case D_STEP:
 		case ATOMIC:
@@ -968,8 +1253,10 @@
 			return e;
 		e = g;
 	}
-	if (cnt >= 200 || !e)
+	if (cnt >= 500 || !e)
+	{	lineno = (f && f->n)?f->n->ln:lineno;
 		fatal("confusing control structure", (char *) 0);
+	}
 	return e;
 }
 
@@ -992,7 +1279,7 @@
 		nBits += sp->nbits;
 		break;
 	case BIT:
-		if (sp->nel == 1 && !(sp->hidden&1))
+		if (sp->nel == 1 && sp->isarray == 0 && !(sp->hidden&1))
 		{	fprintf(th, "\tunsigned %s : 1", sp->name);
 			LstSet = sp; 
 			nBits++;
@@ -1031,13 +1318,13 @@
 		fatal("variable %s undeclared", sp->name);
 	}
 
-	if (sp->nel != 1)
+	if (sp->nel > 1 || sp->isarray)
 		fprintf(th, "[%d]", sp->nel);
 	fprintf(th, ";\n");
 }
 
 static void
-ncases(FILE *fd, int p, int n, int m, char *c[])
+ncases(FILE *fd, int p, int n, int m, const char *c[])
 {	int i, j;
 
 	for (j = 0; c[j]; j++)
@@ -1067,12 +1354,11 @@
 	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)
@@ -1124,6 +1410,22 @@
 
 	ntimes(tc, 0, 1, Addq1);
 
+	fprintf(tc, "#ifdef TRIX\n");
+	fprintf(tc, "int\nwhat_p_size(int t)\n{\tint j;\n");
+	fprintf(tc, "	switch (t) {\n");
+	ntimes(tc, 0, nrRdy+1, R5); /* +1 for np_ */
+	fprintf(tc, "	default: Uerror(\"bad proctype\");\n");
+	fprintf(tc, "	}\n	return j;\n}\n\n");
+
+	fprintf(tc, "int\nwhat_q_size(int t)\n{\tint j;\n");
+	fprintf(tc, "	switch (t) {\n");
+	for (j = 0; j < nqs+1; j++)
+	{	fprintf(tc, "	case %d: j = sizeof(Q%d); break;\n", j, j);
+	}
+	fprintf(tc, "	default: Uerror(\"bad qtype\");\n");
+	fprintf(tc, "	}\n	return j;\n}\n");
+	fprintf(tc, "#endif\n\n");
+
 	if (has_random)
 	{	fprintf(th, "int Q_has(int");
 		for (j = 0; j < Mpars; j++)
@@ -1159,7 +1461,7 @@
 	fprintf(tc, "void\nqsend(int into, int sorted");
 	for (j = 0; j < Mpars; j++)
 		fprintf(tc, ", int fld%d", j);
-	fprintf(tc, ")\n");
+	fprintf(tc, ", int args_given)\n");
 	ntimes(tc, 0, 1, Addq11);
 
 	for (q = qtab; q; q = q->nxt)
@@ -1202,6 +1504,12 @@
 		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\tif (args_given != %d)\n", q->nflds);
+		fprintf(tc, "\t\t{	if (args_given > %d)\n", q->nflds);
+		fprintf(tc, "\t\t		uerror(\"too many parameters in send stmnt\");\n");
+		fprintf(tc, "\t\t	else\n");
+		fprintf(tc, "\t\t		uerror(\"too few parameters in send stmnt\");\n");
+		fprintf(tc, "\t\t}\n");
 		fprintf(tc, "\t\tbreak;\n");
 	}
 	ntimes(tc, 0, 1, Addq2);
@@ -1261,14 +1569,15 @@
 	fprintf(tc, "	case %d: j = sizeof(Q%d); break;\n",
 		q->qid, q->qid);
 	ntimes(tc, 0, 1, R8b);
+	ntimes(th, 0, 1, Proto);	/* function prototypes */
 
-	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, ", int);\n\n");
 
-	fprintf(th, "#define Addproc(x)	addproc(x");
+	fprintf(th, "#define Addproc(x,y)	addproc(256, y, x");
+	/* 256 is param outside the range of valid pids */
 	for (j = 0; j < Npars; j++)
 		fprintf(th, ", 0");
 	fprintf(th, ")\n");
diff -r 51b3bf8bc61b sys/src/cmd/spin/pangen1.h
--- a/sys/src/cmd/spin/pangen1.h	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/pangen1.h	Wed Nov 22 00:21:47 2017 -0800
@@ -1,20 +1,56 @@
 /***** 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)",
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
+
+static const char *Code2a[] = { /* the tail of procedure run() */
+	"	if (state_tables)",
+	"	{ if (dodot) exit(0);",
+	"	  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);",
+	"	}",
+	"#if defined(BFS) && defined(TRIX)", /* before iniglobals */
+	"	{ int i;",
+	"	  for (i = 0; i < MAXPROC+1; i++)",
+	"	  {	processes[i] = (TRIX_v6 *) emalloc(sizeof(TRIX_v6));",
+	"		processes[i]->body = (uchar *) emalloc(Maxbody * sizeof(char));",
+	"	  }",
+	"	  for (i = 0; i < MAXQ+1; i++)",
+	"	  {	channels[i] = (TRIX_v6 *) emalloc(sizeof(TRIX_v6));",
+	"		channels[i]->body = (uchar *) emalloc(Maxbody * sizeof(char));",
+	"	} }",
+	"#endif",
+	"#ifdef BFS_PAR",
+	"	bfs_setup_mem();",
+	"	#ifdef COLLAPSE",
+	"	/* this must be the very first allocation from the shared heap */",
+	"		#ifdef BFS_SEP_HASH",
+	"		ncomps = (ulong *) emalloc((ulong)((256+2) * sizeof(ulong)));",
+	"		#else",
+	"		ncomps = (ulong *) sh_pre_malloc((ulong)((256+2) * sizeof(ulong)));",
+	"		#endif",
+	"	#endif",
+	"#endif",
+	"	iniglobals(258); /* arg outside range of pids */",
+	"#if defined(VERI) && !defined(NOREDUCE) && !defined(NP) && !defined(BFS) && !defined(HAS_LTL)",
 	"	if (!state_tables",
-	"#ifdef HAS_CODE",
+	"	#ifdef HAS_CODE",
 	"	&& !readtrail",
-	"#endif",
+	"	#endif",
+	"	#if NCORE>1",
+	"	&& core_id == 0",
+	"	#endif",
 	"	)",
 	"	{ printf(\"warning: for p.o. reduction to be valid \");",
 	"	  printf(\"the never claim must be stutter-invariant\\n\");",
@@ -24,14 +60,7 @@
 	"#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));",
+	"	sinit();",
 	"#else",
 	"	hinit();",
 	"#endif",
@@ -39,18 +68,24 @@
 	"	onstack_init();",
 	"#endif",
 	"#if defined(CNTRSTACK) && !defined(BFS)",
-	"	LL = (uchar *) emalloc(1L<<(ssize-3));",
-	"#endif",
-	"	stack	= ( Stack *) emalloc(sizeof(Stack));",
+	"	LL = (uchar *) emalloc(ONE_L<<(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",
+	"	noqptr = noptr	= (uchar *) emalloc(Maxbody * sizeof(char));",
+	"#if defined(SVDUMP) && defined(VERBOSE)",
 	"	if (vprefix > 0)",
-	"		write(svfd, (uchar *) &vprefix, sizeof(int));",
-	"#endif",
-	"#ifdef VERI",
-	"	Addproc(VERI);	/* never - pid = 0 */",
+	"		(void) write(svfd, (uchar *) &vprefix, sizeof(int));",
+	"#endif",
+	"#ifdef VERI",
+	"	Addproc(VERI,1);	/* pid = 0, priority 1 */",
+	"	#if NCLAIMS>1",
+	"	if (claimname != NULL)",
+	"	{	whichclaim = find_claim(claimname);",
+	"		select_claim(whichclaim);",
+	"	}",
+	"	#endif",
 	"#endif",
 	"	active_procs();	/* started after never */",
 	"#ifdef EVENT_TRACE",
@@ -66,17 +101,21 @@
 	"#endif",
 	"	do_the_search();",
 	"#ifdef BITSTATE",
-	"	if (--Nrun > 0 && HASH_CONST[++HASH_NR])",
+	"	if (--Nrun > 0 && HASH_CONST[++HASH_NR])", /* last entry is 0 */
 	"	{	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)",
+	"		if (udmem)	/* Dillinger 3/2/09 */",
+	"		{	memset(SS, 0, udmem);",
+	"		} else",
+	"		{	memset(SS, 0, ONE_L<<(ssize-3));",
+	"		}",
+		"#ifdef CNTRSTACK",
+	"		memset(LL, 0, ONE_L<<(ssize-3));",
+		"#endif",
+		"#ifdef FULLSTACK",
 	"		memset((uchar *) S_Tab, 0, ",
-	"		maxdepth*sizeof(struct H_el *));",
+	"		maxdepth*sizeof(H_el *));",
 		"#endif",
 	"		nstates=nlinks=truncs=truncs2=ngrabs = 0;",
 	"		nlost=nShadow=hcmp = 0;",
@@ -86,8 +125,157 @@
 	"	}",
 	"#endif",
 	"}",
+	"#ifdef HAS_PRIORITY",
+	"extern int highest_priority(int, short, Trans *);",
+	"extern int get_priority(int);",
+	"extern int set_priority(int, int);",
+	"#endif",
+	"#ifdef SPIN_HEAP",
+	"void *",
+	"spin_malloc(int n)	/* reserved for use by Modex generated models */",
+	"{	char *spin_heap_ptr = &(now.spin_heap[now.spin_heap_n]);",
+	"	if (now.spin_heap_n + n >= sizeof(now.spin_heap))",
+	"	{	Uerror(\"spin_heap limit reached\");",
+	"	}",
+	"	now.spin_heap_n += n;",
+	"	return spin_heap_ptr;",
+	"}",
+	"void",
+	"spin_free(void *unused)",
+	"{	unused; /* ignore */",
+	"}",
+	"#endif",
+	"int",
+	"spin_join(int p, void **unused)",
+	"{	/* fprintf(stderr, \"join %%d when %%d\\n \", p, now._nr_pr); */",
+	"	return (now._nr_pr <= p);	/* process *p has stopped */",
+	"}",
+	"",
+	"int",
+	"spin_mutex_free(int *m)",
+	"{	return (*m == 0);",
+	"}",
+	"",
+	"int",
+	"spin_mutex_lock(int *m)",
+	"{	*m = 1;",
+	"	return 1;",
+	"}",
+	"void",
+	"spin_mutex_destroy(int *m)",
+	"{	*m = 0;",
+	"}",
+	"void",
+	"spin_mutex_unlock(int *m)",
+	"{	*m = 0;",
+	"}",
+	"void",
+	"spin_mutex_init(int *m, void *val)",
+	"{",
+	"	if (!val)", /* the 2nd arg must be NULL, for now */
+	"	{	*m = 0;",
+	"	} else",
+	"	{	Uerror(\"pthread_mutex_init: unsupported non-default init\");",
+	"	}",
+	"}",
+	"",
+	"int",
+	"spin_cond_wait(int *cond, int *lck)",	/*release and re-acquire lock *lck */
+	"{	/* this version does not scale very far alas */",
+	"	if (((P0 *)this)->_pid + 1 >= WS*8)", /* 32 or 64 */
+	"	{	Uerror(\"pid exceeds range supported by pthread_cond_wait\");",
+	"	}",
+	"	if (((*cond)&1) == 0)",		/* repeatedly tested, so: */
+	"	{	spin_mutex_unlock(lck);", /* avoid double counting */
+	"		*cond |= (1<<(((P0 *)this)->_pid + 1));",
+	"		return 0;",	/* blocked, must test again */
+	"	} else",
+	"	{	/* if other processes are already waiting */",
+	"		/* while our wait flag is 0, then they should go first */",
+	"		if (((*cond)&(~(1 | (1<<(((P0 *)this)->_pid + 1))))) != 0)",
+	"		{	spin_mutex_unlock(lck);",
+	"			return 0;", /* wait for the others to go first */
+	"		}",
+	"		*cond &= ~1;",	/* clear the 'go' bit andy wait flag */
+	"		*cond &= ~(1<<(((P0 *)this)->_pid + 1));",
+	"		return 1;",	/* okay to proceed */
+	"	}",
+	"}",
+	"void",
+	"spin_cond_signal(int *cond)",
+	"{",
+	"	if ( ((*cond)&(~1)) != 0 )", /* procs are waiting */
+	"	{	*cond |= 1;",	/* set the 'go' bit */
+	"	}",
+	"}",
+	"",
 	"#ifdef HAS_PROVIDED",
-	"int provided(int, uchar, int, Trans *);",
+	"	int provided(int, uchar, int, Trans *);",
+	"#endif",
+	"#ifdef BFS_PAR",
+	"	extern void bfs_shutdown(const char *);",
+	"#endif",
+	"",
+	"#if NCORE>1",
+	"	#define GLOBAL_LOCK	(0)",
+	"	#ifndef CS_N",
+	"		#define CS_N		(256*NCORE)", /* must be a power of 2 */
+	"	#endif",
+
+	"	#ifdef NGQ",	/* no global queue */
+	"		#define NR_QS		(NCORE)",
+	"		#define CS_NR		(CS_N+1)	/* 2^N + 1, nr critical sections */",
+	"		#define GQ_RD		GLOBAL_LOCK",	/* not really used in this mode */
+	"		#define GQ_WR		GLOBAL_LOCK",	/* but just in case... */
+	"		#define CS_ID		(1 + (int) (j1_spin & (CS_N-1))) /* mask: 2^N - 1, zero reserved */",
+	"		#define QLOCK(n)	(1+n)", /* overlaps first n zones of hashtable */
+	"	#else",
+	"		#define NR_QS		(NCORE+1)",	/* add a global queue */
+	"		#define CS_NR		(CS_N+3)",	/* 2 extra locks for global q */
+	"		#define GQ_RD		(1)",		/* read access to global q */
+	"		#define GQ_WR		(2)",		/* write access to global q */
+	"		#define CS_ID		(3 + (int) (j1_spin & (CS_N-1)))",
+	"		#define QLOCK(n)	(3+n)",/* overlaps first n zones of hashtable */
+	"	#endif",
+	"",
+	"	#ifndef SEP_STATE",
+	"		#define enter_critical(w)	e_critical(w)",
+	"		#define leave_critical(w)	x_critical(w)",
+	"	#else",
+	"		#ifdef NGQ",
+	"			#define enter_critical(w)	{ if (w < 1+NCORE) e_critical(w); }",
+	"			#define leave_critical(w)	{ if (w < 1+NCORE) x_critical(w); }",
+	"		#else",
+	"			#define enter_critical(w)	{ if (w < 3+NCORE) e_critical(w); }",
+	"			#define leave_critical(w)	{ if (w < 3+NCORE) x_critical(w); }",
+	"		#endif",
+	"	#endif",
+	"",
+	"	int",
+	"	cpu_printf(const char *fmt, ...)", /* only used with VERBOSE/CHECK/DEBUG */
+	"	{	va_list args;",
+	"		enter_critical(GLOBAL_LOCK);	/* printing */",
+	"		printf(\"cpu%%d: \", core_id);",
+	"		fflush(stdout);",
+	"		va_start(args, fmt);",
+	"		vprintf(fmt, args);",
+	"		va_end(args);",
+	"		fflush(stdout);",
+	"		leave_critical(GLOBAL_LOCK);",
+	"		return 1;",
+	"	}",
+	"#else",
+	"	#define enter_critical(w)	/* none */",
+	"	#define leave_critical(w)	/* none */",
+	"",
+	"	int",
+	"	cpu_printf(const char *fmt, ...)",
+	"	{	va_list args;",
+	"		va_start(args, fmt);",
+	"		vprintf(fmt, args);",
+	"		va_end(args);",
+	"		return 1;",
+	"	}",
 	"#endif",
 
 #ifndef PRINTF
@@ -132,7 +320,7 @@
 	"static int stackread;",
 	"static Trail frameptr;",
 	"Trail *",
-	"getframe(int d)",
+	"getframe(long d)",
 	"{",
 	"	if (CNT1 == CNT2)",
 	"		return &trail[d];",
@@ -153,63 +341,103 @@
 	"	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",
-
+	"#if NCORE>1",
+	"extern void cleanup_shm(int);",
+	"volatile uint	*search_terminated; /* to signal early termination */",
+	/*
+	 *	Meaning of bitflags in search_terminated:
+	 *	  1	set by pan_exit
+	 *	  2	set by wrapup
+	 *	  4	set by uerror
+	 *	  8	set by sudden_stop -- called after someone_crashed and [Uu]error
+	 *	 16	set by cleanup_shm
+	 *	 32	set by give_up	-- called on signal
+	 *	 64	set by proxy_exit
+	 *	128	set by proxy on write port failure
+	 *	256	set by proxy on someone_crashed
+	 *
+	 *	Flags 8|32|128|256 indicate abnormal termination
+	 *
+	 *	The flags are checked in 4 functions in the code:
+	 *		sudden_stop()
+	 *		someone_crashed() (proxy and pan version)
+	 *		mem_hand_off()
+	 */
+	"#endif",
 	"void",
 	"pan_exit(int val)",
-	"{	if (signoff) printf(\"--end of output--\\n\");",
+	"{	void stop_timer(int);",
+	"#ifdef BFS_PAR",
+	"	extern void bfs_mark_done(int);",
+	"	extern void bfs_drop_shared_memory(void);",
+	"#endif",
+	"	if (signoff)",
+	"	{	printf(\"--end of output--\\n\");",
+	"	}",
+	"#if NCORE>1",
+	"	if (search_terminated != NULL)",
+	"	{	*search_terminated |= 1;	/* pan_exit */",
+	"	}",
+		"#ifdef USE_DISK",
+	"	{ void	dsk_stats(void);",
+	"		dsk_stats();",
+	"	}",
+		"#endif",
+	"	if (!state_tables && !readtrail)",
+	"	{	cleanup_shm(1);",
+	"	}",
+	"#endif",
+	"#ifdef BFS_PAR",
+	"	if (who_am_i != 0)",
+	"	{	bfs_mark_done(3); /* stopped */",
+	"	}",
+	"	bfs_drop_shared_memory();",
+	"#endif",
+	"	if (val == 2)",
+	"	{	val = 0;",
+	"	}",
+	"#ifdef BFS_PAR",
+	"	if (who_am_i == 0)",
+	"#endif",
+	"	stop_timer(1);",
+	"",
+	"#ifdef C_EXIT",
+	"	C_EXIT; /* trust that it defines a fct */",
+	"#endif",
 	"	exit(val);",
 	"}",
-
-	"#ifdef HAS_CODE",
+	"#ifdef HAS_CODE",
+	"static char tbuf[2][2048];",
+	"",
 	"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 */
+	"	memset(tbuf[0], 0, 2048);",
+	"	memset(tbuf[1], 0, 2048);",
+	"	strcpy(tbuf[toggle], s);",
+	"	while ((v = strstr(tbuf[toggle], \"{c_code\")))",	/* assign v */
 	"	{	*v = '\\0'; v++;",
-	"		strcpy(buf[1-toggle], buf[toggle]);",
+	"		strcpy(tbuf[1-toggle], tbuf[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])",
+	"			{	if (strlen(tbuf[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);",
+	"				strcat(tbuf[1-toggle], code_lookup[i].t);",
+	"				break;",
+	"			}",
+	"		strcat(tbuf[1-toggle], w);",
 	"		toggle = 1 - toggle;",
 	"	}",
-	"	buf[toggle][2047] = '\\0';",
-	"	return buf[toggle];",
+	"	tbuf[toggle][2047] = '\\0';",
+	"	return tbuf[toggle];",
 	"}",
 	"#else",
 	"char * transmognify(char *s) { return s; }",
@@ -223,7 +451,6 @@
 	"",
 	"	for (t = trans[ot][tt]; t; t = t->nxt)",
 	"	{	printf(\"\\t\\t\");",
-
 	"		q = transmognify(t->tp);",
 	"		for ( ; q && *q; q++)",
 	"			if (*q == '\\n')",
@@ -233,6 +460,17 @@
 	"		printf(\"\\n\");",
 	"	}",
 	"}",
+	"",
+	"char *",
+	"find_source(int tp, int s)",
+	"{",
+	"	if (s >= flref[tp]->from",
+	"	&&  s <= flref[tp]->upto)",
+	"	{	return flref[tp]->fnm;",
+	"	}",
+	"	return PanSource; /* i.e., don't know */",
+	"}",
+	"",
 	"void",
 	"wrap_trail(void)",
 	"{	static int wrap_in_progress = 0;",
@@ -243,14 +481,15 @@
 	"",
 	"	printf(\"spin: trail ends after %%ld steps\\n\", depth);",
 	"	if (onlyproc >= 0)",
-	"	{	if (onlyproc >= now._nr_pr) pan_exit(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\",",
+	"			{	printf(\" %%s:%%d\",",
+	"					find_source((int) z->_t, (int) z->_p),",
 	"					src_all[i].src[z->_p]);",
 	"				break;",
 	"			}",
@@ -269,7 +508,8 @@
 	"			depth, II, procname[z->_t]);",
 	"		for (i = 0; src_all[i].src; i++)",
 	"			if (src_all[i].tp == (int) z->_t)",
-	"			{	printf(\" line %%3d\",",
+	"			{	printf(\" %%s:%%d\",",
+	"					find_source((int) z->_t, (int) z->_p),",
 	"					src_all[i].src[z->_p]);",
 	"				break;",
 	"			}",
@@ -293,23 +533,100 @@
 	"findtrail(void)",
 	"{	FILE *fd;",
 	"	char fnm[512], *q;",
-	"	char MyFile[512];",
-	"",
-	"	strcpy(MyFile, TrailFile);",	/* avoid problem with non-writable strings */
-	"",
+	"	char MyFile[512];",	/* avoid using a non-writable string */
+	"	char MySuffix[16];",
+	"	int  try_core;",
+	"	int  candidate_files;",
+	"",
+	"	if (trailfilename != NULL)",
+	"	{	fd = fopen(trailfilename, \"r\");",
+	"		if (fd == NULL)",
+	"		{	printf(\"pan: cannot find %%s\\n\", trailfilename);",
+	"			pan_exit(1);",
+	"		} /* else */",
+	"		goto success;",
+	"	}",
+	"talk:",
+	"	try_core = 1;",
+	"	candidate_files = 0;",
+	"	tprefix = \"trail\";",
+	"	strcpy(MyFile, TrailFile);",
+	"	do { /* see if there's more than one possible trailfile */",
+	"		if (whichtrail)",
+	"		{	sprintf(fnm, \"%%s%%d.%%s\",",
+	"				MyFile, whichtrail, tprefix);",
+	"			fd = fopen(fnm, \"r\");",
+	"			if (fd != NULL)",
+	"			{	candidate_files++;",
+	"				if (verbose==100)",
+	"					printf(\"trail%%d: %%s\\n\",",
+	"						candidate_files, fnm);",
+	"				fclose(fd);",
+	"			}",
+	"			if ((q = strchr(MyFile, \'.\')) != NULL)",
+	"			{	*q = \'\\0\';",	/* e.g., strip .pml */
+	"				sprintf(fnm, \"%%s%%d.%%s\",",
+	"					MyFile, whichtrail, tprefix);",
+	"				*q = \'.\';",
+	"				fd = fopen(fnm, \"r\");",
+	"				if (fd != NULL)",
+	"				{	candidate_files++;",
+	"					if (verbose==100)",
+	"						printf(\"trail%%d: %%s\\n\",",
+	"							candidate_files, fnm);",
+	"					fclose(fd);",
+	"			}	}",
+	"		} else",
+	"		{	sprintf(fnm, \"%%s.%%s\", MyFile, tprefix);",
+	"			fd = fopen(fnm, \"r\");",
+	"			if (fd != NULL)",
+	"			{	candidate_files++;",
+	"				if (verbose==100)",
+	"					printf(\"trail%%d: %%s\\n\",",
+	"						candidate_files, fnm);",
+	"				fclose(fd);",
+	"			}",
+	"			if ((q = strchr(MyFile, \'.\')) != NULL)",
+	"			{	*q = \'\\0\';",	/* e.g., strip .pml */
+	"				sprintf(fnm, \"%%s.%%s\", MyFile, tprefix);",
+	"				*q = \'.\';",
+	"				fd = fopen(fnm, \"r\");",
+	"				if (fd != NULL)",
+	"				{	candidate_files++;",
+	"					if (verbose==100)",
+	"						printf(\"trail%%d: %%s\\n\",",
+	"							candidate_files, fnm);",
+	"					fclose(fd);",
+	"		}	}	}",
+	"		tprefix = MySuffix;",
+	"		sprintf(tprefix, \"cpu%%d_trail\", try_core++);",
+	"	} while (try_core <= NCORE);",
+	"",
+	"	if (candidate_files != 1)",
+	"	{	if (verbose != 100)",
+	"		{	printf(\"error: there are %%d trail files:\\n\",",
+	"				candidate_files);",
+	"			verbose = 100;",
+	"			goto talk;",
+	"		} else",
+	"		{	printf(\"pan: rm or mv all except one\\n\");",
+	"			exit(1);",
+	"	}	}",
+
+	"	try_core = 1;",
+	"	strcpy(MyFile, TrailFile); /* restore */",
+	"	tprefix = \"trail\";",
+	"try_again:",
 	"	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);",
+	"			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\");",
@@ -318,56 +635,122 @@
 	"			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);",
+	"	{	if (try_core < NCORE)",
+	"		{	tprefix = MySuffix;",
+	"			sprintf(tprefix, \"cpu%%d_trail\", try_core++);",
+	"			goto try_again;",
+	"		}",
+	"		printf(\"pan: cannot find trailfile %%s\\n\", fnm);",
 	"		pan_exit(1);",
 	"	}",
+	"success:",
+	"#if NCORE>1 && defined(SEP_STATE)",
+	"	{	void set_root(void); /* for partial traces from local root */",
+	"		set_root();",
+	"	}",
+	"#endif",
 	"	return fd;",
 	"}",
 	"",
 	"uchar do_transit(Trans *, short);",
+	"#ifdef PERMUTED",
+	"void set_permuted(int);",
+	"void set_reversed(int);",
+	"void set_rotated(int);",
+	"void set_randrot(int);",
+	"void (*p_reorder)(int) = set_permuted;",
+	"short p_rotate;",
+	"#endif",
 	"",
 	"void",
 	"getrail(void)",
 	"{	FILE *fd;",
-	"	char *q;",
-	"	int i, t_id, lastnever=-1; short II;",
+	"	char *q, *pnm;",
+	"	int i, t_id, lastnever = -1; short II;",
 	"	Trans *t;",
 	"	P0 *z;",
-	"",
+	"#ifdef PERMUTED",
+	"	char sbuf[128];",
+	"	memset(sbuf, 0, sizeof(sbuf));",
+	"#endif",
 	"	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\");",
+	"		{	printf(\"<<<<<START OF CYCLE>>>>>\\n\");",
+	"		}",
+	"#ifdef PERMUTED",
 	"		if (depth < 0)",
-	"			continue;",
+	"		{	switch (depth) {",
+	"			case -5:",
+	"				if (i && !t_reverse)",
+	"				{	strcat(sbuf, \"-t_reverse \");",
+	"				}",
+	"				break;",
+	"			case -6:",
+	"				if (i && p_reorder != set_permuted)",
+	"				{	strcat(sbuf, \"-p_permute \");",
+	"				} else",
+	"				if (t_id && p_reorder != set_reversed)",
+	"				{	strcat(sbuf, \"-p_reverse \");",
+	"				}",
+	"				break;",
+	"			case -7:",
+	"				if (i",
+	"				&& (p_reorder != set_rotated || p_rotate != t_id))",
+	"				{	char tmp[32];",
+	"					sprintf(tmp, \"-p_rotate%%d \", t_id);",
+	"					strcat(sbuf, tmp);",
+	"				}",
+	"				break;",
+	"			case -8:",
+	"				if (i && p_reorder != set_randrot)",
+	"				{	strcat(sbuf, \"-p_randrot \");",
+	"				}",
+	"				if (s_rand != ++t_id)",
+	"				{	char tmp[32];",
+	"					sprintf(tmp, \"-RS%%u \", (uint) t_id-1);",
+	"					strcat(sbuf, tmp);",
+	"				}",
+	"				break;",
+	"			default:",
+	"				continue;",
+	"			}",
+	"		}",
+	"#endif",
+	"		if (depth < 0)",
+	"		{	continue;",
+	"		}",
+	"#ifdef PERMUTED",
+	"		if (strlen(sbuf) > 0)",
+	"		{	fprintf(efd, \"add: %%s\\n\", sbuf);",
+	"			exit(1);",
+	"		}",
+	"#endif",
 	"		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)",
+	"			if (t->t_id == (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);",
+	"				if (t && t->t_id == (T_ID) t_id)",
+	"				{	printf(\"\\tRecovered 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);",
+	"			printf(\"pan: list of possible transitions in this process:\\n\");",
+	"			if (z->_t >= 0 && z->_t <= _NP_)",
 	"			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);",
@@ -377,11 +760,13 @@
 	"		q = transmognify(t->tp);",
 	"		if (gui) simvals[0] = \'\\0\';",
 
+	"		pnm = procname[z->_t];",
 	"		this = pptr(II);",
 	"		trpt->tau |= 1;",	/* timeout always possible */
 	"		if (!do_transit(t, II))",
 	"		{	if (onlyproc >= 0 && II != onlyproc)",
 	"				goto moveon;",
+	"			if (!verbose) break;",
 	"			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\");",
@@ -391,16 +776,24 @@
 	"			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);",
-	"",
+	"		{	printf(\"%%3ld: proc %%2d (%%s) \", depth, II, pnm);",
+
+	"			for (i = 0; src_all[i].src; i++)",
+	"				if (src_all[i].tp == (int) z->_t)",
+	"				{	printf(\" %%s:%%d \",",
+	"						find_source((int) z->_t, (int) z->_p),",
+	"						src_all[i].src[z->_p]);",
+	"					break;",
+	"				}",
+
+	"			printf(\"(state %%d) trans {%%d,%%d} [%%s]\\n\",",
+	"				z->_p, t_id, t->forw, q?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)",
+	"		} else if (Btypes[z->_t] == N_CLAIM)",
 	"		{	if (lastnever != (int) z->_p)",
 	"			{	for (i = 0; src_all[i].src; i++)",
 	"					if (src_all[i].tp == (int) z->_t)",
@@ -413,38 +806,39 @@
 	"			}",
 	"			lastnever = z->_p;",
 	"			goto sameas;",
-	"		} else",
-	"		if (strcmp(procname[z->_t], \":np_:\") != 0)",
+	"		} else if (Btypes[z->_t] != 0) /* not :np_: */",
 	"		{",
 	"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(%%d):\", pnm, II);",
 	"				printf(\"[%%s]\\n\", q?q:\"\");",
 	"			} else if (!silent)",
 	"			{	if (strlen(simvals) > 0) {",
 	"				printf(\"%%3ld:	proc %%2d (%%s)\", ",
-	"					depth, II, procname[z->_t]);",
+	"					depth, II, pnm);",
 	"				for (i = 0; src_all[i].src; i++)",
 	"					if (src_all[i].tp == (int) z->_t)",
-	"					{	printf(\" line %%3d \\\"pan_in\\\" \",",
+	"					{	printf(\" %%s:%%d \",",
+	"							find_source((int) z->_t, (int) z->_p),",
 	"							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]);",
+	"					depth, II, pnm);",
 	"				for (i = 0; src_all[i].src; i++)",
 	"					if (src_all[i].tp == (int) z->_t)",
-	"					{	printf(\" line %%3d \\\"pan_in\\\" \",",
+	"					{	printf(\" %%s:%%d \",",
+	"							find_source((int) z->_t, (int) z->_p),",
 	"							src_all[i].src[z->_p]);",
 	"						break;",
 	"					}",
 	"				printf(\"(state %%d)\t[%%s]\\n\", z->_p, q?q:\"\");",
-	"				printf(\"\\n\");",
+	"			/*	printf(\"\\n\");	*/",
 	"		}	}",
 	"moveon:	z->_p = t->st;",
 	"	}",
@@ -462,19 +856,22 @@
 	"	}",
 	"	return -1;",
 	"}",
-	"#ifdef VERI",
-	"void check_claim(int);",
-	"#endif",
-	"",
-	"#ifdef BITSTATE",
-#ifndef POWOW
+	"",
+	"#if NCORE>1 && !defined(GLOB_HEAP)",
+	"	#define SEP_HEAP /* version 5.1.2 */",
+	"#endif",
+	"",
+	"#ifdef BITSTATE",
 	"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;",
+	"{	ulong x, y;",
+	"	uint i = 1;",
+	"#if defined(MURMUR) && (WS==8)",
+	"	m_hash((uchar *) v, n); /* bstore_mod - sets j3_spin, j4_spin, K1, K2 */",
+	"#else",
+	"	d_hash((uchar *) v, n); /* bstore_mod - sets j3_spin, j4_spin, K1, K2 */",
+	"#endif",
+	"	x = K1; y = j3_spin;",	/* was K2 before 5.1.1 */
 	"	for (;;)",
 	"	{	if (!(SS[x%%udmem]&(1<<y))) break;",	/* take the hit in speed */
 	"		if (i == hfns) {",
@@ -483,8 +880,8 @@
 				"#endif",
 	"			return 1;",
 	"		}",
-	"		x = (x + K1 + i);",	/* no mask, using mod */
-	"		y = (y + j4) & 7;",
+	"		x = (x + K2 + i);",	/* no mask, using mod - was K1 before 5.1.1 */
+	"		y = (y + j4_spin) & 7;",
 	"		i++;",
 	"	}",
 		"#ifdef RANDSTOR",
@@ -493,8 +890,8 @@
 	"	for (;;)",
 	"	{	SS[x%%udmem] |= (1<<y);",
 	"		if (i == hfns) break;",	/* done */
-	"		x = (x + K1 + i);",	/* no mask */
-	"		y = (y + j4) & 7;",
+	"		x = (x + K2 + i);",	/* no mask - was K1 before 5.1.1 */
+	"		y = (y + j4_spin) & 7;",
 	"		i++;",
 	"	}",
 		"#ifdef DEBUG",
@@ -505,14 +902,16 @@
 	"	}",
 	"	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;",
+	"{	ulong x, y;",
+	"	uint i = 1;",
+	"#if defined(MURMUR) && (WS==8)",
+	"	m_hash((uchar *) v, n); /* bstore_reg - sets j1_spin-j4_spin */",
+	"#else",
+	"	d_hash((uchar *) v, n); /* bstore_reg - sets j1_spin-j4_spin */",
+	"#endif",
+	"	x = j2_spin; y = j3_spin;",
 	"	for (;;)",
 	"	{	if (!(SS[x]&(1<<y))) break;",	/* at least one bit not set */
 	"		if (i == hfns) {",
@@ -521,8 +920,8 @@
 				"#endif",
 	"			return 1;",
 	"		}",
-	"		x = (x + j1 + i) & nmask;",
-	"		y = (y + j4) & 7;",
+	"		x = (x + j1_spin + i) & nmask;",
+	"		y = (y + j4_spin) & 7;",
 	"		i++;",
 	"	}",
 		"#ifdef RANDSTOR",
@@ -531,8 +930,8 @@
 	"	for (;;)",
 	"	{	SS[x] |= (1<<y);",
 	"		if (i == hfns) break;",		/* done */
-	"		x = (x + j1 + i) & nmask;",
-	"		y = (y + j4) & 7;",
+	"		x = (x + j1_spin + i) & nmask;",
+	"		y = (y + j4_spin) & 7;",
 	"		i++;",
 	"	}",
 		"#ifdef DEBUG",
@@ -543,8 +942,8 @@
 	"	}",
 	"	return 0;",
 	"}",
-	"#endif",
-	"unsigned long TMODE = 0666; /* file permission bits for trail files */",
+	"#endif", /* BITSTATE */
+	"ulong TMODE = 0666; /* file permission bits for trail files */",
 	"",
 	"int trcnt=1;",
 	"char snap[64], fnm[512];",
@@ -554,18 +953,34 @@
 	"{	int fd;",
 	"	char *q;",
 	"	char MyFile[512];",
+	"	int w_flags = O_CREAT|O_WRONLY|O_TRUNC;",
+	"",
+	"	if (exclusive == 1 && iterative == 0)",
+	"	{	w_flags |= O_EXCL;",
+	"	}",
 	"",
 	"	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)",
+	"	{",
+	"#ifdef PUTPID",
+	"		sprintf(fnm, \"%%s_%%s_%%d_%%d.%%s\",",
+	"			MyFile, progname, getpid(), Nr_Trails-1, tprefix);",
+	"#else",
 	"		sprintf(fnm, \"%%s%%d.%%s\",",
 	"			MyFile, Nr_Trails-1, tprefix);",
-	"	else",
+	"#endif",
+	"	} else",
+	"	{",
+	"#ifdef PUTPID",
+	"		sprintf(fnm, \"%%s_%%s_%%d.%%s\", MyFile, progname, getpid(), tprefix);",
+	"#else",
 	"		sprintf(fnm, \"%%s.%%s\", MyFile, tprefix);",
-	"",
-	"	if ((fd = creat(fnm, TMODE)) < 0)",
+	"#endif",
+	"	}",
+	"	if ((fd = open(fnm, w_flags, TMODE)) < 0)",
 	"	{	if ((q = strchr(MyFile, \'.\')))",
 	"		{	*q = \'\\0\';",		/* strip .pml */
 	"			if (iterative == 0 && Nr_Trails-1 > 0)",
@@ -574,91 +989,146 @@
 	"			else",
 	"				sprintf(fnm, \"%%s.%%s\", MyFile, tprefix);",
 	"			*q = \'.\';",
-	"			fd = creat(fnm, TMODE);",
+	"			fd = open(fnm, w_flags, TMODE);",
 	"	}	}",
 	"	if (fd < 0)",
 	"	{	printf(\"pan: cannot create %%s\\n\", fnm);",
 	"		perror(\"cause\");",
 	"	} else",
-	"	{	printf(\"pan: wrote %%s\\n\", fnm);",
+	"	{",
+	"#if NCORE>1 && (defined(SEP_STATE) || !defined(FULL_TRAIL))",
+	"	void write_root(void); ",
+	"	write_root();",
+	"#else",
+	"		printf(\"pan: wrote %%s\\n\", fnm);",
+	"#endif",
 	"	}",
 	"	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;",
+	"",
+	"#ifndef FREQ",
+	"#define FREQ	(1000000)",
+	"#endif",
+	"double freq = (double) FREQ;\n",
+
+	"#ifdef TRIX",
+	"void sv_populate(void);",
+	"",
+	"void",
+	"re_populate(void) /* restore procs and chans from now._ids_ */",
+	"{	int i, cnt = 0;",
+	"	char *b;",
+	"#ifdef V_TRIX",
+	"	printf(\"%%4d: re_populate\\n\", depth);",
+	"#endif",
+	"	for (i = 0; i < now._nr_pr; i++, cnt++)",
+	"	{	b = now._ids_[cnt];",
+	"		processes[i]->psize = what_p_size( ((P0 *)b)->_t );",
+	"		memcpy(processes[i]->body, b, processes[i]->psize);",
+	"#ifdef TRIX_RIX",
+	"		((P0 *)pptr(i))->_pid = i;",
+	"		if (BASE > 0 && h > 0)",
+	"		{	((P0 *)pptr(i))->_pid -= BASE;",
+	"		}",
+	"#endif",
+	"#ifndef BFS",
+	"		processes[i]->modified = 1; /* re-populate */",
+	"#endif",
+	"	}",
+	"	for (i = 0; i < now._nr_qs; i++, cnt++)",
+	"	{	b = now._ids_[cnt];",
+	"		channels[i]->psize = what_q_size( ((Q0 *)b)->_t );",
+	"		memcpy(channels[i]->body, b, channels[i]->psize);",
+	"#ifndef BFS",
+	"		channels[i]->modified = 1; /* re-populate */",
+	"#endif",
+	"	}",
+	"}",
+	"#endif\n",
+
+	"#ifdef BFS",	/* breadth-first search */
+	"	#ifndef BFS_PAR",
+	"		BFS_State *bfs_trail, *bfs_bot, *bfs_free;",
+	"		SV_Hold *svfree;",
+	"	#else",
+	"		static ulong	bfs_pre_allocated;",
+	"	#endif",
+	"	#ifdef BFS_DISK",
+	"		#ifndef BFS_LIMIT",
+	"			#define BFS_LIMIT	100000",
+	"		#endif",
+	"		#ifndef BFS_DSK_LIMIT",
+	"			#define BFS_DSK_LIMIT	1000000",
+	"		#endif",
+	"		#if defined(WIN32) || defined(WIN64)",
+	"			#define RFLAGS	(O_RDONLY|O_BINARY)",
+	"			#define WFLAGS	(O_CREAT|O_WRONLY|O_TRUNC|O_BINARY)",
+	"			#define RWFLAGS	(O_RDWR|O_BINARY)",
+	"		#else",
+	"			#define RFLAGS	(O_RDONLY)",
+	"			#define WFLAGS	(O_CREAT|O_WRONLY|O_TRUNC)",
+	"			#define RWFLAGS	(O_RDWR)",
+	"		#endif",
+	"",
+	"		long bfs_size_limit;",
+	"		int bfs_dsk_write = -1;",
+	"		int bfs_dsk_read = -1;",
+	"		long bfs_dsk_writes, bfs_dsk_reads;",
+	"		int bfs_dsk_seqno_w, bfs_dsk_seqno_r;",
+	"	#endif",
 	"",
 	"uchar do_reverse(Trans *, short, uchar);",
 	"void snapshot(void);",
-	"",
+	"#if 0",
+	"void",
+	"select_claim(int x)	/* ignored in BFS mode */",
+	"{	if (verbose)",
+	"	{	printf(\"select %%d (ignored)\\n\", x);",
+	"	}",
+	"}",
+	"#endif",
+	"Trail *ntrpt;",
+	"",
+	"#ifndef BFS_PAR",
 	"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)",
+	"{	SV_Hold *h;",
+	"",
+	"	if (svfree && n <= svfree->sz)",
+	"	{	h = svfree;",
+	"		svfree = h->nxt;",
+	"		h->nxt = (SV_Hold *) 0;",
+	"	} else",
 	"	{	h = (SV_Hold *) emalloc(sizeof(SV_Hold));",
 	"		h->sz = n;",
+	"	#ifdef BFS_DISK",
+	"		if (bfs_size_limit >= BFS_LIMIT)",
+	"		{	h->sv = (State *) 0;	/* means: read disk */",
+	"			bfs_dsk_writes++;	/* count */",
+	"			if (bfs_dsk_write < 0	/* file descriptor */",
+	"			||  bfs_dsk_writes%%BFS_DSK_LIMIT == 0)",
+	"			{	char dsk_nm[32];",
+	"				if (bfs_dsk_write >= 0)",
+	"				{	(void) close(bfs_dsk_write);",
+	"				}",
+	"				sprintf(dsk_nm, \"pan_bfs_%%d.tmp\", bfs_dsk_seqno_w++);",
+	"				bfs_dsk_write = open(dsk_nm, WFLAGS, 0644);",
+	"				if (bfs_dsk_write < 0)",
+	"				{	Uerror(\"could not create tmp disk file\");",
+	"				}",
+	"				printf(\"pan: created disk file %%s\\n\", dsk_nm);",
+	"			}",
+	"			if (write(bfs_dsk_write, (char *) &now, n) != n)",
+	"			{	Uerror(\"aborting -- disk write failed (disk full?)\");",
+	"			}",
+	"			return h; /* no memcpy */",
+	"		}", /* else */
+	"		bfs_size_limit++;",
+	"	#endif",
 	"		h->sv = (State *) emalloc(sizeof(State) - VECTORSZ + n);",
 	"	}",
+	"",
+	"	memcpy((char *)h->sv, (char *)&now, n);",
 	"	return h;",
 	"}",
 	"",
@@ -669,18 +1139,24 @@
 	"",
 	"	for (h = kept; h; h = h->nxt)",
 	"		if (n == h->sz",
+	"#if !defined(NOCOMP) && !defined(HC)",
 	"		&&  (memcmp((char *) Mask, (char *) h->sv, n) == 0)",
+	"#endif",
 	"		&&  (now._nr_pr == h->nrpr)",
 	"		&&  (now._nr_qs == h->nrqs)",
-	"#if VECTORSZ>32000",
+	"	#ifdef TRIX",
+	"		)",
+	"	#else",
+	"		#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",
+	"		#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))",
+	"		#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))",
+	"	#endif",
 	"			break;",
 	"	if (!h)",
 	"	{	h = (EV_Hold *) emalloc(sizeof(EV_Hold));",
@@ -689,29 +1165,33 @@
 	"		h->nrqs = now._nr_qs;",
 	"",
 	"		h->sv = (char *) emalloc(n * sizeof(char));",
+	"#if !defined(NOCOMP) && !defined(HC)",
 	"		memcpy((char *) h->sv, (char *) Mask, n);",
-	"",
+	"#endif",
+	"	#ifndef TRIX",
 	"		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",
+	"		{	h->ps = (char *) emalloc(now._nr_pr * sizeof(int));",
+	"			memcpy((char *) h->ps, (char *) proc_skip,   now._nr_pr * sizeof(uchar));",
+	"		#if VECTORSZ>32000",
+	"			h->po = (char *) emalloc(now._nr_pr * sizeof(int));",
 	"			memcpy((char *) h->po, (char *) proc_offset, now._nr_pr * sizeof(int));",
-	"#else",
+	"		#else",
+	"			h->po = (char *) emalloc(now._nr_pr * sizeof(short));",
 	"			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));",
+	"		#endif",
 	"		}",
 	"		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",
+	"		{	h->qs = (char *) emalloc(now._nr_qs * sizeof(int));",
+	"			memcpy((char *) h->qs, (char *) q_skip,   now._nr_qs * sizeof(uchar));",
+	"		#if VECTORSZ>32000",
+	"			h->qo = (char *) emalloc(now._nr_qs * sizeof(int));",
 	"			memcpy((char *) h->qo, (char *) q_offset, now._nr_qs * sizeof(int));",
-	"#else",
+	"		#else",
+	"			h->qo = (char *) emalloc(now._nr_qs * sizeof(short));",
 	"			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));",
-	"		}",
-	"",
+	"		#endif",
+	"		}",
+	"	#endif",
 	"		h->nxt = kept;",
 	"		kept = h;",
 	"	}",
@@ -724,9 +1204,9 @@
 	"",
 	"	oh = (SV_Hold *) 0;",
 	"	for (h = svfree; h; oh = h, h = h->nxt)",
-	"		if (h->sz >= p->sz)",
-	"			break;",
-	"",
+	"	{	if (p->sz >= h->sz)",
+	"			break;",
+	"	}",
 	"	if (!oh)",
 	"	{	p->nxt = svfree;",
 	"		svfree = p;",
@@ -736,171 +1216,239 @@
 	"	}",
 	"}",
 	"",
-	"BFS_Trail *",
+	"BFS_State *",
 	"get_bfs_frame(void)",
-	"{	BFS_Trail *t;",
+	"{	BFS_State *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->nxt = (BFS_State *) 0;",
+	"	} else",
+	"	{	t = (BFS_State *) emalloc(sizeof(BFS_State));",
 	"	}",
 	"	t->frame = (Trail *) emalloc(sizeof(Trail));", /* always new */
+	"	/* new because we keep a ptr to the frame of parent states */",
+	"	/* used for reconstructing path and recovering failed rvs etc */",
 	"	return t;",
 	"}",
 	"",
 	"void",
 	"push_bfs(Trail *f, int d)",
-	"{	BFS_Trail *t;",
+	"{	BFS_State *t;",
 	"",
 	"	t = get_bfs_frame();",
 	"	memcpy((char *)t->frame, (char *)f, sizeof(Trail));",
 	"	t->frame->o_tt = d;	/* depth */",
 	"",
 	"	t->boq = boq;",
+	"	#ifdef TRIX",
+	"	sv_populate();",
+	"	#endif",
 	"	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 defined(FULLSTACK) && defined(Q_PROVISO)",
+	"	t->lstate = Lstate;	/* bfs */",
+	"	#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",
+	"	#ifdef VERBOSE",
+	"	t->nr = nstates;",
+	"	#endif",
+	"	#ifdef CHECK",
+	"		#ifdef VERBOSE",
+	"	printf(\"PUSH %%lu (depth %%d, nr %%lu)\\n\", (ulong) t->frame, d, t->nr);",
+	"		#else",
+	"	printf(\"PUSH %%lu (depth %%d)\\n\", (ulong) t->frame, d);",
+	"		#endif",
+	"	#endif",
 	"}",
 	"",
 	"Trail *",
 	"pop_bfs(void)",
-	"{	BFS_Trail *t;",
+	"{	BFS_State *t;",
 	"",
 	"	if (!bfs_trail)",
-	"		return (Trail *) 0;",
-	"",
+	"	{	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",
-	"",
+	"	{	bfs_bot = (BFS_State *) 0;",
+	"	}",
+	"	#if defined(Q_PROVISO) && !defined(BITSTATE) && !defined(NOREDUCE)",
+	"	if (t->lstate)			/* bfs */",
+	"	{	t->lstate->tagged = 0;	/* bfs */",
+	"	}",
+	"	#endif",
 	"	t->nxt = bfs_free;",
 	"	bfs_free = t;",
 	"",
 	"	vsize = t->onow->sz;",
 	"	boq = t->boq;",
-	"",
-	"	memcpy((uchar *) &now, (uchar *) t->onow->sv, vsize);",
+	"	#ifdef BFS_DISK",
+	"	if (t->onow->sv == (State *) 0)",
+	"	{	char dsk_nm[32];",
+	"		bfs_dsk_reads++;	/* count */",
+	"		if (bfs_dsk_read >= 0	/* file descriptor */",
+	"		&&  bfs_dsk_reads%%BFS_DSK_LIMIT == 0)",
+	"		{	(void) close(bfs_dsk_read);",
+	"			sprintf(dsk_nm, \"pan_bfs_%%d.tmp\", bfs_dsk_seqno_r-1);",
+	"			(void) unlink(dsk_nm);",
+	"			bfs_dsk_read = -1;",
+	"		}",
+	"		if (bfs_dsk_read < 0)",
+	"		{	sprintf(dsk_nm, \"pan_bfs_%%d.tmp\", bfs_dsk_seqno_r++);",
+	"			bfs_dsk_read = open(dsk_nm, RFLAGS);",
+	"			if (bfs_dsk_read < 0)",
+	"			{	Uerror(\"could not open temp disk file\");",
+	"		}	}",
+	"		if (read(bfs_dsk_read, (char *) &now, vsize) != vsize)",
+	"		{	Uerror(\"bad bfs disk file read\");",
+	"		}",
+	"		#ifndef NOVSZ",
+	"		if (now._vsz != vsize)",
+	"		{	Uerror(\"disk read vsz mismatch\");",
+	"		}",
+	"		#endif",
+	"	} else",
+	"	#endif",
+	"	{	memcpy((uchar *) &now, (uchar *) t->onow->sv, vsize);",
+	"	#ifndef NOVSZ",
+	"		vsize = now._vsz;",
+	"	#endif",
+	"	}",
+	"#if !defined(NOCOMP) && !defined(HC)",
 	"	memcpy((uchar *) Mask, (uchar *) t->omask->sv, vsize);",
-
+	"#endif",
+	"	#ifdef TRIX",
+	"	re_populate();",
+	"	#else",
 	"	if (now._nr_pr > 0)",
-	"#if VECTORSZ>32000",
+	"		#if VECTORSZ>32000",
 	"	{	memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(int));",
-	"#else",
+	"		#else",
 	"	{	memcpy((char *)proc_offset, (char *)t->omask->po, now._nr_pr * sizeof(short));",
-	"#endif",
+	"		#endif",
 	"		memcpy((char *)proc_skip,   (char *)t->omask->ps, now._nr_pr * sizeof(uchar));",
 	"	}",
 	"	if (now._nr_qs > 0)",
-	"#if VECTORSZ>32000",
+	"		#if VECTORSZ>32000",
 	"	{	memcpy((uchar *)q_offset, (uchar *)t->omask->qo, now._nr_qs * sizeof(int));",
-	"#else",
+	"		#else",
 	"	{	memcpy((uchar *)q_offset, (uchar *)t->omask->qo, now._nr_qs * sizeof(short));",
-	"#endif",
+	"		#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",
+	"	#endif",
+	"	#ifdef BFS_DISK",
+	"	if (t->onow->sv != (State *) 0)",
+	"	#endif",
+	"	{	freesv(t->onow);	/* omask not freed */",
+	"	}",
+	"	#ifdef CHECK",
+	"		#ifdef VERBOSE",
+	"	printf(\"POP %%lu (depth %%d, nr %%lu)\\n\", (ulong) t->frame, t->frame->o_tt, t->nr);",
+	"		#else",
+	"	printf(\"POP %%lu (depth %%d)\\n\", (ulong) t->frame, t->frame->o_tt);",
+	"		#endif",
+	"	#endif",
 	"	return t->frame;",
 	"}",
 	"",
 	"void",
 	"store_state(Trail *ntrpt, int shortcut, short oboq)",
 	"{",
-	"#ifdef VERI",
+	"	#ifdef VERI",
 	"	Trans *t2 = (Trans *) 0;",
 	"	uchar ot; int tt, E_state;",
 	"	uchar o_opm = trpt->o_pm, *othis = this;",
 	"",
 	"	if (shortcut)",
 	"	{",
-	"#ifdef VERBOSE",
+	"		#ifdef VERBOSE",
 	"		printf(\"claim: shortcut\\n\");",
-	"#endif",
+	"		#endif",
 	"		goto store_it;	/* no claim move */",
 	"	}",
 	"",
-	"	this  = (((uchar *)&now)+proc_offset[0]); /* 0 = never claim */",
+	"	this  = pptr(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",
+	"		#ifdef HAS_UNLESS",
 	"	E_state = 0;",
-		"#endif",
+	"		#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",
+	"		#ifdef HAS_UNLESS",
+	"		if (E_state > 0 && E_state != t2->e_trans)",
+	"		{	break;",
+	"		}",
+	"		#endif",
 	"		if (do_transit(t2, 0))",
 	"		{",
-		"#ifdef VERBOSE",
+	"		#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",
+	"		#endif",
+	"		#ifdef HAS_UNLESS",
 	"			E_state = t2->e_trans;",
-		"#endif",
+	"		#endif",
 	"			if (t2->st > 0)",
 	"			{	((P0 *)this)->_p = t2->st;",
 	"				reached[ot][t2->st] = 1;",
-		"#ifndef NOCLAIM",
-	"				check_claim(t2->st);",
-		"#endif",
+	"		#ifndef NOCLAIM",
+	"				if (stopstate[ot][t2->st])",
+	"				{	uerror(\"end state in claim reached\");",
+	"				}",
+	"		#endif",
 	"			}",
 	"			if (now._nr_pr == 0)	/* claim terminated */",
 	"				uerror(\"end state in claim reached\");",
 	"",
-		"#ifdef PEG",
+	"		#ifdef PEG",
 	"			peg[t2->forw]++;",
-		"#endif",
+	"		#endif",
 	"			trpt->o_pm |= 1;",
-	"			if (t2->atom&2)",	/* atomic in claim */
-	"			Uerror(\"atomic in claim not supported in BFS mode\");",
+	"			if (t2->atom&2)",
+	"			{ Uerror(\"atomic in claim not supported in BFS\");",
+	"			}",
 	"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",
+	"	#endif",	/* VERI */
+	"",
+	"	#if defined(BITSTATE)",
+	"			if (!b_store((char *)&now, vsize))",
+	"	#elif defined(MA)",
+	"			if (!g_store((char *)&now, vsize, 0))",
+	"	#else",
+	"			if (!h_store((char *)&now, vsize))",
+	"	#endif",
+	"			{	static long sdone = (long) 0; long ndone;",
+	"				nstates++;",
+	"	#ifndef NOREDUCE",
+	"				trpt->tau |= 64;", /* bfs: succ definitely outside stack */
+	"	#endif",
+	"				ndone = (ulong) (nstates/(freq));",
+	"				if (ndone != sdone && mreached%%10 != 0)",
+	"				{	snapshot();",
+	"					sdone = ndone;",
+	"	#if defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(MA)",
+	"					if (nstates > ((double)(1<<(ssize+1))))",
+	"					{	void resize_hashtable(void);",
+	"						resize_hashtable();",
+	"					}",
+	"	#endif",
+	"				}",
+	"	#if SYNC",
 	"				if (boq != -1)",
 	"					midrv++;",
 	"				else if (oboq != -1)",
@@ -908,26 +1456,29 @@
 	"					x = (Trail *) trpt->ostate; /* pre-rv state */",
 	"					if (x) x->o_pm |= 4; /* mark success */",
 	"				}",
-	"#endif",
+	"	#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 defined(Q_PROVISO) && !defined(NOREDUCE) && defined(FULLSTACK)",
+	"		#if !defined(BITSTATE)",
+	"				if (Lstate && Lstate->tagged)",
+	"				{  trpt->tau |= 64;",
+	"				}",
+	"		#else",
 	"				if (trpt->tau&32)",
-	"				{  BFS_Trail *tprov;",
+	"				{  BFS_State *tprov;",
 	"				   for (tprov = bfs_trail; tprov; tprov = tprov->nxt)",
-	"					if (!memcmp((uchar *)&now, (uchar *)tprov->onow->sv, vsize))",
+	"					if (tprov->onow->sv != (State *) 0",
+	"					&&  memcmp((uchar *)&now, (uchar *)tprov->onow->sv, vsize) == 0)",
 	"					{	trpt->tau |= 64;",
 	"						break;	/* state is in queue */",
 	"				}	}",
-		"#endif",
-	"#endif",
-	"			}",
-	"#ifdef VERI",
+	"		#endif",
+	"	#endif",
+	"			}",
+	"	#ifdef VERI",
 	"			((P0 *)this)->_p = tt;	/* reset claim */",
 	"			if (t2)",
 	"				do_reverse(t2, 0, 0);",
@@ -936,10 +1487,8 @@
 	"	}	}",
 	"	this = othis;",
 	"	trpt->o_pm = o_opm;",
-	"#endif",
-	"}",
-	"",
-	"Trail *ntrpt;",	/* 4.2.8 */
+	"	#endif",
+	"}",
 	"",
 	"void",
 	"bfs(void)",
@@ -950,7 +1499,7 @@
 	"	short oboq = boq;",
 	"",
 	"	ntrpt = (Trail *) emalloc(sizeof(Trail));",
-	"	trpt->ostate = (struct H_el *) 0;",
+	"	trpt->ostate = (H_el *) 0;",
 	"	trpt->tau = 0;",
 	"",
 	"	trpt->o_tt = -1;",
@@ -958,81 +1507,74 @@
 	"",
 	"	while ((otrpt = pop_bfs()))	/* also restores now */",
 	"	{	memcpy((char *) trpt, (char *) otrpt, sizeof(Trail));",
-	"#if defined(C_States) && (HAS_TRACK==1)",
+	"	#if defined(C_States) && (HAS_TRACK==1)",
 	"		c_revert((uchar *) &(now.c_state[0]));",
-	"#endif",
+	"	#endif",
 	"		if (trpt->o_pm & 4)",
 	"		{",
-	"#ifdef VERBOSE",
+	"	#ifdef VERBOSE",
 	"			printf(\"Revisit of atomic not needed (%%d)\\n\",",
 	"				trpt->o_pm);",	/* at least 1 rv succeeded */
-	"#endif",
+	"	#endif",
 	"			continue;",
 	"		}",
-	"#ifndef NOREDUCE",
+	"	#ifndef NOREDUCE",
 	"		nps = 0;",
-	"#endif",
+	"	#endif",
 	"		if (trpt->o_pm == 8)",
 	"		{	revrv++;",
 	"			if (trpt->tau&8)",
 	"			{",
-		"#ifdef VERBOSE",
+	"	#ifdef VERBOSE",
 	"				printf(\"Break atomic (pm:%%d,tau:%%d)\\n\",",
 	"					trpt->o_pm, trpt->tau);",
-		"#endif",
+	"	#endif",
 	"				trpt->tau &= ~8;",
 	"			}",
-	"#ifndef NOREDUCE",
+	"	#ifndef NOREDUCE",
 	"			else if (trpt->tau&32)",	/* was a preselected move */
 	"			{",
-		"#ifdef VERBOSE",
+	"		#ifdef VERBOSE",
 	"				printf(\"Void preselection (pm:%%d,tau:%%d)\\n\",",
 	"					trpt->o_pm, trpt->tau);",
-		"#endif",
+	"		#endif",
 	"				trpt->tau &= ~32;",
 	"				nps = 1; /* no preselection in repeat */",
 	"			}",
-	"#endif",
+	"	#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);",
+	"			{	snapshot();",
 	"		}	}",
 	"		depth = trpt->o_tt;",
 
 	"		if (depth >= maxdepth)",
 	"		{",
-	"#if SYNC",
+	"	#if SYNC",
 	"			Trail *x;",
 	"			if (boq != -1)",
 	"			{	x = (Trail *) trpt->ostate;",
 	"				if (x) x->o_pm |= 4; /* not failing */",
 	"			}",
-	"#endif",
+	"	#endif",
 	"			truncs++;",
 	"			if (!warned)",
 	"			{	warned = 1;",
 	"		  		printf(\"error: max search depth too small\\n\");",
 	"			}",
 	"			if (bounded)",
-	"				uerror(\"depth limit reached\");",
+	"			{	uerror(\"depth limit reached\");",
+	"			}",
 	"			continue;",
 	"		}",
-
-/* PO */
-	"#ifndef NOREDUCE",
+	"	#ifndef NOREDUCE",
 	"		if (boq == -1 && !(trpt->tau&8) && nps == 0)",
 	"		for (II = now._nr_pr-1; II >= BASE; II -= 1)",
 	"		{",
-	"Pickup:			this = pptr(II);",
+	"Pickup:		this = pptr(II);",
 	"			tt = (int) ((P0 *)this)->_p;",
 	"			ot = (uchar) ((P0 *)this)->_t;",
 	"			if (trans[ot][tt]->atom & 8)",	/* safe */
@@ -1045,15 +1587,14 @@
 	"				}",
 	"				From = To = II;",
 	"				trpt->tau |= 32; /* preselect marker */",
-		"#ifdef DEBUG",
-	"				printf(\"%%3d: proc %%d PreSelected (tau=%%d)\\n\", ",
+	"		#ifdef DEBUG",
+	"				printf(\"%%3ld: proc %%d PreSelected (tau=%%d)\\n\", ",
 	"					depth, II, trpt->tau);",
-		"#endif",
+	"		#endif",
 	"				goto MainLoop;",
 	"		}	}",
 	"		trpt->tau &= ~32;",	/* not preselected */
-	"#endif",
-/* PO */
+	"	#endif",	/* if !NOREDUCE */
 	"Repeat:",
 	"		if (trpt->tau&8)		/* atomic */",
 	"		{	From = To = (short ) trpt->pr;",
@@ -1066,32 +1607,44 @@
 	"		_n = _m = 0;",
 	"		for (II = From; II >= To; II -= 1)",
 	"		{",
-	"			this = (((uchar *)&now)+proc_offset[II]);",
+	"			this = pptr(II);",
 	"			tt = (int) ((P0 *)this)->_p;",
 	"			ot = (uchar) ((P0 *)this)->_t;",
-	"#if SYNC",
+	"	#if SYNC",
 	"			/* no rendezvous with same proc */",
-	"			if (boq != -1 && trpt->pr == II) continue;",
-	"#endif",
+	"			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_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",
+	"	#endif",
+
+	"	#ifdef HAS_PRIORITY",
+	"			if (!highest_priority(((P0 *)this)->_pid, II, t))",
+	"			{	continue;",
+	"			}",
+	"	#else",
+	"		#ifdef HAS_PROVIDED",
+	"			if (!provided(II, ot, tt, t))",
+	"			{	continue;",
+	"			}",
+	"		#endif",
+	"	#endif",
+
+	"	#ifdef HAS_UNLESS",
 	"			E_state = 0;",
-	"#endif",
+	"	#endif",
 	"			for (t = trans[ot][tt]; t; t = t->nxt)",
 	"			{",
-	"#ifdef HAS_UNLESS",
+	"	#ifdef HAS_UNLESS",
 	"				if (E_state > 0",
 	"				&&  E_state != t->e_trans)",
 	"					break;",
-	"#endif",
+	"	#endif",
 	"				ntrpt->o_t = t;",
 	"",
 	"				oboq = boq;",
@@ -1101,136 +1654,147 @@
 	"",
 	"				trpt->o_pm |= 1;	/* we moved */",
 	"				(trpt+1)->o_m = _m;	/* for unsend */",
-		"#ifdef PEG",
+	"	#ifdef PEG",
 	"				peg[t->forw]++;",
-		"#endif",
-	"#ifdef CHECK",
-	"				printf(\"%%3d: proc %%d exec %%d, \",",
+	"	#endif",
+	"	#ifdef CHECK",
+	"				printf(\"%%3ld: 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",
+	"		#ifdef HAS_UNLESS",
 	"				if (t->e_trans)",
 	"					printf(\" (escapes to state %%d)\", t->st);",
-		"#endif",
+	"		#endif",
 	"				printf(\" %%saccepting [tau=%%d]\\n\",",
 	"					(trpt->o_pm&2)?\"\":\"non-\", trpt->tau);",
-	"#endif",
-	"#ifdef HAS_UNLESS",
+	"	#endif",
+	"	#ifdef HAS_UNLESS",
 	"				E_state = t->e_trans;",
-		"#if SYNC>0",
+	"		#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, \"error:\ta 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;",
+	"		#endif",
+	"	#endif",
+	"				if (t->st > 0)",
+	"				{	((P0 *)this)->_p = t->st;",
+	"				}",
+	"",
+	"	/* ptr to pred: */	ntrpt->ostate = (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",
+	"	#ifdef EVENT_TRACE",
 	"				now._event = trpt->o_event;",
-	"#endif",
-	"",
+	"	#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);",
+	"	#ifdef CHECK",
+	"				enter_critical(GLOBAL_LOCK);	/* verbose mode */",
+	"		#if NCORE>1",
+	"				printf(\"cpu%%d: \", core_id);",
+	"		#endif",
+	"				printf(\"%%3lu: proc %%d \", depth, II);",
 	"				printf(\"reverses %%d, %%d to %%d,\",",
 	"					t->forw, tt, t->st);",
-	"				printf(\" %%s [abit=%%d,adepth=%%d,\",",
+	"				printf(\" %%s [abit=%%d,adepth=%%ld,\",",
 	"					t->tp, now._a_t, A_depth);",
 	"				printf(\"tau=%%d,%%d]\\n\",",
 	"					trpt->tau, (trpt-1)->tau);",
-	"#endif",
+	"				leave_critical(GLOBAL_LOCK);",
+	"	#endif",
 	"				reached[ot][t->st] = 1;",
-	"				reached[ot][tt] = 1;",
+	"				reached[ot][tt]    = 1;",
 	"",
 	"				((P0 *)this)->_p = tt;",
 	"				_n |= _m;",
 	"		}	}",
-/* PO */
-	"#ifndef NOREDUCE",
+	"	#ifndef NOREDUCE",	/* with PO */
 	"		/* 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\", ",
+	"		#ifdef DEBUG",
+	"			cpu_printf(\"%%3ld: proc %%d UnSelected (_n=%%d, tau=%%d)\\n\", ",
 	"				depth, II+1, (int) _n, trpt->tau);",
-	"#endif",
+	"		#endif",
 	"			_n = 0; trpt->tau &= ~32;",
 	"			if (II >= BASE)",
-	"				goto Pickup;",
+	"			{	goto Pickup;",
+	"			}",
 	"			goto MainLoop;",
 	"		}",
 	"		trpt->tau &= ~(32|64);",
-	"#endif",
-/* PO */
+	"	#endif",	/* PO */
 	"		if (_n != 0)",
-	"			continue;",
-	"#ifdef DEBUG",
-	"		printf(\"%%3d: no move [II=%%d, tau=%%d, boq=%%d, _nr_pr=%%d]\\n\",",
+	"		{	continue;",
+	"		}",
+	"	#ifdef DEBUG",
+	"		printf(\"%%3ld: no move [II=%%d, tau=%%d, boq=%%d, _nr_pr=%%d]\\n\",",
 	"			depth, II, trpt->tau, boq, now._nr_pr);",
-	"#endif",
+	"	#endif",
 	"		if (boq != -1)",
 	"		{	failedrv++;",
-	"			x = (Trail *) trpt->ostate; /* pre-rv state */",
-	"			if (!x) continue; /* root state */",
+	"			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",
+	"				this = pptr(otrpt->pr);",
+	"	#ifdef VERBOSE",
 	"				printf(\"\\treset state of %%d from %%d to %%d\\n\",",
 	"					otrpt->pr, ((P0 *)this)->_p, otrpt->st);",
-	"#endif",
+	"	#endif",
 	"				((P0 *)this)->_p = otrpt->st;",
 	"				unsend(boq);	/* retract rv offer */",
 	"				boq = -1;",
 
 	"				push_bfs(x, x->o_tt);",
-	"#ifdef VERBOSE",
+	"	#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",
+	"	#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\",",
+	"	#ifdef DEBUG",
+	"				printf(\"%%3ld: atomic step proc %%d blocks\\n\",",
 	"					depth, II+1);",
-	"#endif",
+	"	#endif",
 	"				goto Repeat;",
 	"			}",
 	"",
 	"			if (!(trpt->tau&1)) /* didn't try timeout yet */",
 	"			{	trpt->tau |=  1;",
-	"#ifdef DEBUG",
-	"				printf(\"%%d: timeout\\n\", depth);",
-	"#endif",
+	"	#ifdef DEBUG",
+	"				printf(\"%%ld: timeout\\n\", depth);",
+	"	#endif",
 	"				goto MainLoop;",
 	"			}",
-	"#ifndef VERI",
+	"	#ifndef VERI",
 	"			if (!noends && !a_cycles && !endstate())",
-	"				uerror(\"invalid end state\");",
-	"#endif",
-	"	}	}",
-	"}",
+	"			{	uerror(\"invalid end state\");",
+	"			}",
+	"	#endif",
+	"	}	}",
+	"}",
+	"#endif",	/* !BFS_PAR */
 	"",
 	"void",
 	"putter(Trail *trpt, int fd)",
@@ -1252,40 +1816,178 @@
 	"}",
 	"",
 	"void",
-	"nuerror(char *str)",
+	"n_ewrite(int fd, char *s, int n)",
+	"{	if (write(fd, s, strlen(s)) != strlen(s))",
+	"	{       printf(\"pan: error writing %%s\\n\", fnm);",
+	"		pan_exit(1);",
+	"	}",
+	"}",
+	"",
+	"void",
+	"nuerror(void)",
 	"{	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",
+	"	#ifdef VERI",
+	"		sprintf(snap, \"-2:%%d:-2\\n\", (uchar) ((P0 *)pptr(0))->_t);",
+	"		n_ewrite(fd, snap, strlen(snap));",
+	"	#endif",
+	"	#ifdef MERGED",
+	"		sprintf(snap, \"-4:-4:-4\\n\");",
+	"		n_ewrite(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);",
-	"	}	}",
+	"		n_ewrite(fd, snap, j);",
+	"	}",
 	"	close(fd);",
 	"	if (errors >= upto && upto != 0)",
-	"	{",
-	"		wrapup();",
+	"	{	wrapup();",
 	"	}",
 	"}",
 	"#endif",	/* BFS */
 	0,
 };
 
-static char *Code2c[] = {
+static const char *Code2d[] = {
+	"clock_t start_time;",
+	"#if NCORE>1",
+	"clock_t crash_stamp;",
+	"#endif",
+	"#if !defined(WIN32) && !defined(WIN64)",
+	"struct tms start_tm;",
+	"#endif",
+	"",
+	"#if SYNC",
+	"extern int q_zero(int);",
+	"extern int not_RV(int);",
+	"#endif",
+	"",
+	"void",
+	"start_timer(void)",
+	"{",
+	"#if defined(WIN32) || defined(WIN64)",
+	"	start_time = clock();",
+	"#else",
+	"	start_time = times(&start_tm);",
+	"#endif",
+	"}",
+	"",
+	"double delta_time;",
+	"",
+	"void",
+	"report_time(void)",
+	"{",
+	"	printf(\"\\npan: elapsed time %%.3g seconds\\n\", delta_time);",
+	"	if (delta_time > 0.01)",
+	"	{	printf(\"pan: rate %%9.8g states/second\\n\", nstates/delta_time);",
+	"		if (verbose)",
+	"		{	printf(\"pan: avg transition delay %%.5g usec\\n\",",
+	"				delta_time/(nstates+truncs));",
+	"	}	}",
+	"}",
+	"",
+	"void",
+	"stop_timer(int report)",
+	"{	clock_t stop_time;",
+	"#if !defined(WIN32) && !defined(WIN64)",
+	"	struct tms stop_tm;",
+	"	stop_time = times(&stop_tm);",
+	"	delta_time = ((double) (stop_time - start_time)) / ((double) sysconf(_SC_CLK_TCK));",
+	"#else",
+	"	stop_time = clock();",
+	"	delta_time = ((double) (stop_time - start_time)) / ((double) CLOCKS_PER_SEC);",
+	"#endif",
+	"	if (readtrail || delta_time < 0.00) return;",
+	"#if NCORE>1",
+	"	if (core_id == 0 && nstates > (double) 0)",
+	"	{	printf(\"\\ncpu%%d: elapsed time %%.3g seconds (%%g states visited)\\n\",",
+	"			core_id, delta_time, nstates);",
+	"		if (delta_time > 0.01)",
+	"		{	printf(\"cpu%%d: rate %%g states/second\\n\", core_id, nstates/delta_time);",
+	"		}",
+	"		{ void check_overkill(void);",
+	"	 	  check_overkill();",
+	"	}	}",
+	"#else",
+	"	if (report)",
+	"	{	report_time();",
+	"	}",
+	"#endif",
+	"}",
+	"",
+	"#if NCORE>1",
+	"#ifdef T_ALERT",
+	"double t_alerts[17];",
+	"",
+	"void",
+	"crash_report(void)",
+	"{	int i;",
+	"	printf(\"crash alert intervals:\\n\");",
+	"	for (i = 0; i < 17; i++)",
+	"	{	printf(\"%%d\\t%%g\\n\", i, t_alerts[i]);",
+	"}	}",
+	"#endif",
+	"",
+	"void",
+	"crash_reset(void)",
+	"{	/* false alarm */",
+	"	if (crash_stamp != (clock_t) 0)",
+	"	{",
+	"#ifdef T_ALERT",
+	"		double delta_time;",
+	"		int i;",
+		"#if defined(WIN32) || defined(WIN64)",
+	"		delta_time = ((double) (clock() - crash_stamp)) / ((double) CLOCKS_PER_SEC);",
+		"#else",
+	"		delta_time = ((double) (times(&start_tm) - crash_stamp)) / ((double) sysconf(_SC_CLK_TCK));",
+		"#endif",
+	"		for (i = 0; i < 16; i++)",
+	"		{	if (delta_time <= (i*30))",
+	"			{	t_alerts[i] = delta_time;",
+	"				break;",
+	"		}	}",
+	"		if (i == 16) t_alerts[i] = delta_time;",
+	"#endif",
+	"		if (verbose)",
+	"		printf(\"cpu%%d: crash alert off\\n\", core_id);",
+	"	}",
+	"	crash_stamp = (clock_t) 0;",
+	"}",
+	"",
+	"int",
+	"crash_test(double maxtime)",
+	"{	double delta_time;",
+	"	if (crash_stamp == (clock_t) 0)",
+	"	{	/* start timing */",
+	"#if defined(WIN32) || defined(WIN64)",
+	"		crash_stamp = clock();",
+	"#else",
+	"		crash_stamp = times(&start_tm);",
+	"#endif",
+	"		if (verbose)",
+	"		{	printf(\"cpu%%d: crash detection\\n\", core_id);",
+	"		}",
+	"		return 0;",
+	"	}",
+	"#if defined(WIN32) || defined(WIN64)",
+	"	delta_time = ((double) (clock() - crash_stamp)) / ((double) CLOCKS_PER_SEC);",
+	"#else",
+	"	delta_time = ((double) (times(&start_tm) - crash_stamp)) / ((double) sysconf(_SC_CLK_TCK));",
+	"#endif",
+	"	return (delta_time >= maxtime);",
+	"}",
+	"#endif",
+	"",
+	"#ifdef BFS_PAR",
+	"int ncores = 0;",
+	"#endif",
+	"",
 	"void",
 	"do_the_search(void)",
 	"{	int i;",
@@ -1300,11 +2002,13 @@
 	"		if (!(trpt->o_pm&2)",
 	"		&&  accpstate[ptr->_t][ptr->_p])",
 	"		{	trpt->o_pm |= 2;",
+	"			break;",
 	"		}",
 	"#else",
 	"		if (!(trpt->o_pm&4)",
 	"		&&  progstate[ptr->_t][ptr->_p])",
 	"		{	trpt->o_pm |= 4;",
+	"			break;",
 	"		}",
 	"#endif",
 	"	}",
@@ -1319,20 +2023,20 @@
 	"	}",
 	"#endif",
 	"#endif",
-	"#ifndef NOCOMP",
+	"#if !defined(NOCOMP) && !defined(HC)",
 	"	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",
+	"	#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",
@@ -1340,12 +2044,19 @@
 	"	{	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\",",
+	"	printf(\"%%3ld: fairness Rule 1, cnt=%%d, _a_t=%%d\\n\",",
 	"		depth, now._cnt[now._a_t&1], now._a_t);",
 		"#endif",
 	"	}",
 	"#endif",
 
+	"	c_stack_start = (char *) &i; /* meant to be read-only */",
+
+	"#if defined(HAS_CODE) && defined (C_INIT)",
+	"	C_INIT; /* initialization of data that must precede fork() */",
+	"	c_init_done++;",
+	"#endif",
+
 	"#if defined(C_States) && (HAS_TRACK==1)",
 	"	/* capture initial state of tracked C objects */",
 	"	c_update((uchar *) &(now.c_state[0]));",
@@ -1354,17 +2065,30 @@
 	"#ifdef HAS_CODE",
 	"	if (readtrail) getrail(); /* no return */",
 	"#endif",
+	"#ifndef BFS_PAR",
+	"	start_timer();",
+	"#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 */",
+	"	#ifdef BFS_PAR",
+	"		bfs_main(ncores,0);",
+	"	#else",
+	"		bfs();",
+	"	#endif",
+	"#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",
+
+	"	#if defined(P_RAND) || defined(T_RAND)",
+	"		srand(s_rand+HASH_NR);", /* do_the_search */
+	"	#endif",
+
+	"	#if NCORE>1",
+	"		mem_get();",
+	"	#else",
+	"		new_state();	/* start 1st DFS */",
+	"	#endif",
 	"#endif",
 	"}",
 
@@ -1373,42 +2097,41 @@
 	"do_reverse(Trans *t, short II, uchar M)",
 	"{	uchar _m = M;",
 	"	int  tt = (int) ((P0 *)this)->_p;",
-	"#include REVERSE_MOVES",
+	"#include BACKWARD_MOVES",
 	"R999:	return _m;",
 	"}",
 	"#endif",
 
 	"#ifndef INLINE",
-	"#ifdef EVENT_TRACE",
+	"	#ifdef EVENT_TRACE",
 	"static char _tp = 'n'; static int _qid = 0;",
-	"#endif",
+	"	#endif",
 	"uchar",
 	"do_transit(Trans *t, short II)",
 	"{	uchar _m = 0;",
 	"	int  tt = (int) ((P0 *)this)->_p;",
-	"#ifdef M_LOSS",
+	"	#ifdef M_LOSS",
 	"	uchar delta_m = 0;",
-	"#endif",
-	"#ifdef EVENT_TRACE",
+	"	#endif",
+	"	#ifdef EVENT_TRACE",
 	"	short oboq = boq;",
 	"	uchar ot = (uchar)  ((P0 *)this)->_t;",
-	"	if (ot == EVENT_TRACE) boq = -1;",
+	"	if (II == -EVENT_TRACE) boq = -1;",
 		"#define continue	{ boq = oboq; return 0; }",
-	"#else",
+	"	#else",
 		"#define continue	return 0",
 		"#ifdef SEPARATE",
 	"	uchar ot = (uchar)  ((P0 *)this)->_t;",
 		"#endif",
-	"#endif",
+	"	#endif",
 	"#include FORWARD_MOVES",
 	"P999:",
-	"#ifdef EVENT_TRACE",
-	"	if (ot == EVENT_TRACE) boq = oboq;",
-	"#endif",
+	"	#ifdef EVENT_TRACE",
+	"	if (II == -EVENT_TRACE) boq = oboq;",
+	"	#endif",
 	"	return _m;",
-	"#undef continue",
-	"}",
-
+	"	#undef continue",
+	"}",
 	"#ifdef EVENT_TRACE",
 	"void",
 	"require(char tp, int qid)",
@@ -1417,67 +2140,65 @@
 	"",
 	"	if (now._event != endevent)",
 	"	for (t = trans[EVENT_TRACE][now._event]; t; t = t->nxt)",
-	"	{	if (do_transit(t, EVENT_TRACE))",
+	"	{	if (do_transit(t, -EVENT_TRACE))",
 	"		{	now._event = t->st;",
 	"			reached[EVENT_TRACE][t->st] = 1;",
-	"#ifdef VERBOSE",
+	"	#ifdef VERBOSE",
 	"	printf(\"	event_trace move to -> %%d\\n\", t->st);",
-	"#endif",
-	"#ifndef BFS",
-		"#ifndef NP",
+	"	#endif",
+	"	#ifndef BFS",
+		"	#ifndef NP",
 	"			if (accpstate[EVENT_TRACE][now._event])",
 	"				(trpt+1)->o_pm |= 2;",
-		"#else",
+		"	#else",
 	"			if (progstate[EVENT_TRACE][now._event])",
 	"				(trpt+1)->o_pm |= 4;",
-		"#endif",
-	"#endif",
-	"#ifdef NEGATED_TRACE",
+		"	#endif",
+	"	#endif",
+	"	#ifdef NEGATED_TRACE",
 	"			if (now._event == endevent)",
 	"			{",
-		"#ifndef BFS",
+		"	#ifndef BFS",
 	"				depth++; trpt++;",
-		"#endif",
+		"	#endif",
 	"				uerror(\"event_trace error (all events matched)\");",
-		"#ifndef BFS",
+		"	#ifndef BFS",
 	"				trpt--; depth--;",
-		"#endif",
-	"				break;",
-	"			}",
-	"#endif",
+		"	#endif",
+	"				break;",
+	"			}",
+	"	#endif",
 	"			for (t = t->nxt; t; t = t->nxt)",
-	"			{	if (do_transit(t, EVENT_TRACE))",
+	"			{	if (do_transit(t, -EVENT_TRACE))",
 	"				 Uerror(\"non-determinism in event-trace\");",
 	"			}",
 	"			return;",
 	"		}",
-	"#ifdef VERBOSE",
+	"	#ifdef VERBOSE",
 	"		 else",
 	"	printf(\"	event_trace miss '%%c' -- %%d, %%d, %%d\\n\",",
 	"			tp, qid, now._event, t->forw);",
-	"#endif",
-	"	}",
-	"#ifdef NEGATED_TRACE",
+	"	#endif",
+	"	}",
+	"	#ifdef NEGATED_TRACE",
 	"	now._event = endevent; /* only 1st try will count -- fixed 4.2.6 */",
-	"#else",	
-		"#ifndef BFS",
+	"	#else",	
+	"		#ifndef BFS",
 	"	depth++; trpt++;",
-		"#endif",
+	"		#endif",
 	"	uerror(\"event_trace error (no matching event)\");",
-		"#ifndef BFS",
+	"		#ifndef BFS",
 	"	trpt--; depth--;",
-		"#endif",
-	"#endif",
-	"}",
-	"#endif",
-
+	"		#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",
+	"",
+	"	pid += BASE;",
 	"	if (pid == iam)",
 	"		Uerror(\"used: enabled(pid=thisproc)\");",
 	"	if (pid < 0 || pid >= (int) now._nr_pr)",
@@ -1496,21 +2217,132 @@
 	"	return res;",
 	"}",
 	"#endif",
+	"",
+	"#ifdef HAS_PRIORITY",
+	"int",
+	"highest_priority(int pid, short nII, Trans *t)",
+	"{	int i = pid; uchar *othis = this;",
+	"",
+	"#ifdef VERI",
+	"	if (nII == 0)",
+	"	{	return 1;", /* never claim */
+	"	}",
+	"#endif",
+	"#ifdef HAS_PROVIDED",
+	"	i = pid+BASE;",	 /* uncorrected process number */
+	"#endif",
+	"	if (i < 0",
+	"	||  i >= (int) now._nr_pr",
+	"#ifdef HAS_PROVIDED",
+	"	|| !provided(i, (uchar) ((P0 *)this)->_t, (int) ((P0 *)this)->_p, t)",
+	"#endif",
+	"	)",
+	"	{	return 0;",
+	"	}",
+	"",
+	"	for (i = BASE; i < now._nr_pr; i++)",	/* all except never, if present */
+	"	{	this = pptr(i);",
+	"		if (i != pid+BASE",
+	"		&&  ((P0 *)this)->_priority > ((P0 *)pptr(pid+BASE))->_priority",
+	"#ifdef HAS_PROVIDED",
+	"		&&  provided(i, (uchar) ((P0 *)this)->_t, (int) ((P0 *)this)->_p, 0)",
+	"#endif",
+	"		&&  enabled(i+1, i-BASE))", /* enabled adds back BASE in 2nd arg */
+	"		{	this = othis;",
+	"			return 0;",
+	"	}	}",
+	"	this = othis;",
+	"	return 1;",
+	"}",
+	"int",
+	"get_priority(int pid)",
+	"{	pid += BASE;	/* 6.2.7 */",
+	"	if (pid < 0 || pid >= (int) now._nr_pr)",
+	"		return 0;",
+	"	return ((P0 *)pptr(pid))->_priority;",
+	"}",
+	"int",
+	"set_priority(int pid, int pr)",
+	"{	pid += BASE;	/* 6.2.7 */",
+	"	if (pid < 0 || pid >= (int) now._nr_pr)",
+	"	{",
+	"	#ifdef VERBOSE",
+	"		printf(\"warning: bad pid %%d, no such process (set_priority)\\n\", pid);",
+	"	#endif",
+	"		return 1;",
+	"	}",
+	"	if (pr < 1 || pr > 255)",
+	"	{	Uerror(\"priority is out of range\");",
+	"	}",
+
+	"	if (!TstOnly)",
+	"	{	(trpt+1)->o_priority = ",
+	"		(((P0 *)pptr(pid))->_priority & 255) | (pid << 8);",
+	"		((P0 *)pptr(pid))->_priority = pr;",
+	"	}",
+
+	"	return 1;", /* always executable */
+	"}",
+	"#endif",
+	"",
+	"void",
+	"snap_time(void)",
+	"{	clock_t stop_time;",
+	"	double delta_time;",
+	"#if !defined(WIN32) && !defined(WIN64)",
+	"	struct tms stop_tm;",
+	"	stop_time  = times(&stop_tm);",
+	"	delta_time = ((double) (stop_time - start_time)) / ((double) sysconf(_SC_CLK_TCK));",
+	"#else",
+	"	stop_time  = clock();",
+	"	delta_time = ((double) (stop_time - start_time)) / ((double) CLOCKS_PER_SEC);",
+	"#endif",
+	"	if (delta_time > 0.01)",
+	"	{	printf(\"t= %%8.3g \", delta_time);",
+	"		printf(\"R= %%7.0g\", nstates/delta_time);",
+	"	}",
+	"	printf(\"\\n\");",
+	"	if (quota > 0.1 && delta_time > quota)",
+	"	{	printf(\"Time limit of %%6.3g minutes exceeded\\n\", quota/60.0);",
+	"#if NCORE>1",
+	"		fflush(stdout);",
+	"		leave_critical(GLOBAL_LOCK);",
+	"		sudden_stop(\"time-limit\");",
+	"		exit(1);",
+	"#endif",
+	"		wrapup();",
+	"	}",
+	"}",
 	"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 BFS_PAR",
+	"	e_critical(BFS_GLOB);		/* bfs_par / snapshot */",
+	"	printf(\"cpu%%d: \", who_am_i);",
+	"#endif",
+	"#if NCORE>1",
+	"	enter_critical(GLOBAL_LOCK);	/* ncore / snapshot */",
+	"	printf(\"cpu%%d: \", core_id);",
+	"#endif",
+	"	printf(\"Depth= %%7ld States= %%8.3g \",",
+	"#if NCORE>1",
+	"		(long) (nr_handoffs * z_handoff) +",
+	"#endif",
+	"		mreached, nstates);",
+	"	printf(\"Transitions= %%8.3g \", nstates+truncs);",
 	"#ifdef MA",
-	"	printf(\"Nodes= %%7d \", nr_states);",
-	"#endif",
-	"	printf(\"Memory= %%-6.3f\\n\", memcnt/1000000.);",
+	"	printf(\"Nodes= %%7lu \", nr_states);",
+	"#endif",
+	"	printf(\"Memory= %%9.3f\\t\", memcnt/1048576.);",
+	"	snap_time();",
 	"	fflush(stdout);",
-	"}",
-
+	"#if NCORE>1",
+	"	leave_critical(GLOBAL_LOCK);",
+	"#endif",
+	"#ifdef BFS_PAR",
+	"	x_critical(BFS_GLOB);",
+	"#endif",
+	"}",
 	"#ifdef SC",
 	"void",
 	"stack2disk(void)",
@@ -1552,46 +2384,246 @@
 	"#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 */
+	"Pptr(int x)",
+	"{	if (x < 0 || x >= MAXPROC",	/* does not exist */
+	"#ifdef TRIX",
+	"	|| !processes[x])",
+	"#else",
+	"	|| !proc_offset[x])",
+	"#endif",
 	"		return noptr;",
 	"	else",
 	"		return (uchar *) pptr(x);",
-	"}",
+	"}\n",
+	"uchar *",
+	"Qptr(int x)",
+	"{	if (x < 0 || x >= MAXQ",
+	"#ifdef TRIX",
+	"	|| !channels[x])",
+	"#else",
+	"	|| !q_offset[x])",
+	"#endif",
+	"		return noqptr;",
+	"	else",
+	"		return (uchar *) qptr(x);",
+	"}\n",
+	"",
+	"#if NCLAIMS>1",
+	"void",
+	"select_claim(int n)",
+	"{	int m, i;",
+	"	if (n < 0 || n >= NCLAIMS)",
+	"	{	uerror(\"non-existing claim\");",
+	"	} else",
+	"	{	m = ((Pclaim *)pptr(0))->_n;",
+	"		if (verbose)",
+	"		{	printf(\"%%d: Claim %%s (%%d), from state %%d\\n\",",
+	"				(int) depth, procname[spin_c_typ[n]],",
+	"				n, ((Pclaim *)pptr(0))->c_cur[n]);",
+	"		} else",
+	"		{	printf(\"pan: ltl formula %%s\\n\",",
+	"				procname[spin_c_typ[n]]);",
+	"		}",
+	"		((Pclaim *)pptr(0))->c_cur[m] = ((Pclaim *)pptr(0))->_p;",
+	"		((Pclaim *)pptr(0))->_t = spin_c_typ[n];",
+	"		((Pclaim *)pptr(0))->_p = ((Pclaim *)pptr(0))->c_cur[n];",
+	"		((Pclaim *)pptr(0))->_n = n;",
+	"		for (i = 0; src_all[i].src != (short *) 0; i++)",
+	"		{	if (src_all[i].tp == spin_c_typ[n])",
+	"			{	src_claim = src_all[i].src;",
+	"				break;",
+	"		}	}", 
+	"		if (src_all[i].src == (short *) 0)",
+	"		{	uerror(\"cannot happen: src_ln ref\");",
+	"	}	}",
+	"}",
+	"#else",
+	"void",
+	"select_claim(int n)",
+	"{	if (n != 0) uerror(\"non-existing claim\");",
+	"}",
+	"#endif",
+
 	"int qs_empty(void);",
-
+	"#if !defined(BFS) && (!defined(BITSTATE) || !defined(MA))",
+	"#ifdef NSUCC",
+	"int N_succ[512];",
+	"void",
+	"tally_succ(int cnt)",
+	"{	if (cnt < 512) N_succ[cnt]++;",
+	"	else printf(\"tally_succ: cnt %%d exceeds range\\n\", cnt);",
+	"}",
+	"",
+	"void",
+	"dump_succ(void)",
+	"{	int i; double sum = 0.0;",
+	"	double w_avg = 0.0;",
+	"	printf(\"Successor counts:\\n\");",
+	"	for (i = 0; i < 512; i++)",
+	"	{	sum += (double) N_succ[i];",
+	"	}",
+	"	for (i = 0; i < 512; i++)",
+	"	{	if (N_succ[i] > 0)",
+	"		{	printf(\"%%3d\t%%10d\t(%%.4g %%%% of total)\\n\",",
+	"				i, N_succ[i], (100.0 * (double) N_succ[i])/sum);",
+	"			w_avg += (double) i * (double) N_succ[i];",
+	"	}	}",
+	"	if (sum > N_succ[0])",
+	"	printf(\"mean %%.4g (without 0: %%.4g)\\n\", w_avg / sum, w_avg / (sum - (double) N_succ[0]));",
+	"}",
+	"#endif",
+	"",
+	"#ifdef P_REVERSE",
+	"	#define FROM_P	(BASE)",
+	"	#define UPTO_P	(now._nr_pr-1)",
+	"	#define MORE_P	(II <= To)",		/* p.o. only */
+	"	#define INI_P	(From-1)",		/* fairness only */
+	"	#define CNT_P	(1 + (To - From))",	/* P_RAND start */
+	"	#define NDONE_P	(From <= To)",		/* P_RAND continue */
+	"	#define ALL_P	(II = From; II <= To; II++)",
+	"#else",
+	"	#define FROM_P	(now._nr_pr-1)",
+	"	#define UPTO_P	(BASE)",
+	"	#define MORE_P	(II >= BASE)",
+	"	#define INI_P	(From+1)",
+	"	#define CNT_P	(1 + (From - To))",
+	"	#define NDONE_P	(From >= To)",
+	"	#define ALL_P	(II = From; II >= To; II--)",
+	"#endif",
+	"",
+	"#ifdef PERMUTED",
+	"	#define CONTINUE0 { if (reversing&2) { II = oII; } continue; }",
+	"	#define CONTINUE  { if (reversing&2) { p_reorder(seed); II = oII; } continue; }",
+	"#else",
+	"	#define CONTINUE0 { continue; }",
+	"	#define CONTINUE  { continue; }",
+	"#endif",
+
+	"#ifdef PERMUTED",
+	"uchar _permutation_[256];",
+	"void",
+	"set_reversed(int unused)",
+	"{	int i, n = now._nr_pr;",
+	"  #ifdef VERBOSE",
+	"	printf(\"%%ld: Set_reversed\\n\", depth);",
+	"  #endif",
+	"  #if defined(VERI) && !defined(NOCLAIM)",
+	"	for (i = 1; i < n; i++)",
+	"	{	_permutation_[i] = n-i;",
+	"	}",
+	"  #else",
+	"	for (i = 0; i < n; i++)",
+	"	{	_permutation_[i] = n-1-i;",
+	"	}",
+	"  #endif",
+	"}",
+	"void",
+	"set_rotated(int unused)",
+	"{	int i, n = now._nr_pr;",
+	"  #ifdef VERBOSE",
+	"	printf(\"%%ld: Set_rotated %%d\\n\", depth, p_rotate);",
+	"  #endif",
+	"  #if defined(VERI) && !defined(NOCLAIM)",
+	"	for (i = 1; i < n; i++)",
+	"	{	_permutation_[i] = 1+(i-1+p_rotate)%%(n-1);",
+	"	}",
+	"  #else",
+	"	for (i = 0; i < n; i++)",
+	"	{	_permutation_[i] = (i+p_rotate)%%n;",
+	"	}",
+	"  #endif",
+	"}",
+	"void",
+	"set_randrot(int unused)",
+	"{",
+	"	if (now._nr_pr > 1)",
+	"	{	p_rotate = 1+rand()%%(now._nr_pr-1);",
+	"	} else",
+	"	{	p_rotate = 0;",
+	"	}",
+	"	set_rotated(0);",
+	"}",
+	"void",
+	"set_permuted(int T)",
+	"{	/* permute nrs 1..n-1, leave 0 in place */",
+	"	int i, j, k, n = now._nr_pr;",
+	"	char tmp, *in = &(_permutation_[0]);",
+	"  #ifdef VERBOSE",
+	"	printf(\"%%ld: Set_permuted %%d\\n\", depth, T);",
+	"  #endif",
+	"	srand(T);",	/* set_permuted */
+	"	for (i = 0; i < n; i++)",
+	"	{	in[i] = i;",
+	"	}",
+	"	if (n > 1)",
+	"	{  for (i = 0; i < n; i++)",
+	"	   {",
+	"  #if defined(VERI) && !defined(NOCLAIM)",
+	"		j = 1 + rand()%%(n-1);",
+	"		k = 1 + rand()%%(n-1);",
+	"  #else",
+	"		j = rand()%%(n);",
+	"		k = rand()%%(n);",
+	"  #endif",
+	"		tmp   = in[j];",
+	"		in[j] = in[k];",
+	"		in[k] = tmp;",
+	"	}  }",
+	"}",
+	"",
+	"  #ifdef VERBOSE",
+	"	short",
+	"	get_permuted(int x)",
+	"	{	printf(\"%%ld: Get_permuted %%d -> %%d\\n\",",
+	"			depth, x, _permutation_[x]);",
+	"		return (short) _permutation_[x];",
+	"	}",
+	"  #else",
+	"	#define get_permuted(x)  (short) _permutation_[x]",
+	"  #endif",
+	"",
+	"#endif",
 	"/*",
 	" * 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",
+	" * if you are studying the code, 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",
+	" * and then study the resulting file, instead of this version",
 	" */",
-	"#if !defined(BFS) && (!defined(BITSTATE) || !defined(MA))",
+	"",
 	"void",
 	"new_state(void)",
 	"{	Trans *t;",
 	"	uchar _n, _m, ot;",
-	"#ifdef RANDOMIZE",
+	"#ifdef T_RAND",
 	"	short ooi, eoi;",
 	"#endif",
+	"#ifdef PERMUTED",
+	"	short oII; uint seed;",
+	"#endif",
 	"#ifdef M_LOSS",
 	"	uchar delta_m = 0;",
 	"#endif",
 	"	short II, JJ = 0, kk;",
 	"	int tt;",
-	"	short From = now._nr_pr-1, To = BASE;",
+	"	short From = FROM_P, To = UPTO_P;",
+	"#ifdef BCS",
+	"	trpt->sched_limit = 0; /* at depth=0 only */",
+	"#endif",
 	"Down:",
 	"#ifdef CHECK",
-	"	printf(\"%%d: Down - %%s\",",
-	"		depth, (trpt->tau&4)?\"claim\":\"program\");",
-	"	printf(\" %%saccepting [pids %%d-%%d]\\n\",",
+	"	cpu_printf(\"%%d: Down - %%s %%saccepting [pids %%d-%%d]\\n\",",
+	"		depth, (trpt->tau&4)?\"claim\":\"program\",",
 	"		(trpt->o_pm&2)?\"\":\"non-\", From, To);",
 	"#endif",
 
+	"#ifdef P_RAND",
+	"	trpt->p_skip = -1;",
+	"#endif",
+
 	"#ifdef SC",
 	"	if (depth > hiwater)",
 	"	{	stack2disk();",
@@ -1599,7 +2631,7 @@
 	"		hiwater += DDD;",
 	"		trpt -= DDD;",
 	"		if(verbose)",
-	"		printf(\"zap %%d: %%d (maxdepth now %%d)\\n\",",
+	"		printf(\"zap %%ld: %%ld (maxdepth now %%ld)\\n\",",
 	"			CNT1, hiwater, maxdepth);",
 	"	}",
 	"#endif",
@@ -1608,126 +2640,233 @@
 	"#if defined(FULLSTACK) && defined(MA)",
 	"	trpt->proviso = 0;",
 	"#endif",
+	"#ifdef NSUCC",
+	"	trpt->n_succ = 0;",
+	"#endif",
+	"#if NCORE>1",
+	"	if (mem_hand_off())",
+	"	{",
+	"#if SYNC",
+	"		(trpt+1)->o_n = 1;	/* not a deadlock: as below  */",
+	"#endif",
+	"#ifndef LOOPSTATE",
+	"		(trpt-1)->tau |= 16;	/* worstcase guess: as below */",
+	"#endif",
+	"#if NCORE>1 && defined(FULL_TRAIL)",
+	"		if (upto > 0)",
+	"		{	Pop_Stack_Tree();",
+	"		}",
+	"#endif",
+	"		goto Up;",
+	"	}",
+	"#endif",
+
 	"	if (depth >= maxdepth)",
-	"	{	truncs++;",
+	"	{	if (!warned)",
+	"		{ warned = 1;",
+	"		  printf(\"error: max search depth too small\\n\");",
+	"		}",
+	"		if (bounded)",
+	"		{	uerror(\"depth limit reached\");",
+	"		}",
+	"		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 */",
+	"#ifndef LOOPSTATE",
+	"		(trpt-1)->tau |= 16;	/* worstcase guess */",
+	"#endif",
+
+	"#if NCORE>1 && defined(FULL_TRAIL)",
+	"		if (upto > 0)",
+	"		{	Pop_Stack_Tree();",
+	"		}",
+	"#endif",
 	"		goto Up;",
 	"	}",
 	"AllOver:",
-	"#if defined(FULLSTACK) && !defined(MA)",
+	"#if (defined(FULLSTACK) && !defined(MA)) || NCORE>1",
 	"	/* if atomic or rv move, carry forward previous state */",
-	"	trpt->ostate = (trpt-1)->ostate;",	/* was: = (struct H_el *) 0;*/
+	"	trpt->ostate = (trpt-1)->ostate;",
 	"#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 0
+	we want to skip nrpr, nrqs, _a_t and cnt[NFAIR] (in the case of fairness)
+	this is calculated in S_A, but S_A subtracts 2 bytes,
+	because nrpr and nrqs are masked in the default state comparisons
+	so we add those two bytes back here
+	-- in default comparisons (h_store) we skip _a_t and cnt in the
+	-- first comparison to find a match on the base-state
+	-- the _a_t and cnt fields are then separately updated if there was
+	-- a match on the base state
+#endif
 	"		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",
+	"		{	int delta = S_A + 2;",
+	"			if (!memcmp((char *)&A_Root + delta, ",
+	"				(char *)&now + delta, vsize - delta))",
+	"			{",
+	"#ifndef NOFAIR",
+	"			   if (fairness && now._cnt[1] != 1) /* was > 1 */",
+	"			   {",
+	"	#ifdef CHECK",
+	"				printf(\"\tfairness count non-zero\\n\");",
+	"	#endif",
+	"				/* treat as new state */",
+	"			   } else",
+	"#endif",
+	"			   {	depthfound = A_depth;",
+	"	#ifdef CHECK",
+	"				printf(\"matches seed\\n\");",
+	"	#endif",
+	"	#ifdef NP",
+	"				uerror(\"non-progress cycle\");",
+	"	#else",
+	"				uerror(\"acceptance cycle\");",
+	"	#endif",
+	"	#if NCORE>1 && defined(FULL_TRAIL)",
+	"				if (upto > 0)",
+	"				{	Pop_Stack_Tree();",
+	"				}",
+	"	#endif",
+	"				goto Up;",
+	"			}  }",
+	"	#ifdef CHECK",
+	"			else",
+	"			{",
+	"			   printf(\"not seed\\n\");",
+	"			}",
+	"	#endif",
 	"		}",
 	"#endif",
 	"		if (!(trpt->tau&8)) /* if no atomic move */",
 	"		{",
+	"#if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)",
+	"			uchar was_last = now._last;",
+	"			now._last = 0;	/* value not stored */",
+	"#endif",
 	"#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 */
+	"		#if defined(BCS) && defined(STORE_CTX)",
+	"		{ int xj;",
+	"			for (xj = trpt->sched_limit; xj <= sched_max; xj++)",
+	"			{	now._ctx = xj;",
+	"				II = b_store((char *)&now, vsize);",
+	"				trpt->j6 = j1_spin; trpt->j7 = j2_spin;",
+	"				JJ = LL[j1_spin] && LL[j2_spin];",
+	"				if (II != 0) { break; }",
+	"			}",
+	"			now._ctx = 0; /* just in case */",
+	"		}",
+	"		#else",
+	"			II = b_store((char *)&now, vsize);",
+	"			trpt->j6 = j1_spin; trpt->j7 = j2_spin;",
+	"			JJ = LL[j1_spin] && LL[j2_spin];",
+	"		#endif",
+		"#else",
+	"		#ifdef FULLSTACK", /* b_store after onstack_now, to preserve j1-j4 */
+	"		   #if defined(BCS) && defined(STORE_CTX)",
+	"		   { int xj;",
+	"			now._ctx = 0;",
+	"			JJ = onstack_now();",		    /* mangles j1 */
+	"			for (xj = trpt->sched_limit; xj <= sched_max; xj++)",
+	"			{	now._ctx = xj;",
+	"				II = b_store((char *)&now, vsize);", /* sets j1-j4 */
+	"				if (II != 0) { break; }",
+	"			}",
+	"			now._ctx = 0;",
+	"		   }",
+	"		   #else",
+	"			JJ = onstack_now();",		    /* mangles j1 */
+	"			II = b_store((char *)&now, vsize);", /* sets j1-j4 */
+	"		   #endif",
+	"		#else",
+	"		   #if defined(BCS) && defined(STORE_CTX)",
+	"		   { int xj;",
+	"			for (xj = trpt->sched_limit; xj <= sched_max; xj++)",
+	"			{	now._ctx = xj;",
+	"				II = b_store((char *)&now, vsize);", /* sets j1-j4 */
+	"				JJ = II; /* worstcase guess for p.o. - order corrected in 5.2.1 */",
+	"				if (II != 0) { break; }",
+	"			}",
+	"			now._ctx = 0;",
+	"		   }",
+	"		   #else",
+	"			II = b_store((char *)&now, vsize);", /* sets j1-j4 */
+	"			JJ = II; /* worstcase guess for p.o. - order corrected in 5.2.1 */",
+	"		   #endif",
+	"		#endif",
 		"#endif",
 	"#else",
 		"#ifdef MA",
-	"			II = gstore((char *)&now, vsize, 0);",
+	"			II = g_store((char *)&now, vsize, 0);",
 			"#ifndef FULLSTACK",
 	"			JJ = II;",
 			"#else",
 	"			JJ = (II == 2)?1:0;",
 			"#endif",
 		"#else",
-	"			II = hstore((char *)&now, vsize);",
+	"			II = h_store((char *)&now, vsize);",
+	"			/* @hash j1_spin II */",
 			"#ifdef FULLSTACK",
 	"			JJ = (II == 2)?1:0;",
 			"#endif",
 		"#endif",
 	"#endif",
 	"			kk = (II == 1 || II == 2);",
+	/* actually, BCS implies HAS_LAST */
+	"#if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)",
+	"			now._last = was_last;	/* restore value */",
+	"#endif",
+
 				/* 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)",
+		/* with multicore we don't know which stack its on */
+		/* with HC there's a small chance of a false match - example fifoq 2012 */
+		"#if !defined(HC) && (NCORE==1 || defined (SEP_STATE))",
 	"			if (II == 2 && ((trpt->o_pm&2) || ((trpt-1)->o_pm&2)))",
-	"			{	II = 3; /* Schwoon & Esparza 2005, Gastin&Moro 2004 */",
-		"#ifdef VERBOSE",
+	"		#ifndef NOFAIR",
+	"			if (a_cycles && !fairness) /* 5.1.6 -- example by Hirofumi Watanabe */",
+	"		#endif",
+	"			if (depth > A_depth) /* forum example by adl */",
+	"			{",
+	"				II = 3; /* Schwoon & Esparza 2005, Gastin&Moro 2004 */",
+			"#ifdef VERBOSE",
 	"				printf(\"state match on dfs stack\\n\");",
-		"#endif",
+			"#endif",
 	"				goto same_case;",
 	"			}",
-
+		"#endif",
 
 		"#if defined(FULLSTACK) && defined(BITSTATE)",
 	"			if (!JJ && (now._a_t&1) && depth > A_depth)",
-	"			{	int oj1 = j1;",
+	"			{	int oj1 = j1_spin;",
 	"				uchar o_a_t = now._a_t;",
 	"				now._a_t &= ~(1|16|32);", /* 1st stack  */
-	"				if (onstack_now())",	  /* changes j1 */
+	"				if (onstack_now())",	  /* changes j1_spin */
 	"				{	II = 3;",
 		"#ifdef VERBOSE",
 	"					printf(\"state match on 1st dfs stack\\n\");",
 		"#endif",
 	"				}",
 	"				now._a_t = o_a_t;",	/* restore */
-	"				j1 = oj1;",
+	"				j1_spin = oj1;",
 	"			}",
 		"#endif",
 	"			if (II == 3 && a_cycles && (now._a_t&1))",
 	"			{",
 		"#ifndef NOFAIR",
-	"			   if (fairness && now._cnt[1] > 1)	/* was != 0 */",
+	"			   if (fairness && now._cnt[1] != 1)	/* was > 1 */",
 	"			   {",
-		"#ifdef VERBOSE",
+		"	#ifdef CHECK",
 	"				printf(\"\tfairness count non-zero\\n\");",
-		"#endif",
+		"	#endif",
 	"				II = 0;", /* treat as new state */
 	"			   } else",
 		"#endif",
@@ -1741,47 +2880,114 @@
 		"#else",
 	"				uerror(\"acceptance cycle\");",
 		"#endif",
+	"#if NCORE>1 && defined(FULL_TRAIL)",
+	"				if (upto > 0)",
+	"				{	Pop_Stack_Tree();",
+	"				}",
+	"#endif",
 	"				goto Up;",
 	"			   }",
 	"			}",
 	"#endif",
 
 	"#ifndef NOREDUCE",
-		"#ifndef SAFETY",
+	"	#ifndef SAFETY",
+	"		#if NCORE>1 && !defined(SEP_STATE) && defined(V_PROVISO)",
+	"			if (II != 0 && (!Lstate || Lstate->cpu_id < core_id))",
+	"			{	(trpt-1)->tau |= 16;",	/* treat as a stack state */
+	"			}",
+	"		#endif",
 	"			if ((II && JJ) || (II == 3))",
 	"			{	/* marker for liveness proviso */",
+	"		#ifndef LOOPSTATE",
+	"				(trpt-1)->tau |= 16;",	/* truncated on stack */
+	"		#endif",
+	"				truncs2++;",
+	"			}",
+		"#else",
+	"		#if NCORE>1 && !defined(SEP_STATE) && defined(V_PROVISO)",
+	"			if (!(II != 0 && (!Lstate || Lstate->cpu_id < core_id)))",
+	"			{	/* treat as stack state */",
 	"				(trpt-1)->tau |= 16;",
-	"				truncs2++;",
-	"			}",
-		"#else",
+	"			} else",
+	"			{	/* treat as non-stack state */",
+	"				(trpt-1)->tau |= 64;",
+	"			}",
+	"		#endif",
 	"			if (!II || !JJ)",
 	"			{	/* successor outside stack */",
 	"				(trpt-1)->tau |= 64;",
 	"			}",
-		"#endif",
+	"	#endif",
+	"#endif",
+	"#if defined(BCS) && (defined(NOREDUCE) || !defined(SAFETY))",
+	/* needed for BCS - cover cases where it would not otherwise be set */
+	"			if (!II || !JJ)",
+	"			{	(trpt-1)->tau |= 64;",
+	"			}",
 	"#endif",
 	"			if (II)",
 	"			{	truncs++;",
+	"#if NCORE>1 && defined(FULL_TRAIL)",
+	"				if (upto > 0)",
+	"				{	Pop_Stack_Tree();",
+	"					if (depth == 0)",
+	"					{	return;",
+	"				}	}",
+	"#endif",
 	"				goto Up;",
 	"			}",
 	"			if (!kk)",
-	"			{	nstates++;",
-	"				if ((unsigned long) nstates%%1000000 == 0)",
-	"					snapshot();",
+	"			{	static long sdone = (long) 0; long ndone;",
+	"				nstates++;",
+	"#if defined(ZAPH) && defined(BITSTATE)",
+	"				zstates += (double) hfns;",
+	"#endif",
+	"				ndone = (ulong) (nstates/(freq));",
+	"				if (ndone != sdone)",
+	"				{	snapshot();",
+	"					sdone = ndone;",
+	"#if defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(MA)",
+	"					if (nstates > ((double)(ONE_L<<(ssize+1))))",
+	"					{	void resize_hashtable(void);",
+	"						resize_hashtable();",
+	"					}",
+	"#endif",
+	"#if defined(ZAPH) && defined(BITSTATE)",
+	"					if (zstates > ((double)(ONE_L<<(ssize-2))))",
+	"					{	/* more than half the bits set */",
+	"						void zap_hashtable(void);",
+	"						zap_hashtable();",
+	"						zstates = 0;",
+	"					}",
+	"#endif",
+	"				}",
 	"#ifdef SVDUMP",
 	"				if (vprefix > 0)",
+	"	#ifdef SHO",	/* Store Hash Only */
+	"			/* always use the same hashfunction, for consistency across runs */",
+	"				if (HASH_NR != 0)",
+	"				{	int oh = HASH_NR;",
+	"					HASH_NR = 0;",
+	"					d_hash((uchar *) &now, vsize); /* SHO - set K1 */",
+	"					HASH_NR = oh;",
+	"				}",
+	"				if (write(svfd, (uchar *) &K1, sizeof(ulong)) != sizeof(ulong))",
+	"	#else",
 	"				if (write(svfd, (uchar *) &now, vprefix) != vprefix)",
-	"				{	fprintf(efd, \"writing %%s.svd failed\\n\", Source);",
+	"	#endif",
+	"				{	fprintf(efd, \"writing %%s.svd failed\\n\", PanSource);",
 	"					wrapup();",
 	"				}",
 	"#endif",
 	"#if defined(MA) && defined(W_XPT)",
-	"				if ((unsigned long) nstates%%W_XPT == 0)",
+	"				if ((ulong) nstates%%W_XPT == 0)",
 	"				{	void w_xpoint(void);",
 	"					w_xpoint();",
 	"				}",
 	"#endif",
 	"			}",
+
 	"#if defined(FULLSTACK) || defined(CNTRSTACK)",
 	"			onstack_put();",
 		"#ifdef DEBUG2",
@@ -1793,9 +2999,12 @@
 	"			printf(\"%%d: putting\\n\", depth);",
 		"#endif",
 		"#endif",
-	"#endif",
-	"	}	}",
-
+	"#else",
+	"	#if NCORE>1",
+	"			trpt->ostate = Lstate;",
+	"	#endif",
+	"#endif",
+	"	}	}",
 
 	"	if (depth > mreached)",
 	"		mreached = depth;",
@@ -1809,40 +3018,56 @@
 	"#endif",
 	"#ifdef VERI",
 	"	if (now._nr_pr == 0)	/* claim terminated */",
-	"		uerror(\"end state in claim reached\");",
-	"	check_claim(((P0 *)pptr(0))->_p);",
+	"	{	uerror(\"end state in claim reached\");",
+	"	}",
+	"	if (stopstate[((Pclaim *)pptr(0))->_t][((Pclaim *)pptr(0))->_p])",
+	"	{	uerror(\"end state in claim reached\");",
+	"	}",
 	"Stutter:",
 	"	if (trpt->tau&4)	/* must make a claimmove */",
 	"	{",
-
-	"#ifndef NOFAIR",
+	"	#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",
+			"#ifdef DEBUG",
 	"	printf(\"%%3d: fairness Rule 3.: _a_t = %%d\\n\",",
-	"		depth, now._a_t);",
-		"#endif",
-	"		}",
-	"#endif",
-
+	"		(int) depth, now._a_t);",
+			"#endif",
+	"		}",
+	"	#endif",
 	"		II = 0;		/* never */",
 	"		goto Veri0;",
 	"	}",
 	"#endif",
+	"#ifdef PERMUTED",
+	"	if (reversing&2)",
+	"	{	seed = rand();",
+	"		p_reorder(seed);",
+	"	}",
+	"#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",
+	"",
+	"#ifdef SAFETY",
+	" #if NCORE>1",
+	"	&& (depth < z_handoff)", /* not for border states */
+	" #endif",
+	"	)",
+	"#else",
+	" #if NCORE>1",
+	"	&& ((a_cycles) || (!a_cycles && depth < z_handoff))",
+	" #endif",
+	" #ifdef BCS",
+	"	&& (sched_max > 0 || depth > BASE)", /* no po in initial state if -L0 */
+	" #endif",
 	"	&&  (!(now._a_t&1)",
 	"	    ||	(a_cycles &&",
-	"#ifndef BITSTATE",
+	" #ifndef BITSTATE",
 		"#ifdef MA",
 			"#ifdef VERI",
 	"		 !((trpt-1)->proviso))",
@@ -1852,63 +3077,58 @@
 		"#else",
 			"#ifdef VERI",
 	"		 (trpt-1)->ostate &&",
-	"		!(((char *)&((trpt-1)->ostate->state))[0] & 128))",
+	"		!(((char *)&((trpt-1)->ostate->state))[0] & 128))", /* proviso bit in _a_t */
 			"#else",
 	"		!(((char *)&(trpt->ostate->state))[0] & 128))",
 			"#endif",
 		"#endif",
-	"#else",
+	" #else",
 		"#ifdef VERI",
 	"		(trpt-1)->ostate &&",
 	"		(trpt-1)->ostate->proviso == 0)",
 		"#else",
 	"		trpt->ostate->proviso == 0)",
 		"#endif",
-	"#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;",
+	"#endif", /* SAFETY */
+	"	/* attempt Partial Order Reduction as preselect moves */",
+	"#ifdef BCS",
+	"	if (trpt->sched_limit < sched_max)",	/* po only if we can switch */
+	"#endif",
+	"	{	for ALL_P {",	/* PO preselect */
+	"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; /* preselect process */",
 	"#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;",
-	"		}",
-	"	}",
+	"				t->om = 0;",
+	"#endif",
+	"				trpt->tau |= 32; /* preselect marker */",
+	"#ifdef DEBUG",
+	"				printf(\"%%3ld: proc %%d PreSelected (tau=%%d)\\n\", ",
+	"					depth, II, trpt->tau);",
+	"#endif",
+	"				goto Again;",
+	"			} else",
+	"			{	continue;",
+	"	}	}	}",
 	"	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 */",
-
+	"	trpt->o_pm &= ~(8|16|32|64); /* clear fairness-marks */",
 	"#ifndef NOFAIR",
 	"	if (fairness && boq == -1",
 		"#ifdef VERI",
@@ -1917,36 +3137,136 @@
 	"	&& !(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))",
+	"		{	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 */
+	"				now._cnt[now._a_t&1] = now._nr_pr + 1;",
 	"				trpt->o_pm |= 8;",
 		"#ifdef DEBUG",
-	"	printf(\"%%3d: fairness Rule 1: cnt=%%d, _a_t=%%d\\n\",",
+	"	printf(\"%%3ld: 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 */
+	"			if (now._cnt[now._a_t&1] == 1)",
+	"			{	now._a_t &= ~2;",	/* reset a-bit */
+	"				now._cnt[now._a_t&1] = 0;",
 	"				trpt->o_pm |= 16;",
 		"#ifdef DEBUG",
-	"	printf(\"%%3d: fairness Rule 3: _a_t = %%d\\n\",",
+	"	printf(\"%%3ld: fairness Rule 3: _a_t = %%d\\n\",",
 	"		depth, now._a_t);",
 		"#endif",
 	"	}	}	}",
 	"#endif",
 
-	"	for (II = From; II >= To; II -= 1)",
-	"	{",
+	"#ifdef BCS",	/* bounded context switching */
+	"	trpt->bcs = trpt->b_pno = 0;	/* initial */",
+	"	if (From != To		/* not a PO or atomic move */",
+	"	&&  depth > BASE)	/* there is a prior move */",
+	"	{	trpt->b_pno = now._last + BASE;",
+	"		trpt->bcs = B_PHASE1;",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: BCS phase 1 proc %%d limit %%d\\n\",",
+	"			depth, trpt->b_pno, trpt->sched_limit);",
+	"	#endif",
+	"		/* allow only process b_pno to move in this phase */",
+	"	}",
+	"c_switch:	/* jumps here with bcs == B_PHASE2 with or wo B_FORCED added */",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: BCS c_switch phase=%%d pno=%%d [forced %%d]\\n\",",
+	"			depth, trpt->bcs, trpt->b_pno, (trpt->bcs&B_FORCED)?1:0);",
+	"	#endif",
+	"#endif",
+
+	"#ifdef P_RAND",
+	"	trpt->p_left = CNT_P;",
+	"	if (trpt->p_left > 1)",
+	"	{	trpt->p_skip = rand() %% (trpt->p_left);",
+	"	} else",
+	"	{	trpt->p_skip = -1;",
+	"	}",
+	"r_switch:",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: P_RAND r_switch p_skip=%%d p_left=%%d\\n\",",
+	"			depth, trpt->p_skip, trpt->p_left);",
+	"	#endif",
+	"#endif",
+
+	"	for ALL_P {",	/* Main Loop */
+	"#ifdef PERMUTED",
+	"		if (reversing&2)",
+	"		{	oII = II;",
+	"			if (From != To)", /* not atomic or preselected */
+	"			{	II = get_permuted(II);",
+	"		}	}",
+	"#endif",
+	"#ifdef P_RAND",
+	"		if (trpt->p_skip >= 0)",
+	"		{	trpt->p_skip--; /* skip random nr of procs */",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: P_RAND skipping %%d [new p_skip=%%d p_left=%%d]\\n\",",
+	"			depth, II, trpt->p_skip, trpt->p_left);",
+	"	#endif",
+	"			CONTINUE0;",
+	"		}",
+	"		if (trpt->p_left == 0)",
+	"		{",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: P_RAND done at %%d\\n\", depth, II);",
+	"	#endif",
+	"			break;	/* done */",
+	"		}",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: P_RAND explore %%d [p_left=%%d]\\n\",",
+	"			depth, II, trpt->p_left);",
+	"	#endif",
+	"		trpt->p_left--;",
+	"#endif",
+
 	"#if SYNC",
 	"		/* no rendezvous with same proc */",
-	"		if (boq != -1 && trpt->pr == II) continue;",
-	"#endif",
+	"		if (boq != -1 && trpt->pr == II)",
+	"		{	CONTINUE0;",
+	"		}",
+	"#endif",
+
+	"#ifdef BCS",	/* never claim with II==0 cannot get here */
+	"		if ((trpt->bcs & B_PHASE1)",
+	"		&&  trpt->b_pno != II)",
+	"		{",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: BCS NotPre II=%%d bcs=%%d pno=%%d [forced %%d]\\n\",",
+	"			depth, II, trpt->bcs, trpt->b_pno, (trpt->bcs&B_FORCED)?1:0);",
+	"	#endif",
+	"			CONTINUE0;",	/* avoid context switch */
+	"		}",
+	"	#ifdef VERBOSE",
+	"		else if ((trpt->bcs & B_PHASE1) && trpt->b_pno == II)",
+	"		printf(\"%%3ld: BCS IsPre II=%%d bcs=%%d pno=%%d [forced %%d]\\n\",",
+	"			depth, II, trpt->bcs, trpt->b_pno, (trpt->bcs&B_FORCED)?1:0);",
+	"	#endif",
+
+	"		if (trpt->bcs & B_PHASE2)	/* 2nd phase */",
+	"		{	if (trpt->b_pno == II)	/* was already done in phase 1 */",
+	"			{",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: BCS NoRepeat II=%%d bcs=%%d pno=%%d [forced %%d]\\n\",",
+	"			depth, II, trpt->bcs, trpt->b_pno, (trpt->bcs&B_FORCED)?1:0);",
+	"	#endif",
+	"				CONTINUE0;",
+	"			}",
+	"			if (!(trpt->bcs & B_FORCED)	/* unless forced */",
+	"			&&  trpt->sched_limit >= sched_max)",
+	"			{",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: BCS Bound II=%%d bcs=%%d pno=%%d [forced %%d]\\n\",",
+	"			depth, II, trpt->bcs, trpt->b_pno, (trpt->bcs&B_FORCED)?1:0);",
+	"	#endif",
+	"				CONTINUE0;	/* enforce bound */",
+	"		}	}",
+	"#endif",
+
 	"#ifdef VERI",
 	"Veri0:",
 	"#endif",
@@ -1967,8 +3287,10 @@
 	"		{	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 */",
+	"				if (_m>_n||(_n>3&&_m!=0))",
+	"				{	_n=_m;",
+	"				}",
+	"				CONTINUE0; /* did it before */",
 	"		}	}",
 	"#endif",
 	"		trpt->o_pm &=  ~1; /* no move in this pid yet */",
@@ -1990,16 +3312,26 @@
 	"				now._cnt[now._a_t&1] = 1;",
 		"#endif",
 		"#ifdef DEBUG",
-	"		printf(\"%%3d: proc %%d fairness \", depth, II);",
+	"		printf(\"%%3ld: 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",
+
+	"#ifdef HAS_PRIORITY",
+	"		if (!highest_priority(((P0 *)this)->_pid, II, t))",
+	"		{	CONTINUE0;",
+	"		}",
+	"#else",
+	"	#ifdef HAS_PROVIDED",
+	"		if (!provided(II, ot, tt, t))",
+	"		{	CONTINUE0;",
+	"		}",
+	"	#endif",
+	"#endif",
+
 	"		/* check all trans of proc II - escapes first */",
 	"#ifdef HAS_UNLESS",
 	"		trpt->e_state = 0;",
@@ -2007,27 +3339,31 @@
 	"		(trpt+1)->pr = (uchar) II;",	/* for uerror */
 	"		(trpt+1)->st = tt;",
 
-	"#ifdef RANDOMIZE",
+	"#ifdef T_RAND",
 	"		for (ooi = eoi = 0, t = trans[ot][tt]; t; t = t->nxt, ooi++)",
-	"			if (strcmp(t->tp, \"else\") == 0)",
-	"				eoi++;",
-	"",
-	"		if (eoi)",
+	"		{	if (strcmp(t->tp, \"else\") == 0",
+	"	#ifdef HAS_UNLESS",
+	"			||  t->e_trans != 0",
+	"	#endif",
+	"			)",
+	"			{	eoi++;", /* no break, must count ooi */
+	"		}	}",
+	"		if (eoi > 0)",
 	"		{	t = trans[ot][tt];",
-	"#ifdef VERBOSE",
-	"			printf(\"randomizer: suppressed, saw else\\n\");",
-	"#endif",
-	"		} else",
+	"	#ifdef VERBOSE",
+	"			printf(\"randomizer: suppressed, saw else or escape\\n\");",
+	"	#endif",
+	"		} else if (ooi > 0)",
 	"		{	eoi = rand()%%ooi;",
-	"#ifdef VERBOSE",
+	"	#ifdef VERBOSE",
 	"			printf(\"randomizer: skip %%d in %%d\\n\", eoi, ooi);",
-	"#endif",
+	"	#endif",
 	"			for (t = trans[ot][tt]; t; t = t->nxt)",
 	"				if (eoi-- <= 0) break;",
 	"		}",
-	"DOMORE:",
+	"domore:",
 	"		for ( ; t && ooi > 0; t = t->nxt, ooi--)",
-	"#else",
+	"#else", /* ie dont randomize */
 	"		for (t = trans[ot][tt]; t; t = t->nxt)",
 	"#endif",
 	"		{",
@@ -2045,49 +3381,83 @@
 	"				break;",
 	"			}",
 	"#endif",
+	"	#if defined(TRIX) && !defined(TRIX_ORIG) && !defined(BFS)",
+	"			(trpt+1)->p_bup = now._ids_[II];",
+	"	#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;",
+	"			if (!(_m = do_transit(t, II)))",
+	"			{	continue;",
+	"			}",
+	"#endif",
+	"#ifdef BCS",
+	"			if (depth > BASE",	/* has prior move */
+	"			&& II >= BASE",		/* not claim */
+	"			&& From != To",		/* not atomic or po */
+	"	#ifndef BCS_NOFIX",
+	"			/* added 5.2.5: prior move was not po */",
+	"			&& !((trpt-(BASE+1))->tau & 32)",
+	"	#endif",
+	"			&& boq == -1",		/* not rv */
+	"			&& (trpt->bcs & B_PHASE2)",
+	"			&&  trpt->b_pno != II	/* context switch */", /* redundant */
+	"			&& !(trpt->bcs & B_FORCED))	/* unless forced */",
+	"			{	(trpt+1)->sched_limit = 1 + trpt->sched_limit;",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: up sched count to %%d\\n\", depth, (trpt+1)->sched_limit);",
+	"	#endif",
+	"			} else",
+	"			{	(trpt+1)->sched_limit = trpt->sched_limit;",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: keep sched count at %%d\\n\", depth, (trpt+1)->sched_limit);",
+	"	#endif",
+	"			}",
 	"#endif",
 	"			if (boq == -1)",
-"#ifdef CTL",
+		"#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->tau |= 16;",	/* CTL */
 	"				trpt->o_pm |= 1; /* we moved */",
 	"			}",
-"#else",
+		"#else",
 	"				trpt->o_pm |= 1; /* we moved */",
-"#endif",
+		"#endif",
+
+	"#ifdef LOOPSTATE",
+	"			if (loopstate[ot][tt])",
+	"			{",
+		"#ifdef VERBOSE",
+	"				printf(\"exiting from loopstate:\\n\");",
+		"#endif",
+	"				trpt->tau |= 16;",	/* exiting loopstate */
+	"				cnt_loops++;",
+	"			}",
+	"#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,",
+	"	cpu_printf(\"%%3ld: proc %%d exec %%d \\n\", depth, II, t->t_id);",
+		"#else",
+	"	cpu_printf(\"%%3ld: proc %%d exec %%d, %%d to %%d, %%s %%s %%s %%saccepting [tau=%%d]\\n\", ",
+	"				depth, II, t->forw, tt, t->st, t->tp,",
 	"				(t->atom&2)?\"atomic\":\"\",",
-	"				(boq != -1)?\"rendez-vous\":\"\");",
-			"#ifdef HAS_UNLESS",
+	"				(boq != -1)?\"rendez-vous\":\"\",",
+	"				(trpt->o_pm&2)?\"\":\"non-\", trpt->tau);",
+		"#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);",
+	"			cpu_printf(\"\\t(escape to state %%d)\\n\", t->st);",
+		"#endif",
+		"#endif",
+		"#ifdef T_RAND",
+	"			cpu_printf(\"\\t(randomizer %%d)\\n\", ooi);",
 		"#endif",
 	"#endif",
 
@@ -2143,9 +3513,16 @@
 	"			trpt->o_ot = ot; trpt->o_tt = tt;",
 	"			trpt->o_To = To; trpt->o_m  = _m;",
 	"			trpt->tau = 0;",
-"#ifdef RANDOMIZE",
+	"#ifdef PERMUTED",
+	"			if (reversing&2)",
+	"			{	trpt->seed = seed;",
+	"				trpt->oII  = oII;",
+	"			}",
+	"#endif",
+
+	"#if defined(T_RAND) && !defined(BFS)",
 	"			trpt->oo_i = ooi;",
-"#endif",
+	"#endif",
 	"			if (boq != -1 || (t->atom&2))",
 	"			{	trpt->tau |= 8;",
 	"#ifdef VERI",
@@ -2171,30 +3548,76 @@
 	"			if (boq == -1 && (t->atom&2))",
 	"			{	From = To = II; nlinks++;",
 	"			} else",
-	"			{	From = now._nr_pr-1; To = BASE;",
-	"			}",
+	"			{	From = FROM_P; To = UPTO_P;",
+	"			}",
+	"#if NCORE>1 && defined(FULL_TRAIL)",
+	"			if (upto > 0)",
+	"			{	Push_Stack_Tree(II, t->t_id);",
+	"			}",
+	"#endif",
+	"#ifdef TRIX",
+	"			if (processes[II])", /* last move could have been a delproc */
+	"			{	processes[II]->modified = 1; /* transition in II */",
+	"	#ifdef V_TRIX",
+	"				printf(\"%%4d: process %%d modified\\n\", depth, II);",
+	"			} else",
+	"			{	printf(\"%%4d: process %%d modified but gone (%%p)\\n\",",
+	"					depth, II, trpt);",
+	"	#endif",
+	"			}",
+	"#endif",
 	"			goto Down;	/* pseudo-recursion */",
 	"Up:",
+	"#ifdef TRIX",
+	"	#ifndef TRIX_ORIG",
+	"		#ifndef BFS",
+	"			now._ids_[trpt->pr] = trpt->p_bup;",
+	"		#endif",
+	"	#else",
+	"			if (processes[trpt->pr])",
+	"			{",
+	"				processes[trpt->pr]->modified = 1; /* reverse move */",
+	"		#ifdef V_TRIX",
+	"				printf(\"%%4d: unmodify pr %%d (%%p)\\n\",",
+	"					depth, trpt->pr, trpt);",
+	"			} else",
+	"			{	printf(\"%%4d: unmodify pr %%d (gone) (%%p)\\n\",",
+	"					depth, trpt->pr, trpt);",
+	"		#endif",
+	"			}",
+	"	#endif",
+	"#endif",
 	"#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);",
-	"	}",
+	"			cpu_printf(\"%%d: Up - %%s\\n\", depth,",
+	"				(trpt->tau&4)?\"claim\":\"program\");",
+	"#endif",
+	"#if NCORE>1",
+	"			iam_alive();",
+	"	#ifdef USE_DISK",
+	"			mem_drain();",
+	"	#endif",
+	"#endif",
+	"#if defined(MA) || NCORE>1",
+	"			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)",	/* 5.1.6: was + 2 */
+	"			{",
+	" 				trpt += DDD;",
+	"				disk2stack();",
+	"				maxdepth -= DDD;",
+	"				hiwater -= DDD;",
+	"				if(verbose)",
+	"				printf(\"unzap %%ld: %%ld\\n\", CNT2, hiwater);",
+	"			}",
+	"#endif",
+
+	"#ifndef SAFETY",	/* moved earlier in version 5.2.5 */
+	"			if ((now._a_t&1) && depth <= A_depth)",
+	"				return;	/* to checkcycles() */",
 	"#endif",
 
 	"#ifndef NOFAIR",
@@ -2203,7 +3626,7 @@
 	"				_n = 1; trpt->o_pm &= ~128;",
 	"				depth--; trpt--;",
 		"#if defined(VERBOSE) || defined(CHECK)",
-	"	printf(\"%%3d: reversed fairness default move\\n\", depth);",
+	"	printf(\"%%3ld: reversed fairness default move\\n\", depth);",
 		"#endif",
 	"				goto Q999;",
 	"			}",
@@ -2211,7 +3634,7 @@
 
 	"#ifdef HAS_LAST",
 	"#ifdef VERI",
-	"			{ int d; Trail *trl;",
+	"			{ long d; Trail *trl;",
 	"			  now._last = 0;",
 	"			  for (d = 1; d < depth; d++)",
 	"			  {	trl = getframe(depth-d); /* was (trpt-d) */",
@@ -2226,61 +3649,63 @@
 	"#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);",
+	"			tt = trpt->o_tt; this = Pptr(II);",
 	"			To = trpt->o_To; _m  = trpt->o_m;",
-"#ifdef RANDOMIZE",
+	"#ifdef PERMUTED",
+	"			if (reversing&2)",
+	"			{	seed = trpt->seed;",
+	"				oII  = trpt->oII;",
+	"			}",
+	"#endif",
+	"#if defined(T_RAND) && !defined(BFS)",
 	"			ooi = trpt->oo_i;",
-"#endif",
+	"#endif",
 	"#ifdef INLINE_REV",
 	"			_m = do_reverse(t, II, _m);",
 	"#else",
-	"#include REVERSE_MOVES",
+	"#include BACKWARD_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);",
+	"			cpu_printf(\"%%3ld: proc %%d reverses %%d, %%d to %%d\\n\",",
+	"				depth, II, t->forw, tt, t->st);",
+	"			cpu_printf(\"\\t%%s [abit=%%d,adepth=%%ld,tau=%%d,%%d]\\n\", ",
+	"				t->tp, now._a_t, A_depth, 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",
+	"				(trpt-1)->tau |= 16;",	/* pass upward */
+	"	#ifdef SAFETY",
 	"			if ((trpt->tau&8)	/* rv or atomic */",
 	"			&&  (trpt->tau&64))",
 	"				(trpt-1)->tau |= 64;",
-	"#endif",
-	"#endif",
+	"	#endif",
+	"#endif",
+
+	"#if defined(BCS) && (defined(NOREDUCE) || !defined(SAFETY))",
+	/* for BCS, cover cases where 64 is otherwise not handled */
+	"			if ((trpt->tau&8)",
+	"			&&  (trpt->tau&64))",
+	"				(trpt-1)->tau |= 64;",
+	"#endif",
+
 	"			depth--; trpt--;",
+	"",
+	"#ifdef NSUCC",
+	"			trpt->n_succ++;",
+	"#endif",
 	"#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][t->st] = 1;",
 	"				reached[ot][tt] = 1;",
 	"			}",
 	"#ifdef HAS_UNLESS",
@@ -2291,18 +3716,18 @@
 	"			((P0 *)this)->_p = tt;",
 	"		} /* all options */",
 
-	"#ifdef RANDOMIZE",
+	"#ifdef T_RAND",
 	"		if (!t && ooi > 0)",	/* means we skipped some initial options */
 	"		{	t = trans[ot][tt];",
-	"#ifdef VERBOSE",
+	"	#ifdef VERBOSE",
 	"			printf(\"randomizer: continue for %%d more\\n\", ooi);",
-	"#endif",
-	"			goto DOMORE;",
-	"		}",
-	"#ifdef VERBOSE",
+	"	#endif",
+	"			goto domore;",
+	"		}",
+	"	#ifdef VERBOSE",
 	"		  else",
 	"			printf(\"randomizer: done\\n\");",
-	"#endif",
+	"	#endif",
 	"#endif",
 
 	"#ifndef NOFAIR",
@@ -2312,12 +3737,12 @@
 	"		{	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*/
+	"				if (now._cnt[now._a_t&1] == 1)",
+	"					now._cnt[now._a_t&1] = 2;",
 		"#endif",
 	"				now._cnt[now._a_t&1] += 1;",
 		"#ifdef VERBOSE",
-	"		printf(\"%%3d: proc %%d fairness \", depth, II);",
+	"		printf(\"%%3ld: 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",
@@ -2326,32 +3751,77 @@
 	"			{	if (_n > 0)", /* a prev proc didn't */
 	"				{",	/* start over */
 	"					trpt->o_pm &= ~64;",
-	"					II = From+1;",
+	"					II = INI_P;", /* after loop incr II == From */
 	"		}	}	}",
 	"#endif",
-
-	"#ifdef VERI",
-	"		if (II == 0) break;	/* never claim */",
-	"#endif",
-	"	} /* all processes */",
+	"#ifdef VERI",
+	"		if (II == 0)",
+	"		{	break;	/* never claim */",
+	"		}",
+	"#endif",
+	"		CONTINUE;",
+	"	} /* ALL_P */",
+
+	"#ifdef NSUCC",
+	"	tally_succ(trpt->n_succ);",
+	"#endif",
+
+	"#ifdef P_RAND",
+	"	if (trpt->p_left > 0 && NDONE_P)",
+	"	{	trpt->p_skip = -1; /* probably rendundant */",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: P_RAND -- explore remainder\\n\", depth);",
+	"	#endif",
+	"		goto r_switch; /* explore the remaining procs */",
+	"	} else",
+	"	{",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: P_RAND -- none left\\n\", depth);",
+	"	#endif",
+	"	}",
+	"#endif",
+
+	"#ifdef BCS",
+	"	if (trpt->bcs & B_PHASE1)",
+	"	{	trpt->bcs = B_PHASE2;	/* start 2nd phase */",
+	"		if (_n == 0 || !(trpt->tau&64))	/* pre-move unexecutable or led to stackstate */",
+	"		{	trpt->bcs |= B_FORCED; /* forced switch */",
+	"		}",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: BCS move to phase 2, _n=%%d %%s\\n\", depth, _n,",
+	"			(trpt->bcs & B_FORCED)?\"forced\":\"free\");",
+	"	#endif",
+	"		From = FROM_P; To = UPTO_P;",
+	"		goto c_switch;",
+	"	}",
+	"",
+	"	if (_n == 0	/* no process could move */",
+	"	&&  II >= BASE	/* not the never claim */",
+	"	&&  trpt->sched_limit >= sched_max)",
+	"	{	_n = 1;",
+	"	#ifdef VERBOSE",
+	"		printf(\"%%3ld: BCS not a deadlock\\n\", depth);",
+	"	#endif",
+	"	}",
+	"#endif",
 
 	"#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 */
+	"		if (now._cnt[now._a_t&1] == 1)",
+	"			now._cnt[now._a_t&1] = 2;",
 		"#endif",
 	"		now._cnt[now._a_t&1] += 1;",
 		"#ifdef VERBOSE",
-	"		printf(\"%%3d: proc -- fairness \", depth);",
+	"		printf(\"%%3ld: 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",
+	"#ifndef NP",
 	/* 12/97 non-progress cycles cannot be created
 	 * by stuttering extension, here or elsewhere
 	 */
@@ -2361,12 +3831,8 @@
 		"	&& !(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",
+		"#ifdef ETIM",
+		"	&&  (trpt->tau&1)	/* already tried timeout */",
 		"#endif",
 		"#ifndef NOREDUCE",
 		"	/* see below  */",
@@ -2382,14 +3848,14 @@
 		"#else",
 	"		trpt->tau = 0;",
 		"#endif",
-	"		From = now._nr_pr-1; To = BASE;",
+	"		From = FROM_P; To = UPTO_P;",
 		"#if defined(VERBOSE) || defined(CHECK)",
-	"		printf(\"%%3d: fairness default move \", depth);",
+	"		printf(\"%%3ld: fairness default move \", depth);",
 	"		printf(\"(all procs block)\\n\");",
 		"#endif",
 	"		goto Down;",
 	"	}",
-"#endif",
+	"#endif",
 	"Q999:	/* returns here with _n>0 when done */;",
 
 	"	if (trpt->o_pm&8)",
@@ -2397,7 +3863,7 @@
 	"		now._cnt[now._a_t&1] = 0;",
 	"		trpt->o_pm &= ~8;",
 		"#ifdef VERBOSE",
-	"		printf(\"%%3d: fairness undo Rule 1, _a_t=%%d\\n\",",
+	"		printf(\"%%3ld: fairness undo Rule 1, _a_t=%%d\\n\",",
 	"			depth, now._a_t);",
 		"#endif",
 	"	}",
@@ -2406,7 +3872,7 @@
 	"		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\",",
+	"		printf(\"%%3ld: fairness undo Rule 3, _a_t=%%d\\n\",",
 	"			depth, now._a_t);",
 		"#endif",
 	"	}",
@@ -2414,35 +3880,41 @@
 
 	"#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",
+	"	#ifdef LOOPSTATE",
+	"	  /* at least one move that was preselected at this */",
+	"	  /* level, blocked or was a loop control flow point */",
+	"	  if ((trpt->tau&32) && (_n == 0 || (trpt->tau&16)))",
+	"	#else",
+	"	  /* preselected move - no successors outside stack */",
+	"	  if ((trpt->tau&32) && !(trpt->tau&64))",
+	"	#endif",
+	"	  {	From = FROM_P; To = UPTO_P; /* undo From == To */",
+	"	#ifdef DEBUG",
+	"		printf(\"%%3ld: 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;",
-	"	}",
+
+	"		if (MORE_P)	/* II already restored and updated */",
+	"		{	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",
+	"	#ifdef DEBUG",
+	"		printf(\"%%3ld: 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",
+	"	#ifdef DEBUG",
+	"			printf(\"%%3ld: setting proviso bit\\n\", depth);",
+	"	#endif",
 	"#ifndef BITSTATE",
 		"#ifdef MA",
 			"#ifdef VERI",
@@ -2466,27 +3938,26 @@
 	"			trpt->ostate->proviso = 1;",
 		"#endif",
 	"#endif",
-	"				From = now._nr_pr-1; To = BASE;",
+	"				From = FROM_P; To = UPTO_P;",
 	"				_n = 0; trpt->tau &= ~(16|32|64);",
 	"				goto Again; /* do full search */",
 	"			} /* else accept reduction */",
 	"		} else",
-	"		{	From = now._nr_pr-1; To = BASE;",
+	"		{	From = FROM_P; To = UPTO_P;",
 	"			_n = 0; trpt->tau &= ~(16|32|64);",
-	"			if (II >= BASE)	/* already decremented */",
-	"				goto Resume;",
-	"			else",
-	"				goto Again;",
-	"	}	}",
-	"/* #endif */",
+	"			if (MORE_P)	/* II already updated */",
+	"			{	goto Resume;",
+	"			} else",
+	"			{	goto Again;",
+	"	}	}	}",
 "#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);",
+	"		cpu_printf(\"%%3ld: no move [II=%%d, tau=%%d, boq=%%d]\\n\",",
+	"			depth, II, trpt->tau, boq);",
 		"#endif",
 	"#if SYNC",
 	"		/* ok if a rendez-vous fails: */",
@@ -2494,18 +3965,14 @@
 	"#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;",
+	"		||  depth >= maxdepth-1) goto Done;	/* undo change from 5.2.3 */",
 
 	"		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\");",
+	"			From = FROM_P; To = UPTO_P;",
+		"#ifdef DEBUG",
+	"		cpu_printf(\"%%3ld: atomic step proc %%d unexecutable\\n\", depth, II+1);",
 		"#endif",
 	"#ifdef VERI",
 	"			trpt->tau |= 4;	/* switch to claim */",
@@ -2524,9 +3991,9 @@
 		"#endif",
 	"				{	trpt->tau |=  1;",
 	"					trpt->tau &= ~2;",
-				"#ifdef DEBUG",
-	"				printf(\"%%d: timeout\\n\", depth);",
-				"#endif",
+	"	#ifdef DEBUG",
+	"				cpu_printf(\"%%d: timeout\\n\", depth);",
+	"	#endif",
 	"					goto Stutter;",
 	"			}	}",
 	"			else",
@@ -2534,18 +4001,22 @@
 	"				if ((trpt->tau&8)",
 	"				&&  !((trpt-1)->tau&4))",
 	"/* blocks inside an atomic */		goto BreakOut;",
-				"#ifdef DEBUG",
-	"				printf(\"%%d: req timeout\\n\",",
+	"	#ifdef DEBUG",
+	"				cpu_printf(\"%%d: req timeout\\n\",",
 	"					depth);",
-				"#endif",
+	"	#endif",
 	"				(trpt-1)->tau |= 2; /* request */",
+	"	#if NCORE>1 && defined(FULL_TRAIL)",
+	"				if (upto > 0)",
+	"				{	Pop_Stack_Tree();",
+	"				}",
+	"	#endif",
 	"				goto Up;",
 	"			}",
 	"#else",
-
-				"#ifdef DEBUG",
-	"			printf(\"%%d: timeout\\n\", depth);",
-				"#endif",
+	"	#ifdef DEBUG",
+	"			cpu_printf(\"%%d: timeout\\n\", depth);",
+	"	#endif",
 	"			trpt->tau |=  1;",
 	"			goto Again;",
 	"#endif",
@@ -2560,7 +4031,7 @@
 	"		{	trpt->tau |= 4;   /* claim stuttering */",
 	"			trpt->tau |= 128; /* stutter mark */",
 				"#ifdef DEBUG",
-	"			printf(\"%%d: claim stutter\\n\", depth);",
+	"			cpu_printf(\"%%d: claim stutter\\n\", depth);",
 				"#endif",
 	"			goto Stutter;",
 	"		}",
@@ -2585,6 +4056,47 @@
 	"Done:",
 	"	if (!(trpt->tau&8))	/* not in atomic seqs */",
 	"	{",
+
+"#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(\"%%ld: 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(\"%%ld: zapping\\n\", depth);",
+		"#endif",
+	"			onstack_zap();",
+		"#ifndef NOREDUCE",
+	"			if (trpt->proviso)",
+	"			g_store((char *) &now, vsize, 1);",
+		"#endif",
+	"		}",
+"#endif",
+
 	"#ifndef SAFETY",
 	"		if (_n != 0",		/* we made a move */
 		"#ifdef VERI",
@@ -2601,7 +4113,7 @@
 	"			if (fairness)",	/* implies a_cycles */
 	"			{",
 			"#ifdef VERBOSE",
-	"			printf(\"Consider check %%d %%d...\\n\",",
+	"			cpu_printf(\"Consider check %%d %%d...\\n\",",
 	"				now._a_t, now._cnt[0]);",
 			"#endif",
 #if 0
@@ -2624,54 +4136,23 @@
 	"				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;",
+	"	}",
+	"	if (depth > 0)",
+	"	{",
+	"#if NCORE>1 && defined(FULL_TRAIL)",
+	"		if (upto > 0)",
+	"		{	Pop_Stack_Tree();",
+	"		}",
+	"#endif",
+	"		goto Up;",
+	"	}",
 	"}\n",
 	"#else",
 	"void new_state(void) { /* place holder */ }",
 	"#endif",	/* BFS */
 	"",
 	"void",
-	"assert(int a, char *s, int ii, int tt, Trans *t)",
+	"spin_assert(int a, char *s, int ii, int tt, Trans *t)",
 	"{",
 	"	if (!a && !noasserts)",
 	"	{	char bad[1024];",
@@ -2688,169 +4169,214 @@
 	"int",
 	"Boundcheck(int x, int y, int a1, int a2, Trans *a3)",
 	"{",
-	"	assert((x >= 0 && x < y), \"- invalid array index\",",
+	"	spin_assert((x >= 0 && x < y), \"- invalid array index\",",
 	"		a1, a2, a3);",
 	"	return x;",
 	"}",
 	"#endif",
+	"int do_hashgen = 0;",
 	"void",
 	"wrap_stats(void)",
 	"{",
 	"	if (nShadow>0)",
-	"	  printf(\"%%8g states, stored (%%g visited)\\n\",",
+	"	  printf(\"%%9.8g states, stored (%%g visited)\\n\",",
 	"			nstates - nShadow, nstates);",
 	"	else",
-	"	  printf(\"%%8g states, stored\\n\", nstates);",
+	"	  printf(\"%%9.8g states, stored\\n\", nstates);",
+	"#ifdef BFS_PAR",
+	"	if (bfs_punt > 0)",
+	"	printf(\"%%9.8g states lost (lack of queue memory)\\n\", (double) bfs_punt);",
+	"#endif",
 	"#ifdef BFS",
-	"#if SYNC",
+	"	#if SYNC",
 	"	printf(\"	%%8g nominal states (- rv and atomic)\\n\", nstates-midrv-nlinks+revrv);",
 	"	printf(\"	%%8g rvs succeeded\\n\", midrv-failedrv);",
-	"#else",
+	"	#else",
 	"	printf(\"	%%8g nominal states (stored-atomic)\\n\", nstates-nlinks);",
-	"#endif",
-	"#ifdef DEBUG",
+	"	#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);",
+	"	#endif",
+	"#endif",
+	"	printf(\"%%9.8g states, matched\\n\", truncs);",
 	"#ifdef CHECK",
-	"	printf(\"%%8g matches within stack\\n\",truncs2);",
+	"	printf(\"%%9.8g matches within stack\\n\",truncs2);",
 	"#endif",
 	"	if (nShadow>0)",
-	"	printf(\"%%8g transitions (= visited+matched)\\n\",",
+	"	printf(\"%%9.8g transitions (= visited+matched)\\n\",",
 	"		nstates+truncs);",
 	"	else",
-	"	printf(\"%%8g transitions (= stored+matched)\\n\",",
+	"	printf(\"%%9.8g transitions (= stored+matched)\\n\",",
 	"		nstates+truncs);",
-	"	printf(\"%%8g atomic steps\\n\", nlinks);",
+	"	printf(\"%%9.8g atomic steps\\n\", nlinks);",
 	"	if (nlost) printf(\"%%g lost messages\\n\", (double) nlost);",
 	"",
 	"#ifndef BITSTATE",
-	"	printf(\"hash conflicts: %%g (resolved)\\n\", hcmp);",
+	"	#ifndef MA",
+	"	printf(\"hash conflicts: %%9.8g (resolved)\\n\", hcmp);",
+	"		#if !defined(AUTO_RESIZE) && !defined(BFS_PAR)",
+	"	if (hcmp > (double) (1<<ssize))",
+	"	{  printf(\"hint: increase hashtable-size (-w) to reduce runtime\\n\");",
+	"	}",
+	"		#endif",
+	"		#if defined(BFS_PAR) && defined(HC)",
+	"	{ double fp = (100. * (double) nstates)/((double) ((ulong) (1<<ssize)));",
+	"	  int fi = 0;",
+	"		printf(\"the hash table is %%3.3g %%%% filled\", fp);",
+	"		if (fp > 1.0)",
+	"		{	fp = 100. / fp;",
+	"			while (fp > 2.) { fi++; fp /= 2.; }",
+	"			if (fi > 0)",
+	"			{	printf(\" (hint: rerun with -w%%d to reduce runtime)\",",
+	"				ssize-fi);",
+	"		}	}",
+	"		printf(\"\\n\");",
+	"	}",
+	"		#endif",
+	"	#endif",
 	"#else",
 		"#ifdef CHECK",
 		"	printf(\"%%8g states allocated for dfs stack\\n\", ngrabs);",
 		"#endif",
+	"	if (udmem)",
 	"	printf(\"\\nhash factor: %%4g (best if > 100.)\\n\\n\",",
-	"		(double)(1<<(ssize-8)) / (double) nstates * 256.0);",
+	"		(double)(((double) udmem) * 8.0) / (double) nstates);",
+	"	else",
+	"	printf(\"\\nhash factor: %%4g (best if > 100.)\\n\\n\",",
+	"		((double)(((ulong)1)<<(ssize-10)) / (double) nstates) * 1024.0);",
+			/* the -10 and *1024 stuff is to avoid overflow */
 	"       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",
-	"}",
+	"	if (do_hashgen)",
+	"	printf(\"hash polynomial used: 0x%%.8x\\n\", HASH_CONST[HASH_NR]);",
+	"	if (s_rand != 12345)",
+	"	printf(\"random seed used: %%u\\n\", (uint) (s_rand-1));",
+	"#endif",
+	"#if defined(BFS_DISK) && !defined(BFS_PAR)",
+	"	printf(\"bfs disk reads: %%ld writes %%ld -- diff %%ld\\n\",",
+	"		bfs_dsk_reads, bfs_dsk_writes, bfs_dsk_writes-bfs_dsk_reads);",
+	"	if (bfs_dsk_read  >= 0) (void) close(bfs_dsk_read);",
+	"	if (bfs_dsk_write >= 0) (void) close(bfs_dsk_write);",
+	"	(void) unlink(\"pan_bfs_dsk.tmp\");",
+	"#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",
-
+	"{	double nr1, nr2, nr3 = 0.0, nr4, nr5 = 0.0;",
+	"#ifdef BFS_PAR",
+	"	if (who_am_i != 0)",
+	"	{	pan_exit(0);",
+	"	}",
+	"#endif",
+	"#if NCORE>1",
+	"	if (verbose) cpu_printf(\"wrapup -- %%d error(s)\\n\", errors);",
+	"	if (core_id != 0)",
+	"	{",
+	"	#ifdef USE_DISK",
+	"		void	dsk_stats(void);",
+	"		dsk_stats();",
+	"	#endif",
+	"		if (search_terminated != NULL)",
+	"		{	*search_terminated |= 2;	/* wrapup */",
+	"		}",
+	"		exit(0); /* normal termination, not an error */",
+	"	}",
+	"#endif",
+	"#if !defined(WIN32) && !defined(WIN64)",
 	"	signal(SIGINT, SIG_DFL);",
-	"	printf(\"(%%s)\\n\", Version);",
+	"#endif",
+	"	printf(\"\\n(%%s)\\n\", SpinVersion);",
 	"	if (!done) printf(\"Warning: Search not completed\\n\");",
+	"#if defined(BFS_PAR) && !defined(BITSTATE)",
+	"	if (bfs_punt > 0) printf(\"Warning: Search incomplete\\n\");",
+	"#endif",
 	"#ifdef SC",
 	"	(void) unlink((const char *)stackfile);",
 	"#endif",
+	"#ifdef BFS_PAR",
+	"	printf(\"	+ Multi-Core (using %%d cores)\\n\", Cores);",
+	"	#ifdef BFS_SEP_HASH",
+	"	printf(\"	+ Separate Hash Tables\\n\");",
+	"	#endif",
+	"	#ifdef BFS_DISK",
+	"	printf(\"	+ Disk storage\\n\");",
+	"	#endif",
+	"#endif",
+	"#if NCORE>1",
+	"	if (a_cycles)",
+	"	{	printf(\"	+ Multi-Core (NCORE=%%d)\\n\", NCORE);",
+	"	} else",
+	"	{	printf(\"	+ Multi-Core (NCORE=%%d -z%%ld)\\n\", NCORE, z_handoff);",
+	"	}",
+	"#endif",
 	"#ifdef BFS",
-	"	printf(\"	+ Using Breadth-First Search\\n\");",
+	"	printf(\"	+ 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 PERMUTED",
+	"	printf(\"	+ Process Scheduling Permutation\\n\");",
+	"#endif",
+	"#ifdef P_REVERSE",
+	"	printf(\"	+ Reverse Depth-First Search Order\\n\");",
+	"#endif",
+	"	if (t_reverse)",
+	"	printf(\"	+ Reverse Transition Ordering\\n\");",
+	"#ifdef T_RAND",
+	"	printf(\"	+ Randomized Transition Ordering\\n\");",
+	"#endif",
+	"#ifdef P_RAND",
+	"	printf(\"	+ Randomized Process Ordering\\n\");",
+	"#endif",
+	"#ifdef BCS",
+	"	printf(\"	+ Scheduling Restriction (-L%%d)\\n\", sched_max);",
+	"#endif",
+	"#ifdef TRIX",
+	"	printf(\"	+ Tree Index Compression\\n\");",
+	"#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",
+	"  #ifdef R_XPT",
+	"	printf(\"	  Restarted from checkpoint %%s.xpt\\n\", PanSource);",
+	"  #endif",
 	"#endif",
 	"#ifdef CHECK",
-		"#ifdef FULLSTACK",
+	"  #ifdef FULLSTACK",
 	"	printf(\"	+ FullStack Matching\\n\");",
-		"#endif",
-		"#ifdef CNTRSTACK",
+	"  #endif",
+	"  #ifdef CNTRSTACK",
 	"	printf(\"	+ CntrStack Matching\\n\");",
-		"#endif",
+	"  #endif",
+	"#endif",
+	"#ifdef PERMUTED",
+	"	if (reversing & 2)",
+	"	{	if (p_reorder == set_permuted)",
+	"		{	printf(\"	+ Permuted\\n\");",
+	"		}",
+	"		if (p_reorder == set_reversed)",
+	"		{	printf(\"	+ Reversed\\n\");",
+	"		}",
+	"		if (p_reorder == set_rotated)",
+	"		{	printf(\"	+ Rotated %%d\\n\", p_rotate);",
+	"		}",
+	"		if (p_reorder == set_randrot)",
+	"		{	printf(\"	+ RandRotated\\n\");",
+	"	}	}",
 	"#endif",
 	"#ifdef BITSTATE",
 	"	printf(\"\\nBit statespace search for:\\n\");",
 	"#else",
-		"#ifdef HC",
+	"  #ifdef HC",
 	"	printf(\"\\nHash-Compact %%d search for:\\n\", HC);",
-		"#else",
+	"  #else",
 	"	printf(\"\\nFull statespace search for:\\n\");",
-		"#endif",
+	"  #endif",
 	"#endif",
 	"#ifdef EVENT_TRACE",
 	"#ifdef NEGATED_TRACE",
@@ -2860,7 +4386,8 @@
 	"#endif",
 	"#endif",
 	"#ifdef VERI",
-	"	printf(\"\tnever claim         \t+\\n\");",
+	"	printf(\"\tnever claim         \t+\");",
+	"	printf(\" (%%s)\\n\", procname[((Pclaim *)pptr(0))->_t]);",
 	"	printf(\"\tassertion violations\t\");",
 	"	if (noasserts)",
 	"		printf(\"- (disabled by -A flag)\\n\");",
@@ -2889,7 +4416,11 @@
 	"			fairness?\"en\":\"dis\");",
 	"	else printf(\"- (not selected)\\n\");",
 	"#else",
+	"	#if !defined(BFS_PAR) || !defined(L_BOUND)",
 	"	printf(\"\tcycle checks       \t- (disabled by -DSAFETY)\\n\");",
+	"	#else",
+	"	printf(\"\tcycle checks       \t+ (bound %%d)\\n\", L_bound);",
+	"	#endif",
 	"#endif",
 	"#ifdef VERI",
 	"	printf(\"\tinvalid end states\t- \");",
@@ -2905,9 +4436,13 @@
 	"	else",
 	"		printf(\"+\\n\\n\");",
 	"#endif",
-	"	printf(\"State-vector %%d byte, depth reached %%d\", ",
-	"					hmax, mreached);",
+	"	printf(\"State-vector %%d byte, depth reached %%ld\", hmax,",
+	"#if NCORE>1",
+	"					(nr_handoffs * z_handoff) +",
+	"#endif",
+	"					mreached);",
 	"	printf(\", errors: %%d\\n\", errors);",
+	"	fflush(stdout);",
 	"#ifdef MA",
 	"	if (done)",
 	"	{	extern void dfa_stats(void);",
@@ -2920,124 +4455,196 @@
 	"	wrap_stats();",
 	"#ifdef CHECK",
 	"	printf(\"stackframes: %%d/%%d\\n\\n\", smax, svmax);",
-	"	printf(\"stats: fa %%d, fh %%d, zh %%d, zn %%d - \",",
+	"	printf(\"stats: fa %%ld, fh %%ld, zh %%ld, zn %%ld - \",",
 	"		Fa, Fh, Zh, Zn);",
-	"	printf(\"check %%d holds %%d\\n\", Ccheck, Cholds);",
-	"	printf(\"stack stats: puts %%d, probes %%d, zaps %%d\\n\",",
+	"	printf(\"check %%ld holds %%ld\\n\", Ccheck, Cholds);",
+	"	printf(\"stack stats: puts %%ld, probes %%ld, zaps %%ld\\n\",",
 	"		PUT, PROBE, ZAPS);",
 	"#else",
 	"	printf(\"\\n\");",
 	"#endif",
 	"",
-	"#if defined(BITSTATE) || !defined(NOCOMP)",
+	"#if !defined(BITSTATE) && defined(NOCOMP)",
+	"	if (!verbose) { goto jump_here; }",	/* added 5.2.0 */
+	"#endif",
+	"",
+	"#if 1",	/* omitted 5.2.0:  defined(BITSTATE) || !defined(NOCOMP) */
 	"	nr1 = (nstates-nShadow)*",
-	"	      (double)(hmax+sizeof(struct H_el)-sizeof(unsigned));",
-		"#ifdef BFS",
+	"	      (double)(hmax+sizeof(H_el)-sizeof(unsigned));",
+	"	#ifdef BFS",
 	"	nr2 = 0.0;",
-		"#else",
+	"	#else",
 	"	nr2 = (double) ((maxdepth+3)*sizeof(Trail));",
-		"#endif",
-
-		"#ifndef BITSTATE",
+	"	#endif",
+
+	"	#ifndef BITSTATE",
 			"#if !defined(MA) || defined(COLLAPSE)",
-	"	nr3 = (double) (1L<<ssize)*sizeof(struct H_el *);",
-			"#endif",
-		"#else",
-#ifndef POWOW
+	"	nr3 = (double) (ONE_L<<ssize)*sizeof(H_el *);",
+			"#endif",
+	"	#else",
 	"	if (udmem)",
 	"		nr3 = (double) (udmem);",
 	"	else",
-#endif
-	"	nr3 = (double) (1L<<(ssize-3));",
+	"		nr3 = (double) (ONE_L<<(ssize-3));",
 			"#ifdef CNTRSTACK",
-	"	nr3 += (double) (1L<<(ssize-3));",
+	"	nr5 = (double) (ONE_L<<(ssize-3));",
 			"#endif",
 			"#ifdef FULLSTACK",
-	"	nr5 = (double) (maxdepth*sizeof(struct H_el *));",
-			"#endif",
-		"#endif",
+	"	nr5 = (double) (maxdepth*sizeof(H_el *));",
+			"#endif",
+	"	#endif",
+
 	"	nr4 = (double) (svmax * (sizeof(Svtack) + hmax))",
-	"	    + (double) (smax * (sizeof(Stack) + Maxbody));",
+	"	    + (double) (smax  * (sizeof(_Stack) + Maxbody * sizeof(char)));",
 		"#ifndef MA",
-	"	if (mverbose || memcnt < nr1+nr2+nr3+nr4+nr5)",
+	"	if (1 /* verbose || memcnt < nr1+nr2+nr3+nr4+nr5 */)",
 		"#endif",
 	"	{ double remainder = memcnt;",
 	"	  double tmp_nr = memcnt-nr3-nr4-(nr2-fragment)-nr5;",
+	"",
+	"	#if NCORE>1 && !defined(SEP_STATE)",
+	"		tmp_nr -= ((double) NCORE * LWQ_SIZE) + GWQ_SIZE;",
+	"	#endif",
 	"		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(\"%%9.3f\tequivalent memory usage for states\",",
+	"			nr1/1048576.); /* 1024*1024=1048576 */",
 	"		printf(\" (stored*(State-vector + overhead))\\n\");",
-		"#ifdef BITSTATE",
-#ifndef POWOW
+	"	#if NCORE>1 && !defined(WIN32) && !defined(WIN64)",
+	"		printf(\"%%9.3f\tshared memory reserved for state storage\\n\",",
+	"			mem_reserved/1048576.);",
+	"		#ifdef SEP_HEAP",
+	"		printf(\"\t\tin %%d local heaps of %%7.3f MB each\\n\",",
+	"			NCORE, mem_reserved/(NCORE*1048576.));",
+	"		#endif",
+	"		printf(\"\\n\");",
+	"	#endif",
+	"	#ifdef BITSTATE",
 	"		if (udmem)",
-	"		printf(\"%%-6.3f\tmemory used for hash array (-M%%ld)\\n\",",
-	"			nr3/1000000., udmem/(1024L*1024L));",
+	"			printf(\"%%9.3f\tmemory used for hash array (-M%%ld)\\n\",",
+	"			nr3/1048576., udmem/(1024L*1024L));",
 	"		else",
-#endif
-	"		printf(\"%%-6.3f\tmemory used for hash array (-w%%d)\\n\",",
-	"			nr3/1000000., ssize);",
+	"			printf(\"%%9.3f\tmemory used for hash array (-w%%d)\\n\",",
+	"			nr3/1048576., ssize);",
 	"		if (nr5 > 0.0)",
-	"		printf(\"%%-6.3f\tmemory used for bit stack\\n\",",
-	"			nr5/1000000.);",
+	"		printf(\"%%9.3f\tmemory used for bit stack\\n\",",
+	"			nr5/1048576.);",
 	"		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",
+	"	#else",
+	"		#ifndef USE_TDH",
+	"			printf(\"%%9.3f\tactual memory usage for states\",",
+	"				tmp_nr/1048576.);",
+	"			remainder -= tmp_nr;",
+	"			if (tmp_nr > 0.)",
+	"			{	if (tmp_nr < nr1) ",
+	"				{	printf(\" (compression: %%.2f%%%%)\\n\",",
+	"						(100.0*tmp_nr)/nr1);",
+	"				} else",
+	"				{	printf(\"\\n\");",
+	"				}",
+	"			} else",
+	"			{	printf(\" (less than 1k)\\n\");",
+	"			}",
+	"			#ifndef MA",
+	"			if (tmp_nr > 0. && tmp_nr < nr1)",
+	"			{	printf(\"         \tstate-vector as stored = %%.0f byte\",",
+	"				(tmp_nr)/(nstates-nShadow) -",
+	"				(double) (sizeof(H_el) - sizeof(unsigned)));",
+	"				printf(\" + %%ld byte overhead\\n\",",
+	"				(long int) sizeof(H_el)-sizeof(unsigned));",
+	"			}",
+	"			#endif",
+	"		#endif",
+	"		#if !defined(MA) || defined(COLLAPSE)",
+	"			#ifdef BFS_PAR",
+	"				printf(\"%%9.3f\tshared memory used for hash table (-w%%d)\\n\",",
+	"				((double) bfs_pre_allocated)/1048576., ssize);",
+	"			#else",
+	"				printf(\"%%9.3f\tmemory used for hash table (-w%%d)\\n\",",
+	"					nr3/1048576., ssize);",
+	"				remainder -= nr3;",
+	"			#endif",
+	"		#endif",
+	"	#endif",
+	"	#ifndef BFS",
+	"		printf(\"%%9.3f\tmemory used for DFS stack (-m%%ld)\\n\",",
+	"			nr2/1048576., maxdepth);",
+	"		remainder -= nr2;",
+	"	#endif",
+	"	#if NCORE>1",
+	"		remainder -= ((double) NCORE * LWQ_SIZE) + GWQ_SIZE;",
+	"		printf(\"%%9.3f\tshared memory used for work-queues\\n\",",
+	"			(GWQ_SIZE + (double) NCORE * LWQ_SIZE) /1048576.);",
+	"		printf(\"\t\tin %%d queues of %%7.3f MB each\",",
+	"			NCORE, (double) LWQ_SIZE /1048576.);",
+	"		#ifndef NGQ",
+	"		printf(\" + a global q of %%7.3f MB\\n\",",
+	"			(double) GWQ_SIZE / 1048576.);",
+	"		#else",
+	"		printf(\"\\n\");",
+	"		#endif",
+	"	#endif",
+	"		if (remainder - fragment > 1048576.)",
+	"		{	printf(\"%%9.3f\tother (proc and chan stacks)\\n\",",
+	"			(remainder-fragment)/1048576.);",
+	"		}",
+	"		if (fragment > 1048576.)",
+	"		{	printf(\"%%9.3f\tmemory lost to fragmentation\\n\",",
+	"			fragment/1048576.);",
+	"		}",
+	"	#ifdef BFS_PAR",
+	"		printf(\"%%9.3f\ttotal non-shared memory usage\\n\\n\",",
+	"			memcnt/1048576.);",
+	"	#else",
+	"		printf(\"%%9.3f\ttotal actual memory usage\\n\\n\",",
+	"			memcnt/1048576.);",
+	"	#endif",
+	"	}",
+	"	#ifndef MA",
+	"	else",
+	"	#endif",
+	"#endif",
+
+	"#if !defined(BITSTATE) && defined(NOCOMP)",
+	"jump_here:",
+	"#endif",
+	"#ifndef MA",
+	"	printf(\"%%9.3f\tmemory usage (Mbyte)\\n\",",
+	"		memcnt/1048576.);",
+	"#endif",
+	"#ifdef BFS_PAR",
+	"	bfs_report_mem();",
+	"#else",
+	"	printf(\"\\n\");",
+	"#endif",
 	"#ifdef COLLAPSE",
-	"	printf(\"nr of templates: [ globals chans procs ]\\n\");",
+	"	printf(\"nr of templates: [ 0:globals 1:chans 2:procs ]\\n\");",
 	"	printf(\"collapse counts: [ \");",
 	"	{ int i; for (i = 0; i < 256+2; i++)",
 	"		if (ncomps[i] != 0)",
-	"			printf(\"%%d \", ncomps[i]);",
+	"			printf(\"%%d:%%lu \", i, ncomps[i]);",
 	"		printf(\"]\\n\");",
 	"	}",
 	"#endif",
+	"	#ifdef TRIX",
+	"	if (verbose)",
+	"	{	int i;",
+	"		printf(\"TRIX counts:\\n\");",
+	"		printf(\"  processes: \");",
+	"		for (i = 0; i < MAXPROC; i++)",
+	"			if (_p_count[i] != 0)",
+	"			{	printf(\"%%3d:%%ld \",",
+	"					i, _p_count[i]);",
+	"			}",
+	"		printf(\"\\n  channels : \");",
+	"		for (i = 0; i < MAXQ; i++)",
+	"			if (_c_count[i] != 0)",
+	"			{	printf(\"%%3d:%%ld \",",
+	"					i, _c_count[i]);",
+	"			}",
+	"		printf(\"\\n\\n\");",
+	"	}",
+	"	#endif",
 
 	"	if ((done || verbose) && !no_rck) do_reach();",
 	"#ifdef PEG",
@@ -3053,21 +4660,90 @@
 	"#ifdef SVDUMP",
 	"	if (vprefix > 0) close(svfd);",
 	"#endif",
+	"#ifdef LOOPSTATE",
+	"	printf(\"%%g loopstates hit\\n\", cnt_loops);",
+	"#endif",
+	"#ifdef NSUCC",
+	"	dump_succ();",
+	"#endif",
+	"#if NCORE>1 && defined(T_ALERT)",
+	"	crash_report();",
+	"#endif",
+	"#ifndef BFS_PAR",
 	"	pan_exit(0);",
+	"#endif",
 	"}\n",
 	"void",
 	"stopped(int arg)",
-	"{	printf(\"Interrupted\\n\");",
+	"{",
+	"#ifdef BFS_PAR",
+	"	bfs_shutdown(\"interrupted\");",
+	"#endif",
+	"	printf(\"Interrupted\\n\");",
+	"#if NCORE>1",
+	"	was_interrupted = 1;",
+	"#endif",
 	"	wrapup();",
 	"	pan_exit(0);",
 	"}",
+	"",
 	"/*",
-	" * based on Bob Jenkins hash-function from 1996",
-	" * see: http://www.burtleburtle.net/bob/",
+	" * super fast hash, based on Paul Hsieh's function",
+	" * http://www.azillionmonkeys.com/qed/hash.html",
 	" */",
-	"",
-"#if defined(HASH64) || defined(WIN64)",
-	/* 64-bit Jenkins hash: http://burtleburtle.net/bob/c/lookup8.c */
+	"#include <stdint.h>",	/* for uint32_t etc */
+	" #undef get16bits",
+	" #if defined(__GNUC__) && defined(__i386__)",
+	"	#define get16bits(d) (*((const uint16_t *) (d)))",
+	" #else",
+	"	#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\\",
+	"                              +(uint32_t)(((const uint8_t *)(d))[0]) )",
+	" #endif",
+	"",
+	"void",
+	"d_sfh(uchar *s, int len)",	/* sets one 32-bit number, in K1 */
+	"{	uint32_t h = len, tmp;",
+	"	int rem;",
+	"",
+	"	rem = len & 3;",
+	"	len >>= 2;",
+	"",
+	"	for ( ; len > 0; len--)",
+	"	{	h  += get16bits(s);",
+	"        	tmp = (get16bits(s+2) << 11) ^ h;",
+	"        	h   = (h << 16) ^ tmp;",
+	"        	s  += 2*sizeof(uint16_t);",
+	"		h  += h >> 11;",
+	"	}",
+	"	switch (rem) {",
+	"	case 3: h += get16bits(s);",
+	"		h ^= h << 16;",
+	"		h ^= s[sizeof(uint16_t)] << 18;",
+	"		h += h >> 11;",
+	"		break;",
+	"	case 2: h += get16bits(s);",
+	"		h ^= h << 11;",
+	"		h += h >> 17;",
+	"		break;",
+	"	case 1: h += *s;",
+	"		h ^= h << 10;",
+	"		h += h >> 1;",
+	"		break;",
+	"	}",
+	"	h ^= h << 3;",
+	"	h += h >> 5;",
+	"	h ^= h << 4;",
+	"	h += h >> 17;",
+	"	h ^= h << 25;",
+	"	h += h >> 6;",
+	"",
+	"	K1 = h;",
+	"}",
+	"",
+	"#if WS>4",
+	"/* 64-bit Jenkins hash, 1997",
+	" * 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);  \\",
@@ -3082,66 +4758,242 @@
 	"  b -= c; b -= a; b ^= (a<<18); \\",
 	"  c -= a; c -= b; c ^= (b>>22); \\",
 	"}",
-"#else",
+	"#else",
+	"/* 32-bit Jenkins hash, 2006",
+	" * http://burtleburtle.net/bob/c/lookup3.c",
+	" */",
+	"#define rot(x,k)	(((x)<<(k))|((x)>>(32-(k))))",
+	"",
 	"#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;",
-	"",
+	"{ a -= c;  a ^= rot(c, 4);  c += b; \\",
+	"  b -= a;  b ^= rot(a, 6);  a += c; \\",
+	"  c -= b;  c ^= rot(b, 8);  b += a; \\",
+	"  a -= c;  a ^= rot(c,16);  c += b; \\",
+	"  b -= a;  b ^= rot(a,19);  a += c; \\",
+	"  c -= b;  c ^= rot(b, 4);  b += a; \\",
+	"}",
+	"",
+	"#define final(a,b,c) \\",
+	"{ c ^= b; c -= rot(b,14); \\",
+	"  a ^= c; a -= rot(c,11); \\",
+	"  b ^= a; b -= rot(a,25); \\",
+	"  c ^= b; c -= rot(b,16); \\",
+	"  a ^= c; a -= rot(c,4);  \\",
+	"  b ^= a; b -= rot(a,14); \\",
+	"  c ^= b; c -= rot(b,24); \\",
+	"}",
+	"#endif",
+	"",
+	"void",
+	"d_hash(uchar *kb, int nbytes)", /* sets two 64-bit or 32-bit nrs, depending on WS */
+	"{	uint8_t  *bp;",
+	"#if WS>4",
+	"	uint64_t a = 0, b, c, n;",
+	"	const uint64_t *k = (uint64_t *) kb;",
+	"#else",
+	"	uint32_t a = 0, b, c, n;",
+	"	const uint32_t *k = (uint32_t *) kb;",
+	"#endif",
+	"	n = nbytes/WS;	/* nr of words */",
+	"	/* extend to multiple of words, if needed */",
+	"	a = WS - (nbytes %% WS);",
+	"	if (a > 0 && a < WS)",
+	"	{	n++;",
+	"		bp = kb + nbytes;",
+	"		switch (a) {",
+	"#if WS>4",
+	"		case 7: *bp++ = 0; /* fall thru */",
+	"		case 6: *bp++ = 0; /* fall thru */",
+	"		case 5: *bp++ = 0; /* fall thru */",
+	"		case 4: *bp++ = 0; /* fall thru */",
+	"#endif",
+	"		case 3: *bp++ = 0; /* fall thru */",
+	"		case 2: *bp++ = 0; /* fall thru */",
+	"		case 1: *bp   = 0;",
+	"		case 0: break;",
+	"	}	}",
+	"#if WS>4",
 	"	b = HASH_CONST[HASH_NR];",
-	"	while (len >= 3)",
+	"	c = 0x9e3779b97f4a7c13LL; /* arbitrary value */",
+	"	while (n >= 3)",
 	"	{	a += k[0];",
 	"		b += k[1];",
 	"		c += k[2];",
 	"		mix(a,b,c);",
-	"		k += 3; len -= 3;",
-	"	}",
-	"	c += length;",
-	"	switch (len) {",
+	"		n -= 3;",
+	"		k += 3;",
+	"	}",
+	"	c += (((uint64_t) nbytes)<<3);",
+	"	switch (n) {",
 	"	case 2: b += k[1];",
 	"	case 1: a += k[0];",
+	"	case 0: break;",
 	"	}",
 	"	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 */",
+	"#else", /* 32 bit version: */
+	"	a = c = 0xdeadbeef + (n<<2);",
+	"	b = HASH_CONST[HASH_NR];",
+	"	while (n > 3)",
+	"	{	a += k[0];",
+	"		b += k[1];",
+	"		c += k[2];",
+	"		mix(a,b,c);",
+	"		n -= 3;",
+	"		k += 3;",
+	"	}",
+	"	switch (n) { ",
+	"	case 3: c += k[2];",
+	"	case 2: b += k[1];",
+	"	case 1: a += k[0];",
+	"		final(a,b,c);",
+	"	case 0: break;",
+	"	}",
+	"#endif",
+	"	j1_spin = c&nmask; j3_spin = a&7; /* 1st bit */",
+	"	j2_spin = b&nmask; j4_spin = (a>>3)&7; /* 2nd bit */",
+	"	K1 = c; K2 = b;",
+	"}",
+	"",
+	"#if defined(MURMUR) && (WS==8)",
+	"/* public-domain, 64-bit MurmurHash3, by Austin Appleby */",
+	"/*  https://code.google.com/p/smhasher/wiki/MurmurHash3 */",
+	"void",
+	"m_hash(uchar *v, int len)",
+	"{	uint8_t *bp, *data = (uint8_t*) v;",
+	"	int i, nblocks = len / 16;",
+	"",
+	"	uint64_t h1 = HASH_CONST[HASH_NR];",
+	"	uint64_t h2 = 0x9e3779b97f4a7c13LL;",
+	"",
+	"	uint64_t c1 = 0x87c37b91114253d5;",
+	"	uint64_t c2 = 0x4cf5ad432745937f;",
+	"",
+	"	uint64_t *blocks = (uint64_t *)(data);",
+	"",
+	"	/* guarantee a multiple of 16 bytes */",
+	"	i = 16 - (len %% 16);",
+	"	if (i > 0 && i < 16)",
+	"	{	nblocks++;",
+	"		bp = v + len;",
+	"		switch (i) {",
+	"		case 15: *bp++ = 0; /* fall thru */",
+	"		case 14: *bp++ = 0;",
+	"		case 13: *bp++ = 0;",
+	"		case 12: *bp++ = 0;",
+	"		case 11: *bp++ = 0;",
+	"		case 10: *bp++ = 0;",
+	"		case  9: *bp++ = 0;",
+	"		case  8: *bp++ = 0;",
+	"		case  7: *bp++ = 0;",
+	"		case  6: *bp++ = 0;",
+	"		case  5: *bp++ = 0;",
+	"		case  4: *bp++ = 0;",
+	"		case  3: *bp++ = 0;",
+	"		case  2: *bp++ = 0;",
+	"		case  1: *bp   = 0;",
+	"		case  0: break;",
+	"       }       }",
+	"",
+	"	for (i = 0; i < nblocks; i++)",
+	"	{	uint64_t k1 = blocks[i*2];",
+	"		uint64_t k2 = blocks[i*2+1];",
+	"",
+	"		k1 *= c1;",
+	"		k1 = (k1 << 31) | (k1 >> 33);",
+	"		k1 *= c2;",
+	"		h1 ^= k1;",
+	"",
+	"		h1 = (h1 << 27) | (h1 >> 37);",
+	"		h1 += h2;",
+	"		h1 = h1 * 5 + 0x52dce729;",
+	"",
+	"		k2 *= c2;",
+	"		k2 = (k2 << 33) | (k2 >> 31);",
+	"		k2 *= c1;",
+	"		h2 ^= k2;",
+	"",
+	"		h2 = (h2 << 31) | (h2 >> 33);",
+	"		h2 += h1;",
+	"		h2 = h2 * 5 + 0x38495ab5;",
+	"	}",
+	"",
+	"	uint8_t *tail = (uint8_t*)(data + (nblocks * 16));",
+	"",
+	"	uint64_t k1 = 0;",
+	"	uint64_t k2 = 0;",
+	"",
+	"	switch(len & 15) {",
+	"	case 15: k2 ^= ((uint64_t) tail[14]) << 48; break;",
+	"	case 14: k2 ^= ((uint64_t) tail[13]) << 40; break;",
+	"	case 13: k2 ^= ((uint64_t) tail[12]) << 32; break;",
+	"	case 12: k2 ^= ((uint64_t) tail[11]) << 24; break;",
+	"	case 11: k2 ^= ((uint64_t) tail[10]) << 16; break;",
+	"	case 10: k2 ^= ((uint64_t) tail[ 9]) << 8; break;",
+	"	case  9: k2 ^= ((uint64_t) tail[ 8]) << 0; break;",
+	"		 k2 *= c2;",
+	"		 k2 = (k2 << 33) | (k2 >> 31);",
+	"		 k2 *= c1;",
+	"		 h2 ^= k2; break;",
+	"	case  8: k1 ^= ((uint64_t) tail[7]) << 56; break;",
+	"	case  7: k1 ^= ((uint64_t) tail[6]) << 48; break;",
+	"	case  6: k1 ^= ((uint64_t) tail[5]) << 40; break;",
+	"	case  5: k1 ^= ((uint64_t) tail[4]) << 32; break;",
+	"	case  4: k1 ^= ((uint64_t) tail[3]) << 24; break;",
+	"	case  3: k1 ^= ((uint64_t) tail[2]) << 16; break;",
+	"	case  2: k1 ^= ((uint64_t) tail[1]) << 8; break;",
+	"	case  1: k1 ^= ((uint64_t) tail[0]) << 0; break;",
+	"		 k1 *= c1;",
+	"		 k1 = (k1 << 31) | (k1 >> 33);",
+	"		 k1 *= c2;",
+	"		 h1 ^= k1;",
+	"	};",
+	"",
+	"	h1 ^= len; h2 ^= len;",
+	"	h1 += h2;",
+	"	h2 += h1;",
+	"	h1 ^= h1 >> 33;",
+	"	h1 *= 0xff51afd7ed558ccd;",
+	"	h1 ^= h1 >> 33;",
+	"	h1 *= 0xc4ceb9fe1a85ec53;",
+	"	h1 ^= h1 >> 33;",
+	"	h2 ^= h2 >> 33;",
+	"	h2 *= 0xff51afd7ed558ccd;",
+	"	h2 ^= h2 >> 33;",
+	"	h2 *= 0xc4ceb9fe1a85ec53;",
+	"	h2 ^= h2 >> 33;",
+	"	h1 += h2;",
+	"	h2 += h1;",
+	"",
+	"	j1_spin = h1&nmask; j3_spin = (h1>>48)&7;",
+	"	j2_spin = h2&nmask; j4_spin = (h2>>48)&7;",
+	"	K1 = h1; K2 = h2;",
+	"}",
+	"#endif",
+	"",
+	"void",
+	"s_hash(uchar *cp, int om)",	/* uses either d_sfh (1x32bit), or d_hash (2x64bit) */
+	"{",				/* depending on ssize ie the -w parameter */
+	"	hasher(cp, om);		/* sets K1 */",
 	"#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;",
+	"		j1_spin = K1 %% omaxdepth;",
+	"	else",
+	"#endif",
+	"	if (ssize < 8*WS)",
+	"		j1_spin = K1&mask;",
+	"	else",
+	"		j1_spin = K1;",
 	"}",
 	"#ifndef RANDSTOR",
 	"int *prerand;",
 	"void",
 	"inirand(void)",
 	"{	int i;",
-	"	srand(123);	/* fixed startpoint */",
+	"	srand(s_rand+HASH_NR);",	/* inirand */
 	"	prerand = (int *) emalloc((omaxdepth+3)*sizeof(int));",
 	"	for (i = 0; i < omaxdepth+3; i++)",
-	"		prerand[i] = rand();",
+	"	{	prerand[i] = rand();",
+	"	}",
 	"}",
 	"int",
 	"pan_rand(void)",
@@ -3150,28 +5002,271 @@
 	"}",
 	"#endif",
 	"",
+	"void",
+	"set_masks(void)",
+	"{",
+	"	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 = ((ONE_L<<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\", (long int) WS);",
+	"		exit(1);",
+	"	} else	/* WS == 4 and ssize < 32 */",
+	"	{	mask = ((ONE_L<<ssize)-1);	/* hash init */",
+	"		nmask = (mask>>3);",
+	"	}",
+	"}",
+	"",
+	"#if defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(MA)",
+	"#if NCORE>1",
+	"	#error cannot combine AUTO_RESIZE with NCORE>1",
+	"#endif",
+	"static long reclaim_size;",
+	"static char *reclaim_mem;",
+	"static H_el **N_tab;",
+	"void",
+	"reverse_capture(H_el *p)",
+	"{	if (!p) return;",
+	"	reverse_capture(p->nxt);",
+	"	/* last element of list moves first */",
+	"	/* to preserve list-order */",
+	"	j2_spin = p->m_K1;",
+	"	if (ssize < 8*WS) /* probably always true */",
+	"	{	j2_spin &= mask;",
+	"	}",
+	"	p->nxt = N_tab[j2_spin];",
+	"	N_tab[j2_spin] = p;",
+	"}",
+	"void",
+	"resize_hashtable(void)",
+	"{",
+	"#ifndef BFS_PAR",	/* ssize and mask/nmask are not in shared mem */
+	"	if (WS == 4 && ssize >= 27 - 1)",
+	"#endif",
+	"	{	return;	/* cannot increase further */",
+	"	}",
+	"",
+	"	ssize += 2; /* 4x size @htable ssize */",
+	"",
+	"	printf(\"pan: resizing hashtable to -w%%d.. \", ssize);",
+	"",
+	"	N_tab = (H_el **) emalloc((ONE_L<<ssize)*sizeof(H_el *));",
+	"	set_masks();	/* they changed */",
+	"",
+	"	for (j1_spin = 0; j1_spin < (ONE_L << (ssize - 2)); j1_spin++)",
+	"	{	reverse_capture(H_tab[j1_spin]);",
+	"	}",
+	"	reclaim_mem = (char *) H_tab;",
+	"	reclaim_size = (ONE_L << (ssize - 2));",
+	"	H_tab = N_tab;",
+	"",
+	"	printf(\" done\\n\");",
+	"}",
+	"#endif",
+	"#if defined(ZAPH) && defined(BITSTATE)",
+	"void",
+	"zap_hashtable(void)",
+	"{	cpu_printf(\"pan: resetting hashtable\\n\");",
+	"	if (udmem)",
+	"	{	memset(SS, 0, udmem);",
+	"	} else",
+	"	{	memset(SS, 0, ONE_L<<(ssize-3));",
+	"	}",
+	"}",
+	"#endif",
+	"",
+	"#if NCLAIMS>1",
+	"int",
+	"find_claim(char *s)",
+	"{	int i, j;",
+	"	for (i = 0; strncmp(procname[i], \":np_:\", 5) != 0; i++)",
+	"	{	if (strcmp(s, procname[i]) == 0)",
+	"		{	for (j = 0; j < NCLAIMS; j++)",
+	"			{	if (spin_c_typ[j] == i)",
+	"				{	return j;",
+	"			}	}",
+	"			break;",
+	"	}	}",
+	"	printf(\"pan: error: cannot find claim '%%s'\\n\", s);",
+	"	exit(1);",
+	"	return -1; /* unreachable */",
+	"}",
+	"#endif",
+	"",
+	"#if defined(BFS_PAR) && defined(BFS_SEP_HASH)",
+	"int	/* to avoid having to include <math.h> and compile with -lm */",
+	"blog2(int n)	/* n >= 1 */",
+	"{	int m=1, r=2;",
+	"	if (n == 1) { return 0; }",
+	"	if (n == 2) { return 1; }",
+	"	while (n > r) { m++; r *= 2; }",
+	"	return m;",
+	"}",
+	"#endif",
+	"",
+	"uint pp[33];",
+	"",
+	"uint ",
+	"mul(uint a, uint b, uint p)",
+	"{	int c = 0;",
+	"	while (a)",
+	"	{	if (a&1)",
+	"		{	a ^= 1;",
+	"			c ^= b;",
+	"		}",
+	"		a = (a>>1);",
+	"		if (b & 0x80000000)",
+	"		{	b += b;",
+	"			b ^= p;",
+	"		} else",
+	"		{	b += b;",
+	"	}	}",
+	"	return c;",
+	"}",
+	"",
+	"uint",
+	"ppow(int n, uint p)",
+	"{	uint t = 1; int i;",
+	"	for (i = 0; i < 32; i++)",
+	"	{	if (n & (1<<i))",
+	"		{	t = mul(t, pp[i], p);",
+	"	}	}",
+	"	return t;",
+	"}",
+	"",
+	"void",
+	"hashgen(void)	/* courtesy Jim Reeds, 1995 */",
+	"{	uint x, y, p; int i, cnt;",
+	"	int ff[5] = { 3, 5, 17, 257, 65537 };",
+	"	int nn[5];",
+	"",
+	"	srand(s_rand);	/* was: srandom(s_rand) */",
+	"	nn[0] = ff[1]*ff[2]*ff[3]*ff[4];",
+	"	nn[1] = ff[0]*ff[2]*ff[3]*ff[4];",
+	"	nn[2] = ff[0]*ff[1]*ff[3]*ff[4];",
+	"	nn[3] = ff[0]*ff[1]*ff[2]*ff[4];",
+	"	nn[4] = ff[0]*ff[1]*ff[2]*ff[3];",
+	"	for (cnt = 0; cnt < 5000; cnt++)",
+	"	{	x = 2;",
+	"		p = ((rand()<<13)^rand()) | 1; /* used random() before */",
+	"		pp[0] = x;",
+	"		for (i = 0; i < 32; i++)",
+	"		{	pp[i+1] = mul(pp[i], pp[i], p);",
+	"		}",
+	"		if (pp[32] == x)",
+	"		{	for (i = 0; i < 5; i++)",
+	"			{	y = ppow(nn[i], p);",
+	"				if (y == 1)",
+	"				{	break;",
+	"			}	}",
+	"			if (y != 1)",
+	"			{	HASH_CONST[0] = p;", /* 32 bit */
+	"				if (verbose)",
+	"				{	printf(\"polynomial: 0x%%.8x (%%d tries)\\n\",",
+	"						p, cnt);",
+	"				}",
+	"				return;", /* success */
+	"	}	}	}",
+	"	fprintf(efd, \"pan: could not find a polynomial in %%d tries\\n\", cnt);",
+	"	fprintf(efd, \"pan: try a different seed with -RSn\\n\");",
+	"	exit(1);",
+	"}",
+	"",
 	"int",
 	"main(int argc, char *argv[])",
 	"{	void to_compile(void);\n",
 	"	efd = stderr;	/* default */",
-	"#ifdef BITSTATE",
-	"	bstore = bstore_reg; /* default */",
+	"#if defined(BFS_PAR) && defined(BFS_SEP_HASH)",
+	"	uchar used_w = 0;",
+	"#endif",
+	"	if (G_long != sizeof(long)",
+	"	||  G_int  != sizeof(int))",
+	"	{	printf(\"spin: error, the version of spin \");",
+	"		printf(\"that generated this pan.c assumed a different \");",
+	"		printf(\"wordsize (%%d iso %%d)\\n\", G_long, (int) sizeof(long));",
+	"		exit(1);",
+	"	}",
+	"",
+	"#if defined(T_RAND) && (T_RAND>0)",
+	"	s_rand = T_RAND;", /* so that -RS can override */
+	"#elif defined(P_RAND) && (P_RAND>0)",
+	"	s_rand = P_RAND;",
+	"#endif",
+	"",
+	"#ifdef PUTPID",
+	"	{	char *ptr = strrchr(argv[0], '/');",
+	"		if (ptr == NULL)",
+	"		{	ptr = argv[0];",
+	"		} else",
+	"		{	ptr++;",
+	"		}",
+	"		progname = emalloc(strlen(ptr));",
+	"		strcpy(progname, ptr);",
+	"		/* printf(\"progname: %%s\\n\", progname); */",
+	"	}",
+	"#endif",
+	"",
+	"#ifdef BITSTATE",
+	"	b_store = bstore_reg; /* default */",
+	"#endif",
+	"#if NCORE>1",
+	"	{	int i, j;",
+	"		strcpy(o_cmdline, \"\");",
+	"		for (j = 1; j < argc; j++)",
+	"		{	strcat(o_cmdline, argv[j]);",
+	"			strcat(o_cmdline, \" \");",
+	"		}",
+	"		/* printf(\"Command Line: %%s\\n\", o_cmdline); */",
+	"		if (strlen(o_cmdline) >= sizeof(o_cmdline))",
+	"		{	Uerror(\"option list too long\");",
+	"	}	}",
 	"#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",
+	"	#ifdef NP",
+	"		case 'a': fprintf(efd, \"warning: -a is disabled by -DNP, ignored\");",
+	"			  break;",
+	"	#else",
 	"		case 'a': a_cycles = 1; break;",
-		"#endif",
+	"	#endif",
+	"#else",
+	"	#if defined(BFS_PAR) && defined(L_BOUND)",
+	"		case 'a': if (isdigit(argv[1][2]))",
+	"			  {	L_bound = atoi(&argv[1][2]);",
+	"				if (L_bound < 1 || L_bound > 255)",
+	"				{	printf(\"usage: -aN with 0<N<256\\n\");",
+	"					exit(1);",
+	"			  }	}",
+	"			  break;",
+	"	#endif",
 	"#endif",
 	"		case 'A': noasserts = 1; break;",
 	"		case 'b': bounded = 1; break;",
-	"		case 'c': upto  = atoi(&argv[1][2]); break;",
+	"#ifdef HAS_CODE",
+	"	#if HAS_CODE>0",
+	"		case 'C': coltrace = 1; goto samething;",
+	"	#endif",
+	"#endif",
+	"		case 'c': upto = atoi(&argv[1][2]); break;",
+	"		case 'D': dodot++; state_tables++; break;",
 	"		case 'd': state_tables++; break;",
-	"		case 'e': every_error = 1; Nr_Trails = 1; break;",
+	"		case 'e': every_error = 1; upto = 0; Nr_Trails = 1; break;",
 	"		case 'E': noends = 1; break;",
 	"#ifdef SC",
 	"		case 'F': if (strlen(argv[1]) > 2)",
@@ -3181,23 +5276,57 @@
 	"#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;",
+	"#ifdef HAS_CODE",
+	"	#if HAS_CODE>0",
+	"		case 'g': gui = 1; goto samething;",
+	"	#endif",
+	"#endif",
+	"		case 'h':",
+	"			  if (strncmp(&argv[1][1], \"hash\", strlen(\"hash\")) == 0)",
+	"			  {	do_hashgen = 1;",
+	"				break;",
+	"			  }",
+	"			  if (!argv[1][2] || !isdigit((int) argv[1][2]))",
+	"			  {	usage(efd);	/* exits */",
+	"			  }",
+	"			  HASH_NR = atoi(&argv[1][2])%%(sizeof(HASH_CONST)/sizeof(uint));",
+	"			  break;",
 	"		case 'I': iterative = 2; every_error = 1; break;",
-	"		case 'i': iterative = 1; every_error = 1; break;",
+	"		case 'i':",
+	"			  if (strncmp(&argv[1][1], \"i_reverse\", strlen(\"i_reverse\")) == 0)",
+	"			  {	reversing |= 1;",
+	"			  } else",
+	"			  {	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",
+	"#ifdef BCS",
+	"		case 'L':",
+	"			sched_max = atoi(&argv[1][2]);",
+	"			if (sched_max > 255)	/* stored as one byte */",
+	"			{	fprintf(efd, \"warning: using max bound (255)\\n\");",
+	"				sched_max = 255;",
+	"			}",
+	"	#ifndef NOREDUCE",
+	"			if (sched_max == 0)",
+	"			{	fprintf(efd, \"warning: with (default) bound -L0, \");",
+	"				fprintf(efd, \"using -DNOREDUCE performs better\\n\");",
+	"			}",
+	"	#endif",
+	"			break;",
+	"#endif",
 	"#ifndef SAFETY",
 		"#ifdef NP",
 	"		case 'l': a_cycles = 1; break;",
 		"#else",
-	"		case 'l': fprintf(efd, \"error: -l disabled\");",
+	"		case 'l': fprintf(efd, \"error: -l not available (compile with -DNP)\");",
 	"			  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;",
@@ -3206,66 +5335,344 @@
 	"			  fprintf(stderr, \"-M and -G affect only -DBITSTATE\\n\");",
 	"			  break;",
 	"#endif",
-#endif
 	"		case 'm': maxdepth = atoi(&argv[1][2]); break;",
+	"#ifndef NOCLAIM",
+	"		case 'N':",
+	"	#if NCLAIMS>1",
+	"			  if (isdigit((int)argv[1][2]))",
+	"			  {	whichclaim = atoi(&argv[1][2]);",
+	"			  } else if (isalpha((int)argv[1][2]))",
+	"			  {     claimname = &argv[1][2];",
+	"			  } else if (argc > 2 && argv[2][0] != '-') /* check next arg */",
+	"			  {	claimname = argv[2];",
+	"				argc--; argv++; /* skip next arg */",
+	"			  }",
+	"	#else",
+	"		#if NCLAIMS==1",
+	"			  fprintf(stderr, \"warning: only one claim defined, -N ignored\\n\");",
+	"		#else",
+	"			  fprintf(stderr, \"warning: no claims defined, -N ignored\\n\");",
+	"		#endif",
+	"			  if (!isdigit((int)argv[1][2]) && argc > 2 && argv[2][0] != '-')",
+	"			  {	argc--; argv++;",
+	"			  }",
+	"	#endif",
+	"#endif",
+	"			  break;\n",
 	"		case 'n': no_rck = 1; break;",
+	"",
+	"		case 'P':",
+	"			  if (!readtrail",
+	"			  &&  isdigit((int) argv[1][2]))", /* was argv[1][2] == '_' */
+	"			  {	int x = atoi(&argv[1][2]);",
+	"				if (x != 0 && x != 1)",
+	"				{	fprintf(efd, \"pan: bad option -P[01], ignored\\n\");",
+	"				}",
+	"				if (x == 0)",
+	"				{	reversing &= ~1;",
+	"					break;",
+	"				}",
+	"				if (x == 1)",
+	"				{	reversing |= 1;",
+	"					break;",
+	"				}",
+	"				if (verbose)",
+	"				fprintf(efd, \"pan: reversed *active* process creation %%s\\n\",",
+	"					reversing&1?\"on\":\"off\");",
+	"				break;",
+	"			  } /* else */",
+	"#ifdef HAS_CODE",
+	"	#if HAS_CODE>0",
+	"			  readtrail = 1; onlyproc = atoi(&argv[1][2]);",
+	"			  if (argc > 2 && argv[2][0] != '-') /* check next arg */",
+	"			  {	trailfilename = argv[2];",
+	"				argc--; argv++; /* skip next arg */",
+	"			  }",
+	"	#else",
+	"			  fprintf(efd, \"pan: option -P not recognized, ignored\\n\");",
+	"	#endif",
+	"#else",
+	"			  fprintf(efd, \"pan: option -P not recognized, ignored\\n\");",
+	"#endif",
+	"			  break;",
+	"",
+	"		case 'p':",
+	"	#if !defined(BFS) && !defined(BFS_PAR)",
+	"	#ifdef PERMUTED",
+	"			  if (strncmp(&argv[1][1], \"p_normal\", strlen(\"p_normal\")) == 0)",
+	"			  {	reversing &= ~2;",
+	"				break;",
+	"			  }",
+	"			  reversing |=2;",
+	"			  if (strncmp(&argv[1][1], \"p_permute\", strlen(\"p_permute\")) == 0)",
+	"			  {	p_reorder = set_permuted;",
+	"				break;",
+	"			  }",
+	"			  if (strncmp(&argv[1][1], \"p_rotate\", strlen(\"p_rotate\")) == 0)",
+	"			  {	p_reorder = set_rotated;",
+	"				if (isdigit((int) argv[1][9]))",
+	"				{	p_rotate = atoi(&argv[1][9]);",
+	"				} else",
+	"				{	p_rotate = 1;",
+	"				}",
+	"				break;",
+	"			  }",
+	"			  if (strncmp(&argv[1][1], \"p_randrot\", strlen(\"p_randrot\")) == 0)",
+	"			  {	p_reorder = set_randrot;",
+	"				break;",
+	"			  }",
+	"			  if (strncmp(&argv[1][1], \"p_reverse\", strlen(\"p_reverse\")) == 0)",
+	"			  {	p_reorder = set_reversed;",
+	"				break;",
+	"			  }",
+	"	#else",
+	"			  if (strncmp(&argv[1][1], \"p_permute\", strlen(\"p_permute\")) == 0",
+	"			  ||  strncmp(&argv[1][1], \"p_rotate\",  strlen(\"p_rotate\")) == 0",
+	"			  ||  strncmp(&argv[1][1], \"p_randrot\",  strlen(\"p_randrot\")) == 0",
+	"			  ||  strncmp(&argv[1][1], \"p_reverse\", strlen(\"p_reverse\")) == 0)",
+	"			  {	fprintf(efd, \"option %%s required compilation with -DPERMUTED\\n\",",
+	"					argv[1]);",
+	"				exit(1);",
+	"			  }",
+	"	#endif",
+	"	#endif",
 	"#ifdef SVDUMP",
-	"		case 'p': vprefix = atoi(&argv[1][2]); break;",
+	"			  vprefix = atoi(&argv[1][2]);",
+	"#else",
+	"			  fprintf(efd, \"invalid option '%%s' -- ignored\\n\", argv[1]);",
+	"#endif",
+	"			  break;",
+	"#if NCORE==1",
+	"		case 'Q': quota = (double) 60.0 * (double) atoi(&argv[1][2]);",
+	"	#ifndef FREQ",
+	"			  freq /= 10.; /* for better resolution */",
+	"	#endif",
+	"			  break;",
 	"#endif",
 	"		case 'q': strict = 1; break;",
-	"#ifdef HAS_CODE",
+	"		case 'R':",
+	"			if (argv[1][2] == 'S') /* e.g., -RS76842 */",
+	"			{	s_rand = atoi(&argv[1][3]);", /* RS */
+	"				break;",
+	"			}",
+	"#ifdef BITSTATE",
+	"			Nrun = atoi(&argv[1][2]);",
+	"			if (Nrun > 100)",
+	"			{	Nrun = 100;",
+	"			} else if (Nrun < 1)",
+	"			{	Nrun = 1;",
+	"			}",
+	"#else",
+	"			usage(efd);",
+	"			break;",
+	"#endif",
 	"		case 'r':",
+	"			  if (strncmp(&argv[1][1], \"rhash\", strlen(\"rhash\")) == 0)",
+	"			  {	if (s_rand == 12345)	/* default seed */",
+	"				{",
+	"#if defined(WIN32) || defined(WIN64)",
+	"					s_rand = (uint) clock();",
+	"#else",
+	"					struct tms dummy_tm;",
+	"					s_rand = (uint) times(&dummy_tm);",
+	"#endif",
+	"				}",
+	"				srand(s_rand++);",
+	"	#ifdef PERMUTED",
+	"			  	do_hashgen = 1;",	/* + randomize p_rotate, p_reverse, p_permute */
+	"			  	switch (rand()%%5) {",
+	"				case 0:	p_reorder = set_permuted;",
+	"					reversing |=2;",
+	"					break;",
+	"			  	case 1:	p_reorder = set_reversed;",
+	"					reversing |=2;",
+	"					break;",
+	"					/* fully randomize p_rotate: */",
+	"				case 2:	p_reorder = set_randrot;",
+	"					reversing |=2;",
+	"					break;",
+	"					/* choose once, then keep p_rotate fixed: */",
+	"				case 3: p_reorder = set_rotated;",
+	"					p_rotate = rand()%%3;",
+	"					reversing |=2;",
+	"					break;",
+	"				default: /* standard search */ break;",
+	"				}",
+	"				if (rand()%%2 == 0)",
+	"			 	{	t_reverse = 1;",
+	"				}",
+	"				break;",
+	"	#else",
+	"				fprintf(efd, \"option -rhash requires compilation with -DPERMUTED\\n\");",
+	"				exit(1);",
+	"	#endif",
+	"			  }",
+	"#if defined(HAS_CODE) && HAS_CODE>0",
 	"samething:		  readtrail = 1;",
-	"			  if (isdigit(argv[1][2]))",
+	"			  if (isdigit((int)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;",
+	"			  else if (argc > 2 && argv[2][0] != '-') /* check next arg */",
+	"			  {	trailfilename = argv[2];",
+	"				argc--; argv++; /* skip next arg */",
+	"			  }",
+	"			  break;",
+	"		case 'S': silent = 1; goto samething;",
+	"#else",
+	"			  fprintf(efd, \"options -r is for models with embedded C code\\n\");",
+	"			  break;",
+	"#endif",
+	"		case 'T':",
+	"			  if (isdigit((int) argv[1][2]))", /* was argv[1][2] == '_' */
+	"			  {	t_reverse = atoi(&argv[1][2]);",
+	"				if (verbose)",
+	"				printf(\"pan: reverse transition ordering %%s\\n\",",
+	"					t_reverse?\"on\":\"off\");",
+	"				break;",
+	"			  }",
+	"			  TMODE = 0444;",
+	"			  break;",
+	"		case 't':",
+	"			  if (strncmp(&argv[1][1], \"t_reverse\", strlen(\"t_reverse\")) == 0)",
+	"			  {	t_reverse = 1;",
+	"				break;",
+	"			  }", /* i.e., a trail prefix cannot be '_reverse' */
+	"			  if (argv[1][2])",
+	"			  {	tprefix = &argv[1][2];",
+	"			  }",
+	"			  break;",
+	"		case 'u':",
+	"	#ifdef BFS_PAR",
+	"			  ncores = atoi(&argv[1][2]);",
+	"	#endif",
+	"			  break;",
+	"		case 'V': start_timer(); printf(\"Generated by %%s\\n\", SpinVersion);",
+	"			  to_compile(); pan_exit(2); break;",
+	"		case 'v': verbose++; break;",
+	"		case 'w': ssize = atoi(&argv[1][2]);",
+	"	#if defined(BFS_PAR) && defined(BFS_SEP_HASH)",
+	"			  used_w = 1;",
+	"	#endif",
+	"			  break;",
 	"		case 'Y': signoff = 1; break;",
 	"		case 'X': efd = stdout; break;",
-	"		default : fprintf(efd, \"saw option -%%c\\n\", argv[1][1]); usage(efd); break;",
+	"		case 'x': exclusive = 1; break;",
+	"	#if NCORE>1",
+	"		/* -B ip is passthru to proxy of remote ip address: */",
+	"		case 'B': argc--; argv++; break;",
+	"		case 'Q': worker_pids[0] = atoi(&argv[1][2]); break;",
+	"		/* -Un means that the nth worker should be instantiated as a proxy */",
+	"		case 'U': proxy_pid = atoi(&argv[1][2]); break;",
+	"		/* -W means this copy is started by a cluster-server as a remote */",
+	"		/* this flag is passed to ./pan_proxy, which interprets it */",
+	"		case 'W': remote_party++; break;",
+	"		case 'Z': core_id = atoi(&argv[1][2]);",
+	"			  if (verbose)",
+	"			  { printf(\"cpu%%d: pid %%d parent %%d\\n\",",
+	"				core_id, getpid(), worker_pids[0]);",
+	"			  }",
+	"			  break;",
+	"		case 'z': z_handoff = atoi(&argv[1][2]); break;",
+	"	#else",
+	"		case 'z': break; /* ignored for single-core */",
+	"	#endif",
+	"		default : fprintf(efd, \"saw option -%%c\\n\",",
+	"				argv[1][1]); usage(efd); break;",
 	"		}",
 	"		argc--; argv++;",
 	"	}",
+	"#if defined(BFS_PAR) && defined(BFS_SEP_HASH)",
+	"	if (used_w == 0)",
+	"	{	if (ncores == 0) /* all cores used, by default */",
+	"		{	ssize -= blog2(BFS_MAXPROCS - 1);",
+	"		} else",
+	"		{	ssize -= blog2(ncores);",
+	"	}	}",
+	"#endif",
+	"	if (do_hashgen)",
+	"	{	hashgen();", /* placed here so that -RSn can appear after -hash */
+	"	}",
+	"#ifndef SAFETY",
+	"	if (fairness && !a_cycles)",
+	"	{	fprintf(efd, \"error: -f requires the use of -a or -l\\n\");", 
+	"		usage(efd);",
+	"	}",
+	"	#if ACCEPT_LAB==0",
+	"	if (a_cycles)",
+	"	{	fprintf(efd, \"warning: no accept labels are defined, \");",
+	"		fprintf(efd, \"so option -a has no effect (ignored)\\n\");",
+	"		a_cycles = 0;",
+	"	}",
+	"	#endif",
+	"#endif",
+	"",
+	"#ifdef BFS_PAR",
+	"	uerror = bfs_uerror;",
+	"	Uerror = bfs_Uerror;",
+	"#else",
+	"	uerror = dfs_uerror;",
+	"	Uerror = dfs_Uerror;",
+	"#endif",
+	"	if (ssize <= 32)	/* 6.2.0 */",
+	"	{	hasher = d_sfh;",
+	"#if !defined(BITSTATE) && defined(USE_TDH)",
+	"		o_hash = o_hash32;",
+	"#endif",
+	"	} else",
+	"	{	hasher = d_hash;",
+	"#if !defined(BITSTATE) && defined(USE_TDH)",
+	"		o_hash = o_hash64;",
+	"#endif",
+	"	}",
 	"	if (iterative && TMODE != 0666)",
 	"	{	TMODE = 0666;",
 	"		fprintf(efd, \"warning: -T ignored when -i or -I is used\\n\");",
 	"	}",
 	"#if defined(WIN32) || defined(WIN64)",
+	"	#ifndef _S_IWRITE",
+	"		#define	S_IWRITE 0000200  /* write permission, owner */",
+	"	#endif",
+	"	#ifndef _S_IREAD",
+	"		#define	S_IREAD  0000400  /* read permission, owner */",
+	"	#endif",
 	"	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",
+	"		TMODE = S_IWRITE | S_IREAD;",
+	"	else",
+	"		TMODE = S_IREAD;",
+	"#endif",
+	"#if NCORE>1",
+	"	store_proxy_pid = proxy_pid; /* for checks in mem_file() and someone_crashed() */",
+	"	if (core_id != 0) { proxy_pid = 0; }",
+	"	#ifndef SEP_STATE",
+	"	if (core_id == 0 && a_cycles)",
+	"	{	fprintf(efd, \"hint: this search may be more efficient \");",
+	"		fprintf(efd, \"if pan.c is compiled -DSEP_STATE\\n\");",
+	"	}",
+	"	#endif",
+	"	if (z_handoff < 0)",
+	"	{	z_handoff =  20; /* conservative default - for non-liveness checks */",
+	"	}",
+	"#if defined(NGQ) || defined(LWQ_FIXED)",
+	"	LWQ_SIZE = (double) (128.*1048576.);",
+	"#else",
+	"	LWQ_SIZE = (double) ( z_handoff + 2.) * (double) sizeof(SM_frame);",
+		/* the added margin of +2 is not really necessary */
+	"#endif",
+	"	#if NCORE>2",
+	"	if (a_cycles)",
+	"	{	fprintf(efd, \"warning: the intended nr of cores to be used in liveness mode is 2\\n\");",
+	"		#ifndef SEP_STATE",
+	"		fprintf(efd, \"warning: without -DSEP_STATE there is no guarantee that all liveness violations are found\\n\");",
+	"		#endif",
+	"	}",	/* it still works though, the later cores get states from the global q */
+	"	#endif",
+	"	#ifdef HAS_HIDDEN",
+	"	#error cannot use hidden variables when compiling multi-core",
+	"	#endif",
+	"#endif",
+	"#if defined(T_RAND) && defined(ELSE_IN_GUARD)",
+	"	#error cannot hide 'else' as guard in d_step, when using -DT_RAND",
+	"#endif",
+	"#ifdef BITSTATE",
 	"	if (hfns <= 0)",
 	"	{	hfns = 1;",
 	"		fprintf(efd, \"warning: using -k%%d as minimal usable value\\n\", hfns);",
@@ -3278,7 +5685,7 @@
 	"		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",
+	" *	power of 2 that can be represented in an ulong",
 	" */",
 	"	}",
 	"#else",
@@ -3297,8 +5704,8 @@
 	"	hiwater = HHH = maxdepth-10;",
 	"	DDD = HHH/2;",
 	"	if (!stackfile)",
-	"	{	stackfile = (char *) emalloc(strlen(Source)+4+1);",
-	"		sprintf(stackfile, \"%%s._s_\", Source);",
+	"	{	stackfile = (char *) emalloc(strlen(PanSource)+4+1);",
+	"		sprintf(stackfile, \"%%s._s_\", PanSource);",
 	"	}",
 	"	if (iterative)",
 	"	{	fprintf(efd, \"error: cannot use -i or -I with -DSC\\n\");",
@@ -3307,69 +5714,97 @@
 	"#endif",
 
 	"#if (defined(R_XPT) || defined(W_XPT)) && !defined(MA)",
-	"	fprintf(efd, \"error: -D?_XPT requires -DMA\\n\");",
-	"	exit(1);",
+	"	#warning -DR_XPT and -DW_XPT assume -DMA (ignored)",
 	"#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",
+	"	#ifdef SC",
+	"		#error -DBFS not compatible with -DSC",
+	"	#endif",
+	"	#ifdef HAS_LAST",
+	"		#error -DBFS not compatible with _last",
+	"	#endif",
+	"	#ifdef HAS_STACK",
+	"		#error cannot use c_track UnMatched with BFS",
+	"	#endif",
+	"	#ifdef BCS",
+	"		#error -DBFS not compatible with -DBCS",
+	"	#endif",
+	"	#ifdef REACH",
+	"		#warning -DREACH is redundant when -DBFS is used",
+	"	#endif",
+	"#endif",
+
+	"#ifdef TRIX",
+	"	#ifdef BITSTATE",
+	"		#error cannot combine -DTRIX and -DBITSTATE",
+	"	#endif",
+	"	#ifdef COLLAPSE",
+	"		#error cannot combine -DTRIX and -DCOLLAPSE",
+	"	#endif",
+	"	#ifdef MA",
+	"		#error cannot combine -DTRIX and -DMA",
+	"	#endif",
+	"	#if defined(BFS_PAR) && defined(BFS_SEP_HEAP)",
+	"		#error cannot combined -DBFS_SEP_HEAP with -DTRIX",
+	"	#endif",
+	"#endif",
+
+	"#ifdef BFS_PAR",
+	"	#ifdef NP",
+	"	#error cannot combine -DBFS_PAR and -DNP",
+	"	#undef NP",
+	"	#endif",
+	"#endif",
+
+	"#ifdef NOCLAIM",
+	"	#ifdef NP",
+	"	#warning using -DNP overrides -DNOCLAIM",
+	"	#undef NOCLAIM",
+	"	#endif",
+	"#endif",
+
+	"#ifdef BCS",
+	"	#ifdef P_RAND",
+	"		#error cannot combine -DBCS and -DP_RAND",
+	"	#endif",
+	"	#ifdef BFS",
+	"		#error cannot combine -DBCS and -DBFS",
+	"	#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",
+	"	#error to use -DPEG use: spin -o3 -a",
+	"#endif",
+	"#if defined(HC) && !defined(BFS_PAR)",
+	"	#ifdef NOCOMP",
+	"		#error cannot combine -DHC and -DNOCOMP",
+	"	#endif",
+	"	#ifdef BITSTATE",
+	"		#error cannot combine -DHC and -DBITSTATE",
+	"	#endif",
 	"#endif",
 	"#if defined(SAFETY) && defined(NP)",
-	"	fprintf(efd, \"error: cannot combine -DNP and -DSAFETY\\n\");",
-	"	pan_exit(1);",
+	"	#error cannot combine -DNP and -DBFS or -DSAFETY",
 	"#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);",
-	"	}",
+	"	#ifdef BITSTATE",
+	"		#error cannot combine -DMA and -DBITSTATE",
+	"	#endif",
+	"	#if MA <= 0",
+	"		#error usage: -DMA=N with N > 0 and N < VECTORSZ",
+	"	#endif",
 	"#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",
+	"	#ifdef BITSTATE",
+	"		#error cannot combine -DBITSTATE and -DCOLLAPSE",
+	"	#endif",
+	"	#ifdef NOCOMP",
+	"		#error cannot combine -DCOLLAPSE and -DNOCOMP",
+	"	#endif",
 	"#endif",
 	"	if (maxdepth <= 0 || ssize <= 1) usage(efd);",
 	"#if SYNC>0 && !defined(NOREDUCE)",
@@ -3382,202 +5817,147 @@
 	"	}",
 	"#endif",
 	"#if defined(REM_VARS) && !defined(NOREDUCE)",
-	"	{ fprintf(efd, \"warning: p.o. reduction not compatible with \");",
-	"	  fprintf(efd, \"remote varrefs (use -DNOREDUCE)\\n\");",
-	"	}",
+	"	#warning p.o. reduction not compatible with remote varrefs (use -DNOREDUCE)",
 	"#endif",
 	"#if defined(NOCOMP) && !defined(BITSTATE)",
 	"	if (a_cycles)",
-	"	{ fprintf(efd, \"error: -DNOCOMP voids -l and -a\\n\");",
+	"	{ fprintf(efd, \"error: use of -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",
+	"#ifdef MEMLIM",
+	"	memlim = ((double) MEMLIM) * (double) (1<<20);	/* size in Mbyte */",
+	"#endif",
+	"#if SYNC>0",
+	"	#ifdef HAS_PRIORITY",
+	"		#error use of priorities cannot be combined with rendezvous",
+	"	#elif HAS_ENABLED",
+	"		#error use of enabled() cannot be combined with rendezvous",
+	"	#endif",
+	"#endif",
+	"#ifndef NOREDUCE",
+	"	#ifdef HAS_PRIORITY",
+	"		#warning use of priorities requires -DNOREDUCE",
+	"	#elif HAS_ENABLED",
+	"		#error use of enabled() requires -DNOREDUCE",
+	"	#endif",
+	"	#ifdef HAS_PCVALUE",
+	"		#error use of pcvalue() requires -DNOREDUCE",
+	"	#endif",
+	"	#ifdef HAS_BADELSE",
+	"		#error use of 'else' combined with i/o stmnts requires -DNOREDUCE",
+	"	#endif",
+	"	#if defined(HAS_LAST) && !defined(BCS)",
+	"		#error use of _last requires -DNOREDUCE",
+	"	#endif",
 	"#endif",
 
 	"#if SYNC>0 && !defined(NOREDUCE)",
-		"#ifdef HAS_UNLESS",
+	"	#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",
+	"		#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\");",
+	"	if (!noends)",
+	"	fprintf(efd, \"warning: use of rendezvous with BFS 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\");",
+	"	{	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\");",
+	"	#warning -DREACH is voided by -DBITSTATE",
 	"#endif",
 	"#if defined(MA) && defined(REACH)",
-	"	fprintf(efd, \"warning: -DREACH voided by -DMA\\n\");",
+	"	#warning -DREACH is voided by -DMA",
 	"#endif",
 	"#if defined(FULLSTACK) && defined(CNTRSTACK)",
-	"	fprintf(efd, \"error: cannot combine\");",
-	"	fprintf(efd, \" -DFULLSTACK and -DCNTRSTACK\\n\");",
-	"	pan_exit(1);",
+	"	#error cannot combine -DFULLSTACK and -DCNTRSTACK",
 	"#endif",
 	"#if defined(VERI)",
-		"#if ACCEPT_LAB>0",
-	"#ifndef BFS",
+	"	#if ACCEPT_LAB>0",
+	"		#ifndef BFS",
+	"			if (!a_cycles",
+	"			#ifdef HAS_CODE",
+	"			&& !readtrail",
+	"			#endif",
+	"			#if NCORE>1",
+	"			&& core_id == 0",
+	"			#endif",
+	"			&& !state_tables)",
+	"			{ fprintf(efd, \"warning: never claim + accept labels \");",
+	"			  fprintf(efd, \"requires -a flag to fully verify\\n\");",
+	"			}",
+	"		#else",
+	"			if (verbose && !state_tables",
+	"			#ifdef HAS_CODE",
+	"			&& !readtrail",
+	"			#endif",
+	"			)",
+	"			{ fprintf(efd, \"warning: verification in BFS mode \");",
+	"			  fprintf(efd, \"is restricted to safety properties\\n\");",
+	"			}",
+	"		#endif",
+	"	#endif",
+	"#endif",
+	"#ifndef SAFETY",
+	"  #if 0",
 	"	if (!a_cycles",
-		"#ifdef HAS_CODE",
+	"	#ifdef HAS_CODE",
 	"	&& !readtrail",
-		"#endif",
+	"	#endif",
+	"	#if NCORE>1",
+	"	&& core_id == 0",
+	"	#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",
+	"  #endif",
+	"	#ifndef NOCOMP",
 	"	if (!a_cycles)",
-	"		S_A = 0;",
-	"	else",
+	"	{	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;",
+	"		{	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",
+	"	}	}",
+	"	#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",
+	"	set_masks();",
+	"#if defined(BFS) || defined(BFS_PAR)",
 	"	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",
+	"	trpt = &trail[0]; /* precaution -- in case uerror is called early */",
+	"#ifdef BFS",
+	"	ntrpt = trpt;",
+	"#endif",
 	"#ifdef SVDUMP",
 	"	if (vprefix > 0)",
 	"	{	char nm[64];",
-	"		sprintf(nm, \"%%s.svd\", Source);",
-	"		if ((svfd = creat(nm, 0666)) < 0)",
+	"		sprintf(nm, \"%%s.svd\", PanSource);",
+	"		if ((svfd = creat(nm, TMODE)) < 0)",
 	"		{	fprintf(efd, \"couldn't create %%s\\n\", nm);",
 	"			vprefix = 0;",
 	"	}	}",
 	"#endif",
 	"#ifdef RANDSTOR",
-	"	srand(123);",
+	"	srand(s_rand+HASH_NR);", /* main - RANDSTOR */
 	"#endif",
 	"#if SYNC>0 && ASYNC==0",
 	"	set_recvs();",
@@ -3591,6 +5971,7 @@
 	"void",
 	"usage(FILE *fd)",
 	"{",
+	"	fprintf(fd, \"%%s\\n\", SpinVersion);",
 	"	fprintf(fd, \"Valid Options are:\\n\");",
 	"#ifndef SAFETY",
 		"#ifdef NP",
@@ -3606,6 +5987,7 @@
 	"	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 in dot-format and stop\\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\");",
@@ -3615,13 +5997,18 @@
 	"#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-hN use different hash-seed N:0..499 (defaults to -h0)\\n\");",
+	"	fprintf(fd, \"\t-hash generate a random hash-polynomial for -h0 (see also -rhash)\\n\");",
+	"	fprintf(fd, \"\t      using a seed set with -RSn (default %%u)\\n\", s_rand);",
 	"	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",
+	"#ifdef BCS",
+	"	fprintf(fd, \"\t-LN set scheduling restriction to N (default 0)\\n\");",
+	"#endif",
 	"#ifndef SAFETY",
 		"#ifdef NP",
 	"	fprintf(fd, \"\t-l  find non-progress cycles\\n\");",
@@ -3631,69 +6018,83 @@
 	"	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\");",
+	"#if NCLAIMS>1",
+	"	fprintf(fd, \"\t-N cn -- use the claim named cn\\n\");",
+	"	fprintf(fd, \"\t-Nn   -- use claim number n\\n\");",
+	"#endif",
 	"	fprintf(fd, \"\t-n  no listing of unreached states\\n\");",
+	"#ifdef PERMUTED",
+	"	fprintf(fd, \"\t-p_permute randomize order in which processes are scheduled (see also -rhash)\\n\");",
+	"	fprintf(fd, \"\t-p_reverse reverse order in which processes are scheduled (see also -rhash)\\n\");",
+	"	fprintf(fd, \"\t-p_rotateN rotate by N the process scheduling order (see also -rhash)\\n\");",
+	"#endif",
 	"#ifdef SVDUMP",
 	"	fprintf(fd, \"\t-pN create svfile (save N bytes per state)\\n\");",
 	"#endif",
+	"	fprintf(fd, \"\t-QN set time-limit on execution of N minutes\\n\");",
 	"	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-r trailfilename  read and execute trail in file\\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-r -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\");",
+	"	fprintf(fd, \"\t-RSn use randomization seed n\\n\");",
+	"	fprintf(fd, \"\t-rhash use random hash-polynomial and randomly choose -p_rotateN, -p_permute, or p_reverse\\n\");",
+	"#ifdef BITSTATE",
+	"	fprintf(fd, \"\t-Rn run n times n: [1..100] using n \");",
+	"	fprintf(fd, \" different hash functions\\n\");",
 	"#endif",
 	"	fprintf(fd, \"\t-T  create trail files in read-only mode\\n\");",
+	"	fprintf(fd, \"\t-t_reverse  reverse order in which transitions are explored\\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);",
+	"	fprintf(fd, \"\t-x  do not overwrite an existing trail file\\n\");",
+	"#if NCORE>1",
+	"	fprintf(fd, \"\t-zN handoff states below depth N to 2nd cpu (multi_core)\\n\");",
+	"#endif",
+	"#ifdef HAS_CODE",
+	"	fprintf(fd, \"\\n\toptions -r, -C, -PN, -g, and -S can optionally be followed by\\n\");",
+	"	fprintf(fd, \"\ta filename argument, as in \'-r filename\', naming the trailfile\\n\");",
+	"#endif",
+	"#if NCORE>1",
+	"	multi_usage(fd);",
+	"#endif",
 	"	exit(1);",
 	"}",
 	"",
 	"char *",
-	"Malloc(unsigned long n)",
+	"Malloc(ulong n)",
 	"{	char *tmp;",
-	"#if defined(MEMCNT) || defined(MEMLIM)",
-	"	if (memcnt+ (double) n > memlim) goto err;",
-	"#endif",
-"#if 1",
+	"#ifdef MEMLIM",
+	"	if (memcnt + (double) n > memlim)",
+	"	{	printf(\"pan: reached -DMEMLIM bound\\n\");",
+	"		goto err;",
+	"	}",
+	"#endif",
 	"	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)",
+	"	{",
+	"#ifdef BFS_PAR",
+	"		Uerror(\"out of non-shared memory\");",
+	"#endif",
+	"		printf(\"pan: out of memory\\n\");",
+	"#ifdef 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);",
+	"		printf(\"\t%%g bytes limit\\n\", memlim);",
 	"#endif",
 	"#ifdef COLLAPSE",
 	"		printf(\"hint: to reduce memory, recompile with\\n\");",
@@ -3714,6 +6115,15 @@
 	"		printf(\"  -DBITSTATE # supertrace, approximation\\n\");",
 	"#endif",
 	"#endif",
+	"#if NCORE>1",
+	"	#ifdef FULL_TRAIL",
+	"		printf(\"  omit -DFULL_TRAIL or use pan -c0 to reduce memory\\n\");",
+	"	#endif",
+	"	#ifdef SEP_STATE",
+	"		printf(\"hint: to reduce memory, recompile without\\n\");",
+	"		printf(\"  -DSEP_STATE # may be faster, but uses more memory\\n\");",
+	"	#endif",
+	"#endif",
 	"		wrapup();",
 	"	}",
 	"	memcnt += (double) n;",
@@ -3723,13 +6133,13 @@
 	"#define CHUNK	(100*VECTORSZ)",
 	"",
 	"char *",
-	"emalloc(unsigned long n) /* never released or reallocated */",
+	"emalloc(ulong 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) */
+	"	if ((ulong) left < n)",	/* was: (left < (long)n) */
 	"	{       grow = (n < CHUNK) ? CHUNK : n;",
 #if 1
 	"	        have = Malloc(grow);",
@@ -3754,9 +6164,15 @@
 	"}",
 
 	"void",
-	"Uerror(char *str)",
+	"dfs_Uerror(char *str)",
 	"{	/* always fatal */",
 	"	uerror(str);",
+	"#if NCORE>1",
+	"	sudden_stop(\"Uerror\");",
+	"#endif",
+	"#ifdef BFS_PAR",
+	"	bfs_shutdown(\"Uerror\");",
+	"#endif",
 	"	wrapup();",
 	"}\n",
 	"#if defined(MA) && !defined(SAFETY)",
@@ -3775,9 +6191,14 @@
 	"	trpt = getframe(depth);",
 	"#endif",
 	"#ifdef VERBOSE",
-	"	printf(\"%%d	 State: \", depth);",
+	"	printf(\"%%ld	 State: \", depth);",
+	"#if !defined(NOCOMP) && !defined(HC)",
 	"	for (i = 0; i < vsize; i++) printf(\"%%d%%s,\",",
 	"		((char *)&now)[i], Mask[i]?\"*\":\"\");",
+	"#else",
+	"	for (i = 0; i < vsize; i++)",
+	"		printf(\"%%d,\", ((char *)&now)[i]);",
+	"#endif",
 	"	printf(\"\\n\");",
 	"#endif",
 	"#ifndef NOFAIR",
@@ -3794,7 +6215,7 @@
 	"#endif",
 	"#ifdef HAS_LAST",
 	"#ifdef VERI",
-	"	{ int d; Trail *trl;",
+	"	{ long d; Trail *trl;",
 	"	  now._last = 0;",
 	"	  for (d = 1; d < depth; d++)",
 	"	  {	trl = getframe(depth-d); /* was trl = (trpt-d); */",
@@ -3820,10 +6241,10 @@
 	"	tt = trpt->o_tt; this = pptr(II);",
 	"	_m = do_reverse(t, II, trpt->o_m);",
 	"#ifdef VERBOSE",
-	"	printf(\"%%3d: proc %%d \", depth, II);",
+	"	printf(\"%%3ld: proc %%d \", depth, II);",
 	"	printf(\"reverses %%d, %%d to %%d,\",",
 	"		t->forw, tt, t->st);",
-	"	printf(\" %%s [abit=%%d,adepth=%%d,\", ",
+	"	printf(\" %%s [abit=%%d,adepth=%%ld,\", ",
 	"		t->tp, now._a_t, A_depth);",
 	"	printf(\"tau=%%d,%%d] <unwind>\\n\", ",
 	"		trpt->tau, (trpt-1)->tau);",
@@ -3862,14 +6283,21 @@
 	"#endif",
 	"static char unwinding;",
 	"void",
-	"uerror(char *str)",
+	"dfs_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);",
+	"#if NCORE>1",
+	"	cpu_printf(\"pan:%%d: %%s (at depth %%ld)\\n\", errors+1, str,",
+	"#else",
+	"	printf(\"pan:%%d: %%s (at depth %%ld)\\n\", errors+1, str,",
+	"#endif",
+	"#if NCORE>1",
+	"		(nr_handoffs * z_handoff) + ",
+	"#endif",
+	"		((depthfound == -1)?depth:depthfound));",
 	"	strncpy(laststr, str, 254);",
 	"	errors++;",
 	"#ifdef HAS_CODE",
@@ -3891,13 +6319,16 @@
 	"			depth = od;",
 	"		}",
 	"#endif",
-"#ifdef BFS",
+	"#if NCORE>1",
+	"		writing_trail = 1;",
+	"#endif",
+	"#ifdef BFS",
 	"		if (depth > 1) trpt--;",
-	"		nuerror(str);",
+	"		nuerror();",
 	"		if (depth > 1) trpt++;",
-"#else",
+	"#else",
 	"		putrail();",
-"#endif",
+	"#endif",
 	"#if defined(MA) && !defined(SAFETY)",
 	"		if (strstr(str, \" cycle\"))",
 	"		{	if (every_error)",
@@ -3905,20 +6336,36 @@
 	"			wrapup(); /* no recovery from unwind */",
 	"		}",
 	"#endif",
+	"#if NCORE>1",
+	"		if (search_terminated != NULL)",
+	"		{	*search_terminated |= 4; /* uerror */",
+	"		}",
+	"		writing_trail = 0;",
+	"#endif",
 	"	}",
 	"	if (!is_cycle)",
 	"	{	depth--; trpt--;	/* undo */",
 	"	}",
-"#ifndef BFS",
+	"#ifndef BFS",
 	"	if (iterative != 0 && maxdepth > 0)",
-	"	{	maxdepth = (iterative == 1)?(depth-1):(depth/2);",
+	"	{	if (maxdepth > depth)",
+	"		{	maxdepth = (iterative == 1)?(depth+1):(depth/2);",
+	"		}",
 	"		warned = 1;",
 	"		printf(\"pan: reducing search depth to %%ld\\n\",",
 	"			maxdepth);",
 	"	} else",
-"#endif",
+	"#endif",
 	"	if (errors >= upto && upto != 0)",
+	"	{",
+	"#ifdef BFS_PAR",
+	"		bfs_shutdown(\"uerror\"); /* no return */",
+	"#endif",
+	"#if NCORE>1",
+	"		sudden_stop(\"uerror\");",
+	"#endif",
 	"		wrapup();",
+	"	}",
 	"	depthfound = -1;",
 	"}\n",
 	"int",
@@ -3930,13 +6377,14 @@
 	"		||  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(\"\\t%%s:%%d\", mp[j].fnm, lno);",
+	"				break;",
+	"			}",
+	"		if (j >= sizeof(mp))	/* fnm not found in list */",
+	"		{	printf(\"\\t%%s:%%d\", PanSource, lno); /* use default */",
+	"		}",
 	"		printf(\", state %%d\", i);",
 	"		if (strcmp(T->tp, \"\") != 0)",
 	"		{	char *q;",
@@ -3951,45 +6399,120 @@
 	"}\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]);",
+	"{	int i, m=0;",
+	"",
+	"	if ((enum btypes) Btypes[M] == N_CLAIM",
+	"	&& claimname != NULL && strcmp(claimname, procname[M]) != 0)",
+	"	{	return;",
+	"	}",
+	"",
+	"	switch ((enum btypes) Btypes[M]) {",
+	"	case P_PROC:",
+	"	case A_PROC:",
+	"		printf(\"unreached in proctype %%s\\n\", procname[M]);",
+	"		break;",
+	"	case I_PROC:",
+	"		printf(\"unreached in init\\n\");",
+	"		break;",
+	"	case E_TRACE:",
+	"	case N_TRACE:",
+	"	case N_CLAIM:",
+	"	default:",
+	"		printf(\"unreached in claim %%s\\n\", procname[M]);",
+	"		break;",
+	"	}",
 	"	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++;",
+	"	{	if (which[i] == 0",
+	"		&&  (mapstate[M][i] == 0",
+	"		||   which[mapstate[M][i]] == 0))",
+	"		{	m += xrefsrc((int) src[i], mp, M, i);",
+	"		} else",
+	"		{	m++;",
+	"	}	}",
 	"	printf(\"\t(%%d of %%d states)\\n\", N-1-m, N-1);",
-	"}\n",
+	"}",
+	"#if NCORE>1 && !defined(SEP_STATE)",
+	"static long rev_trail_cnt;",
+	"",
+	"#ifdef FULL_TRAIL",
+	"void",
+	"rev_trail(int fd, volatile Stack_Tree *st_tr)",
+	"{	long j; char snap[64];",
+	"",
+	"	if (!st_tr)",
+	"	{	return;",
+	"	}",
+	"	rev_trail(fd, st_tr->prv);",
+	"#ifdef VERBOSE",
+	"	printf(\"%%d (%%d) LRT [%%d,%%d] -- %%9u (root %%9u)\\n\",",
+	"		depth, rev_trail_cnt, st_tr->pr, st_tr->t_id, st_tr, stack_last[core_id]);",
+	"#endif",
+	"	if (st_tr->pr != 255)", /* still needed? */
+	"	{	sprintf(snap, \"%%ld:%%d:%%d\\n\", ",
+	"			rev_trail_cnt++, st_tr->pr, st_tr->t_id);",
+	"		j = strlen(snap);",
+	"		if (write(fd, snap, j) != j)",
+	"		{	printf(\"pan: error writing trailfile\\n\");",
+	"			close(fd);",
+	"			wrapup();",
+	"			return;",
+	"		}",
+	"	} else  /* handoff point */",
+	"	{	if (a_cycles)",
+	"		{	(void) write(fd, \"-1:-1:-1\\n\", 9);",
+	"	}	}",
+	"}",
+	"#endif", /* FULL_TRAIL */
+	"#endif", /* NCORE>1 */
+	"",
 	"void",
 	"putrail(void)",
-	"{	int fd; long i, j;",
-	"	Trail *trl;",
+	"{	int fd;",
 	"#if defined VERI || defined(MERGED)",
 	"	char snap[64];",
 	"#endif",
-	"",
+	"#if NCORE==1 || defined(SEP_STATE) || !defined(FULL_TRAIL)",
+	"	long i, j;",
+	"	Trail *trl;",
+	"#endif",
 	"	fd = make_trail();",
 	"	if (fd < 0) return;",
 	"#ifdef VERI",
-	"	sprintf(snap, \"-2:%%d:-2\\n\", VERI);",
-	"	write(fd, snap, strlen(snap));",
+	"	sprintf(snap, \"-2:%%d:-2\\n\", (uchar) ((P0 *)pptr(0))->_t);",
+	"	if (write(fd, snap, strlen(snap)) < 0) return;",
 	"#endif",
 	"#ifdef MERGED",
 	"	sprintf(snap, \"-4:-4:-4\\n\");",
-	"	write(fd, snap, strlen(snap));",
-	"#endif",
-	"	for (i = 1; i <= depth; i++)",
+	"	if (write(fd, snap, strlen(snap)) < 0) return;",
+	"#endif",
+	"#ifdef PERMUTED",
+	"	sprintf(snap, \"-5:%%d:%%d\\n\", t_reverse, reversing&2);",
+	"	if (write(fd, snap, strlen(snap)) < 0) return;",
+	"",
+	"	sprintf(snap, \"-6:%%d:%%d\\n\", p_reorder==set_permuted, p_reorder==set_reversed);",
+	"	if (write(fd, snap, strlen(snap)) < 0) return;",
+	"",
+	"	sprintf(snap, \"-7:%%d:%%d\\n\", p_reorder==set_rotated, p_rotate);",
+	"	if (write(fd, snap, strlen(snap)) < 0) return;",
+	"",
+	"	sprintf(snap, \"-8:%%d:%%d\\n\", p_reorder==set_randrot, --s_rand);",
+	"	if (write(fd, snap, strlen(snap)) < 0) return;",
+	"#endif",
+	"#if NCORE>1 && !defined(SEP_STATE) && defined(FULL_TRAIL)",
+	"	rev_trail_cnt = 1;",
+	"	enter_critical(GLOBAL_LOCK);",
+	"	 rev_trail(fd, stack_last[core_id]);",
+	"	leave_critical(GLOBAL_LOCK);",
+	"#else",
+	"	i = 1; /* trail starts at position 1 */",
+	"	#if NCORE>1 && defined(SEP_STATE)",
+	"	if (cur_Root.m_vsize > 0) { i++; depth++; }",
+	"	#endif",
+	"	for ( ; i <= depth; i++)",
 	"	{	if (i == depthfound+1)",
-	"			write(fd, \"-1:-1:-1\\n\", 9);",
+	"		{	if (write(fd, \"-1:-1:-1\\n\", 9) != 9)",
+	"			{	goto notgood;",
+	"		}	}",
 	"		trl = getframe(i);",
 	"		if (!trl->o_t) continue;",
 	"		if (trl->o_pm&128) continue;",
@@ -3997,12 +6520,16 @@
 	"			i, trl->pr, trl->o_t->t_id);",
 	"		j = strlen(snap);",
 	"		if (write(fd, snap, j) != j)",
-	"		{	printf(\"pan: error writing trailfile\\n\");",
+	"		{",
+	"notgood:		printf(\"pan: error writing trailfile\\n\");",
 	"			close(fd);",
 	"			wrapup();",
-	"		}",
-	"	}",
+	"	}	}",
+	"#endif",
 	"	close(fd);",
+	"#if NCORE>1",
+	"	cpu_printf(\"pan: wrote trailfile\\n\");",
+	"#endif",
 	"}\n",
 	"void",
 	"sv_save(void)	/* push state vector onto save stack */",
@@ -4022,13 +6549,16 @@
 	"#if SYNC",
 	"	svtack->o_boq = boq;",
 	"#endif",
+	"#ifdef TRIX",
+	"	sv_populate();",
+	"#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);",
+	"	cpu_printf(\"%%d:	sv_save\\n\", depth);",
 	"#endif",
 	"}\n",
 	"void",
@@ -4038,7 +6568,9 @@
 	"#if SYNC",
 	"	boq = svtack->o_boq;",
 	"#endif",
-
+	"#ifdef TRIX",
+	"	re_populate();",
+	"#endif",
 	"#if defined(C_States) && (HAS_TRACK==1)",
 	"#ifdef HAS_STACK",
 	"	c_unstack((uchar *) &(svtack->c_stack[0]));",
@@ -4049,78 +6581,144 @@
 	"	if (vsize != svtack->o_delta)",
 	"		Uerror(\"sv_restor\");",
 	"	if (!svtack->lst)",
-	"		Uerror(\"error: v_restor\");",
+	"		Uerror(\"error: sv_restor\");",
 	"	svtack  = svtack->lst;",
 	"#ifdef DEBUG",
-	"	printf(\"	sv_restor\\n\");",
-	"#endif",
-	"}\n",
+	"	cpu_printf(\"	sv_restor\\n\");",
+	"#endif",
+	"}",
+	"",
 	"void",
 	"p_restor(int h)",
-	"{	int i; char *z = (char *) &now;\n",
+	"{	int i;",
+	"	char *z = (char *) &now;\n",
+	"",
+	"#ifdef BFS_PAR",
+	"	bfs_prepmask(1);	/* p_restor */",
+	"#endif",
+	"#ifndef TRIX",
 	"	proc_offset[h] = stack->o_offset;",
 	"	proc_skip[h]   = (uchar) stack->o_skip;",
+	"#else",
+	"	char *oi;",
+	"	#ifdef V_TRIX",
+	"		printf(\"%%4d: p_restor %%d\\n\", depth, h);",
+	"	#endif",
+	"#endif",
 	"#ifndef XUSAFE",
 	"	p_name[h] = stack->o_name;",
 	"#endif",
-	"#ifndef NOCOMP",
+	"#ifdef TRIX",
+	"	vsize += sizeof(char *);",
+	"	#ifndef BFS",
+	"		if (processes[h] != NULL || freebodies == NULL)",
+	"		{	Uerror(\"processes error\");",
+	"		}",
+	"		processes[h] = freebodies;",
+	"		freebodies = freebodies->nxt;",
+	"		processes[h]->nxt = (TRIX_v6 *) 0;",
+	"		processes[h]->modified = 1;	/* p_restor */",
+	"	#endif",
+	"	processes[h]->parent_pid = stack->parent;",
+	"	processes[h]->psize = stack->o_delta;",
+	"	memcpy((char *)pptr(h), stack->b_ptr, stack->o_delta);",
+	"	oi = stack->b_ptr;",
+	"#else",
+	"	#if !defined(NOCOMP) && !defined(HC)",
 	"	for (i = vsize + stack->o_skip; i > vsize; i--)",
 	"		Mask[i-1] = 1; /* align */",
-	"#endif",
+	"	#endif",
 	"	vsize += stack->o_skip;",
 	"	memcpy(z+vsize, stack->body, stack->o_delta);",
 	"	vsize += stack->o_delta;",
+	"	#if !defined(NOCOMP) && !defined(HC)",
+	"		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;",
+	"	#ifdef BFS_PAR",
+	"		bfs_fixmask(1);	/* p_restor */",
+	"	#endif",
+	"#endif",
+	"	now._nr_pr += 1;",
 	"#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 */",
+	"	if (!stack->lst)",
 	"		Uerror(\"error: p_restor\");",
 	"	stack = stack->lst;",
 	"	this = pptr(h);",
 	"	while (i-- > 0)",
 	"		q_restor();",
+	"#ifdef TRIX",
+	"	re_mark_all(1);	/* p_restor - all chans move up in _ids_ */",
+	"	now._ids_[h] = oi; /* restor the original contents */",
+	"#endif",
 	"}\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",
+	"{	int h = now._nr_qs;",
+	"#ifdef TRIX",
+	"	#ifdef V_TRIX",
+	"		printf(\"%%4d: q_restor %%d\\n\", depth, h);",
+	"	#endif",
+	"	vsize += sizeof(char *);",
+	"	#ifndef BFS",
+	"		if (channels[h] != NULL || freebodies == NULL)",
+	"		{	Uerror(\"channels error\");",
+	"		}",
+	"		channels[h] = freebodies;",
+	"		freebodies = freebodies->nxt;",
+	"		channels[h]->nxt = (TRIX_v6 *) 0;",
+	"		channels[h]->modified = 1;	/* q_restor */",
+	"	#endif",
+	"	channels[h]->parent_pid = stack->parent;",
+	"	channels[h]->psize = stack->o_delta;",
+	"	memcpy((char *)qptr(h), stack->b_ptr, stack->o_delta);",
+	"	now._ids_[now._nr_pr + h] = stack->b_ptr;",
+	"#else",
+	"	char *z = (char *) &now;",
+	"	#ifndef NOCOMP",
+	"		int k, k_end;",
+	"	#endif",
+	"	#ifdef BFS_PAR",
+	"		bfs_prepmask(2);	/* q_restor */",
+	"	#endif",
+	"	q_offset[h] = stack->o_offset;",
+	"	q_skip[h]   = (uchar) stack->o_skip;",
 	"	vsize += stack->o_skip;",
 	"	memcpy(z+vsize, stack->body, stack->o_delta);",
 	"	vsize += stack->o_delta;",
+	"#endif",
+	"#ifndef XUSAFE",
+	"	q_name[h] = stack->o_name;",
+	"#endif",
 	"#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 */",
+	"#ifndef TRIX",
+	"	#if !defined(NOCOMP) && !defined(HC)",
+	"		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",
+	"	#ifdef BFS_PAR",
+	"		bfs_fixmask(2);	/* q_restor */",
+	"	#endif",
+	"#endif",
+	"	if (!stack->lst)",
 	"		Uerror(\"error: q_restor\");",
 	"	stack = stack->lst;",
 	"}",
@@ -4163,7 +6761,46 @@
 	"#ifndef NOCOMP",
 	"	int o_vsize = vsize;",
 	"#endif",
-	"	if (h+1 != (int) now._nr_pr) return 0;\n",
+	"	if (h+1 != (int) now._nr_pr)",
+	"	{	return 0;",
+	"	}",
+	"#ifdef TRIX",
+	"	#ifdef V_TRIX",
+	"		printf(\"%%4d: delproc %%d -- parent %%d\\n\", depth, h, processes[h]->parent_pid);",
+	"		if (now._nr_qs > 0)",
+	"		printf(\"	top channel: %%d -- parent %%d\\n\", now._nr_qs-1, channels[now._nr_qs-1]->parent_pid);",
+	"	#endif",
+	"	while (now._nr_qs > 0",
+	"	&&     channels[now._nr_qs-1]->parent_pid == processes[h]->parent_pid)",
+	"	{	delq(sav);",
+	"		i++;",
+	"	}",
+	"	d = processes[h]->psize;",
+	"	if (sav)",
+	"	{	if (!stack->nxt)",
+	"		{	stack->nxt = (_Stack *) emalloc(sizeof(_Stack));",
+	"			stack->nxt->lst = stack;",
+	"			smax++;",
+	"		}",
+	"		stack = stack->nxt;",
+	"	#ifndef XUSAFE",
+	"		stack->o_name   = p_name[h];",
+	"	#endif",
+	"		stack->parent   = processes[h]->parent_pid;",
+	"		stack->o_delta  = d;",
+	"		stack->o_delqs  = i;",
+	"		stack->b_ptr = now._ids_[h];", /* new 6.1 */
+	"	}",
+	"	memset((char *)pptr(h), 0, d);",
+	"	#ifndef BFS",
+	"		processes[h]->nxt = freebodies;",
+	"		freebodies = processes[h];",
+	"		processes[h] = (TRIX_v6 *) 0;",
+	"	#endif",
+	"	vsize -= sizeof(char *);",
+	"	now._nr_pr -= 1;",
+	"	re_mark_all(-1); /* delproc - all chans move down in _ids_ */",
+	"#else",
 	"	while (now._nr_qs",
 	"	&&     q_offset[now._nr_qs-1] > proc_offset[h])",
 	"	{	delq(sav);",
@@ -4172,80 +6809,116 @@
 	"	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 = (_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",
+	"	#if VECTORSZ>32000",
 	"		stack->o_skip   = (int) proc_skip[h];",
-	"#else",
+	"	#else",
 	"		stack->o_skip   = (short) proc_skip[h];",
-	"#endif",
-	"#ifndef XUSAFE",
+	"	#endif",
+	"	#ifndef XUSAFE",
 	"		stack->o_name   = p_name[h];",
-	"#endif",
+	"	#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;",
+	"	now._nr_pr -= 1;",
 	"	memset((char *)pptr(h), 0, d);",
 	"	vsize -= (int) proc_skip[h];",
+	"	#if !defined(NOCOMP) && !defined(HC)",
+	"		#ifdef BFS_PAR",
+	"			bfs_prepmask(3); /* delproc - no chance in proc_offset or proc_skip */",
+	"		#endif",
+	"		for (i = vsize; i < o_vsize; i++)",
+	"			Mask[i] = 0; /* reset */",
+	"		#ifdef BFS_PAR",
+	"			bfs_fixmask(3);	/* delproc */",
+	"		#endif",
+	"	#endif",
+	"#endif",
 	"#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;",
+	"#ifdef TRIX",
+	"	int d = channels[now._nr_qs - 1]->psize;",
+	"#else",
 	"	int d = vsize - q_offset[now._nr_qs - 1];",
+	"#endif",
 	"#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 = (_Stack *) emalloc(sizeof(_Stack));",
+	"#ifndef TRIX",
+	"			stack->nxt->body = emalloc(Maxbody * sizeof(char));",
+	"#endif",
 	"			stack->nxt->lst = stack;",
 	"			smax++;",
 	"		}",
 	"		stack = stack->nxt;",
+	"#ifdef TRIX",
+	"		stack->parent = channels[h]->parent_pid;",
+	"		stack->b_ptr = now._ids_[h];", /* new 6.1 */
+	"#else",
 	"		stack->o_offset = q_offset[h];",
-	"#if VECTORSZ>32000",
+	"	#if VECTORSZ>32000",
 	"		stack->o_skip   = (int) q_skip[h];",
-	"#else",
+	"	#else",
 	"		stack->o_skip   = (short) q_skip[h];",
-	"#endif",
-	"#ifndef XUSAFE",
+	"	#endif",
+	"#endif",
+	"	#ifndef XUSAFE",
 	"		stack->o_name   = q_name[h];",
-	"#endif",
+	"	#endif",
 	"		stack->o_delta  = d;",
+	"#ifndef TRIX",
 	"		memcpy(stack->body, (char *)qptr(h), d);",
-	"	}",
+	"#endif",
+	"	}",
+	"#ifdef TRIX",
+	"	vsize -= sizeof(char *);",
+	"	#ifdef V_TRIX",
+	"		printf(\"%%4d: delq %%d parent %%d\\n\", depth, h, channels[h]->parent_pid);",
+	"	#endif",
+	"#else",
 	"	vsize = q_offset[h];",
-	"	now._nr_qs = now._nr_qs - 1;",
+	"	vsize -= (int) q_skip[h];",
+	"	#if !defined(NOCOMP) && !defined(HC)",
+	"		#ifdef BFS_PAR",
+	"			bfs_prepmask(3); /* delq - no change in q_offset or q_skip */",
+	"		#endif",
+	"		for (k = vsize; k < o_vsize; k++)",
+	"			Mask[k] = 0; /* reset */",
+	"		#ifdef BFS_PAR",
+	"			bfs_fixmask(3);	/* delq */",
+	"		#endif",
+	"	#endif",
+	"#endif",
+	"	now._nr_qs -= 1;",
 	"	memset((char *)qptr(h), 0, d);",
-	"	vsize -= (int) q_skip[h];",
+	"#ifdef TRIX",
+	"	#ifndef BFS",
+	"		channels[h]->nxt = freebodies;",
+	"		freebodies = channels[h];",
+	"		channels[h] = (TRIX_v6 *) 0;",
+	"	#endif",
+	"#endif",
 	"#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)",
@@ -4265,7 +6938,7 @@
 	"			return 0;",
 	"	}",
 	"	if (strict) return qs_empty();",
-	"#if defined(EVENT_TRACE) && !defined(OTIM)",
+	"#if defined(EVENT_TRACE)",
 	"	if (!stopstate[EVENT_TRACE][now._event] && !a_cycles)",
 	"	{	printf(\"pan: event_trace not completed\\n\");",
 	"		return 0;",
@@ -4273,55 +6946,54 @@
 	"#endif",
 	"	return 1;",
 	"}\n",
-	"#ifndef SAFETY",
+	"#if !defined(SAFETY) && !defined(BFS)",
 	"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",
+	"	#ifndef NOFAIR",
+	"		uchar o_cnt = now._cnt[1];",
+	"	#endif",
+	"	#ifdef FULLSTACK",
+	"		#ifndef MA",
+	"			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(\"%%ld: 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",
+	"	/* 1 = 2nd DFS; (16|32) to improve hashing */",
+	"	#ifndef NOFAIR",
+	"		now._cnt[1] = now._cnt[0];",
+	"	#endif",
 	"	memcpy((char *)&A_Root, (char *)&now, vsize);",
 	"	A_depth = depthfound = depth;",
-	"	new_state();	/* start 2nd DFS */",
+
+	"	#if NCORE>1",
+	"		mem_put_acc();", /* handoff accept states */
+	"	#else",
+	"		new_state();	/* start 2nd DFS */",
+	"	#endif",
+
 	"	now._a_t = o_a_t;",
-	"#ifndef NOFAIR",
-	"	now._cnt[1] = o_cnt;",
-	"#endif",
+	"	#ifndef NOFAIR",
+	"		now._cnt[1] = o_cnt;",
+	"	#endif",
 	"	A_depth = 0; depthfound = -1;",
 		"#ifdef DEBUG",
-	"	printf(\"%%d: cycle check returns\\n\", depth);",
+	"	printf(\"%%ld: cycle check returns\\n\", depth);",
 		"#endif",
 		"#ifdef FULLSTACK",
 		"#ifndef MA",
@@ -4331,60 +7003,120 @@
 		"#endif",
 		"#endif",
 	"}",
-	"#endif\n",
+	"#endif",
+	"",
 	"#if defined(FULLSTACK) && defined(BITSTATE)",
-	"struct H_el *Free_list = (struct H_el *) 0;",
+	"H_el *Free_list = (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",
+	"{	S_Tab = (H_el **) emalloc(maxdepth*sizeof(H_el *));",
+	"}",
+	"#endif",
+
+	"#if !defined(BFS_PAR)",
+	" #if defined(FULLSTACK) && defined(BITSTATE)",
+		"H_el *",
+		"grab_state(int n)",
+		"{	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 (H_el *) emalloc(sizeof(H_el)+n-sizeof(unsigned));",
+		"}",
+	" #else",		/* !FULLSTACK || !BITSTATE */
+		"#if NCORE>1",
+			"H_el *",
+			"grab_state(int n)",
+			"{	H_el *grab_shared(int);",
+			"	return grab_shared(sizeof(H_el)+n-sizeof(unsigned));",
+			"}",
+		"#else", /* ! NCORE>1 */
+			"#ifndef AUTO_RESIZE",
+			"	#define grab_state(n) (H_el *) \\",
+			"		emalloc(sizeof(H_el)+n-sizeof(ulong));",
+			"#else",	/* AUTO_RESIZE */
+			"H_el *",
+			"grab_state(int n)",
+			"{	H_el *p;",
+			"	int cnt = sizeof(H_el)+n-sizeof(ulong);",
+			"#ifndef MA",
+			"	if (reclaim_size >= cnt+WS)",
+			"	{	if ((cnt & (WS-1)) != 0) /* alignment */",
+			"		{	cnt += WS - (cnt & (WS-1));",
+			"		}",
+			"		p = (H_el *) reclaim_mem;",
+			"		reclaim_mem  += cnt;",
+			"		reclaim_size -= cnt;",
+			"		memset(p, 0, cnt);",
+			"	} else",
+			"#endif",
+			"	{	p = (H_el *) emalloc(cnt);",
+			"	}",
+			"	return p;",
+			"}",
+			"#endif",	/* AUTO_RESIZE */
+		"#endif", 		/* NCORE>1 */
+	" #endif",			/* FULLSTACK && !BITSTATE */
+	"#else", /* BFS_PAR */
+	"	extern volatile uchar *sh_pre_malloc(ulong);",
+	"	extern volatile uchar *sh_malloc(ulong);",
+	"	H_el *",
+	"	grab_state(int n)	/* bfs_par */",
+	"	{	volatile uchar *rval = NULL;",
+	"		int m = sizeof(H_el) + n - sizeof(unsigned);",
+	"",
+	"		if (n == 0) m = m/n;",
+	"	#ifdef BFS_SEP_HASH",
+	"		rval = emalloc((ulong) m);",
+	"	#else",
+	"		rval = sh_malloc((ulong) m);",
+	"	#endif",
+	"		memset((void *) rval, 0, (size_t) m);",
+	"",
+	"		return (H_el *) rval;",
+	"	}",
+	"#endif", /* BFS_PAR */
+
 "#ifdef COLLAPSE",
-	"unsigned long",
+	"ulong",
 	"ordinal(char *v, long n, short tp)",
-	"{	struct H_el *tmp, *ntmp; long m;",
-	"	struct H_el *olst = (struct H_el *) 0;",
+	"{	H_el *tmp, *ntmp; long m;",
+	"	H_el *olst = (H_el *) 0;",
 	"	s_hash((uchar *)v, n);",
-	"	tmp = H_tab[j1];",
+
+	"#if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"	e_critical(BFS_ID);	/* bfs_par / collapse */",
+	"#endif",
+	"#if NCORE>1 && !defined(SEP_STATE)",
+	"	enter_critical(CS_ID);	/* uses spinlock - 1..128 */",
+	"#endif",
+	"	tmp = H_tab[j1_spin];",
 	"	if (!tmp)",
 	"	{	tmp = grab_state(n);",
-	"		H_tab[j1] = tmp;",
+	"		H_tab[j1_spin] = tmp;",
 	"	} else",
 	"	for ( ;; olst = tmp, tmp = tmp->nxt)",
-	"	{	m = memcmp(((char *)&(tmp->state)), v, n);",
-	"		if (n == tmp->ln)",
-	"		{",
+	"	{	if (n == tmp->ln)",
+	"		{	m = memcmp(((char *)&(tmp->state)), v, n);",
 	"			if (m == 0)",
 	"				goto done;",
 	"			if (m < 0)",
@@ -4392,7 +7124,7 @@
 	"Insert:			ntmp = grab_state(n);",
 	"				ntmp->nxt = tmp;",
 	"				if (!olst)",
-	"					H_tab[j1] = ntmp;",
+	"					H_tab[j1_spin] = ntmp;",
 	"				else",
 	"					olst->nxt = ntmp;",
 	"				tmp = ntmp;",
@@ -4410,15 +7142,38 @@
 	"		else if (!tmp->nxt)",
 	"			goto Append;",
 	"	}",
+	"#if NCORE>1 && !defined(SEP_STATE)",
+	"	enter_critical(GLOBAL_LOCK);",
+	"#endif",
+	"#ifdef BFS_PAR",
+	"	e_critical(BFS_ORD);	/* bfs_par */",
+	"#endif",
 	"	m = ++ncomps[tp];",
+	"#ifdef BFS_PAR",
+	"	x_critical(BFS_ORD);",
+	"#endif",
+	"#if NCORE>1 && !defined(SEP_STATE)",
+	"	leave_critical(GLOBAL_LOCK);",
+	"#endif",
 	"#ifdef FULLSTACK",
 	"	tmp->tagged = m;",
 	"#else",
 	"	tmp->st_id  = m;",
 	"#endif",
+	"#if defined(AUTO_RESIZE) && !defined(BITSTATE)",
+	"	tmp->m_K1 = K1;",
+	"#endif",
 	"	memcpy(((char *)&(tmp->state)), v, n);",
 	"	tmp->ln = n;",
 	"done:",
+
+	"#if NCORE>1 && !defined(SEP_STATE)",
+	"	leave_critical(CS_ID);",
+	"#endif",
+	"#if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"	x_critical(BFS_ID);",
+	"#endif",
+
 	"#ifdef FULLSTACK",
 	"	return tmp->tagged;",
 	"#else",
@@ -4430,7 +7185,7 @@
 	"compress(char *vin, int nin)	/* collapse compression */",
 	"{	char	*w, *v = (char *) &comp_now;",
 	"	int	i, j;",
-	"	unsigned long	n;",
+	"	ulong	n;",
 	"	static char	*x;",
 	"	static uchar	nbytes[513]; /* 1 + 256 + 256 */",
 	"	static unsigned	short nbytelen;",
@@ -4523,7 +7278,7 @@
 		"#if VECTORSZ<65536",
 		"	w = (char *) &(now._vsz) + sizeof(unsigned short);",
 		"#else",
-		"	w = (char *) &(now._vsz) + sizeof(unsigned long);",
+		"	w = (char *) &(now._vsz) + sizeof(ulong);",
 		"#endif",
 	"#endif",
 	"	x = scratch;",
@@ -4535,8 +7290,14 @@
 	"	else",
 	"		n = pptr(0) - (uchar *) w;",
 	"	j = w - (char *) &now;",
+	"",
+	"#if !defined(NOCOMP) && !defined(HC)",
 	"	for (i = 0; i < (int) n; i++, w++)",
 	"		if (!Mask[j++]) *x++ = *w;",
+	"#else",
+	"	memcpy(x, w, n); x += n;",
+	"#endif",
+	"",
 	"#ifndef SEPQS",
 	"	for (i = 0; i < (int) now._nr_qs; i++)",
 	"		x += col_q(i, x);",
@@ -4572,7 +7333,7 @@
 	"	return v - (char *)&comp_now;",
 	"}",
 
-"#else",
+"#else",	/* !COLLAPSE */
 "#if !defined(NOCOMP)",
 	"int",
 	"compress(char *vin, int n)	/* default compression */",
@@ -4600,11 +7361,56 @@
 	"	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;",
+	"  #ifndef NO_FAST_C", /* disable faster compress */
+	"	int r = 0, unroll = n/8;", /* most sv are much longer */
+	"	if (unroll > 0)",
+	"	{	i = 0;",
+	"		while (r++ < unroll)",
+	"		{	/* unroll 8 times, avoid ifs */",
+	"	/* 1 */		*v = *vv++; v += 1 - Mask[i++];",
+	"	/* 2 */		*v = *vv++; v += 1 - Mask[i++];",
+	"	/* 3 */		*v = *vv++; v += 1 - Mask[i++];",
+	"	/* 4 */		*v = *vv++; v += 1 - Mask[i++];",
+	"	/* 5 */		*v = *vv++; v += 1 - Mask[i++];",
+	"	/* 6 */		*v = *vv++; v += 1 - Mask[i++];",
+	"	/* 7 */		*v = *vv++; v += 1 - Mask[i++];",
+	"	/* 8 */		*v = *vv++; v += 1 - Mask[i++];",
+	"		}",
+	"		r = n - i; /* the rest, at most 7 */",
+	"		switch (r) {",
+	"		case 7: *v = *vv++; v += 1 - Mask[i++];",
+	"		case 6: *v = *vv++; v += 1 - Mask[i++];",
+	"		case 5: *v = *vv++; v += 1 - Mask[i++];",
+	"		case 4: *v = *vv++; v += 1 - Mask[i++];",
+	"		case 3: *v = *vv++; v += 1 - Mask[i++];",
+	"		case 2: *v = *vv++; v += 1 - Mask[i++];",
+	"		case 1: *v = *vv++; v += 1 - Mask[i++];",
+	"		case 0: break;",
+	"		}",
+	"		n = i = v - (char *)&comp_now; /* bytes written so far */",
+	"		r = (n+WS-1)/WS; /* in words, rounded up */",
+	"		r *= WS;	 /* total bytes to fill  */",
+	"		i = r - i;	 /* remaining bytes      */",
+	"		switch (i) {",   /* fill word */
+	"		case 7: *v++ = 0;    /* fall thru */",
+	"		case 6: *v++ = 0;",
+	"		case 5: *v++ = 0;",
+	"		case 4: *v++ = 0;",
+	"		case 3: *v++ = 0;",
+	"		case 2: *v++ = 0;",
+	"		case 1: *v++ = 0;",
+	"		case 0: break;",
+	"		default: Uerror(\"unexpected wordsize\");",
+	"		}",
+	"		v -= i;",
+	"	} else",
+	"  #endif",
+	"	{	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);",
@@ -4613,7 +7419,7 @@
 	"#endif",
 	"}",
 "#endif",
-"#endif",
+"#endif",	/* COLLAPSE */
 	"#if defined(FULLSTACK) && defined(BITSTATE)",
 "#if defined(MA)",
 	"#if !defined(onstack_now)",
@@ -4628,9 +7434,15 @@
 "#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_el *v, *w, *last = 0;",
+	"	H_el **tmp = H_tab;",
+	"	char *nv; int n, m;",
+	"	static char warned = 0;",
+	"#if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)",
+	"	uchar was_last = now._last;",
+	"	now._last = 0;",
+	"#endif",
+	"",
 	"	H_tab = S_Tab;",
 	"#ifndef NOCOMP",
 	"	nv = (char *) &comp_now;",
@@ -4648,7 +7460,7 @@
 	"	s_hash((uchar *)nv, n);",
 	"#endif",
 	"	H_tab = tmp;",
-	"	for (v = S_Tab[j1]; v; Zh++, last=v, v=v->nxt)",
+	"	for (v = S_Tab[j1_spin]; v; Zh++, last=v, v=v->nxt)",
 	"	{	m = memcmp(&(v->state), nv, n);",
 	"		if (m == 0)",
 	"			goto Found;",
@@ -4656,101 +7468,190 @@
 	"			break;",
 	"	}",
 	"/* NotFound: */",
-	"	Uerror(\"stack out of wack - zap\");",
-	"	return;",
+	"#ifndef ZAPH",
+	"	/* seen this happen, likely harmless in multicore */",
+	"	if (warned == 0)",
+	"	{	/* Uerror(\"stack out of wack - zap\"); */",
+	"		cpu_printf(\"pan: warning, stack incomplete\\n\");",
+	"		warned = 1;",
+	"	}",
+	"#endif",
+	"	goto done;",
 	"Found:",
 	"	ZAPS++;",
 	"	if (last)",
 	"		last->nxt = v->nxt;",
 	"	else",
-	"		S_Tab[j1] = v->nxt;",
+	"		S_Tab[j1_spin] = v->nxt;",
 	"	v->tagged = (unsigned) n;",
 	"#if !defined(NOREDUCE) && !defined(SAFETY)",
 	"	v->proviso = 0;",
 	"#endif",
-	"	v->nxt = last = (struct H_el *) 0;",
+	"	v->nxt = last = (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; */",
+	"			{	v->nxt = w;",
 	"				last->nxt = v;",
 	"			} else",
 	"			{	v->nxt = Free_list;",
 	"				Free_list = v;",
 	"			}",
-	"			return;",
+	"			goto done;",
 	"		}",
 	"		if (!w->nxt)",
 	"		{	w->nxt = v;",
-	"			return;",
+	"			goto done;",
 	"	}	}",
 	"	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",
+	"done:",
+	"#if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)",
+	"	now._last = was_last;",
+	"#endif",
+	"	return;",
+	"}",
+	"",
+	"#ifndef BFS_PAR",
+	"	void",
+	"	onstack_put(void)",
+	"	{	H_el **tmp = H_tab;",
+	"	#if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)",
+	"		uchar was_last = now._last;",
+	"		now._last = 0;",
+	"	#endif",
+	"		H_tab = S_Tab;",
+	"		if (h_store((char *)&now, vsize) != 0)",
+	"	#if defined(BITSTATE) && defined(LC)",
+	"			printf(\"pan: warning, double stack entry\\n\");",
+	"	#else",
+	"		#ifndef ZAPH",
+	"			Uerror(\"cannot happen - unstack_put\");",
+	"		#endif",
+	"	#endif",
+	"		H_tab = tmp;",
+	"		trpt->ostate = Lstate;",
+	"		PUT++;",
+	"	#if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)",
+	"		now._last = was_last;",
+	"	#endif",
+	"	}",
+	"	int",
+	"	onstack_now(void)",
+	"	{	H_el *tmp;",
+	"		H_el **tmp2 = H_tab;",
+	"		char *v; int n, m = 1;\n",
+	"	#if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)",
+	"		uchar was_last = now._last;",
+	"		now._last = 0;",
+	"	#endif",
+	"		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_spin]; tmp; Zn++, tmp = tmp->nxt)",
+	"		{	m = memcmp(((char *)&(tmp->state)),v,n);",
+	"			if (m <= 0)",
+	"			{	Lstate = (H_el *) tmp;	/* onstack_now */",
+	"				break;",
+	"		}	}",
+	"		PROBE++;",
+	"	#if defined(BCS) && defined(NO_LAST) && defined(HAS_LAST)",
+	"		now._last = was_last;",
+	"	#endif",
+	"		return (m == 0);",
+	"	}",
+	"#endif",	/* !BFS_PAR */
+"#endif",		/* !MA */
+	"#endif",	/* FULLSTACK && BITSTATE */
+
+	"#ifdef BITSTATE",
+	"void init_SS(ulong);",
+	"",
+	"void",
+	"sinit(void)",
+	"{",
+	"	if (udmem)",
+	"	{	udmem *= 1024L*1024L;",
+	"	#if NCORE>1",
+	"		if (!readtrail)",
+	"		{	init_SS((ulong) udmem);",
+	"		} else",
+	"	#endif",
+	"	#if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"		SS = (uchar *) sh_pre_malloc((ulong) udmem);",
+	"	#else",
+	"		SS = (uchar *) emalloc(udmem);",
+	"	#endif",
+	"		b_store = bstore_mod;",
+	"	} else",
+	"	{",
+	"	#if NCORE>1",
+	"		init_SS(ONE_L<<(ssize-3));",
+	"	#else",
+	"		#if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"			SS = (uchar *) sh_pre_malloc((ulong)(ONE_L<<(ssize-3)));",
+	"		#else",
+	"			SS = (uchar *) emalloc(ONE_L<<(ssize-3));",
+	"		#endif",
+	"	#endif",
+	"	}",
+	"}",
+	"#else",
+	" #if !defined(MA) || defined(COLLAPSE)",
+	" void",
+	" set_H_tab(void)",
+	" {",
+	"  #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"	H_tab = (H_el **) sh_pre_malloc((ulong)((ONE_L<<ssize)*sizeof(H_el *)));",
+	"  #else",
+	"	H_tab = (H_el **) emalloc((ONE_L<<ssize)*sizeof(H_el *));",
+	"  #endif",
+	" }",
+	" #endif",
 	"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",
+	"	#ifdef MA",
+	"		#ifdef R_XPT",
+	"			{	void r_xpoint(void);",
+	"				r_xpoint();",
+	"			}",
+	"		#else",
+	"			dfa_init((unsigned short) (MA+a_cycles));",
+	"			#if NCORE>1 && !defined(COLLAPSE)",
+	"			if (!readtrail)",
+	"			{	void init_HT(ulong);",
+	"				init_HT(0L);",
+	"			}",
+	"			#endif",
+	"		#endif",
+	"	#endif",
+	"	#if !defined(MA) || defined(COLLAPSE)",
+	"		#if NCORE>1 || (defined(BFS_PAR) && defined(USE_TDH) && !defined(WIN32) && !defined(WIN64))",
+	"			if (!readtrail)",
+	"			{	void init_HT(ulong);",
+	"				init_HT((ulong) (ONE_L<<ssize)*sizeof(H_el *));",
+	"			#if defined(TRIX) || (defined(BFS_PAR) && defined(COLLAPSE))",
+	"				set_H_tab(); /* need both */",
+	"			#endif",
+	"			} else",
+	"		#endif",
+	"			{	set_H_tab(); /* @htable ssize */",
+	"			}",
+	"	#endif", /* !defined(MA) || defined(COLLAPSE) */
 	"}",
 	"#endif\n",
 
@@ -4771,13 +7672,17 @@
 	"	}",
 	"#endif",
 	"#ifdef SDUMP",
-	"#ifndef NOCOMP",
 	"	printf(\"\t State: \");",
+	"#if !defined(NOCOMP) && !defined(HC)",
 	"	for (i = 0; i < vsize; i++) printf(\"%%d%%s,\",",
 	"		((char *)&now)[i], Mask[i]?\"*\":\"\");",
+	"#else",
+	"	for (i = 0; i < vsize; i++)",
+	"		printf(\"%%d,\", ((char *)&now)[i]);",
 	"#endif",
 	"	printf(\"\\n\tVector: \");",
-	"	for (i = 0; i < n; i++) printf(\"%%d,\", v[i]);",
+	"	for (i = 0; i < n; i++)",
+	"		printf(\"%%d,\", v[i]);",
 	"	printf(\"\\n\");",
 	"#endif",
 	"}",
@@ -4785,8 +7690,9 @@
 
 "#ifdef MA",
 	"int",
-	"gstore(char *vin, int nin, uchar pbit)",
+	"g_store(char *vin, int nin, uchar pbit)",
 	"{	int n, i;",
+	"	int ret_val = 1;",
 	"	uchar *v;",
 	"	static uchar Info[MA+1];",
 	"#ifndef NOCOMP",
@@ -4794,22 +7700,36 @@
 	"	v = (uchar *) &comp_now;",
 	"#else",
 	"	n = nin;",
-	"	v = vin;",
+	"	v = (uchar *) 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;",
-
+	"	if (n > (int) maxgs)",
+	"	{	maxgs = (uint) n;",
+	"	}",
 	"	for (i = 0; i < n; i++)",
-	"		Info[i] = v[i];",
+	"	{	Info[i] = v[i];",
+	"	}",
 	"	for ( ; i < MA-1; i++)",
-	"		Info[i] = 0;",
+	"	{	Info[i] = 0;",
+	"	}",
 	"	Info[MA-1] = pbit;",
 	"	if (a_cycles)	/* place _a_t at the end */",
-	"	{	Info[MA] = Info[0]; Info[0] = 0;  }",
+	"	{	Info[MA] = Info[0];",
+	"		Info[0]  = 0;",
+	"	}",
+	"",
+	"#ifdef BFS_PAR",
+	"	e_critical(BFS_STATE);	/* bfs_par / g_store */",
+	"#endif",
+	"#if NCORE>1 && !defined(SEP_STATE)",
+	"	enter_critical(GLOBAL_LOCK); /* crude, but necessary */",
+	"	/* to make this mode work, also replace emalloc with grab_shared inside store MA routines */",
+	"#endif",
+	"",
 	"	if (!dfa_store(Info))",
 	"	{	if (pbit == 0",
 	"		&& (now._a_t&1)",
@@ -4819,16 +7739,17 @@
 	"			{	Info[MA-1] = 4; /* off-stack bit */",
 	"				nShadow++;",
 	"				if (!dfa_member(MA-1))",
-	"				{",
-	"#ifdef VERBOSE",
-	"		printf(\"intersected 1st dfs stack\\n\");",
-	"#endif",
-	"					return 3;",
+	"				{	ret_val = 3;",
+	"			#ifdef VERBOSE",
+	"					printf(\"intersected 1st dfs stack\\n\");",
+	"			#endif",
+	"					goto done;",
 	"		}	}	}",
-	"#ifdef VERBOSE",
+	"		ret_val = 0;",
+	"	#ifdef VERBOSE",
 	"		printf(\"new state\\n\");",
-	"#endif",
-	"		return 0;	/* new state */",
+	"	#endif",
+	"		goto done;",
 	"	}",
 	"#ifdef FULLSTACK",
 	"	if (pbit == 0)",
@@ -4837,23 +7758,32 @@
 	"		trpt->proviso = dfa_member(MA-1);",
 	"#endif",
 	"		Info[MA-1] = 4;	/* off-stack bit */",
-	"		if (dfa_member(MA-1)) {",
-	"#ifdef VERBOSE",
+	"		if (dfa_member(MA-1))",
+	"		{	ret_val = 1; /* off-stack */",
+	"	#ifdef VERBOSE",
 	"			printf(\"old state\\n\");",
-	"#endif",
-	"			return 1; /* off-stack */",
-	"		} else {",
-	"#ifdef VERBOSE",
+	"	#endif",
+	"		} else",
+	"		{	ret_val = 2; /* on-stack */",
+	"	#ifdef VERBOSE",
 	"			printf(\"on-stack\\n\");",
-	"#endif",
-	"			return 2; /* on-stack */",
-	"		}",
-	"	}",
-	"#endif",
-	"#ifdef VERBOSE",
-	"		printf(\"old state\\n\");",
-	"#endif",
-	"	return 1;	/* old state */",
+	"	#endif",
+	"		}",
+	"		goto done;",
+	"	}",
+	"#endif",
+	"	ret_val = 1;",
+	"#ifdef VERBOSE",
+	"	printf(\"old state\\n\");",
+	"#endif",
+	"done:",
+	"#ifdef BFS_PAR",
+	"	x_critical(BFS_STATE);",
+	"#endif",
+	"#if NCORE>1 && !defined(SEP_STATE)",
+	"	leave_critical(GLOBAL_LOCK);",
+	"#endif",
+	"	return ret_val;	/* old state */",
 	"}",
 "#endif",
 
@@ -4873,34 +7803,140 @@
 	"}",
 	"#endif",
 
-	"int",
-	"hstore(char *vin, int nin)	/* hash table storage */",
-	"{	struct H_el *tmp, *ntmp, *olst = (struct H_el *) 0;",
+	"#ifdef TRIX",
+	"void",
+	"sv_populate(void)",
+	"{	int i, cnt = 0;",
+	"	TRIX_v6 **base = processes;",
+	"	int bound = now._nr_pr; /* MAXPROC+1; */",
+	"#ifdef V_TRIX",
+	"	printf(\"%%4d: sv_populate\\n\", depth);",
+	"#endif",
+	"again:",
+	"	for (i = 0; i < bound; i++)",
+	"	{	if (base[i] != NULL)",
+	"		{	H_el *tmp;",
+	"			int m, n; uchar *v;",
+	"#ifndef BFS",
+	"			if (base[i]->modified == 0)",
+	"			{	cnt++;",
+	"	#ifdef V_TRIX",
+	"				printf(\"%%4d: %%s %%d not modified\\n\",",
+	"				depth, (base == processes)?\"proc\":\"chan\", i);",
+	"	#endif",
+	"				continue;",
+	"			}",
+	"	#ifndef V_MOD",
+	"			base[i]->modified = 0;",
+	"	#endif",
+	"#endif",
+	"#ifdef TRIX_RIX",
+	"			if (base == processes)",
+	"			{	((P0 *)pptr(i))->_pid = 0;",
+	"			}",
+	"#endif",
+	"			n = base[i]->psize;",
+	"			v = base[i]->body;",
+	"			s_hash(v, n); /* sets j1_spin */",
+	"			tmp = H_tab[j1_spin];",
+	"			if (!tmp)	/* new */",
+	"			{	tmp = grab_state(n);",
+	"				H_tab[j1_spin] = tmp;",
+	"				m = 1; /* non-zero */",
+	"			} else",
+	"			{  H_el *ntmp, *olst = (H_el *) 0;",
+	"			   for (;; hcmp++, olst = tmp, tmp = tmp->nxt)",
+	"			   { 	m = memcmp(((char *)&(tmp->state)), v, n);",
+	"				if (m == 0)	/* match */",
+	"				{	break;",
+	"				} else if (m < 0) /* insert */",
+	"				{	ntmp = grab_state(n);",
+	"					ntmp->nxt = tmp;",
+	"					if (!olst)",
+	"						H_tab[j1_spin] = ntmp;",
+	"					else",
+	"						olst->nxt = ntmp;",
+	"					tmp = ntmp;",
+	"					break;",
+	"				} else if (!tmp->nxt)	/* append */",
+	"				{	tmp->nxt = grab_state(n);",
+	"					tmp = tmp->nxt;",
+	"					break;",
+	"			}  }	}",
+	"			if (m != 0)",
+	"			{	memcpy((char *)&(tmp->state), v, n);",
+	"#if defined(AUTO_RESIZE) && !defined(BITSTATE)",
+	"				tmp->m_K1 = K1; /* set via s_hash */",
+	"#endif",
+	"				if (verbose)",
+	"				{	if (base == processes)",
+	"					{	_p_count[i]++;",
+	"					} else",
+	"					{	_c_count[i]++;",
+	"			}	}	}",
+	"			now._ids_[cnt++] = (char *)&(tmp->state);",
+	"#ifdef TRIX_RIX",
+	"			if (base == processes)",
+	"			{	((P0 *)pptr(i))->_pid = i;",
+	"				if (BASE > 0 && i > 0)",
+	"				{	((P0 *)pptr(i))->_pid -= BASE;",
+	"			}	}",
+	"#endif",
+	"	}	}",
+#if 0
+	if a process appears or disappears: always secure a full sv_populate
+	(channels come and go only with a process)
+
+	only one process can disappear per step
+	but any nr of channels can be removed at the same time
+		if a process disappears, all subsequent entries
+		are then in the wrong place in the _ids_ list
+		and need to be recomputed
+	but we do not need to fill out with zeros
+		because vsize prevents them being used
+#endif
+	"	/* do the same for all channels */",
+	"	if (base == processes)",
+	"	{	base = channels;",
+	"		bound = now._nr_qs; /* MAXQ+1; */",
+	"		goto again;",
+	"	}",
+	"}",
+	"#endif\n",
+	"#if !defined(BFS_PAR) || (!defined(BITSTATE) && !defined(USE_TDH))",
+	"int",
+	"h_store(char *vin, int nin)	/* hash table storage */",
+	"{	H_el *ntmp;",
+	"	H_el *tmp, *olst = (H_el *) 0;",
 	"	char *v; int n, m=0;",
-	"#ifdef HC",
+	" #ifdef HC",
 	"	uchar rem_a;",
-	"#endif",
-	"#ifdef NOCOMP",	/* defined by BITSTATE */
-		"#if defined(BITSTATE) && defined(LC)",
+	" #endif",
+	" #ifdef TRIX",
+	"	sv_populate();	/* update proc and chan ids */",
+	" #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",
+	"	#else",
 	"	v = vin; n = nin;",
-		"#endif",
-	"#else",
+	"	#endif",
+	" #else",
 	"	v = (char *) &comp_now;",
 	"	#ifdef HC",
-	"	rem_a = now._a_t;",	/* 4.3.0 */
+	"	rem_a = now._a_t;",	/* new 5.0 */
 	"	now._a_t = 0;",	/* for hashing/state matching to work right */
 	"	#endif",
-	"	n = compress(vin, nin);", /* with HC, this calls s_hash */
+	"	n = compress(vin, nin);", /* with HC, this calls s_hash -- but on vin, not on v... */
 	"	#ifdef HC",
-	"	now._a_t = rem_a;",	/* 4.3.0 */
-	"	#endif",
+	"	now._a_t = rem_a;",	/* new 5.0 */
+	"	#endif",
+		/* with HC4 -a, compress copies K1 and K2 into v[], leaving v[0] free for the a-bit */
 		"#ifndef SAFETY",
 	"	if (S_A)",
 	"	{	v[0] = 0;	/* _a_t  */",
@@ -4911,35 +7947,53 @@
 			"#endif",
 	"		m = 0;",
 	"	}",
-		"#endif",
-	"#endif",
-	"#if !defined(HC) && !(defined(BITSTATE) && defined(LC))",
+	"	#endif",
+	" #endif",
+	" #if !defined(HC) && !(defined(BITSTATE) && defined(LC))",
 	"	s_hash((uchar *)v, n);",
-	"#endif",
-	"	tmp = H_tab[j1];",
+	" #endif",
+	"	/* for BFS_PAR we can only get here in BITSTATE mode */",
+	"	/* and in that case we don't use locks */",
+	" #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"	e_critical(BFS_ID);	/* bfs_par / h_store */",
+	" #endif",
+	" #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)",
+	"	enter_critical(CS_ID);",
+	" #endif",
+	"	tmp = H_tab[j1_spin];",
 	"	if (!tmp)",
-	"	{  tmp = grab_state(n);",
-	"	   H_tab[j1] = tmp;",
+	"	{  tmp = grab_state(n);", /* no zero-returns with bfs_par */
+	" #if NCORE>1",
+	"	   if (!tmp)",
+	"	   {	/* if we get here -- we've already issued a warning */",
+	"		/* but we want to allow the normal distributed termination */",
+	"		/* to collect the stats on all cpus in the wrapup */",
+	"	#if !defined(SEP_STATE) && !defined(BITSTATE)",
+	"		leave_critical(CS_ID);",
+	"	#endif",
+	"		return 1; /* allow normal termination */",
+	"	   }",
+	" #endif",
+	"	   H_tab[j1_spin] = tmp;",
 	"	} else",
 	"	{  for (;; hcmp++, olst = tmp, tmp = tmp->nxt)",
 	"	   {   /* skip the _a_t and the _cnt bytes */",
-	"#ifdef COLLAPSE",
+	" #ifdef COLLAPSE",
 	"		if (tmp->ln != 0)",
 	"		{	if (!tmp->nxt) goto Append;",
 	"			continue;",
 	"		}",
-	"#endif",
+	" #endif",
 	"		m = memcmp(((char *)&(tmp->state)) + S_A, ",
 	"			v + S_A, n - S_A);",
 	"		if (m == 0) {",
-	"#ifdef SAFETY",
+	" #ifdef SAFETY",
 			"#define wasnew	0",
-	"#else",
+	" #else",
 	"		int wasnew = 0;",
-	"#endif",
-
-	"#ifndef SAFETY",
-	"#ifndef NOCOMP",
+	" #endif",
+
+	" #if !defined(SAFETY) && !defined(NOCOMP)",
 	"		if (S_A)",
 	"		{ if ((((char *)&(tmp->state))[0] & V_A) != V_A)",
 	"		  {	wasnew = 1; nShadow++;",
@@ -4948,7 +8002,7 @@
 		"#ifndef NOFAIR",
 	"		  if (S_A > NFAIR)",
 	"		  {	/* 0 <= now._cnt[now._a_t&1] < MAXPROC */",
-	"			unsigned ci, bp; /* index, bit pos */",
+	"			uint 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 */",
@@ -4968,13 +8022,16 @@
 	"		   /* else: wasnew == 0, i.e., old state */",
 		"#endif",
 	"		}",
-	"#endif",
-	"#endif",
+	" #endif",
+
+	" #if NCORE>1",
+	"		Lstate = (H_el *) tmp;	/* h_store */",
+	" #endif",
 
 	"#ifdef FULLSTACK",
 		"#ifndef SAFETY",	/* or else wasnew == 0 */
 	"		if (wasnew)",
-	"		{	Lstate = (struct H_el *) tmp;",
+	"		{	Lstate = (H_el *) tmp;	/* h_store */",
 	"			tmp->tagged |= V_A;",
 	"			if ((now._a_t&1)",
 	"			&& (tmp->tagged&A_V)",
@@ -4982,22 +8039,42 @@
 	"			{",
 	"intersect:",
 		"#ifdef CHECK",
+	" #if NCORE>1",
+	"	printf(\"cpu%%d: \", core_id);",
+	" #endif",
 	"	printf(\"1st dfs-stack intersected on state %%d+\\n\",",
 	"		(int) tmp->st_id);",
 		"#endif",
+
+	" #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"				x_critical(BFS_ID);",
+	" #endif",
+	" #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)",
+	"				leave_critical(CS_ID);",
+	" #endif",
+
 	"				return 3;",
 	"			}",
 		"#ifdef CHECK",
+	" #if NCORE>1",
+	"	printf(\"cpu%%d: \", core_id);",
+	" #endif",
 	"	printf(\"\tNew state %%d+\\n\", (int) tmp->st_id);",
 		"#endif",
 		"#ifdef DEBUG",
 	"	dumpstate(1, (char *)&(tmp->state),n,tmp->tagged);",
 		"#endif",
+	" #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"			x_critical(BFS_ID);",
+	" #endif",
+	" #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)",
+	"			leave_critical(CS_ID);",
+	" #endif",
 	"			return 0;",
 	"		} else",
 		"#endif",
 	"		if ((S_A)?(tmp->tagged&V_A):tmp->tagged)",
-	"		{	Lstate = (struct H_el *) tmp;",
+	"		{	Lstate = (H_el *) tmp;	/* h_store */",
 		"#ifndef SAFETY",
 	"			/* already on current dfs stack */",
 	"			/* but may also be on 1st dfs stack */",
@@ -5014,41 +8091,110 @@
 	"				goto intersect;",
 		"#endif",
 		"#ifdef CHECK",
+	" #if NCORE>1",
+	"	printf(\"cpu%%d: \", core_id);",
+	" #endif",
 	"	printf(\"\tStack state %%d\\n\", (int) tmp->st_id);",
 		"#endif",
 		"#ifdef DEBUG",
 	"	dumpstate(0, (char *)&(tmp->state),n,tmp->tagged);",
 		"#endif",
+	" #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"			x_critical(BFS_ID);",
+	" #endif",
+	" #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)",
+	"			leave_critical(CS_ID);",
+	" #endif",
 	"			return 2; /* match on stack */",
 	"		}",
 	"#else",
 	"		if (wasnew)",
 	"		{",
 		"#ifdef CHECK",
+	" #if NCORE>1",
+	"	printf(\"cpu%%d: \", core_id);",
+	" #endif",
 	"	printf(\"\tNew state %%d+\\n\", (int) tmp->st_id);",
 		"#endif",
 		"#ifdef DEBUG",
 	"	dumpstate(1, (char *)&(tmp->state), n, 0);",
 		"#endif",
+	" #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"			x_critical(BFS_ID);",
+	" #endif",
+	" #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)",
+	"			leave_critical(CS_ID);",
+	" #endif",
 	"			return 0;",
 	"		}",
 	"#endif",
 		"#ifdef CHECK",
+	"#if NCORE>1",
+	"	printf(\"cpu%%d: \", core_id);",
+	"#endif",
 	"	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 defined(BCS)",
+	"  #ifdef CONSERVATIVE",
+	"	if (tmp->ctx_low > trpt->sched_limit)",
+	"	{	tmp->ctx_low = trpt->sched_limit;",
+	"		tmp->ctx_pid[(now._last)/8] = 1 << ((now._last)%%8); /* new */",
+	"	#ifdef CHECK",
+	"		#if NCORE>1",
+	"		printf(\"cpu%%d: \", core_id);",
+	"		#endif",
+	"		printf(\"\t\tRevisit with fewer context switches\\n\");",
+	"	#endif",
+	"		nstates--;",
+	"		#if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"		x_critical(BFS_ID);",
+	"		#endif",
+	"		#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)",
+	"		leave_critical(CS_ID);",
+	"		#endif",
+	"		return 0;",
+	"	} else if ((tmp->ctx_low == trpt->sched_limit",
+	"	&&   (tmp->ctx_pid[(now._last)/8] & ( 1 << ((now._last)%%8) )) == 0 ))",
+	"	{	tmp->ctx_pid[(now._last)/8] |= 1 << ((now._last)%%8); /* add */",
+	"	#ifdef CHECK",
+	"		#if NCORE>1",
+	"		printf(\"cpu%%d: \", core_id);",
+	"		#endif",
+	"		printf(\"\t\tRevisit with same nr of context switches\\n\");",
+	"	#endif",
+	"		nstates--;",
+	"		#if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"		x_critical(BFS_ID);",
+	"		#endif",
+	"		#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)",
+	"		leave_critical(CS_ID);",
+	"		#endif",
+	"		return 0;",
+	"	}",
+	"  #endif",
+	"#endif",
+	" #ifdef REACH",
+	"	if (tmp->D > depth)",
+	"	{	tmp->D = depth;",
+	"	#ifdef CHECK",
+	"		#if NCORE>1",
+	"		printf(\"cpu%%d: \", core_id);",
+	"		#endif",
+	"		printf(\"\t\tReVisiting (from smaller depth)\\n\");",
+	"	#endif",
+	"		nstates--;",
+	"	#if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"		x_critical(BFS_ID);",
+	"	#endif",
+	"	#if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)",
+	"		leave_critical(CS_ID);",
+	"	#endif",
 #if 0
-  possible variation of iterative search for shortest counter-example (pan -i
-  and pan -I) suggested by Pierre Moro (for safety properties):
+  a 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
@@ -5056,54 +8202,86 @@
   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 */
+   shortest counter-example - so not enabled by default)
+	"		if (errors > 0 && iterative)", /* Moro */
 #endif
-	"			return 0;",
-	"		}",
-	"#endif",
-	"#if defined(BFS) && defined(Q_PROVISO)",
-	"		Lstate = (struct H_el *) tmp;",
-	"#endif",
+	"		return 0;",
+	"	}",
+	" #endif",
+	" #if (defined(BFS) && defined(Q_PROVISO)) || NCORE>1",
+	"		Lstate = (H_el *) tmp;	/* h_store */",
+	" #endif",
+	" #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"		x_critical(BFS_ID);",
+	" #endif",
+	" #if NCORE>1 && !defined(SEP_STATE) && !defined(BITSTATE)",
+	"		leave_critical(CS_ID);",
+	" #endif",
 	"		return 1; /* match outside stack */",
 	"	       } else if (m < 0)",
 	"	       {	/* insert state before tmp */",
 	"			ntmp = grab_state(n);",
+	" #if NCORE>1",
+	"			if (!ntmp)",
+	"			{",
+	"	#if !defined(SEP_STATE) && !defined(BITSTATE)",
+	"				leave_critical(CS_ID);",
+	"	#endif",
+	"				return 1;  /* allow normal termination */",
+	"			}",
+	" #endif",
 	"			ntmp->nxt = tmp;",
 	"			if (!olst)",
-	"				H_tab[j1] = ntmp;",
+	"				H_tab[j1_spin] = ntmp;",
 	"			else",
 	"				olst->nxt = ntmp;",
 	"			tmp = ntmp;",
 	"			break;",
 	"	       } else if (!tmp->nxt)",
 	"	       {	/* append after tmp */",
-	"#ifdef COLLAPSE",
+	" #ifdef COLLAPSE",
 	"Append:",
-	"#endif",
+	" #endif",
 	"			tmp->nxt = grab_state(n);",
+	" #if NCORE>1",
+	"			if (!tmp->nxt)",
+	"			{",
+	"	#if !defined(SEP_STATE) && !defined(BITSTATE)",
+	"				leave_critical(CS_ID);",
+	"	#endif",
+	"				return 1;  /* allow normal termination */",
+	"			}",
+	" #endif",
 	"			tmp = tmp->nxt;",
 	"			break;",
 	"	   }   }",
 	"	}",
-	"#ifdef CHECK",
+	" #ifdef CHECK",
 	"	tmp->st_id = (unsigned) nstates;",
+	" #if NCORE>1",
+	"	printf(\"cpu%%d: \", core_id);",
+	" #endif",
 		"#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)",
+	" #if defined(BCS)",
+	"	tmp->ctx_low = trpt->sched_limit;",
+	"	#ifdef CONSERVATIVE",
+	"	tmp->ctx_pid[(now._last)/8] = 1 << ((now._last)%%8); /* new limit */",
+	"	#endif",
+	" #endif",
+	" #if !defined(SAFETY) || defined(REACH)",
 	"	tmp->D = depth;",
-	"#endif",
-	"#ifndef SAFETY",
-	"#ifndef NOCOMP",
+	" #endif",
+	" #if !defined(SAFETY) && !defined(NOCOMP)",
 	"	if (S_A)",
 	"	{	v[0] = V_A;",
 		"#ifndef NOFAIR",
 	"		if (S_A > NFAIR)",
-	"		{	unsigned ci, bp; /* as above */",
+	"		{	uint 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)",
@@ -5114,26 +8292,409 @@
 	"		}",
 		"#endif",
 	"	}",
-	"#endif",
-	"#endif",
+	" #endif",
+	" #if defined(AUTO_RESIZE) && !defined(BITSTATE)",
+	"	tmp->m_K1 = K1;",
+	" #endif",
 	"	memcpy(((char *)&(tmp->state)), v, n);",
-	"#ifdef FULLSTACK",
+	" #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",
+	"		dumpstate(-1, v, n, tmp->tagged);",
+		"#endif",
+	"	Lstate = (H_el *) tmp;	/* end of h_store */",
+	" #else",
+	"	#ifdef DEBUG",
+	"		dumpstate(-1, v, n, 0);",
+	"	#endif",
+	"	#if NCORE>1",
+	"		Lstate = (H_el *) tmp;	/* end of h_store */",
+	"	#endif",
+	" #endif",
+
+	" #if defined(BFS_PAR) && !defined(BFS_SEP_HASH)",
+	"		x_critical(BFS_ID);",
+	" #endif",
+	" #if NCORE>1",
+	"	#ifdef V_PROVISO",
+	"		tmp->cpu_id = core_id;",
+	"	#endif",
+	"	#if !defined(SEP_STATE) && !defined(BITSTATE)",
+	"		leave_critical(CS_ID);",
+	"	#endif",
+	" #endif",
+
 	"	return 0;",
-	"}",
-	"#endif",
+	"}",	/* end of h_store */
+	"#endif", /* !BFS_PAR || !USE_TDH */
+	"",
+	"void",
+	"o_hash32(uchar *s, int len, int h) /* 32-bit, like d_sfh, but with seed */",
+	"{       uint32_t tmp;",
+	"        int rem;",
+	"",
+	"        rem = len & 3;",
+	"        len >>= 2;",
+	"",
+	"        for ( ; len > 0; len--)",
+	"        {       h  += get16bits(s);",
+	"                tmp = (get16bits(s+2) << 11) ^ h;",
+	"                h   = (h << 16) ^ tmp;",
+	"                s  += 2*sizeof(uint16_t);",
+	"                h  += h >> 11;",
+	"        }",
+	"        switch (rem) {",
+	"        case 3: h += get16bits(s);",
+	"                h ^= h << 16;",
+	"                h ^= s[sizeof(uint16_t)] << 18;",
+	"                h += h >> 11;",
+	"                break;",
+	"        case 2: h += get16bits(s);",
+	"                h ^= h << 11;",
+	"                h += h >> 17;",
+	"                break;",
+	"        case 1: h += *s;",
+	"                h ^= h << 10;",
+	"                h += h >> 1;",
+	"                break;",
+	"        }",
+	"        h ^= h << 3;",
+	"        h += h >> 5;",
+	"        h ^= h << 4;",
+	"        h += h >> 17;",
+	"        h ^= h << 25;",
+	"        h += h >> 6;",
+	"",
+	"        K1 = h;",
+	"}",
+	"void",
+	"o_hash64(uchar *kb, int nbytes, int seed)", /* 64-bit hash */
+	"{	uint8_t  *bp;",
+	"	uint64_t a, b, c, n;",
+	"	const uint64_t *k = (uint64_t *) kb;",
+	"	n = nbytes/WS;	/* nr of 8-byte chunks */",
+	"	/* extend to multiple of words, if needed */",
+	"	a = WS - (nbytes %% WS);",
+	"	if (a > 0 && a < WS)",
+	"	{	n++;",
+	"		bp = kb + nbytes;",
+	"		switch (a) {",
+	"		case 7: *bp++ = 0; /* fall thru */",
+	"		case 6: *bp++ = 0; /* fall thru */",
+	"		case 5: *bp++ = 0; /* fall thru */",
+	"		case 4: *bp++ = 0; /* fall thru */",
+	"		case 3: *bp++ = 0; /* fall thru */",
+	"		case 2: *bp++ = 0; /* fall thru */",
+	"		case 1: *bp   = 0;",
+	"		case 0: break;",
+	"	}	}",
+	"	a = (uint64_t) seed;",
+	"	b = HASH_CONST[HASH_NR];",
+	"	c = 0x9e3779b97f4a7c13LL; /* arbitrary */",
+	"	while (n >= 3)",
+	"	{	a += k[0];",
+	"		b += k[1];",
+	"		c += k[2];",
+	"		mix(a,b,c);",
+	"		n -= 3;",
+	"		k += 3;",
+	"	}",
+	"	c += (((uint64_t) nbytes)<<3);",
+	"	switch (n) {",
+	"	case 2: b += k[1];",
+	"	case 1: a += k[0];",
+	"	case 0: break;",
+	"	}",
+	"	mix(a,b,c);",
+	"",
+	"	K1 = a;",
+	"}",
+	"",
+	"#if defined(USE_TDH) && !defined(WIN32) && !defined(WIN64)",
+#if 0
+	some problems with this storage mode:
+
+	0. pre-allocates full hash-table with slots equal to max statevector size
+	    e.g. with -w26 we allocate 2^26 (64 M) slots of VECTORSZ large
+	   which can accomodate up to 64 M states
+	   once you get close to or exceed the max, the search aborts
+	   with a 'hashtable full' message
+	   in HC mode the max storage needed per state is more modest and independent
+	   of the maximum vectorsize; which makes this mode attractive as a default
+
+	1. does not support PO reduction through the Lstate->ostate->tagged
+	   to distinguish open from closed states - this can reduce states by 50%
+	   could add this as another bit from the hash value
+	   e.g., could add it in HC mode to the first hash?
+
+	2. the same state may be stored multiple times
+#endif
+	"#ifdef HC",
+	"	#ifndef T_HC",
+	"		#ifdef BFS_HC",
+	"			#define T_HC	BFS_HC",
+	"		#else",
+	"			#define T_HC	2",
+	"		#endif",
+	"	#endif",
+	"	#if T_HC<1 || T_HC>4",
+	"		#error \"BFS_HC must be 1, 2, 3, or 4 (default is 2)\"",
+	"	#endif",
+	"#endif",
+	"",
+	"#define T_ROW     	 6", /* related to cache line size */
+	"#define T_ROW_SIZE	 (1<<T_ROW)",
+	"#define T_ROW_MASK	-(1<<T_ROW)",
+	"#define T_FREE    	 0",
+	"#define T_STAT    	 1	/* status bit */",
+	"#ifndef T_VSZ",
+	"	#define T_VSZ	VECTORSZ/4	/* compressed vectorsize */",
+	"#endif",
+	"",
+	"static volatile char     *ohash_sd;	/* state data  */",
+	"static volatile uint32_t *ohash_hv;	/* hash values */",
+	"static ulong     	   ohash_max;",
+	"static ulong    	   ohash_mask;",
+	"",
+	"#if defined(USE_TDH) && defined(Q_PROVISO)",
+	"  static volatile uchar    *ohash_inq;	/* open/closed flag BFS_INQ */",
+	"#endif",
+	"#ifdef HC",
+	"  static uint32_t	   ohash_hc[T_HC];",
+	"  static ulong		   ohash_hc_sz;",
+	"#endif",
+	"",
+	"void",
+	"init_HT(ulong x)		/* USE_TDH cygwin/linux */",
+	"{	x = x / (ulong) sizeof(H_el *);	/* room for x pointers */",
+	"	#ifdef DEBUG",
+	"	printf(\"prealloc x %%lu v %%d  x*v %%lu\\n\",",
+	"		x, T_VSZ, (ulong) (x * (ulong)T_VSZ));",
+	"	#endif",
+	"#ifndef HC",
+	"	if (!(x * (ulong) T_VSZ > x))",
+	"	{	Uerror(\"assertion x * (ulong) T_VSZ > x fails\");",
+	"	}",
+	"	#ifdef BFS_SEP_HASH",
+	"		ohash_sd   = (char *) emalloc(x * (ulong) T_VSZ);",
+	"	#else",
+	"		ohash_sd   = (volatile char *) sh_pre_malloc(x * (ulong) T_VSZ);",
+	"	#endif",
+	"#else", /* assume T_HC >= 1, and normally 2 */
+	"	ohash_hc_sz = (ulong) (T_HC * (ulong) sizeof(uint32_t));",
+	"	if (!(x * ohash_hc_sz > x))",	/* watch for overflow */
+	"	{	Uerror(\"assertion x * ohash_hc_sz > x fails\");",
+	"	}",
+	"	#ifdef BFS_SEP_HASH",
+	"		ohash_sd   = (char *) emalloc(x * ohash_hc_sz);",
+	"	#else",
+	"		ohash_sd   = (volatile char *) sh_pre_malloc(x * ohash_hc_sz);",
+	"	#endif",
+	"#endif",
+	"#ifdef BFS_SEP_HASH",
+	"	ohash_hv = (uint32_t *) emalloc(x * (ulong) sizeof(uint32_t));",
+	"#else",
+	"	ohash_hv = (volatile uint32_t *) sh_pre_malloc(x * (ulong) sizeof(uint32_t));",
+	"#endif",
+	"	ohash_mask = (((ulong)1)<<ssize)-1;",
+	"	ohash_max  = (((ulong)1)<<ssize)/100;",
+	"#if defined(USE_TDH) && defined(Q_PROVISO)",
+	"	#ifdef BFS_SEP_HASH",
+	"	ohash_inq  = (uchar *) emalloc(x * (ulong) sizeof(uchar));",
+	"	#else",
+	"	ohash_inq  = (volatile uchar *) sh_pre_malloc(x * (ulong) sizeof(uchar));",
+	"	#endif",
+	"#endif",
+	"}",
+	"",
+	"static int h_table_full;",
+	"#ifdef L_BOUND",
+	"void",
+	"bfs_mark_live(void)",
+	"{	int i;",
+	"",
+	"	trpt->o_pm &= ~2;",
+	"#ifdef VERBOSE",
+	"	bfs_printf(\"check to mark\\n\");",
+	"#endif",
+	"	for (i = 0; i < (int) now._nr_pr; i++)",
+	"	{	P0 *ptr = (P0 *) pptr(i);",
+	"		if (accpstate[ptr->_t][ptr->_p])",
+	"		{	trpt->o_pm |= 2;",
+	"			now._l_bnd = L_bound;",
+	"			now._l_sds = (uchar *) 0;",
+	"#ifdef VERBOSE",
+	"			bfs_printf(\"mark state live\\n\");",
+	"#endif",
+	"			break;",
+	"	}	}",
+	"}",
+	"void",
+	"bfs_check_live(uchar b, uchar *s)",
+	"{	/* assert(b>0); */",
+	"	now._l_bnd = b-1;	/* decrease bound */",
+	"#ifdef VERBOSE",
+	"	bfs_printf(\"check live %%d\\n\", b);",
+	"#endif",
+	"	if (b == L_bound && boq == -1)", /* never mid rv */
+	"	{	now._l_sds = (uchar *) Lstate;	/* new target */",
+	"	} else",
+	"	{	now._l_sds = s;		/* restore target */",
+	"		if (s == (uchar *) Lstate)",
+	"		{	depthfound = depth - (BASE+1)*(L_bound - now._l_bnd - 1);",
+	"			uerror(\"accept cycle found\");",
+	"			depthfound = -1;",
+	"			now._l_bnd = 0;",
+	"			now._l_sds = (uchar *) 0;",
+	"	}	}",
+	"#ifdef VERBOSE",
+	"	bfs_printf(\"set l_bound to %%d -- sds %%p\\n\", b-1, (void *) now._l_sds);",
+	"#endif",
+	"}",
+	"#endif",
+	"/* closed hashing with locality - similar to ltsmin */",
+	"int",
+	"o_store(const char *vin, int nin)",
+	"{	int i, seed = 0;",
+	"	ulong hash_v, ix, ex;",
+	"	uint32_t T_BUSY, T_DONE;",
+	"	volatile uint32_t *t_entry;",
+	"#ifdef HC",
+	"	ulong vs = ohash_hc_sz;",
+	"#else",
+	"	ulong vs = (ulong) T_VSZ;",
+	"#endif",
+	"#ifdef L_BOUND",
+	"	uchar o_bnd, *o_sds;",
+	"#endif",
+	"#ifndef STOP_ON_FULL",
+	"	if (h_table_full)",
+	"	{	goto done;",
+	"	}",
+	"#endif",
+	"#ifdef L_BOUND",
+	"	if (now._l_bnd == 0)",
+	"	{	bfs_mark_live();",
+	"	}",
+	"	#ifdef VERBOSE",
+	"	  else",
+	"	{	bfs_printf(\"non-markable state %%d\\n\", now._l_bnd);",
+	"	}",
+	"	#endif",
+	"	o_bnd = now._l_bnd;",
+	"	o_sds = now._l_sds;",
+	"	now._l_bnd = (o_bnd)?1:0;  /* mark nested phase of bounded search */",
+	"	now._l_sds = (uchar *) 0;",
+	"#endif",
+	"#if !defined(HC) && !defined(T_NOCOMP)",
+	"	nin = compress((char *)vin, nin);",
+	"	vin = (char *) &comp_now;",
+	"#endif",
+	"	do {	o_hash((uchar *)vin, nin, seed++);",
+	"		hash_v = K1;",
+	"	} while (hash_v == T_FREE || hash_v == T_STAT);	/* unlikely, hash_v 0 or 1 */",
+	"",
+	"	T_BUSY = ((uint32_t) hash_v & ~((uint32_t) T_STAT));	/* hash with status bit 0 */",
+	"	T_DONE = ((uint32_t) hash_v |  ((uint32_t) T_STAT));	/* hash with status bit 1 */",
+	"#ifdef HC",
+	"	d_hash((uchar *)vin, nin);",			/* HC */
+	"	ohash_hc[0] = (uint32_t) K1;",
+	"	#if T_HC>1",
+	"	ohash_hc[1] = (uint32_t) (K1>>32);",		/* assumes ulong = 64 bits */
+	"	#endif",
+	"	#if T_HC>2",
+	"	ohash_hc[2] = (uint32_t) K2;",
+	"	#endif",
+	"	#if T_HC>3",
+	"	ohash_hc[3] = (uint32_t) (K2>>32);",
+	"	#endif",
+	"#endif",
+	"	while (seed < ohash_max)",
+	"	{	ix = hash_v & ohash_mask;",
+	"		ex = (ix & T_ROW_MASK) + T_ROW_SIZE;",
+	"		for (i = 0; i < T_ROW_SIZE; i++)",
+	"		{	t_entry = (uint32_t *) &ohash_hv[ix];",
+	"			if (*t_entry == T_FREE && cas(t_entry, T_FREE, T_BUSY))",
+	"			{",
+	"#ifndef HC",
+	"				memcpy((char *) &ohash_sd[ix * vs], vin, nin);",
+	"#else",
+	"				memcpy((char *) &ohash_sd[ix * vs], (char *) ohash_hc, vs);",
+	"#endif",
+	"#if defined(USE_TDH) && defined(Q_PROVISO)",
+	"				ohash_inq[ix] = (uchar) BFS_INQ;",
+	"				Lstate = (H_el *) &ohash_inq[ix];",
+	"#endif",
+	"				*t_entry = T_DONE;",
+	"#ifdef VERBOSE",
+	"	#ifdef L_BOUND",
+	"				bfs_printf(\"New state %%p [%%p]\\n\",",
+	"					(void *) Lstate, (void *) o_sds);",
+	"	#else",
+	"				bfs_printf(\"New state %%p\\n\", (void *) Lstate);",
+	"	#endif",
+	"#endif",
+	"#ifdef L_BOUND",
+	"				if (o_bnd) { bfs_check_live(o_bnd, o_sds); }",
+	"#endif",
+	"				return 0;	/* New State */",
+	"			}",
+	"			while (*t_entry == T_BUSY)",
+	"			{	usleep(2);	/* wait */",
+	"			}",
+	"			if (*t_entry == T_DONE /* (first) hash matches, check data */",
+	"#ifndef HC",
+	"			&&   memcmp((char *) &ohash_sd[ix * vs], vin, nin) == 0)",
+	"#else",
+	"			&&   memcmp((char *) &ohash_sd[ix * vs], (char *) ohash_hc, vs) == 0)",
+	"#endif",
+	"			{",
+	"#if defined(USE_TDH) && defined(Q_PROVISO)",
+	"				Lstate = (H_el *) &ohash_inq[ix];",
+	"#endif",
+	"#ifdef VERBOSE",
+	"	#ifdef L_BOUND",
+	"				bfs_printf(\"Old state %%p [%%p]\\n\",",
+	"					(void *) Lstate, (void *) o_sds);",
+	"	#else",
+	"				bfs_printf(\"Old state %%p\\n\", (void *) Lstate);",
+	"	#endif",
+	"#endif",
+	"#ifdef L_BOUND",
+	"				if (o_bnd) { bfs_check_live(o_bnd, o_sds); }",
+	"#endif",
+	"				return 1;	/* Old State */",
+	"			}",
+	"			hcmp++; ix++;",
+	"			ix = (ix==ex) ? ex - T_ROW_SIZE : ix;",
+	"		}",
+	"		/* find a new slot: */",
+	"		do {	o_hash((uchar *)vin, nin, (int) (hash_v + seed++));",
+	"			hash_v = K1;",
+	"		} while (hash_v == T_FREE || hash_v == T_STAT);",
+	"		T_BUSY = ((uint32_t) hash_v & ~((uint32_t) T_STAT));",
+	"		T_DONE = ((uint32_t) hash_v |  ((uint32_t) T_STAT));",
+	"	}",
+	"#ifdef STOP_ON_FULL",
+	"	Uerror(\"hash table full\");",
+	"	/* no return from Uerror */",
+	"#else",
+	"	if (!h_table_full)",
+	"	{	h_table_full++;",
+	"		if (who_am_i == 0)",
+	"		{	bfs_printf(\"hash table is full\\n\");",
+	"	}	}",
+	"done:",
+	"	bfs_punt++;	/* counts this as a lost state */",
+	"#endif",
+	"#ifdef L_BOUND",
+	"	now._l_bnd = 0; /* no more checking */",
+	"	now._l_sds = (uchar *) 0;",
+	"#endif",
+	"	return 1; /* technically should be 0, but we want to throttle down */",
+	"}",
+	"#endif", /* USE_TDH && !WIN32 && !WIN64 */
+	"#endif", /* !BITSTATE || FULLSTACK */
 	"#include TRANSITIONS",
-	"void",
-	"do_reach(void)",
-	"{",
 	0,
 };
diff -r 51b3bf8bc61b sys/src/cmd/spin/pangen2.c
--- a/sys/src/cmd/spin/pangen2.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/pangen2.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,13 +1,10 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include "spin.h"
 #include "version.h"
@@ -15,33 +12,40 @@
 #include "pangen2.h"
 #include "pangen4.h"
 #include "pangen5.h"
+#include "pangen7.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", \
+#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 Lextok	*runstmnts;
 extern Symbol	*Fname, *oFname, *context;
 extern char	*claimproc, *eventmap;
-extern int	lineno, verbose, Npars, Mpars;
+extern int	lineno, verbose, Npars, Mpars, nclaims;
 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	Ntimeouts, Etimeouts, deadvar, old_scope_rules, old_priority_rules;
+extern int	u_sync, u_async, nrRdy, Unique;
 extern int	GenCode, IsGuard, Level, TestOnly;
+extern int	globmin, globmax, ltl_mode, dont_simplify;
+
 extern short	has_stack;
-extern char	*NextLab[];
+extern char	*NextLab[64];	/* must match value in dstep.c:18 */
 
-FILE	*tc, *th, *tt, *tm, *tb;
+int	 	 buzzed;
+FILE		*tc, *th, *tt, *tb;
+static FILE	*tm;
 
-int	OkBreak = -1;
+int	OkBreak = -1, has_hidden = 0; /* has_hidden set in sym.c and structs.c */
 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_priority=0;	/* spec refers to _priority */
 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() */
@@ -52,9 +56,7 @@
 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 */
+short	has_ltl=0;	/* has inline ltl formulae */
 int	mst=0;		/* max nr of state/process */
 int	claimnr = -1;	/* claim process, if any */
 int	eventmapnr = -1; /* event trace, if any */
@@ -74,6 +76,9 @@
 static int	uniq=1;
 static int	multi_needed, multi_undo;
 static short	AllGlobal=0;	/* set if process has provided clause */
+static short	withprocname=0;	/* prefix local varnames with procname */
+static short	_isok=0;	/* checks usage of predefined variable _ */
+static short	evalindex=0;	/* evaluate index of var names */
 
 int	has_global(Lextok *);
 static int	getweight(Lextok *);
@@ -86,6 +91,29 @@
 static void	Tpe(Lextok *);
 extern void	spit_recvs(FILE *, FILE*);
 
+static L_List *keep_track;
+
+void
+keep_track_off(Lextok *n)
+{	L_List *p;
+
+	p = (L_List *) emalloc(sizeof(L_List));
+	p->n = n;
+	p->nxt = keep_track;
+	keep_track = p;
+}
+
+int
+check_track(Lextok *n)
+{	L_List *p;
+
+	for (p = keep_track; p; p = p->nxt)
+	{	if (p->n == n)
+		{	return n->sym?n->sym->type:0;
+	}	}
+	return 0;
+}
+
 static int
 fproc(char *s)
 {	ProcList *p;
@@ -98,12 +126,33 @@
 	return -1;
 }
 
+int
+pid_is_claim(int p)	/* Pid (p->tn) to type (p->b) */
+{	ProcList *r;
+
+	for (r = rdy; r; r = r->nxt)
+	{	if (r->tn == p) return (r->b == N_CLAIM);
+	}
+	printf("spin: error, cannot find pid %d\n", p);
+	return 0;
+}
+
 static void
 reverse_procs(RunList *q)
 {
 	if (!q) return;
 	reverse_procs(q->nxt);
-	fprintf(tc, "	Addproc(%d);\n", q->tn);
+	fprintf(tc, "		Addproc(%d, %d);\n",
+		q->tn, q->priority < 1 ? 1 : q->priority);
+}
+
+static void
+forward_procs(RunList *q)
+{
+	if (!q) return;
+	fprintf(tc, "		Addproc(%d, %d);\n",
+		q->tn, q->priority < 1 ? 1 : q->priority);
+	forward_procs(q->nxt);
 }
 
 static void
@@ -111,13 +160,14 @@
 {
 	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\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");
@@ -151,51 +201,120 @@
 void
 gensrc(void)
 {	ProcList *p;
+	int i;
 
-	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 */
+	disambiguate();		/* avoid name-clashes between scopes */
+
+	if (!(tc = fopen(Cfile[0].nm[separate], MFLAGS))		/* main routines */
+	||  !(th = fopen(Cfile[1].nm[separate], MFLAGS))		/* header file   */
+	||  !(tt = fopen(Cfile[2].nm[separate], MFLAGS))		/* transition matrix */
+	||  !(tm = fopen(Cfile[3].nm[separate], MFLAGS))		/* forward  moves */
+	||  !(tb = fopen(Cfile[4].nm[separate], MFLAGS)))	/* 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, "#ifndef PAN_H\n");
+	fprintf(th, "#define PAN_H\n\n");
+
+	fprintf(th, "#define SpinVersion	\"%s\"\n", SpinVersion);
+	fprintf(th, "#define PanSource	\"");
+	for (i = 0; oFname->name[i] != '\0'; i++)
+	{	char c = oFname->name[i];
+		if (c == '\\' || c == ' ') /* Windows path */
+		{	fprintf(th, "\\");
+		}
+		fprintf(th, "%c", c);
+	}
+	fprintf(th, "\"\n\n");
+
+	fprintf(th, "#define G_long	%d\n", (int) sizeof(long));
+	fprintf(th, "#define G_int	%d\n\n", (int) sizeof(int));
+	fprintf(th, "#define ulong	unsigned long\n");
+	fprintf(th, "#define ushort	unsigned short\n");
+
+	fprintf(th, "#ifdef WIN64\n");
+	fprintf(th, "	#define ONE_L	(1L)\n");
+	fprintf(th, "/*	#define long	long long */\n");
+	fprintf(th, "#else\n");
+	fprintf(th, "	#define ONE_L	(1L)\n");
+	fprintf(th, "#endif\n\n");
+
+	fprintf(th, "#ifdef BFS_PAR\n");
+	fprintf(th, "	#define NRUNS	%d\n", (runstmnts)?1:0);
+	fprintf(th, "	#ifndef BFS\n");
+	fprintf(th, "		#define BFS\n");
+	fprintf(th, "	#endif\n");
+	fprintf(th, "	#ifndef PUTPID\n");
+	fprintf(th, "		#define PUTPID\n");
+	fprintf(th, "	#endif\n\n");
+	fprintf(th, "	#if !defined(USE_TDH) && !defined(NO_TDH)\n");
+	fprintf(th, "		#define USE_TDH\n");
+	fprintf(th, "	#endif\n");
+	fprintf(th, "	#if defined(USE_TDH) && !defined(NO_HC)\n");
+	fprintf(th, "		#define HC /* default for USE_TDH */\n");
+	fprintf(th, "	#endif\n");
+	fprintf(th, "	#ifndef BFS_MAXPROCS\n");
+	fprintf(th, "		#define BFS_MAXPROCS	64	/* max nr of cores to use */\n");
+	fprintf(th, "	#endif\n");
+
+	fprintf(th, "	#define BFS_GLOB	0	/* global lock */\n");
+	fprintf(th, "	#define BFS_ORD		1	/* used with -DCOLLAPSE */\n");
+	fprintf(th, "	#define BFS_MEM		2	/* malloc from shared heap */\n");
+	fprintf(th, "	#define BFS_PRINT	3	/* protect printfs */\n");
+	fprintf(th, "	#define BFS_STATE	4	/* hashtable */\n\n");
+	fprintf(th, "	#define BFS_INQ 	2	/* state is in q */\n\n");
+
+	fprintf(th, "	#ifdef BFS_FIFO\n");	/* queue access */
+	fprintf(th, "	  #define BFS_ID(a,b)	(BFS_STATE + (int) ((a)*BFS_MAXPROCS+(b)))\n");
+	fprintf(th, "	  #define BFS_MAXLOCKS	(BFS_STATE + (BFS_MAXPROCS*BFS_MAXPROCS))\n");
+	fprintf(th, "	#else\n");		/* h_store access (not needed for o_store) */
+	fprintf(th, "	  #ifndef BFS_W\n");
+	fprintf(th, "		#define BFS_W	10\n");	/* 1<<BFS_W locks */
+	fprintf(th, "	  #endif\n");
+	fprintf(th, "	  #define BFS_MASK	((1<<BFS_W) - 1)\n");
+	fprintf(th, "	  #define BFS_ID	(BFS_STATE + (int) (j1_spin & (BFS_MASK)))\n");
+	fprintf(th, "	  #define BFS_MAXLOCKS	(BFS_STATE + (1<<BFS_W))\n"); /* 4+1024 */
+	fprintf(th, "	#endif\n");
+
+	fprintf(th, "	#undef NCORE\n");
+	fprintf(th, "	extern int Cores, who_am_i;\n");
+	fprintf(th, "	#ifndef SAFETY\n");
+	fprintf(th, "	  #if !defined(BFS_STAGGER) && !defined(BFS_DISK)\n");
+	fprintf(th, "		#define BFS_STAGGER	64 /* randomizer, was 16 */\n");
+	fprintf(th, "	  #endif\n");
+	fprintf(th, "	  #ifndef L_BOUND\n");
+	fprintf(th, "		#define L_BOUND 	10 /* default */\n");
+	fprintf(th, "	  #endif\n");
+	fprintf(th, "	  extern int L_bound;\n");
+	fprintf(th, "	#endif\n");
+	fprintf(th, "	#if defined(BFS_DISK) && defined(BFS_STAGGER)\n");
+	fprintf(th, "		#error BFS_DISK and BFS_STAGGER are not compatible\n");
+	fprintf(th, "	#endif\n");
+	fprintf(th, "#endif\n\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, "	#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, "	#define uchar	unsigned char\n");
 	fprintf(th, "#endif\n");
 	fprintf(th, "#ifndef uint\n");
-	fprintf(th, "#define uint	unsigned int\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));
+		s->minel = -1;
 		claimproc = n->name = "_:never_template:_";
-		ready(n, ZN, s, 0, ZN);
+		ready(n, ZN, s, 0, ZN, N_CLAIM);
 	}
 	if (separate == 2)
 	{	if (has_remote)
@@ -207,20 +326,29 @@
 		fprintf(th, "#endif\n");
 		if (has_last)
 		fprintf(th, "#define HAS_LAST	%d\n", has_last);
+		if (has_priority && !old_priority_rules)
+		fprintf(th, "#define HAS_PRIORITY	%d\n", has_priority);
 		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, "	#if NCORE>1 && !defined(SEP_STATE)\n");
+	fprintf(th, "		#define SEP_STATE\n");
+	fprintf(th, "	#endif\n");
+	fprintf(th, "	#if MA==1\n"); /* user typed -DMA without size */
+	fprintf(th, "		#undef MA\n");
+	fprintf(th, "		#define MA	100\n");
+	fprintf(th, "	#endif\n");
+	fprintf(th, "#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, "	#if W_XPT==1\n"); /* user typed -DW_XPT without size */
+	fprintf(th, "		#undef W_XPT\n");
+	fprintf(th, "		#define W_XPT 1000000\n");
+	fprintf(th, "	#endif\n");
+	fprintf(th, "#endif\n");
 	fprintf(th, "#ifndef NFAIR\n");
-	fprintf(th, "#define NFAIR	2	/* must be >= 2 */\n");
+	fprintf(th, "	#define NFAIR	2	/* must be >= 2 */\n");
 	fprintf(th, "#endif\n");
 	if (Ntimeouts)
 	fprintf(th, "#define NTIM	%d\n", Ntimeouts);
@@ -230,18 +358,33 @@
 	fprintf(th, "#define REM_VARS	1\n");
 	if (has_remote)
 	fprintf(th, "#define REM_REFS	%d\n", has_remote); /* not yet used */
+	if (has_hidden)
+	{	fprintf(th, "#define HAS_HIDDEN	%d\n", has_hidden);
+		fprintf(th, "#if defined(BFS_PAR) || defined(BFS)\n");
+		fprintf(th, "	#error cannot use BFS on models with variables declared hidden\n");
+		fprintf(th, "#endif\n");
+	}
 	if (has_last)
 	fprintf(th, "#define HAS_LAST	%d\n", has_last);
+	if (has_priority && !old_priority_rules)
+	fprintf(th, "#define HAS_PRIORITY	%d\n", has_priority);
 	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_ltl)
+	fprintf(th, "#define HAS_LTL	1\n");
+	fprintf(th, "#define HAS_CODE	1\n");	/* could also be set to has_code */
+		/* always defining it doesn't seem to cause measurable overhead though */
+		/* and allows for pan -r etc to work for non-embedded code as well */
+	fprintf(th, "#if defined(RANDSTORE) && !defined(RANDSTOR)\n");
+	fprintf(th, "	#define RANDSTOR	RANDSTORE\n"); /* xspin uses RANDSTORE... */
+	fprintf(th, "#endif\n");
 	if (has_stack)
-	fprintf(th, "#define HAS_STACK\n");
-	if (has_enabled)
+	fprintf(th, "#define HAS_STACK	%d\n", has_stack);
+	if (has_enabled || (has_priority && !old_priority_rules))
 	fprintf(th, "#define HAS_ENABLED	1\n");
 	if (has_unless)
 	fprintf(th, "#define HAS_UNLESS	%d\n", has_unless);
@@ -252,11 +395,12 @@
 	if (has_badelse)
 	fprintf(th, "#define HAS_BADELSE	%d\n", has_badelse);
 	if (has_enabled
+	|| (has_priority && !old_priority_rules)
 	||  has_pcvalue
 	||  has_badelse
 	||  has_last)
 	{	fprintf(th, "#ifndef NOREDUCE\n");
-		fprintf(th, "#define NOREDUCE	1\n");
+		fprintf(th, "	#define NOREDUCE	1\n");
 		fprintf(th, "#endif\n");
 	}
 	if (has_np)
@@ -265,33 +409,46 @@
 	fprintf(th, "#define MERGED	1\n");
 
 doless:
-	fprintf(th, "#ifdef NP	/* includes np_ demon */\n");
+	fprintf(th, "#if !defined(HAS_LAST) && defined(BCS)\n");
+	fprintf(th, "	#define HAS_LAST	1 /* use it, but */\n");
+	fprintf(th, "	#ifndef STORE_LAST\n"); /* unless the user insists */
+	fprintf(th, "		#define NO_LAST	1 /* dont store it */\n");
+	fprintf(th, "	#endif\n");
+	fprintf(th, "#endif\n");
+
+	fprintf(th, "#if defined(BCS) && defined(BITSTATE)\n");
+	fprintf(th, "	#ifndef NO_CTX\n");
+	fprintf(th, "		#define STORE_CTX	1\n");
+	fprintf(th, "	#endif\n");
+	fprintf(th, "#endif\n");
+
+	fprintf(th, "#ifdef NP\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, "	#define HAS_NP	2\n");
+	fprintf(th, "	#define VERI	%d	/* np_ */\n",	nrRdy);
 	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);
+	{	claimnr = fproc(claimproc);	/* the default claim */
+		fprintf(th, "#ifndef NOCLAIM\n");
+		fprintf(th, "	#define NCLAIMS	%d\n", nclaims);
+		fprintf(th, "	#ifndef NP\n");
+		fprintf(th, "		#define VERI	%d\n", claimnr);
+		fprintf(th, "	#endif\n");
 		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);
+		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, "\ntypedef struct S_F_MAP {\n");
+	fprintf(th, "	char *fnm;\n\tint from;\n\tint upto;\n");
 	fprintf(th, "} S_F_MAP;\n");
 
-	fprintf(tc, "/*** Generated by %s ***/\n", Version);
+	fprintf(tc, "/*** Generated by %s ***/\n", SpinVersion);
 	fprintf(tc, "/*** From source: %s ***/\n\n", oFname->name);
 
 	ntimes(tc, 0, 1, Pre0);
@@ -304,19 +461,36 @@
 	case 2:	fprintf(tc, "#include \"pan_t.h\"\n"); break;
 	}
 
+	if (separate != 2)
+	{	fprintf(tc, "char *TrailFile = PanSource; /* default */\n");
+		fprintf(tc, "char *trailfilename;\n");
+	}
+
+	fprintf(tc, "#ifdef LOOPSTATE\n");
+	fprintf(tc, "double cnt_loops;\n");
+	fprintf(tc, "#endif\n");
+
 	fprintf(tc, "State	A_Root;	/* seed-state for cycles */\n");
 	fprintf(tc, "State	now;	/* the full state-vector */\n");
+	fprintf(tc, "#if NQS > 0\n");
+	fprintf(tc, "short q_flds[NQS+1];\n");
+	fprintf(tc, "short q_max[NQS+1];\n");
+	fprintf(tc, "#endif\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");
+	{	ntimes(tc, 0, 1, Preamble);
+		ntimes(tc, 0, 1, Separate); /* things that moved out of pan.h */
+	} else
+	{	fprintf(tc, "extern int verbose;\n");
+		fprintf(tc, "extern long depth, depthfound;\n");
+	}
 
 	fprintf(tc, "#ifndef NOBOUNDCHECK\n");
-	fprintf(tc, "#define Index(x, y)\tBoundcheck(x, y, II, tt, t)\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, "	#define Index(x, y)\tx\n");
 	fprintf(tc, "#endif\n");
 
 	c_preview();	/* sets hastrack */
@@ -335,7 +509,7 @@
 		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, "	printf(\"%%s:%%d\\n\",\n");
 		fprintf(tt, "		T_SRC[n].fl, T_SRC[n].ln);\n");
 		fprintf(tt, "}\n");
 		if (!merger)
@@ -359,13 +533,18 @@
 		}
 
 		fprintf(tm, "#define rand	pan_rand\n");
+		fprintf(tm, "#define pthread_equal(a,b)	((a)==(b))\n");
 		fprintf(tm, "#if defined(HAS_CODE) && defined(VERBOSE)\n");
-		fprintf(tm, "	printf(\"Pr: %%d Tr: %%d\\n\", II, t->forw);\n");
+		fprintf(tm, "	#ifdef BFS_PAR\n");
+		fprintf(tm, "		bfs_printf(\"Pr: %%d Tr: %%d\\n\", II, t->forw);\n");
+		fprintf(tm, "	#else\n");
+		fprintf(tm, "		cpu_printf(\"Pr: %%d Tr: %%d\\n\", II, t->forw);\n");
+		fprintf(tm, "	#endif\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, "	#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");
@@ -373,8 +552,9 @@
 		fprintf(tt, " char *, int, int, int);\n\n");
 
 		fprintf(tm, "#define rand	pan_rand\n");
+		fprintf(tm, "#define pthread_equal(a,b)	((a)==(b))\n");
 		fprintf(tm, "#if defined(HAS_CODE) && defined(VERBOSE)\n");
-		fprintf(tm, "	printf(\"Pr: %%d Tr: %%d\\n\", II, forw);\n");
+		fprintf(tm, "	cpu_printf(\"Pr: %%d Tr: %%d\\n\", II, forw);\n");
 		fprintf(tm, "#endif\n");
 		fprintf(tm, "	switch (forw) {\n");
 	}
@@ -404,24 +584,47 @@
 	fprintf(tb, "	case  0: goto R999; /* nothing to undo */\n");
 
 	for (p = rdy; p; p = p->nxt)
-		putproc(p);
-
+	{	putproc(p);
+	}
 
 	if (separate != 2)
-	{	fprintf(th, "struct {\n");
-		fprintf(th, "	int tp; short *src;\n");
-		fprintf(th, "} src_all[] = {\n");
+	{	fprintf(th, "\n");
 		for (p = rdy; p; p = p->nxt)
-			fprintf(th, "	{ %d, &src_ln%d[0] },\n",
+			fprintf(th, "extern short src_ln%d[];\n", p->tn);
+		for (p = rdy; p; p = p->nxt)
+			fprintf(th, "extern S_F_MAP src_file%d[];\n", p->tn);
+		fprintf(th, "\n");
+
+		fprintf(tc, "uchar reached%d[3];  /* np_ */\n", nrRdy);	
+		fprintf(tc, "uchar *loopstate%d;  /* np_ */\n", nrRdy);
+
+		fprintf(tc, "struct {\n");
+		fprintf(tc, "	int tp; short *src;\n");
+		fprintf(tc, "} src_all[] = {\n");
+		for (p = rdy; p; p = p->nxt)
+			fprintf(tc, "	{ %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 */
+		fprintf(tc, "	{ 0, (short *) 0 }\n");
+		fprintf(tc, "};\n");
+
+		fprintf(tc, "S_F_MAP *flref[] = {\n");	/* 5.3.0 */
+		for (p = rdy; p; p = p->nxt)
+		{	fprintf(tc, "	src_file%d%c\n", p->tn, p->nxt?',':' ');
+		}
+		fprintf(tc, "};\n\n");
 	} else
-	{	fprintf(th, "extern short *frm_st0;\n");
+	{	fprintf(tc, "extern uchar reached%d[3];  /* np_ */\n", nrRdy);	
 	}
 
-	gencodetable(th);
+	gencodetable(tc);	/* was th */
+
+	if (Unique < (1 << (8*sizeof(unsigned char)) ))	/* was uniq before */
+	{	fprintf(th, "#define T_ID	unsigned char\n");
+	} else if (Unique < (1 << (8*sizeof(unsigned short)) ))
+	{	fprintf(th, "#define T_ID	unsigned short\n");
+	} else
+	{	fprintf(th, "#define T_ID	unsigned int\n");
+	}
 
 	if (separate != 1)
 	{	tm_predef_np();
@@ -438,13 +641,13 @@
 		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 BACKWARD_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 BACKWARD_MOVES\t\"pan.b\"\n");
 			fprintf(th, "#define TRANSITIONS\t\"pan.t\"\n");
 		}
 		genaddproc();
@@ -456,33 +659,37 @@
 		if (!run) fatal("no runable process", (char *)0);
 		fprintf(tc, "void\n");
 		fprintf(tc, "active_procs(void)\n{\n");
+
+		fprintf(tc, "	if (reversing == 0) {\n");
 			reverse_procs(run);
+		fprintf(tc, "	} else {\n");
+			forward_procs(run);
+		fprintf(tc, "	}\n");
+
 		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);
+		{	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 BACKWARD_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, "	extern int *proc_offset;\n");
 		fprintf(tc, "#else\n");
-		fprintf(tc, "extern short proc_offset[];\n");
+		fprintf(tc, "	extern short *proc_offset;\n");
 		fprintf(tc, "#endif\n");
-		fprintf(tc, "extern uchar proc_skip[];\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 *loopstate[];\n");
 		fprintf(tc, "extern uchar *stopstate[];\n");
 		fprintf(tc, "extern uchar *visstate[];\n\n");
 		fprintf(tc, "extern short *mapstate[];\n");
@@ -491,7 +698,7 @@
 		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, "	#include PROV\n");
 		fprintf(tc, "#endif\n");
 		fprintf(tc, "\tset_claim();\n");
 		genother();
@@ -509,13 +716,42 @@
 		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);
 	}
+
+	fprintf(th, "#if defined(BFS_PAR) || NCORE>1\n");
+	fprintf(th, "	void e_critical(int);\n");
+	fprintf(th, "	void x_critical(int);\n");
+	fprintf(th, "	#ifdef BFS_PAR\n");
+	fprintf(th, "		void bfs_main(int, int);\n");
+	fprintf(th, "		void bfs_report_mem(void);\n");
+	fprintf(th, "	#endif\n");
+	fprintf(th, "#endif\n");
+
+	fprintf(th, "\n\n/* end of PAN_H */\n#endif\n");
+	fclose(th);
+	fclose(tt);
+	fclose(tm);
+	fclose(tb);
+
+	if (!(th = fopen("pan.p", MFLAGS)))
+	{	printf("spin: cannot create pan.p for -DBFS_PAR\n");
+		return; 	/* we're done anyway */
+	}
+
+	ntimes(th, 0, 1, pan_par);	/* BFS_PAR */
+	fclose(th);
+
+	fprintf(tc, "\nTrans *t_id_lkup[%d];\n\n", globmax+1); 
+
+	if (separate != 2)
+	{	fprintf(tc, "\n#ifdef BFS_PAR\n\t#include \"pan.p\"\n#endif\n");
+	}
+	fprintf(tc, "\n/* end of pan.c */\n");
+	fclose(tc);
 }
 
 static int
@@ -537,13 +773,13 @@
 	fprintf(tc, "%s(", pre);
 	if (!(s->hidden&1))
 	{	if (s->context)
-			fprintf(tc, "((P%d *)this)->", pid);
+			fprintf(tc, "(int) ( ((P%d *)this)->", pid);
 		else
-			fprintf(tc, "now.");
+			fprintf(tc, "(int) ( now.");
 	}
 	fprintf(tc, "%s", s->name);
-	if (qln > 1) fprintf(tc, "[%d]", ai);
-	fprintf(tc, ")");
+	if (qln > 1 || s->isarray) fprintf(tc, "[%d]", ai);
+	fprintf(tc, ") )");
 }
 
 struct AA {	char TT[9];	char CC[8]; };
@@ -712,47 +948,60 @@
 	fprintf(tc, "}\n");
 }
 
+extern int find_min(Sequence *);
+extern int find_max(Sequence *);
+
 static void
 putproc(ProcList *p)
 {	Pid = p->tn;
 	Det = p->det;
 
-	if (Pid == claimnr
+	if (pid_is_claim(Pid)
 	&&  separate == 1)
 	{	fprintf(th, "extern uchar reached%d[];\n", Pid);
 #if 0
-		fprintf(th, "extern short nstates%d;\n", Pid);
+		fprintf(th, "extern short _nstates%d;\n", Pid);
 #else
-		fprintf(th, "\n#define nstates%d	%d\t/* %s */\n",
+		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 uchar *loopstate%d;\n", Pid);
 		fprintf(th, "extern S_F_MAP src_file%d[];\n", Pid);
-		fprintf(th, "#define endstate%d	%d\n",
+		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
+	if (!pid_is_claim(Pid)
 	&&  separate == 2)
 	{	fprintf(th, "extern short src_ln%d[];\n", Pid);
+		fprintf(th, "extern uchar *loopstate%d;\n", Pid);
 		return;
 	}
 
 	AllGlobal = (p->prov)?1:0;	/* process has provided clause */
 
-	fprintf(th, "\n#define nstates%d	%d\t/* %s */\n",
+	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);
+/* new */
+	fprintf(th, "#define minseq%d	%d\n", Pid, find_min(p->s));
+	fprintf(th, "#define maxseq%d	%d\n", Pid, find_max(p->s));
+
+/* end */
+
 	if (Pid == eventmapnr)
-	fprintf(th, "#define nstates_event	nstates%d\n", Pid);
+	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(th, "#define _endstate%d	%d\n", Pid, p->s->last?p->s->last->seqno:0);
+
+	if (p->b == N_CLAIM || p->b == E_TRACE || p->b == N_TRACE)
+	{	fprintf(tm, "\n		 /* CLAIM %s */\n", p->n->name);
+		fprintf(tb, "\n		 /* CLAIM %s */\n", p->n->name);
+	}
+	else
+	{	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);
@@ -761,7 +1010,6 @@
 	{	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");
@@ -947,10 +1195,10 @@
 	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);
+		fprintf(tm, "// STATE %d - %s:%d - [",
+			e->seqno, e->n->fn->name, e->n->ln);
 		comment(tm, e->n, 0);
-		fprintf(tm, "] */\n\t\t");
+		fprintf(tm, "]\n\t\t");
 
 		if (s->last->n->ntyp == BREAK)
 			OkBreak = target(huntele(s->last->nxt,
@@ -971,7 +1219,7 @@
 		}
 	
 		fprintf(tb, "\tcase %d: ", uniq-1);
-		fprintf(tb, "/* STATE %d */\n", e->seqno);
+		fprintf(tb, "// STATE %d\n", e->seqno);
 		fprintf(tb, "\t\tsv_restor();\n");
 		fprintf(tb, "\t\tgoto R999;\n");
 		if (e->nxt)
@@ -1024,7 +1272,7 @@
 	struct CaseCache *nxt;
 } CaseCache;
 
-CaseCache *casing[6];
+static CaseCache *casing[6];
 
 static int
 identical(Lextok *p, Lextok *q)
@@ -1076,6 +1324,9 @@
 	if (stopat)
 	while (f && f->seqno != stopat)
 	{	f = findnext(f);
+		if (!f)
+		{	break;
+		}
 		switch (f->n->ntyp) {
 		case GOTO:
 		case '.':
@@ -1084,8 +1335,7 @@
 			break;
 		default:
 			return f;
-		}
-	}
+	}	}
 	return (Element *) 0;
 }
 
@@ -1107,18 +1357,16 @@
 	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;
+	f = advance(a, stopat_a);
+	g = advance(b, stopat_b);
+
+	if (!f && !g)
+		return 1;
+
+	if (f && g)
+		return identical(f->n, g->n);
+
+	return 0;
 }
 
 static CaseCache *
@@ -1174,6 +1422,7 @@
 
 	switch (e->n->ntyp) {
 	case ASGN:
+		if (check_track(e->n) == STRUCT) { break; }
 		nr++;
 		break;
 	case  'r':
@@ -1234,10 +1483,10 @@
 		}
 
 		if (f && !f->merge && !f->merge_single && f->seqno != stopat)
-		{	fprintf(tm, "\n\t\tbad hop %s:%d -- at %d, <",
+		{	fprintf(tm, "\n\t\t// bad 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",
+			fprintf(tm, "> looking for %d -- merge %d:%d:%d ",
 				stopat, f->merge, f->merge_start, f->merge_single);
 		 	break;
 		}
@@ -1258,18 +1507,20 @@
 }
 
 static void
-doforward(FILE *tm, Element *e)
+doforward(FILE *tm_fd, Element *e)
 {	FSM_use *u;
 
-	putstmnt(tm, e->n, e->seqno);
+	putstmnt(tm_fd, 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\")");
+	{	fprintf(tm_fd, ";\n\t\tif (trpt->o_pm&1)\n\t\t");
+		fprintf(tm_fd, "\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 */  ",
+	{	fprintf(tm_fd, ";\n\t\t");
+		fprintf(tm_fd, "if (TstOnly) return 1; /* TT */\n");
+		fprintf(tm_fd, "\t\t/* dead %d: %s */  ",
 			u->special, u->var->name);
 
 		switch (u->special) {
@@ -1281,10 +1532,10 @@
 			}
 			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");
+				fprintf(tm_fd, "\n#ifdef HAS_CODE\n");
+				fprintf(tm_fd, "\t\tif (!readtrail)\n");
+				fprintf(tm_fd, "#endif\n\t\t\t");
+				putname(tm_fd, "", &XZ, 0, " = 0");
 				break;
 			} /* else fall through */
 		case 1:		/* dead after read -- add asgn of rval -- needs bup */
@@ -1292,20 +1543,20 @@
 			CnT[YZcnt]++;		/* this step added bups */
 			if (multi_oval)
 			{	check_needed();
-				fprintf(tm, "(trpt+1)->bup.ovals[%d] = ",
+				fprintf(tm_fd, "(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");
+				fprintf(tm_fd, "(trpt+1)->bup.oval = ");
+			putname(tm_fd, "", &YZ[YZmax], 0, ";\n");
+			fprintf(tm_fd, "#ifdef HAS_CODE\n");
+			fprintf(tm_fd, "\t\tif (!readtrail)\n");
+			fprintf(tm_fd, "#endif\n\t\t\t");
+			putname(tm_fd, "", &YZ[YZmax], 0, " = 0");
 			YZmax++;
 			break;
 	}	}
-	fprintf(tm, ";\n\t\t");
+	fprintf(tm_fd, ";\n\t\t");
 }
 
 static int
@@ -1318,7 +1569,7 @@
 
 	if (!didcase)
 	{	fprintf(tb, "\n\tcase %d: ", casenr);
-		fprintf(tb, "/* STATE %d */\n\t\t", e->seqno);
+		fprintf(tb, "// STATE %d\n\t\t", e->seqno);
 		didcase++;
 	}
 
@@ -1412,7 +1663,7 @@
 {	int bupcase = 0, casenr = uniq, fromcache = 0;
 	CaseCache *Cached = (CaseCache *) 0;
 	Element *f, *g;
-	int j, nrbups, mark, target;
+	int j, nrbups, mark, ntarget;
 	extern int ccache;
 
 	mark = (e->status&ATOM); /* could lose atomicity in a merge chain */
@@ -1439,17 +1690,17 @@
 	fprintf(tt, "\ttrans[%d][%d]\t= ", Pid, e->seqno);
 
 	if (ccache
-	&&  Pid != claimnr
+	&&  !pid_is_claim(Pid)
 	&&  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);
+		fprintf(tm, "// STATE %d - %s:%d - [",
+			e->seqno, e->n->fn->name, e->n->ln);
 		comment(tm, e->n, 0);
-		fprintf(tm, "] (%d:%d - %d) same as %d (%d:%d - %d) */\n",
+		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);
@@ -1457,17 +1708,17 @@
 		goto gotit;
 	}
 
-	fprintf(tm, "\tcase %d: /* STATE %d - line %d %s - [",
-		uniq++, e->seqno, e->n->ln, e->n->fn->name);
+	fprintf(tm, "\tcase %d: // STATE %d - %s:%d - [",
+		uniq++, e->seqno, e->n->fn->name, e->n->ln);
 	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",
+	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)
+	if (e->n->ntyp != 'r' && !pid_is_claim(Pid) && Pid != eventmapnr)
 		fprintf(tm, "IfNotBlocked\n\t\t");
 
 	if (multi_needed != 0 || multi_undo != 0)
@@ -1482,18 +1733,29 @@
 	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");
+/* new 4.2.6, revised 6.0.0 */
+	if (pid_is_claim(Pid))
+	{	fprintf(tm, "\n#if defined(VERI) && !defined(NP)\n");
+		fprintf(tm, "#if NCLAIMS>1\n\t\t");
+		 fprintf(tm, "{	static int reported%d = 0;\n\t\t", e->seqno);
+		 fprintf(tm, "	if (verbose && !reported%d)\n\t\t", e->seqno);
+		 fprintf(tm, "	{	int nn = (int) ((Pclaim *)pptr(0))->_n;\n\t\t");
+		 fprintf(tm, "		printf(\"depth %%ld: Claim %%s (%%d), state %%d (line %%d)\\n\",\n\t\t");
+		 fprintf(tm, "			depth, procname[spin_c_typ[nn]], nn, ");
+		 fprintf(tm, "(int) ((Pclaim *)pptr(0))->_p, src_claim[ (int) ((Pclaim *)pptr(0))->_p ]);\n\t\t");
+		 fprintf(tm, "		reported%d = 1;\n\t\t", e->seqno);
+		 fprintf(tm, "		fflush(stdout);\n\t\t");
+		 fprintf(tm, "}	}\n");
+		fprintf(tm, "#else\n\t\t");
+		 fprintf(tm, "{	static int reported%d = 0;\n\t\t", e->seqno);
+		 fprintf(tm, "	if (verbose && !reported%d)\n\t\t", e->seqno);
+		 fprintf(tm, "	{	printf(\"depth %%d: Claim, state %%d (line %%d)\\n\",\n\t\t");
+		 fprintf(tm, "			(int) depth, (int) ((Pclaim *)pptr(0))->_p, ");
+		 fprintf(tm, "src_claim[ (int) ((Pclaim *)pptr(0))->_p ]);\n\t\t");
+		 fprintf(tm, "		reported%d = 1;\n\t\t", e->seqno);
+		 fprintf(tm, "		fflush(stdout);\n\t\t");
+		 fprintf(tm, "}	}\n");
+		fprintf(tm, "#endif\n");
 		fprintf(tm, "#endif\n\t\t");
 	}
 /* end */
@@ -1504,32 +1766,32 @@
 	doforward(tm, e);
 
 	if (e->merge_start)
-		target = e->merge_start;
+		ntarget = e->merge_start;
 	else
-		target = e->merge;
+		ntarget = e->merge;
 
-	if (target)
+	if (ntarget)
 	{	f = e;
 
 more:		if (f->n->ntyp == GOTO)
 		{	g = get_lab(f->n, 1);
-			if (g->seqno == target)
+			if (g->seqno == ntarget)
 				f = g;
 			else
-				f = huntele(g, f->status, target);
+				f = huntele(g, f->status, ntarget);
 		} else
 			f = f->nxt;
 
 
-		if (f && f->seqno != target)
+		if (f && f->seqno != ntarget)
 		{	if (!f->merge && !f->merge_single)
 			{	fprintf(tm, "/* stop at bad hop %d, %d */\n\t\t",
-					f->seqno, target);
+					f->seqno, ntarget);
 				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,  "(%d, %d, %d) */\n\t\t", f->merge, f->seqno, ntarget);
 			fprintf(tm, "reached[%d][%d] = 1;\n\t\t", Pid, f->seqno);
 			YZcnt++;
 			lab_transfer(e, f);
@@ -1547,8 +1809,8 @@
 	multi_needed = 0;
 	didcase = 0;
 
-	if (target)
-		lastfirst(target, e, casenr); /* mergesteps only */
+	if (ntarget)
+		lastfirst(ntarget, e, casenr); /* mergesteps only */
 
 	dobackward(e, casenr);			/* the original step */
 
@@ -1557,7 +1819,7 @@
 	if (e->merge || e->merge_start)
 	{	if (!didcase)
 		{	fprintf(tb, "\n\tcase %d: ", casenr);
-			fprintf(tb, "/* STATE %d */", e->seqno);
+			fprintf(tb, "// STATE %d", e->seqno);
 			didcase++;
 		} else
 			fprintf(tb, ";");
@@ -1607,8 +1869,8 @@
 	} else
 		a = 0;
 	if (g
-	&&  (g->status&CHECK2	/* entering remotely ref'd state */
-	||   e->status&CHECK2))	/* leaving  remotely ref'd state */
+	&&  ((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 */
@@ -1758,8 +2020,8 @@
 				{	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:"");
+					printf("spin: %s:%d, warning, condition is always false\n",
+						g->n->fn?g->n->fn->name:"", g->n->ln);
 				} else
 					deadlink = 0;
 				if (0) printf("			settr %d %d\n", a, 0);
@@ -1867,7 +2129,7 @@
 	case BREAK:
 		if (e->nxt)
 		{	f = find_target(huntele(e->nxt, e->status, -1));
-			break;	/* 4.3.0 -- was missing */
+			break;	/* new 5.0 -- was missing */
 		}
 		/* else fall through */
 	default:
@@ -1888,6 +2150,26 @@
 }
 
 static int
+seq_has_el(Sequence *s, Element *g)		/* new to version 5.0 */
+{	Element *f;
+	SeqList *h;
+
+	for (f = s->frst; f; f = f->nxt)	/* g in same atomic? */
+	{	if (f == g)
+		{	return 1;
+		}
+		if (f->status & CHECK3)
+		{	continue;
+		}
+		f->status |= CHECK3; /* protect against cycles */
+		for (h = f->sub; h; h = h->nxt)
+		{	if (h->this && seq_has_el(h->this, g))
+			{	return 1;
+	}	}	}
+	return 0;
+}
+
+static int
 scan_seq(Sequence *s)
 {	Element *f, *g;
 	SeqList *h;
@@ -1896,20 +2178,22 @@
 	{	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
+		if  (f->n->ntyp == GOTO	/* may exit or reach other atomic */
+		&& !(f->status & D_ATOM))	/* cannot jump from d_step */
+		{	/* consider jump from an atomic without globals into
+			 * an atomic with globals
 			 * example by Claus Traulsen, 22 June 2007
 			 */
 			g = target(f);
+#if 1
+			if (g && !seq_has_el(s, g)) /* not internal to this atomic/dstep */
+
+#else
 			if (g
 			&& !(f->status & L_ATOM)
 			&& !(g->status & (ATOM|L_ATOM)))
 #endif
-			{	fprintf(tt, "	/* mark-down line %d */\n",
-					f->n->ln);
+			{	fprintf(tt, "\t/* mark-down line %d status %d = %d */\n", f->n->ln, f->status, (f->status & D_ATOM));
 				return 1; /* assume worst case */
 		}	}
 		for (h = f->sub; h; h = h->nxt)
@@ -1937,9 +2221,26 @@
 	return result;
 }
 
+static int
+proc_is_safe(const Lextok *n)
+{	ProcList *p;
+	/* not safe unless no local var inits are used */
+	/* note that a local variable init could refer to a global */
+
+	for (p = rdy; p; p = p->nxt)
+	{	if (strcmp(n->sym->name, p->n->name) == 0)
+		{	/* printf("proc %s safety: %d\n", p->n->name, p->unsafe); */
+			return (p->unsafe != 0);
+	}	}
+/*	non_fatal("bad call to proc_is_safe", (char *) 0);	*/
+	/* cannot happen */
+	return 0;
+}
+
 int
 has_global(Lextok *n)
-{	Lextok *v; extern int runsafe;
+{	Lextok *v;
+	static Symbol *n_seen = (Symbol *) 0;
 
 	if (!n) return 0;
 	if (AllGlobal) return 1;	/* global provided clause */
@@ -1968,6 +2269,14 @@
 	case  LEN:   return (((n->sym->xu)&(XR|XS|XX)) != (XR|XS));
 
 	case   NAME:
+		if (strcmp(n->sym->name, "_priority") == 0)
+		{	if (old_priority_rules)
+			{	if (n_seen != n->sym)
+					fatal("cannot refer to _priority with -o6", (char *) 0);
+				n_seen = n->sym;
+			}
+			return 0;
+		}
 		if (n->sym->context
 		|| (n->sym->hidden&64)
 		||  strcmp(n->sym->name, "_pid") == 0
@@ -1975,14 +2284,15 @@
 			return 0;
 		return 1;
 
-	case RUN: return 1-runsafe;
+	case RUN:
+		return proc_is_safe(n);
 
 	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:
+	case 'p':    case 'q':
+	case TIMEOUT: case SET_P:  case GET_P:
 		return 1;
 
 	/* 	@ was 1 (global) since 2.8.5
@@ -2017,11 +2327,12 @@
 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);
+	{	fprintf(fd, "continue%s", str);
+	} else if (IsGuard)
+	{	fprintf(fd, "%s%s", NextLab[Level], str);
+	} else
+	{	fprintf(fd, "Uerror(\"block in d_step seq\")%s", str);
+	}
 }
 
 #define cat0(x)   	putstmnt(fd,now->lft,m); fprintf(fd, x); \
@@ -2029,6 +2340,7 @@
 #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)
+#define cat30(x,y,z)	fprintf(fd,x,0); putstmnt(fd,y,m); fprintf(fd,z)
 
 void
 putstmnt(FILE *fd, Lextok *now, int m)
@@ -2070,12 +2382,14 @@
 		else
 			fprintf(fd, "((trpt->tau)&1)");
 		if (GenCode)
-		 printf("spin: line %3d, warning: 'timeout' in d_step sequence\n",
-			lineno);
+		 printf("spin: %s:%d, warning, 'timeout' in d_step sequence\n",
+			Fname->name, lineno);
 		/* is okay as a guard */
 		break;
 
 	case RUN:
+		if (now->sym == NULL)
+			fatal("internal error pangen2.c", (char *) 0);
 		if (claimproc
 		&&  strcmp(now->sym->name, claimproc) == 0)
 			fatal("claim %s, (not runnable)", claimproc);
@@ -2084,29 +2398,57 @@
 			fatal("eventmap %s, (not runnable)", eventmap);
 
 		if (GenCode)
-		  fatal("'run' in d_step sequence (use atomic)",
-			(char *)0);
+			fatal("'run' in d_step sequence (use atomic)", (char *)0);
 
-		fprintf(fd,"addproc(%d", fproc(now->sym->name));
+		fprintf(fd,"addproc(II, %d, %d",
+			(now->val > 0 && !old_priority_rules) ? now->val : 1,
+			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);
+		{	/* 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, ")");
+#if 0
+		/* process now->sym->name has run priority now->val */
+		if (now->val > 0 && now->val < 256 && !old_priority_rules)
+		{	fprintf(fd, " && (((P0 *)pptr(now._nr_pr - 1))->_priority = %d)", now->val);
+		}
+#endif
+		if (now->val < 0 || now->val > 255)	/* 0 itself is allowed */
+		{	fatal("bad process in run %s, valid range: 1..255", now->sym->name);
+		}
 		break;
 
 	case ENABLED:
 		cat3("enabled(II, ", now->lft, ")");
 		break;
 
+	case GET_P:
+		if (old_priority_rules)
+		{	fprintf(fd, "1");
+		} else
+		{	cat3("get_priority(", now->lft, ")");
+		}
+		break;
+
+	case SET_P:
+		if (!old_priority_rules)
+		{	fprintf(fd, "if (TstOnly) return 1; /* T30 */\n\t\t");
+			fprintf(fd, "set_priority(");
+			putstmnt(fd, now->lft->lft, m);
+			fprintf(fd, ", ");
+			putstmnt(fd, now->lft->rgt, m);
+			fprintf(fd, ")");
+		}
+		break;
+
 	case NONPROGRESS:
 		/* o_pm&4=progress, tau&128=claim stutter */
 		if (separate == 2)
@@ -2180,7 +2522,7 @@
 
 	case 's':
 		if (Pid == eventmapnr)
-		{	fprintf(fd, "if ((ot == EVENT_TRACE && _tp != 's') ");
+		{	fprintf(fd, "if ((II == -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
@@ -2208,31 +2550,37 @@
 			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, "\n#if !defined(XUSAFE) && !defined(NOREDUCE)\n\t\t");
+			putname(fd, "if (q_claim[", now->lft, m, "]&2)\n\t\t");
+			putname(fd, "{	q_S_check(", now->lft, m, ", II);\n\t\t");
+			fprintf(fd, "}\n");
+			if (has_sorted && now->val == 1)
+			{	putname(fd, "\t\tif (q_claim[", now->lft, m, "]&1)\n\t\t"); /* &1 iso &2 */
+				fprintf(fd, "{	uerror(\"sorted send on xr channel violates po reduction\");\n\t\t");
+				fprintf(fd, "}\n");
+			}
+			fprintf(fd, "#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{ 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 (has_enabled || has_priority)
+			fprintf(fd, "\n\t\tif (TstOnly) return 1; /* T1 */");
 
 		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");
+		fprintf(fd, "\t\t\tchar simtmp[64];\n");
 		putname(fd, "\t\t\tsprintf(simvals, \"%%d!\", ", now->lft, m, ");\n");
 		_isok++;
 		for (v = now->rgt, i = 0; v; v = v->rgt, i++)
@@ -2256,9 +2604,9 @@
 			printf("	%d msg parameters sent, %d expected\n", i, Mpars);
 			fatal("too many pars in send", "");
 		}
-		for ( ; i < Mpars; i++)
+		for (j = i; i < Mpars; i++)
 			fprintf(fd, ", 0");
-		fprintf(fd, ")");
+		fprintf(fd, ", %d)", j);
 		if (u_sync)
 		{	fprintf(fd, ";\n\t\t");
 			if (u_async)
@@ -2274,7 +2622,7 @@
 
 	case 'r':
 		if (Pid == eventmapnr)
-		{	fprintf(fd, "if ((ot == EVENT_TRACE && _tp != 'r') ");
+		{	fprintf(fd, "if ((II == -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
@@ -2342,10 +2690,13 @@
 			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");
+		{	fprintf(fd, "\n#if !defined(XUSAFE) && !defined(NOREDUCE)\n\t\t");
+			putname(fd, "if (q_claim[", now->lft, m, "]&1)\n\t\t");
+			putname(fd, "{	q_R_check(", now->lft, m, ", II);\n\t\t");
+			if (has_random && now->val != 0)
+			fprintf(fd, "	uerror(\"rand receive on xr channel violates po reduction\");\n\t\t");
+			fprintf(fd, "}\n");
+			fprintf(fd, "#endif\n\t\t");
 		}
 		if (u_sync)
 		{	if (now->val >= 2)
@@ -2398,6 +2749,8 @@
 				  fprintf(fd, "0, %d, 0)) ", i);
 				  Bailout(fd, "");
 			}	}
+			if (has_enabled || has_priority)
+				fprintf(fd, ";\n\t\tif (TstOnly) return 1 /* T2 */");
 		} else	/* random receive: val 1 or 3 */
 		{	fprintf(fd, ";\n\t\tif (!(XX = Q_has(");
 			putname(fd, "", now->lft, m, "");
@@ -2415,19 +2768,21 @@
 				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 (has_enabled || has_priority)
+				fprintf(fd, ";\n\t\tif (TstOnly) return 1 /* T2 */");
+			if (!GenCode) {
+				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 (j == 0 && now->val >= 2)
 		{	fprintf(fd, ";\n\t\t");
@@ -2439,16 +2794,20 @@
 			fprintf(fd, ";\n\t\t");
 			/* no variables modified */
 			if (j == 0 && now->val == 0)
-			{	fprintf(fd, "if (q_flds[((Q0 *)qptr(");
+			{	fprintf(fd, "\n#ifndef BFS_PAR\n\t\t");
+				/* q_flds values are not shared among cores */
+				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");
+				fprintf(fd, " != %d)\n\t\t\t", i);
+				fprintf(fd, "Uerror(\"wrong nr of msg fields in rcv\");\n");
+				fprintf(fd, "#endif\n\t\t");
 			}
 
 			for (v = now->rgt; v; v = v->rgt)
-				if ((v->lft->ntyp != CONST
+			{	if ((v->lft->ntyp != CONST
 				&&   v->lft->ntyp != EVAL))
-					jj++;	/* nr of vars needing bup */
+				{	jj++;	/* nr of vars needing bup */
+			}	}
 
 			if (jj)
 			for (v = now->rgt, i = 0; v; v = v->rgt, i++)
@@ -2467,12 +2826,12 @@
 					sprintf(tempbuf, "(trpt+1)->bup.oval = ");
 
 				if (v->lft->sym && !strcmp(v->lft->sym->name, "_"))
-				{	fprintf(fd, tempbuf);
+				{	fprintf(fd, tempbuf, (char *) 0);
 					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");
+					cat30(tempbuf, v->lft, ";\n\t\t");
 					_isok--;
 				}
 			}
@@ -2485,7 +2844,7 @@
 					&&  v->lft->ntyp != EVAL
 					&&  v->lft->sym
 					&&  v->lft->sym->type != STRUCT	/* not a struct */
-					&&  v->lft->sym->nel == 1	/* not an array */
+					&&  (v->lft->sym->nel == 1 && v->lft->sym->isarray == 0) /* not array */
 					&&  strcmp(v->lft->sym->name, "_") != 0)
 					for (w = v->rgt; w; w = w->rgt)
 						if (v->lft->sym == w->lft->sym)
@@ -2501,6 +2860,7 @@
 
 			if (v->lft->ntyp != CONST
 			&&  v->lft->ntyp != EVAL
+			&&  v->lft->sym != NULL
 			&&  strcmp(v->lft->sym->name, "_") != 0)
 			{	nocast=1;
 				_isok++;
@@ -2515,6 +2875,7 @@
 
 			if (v->lft->ntyp != CONST
 			&&  v->lft->ntyp != EVAL
+			&&  v->lft->sym != NULL
 			&& strcmp(v->lft->sym->name, "_") != 0
 			&&  (v->lft->ntyp != NAME
 			||   v->lft->sym->type != CHAN))
@@ -2658,8 +3019,10 @@
 		break;
 
 	case ASGN:
-		if (has_enabled)
-		fprintf(fd, "if (TstOnly) return 1;\n\t\t");
+		if (check_track(now) == STRUCT) { break; }
+
+		if (has_enabled || has_priority)
+		fprintf(fd, "if (TstOnly) return 1; /* T3 */\n\t\t");
 		_isok++;
 
 		if (!GenCode)
@@ -2669,14 +3032,27 @@
 				sprintf(tempbuf, "(trpt+1)->bup.ovals[%d] = ",
 					multi_oval-1);
 				multi_oval++;
-				cat3(tempbuf, now->lft, ";\n\t\t");
+				cat30(tempbuf, now->lft, ";\n\t\t");
 			} else
 			{	cat3("(trpt+1)->bup.oval = ", now->lft, ";\n\t\t");
 		}	}
+		if (now->lft->sym
+		&&  now->lft->sym->type == PREDEF
+		&&  strcmp(now->lft->sym->name, "_") != 0
+		&&  strcmp(now->lft->sym->name, "_priority") != 0)
+		{	fatal("invalid assignment to %s", now->lft->sym->name);
+		}
+
 		nocast = 1; putstmnt(fd,now->lft,m); nocast = 0;
 		fprintf(fd," = ");
 		_isok--;
-		putstmnt(fd,now->rgt,m);
+		if (now->lft->sym->isarray
+		&&  now->rgt->ntyp == ',')	/* array initializer */
+		{	putstmnt(fd, now->rgt->lft, m);
+			non_fatal("cannot use an array list initializer here", (char *) 0);
+		} else
+		{	putstmnt(fd, now->rgt, m);
+		}
 
 		if (now->sym->type != CHAN
 		||  verbose > 0)
@@ -2695,8 +3071,8 @@
 		break;
 
 	case PRINT:
-		if (has_enabled)
-		fprintf(fd, "if (TstOnly) return 1;\n\t\t");
+		if (has_enabled || has_priority)
+			fprintf(fd, "if (TstOnly) return 1; /* T4 */\n\t\t");
 #ifdef PRINTF
 		fprintf(fd, "printf(%s", now->sym->name);
 #else
@@ -2709,8 +3085,8 @@
 		break;
 
 	case PRINTM:
-		if (has_enabled)
-		fprintf(fd, "if (TstOnly) return 1;\n\t\t");
+		if (has_enabled || has_priority)
+			fprintf(fd, "if (TstOnly) return 1; /* T5 */\n\t\t");
 		fprintf(fd, "printm(");
 		if (now->lft && now->lft->ismtyp)
 			fprintf(fd, "%d", now->lft->val);
@@ -2732,7 +3108,7 @@
 
 	case   'q':
 		if (terse)
-			fprintf(fd, "%s", now->sym->name);
+			fprintf(fd, "%s", now->sym?now->sym->name:"?");
 		else
 			fprintf(fd, "%d", remotelab(now));
 		break;
@@ -2748,14 +3124,16 @@
 		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 (now->sym)
+			fprintf(fd, "/* %s */\n\t\t", now->sym->name);
+		if (has_enabled || has_priority)
+			fprintf(fd, "if (TstOnly) return 1; /* T6 */\n\t\t");
+
+		if (now->sym)
+			plunk_inline(fd, now->sym->name, 1, GenCode);
+		else
+			fatal("internal error pangen2.c", (char *) 0);
+
 		if (!GenCode)
 		{	fprintf(fd, "\n");	/* state changed, capture it */
 			fprintf(fd, "#if defined(C_States) && (HAS_TRACK==1)\n");
@@ -2765,10 +3143,10 @@
 		break;
 
 	case ASSERT:
-		if (has_enabled)
-			fprintf(fd, "if (TstOnly) return 1;\n\t\t");
+		if (has_enabled || has_priority)
+			fprintf(fd, "if (TstOnly) return 1; /* T7 */\n\t\t");
 
-		cat3("assert(", now->lft, ", ");
+		cat3("spin_assert(", now->lft, ", ");
 		terse = nocast = 1;
 		cat3("\"", now->lft, "\", II, tt, t)");
 		terse = nocast = 0;
@@ -2788,7 +3166,7 @@
 			break;
 		}
 
-		if (has_enabled)
+		if (has_enabled || has_priority)
 		{	fprintf(fd, "if (TstOnly)\n\t\t\t");
 			fprintf(fd, "return (II+1 == now._nr_pr);\n\t\t");
 		}
@@ -2797,16 +3175,30 @@
 		break;
 
 	default:
-		printf("spin: bad node type %d (.m) - line %d\n",
-			now->ntyp, now->ln);
-		fflush(tm);
+		printf("spin: error, %s:%d, bad node type %d (.m)\n",
+			now->fn->name, now->ln, now->ntyp);
+		fflush(fd);
 		alldone(1);
 	}
 }
 
+char *
+simplify_name(char *s)
+{	char *t = s;
+
+	if (!old_scope_rules)
+	{	while (*t == '_' || isdigit((int)*t))
+		{	t++;
+	}	}
+
+	return t;
+}
+
 void
 putname(FILE *fd, char *pre, Lextok *n, int m, char *suff) /* varref */
 {	Symbol *s = n->sym;
+	char *ptr;
+
 	lineno = n->ln; Fname = n->fn;
 
 	if (!s)
@@ -2819,48 +3211,67 @@
 	{	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);
+			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);
+	fprintf(fd, pre, 0);
 	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);
+	{	if (old_priority_rules
+		&&  strcmp(s->name, "_priority") == 0)
+		{	fprintf(fd, "1");	
+			goto shortcut;
 		} 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 (s->context
+			||  strcmp(s->name, "_p") == 0
+			||  strcmp(s->name, "_pid") == 0
+			||  strcmp(s->name, "_priority") == 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 (terse && buzzed == 1)
+	{	fprintf(fd, "B_state.%s", (s->context)?"local[B_pid].":"");
+	}
+
+	ptr = s->name;
+
+	if (!dont_simplify	/* new 6.4.3 */
+	&&  s->type != PREDEF)	/* new 6.0.2 */
+	{	if (withprocname
+		&&  s->context
+		&&  strcmp(pre, "."))
+		{	fprintf(fd, "%s:", s->context->name);
+			ptr = simplify_name(ptr);
+		} else
+		{	if (terse)
+			{	ptr = simplify_name(ptr);
+	}	}	}
 
 	if (evalindex != 1)
-		fprintf(fd, "%s", s->name);
+		fprintf(fd, "%s", ptr);
 
-	if (s->nel != 1)
+	if (s->nel > 1 || s->isarray == 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");
+		{	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 -
@@ -2885,15 +3296,32 @@
 			|| (!n->lft && s->nel > 0))
 			{	cat3("[", n->lft, "]");
 			} else
-			{	cat3("[ Index(", n->lft, ", ");
+			{	/* attempt to catch arrays that are indexed with an array element in the same array
+				 * this causes trouble in the verifier in the backtracking
+				 * e.g., restoring a[?] in the assignment: a [a[1]] = x where a[1] == 1
+				 * but it is hard when the array is inside a structure, so the names dont match
+				 */
+#if 0
+				if (n->lft->ntyp == NAME)
+				{	printf("%4d: Basename %s	index %s\n",
+						n->lft->ln, s->name, n->lft->sym->name);
+				}
+#endif
+				cat3("[ Index(", n->lft, ", ");
 				fprintf(fd, "%d) ]", s->nel);
-			}
-		}
-	}
+		}	}
+	} else
+	{	if (n->lft	/* effectively a scalar, but with an index */
+		&& (n->lft->ntyp != CONST
+		||  n->lft->val != 0))
+		{	fatal("ref to scalar '%s' using array index", (char *) ptr);
+	}	}
+
 	if (s->type == STRUCT && n->rgt && n->rgt->lft)
 	{	putname(fd, ".", n->rgt->lft, m, "");
 	}
-	fprintf(fd, suff);
+shortcut:
+	fprintf(fd, suff, 0);
 }
 
 void
@@ -2908,7 +3336,11 @@
 			putstmnt(fd, n->lft->lft, m);	/* pid */
 			fprintf(fd, "]");
 		}
-		fprintf(fd, ".%s", n->sym->name);
+		if (ltl_mode)
+		{	fprintf(fd, ":%s", n->sym->name);
+		} else
+		{	fprintf(fd, ".%s", n->sym->name);
+		}
 	} else
 	{	if (Sym_typ(n) < SHORT)
 		{	promoted = 1;
diff -r 51b3bf8bc61b sys/src/cmd/spin/pangen2.h
--- a/sys/src/cmd/spin/pangen2.h	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/pangen2.h	Wed Nov 22 00:21:47 2017 -0800
@@ -1,32 +1,15 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://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\");",
-	"}",
+static const char *Pre0[] = {
+	"#ifdef SC",
+	"	#define _FILE_OFFSET_BITS	64",	/* allows file sizes greater than 2Gb */
 	"#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>",
@@ -38,12 +21,14 @@
 		"#include <time.h>",
 	"#else",
 		"#include <unistd.h>",
-		"#include <sys/times.h>",	/* new 4.3.0 */
+		"#include <sys/times.h>",
 	"#endif",
 	"#include <sys/types.h>",	/* defines off_t */
 	"#include <sys/stat.h>",
+	"#include <limits.h>",
 	"#include <fcntl.h>",
-	"#define Offsetof(X, Y)	((unsigned long)(&(((X *)0)->Y)))",
+
+	"#define Offsetof(X, Y)	((ulong)(&(((X *)0)->Y)))",
 	"#ifndef max",
 	"#define max(a,b) (((a)<(b)) ? (b) : (a))",
 	"#endif",
@@ -53,12 +38,62 @@
 	0,
 };
 
-static char *Preamble[] = {
+static const char *Separate[] = {
+	"#ifdef COLLAPSE",
+	"	#if (NCORE>1 && !defined(SEP_STATE)) || defined(BFS_PAR)",
+	"		volatile ulong *ncomps;	/* in shared memory */",
+	"	#else",
+	"		ulong ncomps[256+2];",
+	"	#endif",
+	"#endif",
+	"Trans ***trans;	/* 1 ptr per state per proctype */\n",
+	"",
+	"#if VECTORSZ>32000",
+	"	int P_o[MAXPROC], P_o_tmp[MAXPROC+1];",
+	"	int Q_o[MAXQ],    Q_o_tmp[MAXPROC+1];",
+	"",
+	"	int *proc_offset = (int *) P_o;",
+	"	int *q_offset    = (int *) Q_o;",
+	"#else",
+	"	short P_o[MAXPROC], P_o_tmp[MAXPROC+1];",
+	"	short Q_o[MAXQ],    Q_o_tmp[MAXPROC+1];",
+	"",
+	"	short *proc_offset = (short *) P_o;",
+	"	short *q_offset    = (short *) Q_o;",
+	"#endif",
+	"uchar P_s[MAXPROC+1], P_s_tmp[MAXPROC+1];",
+	"uchar Q_s[MAXQ+1],    Q_s_tmp[MAXQ+1];",
+	"uchar *proc_skip = (uchar *) P_s;",
+	"uchar *q_skip    = (uchar *) Q_s;",
+	"",
+	"#ifdef TRIX",
+	"	TRIX_v6 *freebodies;",
+	"	TRIX_v6 *processes[MAXPROC+1];",
+	"	TRIX_v6 *channels[MAXQ+1];",
+	"	long _p_count[MAXPROC];",
+	"	long _c_count[MAXPROC];",
+	"#endif\n",
+	"ulong  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 */",
+	"int _;	/* predefined write-only variable */",
+	"#ifdef PEG",
+	"	long peg[NTRANS];",
+	"#endif",
+	0,
+};
 
+static const char *Preamble[] = {
+	"#ifdef RANDOMIZE",
+	"	#define T_RAND  RANDOMIZE",
+	"#endif",
 	"#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]--",
+	"	#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)",
@@ -68,13 +103,13 @@
 		 * 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;",
+	"	#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",
+	"	#define V_A	0",
+	"	#define A_V	0",
+	"	#define S_A	0",
 	"#endif",
 
 "#ifdef MA",
@@ -82,7 +117,7 @@
 	"#undef onstack_put",
 	"#undef onstack_zap",
 	"#define onstack_put()	;",
-	"#define onstack_zap()	gstore((char *) &now, vsize, 4)",
+	"#define onstack_zap()	g_store((char *) &now, vsize, 4)",
 "#else",
 	"#if defined(FULLSTACK) && !defined(BITSTATE)",
 	"#define onstack_put()	trpt->ostate = Lstate",
@@ -93,165 +128,284 @@
 	"	}",
 	"#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;",
+	"H_el	**H_tab, **S_Tab;",
+	"/* #ifndef BFS_PAR */",
+	"	H_el   *Lstate;",
+	"/* #endif */",
 	"Trail	*trail, *trpt;",
-
 	"FILE	*efd;",
 	"uchar	*this;",
 	"long	maxdepth=10000;",
 	"long	omaxdepth=10000;",
+	"#ifdef BCS",
+	"	/* bitflags in trpt->bcs */",
+	"	#define B_PHASE1	1",
+	"	#define B_PHASE2	2",
+	"	#define B_FORCED	4",
+	"int	sched_max = 0;",
+	"#endif",
+	"",
+	"double	quota;	/* time limit */",
+	"#if NCORE>1",
+	"	long	z_handoff = -1;",
+	"#endif",
 	"#ifdef SC",	/* stack cycling */
-	"char	*stackfile;",
+	"	char	*stackfile;",
  	"#endif",
 	"uchar	*SS, *LL;",
+	"",
+	"uchar	reversing = 0;",
 	"uchar	HASH_NR = 0;",
 	"",
 	"double memcnt = (double) 0;",
-	"double memlim = (double) (1<<30);",
+	"double memlim = (double) (1<<30); /* 1 GB */",
+	"#if NCORE>1",
+	"double mem_reserved = (double) 0;",
+	"#endif",
 	"",
 	"/* for emalloc: */",
 	"static char *have;",
 	"static long left = 0L;",
 	"static double fragment = (double) 0;",
-	"static unsigned long grow;",
+	"static ulong grow;",
 	"",
+#if 1
+	"unsigned int HASH_CONST[] = {",
+	"	/* generated by hashgen 421 -- assumes 4 bytes per int */",
+	"	0x100d4e63,	0x0fc22f87,	0xa7155c77,	0x78f2c3b9,",
+	"	0xde32d207,	0xc27d305b,	0x1bb3fb2b,	0x2798c7a5,",
+	"	0x9c675ffd,	0x777d9081,	0x07aef2f1,	0xae08922f,",
+	"	0x5bd365b7,	0xed51c47b,	0x9b5aeea1,	0xbcc9d431,",
+	"	0x396d8fff,	0xa2fd1367,	0x08616521,	0x5e84991f,",
+	"	0x87495bc5,	0x2930039b,	0xceb6a593,	0xfe522d63,",
+	"	0x7ff60baf,	0xf89b1fbf,	0x74c01755,	0xe0c559bf,",
+	"	0x3669fc47,	0x8756d3bf,	0x14f78445,	0x24c41779,",
+	"	0x0af7b129,	0xde22368d,	0x3e1c01e3,	0xaf773e49,",
+	"	0x5b762459,	0x86d12911,	0x0953a3af,	0xb66dc23d,",
+	"	0x96b3bd4f,	0x19b1dd51,	0xd886fbc3,	0xa7f3a025,",
+	"	0xccb48e63,	0x87d8f027,	0x2bea270d,	0xdb0e9379,",
+	"	0x78c09f21,	0x0cbbfe07,	0xea4bc7c3,	0x5bfbc3c9,",
+	"	0x3c6e53fd,	0xab320cdd,	0x31041409,	0x416e7485,",
+	"	0xe41d75fd,	0xc3c5060f,	0x201a9dc1,	0x93dee72b,",
+	"	0x6461305f,	0xc571dec5,	0xa1fd21c5,	0xfb421ce1,",
+	"	0x7f024b05,	0xfa518819,	0x6c9777fb,	0x0d4d9351,",
+	"	0x08b33861,	0xccb9d0f3,	0x34112791,	0xe962d7c9,",
+	"	0x8d742211,	0xcd9c47a1,	0x64437b69,	0x5fe40feb,",
+	"	0x806113cb,	0x10e1d593,	0x821851b3,	0x057a1ff3,",
+	"	0x8ededc0b,	0x90dd5b31,	0x635ff359,	0x68dbcd35,",
+	"	0x1050ff4f,	0xdbb07257,	0x486336db,	0x83af1e75,",
+	"	0x432f1799,	0xc1d0e7e7,	0x21f4eb5b,	0x881ec2c1,",
+	"	0x23f3b539,	0x6cdfb80d,	0x71d474cf,	0x97d5d4a9,",
+	"	0xf721d2e5,	0xb5ff3711,	0x3f2e58cd,	0x4e06e3d9,",
+	"	0x7d711739,	0x927887df,	0x7d57ad71,	0x232eb767,",
+	"	0xe3f5cc51,	0x6576b443,	0xed17bf1f,	0x8828b637,",
+	"	0xc940f6ab,	0xc7b830ef,	0x11ed8a13,	0xaff20949,",
+	"	0xf28a8465,	0x0da10cf9,	0xb512497d,	0x44accae1,",
+	"	0x95e0929f,	0xe08c8901,	0xfd22d6c9,	0xb6a5c029,",
+	"	0xaadb428d,	0x6e8a453d,	0x3d5c0195,	0x8bf4ae39,",
+	"	0xbf83ab19,	0x3e9dac33,	0xc4df075d,	0x39472d71,",
+	"	0xb8647725,	0x1a6d4887,	0x78a03577,	0xafd76ef7,",
+	"	0xc1a1d6b3,	0x1afb33c5,	0x87896299,	0x5cc992ef,",
+	"	0x7f805d0d,	0x089a039b,	0xa353cc27,	0x57b296b3,",
+	"	0x52badec9,	0xc916e431,	0x09171957,	0x14996d51,",
+	"	0xe87e32c7,	0xb4fdbb5d,	0xdd216a03,	0x4ddd3fff,",
+	"	0x767d5c57,	0x79c97509,	0xab70543b,	0xc5feca4f,",
+	"	0x8eb37b89,	0x20a2cefd,	0xf4b00b91,	0xf166593d,",
+	"	0x7bf50f65,	0x753e6c8b,	0xfb5b81dd,	0xf2d45ef5,",
+	"	0x9741c04f,	0x300da48d,	0x01dc4121,	0xa112cd47,",
+	"	0x0223b24b,	0xa89fbce7,	0x681e1f7b,	0xe7c6aedf,",
+	"	0x1fd3d523,	0x561ba723,	0xf54042fb,	0x1a516751,",
+	"	0xcd085bd5,	0xe74246d5,	0x8b170b5d,	0x249985e9,",
+	"	0x5b4d9cf7,	0xe9912323,	0x5fc0f339,	0x41f8f051,",
+	"	0x8a296fb1,	0x62909f51,	0x2c05d695,	0x095efccb,",
+	"	0xa91574f1,	0x0f5cc6c3,	0x23a2ca2b,	0xc6053ec1,",
+	"	0xeb19e081,	0x3d1b3997,	0xb0c5f3cd,	0xe5d85b35,",
+	"	0x1cb1bdf1,	0x0c8f278f,	0x518249c3,	0x9f61b68d,",
+	"	0xade0919d,	0x779e29c3,	0xdbac9485,	0x2ce149a9,",
+	"	0x254c2409,	0x205b34fb,	0xc8ab1a89,	0x6b4a2585,",
+	"	0x2303d94b,	0x8fa186b9,	0x49826da5,	0xd23a37ad,",
+	"	0x680b18c9,	0xa46fbd7f,	0xe42c2cf9,	0xf7cfcb5f,",
+	"	0xb4842b8b,	0xe483780d,	0x66cf756b,	0x3eb73781,",
+	"	0x41ca17a5,	0x59f91b0f,	0x92fb67d9,	0x0a5c330f,",
+	"	0x46013fdb,	0x3b0634af,	0x9024f533,	0x96a001a7,",
+	"	0x15bcd793,	0x3a311fb1,	0x78913b8b,	0x9d4a5ddf,",
+	"	0x33189b31,	0xa99e8283,	0xf7cb29e9,	0x12d64a27,",
+	"	0xeda770ff,	0xa7320297,	0xbd3c14a5,	0x96d0156f,",
+	"	0x0115db95,	0x7f79f52b,	0xa6d52521,	0xa063d4bd,",
+	"	0x9cb5e039,	0x42cf8195,	0xcb716835,	0x1bc21273,",
+	"	0x5a67ad27,	0x4b3b0545,	0x162cda67,	0x0489166b,",
+	"	0x85fd06a9,	0x562b037d,	0x995bc1f3,	0xe144e78b,",
+	"	0x1e749f69,	0xa36df057,	0xcfee1667,	0x8c4116b7,",
+	"	0x94647fe3,	0xe6899df7,	0x6d218981,	0xf1069079,",
+	"	0xd1851a33,	0xf424fc83,	0x24467005,	0xad8caf59,",
+	"	0x1ae5da13,	0x497612f9,	0x10f6d1ef,	0xeaf4ff05,",
+	"	0x405f030b,	0x693b041d,	0x2065a645,	0x9fec71b3,",
+	"	0xc3bd1b0f,	0xf29217a3,	0x0f25e15d,	0xd48c2b97,",
+	"	0xce8acf2d,	0x0629489b,	0x1a5b0e01,	0x32d0c059,",
+	"	0x2d3664bf,	0xc45f3833,	0xd57f551b,	0xbdd991c5,",
+	"	0x9f97da9f,	0xa029c2a9,	0x5dd0cbdf,	0xe237ba41,",
+	"	0x62bb0b59,	0x93e7d037,	0x7e495619,	0x51b8282f,",
+	"	0x853e8ef3,	0x9b8abbeb,	0x055f66f9,	0x2736f7e5,",
+	"	0x8d7e6353,	0x143abb65,	0x4e2bb5b3,	0x872e1adf,",
+	"	0x8fcac853,	0xb7cf6e57,	0x12177f3d,	0x1d2da641,",
+	"	0x07856425,	0xc0ed53dd,	0x252271d9,	0x79874843,",
+	"	0x0aa8c9b5,	0x7e804f93,	0x2d080e09,	0x3929ddfd,",
+	"	0x36433dbd,	0xd6568c17,	0xe624e939,	0xb33189ef,",
+	"	0x29e68bff,	0x8aae2433,	0xe6335499,	0xc5facd9d,",
+	"	0xbd5afc65,	0x7a584fa7,	0xab191435,	0x64bbdeef,",
+	"	0x9f5cd8e1,	0xb3a1be05,	0xbd0c1753,	0xb00e2c7f,",
+	"	0x6a96e315,	0x96a31589,	0x660af5af,	0xc0438d43,",
+	"	0x17637373,	0x6460e8df,	0x7d458de9,	0xd76b923f,",
+	"	0x316f045f,	0x3ccbd035,	0x63f64d81,	0xd990d969,",
+	"	0x7c860a93,	0x99269ff7,	0x6fbcac8f,	0xd8cc562b,",
+	"	0x67141071,	0x09f85ea3,	0x1298f2dd,	0x41fa86e5,",
+	"	0xce1d7cf5,	0x6b232c9d,	0x8f093d4b,	0x3203ad4b,",
+	"	0x07d70d5f,	0x38c44c75,	0x0887c9ef,	0x1833acf5,",
+	"	0xa3607f85,	0x7d367573,	0x0ea4ffc3,	0xad2d09c1,",
+	"	0x7a1e664f,	0xef41dff5,	0x03563491,	0x67f30a1f,",
+	"	0x5ce5f9ef,	0xa2487a27,	0xe5077957,	0x9beb36fd,",
+	"	0x16e41251,	0x216799ef,	0x07181f8d,	0xc191c3cf,",
+	"	0xba21cab5,	0x73944eb7,	0xdf9eb69d,	0x5fef6cfd,",
+	"	0xd750a6f5,	0x04f3fa43,	0x7cb2d063,	0xd3bdb369,",
+	"	0x35f35981,	0x9f294633,	0x5e293517,	0x70e51d05,",
+	"	0xf8db618d,	0x66ee05db,	0x835eaa77,	0x166a02c3,",
+	"	0xb516f283,	0x94102293,	0x1ace50a5,	0x64072651,",
+	"	0x66df7b75,	0x02e1b261,	0x8e6a73b9,	0x19dddfe7,",
+	"	0xd551cf39,	0x391c17cb,	0xf4304de5,	0xcd67b8d1,",
+	"	0x25873e8d,	0x115b4c71,	0x36e062f3,	0xaec0c7c9,",
+	"	0xd929f79d,	0x935a661b,	0xda762b47,	0x170bd76b,",
+	"	0x1a955cb5,	0x341fb0ef,	0x7f366cef,	0xc98f60c7,",
+	"	0xa4181af3,	0xa94a8837,	0x5fa3bc43,	0x11c638c1,",
+	"	0x4e66fabb,	0x30ab85cf,	0x250704ef,	0x8bf3bc07,",
+	"	0x6d2cd5ab,	0x613ef9c3,	0xb8e62149,	0x0404fd91,",
+	"	0xa04fd9b1,	0xa5e389eb,	0x9543bd23,	0xad6ca1f9,",
+	"	0x210c49ab,	0xf8e9532b,	0x854fba89,	0xdc7fc6bb,",
+	"	0x48a051a7,	0x6b2f383b,	0x61a4b433,	0xd3af231b,",
+	"	0xc5023fc7,	0xa5aa85df,	0xa0cd1157,	0x4206f64d,",
+	"	0x3fea31c3,	0x62d510a1,	0x13988957,	0x6a11a033,",
+	"	0x46f2a3b7,	0x2784ef85,	0x229eb9eb,	0x9c0c3053,",
+	"	0x5b7ead39,	0x82ae9afb,	0xf99e9fb3,	0x914b6459,",
+	"	0xaf05edd7,	0xc82710dd,	0x8fc1ea1f,	0x7e0d7a8d,",
+	"	0x7c7592e9,	0x65321017,	0xea57553f,	0x4aeb49ff,",
+	"	0x5239ae4d,	0x4b4b4585,	0x94091c21,	0x7eaaf4cb,",
+	"	0x6b489d6f,	0xecb9c0c3,	0x29a7af63,	0xaf117a0d,",
+	"	0x969ea6cd,	0x7658a34d,	0x5fc0bba9,	0x26e99b7f,",
+	"	0x7a6f260f,	0xe37c34f1,	0x1a1569bb,	0xc3bc7371,",
+	"	0x8567543d,	0xad0c46a9,	0xa1264fd9,	0x16f10b29,",
+	"	0x5e00dd3b,	0xf85b6bcd,	0xa2d32d8b,	0x4a3c8d43,",
+	"	0x6b33b959,	0x4fd1e6c9,	0x7938b8a9,	0x1ec795c7,",
+	"	0xe2ef3409,	0x83c16b9d,	0x0d3fd9eb,	0xeb461ad7,",
+	"	0xb09c831d,	0xaf052001,	0x7911164d,	0x1a9dc191,",
+	"	0xb52a0815,	0x0f732157,	0xc68c4831,	0x12cf3cbb };",
+#else
 	"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;",
+	"	0x100d4e63,	0x0fc22f87,",
+	"	0x3ff0c3ff,	0x38e84cd7,",
+	"	0x02b148e9,	0x98b2e49d,",
+	"	0xb616d379,	0xa5247fd9,",
+	"	0xbae92a15,	0xb91c8bc5,",
+	"	0x8e5880f3,	0xacd7c069,",
+	"	0xb4c44bb3,	0x2ead1fb7,",
+	"	0x8e428171,	0xdbebd459,",
+	"	0x00400007,	0x04c11db7,",
+	"	0x828ae611,	0x6cb25933,",
+	"	0x86cdd651,	0x9e8f5f21,",
+	"	0xd5f8d8e7,	0x9c4e956f,",
+	"	0xb5cf2c71,	0x2e805a6d,",
+	"	0x33fc3a55,	0xaf203ed1,",
+	"	0xe31f5909,	0x5276db35,",
+	"	0x0c565ef7,	0x273d1aa5,",
+	"	0x8923b1dd,	0xa9acaac5,",
+	"	0xd1f69207,	0xedfd944b,",
+	"	0x9a68e46b,	0x5355e13f,",
+	"	0x7eeb44f9,	0x932beea9,",
+	"	0x330c4cd3,	0x87f34e5f,",
+	"	0x1b5851b7,	0xb9ca6447,",
+	"	0x58f96a8f,	0x1b3b5307,",
+	"	0x31c387b3,	0xf35f0f35,",
+	"	0xa0acc4df,	0xf3140303,",
+	"	0x2446245d,	0xe4b8f4ef,",
+	"	0x5c007383,	0x68e648af,",
+	"	0x1814fba7,	0xcdf731b5,",
+	"	0xd09ccb4b,	0xb92d0eff,",
+	"	0xcc3c6b67,	0xd3af6a57,",
+	"	0xf44fc3f5,	0x5bb67623,",
+	"	0xaeb9c953,	0x5e0ac739,",
+	"	0x3a7fda09,	0x5edf39eb,",
+	"	0x661eefd9,	0x6423f0d1,",
+	"	0x910fe413,	0x9ec92297,",
+	"	0x4bd8159d,	0xa7b16ee1,",
+	"	0x89d484e9,	0x7f305cb3,",
+	"	0xc5f303e7,	0x415deeef,",
+	"	0x09986f89,	0x7e9c4117,",
+	"	0x0b7cbedb,	0xf9ed7561,",
+	"	0x7a20ac99,	0xf05adef3,",
+	"	0x5893d75b,	0x44d73327,",
+	"	0xb583c873,	0x324d2145,",
+	"	0x7fa3829b,	0xe4b47a23,",
+	"	0xe256d94f,	0xb1fd8959,",
+	"	0xe561a321,	0x1435ac09,",
+	"	0xdd62408b,	0x02ec0bcb,",
+	"	0x5469b785,	0x2f4f50bb,",
+	"	0x20f19395,	0xf96ba085,",
+	"	0x2381f937,	0x768e2a11 };",
+#endif
+	"",
+	"#if NCORE>1",
+	"extern int core_id;",
+	"#endif",
+	"long	mreached=0;",
+	"int done=0, errors=0, Nrun=1;",
+	"int	c_init_done=0;",
+	"char	*c_stack_start = (char *) 0;",
 	"double	nstates=0, nlinks=0, truncs=0, truncs2=0;",
 	"double	nlost=0, nShadow=0, hcmp=0, ngrabs=0;",
+	"#ifdef BFS_PAR",
+	"extern ulong bfs_punt;",
+	"#endif",
+	"#ifdef PUTPID",
+	"char *progname;",
+	"#endif",
+	"#if defined(ZAPH) && defined(BITSTATE)",
+	"double zstates = 0;",
+	"#endif",
+	"/* int	c_init_run; */",
+	"#ifdef REVERSE",
+	"	#define P_REVERSE",
+	"#endif",
+	"#ifdef T_REVERSE",
+	"	int	t_reverse = 1;", /* can be modified with a parameter */
+	"#else",
+	"	int	t_reverse = 0;",
+	"#endif",
 	"#ifdef BFS",
 	"double midrv=0, failedrv=0, revrv=0;",
 	"#endif",
-	"unsigned long	nr_states=0; /* nodes in DFA */",
+	"ulong	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;",
+	"int	gui = 0, coltrace = 0, readtrail = 0;",
+	"int	whichtrail = 0, whichclaim = -1, onlyproc = -1, silent = 0;",
+	"char	*claimname;",
 	"#endif",
-	"int	state_tables=0, fairness=0, no_rck=0, Nr_Trails=0;",
-	"char	simvals[128];",
+	"int	state_tables=0, fairness=0, no_rck=0, Nr_Trails=0, dodot=0;",
+	"char	simvals[256];",
 	"#ifndef INLINE",
 	"int	TstOnly=0;",
 	"#endif",
-	"unsigned long mask, nmask;",
+	"ulong mask, nmask;",
 	"#ifdef BITSTATE",
-	"int	ssize=23;	/* 1 Mb */",
+	"int	ssize=27;	/* 16 Mb */",
 	"#else",
-	"int	ssize=19;	/* 512K slots */",
+	"int	ssize=24;	/* 16M slots */",
 	"#endif",
 	"int	hmax=0, svmax=0, smax=0;",
 	"int	Maxbody=0, XX;",
-	"uchar	*noptr;	/* used by macro Pptr(x) */",
+	"uchar	*noptr, *noqptr;	/* used by Pptr(x) and Qptr(x) */",
 	"#ifdef VAR_RANGES",
 	"void logval(char *, int);",
 	"void dumpranges(void);",
@@ -260,36 +414,55 @@
 	"#ifdef MA",
 	"#define INLINE_REV",
 	"extern void dfa_init(unsigned short);",
-	"extern int  dfa_member(unsigned long);",
+	"extern int  dfa_member(ulong);",
 	"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 ALIGNED",
+	"	State	comp_now __attribute__ ((aligned (8)));",
+	"	/* gcc 64-bit aligned for Itanium2 systems */",
+	"	/* MAJOR runtime penalty if not used on those systems */",
+	"#else",
+	"	State	comp_now;	/* compressed state vector */",
+	"#endif",
+	"",
+	"#ifndef HC",
+	"	#ifdef BFS_PAR",
+	"		State tmp_msk;",
+	"	#endif",
+	"	State	comp_msk;",
+	"	uchar	*Mask = (uchar *) &comp_msk;",
+	"#endif",
 	"#ifdef COLLAPSE",
-	"State	comp_tmp;",
-	"static char	*scratch = (char *) &comp_tmp;",
+	"	State	comp_tmp;",
+	"	static char	*scratch = (char *) &comp_tmp;",
 	"#endif",
-
-	"Stack	*stack; 	/* for queues, processes */",
+	"",
+	"_Stack	*stack; 	/* for queues, processes */",
 	"Svtack	*svtack;	/* for old state vectors */",
 	"#ifdef BITSTATE",
-	"static unsigned hfns = 3;	/* new default */",
+	"static unsigned int hfns = 3;	/* new default */",
 	"#endif",
-	"static unsigned long j1;",
-	"static unsigned long K1, K2;",
-	"static unsigned long j2, j3, j4;",
+	"static ulong j1_spin, j2_spin; /* 5.2.1: avoid nameclash with math.h */",
+	"static ulong j3_spin, j4_spin;",
+	"ulong K1, K2;",
 	"#ifdef BITSTATE",
-#ifndef POWOW
-	"static long udmem;",
-#endif
+	"long udmem;",
 	"#endif",
+	"#ifndef BFS_PAR",
 	"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;",
+	"#endif",
+	"long	depth = 0;",
+	"long depthfound = -1;	/* loop detection */",
+	/* depth: not static to support -S2, but possible clash with embedded code */
+	"#if NCORE>1",
+	"long nr_handoffs = 0;",
+	"#endif",
+	"uchar	warned = 0, iterative = 0, exclusive = 0, like_java = 0, every_error = 0;",
+	"uchar	noasserts = 0, noends = 0, bounded = 0;",
+	"uint	s_rand = 12345;	/* default seed */",
+
 	"#if SYNC>0 && ASYNC==0",
 	"void set_recvs(void);",
 	"int  no_recvs(int);",
@@ -302,17 +475,32 @@
 	"#define UnBlock     	/* don't bother */",
 	"#endif\n",
 	"#ifdef BITSTATE",
-	"int (*bstore)(char *, int);",
+	"int (*b_store)(char *, int);",
 	"int bstore_reg(char *, int);",
-#ifndef POWOW
 	"int bstore_mod(char *, int);",
-#endif
 	"#endif",
+	"",
+	"void dfs_uerror(char *);",
+	"void dfs_Uerror(char *);",
+	"#ifdef BFS_PAR",
+	"void bfs_uerror(char *);",
+	"void bfs_Uerror(char *);",
+	"#endif",
+	"void (*uerror)(char *);",
+	"void (*Uerror)(char *);",
+	"void (*hasher)(uchar *, int);",
+	"void (*o_hash)(uchar *, int, int);",
+	"void d_hash(uchar *, int);",
+	"void m_hash(uchar *, int);",
+	"void d_sfh(uchar *, int);",
+	"void o_hash32(uchar *, int, int);",
+	"void o_hash64(uchar *, int, int);",
+	"",
 	"void active_procs(void);",
 	"void cleanup(void);",
 	"void do_the_search(void);",
 	"void find_shorter(int);",
-	"void iniglobals(void);",
+	"void iniglobals(int);",
 	"void stopped(int);",
 	"void wrapup(void);",
 	"int *grab_ints(int);",
@@ -320,7 +508,7 @@
 	0,
 };
 
-static char *Tail[] = {
+static const char *Tail[] = {
 	"Trans *",
 	"settr(	int t_id, int a, int b, int c, int d,",
 	"	char *t, int g, int tpe0, int tpe1)",
@@ -425,10 +613,14 @@
 	"}",
 	"#endif",
 	"void",
-	"retrans(int n, int m, int is, short srcln[], uchar reach[])",
+	"retrans(int n, int m, int is, short srcln[], uchar reach[], uchar lpstate[])",
 	"	/* process n, with m states, is=initial state */",
 	"{	Trans *T0, *T1, *T2, *T3;",
-	"	int i, k;",
+	"	Trans *T4, *T5; /* t_reverse or has_unless */",
+	"	int i;",
+	"#if defined(HAS_UNLESS) || !defined(NOREDUCE)",
+	"	int k;",
+	"#endif",
 	"#ifndef NOREDUCE",
 	"	int g, h, j, aa;",
 	"#endif",
@@ -436,7 +628,7 @@
 	"	int p;",
 	"#endif",
 	"	if (state_tables >= 4)",
-	"	{	printf(\"STEP 1 proctype %%s\\n\", ",
+	"	{	printf(\"STEP 1 %%s\\n\", ",
 	"			procname[n]);",
 	"		for (i = 1; i < m; i++)",
 	"		for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
@@ -477,7 +669,7 @@
 	"	} while (cnt);",
 
 	"	if (state_tables >= 3)",
-	"	{	printf(\"STEP 2 proctype %%s\\n\", ",
+	"	{	printf(\"STEP 2 %%s\\n\", ",
 	"			procname[n]);",
 	"		for (i = 1; i < m; i++)",
 	"		for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
@@ -490,7 +682,9 @@
 	"#if 0",
 	"			printf(\"\\t\\tpull %%d (%%d) to %%d\\n\",",
 	"			T1->st, T1->forw, i);",
-	"#endif",
+	"#endif",		/* pull linenumber ref as well: */
+	"			srcln[i] = srcln[T1->st];	/* Oyvind Teig, 5.2.0 */",
+	"",
 	"			if (!trans[n][T1->st]) continue;",
 	"			T0 = cpytr(trans[n][T1->st]);",
 	"			trans[n][i] = T0;",
@@ -502,6 +696,7 @@
 	"			printf(\"\\t\\tpull %%d (%%d) to %%d\\n\",",
 	"				T1->st, T1->forw, i);",
 	"#endif",
+	"		/*		srcln[i] = srcln[T1->st];  gh: not useful */",
 	"				if (!trans[n][T1->st]) continue;",
 	"				T0->nxt = cpytr(trans[n][T1->st]);",
 	"				T0 = T0->nxt;",
@@ -509,7 +704,7 @@
 	"				imed(T0, T1->st, n, i);",
 	"	}	}	}",
 	"	if (state_tables >= 2)",
-	"	{	printf(\"STEP 3 proctype %%s\\n\", ",
+	"	{	printf(\"STEP 3 %%s\\n\", ",
 	"			procname[n]);",
 	"		for (i = 1; i < m; i++)",
 	"		for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
@@ -525,8 +720,8 @@
 	"		 * and prepend them to the transition-",
 	"		 * list of state i",
 	"		 */",
-	" if (!like_java) /* the default */",
-	" {		for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
+	"	 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)",
@@ -537,9 +732,8 @@
 	"				T2->nxt = trans[n][i];",
 	"				trans[n][i] = T2;",
 	"		}	}",
-	" } else /* outermost unless checked first */",
-	" {		Trans *T4;",
-	"		T4 = T3 = (Trans *) 0;",
+	"	 } else /* outermost unless checked first */",
+	"	 {	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])",
@@ -557,22 +751,21 @@
 	"		{	T3->nxt = trans[n][i];",
 	"			trans[n][i] = T4;",
 	"		}",
-	" }",
+	"	 }",
 	"	}",
 	"#endif",
 
 	"#ifndef NOREDUCE",
 	"	for (i = 1; i < m; i++)",
-	"	{",
-	"		if (a_cycles)",
+	"	{	if (a_cycles)",
 	"		{ /* moves through these states are visible */",
-	"#if PROG_LAB>0 && defined(HAS_NP)",
+	"	#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",
+	"	#endif",
 	"			if (accpstate[n][i] || visstate[n][i])",
 	"				goto degrade;",
 	"			for (T1 = trans[n][i]; T1; T1 = T1->nxt)",
@@ -668,19 +861,44 @@
 	"			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]);",
+	"	if (state_tables && !verbose)",
+	"	{	if (dodot)",
+	"		{	char buf[256], *q = buf, *p = procname[n];",
+	"			while (*p != '\\0')",
+	"			{	if (*p != ':')",
+	"				{	*q++ = *p;",
+	"				}",
+	"				p++;",
+	"			}",
+	"			*q = '\\0';",
+	"			printf(\"digraph \");",
+	"			switch (Btypes[n]) {",
+	"			case I_PROC:  printf(\"init {\\n\"); break;",
+	"			case N_CLAIM: printf(\"claim_%%s {\\n\", buf); break;",
+	"			case E_TRACE: printf(\"notrace {\\n\"); break;",
+	"			case N_TRACE: printf(\"trace {\\n\"); break;",
+	"			default:      printf(\"p_%%s {\\n\", buf); break;",
+	"			}",
+	"			printf(\"size=\\\"8,10\\\";\\n\");",
+	"			printf(\"  GT [shape=box,style=dotted,label=\\\"%%s\\\"];\\n\", buf);",
+	"			printf(\"  GT -> S%%d;\\n\", is);",
+	"		} else",
+	"		{	switch (Btypes[n]) {",
+	"			case I_PROC:  printf(\"init\\n\"); break;",
+	"			case N_CLAIM: printf(\"claim %%s\\n\", procname[n]); break;",
+	"			case E_TRACE: printf(\"notrace assertion\\n\"); break;",
+	"			case N_TRACE: printf(\"trace assertion\\n\"); break;",
+	"			default:      printf(\"proctype %%s\\n\", procname[n]); break;",
+	"		}	}",
 	"		for (i = 1; i < m; i++)",
-	"			reach[i] = 1;",
+	"		{	reach[i] = 1;",
+	"		}",
 	"		tagtable(n, m, is, srcln, reach);",
+	"		if (dodot) printf(\"}\\n\");",
 	"	} else",
 	"	for (i = 1; i < m; i++)",
 	"	{	int nrelse;",
-	"		if (strcmp(procname[n], \":never:\") != 0)",
+	"		if (Btypes[n] != N_CLAIM)",
 	"		{	for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
 	"			{	if (T0->st == i",
 	"				&& strcmp(T0->tp, \"(1)\") == 0)",
@@ -703,16 +921,84 @@
 	"		  	printf(\" 'else' stmnts\\n\");",
 	"			pan_exit(1);",
 	"	}	}",
-	"	if (!state_tables && strcmp(procname[n], \":never:\") == 0)",
-	"	{	int h = 0;",
+	"#if !defined(LOOPSTATE) && !defined(BFS_PAR)",
+	"	if (state_tables)",
+	"#endif",
+	"	do_dfs(n, m, is, srcln, reach, lpstate);",
+	"",
+	"	if (!t_reverse)",
+	"	{	return;",
+	"	}",
+	"	/* process n, with m states, is=initial state -- reverse list */",
+	"	if (!state_tables && Btypes[n] != N_CLAIM)",
+	"	{	for (i = 1; i < m; i++)", /* for each state */
+	"		{	Trans *Tx = (Trans *) 0; /* list of escapes */",
+	"			Trans *Ty = (Trans *) 0; /* its tail element */",
+	"			T1 = (Trans *) 0; /* reversed list */",
+	"			T2 = (Trans *) 0; /* its tail */",
+	"			T3 = (Trans *) 0; /* remembers possible 'else' */",
+	"",
+	"			/* find unless-escapes, they should go first */",
+	"			T4 = T5 = T0 = trans[n][i];",
+	"	#ifdef HAS_UNLESS",
+	"			while (T4 && T4->e_trans) /* escapes are first in orig list */",
+	"			{	T5 = T4;	  /* remember predecessor */",
+	"				T4 = T4->nxt;",
+	"			}",
+	"	#endif",
+	"			/* T4 points to first non-escape, T5 to its parent, T0 to original list */",
+	"			if (T4 != T0)		 /* there was at least one escape */",	
+	"			{	T3 = T5->nxt;		 /* start of non-escapes */",
+	"				T5->nxt = (Trans *) 0;	 /* separate */",
+	"				Tx = T0;		 /* start of the escapes */",
+	"				Ty = T5;		 /* its tail */",
+	"				T0 = T3;		 /* the rest, to be reversed */",
+	"			}",
+	"			/* T0 points to first non-escape, Tx to the list of escapes, Ty to its tail */",
+	"",
+	"			/* first tail-add non-escape transitions, reversed */",
+	"			T3 = (Trans *) 0;", /* remember a possible 'else' */
+	"			for (T5 = T0; T5; T5 = T4)",
+	"			{	T4 = T5->nxt;",
+	"	#ifdef HAS_UNLESS",
+	"				if (T5->e_trans)",
+	"				{	printf(\"error: cannot happen!\\n\");",
+	"					continue;",
+	"				}",
+	"	#endif",
+	"				if (strcmp(T5->tp, \"else\") == 0)",
+	"				{	T3 = T5;",
+	"					T5->nxt = (Trans *) 0;",
+	"				} else",
+	"				{	T5->nxt = T1;",
+	"					if (!T1) { T2 = T5; }",
+	"					T1 = T5;",
+	"			}	}",
+	"			/* T3 points to a possible else, which is removed from the list */",
+	"			/* T1 points to the reversed list so far (without escapes) */",
+	"			/* T2 points to the tail element -- where the else should go */",
+	"			if (T2 && T3)",
+	"			{	T2->nxt = T3;	/* add else */",
+	"			} else",
+	"			{	if (T3) /* there was an else, but there's no tail */",
+	"				{	if (!T1)	/* and no reversed list */",
+	"					{	T1 = T3; /* odd, but possible */",
+	"					} else		/* even stranger */",
+	"					{	T1->nxt = T3;",
+	"			}	}	}",
+	"",
+	"			/* add in the escapes, to that they appear at the front */",
+	"			if (Tx && Ty) { Ty->nxt = T1; T1 = Tx; }",
+	"",
+	"			trans[n][i] = T1;",
+	"			/* reversed, with escapes first and else last */",
+	"	}	}",
+	"	if (state_tables && verbose)",
+	"	{	printf(\"FINAL proctype %%s\\n\", ",
+	"			procname[n]);",
 	"		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;",
+	"			crack(n, i, T0, srcln);",
 	"	}",
 	"}",
 	"void",
@@ -731,7 +1017,12 @@
 	"	reach[is] = 0;",
 	"	if (state_tables)",
 	"	for (z = trans[n][is]; z; z = z->nxt)",
-	"		crack(n, is, z, srcln);",
+	"	{	if (dodot)",
+	"			dot_crack(n, is, z);",
+	"		else",
+	"			crack(n, is, z, srcln);",
+	"	}",
+	"",
 	"	for (z = trans[n][is]; z; z = z->nxt)",
 	"	{",
 	"#ifdef HAS_UNLESS",
@@ -747,6 +1038,47 @@
 	"#endif",
 	"	}",
 	"}",
+	"",
+	"extern Trans *t_id_lkup[];",	/* needed by BFS_PAR */
+	"",
+	"void",
+	"dfs_table(int n, int m, int is, short srcln[], uchar reach[], uchar lpstate[])",
+	"{	Trans *z;\n",
+	"	if (is >= m || is <= 0 || !trans[n][is])",
+	"		return;",
+	"	if ((reach[is] & (4|8|16)) != 0)",
+	"	{	if ((reach[is] & (8|16)) == 16)	/* on stack, not yet recorded */",
+	"		{	lpstate[is] = 1;",
+	"			reach[is] |= 8; /* recorded */",
+	"			if (state_tables && verbose)",
+	"			{	printf(\"state %%d line %%d is a loopstate\\n\", is, srcln[is]);",
+	"		}	}",
+	"		return;",
+	"	}",
+	"	reach[is] |= (4|16);	/* visited | onstack */",
+	"	for (z = trans[n][is]; z; z = z->nxt)",
+	"	{	t_id_lkup[z->t_id] = z;",	/* needed by BFS_PAR */
+	"#ifdef HAS_UNLESS",
+	"		int i, j;",
+	"#endif",
+	"		dfs_table(n, m, z->st, srcln, reach, lpstate);",
+	"#ifdef HAS_UNLESS",
+	"		for (i = 0; i < HAS_UNLESS; i++)",
+	"		{	j = trans[n][is]->escp[i];",
+	"			if (!j) break;",
+	"			dfs_table(n, m, j, srcln, reach, lpstate);",
+	"		}",
+	"#endif",
+	"	}",
+	"	reach[is] &= ~16; /* no longer on stack */",
+	"}",
+	"void",
+	"do_dfs(int n, int m, int is, short srcln[], uchar reach[], uchar lpstate[])",
+	"{	int i;",
+	"	dfs_table(n, m, is, srcln, reach, lpstate);",
+	"	for (i = 0; i < m; i++)",
+	"		reach[i] &= ~(4|8|16);",
+	"}",
 	"void",
 	"crack(int n, int j, Trans *z, short srcln[])",
 	"{	int i;\n",
@@ -765,19 +1097,19 @@
 	"	}",
 	"#endif",
 	"	printf(\"]\");",
-	"	printf(\" [%%s%%s%%s%%s%%s] line %%d => \",",
+	"	printf(\" [%%s%%s%%s%%s%%s] %%s:%%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]);",
+	"		PanSource, 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])",
+	"	if (verbose && z->qu[0])",
 	"	{	printf(\"\\t[\");",
 	"		for (i = 0; i < 6; i++)",
 	"			if (z->qu[i])",
@@ -788,6 +1120,32 @@
 	"	printf(\"\\n\");",
 	"	fflush(stdout);",
 	"}",
+	"/* spin -a m.pml; cc -o pan pan.c; ./pan -D | dot -Tps > foo.ps; ps2pdf foo.ps */",
+	"void",
+	"dot_crack(int n, int j, Trans *z)",
+	"{	int i;\n",
+	"	if (!z) return;",
+	"	printf(\"\tS%%d -> S%%d  [color=black\", j, z->st);",
+	"",
+	"	if (z->atom&6) printf(\",style=dashed\");",		/* A */
+	"	else if (z->atom&32) printf(\",style=dotted\");",	/* D */
+	"	else if (z->atom&8) printf(\",style=solid\");",		/* L */
+	"	else printf(\",style=bold\");",				/* G */
+		/* other styles: filled dotted */
+	"",
+	"	printf(\",label=\\\"\");",
+	"	for (i = 0; z->tp[i]; i++)",
+	"	{	if (z->tp[i] == \'\\\\\'",
+	"		&&  z->tp[i+1] == \'n\')",
+	"		{	i++; printf(\" \");",
+	"		} else",
+	"		{	putchar(z->tp[i]);",
+	"	}	}",
+	"	printf(\"\\\"];\\n\");",
+	"	if (accpstate[n][j]) printf(\"  S%%d [color=red,style=bold];\\n\", j);",
+	"	else if (progstate[n][j]) printf(\"  S%%d [color=green,style=bold];\\n\", j);",
+	"	if (stopstate[n][j]) printf(\"  S%%d [color=blue,style=bold,shape=box];\\n\", j);",
+	"}",
 	"",
 	"#ifdef VAR_RANGES",
 	"#define BYTESIZE	32	/* 2^8 : 2^3 = 256:8 = 32 */",
diff -r 51b3bf8bc61b sys/src/cmd/spin/pangen3.c
--- a/sys/src/cmd/spin/pangen3.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/pangen3.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,22 +1,20 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include "spin.h"
 #include "y.tab.h"
+#include <assert.h>
 
-extern FILE	*th;
-extern int	claimnr, eventmapnr;
+extern FILE	*th, *tc;
+extern int	eventmapnr, old_priority_rules;
 
 typedef struct SRC {
-	short ln, st;	/* linenr, statenr */
+	int ln, st;	/* linenr, statenr */
 	Symbol *fn;	/* filename */
 	struct SRC *nxt;
 } SRC;
@@ -28,16 +26,18 @@
 static SRC	*frst = (SRC *) 0;
 static SRC	*skip = (SRC *) 0;
 
+extern int	ltl_mode;
+
 extern void	sr_mesg(FILE *, int, int);
 
 static void
 putnr(int n)
 {
 	if (col++ == 8)
-	{	fprintf(th, "\n\t");
+	{	fprintf(tc, "\n\t");	/* was th */
 		col = 1;
 	}
-	fprintf(th, "%3d, ", n);
+	fprintf(tc, "%3d, ", n);	/* was th */
 }
 
 static void
@@ -47,7 +47,7 @@
 		return;
 
 	if (lastfnm)
-		fprintf(th, "{ %s, %d, %d },\n\t",
+		fprintf(tc, "{ \"%s\", %d, %d },\n\t",	/* was th */
 			lastfnm->name,
 			lastfrom,
 			j-1);
@@ -59,73 +59,118 @@
 putfnm_flush(int j)
 {
 	if (lastfnm)
-		fprintf(th, "{ %s, %d, %d }\n",
+		fprintf(tc, "{ \"%s\", %d, %d }\n",	/* was th */
 			lastfnm->name,
 			lastfrom, j);
 }
 
+static SRC *
+newsrc(int m, SRC *n)
+{	SRC *tmp;
+	tmp = (SRC *) emalloc(sizeof(SRC));
+	tmp->st  = m;
+	tmp->nxt = n;
+	return tmp;
+}
+
 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;
+{	SRC *tmp, *lst = (SRC *)0;
+	/* 6.4.0: now an ordered list */
+	for (tmp = skip; tmp; lst = tmp, tmp = tmp->nxt)
+	{	if (tmp->st == m)
+		{	return;
+		}
+		if (tmp->st > m)	/* insert before */
+		{	if (tmp == skip)
+			{	tmp = newsrc(m, skip);
+				skip = tmp;
+			} else
+			{	assert(lst);
+				tmp = newsrc(m, lst->nxt);
+				lst->nxt = tmp;
+			}
+			return;	
+	}	}
+	/* insert at the end */
+	if (lst)
+	{	lst->nxt = newsrc(m, 0);
+	} else	/* empty list */
+	{	skip = newsrc(m, 0);
+	}
 }
 
 void
 unskip(int m)	/* a state that needs to be reached after all */
-{	SRC *tmp, *lst=(SRC *)0;
+{	SRC *tmp, *lst = (SRC *)0;
 
 	for (tmp = skip; tmp; lst = tmp, tmp = tmp->nxt)
-		if (tmp->st == m)
+	{	if (tmp->st == m)
 		{	if (tmp == skip)
 				skip = skip->nxt;
-			else
+			else if (lst)	/* always true, but helps coverity */
 				lst->nxt = tmp->nxt;
 			break;
 		}
+		if (tmp->st > m)
+		{	break;	/* m is not in list */
+	}	}
 }
 
 void
 putsrc(Element *e)	/* match states to source lines */
-{	SRC *tmp;
+{	SRC *tmp, *lst = (SRC *)0;
 	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)
+	/* 6.4.0: now an ordered list */
+	for (tmp = frst; tmp; lst = 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,
+			printf("putsrc mismatch seqno %d, line %d - %d, file %s\n", m, n,
 				tmp->ln, tmp->fn->name);
 			return;
 		}
-	tmp = (SRC *) emalloc(sizeof(SRC));
-	tmp->ln = (short) n;
-	tmp->st = (short) m;
+		if (tmp->st > m) /* insert before */
+		{	if (tmp == frst)
+			{	tmp = newsrc(m, frst);
+				frst = tmp;
+			} else
+			{	assert(lst);
+				tmp = newsrc(m, lst->nxt);
+				lst->nxt = tmp;
+			}
+			tmp->ln = n;
+			tmp->fn = e->n->fn;
+			return;
+	}	}
+	/* insert at the end */
+	tmp = newsrc(m, lst?lst->nxt:0);
+	tmp->ln = n;
 	tmp->fn = e->n->fn;
-	tmp->nxt = frst;
-	frst = tmp;
+	if (lst)
+	{	lst->nxt = tmp;
+	} else
+	{	frst = tmp;
+	}
 }
 
 static void
 dumpskip(int n, int m)
 {	SRC *tmp, *lst;
+	FILE *tz = tc;	/* was th */
 	int j;
 
-	fprintf(th, "uchar reached%d [] = {\n\t", m);
+	fprintf(tz, "uchar reached%d [] = {\n\t", m);
+	tmp = skip;
+	lst = (SRC *) 0;
 	for (j = 0, col = 0; j <= n; j++)
-	{	lst = (SRC *) 0;
-		for (tmp = skip; tmp; lst = tmp, tmp = tmp->nxt)
-			if (tmp->st == j)
+	{	/* find j in the sorted list */
+		for ( ; tmp; lst = tmp, tmp = tmp->nxt)
+		{	if (tmp->st == j)
 			{	putnr(1);
 				if (lst)
 					lst->nxt = tmp->nxt;
@@ -133,12 +178,17 @@
 					skip = tmp->nxt;
 				break;
 			}
+			if (tmp->st > j)
+			{	putnr(0);
+				break;	/* j is not in the list */
+		}	}
+
 		if (!tmp)
-			putnr(0);
-	}
-	fprintf(th, "};\n");
-	if (m == claimnr)
-		fprintf(th, "#define reached_claim	reached%d\n", m);
+		{	putnr(0);
+	}	}
+	fprintf(tz, "};\n");
+	fprintf(tz, "uchar *loopstate%d;\n", m);
+
 	if (m == eventmapnr)
 		fprintf(th, "#define reached_event	reached%d\n", m);
 
@@ -149,27 +199,34 @@
 dumpsrc(int n, int m)
 {	SRC *tmp, *lst;
 	int j;
+	static int did_claim = 0;
+	FILE *tz = tc;	/* was th */
 
-	fprintf(th, "short src_ln%d [] = {\n\t", m);
+	fprintf(tz, "\nshort src_ln%d [] = {\n\t", m);
+	tmp = frst;
 	for (j = 0, col = 0; j <= n; j++)
-	{	lst = (SRC *) 0;
-		for (tmp = frst; tmp; lst = tmp, tmp = tmp->nxt)
-			if (tmp->st == j)
+	{	for ( ; tmp; tmp = tmp->nxt)
+		{	if (tmp->st == j)
 			{	putnr(tmp->ln);
 				break;
 			}
+			if (tmp->st > j)
+			{	putnr(0);
+				break;
+		}	}
 		if (!tmp)
-			putnr(0);
-	}
-	fprintf(th, "};\n");
+		{	putnr(0);
+	}	}
+	fprintf(tz, "};\n");
 
 	lastfnm = (Symbol *) 0;
-	lastdef.name = "\"-\"";
-	fprintf(th, "S_F_MAP src_file%d [] = {\n\t", m);
+	lastdef.name = "-";
+	fprintf(tz, "S_F_MAP src_file%d [] = {\n\t", m);
+	tmp = frst;
+	lst = (SRC *) 0;
 	for (j = 0, col = 0; j <= n; j++)
-	{	lst = (SRC *) 0;
-		for (tmp = frst; tmp; lst = tmp, tmp = tmp->nxt)
-			if (tmp->st == j)
+	{	for ( ; tmp; lst = tmp, tmp = tmp->nxt)
+		{	if (tmp->st == j)
 			{	putfnm(j, tmp->fn);
 				if (lst)
 					lst->nxt = tmp->nxt;
@@ -177,14 +234,20 @@
 					frst = tmp->nxt;
 				break;
 			}
+			if (tmp->st > j)
+			{	putfnm(j, &lastdef);
+				break;
+		}	}
 		if (!tmp)
-			putfnm(j, &lastdef);
+		{	putfnm(j, &lastdef);
+	}	}
+	putfnm_flush(j);
+	fprintf(tz, "};\n");
+
+	if (pid_is_claim(m) && !did_claim)
+	{	fprintf(tz, "short *src_claim;\n");
+		did_claim++;
 	}
-	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);
 
@@ -237,7 +300,27 @@
 	case GT:	Cat1(">"); break;
 	case LT:	Cat1("<"); break;
 	case NE:	Cat1("!="); break;
-	case EQ:	Cat1("=="); break;
+	case EQ:
+			if (ltl_mode
+			&&  now->lft->ntyp == 'p'
+			&&  now->rgt->ntyp == 'q')	/* remote ref */
+			{	Lextok *p = now->lft->lft;
+
+				fprintf(fd, "(");
+				fprintf(fd, "%s", p->sym->name);
+				if (p->lft)
+				{	fprintf(fd, "[");
+					putstmnt(fd, p->lft, 0); /* pid */
+					fprintf(fd, "]");
+				}
+				fprintf(fd, "@");
+				fprintf(fd, "%s", now->rgt->sym->name);
+				fprintf(fd, ")");
+				break;
+			}
+			Cat1("==");
+			break;
+
 	case OR:	Cat1("||"); break;
 	case AND:	Cat1("&&"); break;
 	case LSHIFT:	Cat1("<<"); break;
@@ -298,6 +381,22 @@
 	case ENABLED:	Cat3("enabled(", now->lft, ")");
 			break;
 
+	case GET_P:	if (old_priority_rules)
+			{	fprintf(fd, "1");
+			} else
+			{	Cat3("get_priority(", now->lft, ")");
+			}
+			break;
+
+	case SET_P:	if (!old_priority_rules)
+			{	fprintf(fd, "set_priority(");
+				comwork(fd, now->lft->lft, m);
+				fprintf(fd, ", ");
+				comwork(fd, now->lft->rgt, m);
+				fprintf(fd, ")");
+			}
+			break;
+
 	case EVAL:	Cat3("eval(", now->lft, ")");
 			break;
 
@@ -320,12 +419,14 @@
 			}
 			break;	
 
-	case ASGN:	comwork(fd,now->lft,m);
+	case ASGN:
+			if (check_track(now) == STRUCT) { break; }
+			comwork(fd,now->lft,m);
 			fprintf(fd," = ");
 			comwork(fd,now->rgt,m);
 			break;
 
-	case PRINT:	{	char c, buf[512];
+	case PRINT:	{	char c, buf[1024];
 				strncpy(buf, now->sym->name, 510);
 				for (i = j = 0; i < 510; i++, j++)
 				{	c = now->sym->name[i];
@@ -349,9 +450,23 @@
 			comwork(fd, now->lft, m);
 			fprintf(fd, ")");
 			break;
-	case NAME:	putname(fd, "", now, m, "");
+	case NAME:
+			putname(fd, "", now, m, "");
 			break;
-	case   'p':	putremote(fd, now, m);
+
+	case   'p':
+			if (ltl_mode)
+			{	fprintf(fd, "%s", now->lft->sym->name); /* proctype */
+				if (now->lft->lft)
+				{	fprintf(fd, "[");
+					putstmnt(fd, now->lft->lft, 0); /* pid */
+					fprintf(fd, "]");
+				}
+				fprintf(fd, ":");	/* remote varref */
+				fprintf(fd, "%s", now->sym->name);	/* varname */
+				break;
+			}
+			putremote(fd, now, m);
 			break;
 	case   'q':	fprintf(fd, "%s", now->sym->name);
 			break;
@@ -366,7 +481,7 @@
 	case  ELSE:	fprintf(fd, "else"); break;
 	case   '@':	fprintf(fd, "-end-"); break;
 
-	case D_STEP:	fprintf(fd, "D_STEP"); break;
+	case D_STEP:	fprintf(fd, "D_STEP%d", now->ln); break;
 	case ATOMIC:	fprintf(fd, "ATOMIC"); break;
 	case NON_ATOMIC: fprintf(fd, "sub-sequence"); break;
 	case IF:	fprintf(fd, "IF"); break;
diff -r 51b3bf8bc61b sys/src/cmd/spin/pangen3.h
--- a/sys/src/cmd/spin/pangen3.h	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/pangen3.h	Wed Nov 22 00:21:47 2017 -0800
@@ -1,22 +1,19 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
-static char *Head0[] = {
+static const char *Head0[] = {
 	"#if defined(BFS) && defined(REACH)",
-	"#undef REACH",	/* redundant with bfs */
+	"	#undef REACH",	/* redundant with bfs */
 	"#endif",
 	"#ifdef VERI",
-		"#define BASE	1",
+	"	#define BASE	1",
 	"#else",
-		"#define BASE	0",
+	"	#define BASE	0",
 	"#endif",
 	"typedef struct Trans {",
 	"	short atom;	/* if &2 = atomic trans; if &8 local */",
@@ -37,108 +34,131 @@
 	"	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)",	*/
+
+	"#ifdef TRIX",
+	"	#define qptr(x)	(channels[x]->body)",
+	"	#define pptr(x)	(processes[x]->body)",
+	"#else",
+	"	#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)",	*/
+	"#endif",
 	"extern uchar *Pptr(int);",
+	"extern uchar *Qptr(int);",
 
-	"#define q_sz(x)	(((Q0 *)qptr(x))->Qlen)\n",
-	"#ifndef VECTORSZ",
-	"#define VECTORSZ	1024           /* sv   size in bytes */",
+	"#define q_sz(x)	(((Q0 *)qptr(x))->Qlen)",
+	"",
+	"#ifdef TRIX",
+	"	#ifdef VECTORSZ",
+	"		#undef VECTORSZ",	/* backward compatibility */
+	"	#endif",
+	"	#if WS==4",
+	"		#define VECTORSZ	2056	/* ((MAXPROC+MAXQ+4)*sizeof(uchar *)) */",
+	"	#else",
+	"		#define VECTORSZ	4112	/* the formula causes probs in preprocessing */",
+	"	#endif",
+	"#else",
+	"	#ifndef VECTORSZ",
+	"		#define VECTORSZ	1024	/* sv size in bytes */",
+	"	#endif",
 	"#endif\n",
+	"#define MAXQ   	255",
+	"#define MAXPROC	255",
+	"",
 	0,
 };
 
-static char *Header[] = {
+static const char *Header[] = {
 	"#ifdef VERBOSE",
-		"#ifndef CHECK",
-		"#define CHECK",
-		"#endif",
-		"#ifndef DEBUG",
-		"#define DEBUG",
-		"#endif",
+	"	#ifndef CHECK",
+	"		#define CHECK",
+	"	#endif",
+	"	#ifndef DEBUG",
+	"		#define DEBUG",
+	"	#endif",
 	"#endif",
 	"#ifdef SAFETY",
-		"#ifndef NOFAIR",
-			"#define NOFAIR",
-		"#endif",
+	"	#ifndef NOFAIR",
+	"		#define NOFAIR",
+	"	#endif",
 	"#endif",
+#if 0
+                 NOREDUCE BITSTATE SAFETY  MA   WS>4
+     CNTRSTACK:     -        +       +     d     -
+     FULLSTACK:     +        d       -     -     d
+                    -        +       d     d     d
+                    -        +       +     d     +
+                    -        -       d     d     d
+     Neither:       +        d       +     d     d
+                    +        d       d     +     d
+#endif
 	"#ifdef NOREDUCE",
-		"#ifndef XUSAFE",
-		"#define XUSAFE",
-		"#endif",
-		"#if !defined(SAFETY) && !defined(MA)",
-			"#define FULLSTACK",
-		"#endif",
+	"	#ifndef XUSAFE",
+	"		#define XUSAFE",
+	"	#endif",
+	"	#if !defined(SAFETY) && !defined(MA)",
+	"		#define FULLSTACK",		/* => NOREDUCE && !SAFETY && !MA */
+	"	#endif",
 	"#else",
-		"#ifdef BITSTATE",
-			"#ifdef SAFETY && !defined(HASH64)",
-				"#define CNTRSTACK",
-			"#else",
-				"#define FULLSTACK",
-			"#endif",
-		"#else",
-			"#define FULLSTACK",
-		"#endif",
+	"	#ifdef BITSTATE",
+	"		#if defined(SAFETY) && WS<=4",
+	"			#define CNTRSTACK",	/* => !NOREDUCE && BITSTATE && SAFETY && WS<=4 */
+	"		#else",
+	"			#define FULLSTACK",	/* => !NOREDUCE && BITSTATE && (!SAFETY || WS>4) */
+	"		#endif",
+	"	#else",
+	"		#define FULLSTACK",		/* => !NOREDUCE && !BITSTATE */
+	"	#endif",
 	"#endif",
 	"#ifdef BITSTATE",
-		"#ifndef NOCOMP",
-		"#define NOCOMP",
-		"#endif",
-		"#if !defined(LC) && defined(SC)",
-		"#define LC",
-		"#endif",
+	"	#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",
+	"	/* accept the above for backward compatibility */",
+	"	#define COLLAPSE",
 	"#endif",
 	"#ifdef HC",
-	"#undef HC",
-	"#define HC4",
+	"	#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 defined(HC0) || defined(HC1) || defined(HC2) || defined(HC3) || defined(HC4)",
+	"	#define HC	4",	/* 2x32 bits */
+	"#endif",	/* really only one hashcompact mode, not 5 */
+	"",
+	"typedef struct _Stack  {	 /* for queues and processes */",
 	"#if VECTORSZ>32000",
 	"	int o_delta;",
-	"	int o_offset;",
-	"	int o_skip;",
+	"	#ifndef TRIX",
+	"		int o_offset;",
+	"		int o_skip;",
+	"	#endif",
 	"	int o_delqs;",
 	"#else",
 	"	short o_delta;",
-	"	short o_offset;",
-	"	short o_skip;",
+	"	#ifndef TRIX",
+	"		short o_offset;",
+	"		short o_skip;",
+	"	#endif",
 	"	short o_delqs;",
 	"#endif",
 	"	short o_boq;",
+	"#ifdef TRIX",
+	"	short parent;",
+	"	char *b_ptr;",	/* used in delq/q_restor and delproc/p_restor */
+	"#else",
+	"	char *body;",	/* full copy of state vector in non-trix mode */
+	"#endif",
 	"#ifndef XUSAFE",
 	"	char *o_name;",
 	"#endif",
-	"	char *body;",
-	"	struct Stack *nxt;",
-	"	struct Stack *lst;",
-	"} Stack;\n",
+	"	struct _Stack *nxt;",
+	"	struct _Stack *lst;",
+	"} _Stack;\n",
 	"typedef struct Svtack { /* for complete state vector */",
 	"#if VECTORSZ>32000",
 	"	int o_delta;",
@@ -153,35 +173,15 @@
 	0,
 };
 
-static char *Header0[] = {
+static const 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[] = {
+static const char *Head1[] = {
 	"typedef struct State {",
 	"	uchar _nr_pr;",
 	"	uchar _nr_qs;",
@@ -207,24 +207,32 @@
 #endif
 		"	unsigned short _vsz;",
 		"#else",
-		"	unsigned long  _vsz;",
+		"	ulong  _vsz;",
 		"#endif",
 	"#endif",
 
-	"#ifdef HAS_LAST",	/* cannot go before _cnt - see hstore() */
+	"#ifdef HAS_LAST",	/* cannot go before _cnt - see h_store() */
 	"	uchar  _last;	/* pid executed in last step */",
 	"#endif",
+
+	"#if defined(BITSTATE) && defined(BCS) && defined(STORE_CTX)",
+	"	uchar  _ctx;	/* nr of context switches so far */",
+	"#endif",
+	"#if defined(BFS_PAR) && defined(L_BOUND)",
+	"	uchar  _l_bnd;	/* bounded liveness */",
+	"	uchar *_l_sds;	/* seed state */",
+	"#endif",
 	"#ifdef EVENT_TRACE",
-		"#if nstates_event<256",
-	"	uchar _event;",
-		"#else",
-	"	unsigned short _event;",
-		"#endif",
+	"	#if nstates_event<256",
+	"		uchar _event;",
+	"	#else",
+	"		unsigned short _event;",
+	"	#endif",
 	"#endif",
 	0,
 };
 
-static char *Addp0[] = {
+static const char *Addp0[] = {
 	/* addproc(....parlist... */ ")",
 	"{	int j, h = now._nr_pr;",
 	"#ifndef NOCOMP",
@@ -235,45 +243,66 @@
 	"	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)",
+	"	/* 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\");",
+	"#ifdef V_TRIX",
+	"	printf(\"%%4d: add process %%d\\n\", depth, h);",
+	"#endif",
 	"	switch (n) {",
 	"	case 0: j = sizeof(P0); break;",
 	0,
 };
 
-static char *Addp1[] = {
+static const char *Addp1[] = {
 	"	default: Uerror(\"bad proc - addproc\");",
 	"	}",
+	"	#ifdef BFS_PAR",
+	"		bfs_prepmask(1);	/* addproc */",
+	"	#endif",
+
+	"#ifdef TRIX",
+	"	vsize += sizeof(H_el *);",
+	"#else",
 	"	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",
+	"	#if !defined(NOCOMP) && !defined(HC)",
+	"		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",
+	"	vsize += j;",
+	"	#if defined(SVDUMP) && defined(VERBOSE)",
 	"	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",
+	"	#if VECTORSZ>32000",
 	"		write(svfd, (uchar *) &proc_offset[h], sizeof(int));",
-	"#else",
+	"		write(svfd, (uchar *) &now, vprefix-4*sizeof(int)); /* padd */",
+	"	#else",
 	"		write(svfd, (uchar *) &proc_offset[h], sizeof(short));",
+	"		write(svfd, (uchar *) &now, vprefix-3*sizeof(int)-sizeof(short)); /* padd */",
+	"	#endif",
+	"	}",
+	"	#endif",
 	"#endif",
-	"		write(svfd, (uchar *) &now, vprefix-4*sizeof(int)); /* padd */",
+
+	"	now._nr_pr += 1;",
+	"#if defined(BCS) && defined(CONSERVATIVE)",
+	"	if (now._nr_pr >= CONSERVATIVE*8)",
+	"	{	printf(\"pan: error: too many processes -- recompile with \");",
+	"		printf(\"-DCONSERVATIVE=%%d\\n\", CONSERVATIVE+1);",
+	"		pan_exit(1);",
 	"	}",
 	"#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\",",
@@ -282,78 +311,134 @@
 	"			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);",
+
+	"#ifdef TRIX",
+	"	#ifndef BFS",
+	"		if (freebodies)",
+	"		{	processes[h] = freebodies;",
+	"			freebodies = freebodies->nxt;",
+	"		} else",
+	"		{	processes[h] = (TRIX_v6 *) emalloc(sizeof(TRIX_v6));",
+	"			processes[h]->body = (uchar *) emalloc(Maxbody * sizeof(char));",
+	"		}",
+	"		processes[h]->modified = 1;	/* addproc */",
+	"	#endif",
+	"	processes[h]->psize = j;",
+	"	processes[h]->parent_pid = calling_pid;",
+	"	processes[h]->nxt = (TRIX_v6 *) 0;",
+	"#else",
+	"	#if !defined(NOCOMP) && !defined(HC)",
+	"		for (k = 1; k <= Air[n]; k++)",
+	"			Mask[vsize - k] = 1; /* pad */",
+	"		Mask[vsize-j] = 1; /* _pid */",
+	"	#endif",
+	"	#ifdef BFS_PAR",
+	"		bfs_fixmask(1);	/* addproc */",
+	"	#endif",
 	"	if (vsize >= VECTORSZ)",
 	"	{	printf(\"pan: error, VECTORSZ too small, recompile pan.c\");",
-	"		printf(\" with -DVECTORSZ=N with N>%%d\\n\", vsize);",
+	"		printf(\" with -DVECTORSZ=N with N>%%d\\n\", (int) vsize);",
 	"		Uerror(\"aborting\");",
 	"	}",
+	"#endif",
+
 	"	memset((char *)pptr(h), 0, j);",
 	"	this = pptr(h);",
 	"	if (BASE > 0 && h > 0)",
-	"		((P0 *)this)->_pid = h-BASE;",
-	"	else",
-	"		((P0 *)this)->_pid = h;",
+	"	{	((P0 *)this)->_pid = h-BASE;",
+	"	} else",
+	"	{	((P0 *)this)->_pid = h;",
+	"	}",
 	"	switch (n) {",
 	0,
 };
 
-static char *Addq0[] = {
+static const char *Addq0[] = {
+	"",
 	"int",
-	"addqueue(int n, int is_rv)",
+	"addqueue(int calling_pid, int n, int is_rv)",
 	"{	int j=0, i = now._nr_qs;",
-	"#ifndef NOCOMP",
+	"#if !defined(NOCOMP) && !defined(TRIX)",
 	"	int k;",
 	"#endif",
 	"	if (i >= MAXQ)",
 	"		Uerror(\"too many queues\");",
+	"#ifdef V_TRIX",
+	"	printf(\"%%4d: add queue %%d\\n\", depth, i);",
+	"#endif",
 	"	switch (n) {",
 	0,
 };
 
-static char *Addq1[] = {
+static const char *Addq1[] = {
 	"	default: Uerror(\"bad queue - addqueue\");",
 	"	}",
+	"	#ifdef BFS_PAR",
+	"		bfs_prepmask(2);	/* addqueue */",
+	"	#endif",
+
+	"#ifdef TRIX",
+	"	vsize += sizeof(H_el *);",
+	"#else",
 	"	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",
+	"	#if !defined(NOCOMP) && !defined(HC)",
+	"		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;",
+	"	vsize += j;",
+	"	#ifdef BFS_PAR",
+	"		bfs_fixmask(2);	/* addqueue */",
+	"	#endif",
+	"#endif",
+
 	"	now._nr_qs += 1;",
-	"	vsize += j;",
 	"#ifndef NOVSZ",
 	"	now._vsz = vsize;",
 	"#endif",
 	"	hmax = max(hmax, vsize);",
+
+	"#ifdef TRIX",
+	"	#ifndef BFS",
+	"		if (freebodies)",
+	"		{	channels[i] = freebodies;",
+	"			freebodies = freebodies->nxt;",
+	"		} else",
+	"		{	channels[i] = (TRIX_v6 *) emalloc(sizeof(TRIX_v6));",
+	"			channels[i]->body = (uchar *) emalloc(Maxbody * sizeof(char));",
+	"		}",
+	"		channels[i]->modified = 1;	/* addq */",
+	"	#endif",
+	"	channels[i]->psize = j;",
+	"	channels[i]->parent_pid = calling_pid;",
+	"	channels[i]->nxt = (TRIX_v6 *) 0;",
+	"#else",
 	"	if (vsize >= VECTORSZ)",
 	"		Uerror(\"VECTORSZ is too small, edit pan.h\");",
-	"	memset((char *)qptr(i), 0, j);",
+	"#endif",
+
+	"	if (j > 0)", /* zero if there are no queues */
+	"	{	memset((char *)qptr(i), 0, j);",
+	"	}",
 	"	((Q0 *)qptr(i))->_t = n;",
 	"	return i+1;",
 	"}\n",
 	0,
 };
 
-static char *Addq11[] = {
+static const char *Addq11[] = {
 	"{	int j; uchar *z;\n",
 	"#ifdef HAS_SORTED",
 	"	int k;",
@@ -362,13 +447,26 @@
 	"	uerror(\"ref to uninitialized chan name (sending)\");",
 	"	if (into >= (int) now._nr_qs || into < 0)",
 	"		Uerror(\"qsend bad queue#\");",
+	"#if defined(TRIX) && !defined(BFS)",
+	"	#ifndef TRIX_ORIG",
+	"		(trpt+1)->q_bup = now._ids_[now._nr_pr+into];",
+	"		#ifdef V_TRIX",
+	"			printf(\"%%4d: channel %%d s save %%p from %%d\\n\",",
+	"			depth, into, (trpt+1)->q_bup, now._nr_pr+into);",
+	"		#endif",
+	"	#endif",
+	"	channels[into]->modified = 1;	/* qsend */",
+	"	#ifdef V_TRIX",
+	"		printf(\"%%4d: channel %%d modified\\n\", depth, into);",
+	"	#endif",
+	"#endif",
 	"	z = qptr(into);",
 	"	j = ((Q0 *)qptr(into))->Qlen;",
 	"	switch (((Q0 *)qptr(into))->_t) {",
 	0,
 };
 
-static char *Addq2[] = {
+static const char *Addq2[] = {
 	"	case 0: printf(\"queue %%d was deleted\\n\", into+1);",
 	"	default: Uerror(\"bad queue - qsend\");",
 	"	}",
@@ -389,7 +487,7 @@
 	0,
 };
 
-static char *Addq3[] = {
+static const char *Addq3[] = {
 	"	case 0: printf(\"queue %%d was deleted\\n\", from+1);",
 	"	}",
 	"	Uerror(\"bad queue q-zero\");",
@@ -449,7 +547,11 @@
 	"short q_recver[MAXQ+1];",
 	"int",
 	"q_R_check(int x, int who)",
-	"{	if (!q_recver[x])",
+	"{",
+	"#ifdef VERBOSE",
+	"	printf(\"q_R_check x=%%d who=%%d\\n\", x, who);",
+	"#endif",
+	"	if (!q_recver[x])",
 	"	{	q_recver[x] = who+1;",
 	"#if SYNC",
 	"		if (q_zero(x))",
@@ -489,7 +591,7 @@
 	0,
 };
 
-static char *Addq4[] = {
+static const char *Addq4[] = {
 	"	case 0: printf(\"queue %%d was deleted\\n\", from+1);",
 	"	}",
 	"	Uerror(\"bad queue - q_full\");",
@@ -509,6 +611,19 @@
 	"	int j, k, r=0;\n",
 	"	if (!from--)",
 	"	uerror(\"ref to uninitialized chan name (receiving)\");",
+	"#if defined(TRIX) && !defined(BFS)",
+	"	#ifndef TRIX_ORIG",
+	"		(trpt+1)->q_bup = now._ids_[now._nr_pr+from];",
+	"		#ifdef V_TRIX",
+	"			printf(\"%%4d: channel %%d r save %%p from %%d\\n\",",
+	"			depth, from, (trpt+1)->q_bup, now._nr_pr+from);",
+	"		#endif",
+	"	#endif",
+	"	channels[from]->modified = 1;	/* qrecv */",
+	"	#ifdef V_TRIX",
+	"		printf(\"%%4d: channel %%d modified\\n\", depth, from);",
+	"	#endif",
+	"#endif",
 	"	if (from >= (int) now._nr_qs || from < 0)",
 	"		Uerror(\"qrecv bad queue#\");",
 	"	z = qptr(from);",
@@ -520,7 +635,7 @@
 	0,
 };
 
-static char *Addq5[] = {
+static const char *Addq5[] = {
 	"	case 0: printf(\"queue %%d was deleted\\n\", from+1);",
 	"	default: Uerror(\"bad queue - qrecv\");",
 	"	}",
@@ -528,7 +643,7 @@
 	"}",
 	"#endif\n",
 	"#ifndef BITSTATE",
-	"#ifdef COLLAPSE",
+	"	#ifdef COLLAPSE",
 	"long",
 	"col_q(int i, char *z)",
 	"{	int j=0, k;",
@@ -538,15 +653,22 @@
 	0,
 };
 
-static char *Code0[] = {
+static const char *Code0[] = {
 	"void",
 	"run(void)",
 	"{	/* int i; */",
 	"	memset((char *)&now, 0, sizeof(State));",
-	"	vsize = (unsigned long) (sizeof(State) - VECTORSZ);",
+	"	vsize = (ulong) (sizeof(State) - VECTORSZ);",
 	"#ifndef NOVSZ",
 	"	now._vsz = vsize;",
 	"#endif",
+	"#ifdef TRIX",
+	"	if (VECTORSZ != sizeof(now._ids_))",
+	"	{	printf(\"VECTORSZ is %%d, but should be %%d in this mode\\n\",",
+	"			VECTORSZ, (int) sizeof(now._ids_));",
+	"		Uerror(\"VECTORSZ set incorrectly, recompile Spin (not pan.c)\");",
+	"	}",
+	"#endif",
 	"/* optional provisioning statements, e.g. to */",
 	"/* set hidden variables, used as constants */",
 	"#ifdef PROV",
@@ -556,151 +678,311 @@
 	0,
 };
 
-static char *R0[] = {
-	"	Maxbody = max(Maxbody, sizeof(P%d));",
+static const char *R0[] = {
+	"	Maxbody = max(Maxbody, ((int) 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;",
+	"	accpstate[%d] = (uchar *) emalloc(_nstates%d);",
+	"	progstate[%d] = (uchar *) emalloc(_nstates%d);",
+	"	loopstate%d = loopstate[%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));",
+	"	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);",
-	"	}",
+static const char *R00[] = {
+	"	NrStates[%d] = _nstates%d;",
 	0,
 };
 
-static char *Code1[] = {
+static const char *R0a[] = {
+	"	retrans(%d, _nstates%d, _start%d, src_ln%d, reached%d, loopstate%d);",
+	0,
+};
+
+static const char *Code1[] = {
 	"#ifdef NP",
-	"#define ACCEPT_LAB	1 /* at least 1 in np_ */",
+	"	#define ACCEPT_LAB	1 /* at least 1 in np_ */",
 	"#else",
-	"#define ACCEPT_LAB	%d /* user-defined accept labels */",
+	"	#define ACCEPT_LAB	%d /* user-defined accept labels */",
+	"#endif",
+	"#ifdef MEMCNT",
+	"	#ifdef MEMLIM",
+	"		#warning -DMEMLIM takes precedence over -DMEMCNT",
+	"		#undef MEMCNT",
+	"	#else",
+	"		#if MEMCNT<20",
+	"			#warning using minimal value -DMEMCNT=20 (=1MB)",
+	"			#define MEMLIM	(1)",
+	"			#undef MEMCNT",
+	"		#else",
+	"			#if MEMCNT==20",
+	"				#define MEMLIM	(1)",
+	"				#undef MEMCNT",
+	"			#else",
+	"			 #if MEMCNT>=50",
+	"				#error excessive value for MEMCNT",
+	"			 #else",
+	"				#define MEMLIM	(1<<(MEMCNT-20))",
+	"			 #endif",
+	"			#endif",
+	"		#endif",
+	"	#endif",
+	"#endif",
+
+	"#if NCORE>1 && !defined(MEMLIM)",
+	"	#define MEMLIM	(2048)	/* need a default, using 2 GB */",
 	"#endif",
 	0,
 };
 
-static char *Code3[] = {
+static const char *Code3[] = {
 	"#define PROG_LAB	%d /* progress labels */",
 	0,
 };
 
-static char *R2[] = {
+static const char *R2[] = {
 	"uchar *accpstate[%d];",
 	"uchar *progstate[%d];",
+	"uchar *loopstate[%d];",
 	"uchar *reached[%d];",
 	"uchar *stopstate[%d];",
 	"uchar *visstate[%d];",
 	"short *mapstate[%d];",
 	"#ifdef HAS_CODE",
-	"int NrStates[%d];",
+	"	int NrStates[%d];",
 	"#endif",
 	0,
 };
-static char *R3[] = {
-	"	Maxbody = max(Maxbody, sizeof(Q%d));",
+static const char *R3[] = {
+	"	Maxbody = max(Maxbody, ((int) sizeof(Q%d)));",
 	0,
 };
-static char *R4[] = {
-	"	r_ck(reached%d, nstates%d, %d, src_ln%d, src_file%d);",
+static const char *R4[] = {
+	"	r_ck(reached%d, _nstates%d, %d, src_ln%d, src_file%d);",
 	0,
 };
-static char *R5[] = {
+static const char *R5[] = {
 	"	case %d: j = sizeof(P%d); break;",
 	0,
 };
-static char *R6[] = {
+static const char *R6[] = {
 	"	}",
 	"	this = o_this;",
+	"#ifdef TRIX",
+	"	re_mark_all(1); /* addproc */",
+	"#endif",
 	"	return h-BASE;",
 	"#ifndef NOBOUNDCHECK",
-	"#undef Index",
-	"#define Index(x, y)	Boundcheck(x, y, II, tt, t)",
+	"	#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; }",
+	"	/* 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",
+	"	#ifdef COLLAPSE",
 	"long",
 	"col_p(int i, char *z)",
-	"{	int j, k; unsigned long ordinal(char *, long, short);",
+	"{	int j, k; ulong 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[] = {
+static const char *R7a[] = {
+	"void\nre_mark_all(int whichway)",
+	"{	int j;",
+	"	#ifdef V_TRIX",
+	"		printf(\"%%d: re_mark_all channels %%d\\n\", depth, whichway);",
+	"	#endif",
+	"	#ifndef BFS",
+	"	for (j = 0; j < now._nr_qs; j++)",
+	"		channels[j]->modified = 1; /* channel index moved */",
+	"	#endif",
+	"	#ifndef TRIX_ORIG",
+	"	if (whichway > 0)",
+	"	{	for (j = now._nr_pr + now._nr_qs - 1; j >= now._nr_pr; j--)",
+	"			now._ids_[j] = now._ids_[j-1];",
+	"	} else",
+	"	{	for (j = now._nr_pr; j < now._nr_pr + now._nr_qs; j++)",
+	"			now._ids_[j] = now._ids_[j+1];",
+	"	}",
+	"	#endif",
+	"}",
+	0,
+};
+
+static const char *R7b[] = {
+	"#ifdef BFS_PAR",
+	"inline void",
+	"bfs_prepmask(int caller)",
+	"{",
+	"#if !defined(NOCOMP) && !defined(HC)",
+	"	memcpy((char *) &tmp_msk, (const char *) Mask, sizeof(State));",
+	"	Mask = (uchar *) &tmp_msk;",
+	"#endif",
+	"	switch (caller) {",
+	"	case 1:	/* addproc */",
+	"#if VECTORSZ>32000",
+	"		memcpy((char *) P_o_tmp, (const char *) proc_offset, MAXPROC*sizeof(int));",
+	"#else",
+	"		memcpy((char *) P_o_tmp, (const char *) proc_offset, MAXPROC*sizeof(short));",
+	"#endif",
+	"		memcpy((char *) P_s_tmp, (const char *) proc_skip, MAXPROC*sizeof(uchar));",
+	"		proc_offset = P_o_tmp;",
+	"		proc_skip   = (uchar *) &P_s_tmp[0];",
+	"		break;",
+	"	case 2: /* addqueue */",
+	"#if VECTORSZ>32000",
+	"		memcpy((char *) Q_o_tmp, (const char *) q_offset, MAXQ*sizeof(int));",
+	"#else",
+	"		memcpy((char *) Q_o_tmp, (const char *) q_offset, MAXQ*sizeof(short));",
+	"#endif",
+	"		memcpy((char *) Q_s_tmp, (const char *) q_skip, MAXQ*sizeof(uchar));",
+	"		q_offset = Q_o_tmp;",
+	"		q_skip   = (uchar *) &Q_s_tmp[0];",
+	"		break;",
+	"	case 3: /* no nothing */",
+	"		break;",
+	"	default: /* cannot happen */",
+	"		Uerror(\"no good\");",
+	"		break;",
+	"	}",
+	"}",
+	"",
+	"typedef struct BFS_saves BFS_saves;",
+	"struct BFS_saves {",
+	"	char *m;",
+	"	BFS_saves *nxt;",
+	"} *bfs_save_po,",
+	"  *bfs_save_ps,",
+	"#if !defined(NOCOMP) && !defined(HC)",
+	"  *bfs_save_mask,",
+	"#endif",
+	"  *bfs_save_qo,",
+	"  *bfs_save_qs;",
+	"",
+	"extern volatile uchar *sh_malloc(ulong);",
+	"static int bfs_runs; /* 0 before local heaps are initialized */",
+	"",
+	"void",
+	"bfs_swoosh(BFS_saves **where, char **what, int howmuch)",
+	"{	BFS_saves *m;",
+	"	for (m = *where; m; m = m->nxt)",
+	"	{	if (memcmp(m->m, *what, howmuch) == 0)",
+	"		{	*what = m->m;",
+	"			return;",
+	"	}	}",
+	"	m = (BFS_saves *) emalloc(sizeof(BFS_saves));",
+	"	if (bfs_runs)",
+	"	{	m->m = (char *) sh_malloc(howmuch);",
+	"	} else",
+	"	{	m->m = (char *) sh_pre_malloc(howmuch);",
+	"	}",
+	"	memcpy(m->m, *what, howmuch);",
+	"	m->nxt = *where;",
+	"	*where = m;",
+	"	*what = m->m;",
+	"}",
+	"",
+	"void",
+	"bfs_fixmask(int caller)",	/* 1=addproc, 2=addqueue */
+	"{",
+	"#if !defined(NOCOMP) && !defined(HC)",
+	"	bfs_swoosh(&bfs_save_mask, (char **) &Mask, sizeof(State));",
+	"#endif",
+	"#ifndef TRIX",
+	"	switch (caller) {",
+	"	case 1: /* addproc */",
+	"	#if VECTORSZ>32000",
+	"		bfs_swoosh(&bfs_save_po, (char **) &proc_offset, MAXPROC*sizeof(int));",
+	"	#else",
+	"		bfs_swoosh(&bfs_save_po, (char **) &proc_offset, MAXPROC*sizeof(short));",
+	"	#endif",
+	"		bfs_swoosh(&bfs_save_ps, (char **) &proc_skip, MAXPROC*sizeof(uchar));",
+	"		break;",
+	"	case 2: /* addqueue */",
+	"	#if VECTORSZ>32000",
+	"		bfs_swoosh(&bfs_save_qo, (char **) &q_offset, MAXQ*sizeof(int));",
+	"	#else",
+	"		bfs_swoosh(&bfs_save_qo, (char **) &q_offset, MAXQ*sizeof(short));",
+	"	#endif",
+	"		bfs_swoosh(&bfs_save_qs, (char **) &q_skip, MAXQ*sizeof(uchar));",
+	"		break;",
+	"	case 3: /* do nothing */",
+	"		break;",
+	"	default:",
+	"		Uerror(\"double plus ungood\");",
+	"		break;",
+	"	}",
+	"#endif",
+	"}",
+	"#endif",
+	0,
+};
+static const char *R8a[] = {
 	"	default: Uerror(\"bad proctype - collapse\");",
 	"	}",
 	"	if (z) x = z; else x = scratch;",
 	"	y = (char *) ptr; k = proc_offset[i];",
-
+	"",
+	"#if !defined(NOCOMP) && !defined(HC)",
 	"	for ( ; j > 0; j--, y++)",
 	"		if (!Mask[k++]) *x++ = *y;",
-
+	"#else",
+	"	memcpy(x, y, j);",
+	"	x += j;",
+	"#endif",
 	"	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",
 	"#endif",
 	0,
 };
-static char *R8b[] = {
+static const char *R8b[] = {
 	"	default: Uerror(\"bad qtype - collapse\");",
 	"	}",
 	"	if (z) x = z; else x = scratch;",
 	"	y = (char *) ptr; k = q_offset[i];",
 
+	"#if NQS > 0",
 	"	/* no need to store the empty slots at the end */",
 	"	j -= (q_max[ptr->_t] - ptr->Qlen) * ((j - 2)/q_max[ptr->_t]);",
-
+	"#endif",
+	"",
+	"#if !defined(NOCOMP) && !defined(HC)",
 	"	for ( ; j > 0; j--, y++)",
 	"		if (!Mask[k++]) *x++ = *y;",
-
+	"#else",
+	"	memcpy(x, y, j);",
+	"	x += j;",
+	"#endif",
 	"	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",
 	"#endif",
 	0,
 };
 
-static char *R12[] = {
+static const char *R12[] = {
 	"\t\tcase %d: r = ((Q%d *)z)->contents[slot].fld%d; break;",
 	0,
 };
-char *R13[] = {
+const char *R13[] = {
 	"int ",
 	"unsend(int into)",
 	"{	int _m=0, j; uchar *z;\n",
@@ -709,13 +991,27 @@
 	"#endif",
 	"	if (!into--)",
 	"		uerror(\"ref to uninitialized chan (unsend)\");",
+	"#if defined(TRIX) && !defined(BFS)",
+	"	#ifndef TRIX_ORIG",
+	"		now._ids_[now._nr_pr+into] = trpt->q_bup;",
+	"		#ifdef V_TRIX",
+	"			printf(\"%%4d: channel %%d s restore %%p into %%d\\n\",",
+	"				depth, into, trpt->q_bup, now._nr_pr+into);",
+	"		#endif",
+	"	#else",
+	"		channels[into]->modified = 1;	/* unsend */",
+	"		#ifdef V_TRIX",
+	"			printf(\"%%4d: channel %%d unmodify\\n\", depth, into);",
+	"		#endif",
+	"	#endif",
+	"#endif",
 	"	z = qptr(into);",
 	"	j = ((Q0 *)z)->Qlen;",
 	"	((Q0 *)z)->Qlen = --j;",
 	"	switch (((Q0 *)qptr(into))->_t) {",
 	0,
 };
-char *R14[] = {
+const char *R14[] = {
 	"	default: Uerror(\"bad queue - unsend\");",
 	"	}",
 	"	return _m;",
@@ -725,40 +1021,53 @@
 	"{	int j; uchar *z;\n",
 	"	if (!from--)",
 	"		uerror(\"ref to uninitialized chan (unrecv)\");",
+	"#if defined(TRIX) && !defined(BFS)",
+	"	#ifndef TRIX_ORIG",
+	"		now._ids_[now._nr_pr+from] = trpt->q_bup;",
+	"		#ifdef V_TRIX",
+	"			printf(\"%%4d: channel %%d r restore %%p into %%d\\n\",",
+	"				depth, from, trpt->q_bup, now._nr_pr+from);",
+	"		#endif",
+	"	#else",
+	"		channels[from]->modified = 1;	/* unrecv */",
+	"		#ifdef V_TRIX",
+	"			printf(\"%%4d: channel %%d unmodify\\n\", depth, from);",
+	"		#endif",
+	"	#endif",
+	"#endif",
 	"	z = qptr(from);",
 	"	j = ((Q0 *)z)->Qlen;",
 	"	if (strt) ((Q0 *)z)->Qlen = j+1;",
 	"	switch (((Q0 *)qptr(from))->_t) {",
 	0,
 };
-char *R15[] = {
+const char *R15[] = {
 	"	default: Uerror(\"bad queue - qrecv\");",
 	"	}",
 	"}",
 	0,
 };
-static char *Proto[] = {
+static const char *Proto[] = {
 	"",
 	"/** function prototypes **/",
-	"char *emalloc(unsigned long);",
-	"char *Malloc(unsigned long);",
+	"char *emalloc(ulong);",
+	"char *Malloc(ulong);",
 	"int Boundcheck(int, int, int, int, Trans *);",
-	"int addqueue(int, int);",
+	"int addqueue(int, 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);",
+	"	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 find_claim(char *);",
+	"int h_store(char *, int);",
+	"int pan_rand(void);",
 	"int q_cond(short, Trans *);",
 	"int q_full(int);",
 	"int q_len(int);",
@@ -766,65 +1075,353 @@
 	"int qrecv(int, int, int, int);",
 	"int unsend(int);",
 	"/* void *sbrk(int); */",
-	"void Uerror(char *);",
-	"void assert(int, char *, int, int, Trans *);",
+	"void spin_assert(int, char *, int, int, Trans *);",
+	"#ifdef BFS_PAR",
+	"void bfs_printf(const char *, ...);",
+	"volatile uchar *sh_pre_malloc(ulong);",
+	"#endif",
 	"void c_chandump(int);",
 	"void c_globals(void);",
 	"void c_locals(int, int);",
 	"void checkcycles(void);",
 	"void crack(int, int, Trans *, short *);",
+	"void d_sfh(uchar *, int);",
 	"void d_hash(uchar *, int);",
+	"void m_hash(uchar *, int);",
 	"void s_hash(uchar *, int);",
-	"void r_hash(uchar *, int);",
 	"void delq(int);",
+	"void dot_crack(int, int, Trans *);",
 	"void do_reach(void);",
 	"void pan_exit(int);",
 	"void exit(int);",
-	"void hinit(void);",
+	"#ifdef BFS_PAR",
+	"	void bfs_setup_mem(void);",
+	"#endif",
+	"#ifdef BITSTATE",
+	"	void sinit(void);",
+	"#else",
+	"	void hinit(void);",
+	"#endif",
 	"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 retrans(int, int, int, short *, uchar *, uchar *);",
+	"void select_claim(int);",
 	"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 do_dfs(int, int, int, short *, uchar *, uchar *);",
 	"void unrecv(int, int, int, int, int);",
 	"void usage(FILE *);",
-	"void wrap_stats(void);",
+	"void wrap_stats(void);\n",
+	"#ifdef MA",
+	"	int g_store(char *, int, uchar);",
+	"#endif",
 	"#if defined(FULLSTACK) && defined(BITSTATE)",
-	"int  onstack_now(void);",
-	"void onstack_init(void);",
-	"void onstack_put(void);",
-	"void onstack_zap(void);",
+	"	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];",
+	"	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",
+	"",
+	"#ifndef NO_V_PROVISO",
+	"	#define V_PROVISO",
+	"#endif",
+	"#if !defined(NO_RESIZE) && !defined(AUTO_RESIZE) && !defined(BITSTATE) && !defined(SPACE) && !defined(USE_TDH) && NCORE==1",
+	"	#define AUTO_RESIZE",
+	"#endif",
+	"",
+	"typedef struct Trail Trail;",
+	"typedef struct H_el  H_el;",
+	"",
+	"struct H_el {",
+	"	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))",
+	"		ulong st_id;",
+	"	#endif",
+	"	#if !defined(SAFETY) || defined(REACH)",
+	"		uint D;",
+	"	#endif",
+	"	#ifdef BCS",
+	"		#ifndef CONSERVATIVE",
+	"			#define CONSERVATIVE	1 /* good for up to 8 processes */",
+	"		#endif",
+	"		#ifdef CONSERVATIVE",
+	"			#if CONSERVATIVE <= 0 || CONSERVATIVE>32",
+	"			#error sensible values for CONSERVATIVE are 1..32 (256/8 = 32)",
+	"			#endif",
+	"			uchar ctx_pid[CONSERVATIVE];", /* pids setting lowest value */
+	"		#endif",
+	"		uchar ctx_low;", /* lowest nr of context switches seen so far */
+	"	#endif",
+	"	#if NCORE>1",
+	"		/* could cost 1 extra word: 4 bytes if 32-bit and 8 bytes if 64-bit */",
+	"		#ifdef V_PROVISO",
+	"			uchar	cpu_id;		/* id of cpu that created the state */",
+	"		#endif",
+	"	#endif",
+	"	#ifdef COLLAPSE",
+	"		#if VECTORSZ<65536",
+	"			ushort ln;",	/* length of vector */
+	"		#else",
+	"			ulong ln;",	/* length of vector */
+	"		#endif",
+	"	#endif",
+	"	#if defined(AUTO_RESIZE) && !defined(BITSTATE)",
+	"		ulong m_K1;",
+	"	#endif",
+	"	ulong state;",
+	"};",
+	"",
+	"#ifdef BFS_PAR",
+	"typedef struct BFS_Trail BFS_Trail;",
+	"struct BFS_Trail {",
+	"	H_el *ostate;",
+	"	int   st;",
+	"	int   o_tt;",
+	"	T_ID  t_id;", /* could be uint, ushort, or uchar */
+	"	uchar pr;",
+	"	uchar o_pm;",
+	"	uchar tau;",
+	"};",
+	"	#if SYNC>0",
+	"		#undef BFS_NOTRAIL", /* just in case it was used */
+	"	#endif",
+	"#endif",
+	"",
+	"#ifdef RHASH",
+	"	#ifndef PERMUTED",
+	"	#define PERMUTED",
+	"	#endif",
+	"#endif",
+	"",
+	"struct Trail {",
+	"	int   st;	/* current state */",
+	"	int   o_tt;",
+	"#ifdef PERMUTED",
+	"	uint  seed;",
+	"	uchar oII;",
+	"#endif",
+	"	uchar pr;	/* process id */",
+	"	uchar tau;	/* 8 bit-flags */",
+	"	uchar o_pm;	/* 8 more bit-flags */",
+	"",
+	"	#if 0",
+	"	Meaning of bit-flags on tau and o_pm:",
+	"	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",
+	"",
+	"	#ifdef NSUCC",
+	"	 uchar n_succ;	/* nr of successor states */",
+	"	#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",
+	"	#ifndef BFS",
+	"		short o_To;",
+	"		#if defined(T_RAND) || defined(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) || (NCORE>1)",
+	"	 H_el *ostate;	/* pointer to stored state */",
+	"	#endif",
+	/* CNTRSTACK when !NOREDUCE && BITSTATE && SAFETY && WS<=4, uses LL[] */
+	"	#if defined(CNTRSTACK) && !defined(BFS)",
+	"	 long	j6, j7;",
+	"	#endif",
+	"	Trans *o_t;",	/* transition fct, next state   */
+
+	"	#if !defined(BFS) && !defined(TRIX_ORIG)",
+	"	 char *p_bup;",
+	"	 char *q_bup;",
+	"	#endif",
+
+	"	#ifdef BCS",
+	"	 unsigned short sched_limit;",
+	"	 unsigned char  bcs; /* phase 1 or 2, or forced 4 */",
+	"	 unsigned char  b_pno; /* preferred pid */",
+	"	#endif",
+
+	"	#ifdef P_RAND",	/* process scheduling randomization */
+	"	 unsigned char p_left;	/* nr of procs left to explore */",
+	"	 short p_skip;	/* to find starting point in list */",
+	"	#endif",
+
+	"	#ifdef HAS_SORTED",
+	"	 short ipt;",	/* insertion slot in q */
+	"	#endif",
+	"	#ifdef HAS_PRIORITY",
+	"	 short o_priority;",
+	"	#endif",
+	"	union {",
+	"	 int oval;",	/* single backup value of variable */
+	"	 int *ovals;",	/* ptr to multiple values */
+	"	} bup;",
+	"}; /* end of struct Trail */",
+	"",
+	"#ifdef BFS",	/* breadth-first search */
+	"	#define Q_PROVISO",
+	"	#ifndef INLINE_REV",
+	"		#define INLINE_REV",
+	"	#endif",
+	"",
+	"typedef struct SV_Hold {",
+	"	State *sv;",
+	" #ifndef BFS_PAR",
+	"	int  sz;",
+	" #endif",
+	"	struct SV_Hold *nxt;",
+	"} SV_Hold;",
+	"#if !defined(BFS_PAR) || NRUNS>0",
+	"	typedef struct EV_Hold {",
+	"	 #if !defined(BFS_PAR) || (!defined(NOCOMP) && !defined(HC) && NRUNS>0)",
+	"		char *sv;	/* Mask */",
+	"	 #endif",
+	"	 #if VECTORSZ<65536",
+	"		ushort sz;	/* vsize */",
+	"	 #else",
+	"		ulong  sz;",
+	"	 #endif",
+	"	 #ifdef BFS_PAR",
+	"		uchar owner;",
+	"	 #endif",
+	"		uchar nrpr;",
+	"		uchar nrqs;",
+	"		#if !defined(BFS_PAR) || (!defined(TRIX) && NRUNS>0)",
+	"			char *po, *qo;",
+	"			char *ps, *qs;",
+	"		#endif",
+	"		struct EV_Hold *nxt;",
+	"	} EV_Hold;",
+	"#endif",
+	"typedef struct BFS_State {",
+	" #ifdef BFS_PAR",
+	"	BFS_Trail *t_info;",
+	"	State	*osv;",
+	" #else",
+	"	Trail	*frame;",
+	"	SV_Hold *onow;",
+	" #endif",
+	" #if !defined(BFS_PAR) || NRUNS>0",
+	"	EV_Hold *omask;",
+	" #endif",
+	" #if defined(Q_PROVISO) && !defined(NOREDUCE)",
+	"	H_el *lstate;",
+	" #endif",
+	" #if !defined(BFS_PAR) || SYNC>0",
+	"	short boq;",
+	" #endif",
+	" #ifdef VERBOSE",
+	"	ulong nr;",
+	" #endif",
+	" #ifndef BFS_PAR",	/* new 6.2.4, 3 dec 2012 */
+	"	struct BFS_State *nxt;",
+	" #endif",
+	"} BFS_State;",
+	"#endif\n",
 	0,
 };
 
-static char *SvMap[] = {
+static const char *SvMap[] = {
 	"void",
 	"to_compile(void)",
-	"{	char ctd[1024], carg[64];",
+	"{	char ctd[2048], carg[128];",
 	"#ifdef BITSTATE",
 	"	strcpy(ctd, \"-DBITSTATE \");",
 	"#else",
 	"	strcpy(ctd, \"\");",
 	"#endif",
+	"#ifdef BFS_PAR",
+	"	strcat(ctd, \"-DBFS_PAR \");",
+	"#endif",
 	"#ifdef NOVSZ",
 	"	strcat(ctd, \"-DNOVSZ \");",
 	"#endif",
+	"#ifdef RHASH",
+	"	strcat(ctd, \"-DRHASH \");",
+	"#else",
+	"	#ifdef PERMUTED",
+	"		strcat(ctd, \"-DPERMUTED \");",
+	"	#endif",
+	"#endif",
+	"#ifdef P_REVERSE",
+	"	strcat(ctd, \"-DP_REVERSE \");",
+	"#endif",
+	"#ifdef T_REVERSE",
+	"	strcat(ctd, \"-DT_REVERSE \");",
+	"#endif",
+	"#ifdef T_RAND",
+	"	#if T_RAND>0",
+	"	sprintf(carg, \"-DT_RAND=%%d \", T_RAND);",
+	"	strcat(ctd, carg);",
+	"	#else",
+	"	strcat(ctd, \"-DT_RAND \");",
+	"	#endif",
+	"#endif",
+	"#ifdef P_RAND",
+	"	#if P_RAND>0",
+	"	sprintf(carg, \"-DP_RAND=%%d \", P_RAND);",
+	"	strcat(ctd, carg);",
+	"	#else",
+	"	strcat(ctd, \"-DP_RAND \");",
+	"	#endif",
+	"#endif",
+	"#ifdef BCS",
+	"	sprintf(carg, \"-DBCS=%%d \", BCS);",
+	"	strcat(ctd, carg);",
+	"#endif",
+	"#ifdef BFS",
+	"	strcat(ctd, \"-DBFS \");",
+	"#endif",
 	"#ifdef MEMLIM",
 	"	sprintf(carg, \"-DMEMLIM=%%d \", MEMLIM);",
 	"	strcat(ctd, carg);",
@@ -867,20 +1464,8 @@
 	"#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 \");",
+	"#ifdef HC",
+	"	strcat(ctd, \"-DHC \");",
 	"#endif",
 	"#ifdef CHECK",
 	"	strcat(ctd, \"-DCHECK \");",
@@ -888,6 +1473,9 @@
 	"#ifdef CTL",
 	"	strcat(ctd, \"-DCTL \");",
 	"#endif",
+	"#ifdef TRIX",
+	"	strcat(ctd, \"-DTRIX \");",
+	"#endif",
 	"#ifdef NIBIS",
 	"	strcat(ctd, \"-DNIBIS \");",
 	"#endif",
@@ -903,9 +1491,6 @@
 	"#ifdef PRINTF",
 	"	strcat(ctd, \"-DPRINTF \");",
 	"#endif",
-	"#ifdef OTIM",
-	"	strcat(ctd, \"-DOTIM \");",
-	"#endif",
 	"#ifdef COLLAPSE",
 	"	strcat(ctd, \"-DCOLLAPSE \");",
 	"#endif",
@@ -916,7 +1501,7 @@
 	"#ifdef SVDUMP",
 	"	strcat(ctd, \"-DSVDUMP \");",
 	"#endif",
-	"#ifdef VECTORSZ",
+	"#if defined(VECTORSZ) && !defined(TRIX)",
 	"	if (VECTORSZ != 1024)",
 	"	{	sprintf(carg, \"-DVECTORSZ=%%d \", VECTORSZ);",
 	"		strcat(ctd, carg);",
@@ -931,8 +1516,31 @@
 	"#ifdef SDUMP",
 	"	strcat(ctd, \"-DSDUMP \");",
 	"#endif",
-	"#ifdef COVEST",
-	"	strcat(ctd, \"-DCOVEST \");",
+	"#if NCORE>1",
+	"	sprintf(carg, \"-DNCORE=%%d \", NCORE);",
+	"	strcat(ctd, carg);",
+	"#endif",
+	"#ifdef VMAX",
+	"	if (VMAX != 256)",
+	"	{	sprintf(carg, \"-DVMAX=%%d \", VMAX);",
+	"		strcat(ctd, carg);",
+	"	}",
+	"#endif",
+	"#ifdef PMAX",
+	"	if (PMAX != 16)",
+	"	{	sprintf(carg, \"-DPMAX=%%d \", PMAX);",
+	"		strcat(ctd, carg);",
+	"	}",
+	"#endif",
+	"#ifdef QMAX",
+	"	if (QMAX != 16)",
+	"	{	sprintf(carg, \"-DQMAX=%%d \", QMAX);",
+	"		strcat(ctd, carg);",
+	"	}",
+	"#endif",
+	"#ifdef SET_WQ_SIZE",
+	"	sprintf(carg, \"-DSET_WQ_SIZE=%%d \", SET_WQ_SIZE);",
+	"	strcat(ctd, carg);",
 	"#endif",
 	"	printf(\"Compiled as: cc -o pan %%span.c\\n\", ctd);",
 	"}",
diff -r 51b3bf8bc61b sys/src/cmd/spin/pangen4.c
--- a/sys/src/cmd/spin/pangen4.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/pangen4.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,13 +1,10 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include "spin.h"
 #include "y.tab.h"
@@ -17,7 +14,7 @@
 extern Symbol	*Fname;
 extern int	lineno, m_loss, Pid, eventmapnr, multi_oval;
 extern short	nocast, has_provided, has_sorted;
-extern char	*R13[], *R14[], *R15[];
+extern const char *R13[], *R14[], *R15[];
 
 static void	check_proc(Lextok *, int);
 
@@ -44,7 +41,7 @@
 	case FULL:	case EMPTY:	case 'R':
 	case NFULL:	case NEMPTY:	case ENABLED:
 	case '?':	case PC_VAL:	case '^':
-	case C_EXPR:
+	case C_EXPR:	case GET_P:
 	case NONPROGRESS:
 		putstmnt(tb, now, m);
 		break;
@@ -153,7 +150,14 @@
 		fprintf(tb, "p_restor(II);\n\t\t");
 		break;
 
+	case SET_P:
+		fprintf(tb, "((P0 *)pptr((trpt->o_priority >> 8)))");
+		fprintf(tb, "->_priority = trpt->o_priority & 255");
+		break;
+
 	case ASGN:
+		if (check_track(now) == STRUCT) { break; }
+
 		nocast=1; putstmnt(tb,now->lft,m);
 		nocast=0; fprintf(tb, " = trpt->bup.oval");
 		if (multi_oval > 0)
@@ -307,6 +311,8 @@
 	ntimes(tc, 0, 1, R15);
 }
 
+extern void explain(int);
+
 int
 proper_enabler(Lextok *n)
 {
@@ -317,15 +323,19 @@
 	case LEN:	case 'R':
 	case NAME:
 		has_provided = 1;
-		if (strcmp(n->sym->name, "_pid") == 0)
+		if (strcmp(n->sym->name, "_pid") == 0
+		||  strcmp(n->sym->name, "_priority") == 0)
 			return 1;
 		return (!(n->sym->context));
 
-	case CONST:	case TIMEOUT:
+	case C_EXPR:
+	case CONST:
+	case TIMEOUT:
 		has_provided = 1;
 		return 1;
 
 	case ENABLED:	case PC_VAL:
+	case GET_P:	/* not SET_P */
 		return proper_enabler(n->lft);
 
 	case '!': case UMIN: case '~':
@@ -335,10 +345,14 @@
 	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 RSHIFT: case 'c': /* case ',': */
 		return proper_enabler(n->lft) && proper_enabler(n->rgt);
+
 	default:
 		break;
 	}
+	printf("spin: saw ");
+	explain(n->ntyp);
+	printf("\n");
 	return 0;
 }
diff -r 51b3bf8bc61b sys/src/cmd/spin/pangen4.h
--- a/sys/src/cmd/spin/pangen4.h	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/pangen4.h	Wed Nov 22 00:21:47 2017 -0800
@@ -1,24 +1,21 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://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.
+ */
 
-/* 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[] = {
+static const char *Dfa[] = {
 	"#ifdef MA",
+#if 0
 	"/*",
 	"#include <stdio.h>",
 	"#define uchar	unsigned char",
@@ -26,6 +23,7 @@
 	"#define ulong	unsigned long",
 	"#define ushort	unsigned short",
 	"",
+#endif
 	"#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))",
@@ -466,7 +464,7 @@
 	"	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\",",
+	"	printf(\"Minimized Automaton:\t%%6lu nodes and %%6g edges\\n\",",
 	"		nr_states, cnt);",
 	"}",
 	"",
diff -r 51b3bf8bc61b sys/src/cmd/spin/pangen5.c
--- a/sys/src/cmd/spin/pangen5.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/pangen5.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,13 +1,10 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include "spin.h"
 #include "y.tab.h"
@@ -140,6 +137,7 @@
 	||  lt->ntyp == C_CODE
 	||  lt->ntyp == C_EXPR
 	||  has_lab(el, 0)		/* any label at all */
+	||  lt->ntyp == SET_P		/* to prevent multiple set_p merges */
 
 	||  lt->ntyp == DO
 	||  lt->ntyp == UNLESS
@@ -211,13 +209,18 @@
 static int
 build_step(FSM_trans *v)
 {	FSM_state *f;
-	Element	*el = v->step;
+	Element	*el;
 #if 0
 	Lextok	*lt = ZN;
 #endif
-	int	st  = v->to;
+	int	st;
 	int	r;
 
+	if (!v) return -1;
+
+	el = v->step;
+	st = v->to;
+
 	if (!el) return -1;
 
 	if (v->step->merge)
@@ -234,9 +237,7 @@
 	lt = v->step->n;
 	if (verbose&32)
 	{	if (++howdeep == 1)
-			printf("spin: %s, line %3d, merge:\n",
-				lt->fn->name,
-				lt->ln);
+			printf("spin: %s:%d, merge:\n", lt->fn->name, lt->ln);
 		printf("\t[%d] <seqno %d>\t", howdeep, el->seqno);
 		comment(stdout, lt, 0);
 		printf(";\n");
@@ -257,7 +258,7 @@
 }
 
 static void
-FSM_MERGER(char *pname_unused)	/* find candidates for safely merging steps */
+FSM_MERGER(/* char *pname */ void)	/* find candidates for safely merging steps */
 {	FSM_state *f, *g;
 	FSM_trans *t;
 	Lextok	*lt;
@@ -281,14 +282,14 @@
 			continue;
 
 		g = fsm_tbl[t->to];
-		if (!eligible(g->t))
+		if (!g || !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",
+			{	printf("spin: %s:%d, merge_single:\n\t<seqno %d>\t",
 					t->step->n->fn->name,
 					t->step->n->ln,
 					t->step->seqno);
@@ -321,14 +322,17 @@
 		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
+	an rv send operation ('s') 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
+	the same is not true for non-rv send operations;
+	6.2.2:
+	RUN statements can start a new process at a higher priority level
+	which interferes with statement merging, so it too is not a suitable
+	merge target
 #endif
 
-		if (lt->ntyp == 'c'	/* potentially blocking stmnts */
+		if ((lt->ntyp == 'c' && !any_oper(lt->lft, RUN)) /* 2nd clause 6.2.2 */
 		||  lt->ntyp == 'r'
 		||  (lt->ntyp == 's' && u_sync == 0))	/* added !u_sync in 4.1.3 */
 		{	if (!canfill_in(t))		/* atomic, non-global, etc. */
@@ -346,9 +350,8 @@
 #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,
+			{	printf("spin: %s:%d, merge_START:\n\t<seqno %d>\t",
+						lt->fn->name, lt->ln,
 						t->step->seqno);
 				comment(stdout, lt, 0);
 				printf(";\n");
@@ -532,6 +535,7 @@
 	if (now->sym->name[0] == '_'
 	&&  (strcmp(now->sym->name, "_") == 0
 	||   strcmp(now->sym->name, "_pid") == 0
+	||   strcmp(now->sym->name, "_priority") == 0
 	||   strcmp(now->sym->name, "_last") == 0))
 		return;
 
@@ -588,10 +592,17 @@
 	case C_EXPR:
 		break;
 
+	case ',': /* reached with SET_P and array initializers */
+		if (now->lft && now->lft->rgt)
+		{	ana_stmnt(t, now->lft->rgt, RVAL);
+		}
+		break;
+
 	case '!':	
 	case UMIN:
 	case '~':
 	case ENABLED:
+	case GET_P:
 	case PC_VAL:
 	case LEN:
 	case FULL:
@@ -603,6 +614,11 @@
 		ana_stmnt(t, now->lft, RVAL);
 		break;
 
+	case SET_P:
+		ana_stmnt(t, now->lft, RVAL); /* ',' */
+		ana_stmnt(t, now->lft->rgt, RVAL);
+		break;
+
 	case '/':
 	case '*':
 	case '-':
@@ -626,8 +642,11 @@
 		break;
 
 	case ASGN:
+		if (check_track(now) == STRUCT) { break; }
+
 		ana_stmnt(t, now->lft, LVAL);
-		ana_stmnt(t, now->rgt, RVAL);
+		if (now->rgt->ntyp)
+			ana_stmnt(t, now->rgt, RVAL);
 		break;
 
 	case PRINT:
@@ -679,7 +698,8 @@
 		break;
 
 	default:
-		printf("spin: bad node type %d line %d (ana_stmnt)\n", now->ntyp, now->ln);
+		printf("spin: %s:%d, bad node type %d (ana_stmnt)\n",
+			now->fn->name, now->ln, now->ntyp);
 		fatal("aborting", (char *) 0);
 	}
 }
@@ -692,10 +712,7 @@
 	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();
 
@@ -711,7 +728,7 @@
 		{	FSM_ANA();
 		}
 		if (merger)
-		{	FSM_MERGER(p->n->name);
+		{	FSM_MERGER(/* p->n->name */);
 			huntele(e, e->status, -1)->merge_in = 1; /* start-state */
 #if 0
 			printf("\n");
@@ -726,8 +743,7 @@
 	{
 		if (!(e->status&DONE) && (verbose&32))
 		{	printf("unreachable code: ");
-			printf("%s, line %3d:  ",
-				e->n->fn->name, e->n->ln);
+			printf("%s:%3d  ", e->n->fn->name, e->n->ln);
 			comment(stdout, e->n, 0);
 			printf("\n");
 		}
@@ -735,7 +751,7 @@
 	}
 	if (export_ast)
 	{	AST_slice();
-		exit(0);
+		alldone(0);	/* changed in 5.3.0: was exit(0) */
 	}
 }
 
@@ -831,9 +847,15 @@
 		{	if (e->n->ntyp == GOTO)
 			{	g = get_lab(e->n, 1);
 				g = huntele(g, e->status, -1);
+				if (!g)
+				{	fatal("unexpected error 2", (char *) 0);
+				}
 				To = g->seqno;
 			} else if (e->nxt)
 			{	g = huntele(e->nxt, e->status, -1);
+				if (!g)
+				{	fatal("unexpected error 3", (char *) 0);
+				}
 				To = g->seqno;
 			} else
 				To = 0;
diff -r 51b3bf8bc61b sys/src/cmd/spin/pangen5.h
--- a/sys/src/cmd/spin/pangen5.h	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/pangen5.h	Wed Nov 22 00:21:47 2017 -0800
@@ -1,15 +1,12 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
-static char *Xpt[] = {
+static const char *Xpt[] = {
 	"#if defined(MA) && (defined(W_XPT) || defined(R_XPT))",
 	"static Vertex	**temptree;",
 	"static char	wbuf[4096];",
@@ -80,7 +77,7 @@
 	"	int i, j;  uchar c;",
 	"	static uchar xwarned = 0;",
 	"",
-	"	sprintf(nm, \"%%s.xpt\", Source);",
+	"	sprintf(nm, \"%%s.xpt\", PanSource);",
 	"	if ((fd = creat(nm, 0666)) <= 0)",
 	"	if (!xwarned)",
 	"	{	xwarned = 1;",
@@ -136,7 +133,7 @@
 	"	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);",
+	"	{	printf(\"%%lu: \", stackcnt);",
 	"		for (i = 0; i < dfa_depth; i++)",
 	"			printf(\"%%d,\", stacker[i]);",
 	"		printf(\" -- not a stackstate <o:%%d,4:%%d>\\n\", r, j);",
@@ -372,7 +369,7 @@
 	"	int i, j;",
 	"",
 	"	wcnt = 0;",
-	"	sprintf(nm, \"%%s.xpt\", Source);",
+	"	sprintf(nm, \"%%s.xpt\", PanSource);",
 	"	if ((fd = open(nm, 0)) < 0)	/* O_RDONLY */",
 	"		Uerror(\"cannot open checkpoint file\");",
 	"",
@@ -416,7 +413,7 @@
 	"	x_cleanup(d);",
 	"	close(fd);",
 	"",
-	"	printf(\"pan: removed %%d stackstates\\n\", stackcnt);",
+	"	printf(\"pan: removed %%lu stackstates\\n\", stackcnt);",
 	"	nstates -= (double) stackcnt;",
 	"}",
 	"#endif",
diff -r 51b3bf8bc61b sys/src/cmd/spin/pangen6.c
--- a/sys/src/cmd/spin/pangen6.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/pangen6.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,20 +1,10 @@
 /***** 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          */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include "spin.h"
 #include "y.tab.h"
@@ -90,7 +80,6 @@
 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;
 
@@ -145,7 +134,7 @@
 {
 	if (!n || !n->sym) return;
 
-	if (n->sym->nel != 1)
+	if (n->sym->nel > 1 || n->sym->isarray)
 		def_use(n->lft, code);		/* process the index */
 
 	if (n->sym->type == STRUCT		/* and possible deeper ones */
@@ -202,6 +191,8 @@
 	case '~':
 	case 'c':
 	case ENABLED:
+	case SET_P:
+	case GET_P:
 	case ASSERT:
 	case EVAL:
 		def_use(now->lft, USE|code);
@@ -503,7 +494,7 @@
 	if (strcmp(as->name, bs->name) != 0)
 		return 0;
 
-	if (as->type == STRUCT && a->rgt && b->rgt)
+	if (as->type == STRUCT && a->rgt && b->rgt)	/* we know that a and b are not null */
 		return AST_mutual(a->rgt->lft, b->rgt->lft, 0);
 
 	return 1;
@@ -545,14 +536,14 @@
 			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 */
+				{	int aa = AST_nrpar(cl->s);
+					int bb = AST_nrpar(t->step->n);
+					if (aa != bb)	/* 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 */
+					aa = AST_ord(cl->s, cl->n);
+					bb = AST_ord(t->step->n, u->n);
+					if (aa != bb)	/* same position in parlist */
 						continue;
 
 					AST_add_alias(cl->n, 4); /* RCV assume possible match */
@@ -692,9 +683,7 @@
 	}
 
 	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)
+	{	if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE)
 		for (f = a->fsm; f; f = f->nxt)
 		for (t = f->t; t; t = t->nxt)
 		{	if (!(t->relevant&1))
@@ -786,10 +775,8 @@
 	 */
 
 	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)
+	{	if (a->p->b == N_CLAIM || a->p->b == I_PROC
+		||  a->p->b == E_TRACE || a->p->b == N_TRACE)
 		{	a->relevant |= 1;	/* the proctype is relevant */
 			continue;
 		}
@@ -823,9 +810,9 @@
 		printf("spin: redundant in proctype %s (for given property):\n",
 			a->p->n->name);
 	}
-	printf("      line %3d %s (state %d)",
+	printf("      %s:%d (state %d)",
+		e->n?e->n->fn->name:"-",
 		e->n?e->n->ln:-1,
-		e->n?e->n->fn->name:"-",
 		e->seqno);
 	printf("	[");
 	comment(stdout, e->n, 0);
@@ -1016,7 +1003,8 @@
 	printf(" -- %d\n", code);
 #endif
 	if (in_recv && (code&DEF) && (code&USE))
-	{	printf("spin: error: DEF and USE of same var in rcv stmnt: ");
+	{	printf("spin: %s:%d, error: DEF and USE of same var in rcv stmnt: ",
+			n->fn->name, n->ln);
 		AST_var(n, n->sym, 1);
 		printf(" -- %d\n", code);
 		nr_errs++;
@@ -1065,6 +1053,8 @@
 	case '~':
 	case 'c':
 	case ENABLED:
+	case SET_P:
+	case GET_P:
 	case ASSERT:
 		AST_track(now->lft, USE|code);
 		break;
@@ -1075,8 +1065,8 @@
 
 	case NAME:
 		name_AST_track(now, code);
-		if (now->sym->nel != 1)
-			AST_track(now->lft, USE|code);	/* index */
+		if (now->sym->nel > 1 || now->sym->isarray)
+			AST_track(now->lft, USE);	/* index, was USE|code */
 		break;
 
 	case 'R':
@@ -1569,7 +1559,8 @@
 			{	t->relevant &= ~2;	/* clear mark */
 				if (verbose&32)
 				{	printf("\t\tnomark ");
-					comment(stdout, t->step->n, 0);
+					if (t->step && t->step->n)
+						comment(stdout, t->step->n, 0);
 					printf("\n");
 	}		}	}
 
@@ -1601,7 +1592,8 @@
 			t->relevant |= 2;	/* lift */
 			if (verbose&32)
 			{	printf("\t\t\tliftmark ");
-				comment(stdout, t->step->n, 0);
+				if (t->step && t->step->n)
+					comment(stdout, t->step->n, 0);
 				printf("\n");
 			}
 			AST_spread(a, t->to);	/* and spread to all guards */
@@ -1621,10 +1613,9 @@
 {	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);
+	{	if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE)
+		{	AST_ctrl(a);
+	}	}
 }
 
 static void
@@ -1634,9 +1625,7 @@
 	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)
+	{	if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE)
 		for (f = a->fsm; f; f = f->nxt)
 		for (t = f->t; t; t = t->nxt)
 		{	if (t->step
@@ -1692,8 +1681,7 @@
 	int spurious = 0;
 
 	if (!slicer)
-	{	non_fatal("no slice criteria (or no claim) specified",
-		(char *) 0);
+	{	printf("spin: warning: no slice criteria found (no assertions and no claim)\n");
 		spurious = 1;
 	}
 	AST_dorelevant();		/* mark procs refered to in remote refs */
@@ -1730,9 +1718,7 @@
 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)
+	if (p->b != N_CLAIM && p->b != E_TRACE && p->b != N_TRACE)
 	{	n_ast = (AST *) emalloc(sizeof(AST));
 		n_ast->p = p;
 		n_ast->i_st = start_state;
@@ -1809,12 +1795,10 @@
 	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 */
-
+	{	if (a->p->b == N_CLAIM || a->p->b == I_PROC
+		||  a->p->b == E_TRACE || a->p->b == N_TRACE)
+		{	continue;			/* has no params */
+		}
 		cnt = 0;
 		for (f = a->p->p; f; f = f->rgt)	/* types */
 		for (t = f->lft; t; t = t->rgt)		/* formals */
@@ -1845,9 +1829,8 @@
 	}	}
 
 	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 */
+	{	if (a->p->b != N_CLAIM
+		&&  a->p->b != E_TRACE && a->p->b != N_TRACE)	/* has no locals */
 		for (walk = all_names; walk; walk = walk->next)	
 		{	sp = walk->entry;
 			if (sp
@@ -1995,7 +1978,7 @@
 	h = fsm_tbl[out];
 
 	i = f->from / BPW;
-	j = f->from % BPW;
+	j = f->from % BPW; /* assert(j <= 32); else lshift undefined? */
 	g = h->mod;
 
 	if (verbose&32)
@@ -2023,28 +2006,30 @@
 		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. */
-
+		{	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. */
-
+			{	continue;				/* c. */
+			}
 			i = cnt / BPW;
-			j = cnt % BPW;
+			j = cnt % BPW;	/* assert(j <= 32); */
 			if (!(f->dom[i]&(1<<j)))
-				continue;
-
+			{	continue;
+			}
 			for (t = fsm_tbl[cnt]->t, i = 0; t; t = t->nxt)
-				i += fsm_tbl[t->to]->seen;
+			{	i += fsm_tbl[t->to]->seen;
+			}
 			if (i <= 1)
-				continue;				/* b. */
-
+			{	continue;				/* b. */
+			}
 			if (f->mod)			/* final check in 2nd phase */
-				subgraph(a, f, cnt);	/* possible entry-exit pair */
-		}
-	}
+			{	subgraph(a, f, cnt);	/* possible entry-exit pair */
+	}	}	}
 }
 
 static void
@@ -2178,27 +2163,26 @@
 	for (f = a->fsm; f; f = f->nxt)
 	{	if (!f->seen) continue;
 
-		f->dom = (ulong *)
-			emalloc(a->nwords * sizeof(ulong));
+		f->dom = (ulong *) emalloc(a->nwords * sizeof(ulong));
 
 		if (f->from == a->i_st)
 		{	i = a->i_st / BPW;
-			j = a->i_st % BPW;
+			j = a->i_st % BPW; /* assert(j <= 32); */
 			f->dom[i] = (1<<j);			/* (1) */
 		} else						/* (2) */
 		{	for (i = 0; i < a->nwords; i++)
-				f->dom[i] = (ulong) ~0;			/* all 1's */
-
+			{	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 */
-
+			{	f->dom[a->nwords-1] &= ~(1<< ((ulong) i)); /* clear tail */
+			}
 			for (cnt = 0; cnt < a->nstates; cnt++)
-				if (!fsm_tbl[cnt]->seen)
+			{	if (!fsm_tbl[cnt]->seen)
 				{	i = cnt / BPW;
-					j = cnt % BPW;
-					f->dom[i] &= ~(1<<j);
-	}	}		}
+					j = cnt % BPW; /* assert(j <= 32); */
+					f->dom[i] &= ~(1<< ((ulong) j));
+	}	}	}	}
 }
 
 static int
@@ -2226,7 +2210,7 @@
 	}
 
 	i = f->from / BPW;
-	j = f->from % BPW;
+	j = f->from % BPW;	/* assert(j <= 32); */
 	ndom[i] |= (1<<j);			/* (5a) */
 
 	for (i = 0; i < a->nwords; i++)
@@ -2261,6 +2245,7 @@
 	FSM_trans *t;
 	AST *a;
 	int oi;
+	static FSM_state no_state;
 #if 0
 	find dominators
 	Aho, Sethi, & Ullman, Compilers - principles, techniques, and tools
diff -r 51b3bf8bc61b sys/src/cmd/spin/pangen6.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/cmd/spin/pangen6.h	Wed Nov 22 00:21:47 2017 -0800
@@ -0,0 +1,2878 @@
+/***** spin: pangen6.h *****/
+
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
+
+static const char *Code2e[] = {
+	"#if (NCORE>1 || defined(BFS_PAR)) && !defined(WIN32) && !defined(WIN64)",
+	"	/* Test and Set assembly code */",
+	"	#if defined(i386) || defined(__i386__) || defined(__x86_64__)",
+	"		int",
+	"		tas(volatile int *s)	/* tested */",
+	"		{	int r;",
+	"			__asm__ __volatile__(",
+	"				\"xchgl %%0, %%1 \\n\\t\"",
+	"		       		: \"=r\"(r), \"=m\"(*s)",
+	"				: \"0\"(1), \"m\"(*s)",
+	"				: \"memory\");",
+	"		",
+	"			return r;",
+	"		}",
+	"	#elif defined(__arm__)",
+	"		int",
+	"		tas(volatile int *s)	/* not tested */",
+	"		{	int r = 1;",
+	"			__asm__ __volatile__(",
+	"				\"swpb %%0, %%0, [%%3] \\n\"",
+	"				: \"=r\"(r), \"=m\"(*s)",
+	"				: \"0\"(r), \"r\"(s));",
+	"",
+	"			return r;",
+	"		}",
+	"	#elif defined(sparc) || defined(__sparc__)",
+	"		int",
+	"		tas(volatile int *s)	/* not tested */",
+	"		{	int r = 1;",
+	"			__asm__ __volatile__(",
+	"				\" ldstub [%%2], %%0 \\n\"",
+	"				: \"=r\"(r), \"=m\"(*s)",
+	"				: \"r\"(s));",
+	"",
+	"			return r;",
+	"		}",
+	"	#elif defined(ia64) || defined(__ia64__)",
+	"		/* Intel Itanium */",
+	"		int",
+	"		tas(volatile int *s)	/* tested */",
+	"		{	long int r;",
+	"			__asm__ __volatile__(",
+	"				\"	xchg4 	%%0=%%1,%%2	\\n\"",
+	"		:		\"=r\"(r), \"+m\"(*s)",
+	"		:		\"r\"(1)",
+	"		:		\"memory\");",
+	"			return (int) r;",
+	"		}",
+	"	#elif defined(__powerpc64__)",
+	"		int",
+	"		tas(volatile int *s)	/* courtesy srirajpaul */",
+	"		{	int r;",
+	" #if 1",
+	"			r = __sync_lock_test_and_set();",
+	" #else",
+	"			/* xlc compiler only */",
+	"			r = __fetch_and_or(s, 1);",
+	"			__isync();",
+	" #endif",
+	"			return r;",
+	"		}",
+	"	#else",
+	"		#error missing definition of test and set operation for this platform",
+	"	#endif",
+	"",
+	"	#ifndef NO_CAS", /* linux, windows */
+	"		#define cas(a,b,c) __sync_bool_compare_and_swap(a,b,c)",
+	"	#else",
+	"	int", /* workaround if the above is not available */
+	"	cas(volatile uint32_t *a, uint32_t b, uint32_t c)",
+	"	{	static volatile int cas_lock;",
+	"		while (tas(&cas_lock) != 0) { ; }",
+	"		if (*a == b)",
+	"		{	*a = c;",
+	"			cas_lock = 0;",
+	"			return 1;",
+	"		}",
+	"		cas_lock = 0;",
+	"		return 0;",
+	"	}",
+	"	#endif",
+	"#endif",
+	0,
+};
+
+static const char *Code2c[] = { /* multi-core option - Spin 5.0 and later */
+	"#if NCORE>1",
+	"#if defined(WIN32) || defined(WIN64)",
+	"	#ifndef _CONSOLE",
+	"		#define _CONSOLE",
+	"	#endif",
+	"	#ifdef WIN64",
+	"		#undef long",
+	"	#endif",
+	"	#include <windows.h>",
+	"/*",
+	"	#ifdef WIN64",
+	"		#define long	long long",
+	"	#endif",
+	"*/",
+	"#else",
+	"	#include <sys/ipc.h>",
+	"	#include <sys/sem.h>",
+	"	#include <sys/shm.h>",
+	"#endif",
+	"",
+	"/* code common to cygwin/linux and win32/win64: */",
+	"",
+	"#ifdef VERBOSE",
+	"	#define VVERBOSE	(1)",
+	"#else",
+	"	#define VVERBOSE	(0)",
+	"#endif",
+	"",
+	"/* the following values must be larger than 256 and must fit in an int */",
+	"#define QUIT		1024	/* terminate now command */",
+	"#define QUERY		 512	/* termination status query message */",
+	"#define QUERY_F	 513	/* query failed, cannot quit */",
+	"",
+	"#define GN_FRAMES	(int) (GWQ_SIZE / (double) sizeof(SM_frame))",
+	"#define LN_FRAMES	(int) (LWQ_SIZE / (double) sizeof(SM_frame))",
+	"",
+	"#ifndef VMAX",
+	"	#define VMAX	VECTORSZ",
+	"#endif",
+	"#ifndef PMAX",
+	"	#define PMAX	64",
+	"#endif",
+	"#ifndef QMAX",
+	"	#define QMAX	64",
+	"#endif",
+	"",
+	"#if VECTORSZ>32000",
+	"	#define OFFT	int",
+	"#else",
+	"	#define OFFT	short",
+	"#endif",
+	"",
+	"#ifdef SET_SEG_SIZE",
+	"	/* no longer useful -- being recomputed for local heap size anyway */",
+	"	double SEG_SIZE = (((double) SET_SEG_SIZE) * 1048576.);",
+	"#else",
+	"	double SEG_SIZE = (1048576.*1024.);	/* 1GB default shared memory pool segments */",
+	"#endif",
+	"",
+	"double LWQ_SIZE = 0.; /* initialized in main */",
+	"",
+	"#ifdef SET_WQ_SIZE",
+	"	#ifdef NGQ",
+	"	#warning SET_WQ_SIZE applies to global queue -- ignored",
+	"	double GWQ_SIZE = 0.;",
+	"	#else",
+	"	double GWQ_SIZE = (((double) SET_WQ_SIZE) * 1048576.);",
+	"	/* must match the value in pan_proxy.c, if used */",
+	"	#endif",
+	"#else",
+	"	#ifdef NGQ",
+	"	double GWQ_SIZE = 0.;",
+	"	#else",
+	"	double GWQ_SIZE = (128.*1048576.);	/* 128 MB default queue sizes */",
+	"	#endif",
+	"#endif",
+	"",
+	"/* Crash Detection Parameters */",
+	"#ifndef ONESECOND",
+	"	#define ONESECOND	(1<<25)", /* name is somewhat of a misnomer */
+	"#endif",
+	"#ifndef SHORT_T",
+	"	#define SHORT_T	(0.1)",
+	"#endif",
+	"#ifndef LONG_T",
+	"	#define LONG_T	(600)",
+	"#endif",
+	"",
+	"double OneSecond   = (double) (ONESECOND); /* waiting for a free slot -- checks crash */",
+	"double TenSeconds  = 10. * (ONESECOND);    /* waiting for a lock -- check for a crash */",
+	"",
+	"/* Termination Detection Params -- waiting for new state input in Get_Full_Frame */",
+	"double Delay       = ((double) SHORT_T) * (ONESECOND);	/* termination detection trigger */",
+	"double OneHour     = ((double) LONG_T) * (ONESECOND);	/* timeout termination detection */",
+	"",
+	"typedef struct SM_frame     SM_frame;",
+	"typedef struct SM_results   SM_results;",
+	"typedef struct sh_Allocater sh_Allocater;",
+	"",
+	"struct SM_frame {			/* about 6K per slot */",
+	"	volatile int	m_vsize;	/* 0 means free slot */",
+	"	volatile int	m_boq;		/* >500 is a control message */",
+	"#ifdef FULL_TRAIL",
+	"	volatile struct Stack_Tree *m_stack;	/* ptr to previous state */",
+	"#endif",
+	"	volatile uchar	m_tau;",
+	"	volatile uchar	m_o_pm;",
+	"	volatile int	nr_handoffs;	/* to compute real_depth */",
+	"	volatile char	m_now     [VMAX];",
+	"#if !defined(NOCOMP) && !defined(HC)",
+	"	volatile char	m_mask    [(VMAX + 7)/8];",
+	"#endif",
+	"	volatile OFFT	m_p_offset[PMAX];",
+	"	volatile OFFT	m_q_offset[QMAX];",
+	"	volatile uchar	m_p_skip  [PMAX];",
+	"	volatile uchar	m_q_skip  [QMAX];",
+	"#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)",
+	"	volatile uchar	m_c_stack [StackSize];",
+		 /* captures contents of c_stack[] for unmatched objects */
+	"#endif",
+	"};",
+	"",
+	"int	proxy_pid;		/* id of proxy if nonzero -- receive half */",
+	"int	store_proxy_pid;",
+	"short	remote_party;",
+	"int	proxy_pid_snd;		/* id of proxy if nonzero -- send half */",
+	"char	o_cmdline[512];		/* to pass options to children */",
+	"",
+	"int	iamin[CS_NR+NCORE];		/* non-shared */",
+	"",
+"#if defined(WIN32) || defined(WIN64)",
+	"int tas(volatile LONG *);",
+	"",
+	"HANDLE		proxy_handle_snd;	/* for Windows Create and Terminate */",
+	"",
+	"struct sh_Allocater {			/* shared memory for states */",
+	"	volatile char	*dc_arena;	/* to allocate states from */",
+	"	volatile long	 pattern;	/* to detect overruns */",
+	"	volatile long	 dc_size;	/* nr of bytes left */",
+	"	volatile void	*dc_start;	/* where memory segment starts */",
+	"	volatile void	*dc_id;		/* to attach, detach, remove shared memory segments */",
+	"	volatile sh_Allocater *nxt;	/* linked list of pools */",
+	"};",
+	"DWORD		worker_pids[NCORE];	/* root mem of pids of all workers created */",
+	"HANDLE		worker_handles[NCORE];	/* for windows Create and Terminate */",
+	"void *		shmid      [NR_QS];	/* return value from CreateFileMapping */",
+	"void *		shmid_M;		/* shared mem for state allocation in hashtable */",
+	"",
+	"#ifdef SEP_STATE",
+	"	void *shmid_X;",
+	"#else",
+	"	void *shmid_S;			/* shared bitstate arena or hashtable */",
+	"#endif",
+"#else",
+	"int tas(volatile int *);",
+	"",
+	"struct sh_Allocater {			/* shared memory for states */",
+	"	volatile char	*dc_arena;	/* to allocate states from */",
+	"	volatile long	 pattern;	/* to detect overruns */",
+	"	volatile long	 dc_size;	/* nr of bytes left */",
+	"	volatile char	*dc_start;	/* where memory segment starts */",
+	"	volatile int	dc_id;		/* to attach, detach, remove shared memory segments */",
+	"	volatile sh_Allocater *nxt;	/* linked list of pools */",
+	"};",
+	"",
+	"int	worker_pids[NCORE];	/* root mem of pids of all workers created */",
+	"int	shmid      [NR_QS];	/* return value from shmget */",
+	"int	nibis = 0;		/* set after shared mem has been released */",
+	"int	shmid_M;		/* shared mem for state allocation in hashtable */",
+	"#ifdef SEP_STATE",
+	"	long	shmid_X;",
+	"#else",
+	"	int	shmid_S;	/* shared bitstate arena or hashtable */",
+	"	volatile sh_Allocater	*first_pool;	/* of shared state memory */",
+	"	volatile sh_Allocater	*last_pool;",
+	"#endif", /* SEP_STATE */
+"#endif", /* WIN32 || WIN64 */
+	"",
+	"struct SM_results {			/* for shuttling back final stats */",
+	"	volatile int	m_vsize;	/* avoid conflicts with frames */",
+	"	volatile int	m_boq;		/* these 2 fields are not written in record_info */",
+	"	/* probably not all fields really need to be volatile */",
+	"	volatile double	m_memcnt;",
+	"	volatile double	m_nstates;",
+	"	volatile double	m_truncs;",
+	"	volatile double	m_truncs2;",
+	"	volatile double	m_nShadow;",
+	"	volatile double	m_nlinks;",
+	"	volatile double	m_ngrabs;",
+	"	volatile double	m_nlost;",
+	"	volatile double	m_hcmp;",
+	"	volatile double	m_frame_wait;",
+	"	volatile int	m_hmax;",
+	"	volatile int	m_svmax;",
+	"	volatile int	m_smax;",
+	"	volatile int	m_mreached;",
+	"	volatile int	m_errors;",
+	"	volatile int	m_VMAX;",
+	"	volatile short	m_PMAX;",
+	"	volatile short	m_QMAX;",
+	"	volatile uchar	m_R;		/* reached info for all proctypes */",
+	"};",
+	"",
+	"int		core_id = 0;		/* internal process nr, to know which q to use */",
+	"unsigned long	nstates_put = 0;	/* statistics */",
+	"unsigned long	nstates_get = 0;",
+	"int		query_in_progress = 0;	/* termination detection */",
+	"",
+	"double		free_wait  = 0.;	/* waiting for a free frame */",
+	"double		frame_wait = 0.;	/* waiting for a full frame */",
+	"double		lock_wait  = 0.;	/* waiting for access to cs */",
+	"double		glock_wait[3];	/* waiting for access to global lock */",
+	"",
+	"char		*sprefix = \"rst\";",
+	"uchar		was_interrupted, issued_kill, writing_trail;",
+	"",
+	"static SM_frame cur_Root;		/* current root, to be safe with error trails */",
+	"",
+	"SM_frame	*m_workq   [NR_QS];	/* per cpu work queues + global q */",
+	"char		*shared_mem[NR_QS];	/* return value from shmat */",
+	"#ifdef SEP_HEAP",
+	"char		*my_heap;",
+	"long		 my_size;",
+	"#endif",
+	"volatile sh_Allocater	*dc_shared;	/* assigned at initialization */",
+	"",
+	"static int	vmax_seen, pmax_seen, qmax_seen;",
+	"static double	gq_tries, gq_hasroom, gq_hasnoroom;",
+	"",
+	"volatile int *prfree;",	/* [NCORE] */
+	"volatile int *prfull;",	/* [NCORE] */
+	"volatile int *prcnt;",		/* [NCORE] */
+	"volatile int *prmax;",		/* [NCORE] */
+	"",
+	"volatile int	*sh_lock;	/* mutual exclusion locks - in shared memory */",
+	"volatile double *is_alive;	/* to detect when processes crash */",
+	"volatile int    *grfree, *grfull, *grcnt, *grmax;	/* access to shared global q */",
+	"volatile double *gr_readmiss, *gr_writemiss;",
+	"static   int	lrfree;		/* used for temporary recording of slot */",
+	"static   int dfs_phase2;",
+	"",
+	"void mem_put(int);		/* handoff state to other cpu */",
+	"void mem_put_acc(void);	/* liveness mode */",
+	"void mem_get(void);		/* get state from work queue  */",
+	"void sudden_stop(char *);",
+	"",
+	"void",
+	"record_info(SM_results *r)",
+	"{	int i;",
+	"	uchar *ptr;",
+	"",
+	"#ifdef SEP_STATE",
+	"	if (0)",
+	"	{	cpu_printf(\"nstates %%g nshadow %%g -- memory %%-6.3f Mb\\n\",",
+	"			nstates, nShadow, memcnt/(1048576.));",
+	"	}",
+	"	r->m_memcnt = 0;",
+	"#else",
+	"	#ifdef BITSTATE",
+		"	r->m_memcnt = 0; /* it's shared */",
+	"	#endif",
+	"	r->m_memcnt = memcnt;",
+	"#endif",
+	"	if (a_cycles && core_id == 1)",
+	"	{	r->m_nstates  = nstates;",
+	"		r->m_nShadow  = nstates;",
+	"	} else",
+	"	{	r->m_nstates  = nstates;",
+	"		r->m_nShadow  = nShadow;",
+	"	}",
+	"	r->m_truncs   = truncs;",
+	"	r->m_truncs2  = truncs2;",
+	"	r->m_nlinks   = nlinks;",
+	"	r->m_ngrabs   = ngrabs;",
+	"	r->m_nlost    = nlost;",
+	"	r->m_hcmp     = hcmp;",
+	"	r->m_frame_wait = frame_wait;",
+	"	r->m_hmax     = hmax;",
+	"	r->m_svmax    = svmax;",
+	"	r->m_smax     = smax;",
+	"	r->m_mreached = mreached;",
+	"	r->m_errors   = errors;",
+	"	r->m_VMAX     = vmax_seen;",
+	"	r->m_PMAX     = (short) pmax_seen;",
+	"	r->m_QMAX     = (short) qmax_seen;",
+	"	ptr = (uchar *) &(r->m_R);",
+	"	for (i = 0; i <= _NP_; i++)	/* all proctypes */",
+	"	{	memcpy(ptr, reached[i], NrStates[i]*sizeof(uchar));",
+	"		ptr += NrStates[i]*sizeof(uchar);",
+	"	}",
+	"	if (verbose>1)",
+	"	{	cpu_printf(\"Put Results nstates %%g (sz %%d)\\n\", nstates, ptr - &(r->m_R));",
+	"	}",
+	"}",
+	"",
+	"void snapshot(void);",
+	"",
+	"void",
+	"retrieve_info(SM_results *r)",
+	"{	int i, j;",
+	"	volatile uchar *ptr;",
+	"",
+	"	snapshot();	/* for a final report */",
+	"",
+	"	enter_critical(GLOBAL_LOCK);",
+	"#ifdef SEP_HEAP",
+	"	if (verbose)",
+	"	{	printf(\"cpu%%d: local heap-left %%ld KB (%%d MB)\\n\",",
+	"			core_id, (long) (my_size/1024), (int) (my_size/1048576));",
+	"	}",
+	"#endif",
+	"	if (verbose && core_id == 0)",
+	"	{	printf(\"qmax: \");",
+	"		for (i = 0; i < NCORE; i++)",
+	"		{	printf(\"%%d \", prmax[i]);",
+	"		}",
+	"#ifndef NGQ",
+	"		printf(\"G: %%d\", *grmax);",
+	"#endif",
+	"		printf(\"\\n\");",
+	"	}",
+	"	leave_critical(GLOBAL_LOCK);",
+	"",
+	"	memcnt  += r->m_memcnt;",
+	"	nstates += r->m_nstates;",
+	"	nShadow += r->m_nShadow;",
+	"	truncs  += r->m_truncs;",
+	"	truncs2 += r->m_truncs2;",
+	"	nlinks  += r->m_nlinks;",
+	"	ngrabs  += r->m_ngrabs;",
+	"	nlost   += r->m_nlost;",
+	"	hcmp    += r->m_hcmp;",
+	"	/* frame_wait += r->m_frame_wait; */",
+	"	errors  += r->m_errors;",
+	"",
+	"	if (hmax  < r->m_hmax)  hmax  = r->m_hmax;",
+	"	if (svmax < r->m_svmax) svmax = r->m_svmax;",
+	"	if (smax  < r->m_smax)  smax  = r->m_smax;",
+	"	if (mreached < r->m_mreached) mreached = r->m_mreached;",
+	"",
+	"	if (vmax_seen < r->m_VMAX) vmax_seen = r->m_VMAX;",
+	"	if (pmax_seen < (int) r->m_PMAX) pmax_seen = (int) r->m_PMAX;",
+	"	if (qmax_seen < (int) r->m_QMAX) qmax_seen = (int) r->m_QMAX;",
+	"",
+	"	ptr = &(r->m_R);",
+	"	for (i = 0; i <= _NP_; i++)	/* all proctypes */",
+	"	{	for (j = 0; j < NrStates[i]; j++)",
+	"		{	if (*(ptr + j) != 0)",
+	"			{	reached[i][j] = 1;",
+	"		}	}",
+	"		ptr += NrStates[i]*sizeof(uchar);",
+	"	}",
+	"	if (verbose>1)",
+	"	{	cpu_printf(\"Got Results (%%d)\\n\", (int) (ptr - &(r->m_R)));",
+	"		snapshot();",
+	"	}",
+	"}",
+	"",
+	"#if !defined(WIN32) && !defined(WIN64)",
+	"static void",
+	"rm_shared_segments(void)",
+	"{	int m;",
+	"	volatile sh_Allocater *nxt_pool;",
+	"	/*",
+	"	 * mark all shared memory segments for removal ",
+	"	 * the actual removes wont happen intil last process dies or detaches",
+	"	 * the shmctl calls can return -1 if not all procs have detached yet",
+	"	 */",
+	"	for (m = 0; m < NR_QS; m++)	/* +1 for global q */",
+	"	{	if (shmid[m] != -1)",
+	"		{	(void) shmctl(shmid[m], IPC_RMID, NULL);",
+	"	}	}",
+	"#ifdef SEP_STATE",
+	"	if (shmid_M != -1)",
+	"	{	(void) shmctl(shmid_M, IPC_RMID, NULL);",
+	"	}",
+	"#else",
+	"	if (shmid_S != -1)",
+	"	{	(void) shmctl(shmid_S, IPC_RMID, NULL);",
+	"	}",
+	"	for (last_pool = first_pool; last_pool != NULL; last_pool = nxt_pool)",
+	"	{	shmid_M = (int) (last_pool->dc_id);",
+	"		nxt_pool = last_pool->nxt;	/* as a pre-caution only */",
+	"		if (shmid_M != -1)",
+	"		{	(void) shmctl(shmid_M, IPC_RMID, NULL);",
+	"	}	}",
+	"#endif",
+	"}",
+	"#endif",
+	"",
+	"void",
+	"sudden_stop(char *s)",
+	"{	char b[64];",
+	"	int i;",
+	"",
+	"	printf(\"cpu%%d: stop - %%s\\n\", core_id, s);",
+	"#if !defined(WIN32) && !defined(WIN64)",
+	"	if (proxy_pid != 0)",
+	"	{	rm_shared_segments();",
+	"	}",
+	"#endif",
+	"	if (search_terminated != NULL)",
+	"	{	if (*search_terminated != 0)",
+	"		{	if (verbose)",
+	"			{	printf(\"cpu%%d: termination initiated (%%d)\\n\",",
+	"					core_id, (int) *search_terminated);",
+	"			}",
+	"		} else",
+	"		{	if (verbose)",
+	"			{	printf(\"cpu%%d: initiated termination\\n\", core_id);",
+	"			}",
+	"			*search_terminated |= 8;	/* sudden_stop */",
+	"		}",
+	"		if (core_id == 0)",
+	"		{	if (((*search_terminated) & 4)	/* uerror in one of the cpus */",
+	"			&& !((*search_terminated) & (8|32|128|256))) /* abnormal stop */",
+	"			{	if (errors == 0) errors++; /* we know there is at least 1 */",
+	"			}",
+	"			wrapup(); /* incomplete stats, but at least something */",
+	"		}",
+	"		return;",
+	"	} /* else: should rarely happen, take more drastic measures */",
+	"",
+	"	if (core_id == 0)	/* local root process */",
+	"	{	for (i = 1; i < NCORE; i++)	/* not for 0 of course */",
+	"		{	int ignore;",
+	"#if defined(WIN32) || defined(WIN64)",
+	"				DWORD dwExitCode = 0;",
+	"				GetExitCodeProcess(worker_handles[i], &dwExitCode);",
+	"				if (dwExitCode == STILL_ACTIVE)",
+	"				{	TerminateProcess(worker_handles[i], 0);",
+	"				}",
+	"				printf(\"cpu0: terminate %%d %%d\\n\",",
+	"					(int) worker_pids[i], (dwExitCode == STILL_ACTIVE));",
+	"#else",
+	"				sprintf(b, \"kill -%%d %%d\", (int) SIGKILL, (int) worker_pids[i]);",
+	"				ignore = system(b);	/* if this is a proxy: receive half */",
+	"				printf(\"cpu0: %%s\\n\", b);",
+	"#endif",
+	"		}",
+	"		issued_kill++;",
+	"	} else",
+	"	{	/* on WIN32/WIN64 -- these merely kills the root process... */",
+	"		if (was_interrupted == 0)",	/* 2=SIGINT to root to trigger stop */
+	"		{	int ignore;",
+	"			sprintf(b, \"kill -%%d %%d\", (int) SIGINT, (int) worker_pids[0]);",
+	"			ignore = system(b);	/* warn the root process */",
+	"			printf(\"cpu%%d: %%s\\n\", core_id, b);",
+	"			issued_kill++;",
+	"	}	}",
+	"}",
+	"",
+	"#define iam_alive()	is_alive[core_id]++",	/* for crash detection */
+	"",
+	"extern int crash_test(double);",
+	"extern void crash_reset(void);",
+	"",
+	"int",
+	"someone_crashed(int wait_type)",
+	"{	static double last_value = 0.0;",
+	"	static int count = 0;",
+	"",
+	"	if (search_terminated == NULL",
+	"	|| *search_terminated != 0)",
+	"	{",
+	"		if (!(*search_terminated & (8|32|128|256)))",
+	"		{	if (count++ < 100*NCORE)",
+	"			{	return 0;",
+	"		}	}",
+	"		return 1;",
+	"	}",
+	"	/* check left neighbor only */",
+	"	if (last_value == is_alive[(core_id + NCORE - 1) %% NCORE])",
+	"	{	if (count++ >= 100)	/* to avoid unnecessary checks */",
+	"		{	return 1;",
+	"		}",
+	"		return 0;",
+	"	}",
+	"	last_value = is_alive[(core_id + NCORE - 1) %% NCORE];",
+	"	count = 0;",
+	"	crash_reset();",
+	"	return 0;",
+	"}",
+	"",
+	"void",
+	"sleep_report(void)",
+	"{",
+	"	enter_critical(GLOBAL_LOCK);",
+	"	if (verbose)",
+	"	{",
+	"#ifdef NGQ",
+	"		printf(\"cpu%%d: locks: global %%g\\tother %%g\\t\",",
+	"			core_id, glock_wait[0], lock_wait - glock_wait[0]);",
+	"#else",
+	"		printf(\"cpu%%d: locks: GL %%g, RQ %%g, WQ %%g, HT %%g\\t\",",
+	"			core_id, glock_wait[0], glock_wait[1], glock_wait[2],",
+	"			lock_wait - glock_wait[0] - glock_wait[1] - glock_wait[2]);",
+	"#endif",
+	"		printf(\"waits: states %%g slots %%g\\n\", frame_wait, free_wait);",
+	"#ifndef NGQ",
+	"		printf(\"cpu%%d: gq [tries %%g, room %%g, noroom %%g]\\n\", core_id, gq_tries, gq_hasroom, gq_hasnoroom);",
+	"		if (core_id == 0 && (*gr_readmiss >= 1.0 || *gr_readmiss >= 1.0 || *grcnt != 0))",
+	"		printf(\"cpu0: gq [readmiss: %%g, writemiss: %%g cnt %%d]\\n\", *gr_readmiss, *gr_writemiss, *grcnt);",
+	"#endif",
+	"	}",
+	"	if (free_wait > 1000000.)",
+	"	#ifndef NGQ",
+	"	if (!a_cycles)",
+	"	{	printf(\"hint: this search may be faster with a larger work-queue\\n\");",
+	"		printf(\"	(-DSET_WQ_SIZE=N with N>%%g), and/or with -DUSE_DISK\\n\",",
+	"			GWQ_SIZE/sizeof(SM_frame));",
+	"		printf(\"      or with a larger value for -zN (N>%%ld)\\n\", z_handoff);",
+	"	#else",
+	"	{	printf(\"hint: this search may be faster if compiled without -DNGQ, with -DUSE_DISK, \");",
+	"		printf(\"or with a larger -zN (N>%%d)\\n\", z_handoff);",
+	"	#endif",
+	"	}",
+	"	leave_critical(GLOBAL_LOCK);",
+	"}",
+	"",
+	"#ifndef MAX_DSK_FILE",
+	"	#define MAX_DSK_FILE	1000000	/* default is max 1M states per file */",
+	"#endif",
+	"",
+	"void",
+	"multi_usage(FILE *fd)",
+	"{	static int warned = 0;",
+	"	if (warned > 0) { return; } else { warned++; }",
+	"	fprintf(fd, \"\\n\");",
+	"	fprintf(fd, \"Defining multi-core  64  892k   64  576k    0     0   576k      0  0:00:01 --:--:--  0:00:01  622kmode:\\n\\n\");",
+	"	fprintf(fd, \"        -DDUAL_CORE --> same as -DNCORE=2\\n\");",
+	"	fprintf(fd, \"        -DQUAD_CORE --> same as -DNCORE=4\\n\");",
+	"	fprintf(fd, \"        -DNCORE=N   --> enables multi_core verification if N>1\\n\");",
+	"	fprintf(fd, \"\\n\");",
+	"	fprintf(fd, \"Additional directives supported in multi-core mode:\\n\\n\");",
+	"	fprintf(fd, \"        -DSEP_STATE --> forces separate statespaces instead of a single shared state space\\n\");",
+	"	fprintf(fd, \"        -DNUSE_DISK --> use disk for storing states when a work queue overflows\\n\");",
+	"	fprintf(fd, \"        -DMAX_DSK_FILE --> max nr of states per diskfile (%%d)\\n\", MAX_DSK_FILE);",
+	"	fprintf(fd, \"        -DFULL_TRAIL --> support full error trails (increases memory use)\\n\");",
+	"	fprintf(fd, \"\\n\");",
+	"	fprintf(fd, \"More advanced use (should rarely need changing):\\n\\n\");",
+	"	fprintf(fd, \"     To change the nr of states that can be stored in the global queue\\n\");",
+	"	fprintf(fd, \"     (lower numbers allow for more states to be stored, prefer multiples of 8):\\n\");",
+	"	fprintf(fd, \"        -DVMAX=N    --> upperbound on statevector for handoffs (N=%%d)\\n\", VMAX);",
+	"	fprintf(fd, \"        -DPMAX=N    --> upperbound on nr of procs (default: N=%%d)\\n\", PMAX);",
+	"	fprintf(fd, \"        -DQMAX=N    --> upperbound on nr of channels (default: N=%%d)\\n\", QMAX);",
+	"	fprintf(fd, \"\\n\");",
+#if 0
+	"#if !defined(WIN32) && !defined(WIN64)",
+	"	fprintf(fd, \"     To change the size of spin's individual shared memory segments for cygwin/linux:\\n\");",
+	"	fprintf(fd, \"        -DSET_SEG_SIZE=N --> default %%g (Mbytes)\\n\", SEG_SIZE/(1048576.));",
+	"	fprintf(fd, \"\\n\");",
+	"#endif",
+#endif
+	"	fprintf(fd, \"     To set the total amount of memory reserved for the global workqueue:\\n\");",
+	"	fprintf(fd, \"        -DSET_WQ_SIZE=N --> default: N=128 (defined in MBytes)\\n\\n\");",
+#if 0
+	"	fprintf(fd, \"     To omit the global workqueue completely (bad idea):\\n\");",
+	"	fprintf(fd, \"        -DNGQ\\n\\n\");",
+#endif
+	"	fprintf(fd, \"     To force the use of a single global heap, instead of separate heaps:\\n\");",
+	"	fprintf(fd, \"        -DGLOB_HEAP\\n\");",
+	"	fprintf(fd, \"\\n\");",
+	"	fprintf(fd, \"     To define a fct to initialize data before spawning processes (use quotes):\\n\");",
+	"	fprintf(fd, \"        \\\"-DC_INIT=fct()\\\"\\n\");",
+	"	fprintf(fd, \"\\n\");",
+	"	fprintf(fd, \"     Timer settings for termination and crash detection:\\n\");",
+	"	fprintf(fd, \"        -DSHORT_T=N --> timeout for termination detection trigger (N=%%g)\\n\", (double) SHORT_T);",
+	"	fprintf(fd, \"        -DLONG_T=N  --> timeout for giving up on termination detection (N=%%g)\\n\", (double) LONG_T);",
+	"	fprintf(fd, \"        -DONESECOND --> (1<<29) --> timeout waiting for a free slot -- to check for crash\\n\");",
+	"	fprintf(fd, \"        -DT_ALERT   --> collect stats on crash alert timeouts\\n\\n\");",
+	"	fprintf(fd, \"Help with Linux/Windows/Cygwin configuration for multi-core:\\n\");",
+	"	fprintf(fd, \"	http://spinroot.com/spin/multicore/V5_Readme.html\\n\");",
+	"	fprintf(fd, \"\\n\");",
+	"}",
+	"#if NCORE>1 && defined(FULL_TRAIL)",
+	"typedef struct Stack_Tree {",
+	"	uchar	      pr;	/* process that made transition */",
+	"	T_ID	    t_id;	/* id of transition */",
+	"	volatile struct Stack_Tree *prv; /* backward link towards root */",
+	"} Stack_Tree;",
+	"",
+	"H_el *grab_shared(int);",
+	"volatile Stack_Tree **stack_last; /* in shared memory */",
+	"char *stack_cache = NULL;	/* local */",
+	"int  nr_cached = 0;		/* local */",
+	"",
+	"#ifndef CACHE_NR",
+	"	#define CACHE_NR	1024",
+	"#endif",
+	"",
+	"volatile Stack_Tree *",
+	"stack_prefetch(void)",
+	"{	volatile Stack_Tree *st;",
+	"",
+	"	if (nr_cached == 0)",
+	"	{	stack_cache = (char *) grab_shared(CACHE_NR * sizeof(Stack_Tree));",
+	"		nr_cached = CACHE_NR;",
+	"	}",
+	"	st = (volatile Stack_Tree *) stack_cache;",
+	"	stack_cache += sizeof(Stack_Tree);",
+	"	nr_cached--;",
+	"	return st;",
+	"}",
+	"",
+	"void",
+	"Push_Stack_Tree(short II, T_ID t_id)",
+	"{	volatile Stack_Tree *st;",
+	"",
+	"	st = (volatile Stack_Tree *) stack_prefetch();",
+	"	st->pr = II;",
+	"	st->t_id = t_id;",
+	"	st->prv = (Stack_Tree *) stack_last[core_id];",
+	"	stack_last[core_id] = st;",
+	"}",
+	"",
+	"void",
+	"Pop_Stack_Tree(void)",
+	"{	volatile Stack_Tree *cf = stack_last[core_id];",
+	"",
+	"	if (cf)",
+	"	{	stack_last[core_id] = cf->prv;",
+	"	} else if (nr_handoffs * z_handoff + depth > 0)",
+	"	{	printf(\"cpu%%d: error pop_stack_tree (depth %%ld)\\n\",",
+	"			core_id, depth);",
+	"	}",
+	"}",
+	"#endif", /* NCORE>1 && FULL_TRAIL */
+	"",
+	"void",
+	"e_critical(int which)",
+	"{	double cnt_start;",
+	"",
+	"	if (readtrail || iamin[which] > 0)",
+	"	{	if (!readtrail && verbose)",
+	"		{	printf(\"cpu%%d: Double Lock on %%d (now %%d)\\n\",",
+	"				core_id, which, iamin[which]+1);",
+	"			fflush(stdout);",
+	"		}",
+	"		iamin[which]++;	/* local variable */",
+	"		return;",
+	"	}",
+	"",
+	"	cnt_start = lock_wait;",
+	"",
+	"	while (sh_lock != NULL)	/* as long as we have shared memory */",
+	"	{	int r = tas(&sh_lock[which]);",
+	"		if (r == 0)",
+	"		{	iamin[which] = 1;",
+	"			return;		/* locked */",
+	"		}",
+	"",
+	"		lock_wait++;",
+	"#ifndef NGQ",
+	"		if (which < 3) { glock_wait[which]++; }",
+	"#else",
+	"		if (which == 0) { glock_wait[which]++; }",
+	"#endif",
+	"		iam_alive();",
+	"",
+	"		if (lock_wait - cnt_start > TenSeconds)",
+	"		{	printf(\"cpu%%d: lock timeout on %%d\\n\", core_id, which);",
+	"			cnt_start = lock_wait;",
+	"			if (someone_crashed(1))",
+	"			{	sudden_stop(\"lock timeout\");",
+	"				pan_exit(1);",
+	"	}	}	}",
+	"}",
+	"",
+	"void",
+	"x_critical(int which)",
+	"{",
+	"	if (iamin[which] != 1)",
+	"	{	if (iamin[which] > 1)",
+	"		{	iamin[which]--;	/* this is thread-local - no races on this one */",
+	"			if (!readtrail && verbose)",
+	"			{	printf(\"cpu%%d: Partial Unlock on %%d (%%d more needed)\\n\",",
+	"					core_id, which, iamin[which]);",
+	"				fflush(stdout);",
+	"			}",
+	"			return;",
+	"		} else /* iamin[which] <= 0 */",
+	"		{	if (!readtrail)",
+	"			{	printf(\"cpu%%d: Invalid Unlock iamin[%%d] = %%d\\n\",",
+	"					core_id, which, iamin[which]);",
+	"				fflush(stdout);",
+	"			}",
+	"			return;",
+	"	}	}",
+	"",
+	"	if (sh_lock != NULL)",
+	"	{	iamin[which]   = 0;",
+	"#if defined(__powerpc64__)",
+	"	#if 1",
+	"		__sync_synchronize();	/* srirajpaul */",
+	"	#else",
+	"		__lwsync();		/* xlc compiler only */",
+	"	#endif",
+	"#endif",
+	"		sh_lock[which] = 0;	/* unlock */",
+	"	}",
+	"}",
+	"",
+	"void",
+	"#if defined(WIN32) || defined(WIN64)",
+	"start_proxy(char *s, DWORD r_pid)",
+	"#else",
+	"start_proxy(char *s, int r_pid)",
+	"#endif",
+	"{	char  Q_arg[16], Z_arg[16], Y_arg[16];",
+	"	char *args[32], *ptr;",
+	"	int   argcnt = 0;",
+	"",
+	"	sprintf(Q_arg, \"-Q%%d\", getpid());",
+	"	sprintf(Y_arg, \"-Y%%d\", r_pid);",
+	"	sprintf(Z_arg, \"-Z%%d\", proxy_pid /* core_id */);",
+	"",
+	"	args[argcnt++] = \"proxy\";",
+	"	args[argcnt++] = s; /* -r or -s */",
+	"	args[argcnt++] = Q_arg;",
+	"	args[argcnt++] = Z_arg;",
+	"	args[argcnt++] = Y_arg;",
+	"",
+	"	if (strlen(o_cmdline) > 0)",
+	"	{	ptr = o_cmdline; /* assume args separated by spaces */",
+	"		do {	args[argcnt++] = ptr++;",
+	"			if ((ptr = strchr(ptr, ' ')) != NULL)",
+	"			{	while (*ptr == ' ')",
+	"				{	*ptr++ = '\\0';",
+	"				}",
+	"			} else",
+	"			{	break;",
+	"			}",
+	"		} while (argcnt < 31);",
+	"	}",
+	"	args[argcnt] = NULL;",
+	"#if defined(WIN32) || defined(WIN64)",
+	"	execvp(\"pan_proxy\", args); /* no return */",
+	"#else",
+	"	execvp(\"./pan_proxy\", args); /* no return */",
+	"#endif",
+	"	Uerror(\"pan_proxy exec failed\");",
+	"}",
+	"/*** end of common code fragment ***/",
+	"",
+	"#if !defined(WIN32) && !defined(WIN64)",
+	"void",
+	"init_shm(void)		/* initialize shared work-queues - linux/cygwin */",
+	"{	key_t	key[NR_QS];",
+	"	int	n, m;",
+	"	int	must_exit = 0;",
+	"",
+	"	if (core_id == 0 && verbose)",
+	"	{	printf(\"cpu0: step 3: allocate shared workqueues %%g MB\\n\",",
+	"			((double) NCORE * LWQ_SIZE + GWQ_SIZE) / (1048576.) );",
+	"	}",
+	"	for (m = 0; m < NR_QS; m++)		/* last q is the global q */",
+	"	{	double qsize = (m == NCORE) ? GWQ_SIZE : LWQ_SIZE;",
+	"		key[m] = ftok(PanSource, m+1);", /* m must be nonzero, 1..NCORE */
+	"		if (key[m] == -1)",
+	"		{	perror(\"ftok shared queues\"); must_exit = 1; break;",
+	"		}",
+	"",
+	"		if (core_id == 0)	/* root creates */",
+	"		{	/* check for stale copy */",
+	"			shmid[m] = shmget(key[m], (size_t) qsize, 0600);",
+	"			if (shmid[m] != -1)	/* yes there is one; remove it */",
+	"			{	printf(\"cpu0: removing stale q%%d, status: %%d\\n\",",
+	"					m, shmctl(shmid[m], IPC_RMID, NULL));",
+	"			}",
+	"			shmid[m] = shmget(key[m], (size_t) qsize, 0600|IPC_CREAT|IPC_EXCL);",
+	"			memcnt += qsize;",
+	"		} else			/* workers attach */",
+	"		{	shmid[m] = shmget(key[m], (size_t) qsize, 0600);",
+	"			/* never called, since we create shm *before* we fork */",
+	"		}",
+	"		if (shmid[m] == -1)",
+	"		{	perror(\"shmget shared queues\"); must_exit = 1; break;",
+	"		}",
+	"",
+	"		shared_mem[m] = (char *) shmat(shmid[m], (void *) 0, 0);	/* attach */",
+	"		if (shared_mem[m] == (char *) -1)",
+	"		{ fprintf(stderr, \"error: cannot attach shared wq %%d (%%d Mb)\\n\",",
+	"				m+1, (int) (qsize/(1048576.)));",
+	"		  perror(\"shmat shared queues\"); must_exit = 1; break;",
+	"		}",
+	"",
+	"		m_workq[m] = (SM_frame *) shared_mem[m];",
+	"		if (core_id == 0)",
+	"		{	int nframes = (m == NCORE) ? GN_FRAMES : LN_FRAMES;",
+	"			for (n = 0; n < nframes; n++)",
+	"			{	m_workq[m][n].m_vsize = 0;",
+	"				m_workq[m][n].m_boq = 0;",
+	"	}	}	}",
+	"",
+	"	if (must_exit)",
+	"	{	rm_shared_segments();",
+	"		fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
+	"		pan_exit(1);	/* calls cleanup_shm */",
+	"	}",
+	"}",
+	"",
+	"static uchar *",
+	"prep_shmid_S(size_t n)		/* either sets SS or H_tab, linux/cygwin */",
+	"{	char	*rval;",
+	"#ifndef SEP_STATE",
+	"	key_t	key;",
+	"",
+	"	if (verbose && core_id == 0)",
+	"	{",
+	"	#ifdef BITSTATE",
+	"		printf(\"cpu0: step 1: allocate shared bitstate %%g Mb\\n\",",
+	"			(double) n / (1048576.));",
+	"	#else",
+	"		printf(\"cpu0: step 1: allocate shared hastable %%g Mb\\n\",",
+	"			(double) n / (1048576.));",
+	"	#endif",
+	"	}",
+	"	#ifdef MEMLIM", /* memlim has a value */
+	"	if (memcnt + (double) n > memlim)",
+	"	{	printf(\"cpu0: S %%8g + %%d Kb exceeds memory limit of %%8g Mb\\n\",",
+	"			memcnt/1024., (int) (n/1024), memlim/(1048576.));",
+	"		printf(\"cpu0: insufficient memory -- aborting\\n\");",
+	"		exit(1);",
+	"	}",
+	"	#endif",
+	"",
+	"	key = ftok(PanSource, NCORE+2);	/* different from queues */",
+	"	if (key == -1)",
+	"	{	perror(\"ftok shared bitstate or hashtable\");",
+	"		fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
+	"		pan_exit(1);",
+	"	}",
+	"",
+	"	if (core_id == 0)	/* root */",
+	"	{	shmid_S = shmget(key, n, 0600);",
+	"		if (shmid_S != -1)",
+	"		{	printf(\"cpu0: removing stale segment, status: %%d\\n\",",
+	"				(int) shmctl(shmid_S, IPC_RMID, NULL));",
+	"		}",
+	"		shmid_S = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL);",
+	"		memcnt += (double) n;",
+	"	} else			/* worker */",
+	"	{	shmid_S = shmget(key, n, 0600);",
+	"	}",
+	"	if (shmid_S == -1)",
+	"	{	perror(\"shmget shared bitstate or hashtable too large?\");",
+	"		fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
+	"		pan_exit(1);",
+	"	}",
+	"",
+	"	rval = (char *) shmat(shmid_S, (void *) 0, 0);	/* attach */",
+	"	if ((char *) rval == (char *) -1)",
+	"	{	perror(\"shmat shared bitstate or hashtable\");",
+	"		fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
+	"		pan_exit(1);",
+	"	}",
+	"#else",
+	"	rval = (char *) emalloc(n);",
+	"#endif",
+	"	return (uchar *) rval;",
+	"}",
+	"",
+	"#define TRY_AGAIN	1",
+	"#define NOT_AGAIN	0",
+	"",
+	"static char shm_prep_result;",
+	"",
+	"static uchar *",
+	"prep_state_mem(size_t n)		/* sets memory arena for states linux/cygwin */",
+	"{	char	*rval;",
+	"	key_t	key;",
+	"	static int cnt = 3;		/* start larger than earlier ftok calls */",
+	"",
+	"	shm_prep_result = NOT_AGAIN;	/* default */",
+	"	if (verbose && core_id == 0)",
+	"	{	printf(\"cpu0: step 2+: pre-allocate memory arena %%d of %%6.2g Mb\\n\",",
+	"			cnt-3, (double) n / (1048576.));",
+	"	}",
+	"	#ifdef MEMLIM",
+	"	if (memcnt + (double) n > memlim)",
+	"	{	printf(\"cpu0: error: M %%.0f + %%.0f Kb exceeds memory limit of %%.0f Mb\\n\",",
+	"			memcnt/1024.0, (double) n/1024.0, memlim/(1048576.));",
+	"		return NULL;",
+	"	}",
+	"	#endif",
+	"",
+	"	key = ftok(PanSource, NCORE+cnt); cnt++;", /* starts at NCORE+3 */
+	"	if (key == -1)",
+	"	{	perror(\"ftok T\");",
+	"		printf(\"pan: check './pan --' for usage details\\n\");",
+	"		pan_exit(1);",
+	"	}",
+	"",
+	"	if (core_id == 0)",
+	"	{	shmid_M = shmget(key, n, 0600);",
+	"		if (shmid_M != -1)",
+	"		{	printf(\"cpu0: removing stale memory segment %%d, status: %%d\\n\",",
+	"				cnt-3, shmctl(shmid_M, IPC_RMID, NULL));",
+	"		}",
+	"		shmid_M = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL);",
+	"		/* memcnt += (double) n; -- only amount actually used is counted */",
+	"	} else",
+	"	{	shmid_M = shmget(key, n, 0600);",
+	"	",
+	"	}",
+	"	if (shmid_M == -1)",
+	"	{	if (verbose)",
+	"		{	printf(\"error: failed to get pool of shared memory %%d of %%.0f Mb\\n\",",
+	"				cnt-3, ((double)n)/(1048576.));",
+	"			perror(\"state mem\");",
+	"			printf(\"pan: check './pan --' for usage details\\n\");",
+	"		}",
+	"		shm_prep_result = TRY_AGAIN;",
+	"		return NULL;",
+	"	}",
+	"	rval = (char *) shmat(shmid_M, (void *) 0, 0);	/* attach */",
+	"",
+	"	if ((char *) rval == (char *) -1)",
+	"	{	printf(\"cpu%%d error: failed to attach pool of shared memory %%d of %%.0f Mb\\n\",",
+	"			 core_id, cnt-3, ((double)n)/(1048576.));",
+	"		perror(\"state mem\");",
+	"		return NULL;",
+	"	}",
+	"	return (uchar *) rval;",
+	"}",
+	"",
+	"void",
+	"init_HT(unsigned long n)	/* cygwin/linux version */",
+	"{	volatile char	*x;",
+	"	double  get_mem;",
+	"#ifndef SEP_STATE",
+	"	volatile char	*dc_mem_start;",
+	"	double  need_mem, got_mem = 0.;",
+	"#endif",
+	"",
+"#ifdef SEP_STATE",
+	" #ifndef MEMLIM",
+	"	if (verbose)",
+	"	{	printf(\"cpu0: steps 0,1: no -DMEMLIM set\\n\");", /* cannot happen */
+	"	}",
+	" #else",
+	"	if (verbose)",
+	"	{	printf(\"cpu0: steps 0,1: -DMEMLIM=%%d Mb - (hashtable %%g Mb + workqueues %%g Mb)\\n\",",
+	"		MEMLIM, ((double)n/(1048576.)), (((double) NCORE * LWQ_SIZE) + GWQ_SIZE) /(1048576.) );",
+	"	}",
+	" #endif",
+	"	get_mem = NCORE * sizeof(double) + (1 + CS_NR) * sizeof(void *) + 4*sizeof(void *) + 2*sizeof(double);",
+	"	/* NCORE * is_alive + search_terminated + CS_NR * sh_lock + 6 gr vars */",
+	"	get_mem += 4 * NCORE * sizeof(void *); /* prfree, prfull, prcnt, prmax */",
+	" #ifdef FULL_TRAIL",
+	"	get_mem += (NCORE) * sizeof(Stack_Tree *); /* NCORE * stack_last */",
+	" #endif",
+	"	x = (volatile char *) prep_state_mem((size_t) get_mem); /* work queues and basic structs */",
+	"	shmid_X = (long) x;",
+	"	if (x == NULL)", /* do not repeat for smaller sizes */
+	"	{	printf(\"cpu0: could not allocate shared memory, see ./pan --\\n\");",
+	"		exit(1);",
+	"	}",
+	"	search_terminated = (volatile unsigned int *) x; /* comes first */",
+	"	x += sizeof(void *); /* maintain alignment */",
+	"",
+	"	is_alive   = (volatile double *) x;",
+	"	x += NCORE * sizeof(double);",
+	"",
+	"	sh_lock   = (volatile int *) x;",
+	"	x += CS_NR * sizeof(void *);", /* allow 1 word per entry */
+	"",
+	"	grfree    = (volatile int *) x;",
+	"	x += sizeof(void *);",
+	"	grfull    = (volatile int *) x;",
+	"	x += sizeof(void *);",
+	"	grcnt    = (volatile int *) x;",
+	"	x += sizeof(void *);",
+	"	grmax    = (volatile int *) x;",
+	"	x += sizeof(void *);",
+	"	prfree = (volatile int *) x;",
+	"	x += NCORE * sizeof(void *);",
+	"	prfull = (volatile int *) x;",
+	"	x += NCORE * sizeof(void *);",
+	"	prcnt = (volatile int *) x;",
+	"	x += NCORE * sizeof(void *);",
+	"	prmax = (volatile int *) x;",
+	"	x += NCORE * sizeof(void *);",
+	"	gr_readmiss    = (volatile double *) x;",
+	"	x += sizeof(double);",
+	"	gr_writemiss    = (volatile double *) x;",
+	"	x += sizeof(double);",
+	"",
+	"	#ifdef FULL_TRAIL",
+	"		stack_last = (volatile Stack_Tree **) x;",
+	"		x += NCORE * sizeof(Stack_Tree *);",
+	"	#endif",
+	"",
+	"	#ifndef BITSTATE",
+	"		H_tab = (H_el **) emalloc(n);",
+	"	#endif",
+"#else",
+	"	#ifndef MEMLIM",
+	"		#warning MEMLIM not set", /* cannot happen */
+	"		#define MEMLIM	(2048)",
+	"	#endif",
+	"",
+	"	if (core_id == 0 && verbose)",
+	"	{	printf(\"cpu0: step 0: -DMEMLIM=%%d Mb minus hashtable+workqs (%%g + %%g Mb) leaves %%g Mb\\n\",",
+	"			MEMLIM, ((double)n/(1048576.)), (NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.),",
+	"			(memlim - memcnt - (double) n - (NCORE * LWQ_SIZE + GWQ_SIZE))/(1048576.));",
+	"	}",
+	"	#ifndef BITSTATE",
+	"		H_tab = (H_el **) prep_shmid_S((size_t) n);	/* hash_table */",
+	"	#endif",
+	"	need_mem = memlim - memcnt - ((double) NCORE * LWQ_SIZE) - GWQ_SIZE;",
+	"	if (need_mem <= 0.)",
+	"	{	Uerror(\"internal error -- shared state memory\");",
+	"	}",
+	"",
+	"	if (core_id == 0 && verbose)",
+	"	{	printf(\"cpu0: step 2: pre-allocate shared state memory %%g Mb\\n\",",
+	"			need_mem/(1048576.));",
+	"	}",
+	"#ifdef SEP_HEAP",
+	"	SEG_SIZE = need_mem / NCORE;",
+	"	if (verbose && core_id == 0)",
+	"	{	printf(\"cpu0: setting segsize to %%6g MB\\n\",",
+	"			SEG_SIZE/(1048576.));",
+	"	}",
+	"	#if defined(CYGWIN) || defined(__CYGWIN__)",
+	"	if (SEG_SIZE > 512.*1024.*1024.)",
+	"	{	printf(\"warning: reducing SEG_SIZE of %%g MB to 512MB (exceeds max for Cygwin)\\n\",",
+	"			SEG_SIZE/(1024.*1024.));",
+	"		SEG_SIZE = 512.*1024.*1024.;",
+	"	}",
+	"	#endif",
+	"#endif",
+	"	mem_reserved = need_mem;",
+	"	while (need_mem > 1024.)",
+	"	{	get_mem = need_mem;",
+	"shm_more:",
+	"		if (get_mem > (double) SEG_SIZE)",
+	"		{	get_mem = (double) SEG_SIZE;",
+	"		}",
+	"		if (get_mem <= 0.0) break;",
+	"",
+	"		/* for allocating states: */",
+	"		x = dc_mem_start = (volatile char *) prep_state_mem((size_t) get_mem);",
+	"		if (x == NULL)",
+	"		{	if (shm_prep_result == NOT_AGAIN",
+	"			||  first_pool != NULL",
+	"			||  SEG_SIZE < (16. * 1048576.))",
+	"			{	break;",
+	"			}",
+	"			SEG_SIZE /= 2.;",
+	"			if (verbose)",
+	"			{	printf(\"pan: lowered segsize to %%f\\n\", SEG_SIZE);",
+	"			}",
+	"			if (SEG_SIZE >= 1024.)",
+	"			{	goto shm_more;", /* always terminates */
+	"			}",
+	"			break;",
+	"		}",
+	"",
+	"		need_mem -= get_mem;",
+	"		got_mem  += get_mem;",
+	"		if (first_pool == NULL)",
+	"		{	search_terminated = (volatile unsigned int *) x; /* comes first */",
+	"			x += sizeof(void *); /* maintain alignment */",
+	"",
+	"			is_alive   = (volatile double *) x;",
+	"			x += NCORE * sizeof(double);",
+	"",
+	"			sh_lock   = (volatile int *) x;",
+	"			x += CS_NR * sizeof(void *);", /* allow 1 word per entry */
+	"",
+	"			grfree    = (volatile int *) x;",
+	"			x += sizeof(void *);",
+	"			grfull    = (volatile int *) x;",
+	"			x += sizeof(void *);",
+	"			grcnt    = (volatile int *) x;",
+	"			x += sizeof(void *);",
+	"			grmax    = (volatile int *) x;",
+	"			x += sizeof(void *);",
+	"			prfree = (volatile int *) x;",
+	"			x += NCORE * sizeof(void *);",
+	"			prfull = (volatile int *) x;",
+	"			x += NCORE * sizeof(void *);",
+	"			prcnt = (volatile int *) x;",
+	"			x += NCORE * sizeof(void *);",
+	"			prmax = (volatile int *) x;",
+	"			x += NCORE * sizeof(void *);",
+	"			gr_readmiss  = (volatile double *) x;",
+	"			x += sizeof(double);",
+	"			gr_writemiss = (volatile double *) x;",
+	"			x += sizeof(double);",
+	" #ifdef FULL_TRAIL",
+	"			stack_last = (volatile Stack_Tree **) x;",
+	"			x += NCORE * sizeof(Stack_Tree *);",
+	" #endif",
+	"			if (((long)x)&(sizeof(void *)-1)) /* 64-bit word alignment */",
+	"			{	x += sizeof(void *)-(((long)x)&(sizeof(void *)-1));",
+	"			}",
+	"",
+	"			#ifdef COLLAPSE",
+	"			ncomps = (unsigned long *) x;",
+	"			x += (256+2) * sizeof(unsigned long);",
+	"			#endif",
+	"		}",
+	"",
+	"		dc_shared = (sh_Allocater *) x; /* must be in shared memory */",
+	"		x += sizeof(sh_Allocater);",
+	"",
+	"		if (core_id == 0)	/* root only */",
+	"		{	dc_shared->dc_id     = shmid_M;",
+	"			dc_shared->dc_start  = dc_mem_start;",
+	"			dc_shared->dc_arena  = x;",
+	"			dc_shared->pattern   = 1234567; /* protection */",
+	"			dc_shared->dc_size   = (long) get_mem - (long) (x - dc_mem_start);",
+	"			dc_shared->nxt       = (long) 0;",
+	"",
+	"			if (last_pool == NULL)",
+	"			{	first_pool = last_pool = dc_shared;",
+	"			} else",
+	"			{	last_pool->nxt = dc_shared;",
+	"				last_pool = dc_shared;",
+	"			}",
+	"		} else if (first_pool == NULL)",
+	"		{	first_pool = dc_shared;",
+	"	}	}",
+	"",
+	"	if (need_mem > 1024.)",
+	"	{	printf(\"cpu0: could allocate only %%g Mb of shared memory (wanted %%g more)\\n\",",
+	"			got_mem/(1048576.), need_mem/(1048576.));",
+	"	}",
+	"",
+	"	if (!first_pool)",
+	"	{	printf(\"cpu0: insufficient memory -- aborting.\\n\");",
+	"		exit(1);",
+	"	}",
+	"	/* we are still single-threaded at this point, with core_id 0 */",
+	"	dc_shared = first_pool;",
+	"",
+"#endif", /* !SEP_STATE */
+	"}",
+	"",
+	"void",
+	"cleanup_shm(int val)",
+	"{	volatile sh_Allocater *nxt_pool;",
+	"	unsigned long cnt = 0;",
+	"	int m;",
+	"",
+	"	if (nibis != 0)",
+	"	{	printf(\"cpu%%d: Redundant call to cleanup_shm(%%d)\\n\", core_id, val);",
+	"		return;",
+	"	} else",
+	"	{	nibis = 1;",
+	"	}",
+	"	if (search_terminated != NULL)",
+	"	{	*search_terminated |= 16; /* cleanup_shm */",
+	"	}",
+	"",
+	"	for (m = 0; m < NR_QS; m++)",
+	"	{	if (shmdt((void *) shared_mem[m]) > 0)",
+	"		{	perror(\"shmdt detaching from shared queues\");",
+	"	}	}",
+	"",
+	"#ifdef SEP_STATE",
+	"	if (shmdt((void *) shmid_X) != 0)",
+	"	{	perror(\"shmdt detaching from shared state memory\");",
+	"	}",
+	"#else",
+	"	#ifdef BITSTATE",
+	"		if (SS > 0 && shmdt((void *) SS) != 0)",
+	"		{	if (verbose)",
+	"			{	perror(\"shmdt detaching from shared bitstate arena\");",
+	"		}	}",
+	"	#else",
+	"		if (core_id == 0)",
+	"		{	/* before detaching: */",
+	"			for (nxt_pool = dc_shared; nxt_pool != NULL; nxt_pool = nxt_pool->nxt)",
+	"			{	cnt += nxt_pool->dc_size;",
+	"			}",
+	"			if (verbose)",
+	"			{	printf(\"cpu0: done, %%ld Mb of shared state memory left\\n\",",
+	"					cnt / (long)(1048576));",
+	"		}	}",
+	"",
+	"		if (shmdt((void *) H_tab) != 0)",
+	"		{	perror(\"shmdt detaching from shared hashtable\");",
+	"		}",
+	"",
+	"		for (last_pool = first_pool; last_pool != NULL; last_pool = nxt_pool)",
+	"		{	nxt_pool = last_pool->nxt;",
+	"			if (shmdt((void *) last_pool->dc_start) != 0)",
+	"			{	perror(\"shmdt detaching from shared state memory\");",
+	"		}	}",
+	"		first_pool = last_pool = NULL;	/* precaution */",
+	"	#endif",
+	"#endif",
+	"	/* detached from shared memory - so cannot use cpu_printf */",
+	"	if (verbose)",
+	"	{	printf(\"cpu%%d: done -- got %%ld states from queue\\n\",",
+	"			core_id, nstates_get);",
+	"	}",
+	"}",
+	"",
+	"extern void give_up(int);",
+	"extern void Read_Queue(int);",
+	"",
+	"void",
+	"mem_get(void)",
+	"{	SM_frame   *f;",
+	"	int is_parent;",
+	"",
+	"#if defined(MA) && !defined(SEP_STATE)",
+	"	#error MA without SEP_STATE is not supported with multi-core",
+	"#endif",
+	"#ifdef BFS",
+	"	#error instead of -DNCORE -DBFS use -DBFS_PAR",
+	"#endif",
+	"#ifdef SC",
+	"	#error SC is not supported with multi-core",
+	"#endif",
+	"	init_shm();	/* we are single threaded when this starts */",
+	"",
+	"	if (core_id == 0 && verbose)",
+	"	{	printf(\"cpu0: step 4: calling fork()\\n\");",
+	"	}",
+	"	fflush(stdout);",
+	"",
+	"/*	if NCORE > 1 the child or the parent should fork N-1 more times",
+	" *	the parent is the only process with core_id == 0 and is_parent > 0",
+	" *	the workers have is_parent = 0 and core_id = 1..NCORE-1",
+	" */",
+	"	if (core_id == 0)",
+	"	{	worker_pids[0] = getpid();	/* for completeness */",
+	"		while (++core_id < NCORE)	/* first worker sees core_id = 1 */",
+	"		{	is_parent = fork();",
+	"			if (is_parent == -1)",
+	"			{	Uerror(\"fork failed\");",
+	"			}",
+	"			if (is_parent == 0)	/* this is a worker process */",
+	"			{	if (proxy_pid == core_id)	/* always non-zero */",
+	"				{	start_proxy(\"-r\", 0);	/* no return */",
+	"				}",
+	"				goto adapt;	/* root process continues spawning */",
+	"			}",
+	"			worker_pids[core_id] = is_parent;",
+	"		}",
+	"		/* note that core_id is now NCORE */",
+	"		if (proxy_pid > 0 && proxy_pid < NCORE)", /* add send-half of proxy */
+	"		{	proxy_pid_snd = fork();",
+	"			if (proxy_pid_snd == -1)",
+	"			{	Uerror(\"proxy fork failed\");",
+	"			}",
+	"			if (proxy_pid_snd == 0)",
+	"			{	start_proxy(\"-s\", worker_pids[proxy_pid]); /* no return */",
+	"		}	} /* else continue */",
+
+	"		if (is_parent > 0)",
+	"		{	core_id = 0;	/* reset core_id for root process */",
+	"		}",
+	"	} else	/* worker */",
+	"	{	static char db0[16];	/* good for up to 10^6 cores */",
+	"		static char db1[16];",
+	"adapt:		tprefix = db0; sprefix = db1;",
+	"		sprintf(tprefix, \"cpu%%d_trail\", core_id);",
+	"		sprintf(sprefix, \"cpu%%d_rst\", core_id);",
+	"		memcnt = 0;	/* count only additionally allocated memory */",
+	"	}",
+	"	signal(SIGINT, give_up);",
+	"",
+	"	if (proxy_pid == 0)		/* not in a cluster setup, pan_proxy must attach */",
+	"	{	rm_shared_segments();	/* mark all shared segments for removal on exit */",
+	"	}", /* doing it early means less chance of being unable to do this */
+	"	if (verbose)",
+	"	{	cpu_printf(\"starting core_id %%d -- pid %%d\\n\", core_id, getpid());",
+	"	}",
+
+	"#if defined(SEP_HEAP) && !defined(SEP_STATE)",	/* set my_heap and adjust dc_shared */
+	"	{	int i;",
+	"		volatile sh_Allocater *ptr;",
+	"		ptr = first_pool;",
+	"		for (i = 0; i < NCORE  && ptr != NULL; i++)",
+	"		{	if (i == core_id)",
+	"			{	my_heap = (char *) ptr->dc_arena;",
+	"				my_size = (long) ptr->dc_size;",
+	"				if (verbose)",
+	"				cpu_printf(\"local heap %%ld MB\\n\", my_size/(1048576));",
+	"				break;",
+	"			}",
+	"			ptr = ptr->nxt; /* local */",
+	"		}",
+	"		if (my_heap == NULL)",
+	"		{	printf(\"cpu%%d: no local heap\\n\", core_id);",
+	"			pan_exit(1);",
+	"		} /* else */",
+	"	#if defined(CYGWIN) || defined(__CYGWIN__)",
+	"		ptr = first_pool;",
+	"		for (i = 0; i < NCORE  && ptr != NULL; i++)",
+	"		{	ptr = ptr->nxt; /* local */",
+	"		}",
+	"		dc_shared = ptr; /* any remainder */",
+	"	#else",
+	"		dc_shared = NULL; /* used all mem for local heaps */",
+	"	#endif",
+	"	}",
+	"#endif",
+
+	"	if (core_id == 0 && !remote_party)",
+	"	{	new_state();		/* cpu0 explores root */",
+	"		if (verbose)",
+	"		cpu_printf(\"done with 1st dfs, nstates %%g (put %%d states), read q\\n\",",
+	"			nstates, nstates_put);",
+	"		dfs_phase2 = 1;",
+	"	}",
+	"	Read_Queue(core_id);	/* all cores */",
+	"",
+	"	if (verbose)",
+	"	{	cpu_printf(\"put %%6d states into queue -- got %%6d\\n\",",
+	"			nstates_put, nstates_get);",
+	"	}",
+	"	if (proxy_pid != 0)",
+	"	{	rm_shared_segments();",
+	"	}",
+	"	done = 1;",
+	"	wrapup();",
+	"	exit(0);",
+	"}",
+	"",
+	"#else",
+	"int unpack_state(SM_frame *, int);",
+	"#endif",
+	"",
+	"H_el *",
+	"grab_shared(int n)",
+	"{",
+	"#ifndef SEP_STATE",
+	"	char *rval = (char *) 0;",
+	"",
+	"	if (n == 0)",
+	"	{	printf(\"cpu%%d: grab shared zero\\n\", core_id); fflush(stdout);",
+	"		return (H_el *) rval;",
+	"	} else if (n&(sizeof(void *)-1))",
+	"	{	n += sizeof(void *)-(n&(sizeof(void *)-1)); /* alignment */",
+	"	}",
+	"",
+	"#ifdef SEP_HEAP",
+	"	/* no locking */",
+	"	if (my_heap != NULL && my_size > n)",
+	"	{	rval = my_heap;",
+	"		my_heap += n;",
+	"		my_size -= n;",
+	"		goto done;",
+	"	}",
+	"#endif",
+	"",
+	"	if (!dc_shared)",
+	"	{	sudden_stop(\"pan: out of memory\");",
+	"	}",
+	"",
+	"	/* another lock is always already in effect when this is called */",
+	"	/* but not always the same lock -- i.e., on different parts of the hashtable */",
+	"	enter_critical(GLOBAL_LOCK);	/* this must be independently mutex */",
+	"#if defined(SEP_HEAP) && !defined(WIN32) && !defined(WIN64)",
+	"	{	static int noted = 0;",
+	"		if (!noted)",
+	"		{	noted = 1;",
+	"			printf(\"cpu%%d: global heap has %%ld bytes left, needed %%d\\n\",",
+	"				core_id, dc_shared?dc_shared->dc_size:0, n);",
+	"	}	}",
+	"#endif",
+	"#if 0",	/* for debugging */
+	"		if (dc_shared->pattern != 1234567)",
+	"		{	leave_critical(GLOBAL_LOCK);",
+	"			Uerror(\"overrun -- memory corruption\");",
+	"		}",
+	"#endif",
+	"		if (dc_shared->dc_size < n)",
+	"		{	if (verbose)",
+	"			{ printf(\"Next Pool %%g Mb + %%d\\n\", memcnt/(1048576.), n);",
+	"			}",
+	"			if (dc_shared->nxt == NULL",
+	"			||  dc_shared->nxt->dc_arena == NULL",
+	"			||  dc_shared->nxt->dc_size < n)",
+	"			{	printf(\"cpu%%d: memcnt %%g Mb + wanted %%d bytes more\\n\",",
+	"					core_id, memcnt / (1048576.), n);",
+	"				leave_critical(GLOBAL_LOCK);",
+	"				sudden_stop(\"out of memory -- aborting\");",
+	"				wrapup();	/* exits */",
+	"			} else",
+	"			{	dc_shared = (sh_Allocater *) dc_shared->nxt;",
+	"		}	}",
+	"",
+	"		rval = (char *) dc_shared->dc_arena;",
+	"		dc_shared->dc_arena += n;",
+	"		dc_shared->dc_size  -= (long) n;",
+	"#if 0",
+	"		if (VVERBOSE)",
+	"		printf(\"cpu%%d grab shared (%%d bytes) -- %%ld left\\n\",",
+	"			core_id, n, dc_shared->dc_size);",
+	"#endif",
+	"	leave_critical(GLOBAL_LOCK);",
+	"done:",
+	"	memset(rval, 0, n);",
+	"	memcnt += (double) n;",
+	"",
+	"	return (H_el *) rval;",
+	"#else",
+	"	return (H_el *) emalloc(n);",
+	"#endif",
+	"}",
+	"",
+	"SM_frame *",
+	"Get_Full_Frame(int n)",
+	"{	SM_frame *f;",
+	"	double cnt_start = frame_wait;",
+	"",
+	"	f = &m_workq[n][prfull[n]];",
+	"	while (f->m_vsize == 0)	/* await full slot LOCK : full frame */",
+	"	{	iam_alive();",
+	"#ifndef NGQ",
+	"	#ifndef SAFETY",
+	"		if (!a_cycles || core_id != 0)",
+	"	#endif",
+	"		if (*grcnt > 0)	/* accessed outside lock, but safe even if wrong */",
+	"		{	enter_critical(GQ_RD);	/* gq - read access */",
+	"			if (*grcnt > 0)		/* could have changed */",
+	"			{	f = &m_workq[NCORE][*grfull];	/* global q */",
+	"				if (f->m_vsize == 0)",
+	"				{	/* writer is still filling the slot */",
+	"					*gr_writemiss++;",
+	"					f = &m_workq[n][prfull[n]]; /* reset */",
+	"				} else",
+	"				{	*grfull = (*grfull+1) %% (GN_FRAMES);",
+	"						enter_critical(GQ_WR);",
+	"						*grcnt = *grcnt - 1;",
+	"						leave_critical(GQ_WR);",
+	"					leave_critical(GQ_RD);",
+	"					return f;",
+	"			}	}",
+	"			leave_critical(GQ_RD);",
+	"		}",
+	"#endif",
+	"		if (frame_wait++ - cnt_start > Delay)",
+	"		{	if (0)", /* too frequent to enable this one */
+	"			{	cpu_printf(\"timeout on q%%d -- %%u -- query %%d\\n\",",
+	"					n, f, query_in_progress);",
+	"			}",
+	"			return (SM_frame *) 0;	/* timeout */",
+	"	}	}",
+	"	iam_alive();",
+	"	if (VVERBOSE) cpu_printf(\"got frame from q%%d\\n\", n);",
+	"	prfull[n] = (prfull[n] + 1) %% (LN_FRAMES);",
+	"	enter_critical(QLOCK(n));",
+	"		prcnt[n]--; /* lock out increments */",
+	"	leave_critical(QLOCK(n));",
+	"	return f;",
+	"}",
+	"",
+	"SM_frame *",
+	"Get_Free_Frame(int n)",
+	"{	SM_frame *f;",
+	"	double cnt_start = free_wait;",
+	"",
+	"	if (VVERBOSE) { cpu_printf(\"get free frame from q%%d\\n\", n); }",
+	"",
+	"	if (n == NCORE)	/* global q */",
+	"	{	f = &(m_workq[n][lrfree]);",
+	"	} else",
+	"	{	f = &(m_workq[n][prfree[n]]);",
+	"	}",
+	"	while (f->m_vsize != 0)	/* await free slot LOCK : free slot */",
+	"	{	iam_alive();",
+	"		if (free_wait++ - cnt_start > OneSecond)",
+	"		{	if (verbose)",
+	"			{	cpu_printf(\"timeout waiting for free slot q%%d\\n\", n);",
+	"			}",
+	"			cnt_start = free_wait;",
+	"			if (someone_crashed(1))",
+	"			{	printf(\"cpu%%d: search terminated\\n\", core_id);",
+	"				sudden_stop(\"get free frame\");",
+	"				pan_exit(1);",
+	"	}	}	}",
+	"	if (n != NCORE)",
+	"	{	prfree[n] = (prfree[n] + 1) %% (LN_FRAMES);",
+	"		enter_critical(QLOCK(n));",
+	"			prcnt[n]++; /* lock out decrements */",
+	"			if (prmax[n] < prcnt[n])",
+	"			{	prmax[n] = prcnt[n];",
+	"			}",
+	"		leave_critical(QLOCK(n));",
+	"	}",
+	"	return f;",
+	"}",
+	"",
+	"#ifndef NGQ",
+	"int",
+	"GlobalQ_HasRoom(void)",
+	"{	int rval = 0;",
+	"",
+	"	gq_tries++;",
+	"	if (*grcnt < GN_FRAMES) /* there seems to be room */",
+	"	{	enter_critical(GQ_WR);	/* gq write access */",
+	"		if (*grcnt < GN_FRAMES)",
+	"		{	if (m_workq[NCORE][*grfree].m_vsize != 0)",
+	"			{	/* can happen if reader is slow emptying slot */",
+	"				*gr_readmiss++;",
+	"				goto out; /* dont wait: release lock and return */",
+	"			}",
+	"			lrfree = *grfree;	/* Get_Free_Frame use lrfree in this mode */",
+	"			*grfree = (*grfree + 1) %% GN_FRAMES;",	/* next process looks at next slot */
+	"			*grcnt = *grcnt + 1;	/* count nr of slots filled -- no additional lock needed */",
+	"			if (*grmax < *grcnt) *grmax = *grcnt;",
+	"			leave_critical(GQ_WR);	/* for short lock duration */",
+	"			gq_hasroom++;",
+	"			mem_put(NCORE);		/* copy state into reserved slot */",
+	"			rval = 1;		/* successfull handoff */",
+	"		} else",
+	"		{	gq_hasnoroom++;",
+	"out:			leave_critical(GQ_WR);",	/* should be rare */
+	"	}	}",
+	"	return rval;",
+	"}",
+	"#endif",
+	"",
+	"int",
+	"unpack_state(SM_frame *f, int from_q)",
+	"{	int i, j;",
+	"	static H_el D_State;",
+	"",
+	"	if (f->m_vsize > 0)",
+	"	{	boq   = f->m_boq;",
+	"		if (boq > 256)",
+	"		{	cpu_printf(\"saw control %%d, expected state\\n\", boq);",
+	"			return 0;",
+	"		}",
+	"		vsize = f->m_vsize;",
+	"correct:",
+	"		memcpy((uchar *) &now, (uchar *) f->m_now, vsize);",
+	"	#if !defined(NOCOMP) && !defined(HC)",
+	"		for (i = j = 0; i < VMAX; i++, j = (j+1)%%8)",
+	"		{	Mask[i] = (f->m_mask[i/8] & (1<<j)) ? 1 : 0;",
+	"		}",
+	"	#endif",
+	"		if (now._nr_pr > 0)",
+	"		{	memcpy((uchar *) proc_offset, (uchar *) f->m_p_offset, now._nr_pr * sizeof(OFFT));",
+	"			memcpy((uchar *) proc_skip,   (uchar *) f->m_p_skip,   now._nr_pr * sizeof(uchar));",
+	"		}",
+	"		if (now._nr_qs > 0)",
+	"		{	memcpy((uchar *) q_offset,    (uchar *) f->m_q_offset, now._nr_qs * sizeof(OFFT));",
+	"			memcpy((uchar *) q_skip,      (uchar *) f->m_q_skip,   now._nr_qs * sizeof(uchar));",
+	"		}",
+	"#ifndef NOVSZ",
+	"		if (vsize != now._vsz)",
+	"		{	cpu_printf(\"vsize %%d != now._vsz %%d (type %%d) %%d\\n\",",
+	"				vsize, now._vsz, f->m_boq, f->m_vsize);",
+	"			vsize = now._vsz;",
+	"			goto correct;	/* rare event: a race */",
+	"		}",
+	"#endif",
+	"		hmax = max(hmax, vsize);",
+	"",
+	"		if (f != &cur_Root)",
+	"		{	memcpy((uchar *) &cur_Root, (uchar *) f, sizeof(SM_frame));",
+	"		}",
+	"",
+	"		if (((now._a_t) & 1) == 1)	/* i.e., when starting nested DFS */",
+	"		{	A_depth = depthfound = 0;",
+	"			memcpy((uchar *)&A_Root, (uchar *)&now, vsize);",
+	"		}",
+	"		nr_handoffs = f->nr_handoffs;",
+	"	} else",
+	"	{	cpu_printf(\"pan: state empty\\n\");",
+	"	}",
+	"",
+	"	depth = 0;",
+	"	trpt = &trail[1];",
+	"	trpt->tau    = f->m_tau;",
+	"	trpt->o_pm   = f->m_o_pm;",
+	"",
+	"	(trpt-1)->ostate = &D_State; /* stub */",
+	"	trpt->ostate = &D_State;",
+	"",
+	"#ifdef FULL_TRAIL",
+	"	if (upto > 0)",
+	"	{	stack_last[core_id] = (Stack_Tree *) f->m_stack;",
+	"	}",
+	"	#if defined(VERBOSE)",
+	"	if (stack_last[core_id])",
+	"	{	cpu_printf(\"%%d: UNPACK -- SET m_stack %%u (%%d,%%d)\\n\",",
+	"			depth, stack_last[core_id], stack_last[core_id]->pr,",
+	"			stack_last[core_id]->t_id);",
+	"	}",
+	"	#endif",
+	"#endif",
+	"",
+	"	if (!trpt->o_t)",
+	"	{	static Trans D_Trans;",
+	"		trpt->o_t = &D_Trans;",
+	"	}",
+	"",
+	"	#ifdef VERI",
+	"	if ((trpt->tau & 4) != 4)",
+	"	{	trpt->tau |= 4;	/* the claim moves first */",
+	"		cpu_printf(\"warning: trpt was not up to date\\n\");",
+	"	}",
+	"	#endif",
+	"",
+	"	for (i = 0; i < (int) now._nr_pr; i++)",
+	"	{	P0 *ptr = (P0 *) pptr(i);",
+	"	#ifndef NP",
+	"		if (accpstate[ptr->_t][ptr->_p])",
+	"		{	trpt->o_pm |= 2;",
+	"		}",
+	"	#else",
+	"		if (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",
+	"",
+	"	#if defined(C_States) && (HAS_TRACK==1)",
+	"		/* restore state of tracked C objects */",
+	"		c_revert((uchar *) &(now.c_state[0]));",
+	"		#if (HAS_STACK==1)",
+	"		c_unstack((uchar *) f->m_c_stack); /* unmatched tracked data */",
+	"		#endif",
+	"	#endif",
+	"	return 1;",
+	"}",
+	"",
+	"void",
+	"write_root(void)	/* for trail file */",
+	"{	int fd;",
+	"",
+	"	if (iterative == 0 && Nr_Trails > 1)",
+	"		sprintf(fnm, \"%%s%%d.%%s\", TrailFile, Nr_Trails-1, sprefix);",
+	"	else",
+	"		sprintf(fnm, \"%%s.%%s\", TrailFile, sprefix);",
+	"",
+	"	if (cur_Root.m_vsize == 0)",
+	"	{	(void) unlink(fnm); /* remove possible old copy */",
+	"		return;	/* its the default initial state */",
+	"	}",
+	"",
+	"	if ((fd = creat(fnm, TMODE)) < 0)",
+	"	{	char *q;",
+	"		if ((q = strchr(TrailFile, \'.\')))",
+	"		{	*q = \'\\0\';		/* strip .pml */",
+	"			if (iterative == 0 && Nr_Trails-1 > 0)",
+	"				sprintf(fnm, \"%%s%%d.%%s\", TrailFile, Nr_Trails-1, sprefix);",
+	"			else",
+	"				sprintf(fnm, \"%%s.%%s\", TrailFile, sprefix);",
+	"			*q = \'.\';",
+	"			fd = creat(fnm, TMODE);",
+	"		}",
+	"		if (fd < 0)",
+	"		{	cpu_printf(\"pan: cannot create %%s\\n\", fnm);",
+	"			perror(\"cause\");",
+	"			return;",
+	"	}	}",
+	"",
+	"	if (write(fd, &cur_Root, sizeof(SM_frame)) != sizeof(SM_frame))",
+	"	{	cpu_printf(\"pan: error writing %%s\\n\", fnm);",
+	"	} else",
+	"	{	cpu_printf(\"pan: wrote %%s\\n\", fnm);",
+	"	}",
+	"	close(fd);",
+	"}",
+	"",
+	"void",
+	"set_root(void)",
+	"{	int fd;",
+	"	char *q;",
+	"	char MyFile[512];",	/* enough to hold a reasonable pathname */
+	"	char MySuffix[16];",
+	"	char *ssuffix = \"rst\";",
+	"	int  try_core = 1;",
+	"",
+	"	strcpy(MyFile, TrailFile);",
+	"try_again:",
+	"	if (whichtrail > 0)",
+	"	{	sprintf(fnm, \"%%s%%d.%%s\", MyFile, whichtrail, ssuffix);",
+	"		fd = open(fnm, O_RDONLY, 0);",
+	"		if (fd < 0 && (q = strchr(MyFile, \'.\')))",
+	"		{	*q = \'\\0\';	/* strip .pml */",
+	"			sprintf(fnm, \"%%s%%d.%%s\", MyFile, whichtrail, ssuffix);",
+	"			*q = \'.\';",
+	"			fd = open(fnm, O_RDONLY, 0);",
+	"		}",
+	"	} else",
+	"	{	sprintf(fnm, \"%%s.%%s\", MyFile, ssuffix);",
+	"		fd = open(fnm, O_RDONLY, 0);",
+	"		if (fd < 0 && (q = strchr(MyFile, \'.\')))",
+	"		{	*q = \'\\0\';	/* strip .pml */",
+	"			sprintf(fnm, \"%%s.%%s\", MyFile, ssuffix);",
+	"			*q = \'.\';",
+	"			fd = open(fnm, O_RDONLY, 0);",
+	"	}	}",
+	"",
+	"	if (fd < 0)",
+	"	{	if (try_core < NCORE)",
+	"		{	ssuffix = MySuffix;",
+	"			sprintf(ssuffix, \"cpu%%d_rst\", try_core++);",
+	"			goto try_again;",
+	"		}",
+	"		cpu_printf(\"no file '%%s.rst' or '%%s' (not an error)\\n\", MyFile, fnm);",
+	"	} else",
+	"	{	if (read(fd, &cur_Root, sizeof(SM_frame)) != sizeof(SM_frame))",
+	"		{	cpu_printf(\"read error %%s\\n\", fnm);",
+	"			close(fd);",
+	"			pan_exit(1);",
+	"		}",
+	"		close(fd);",
+	"		(void) unpack_state(&cur_Root, -2);",
+	"#ifdef SEP_STATE",
+	"		cpu_printf(\"partial trail -- last few steps only\\n\");",
+	"#endif",
+	"		cpu_printf(\"restored root from '%%s'\\n\", fnm);",
+	"		printf(\"=====State:=====\\n\");",
+	"		{	int i, j; P0 *z;",
+	"			for (i = 0; i < now._nr_pr; i++)",
+	"			{	z = (P0 *)pptr(i);",
+	"				printf(\"proc %%2d (%%s) \", i, procname[z->_t]);",
+
+	"				for (j = 0; src_all[j].src; j++)",
+	"				if (src_all[j].tp == (int) z->_t)",
+	"				{	printf(\" %%s:%%d \",",
+	"						PanSource, src_all[j].src[z->_p]);",
+	"					break;",
+	"				}",
+	"				printf(\"(state %%d)\\n\", z->_p);",
+	"				c_locals(i, z->_t);",
+	"			}",
+	"			c_globals();",
+	"		}",
+	"		printf(\"================\\n\");",
+	"	}",
+	"}",
+	"",
+	"#ifdef USE_DISK",
+	"unsigned long dsk_written, dsk_drained;",
+	"void mem_drain(void);",
+	"#endif",
+	"",
+	"void",
+	"m_clear_frame(SM_frame *f)", /* clear room for stats */
+	"{	int i, clr_sz = sizeof(SM_results);",
+	"",
+	"	for (i = 0; i <= _NP_; i++)	/* all proctypes */",
+	"	{	clr_sz += NrStates[i]*sizeof(uchar);",
+	"	}",
+	"	memset(f, 0, clr_sz);",
+	"	/* caution if sizeof(SM_results) > sizeof(SM_frame) */",
+	"}",
+	"",
+	"#define TargetQ_Full(n)	(m_workq[n][prfree[n]].m_vsize != 0)", /* no free slot */
+	"#define TargetQ_NotFull(n)	(m_workq[n][prfree[n]].m_vsize == 0)", /* avoiding prcnt */
+	"",
+	"int",
+	"AllQueuesEmpty(void)",
+	"{	int q;",
+	"#ifndef NGQ",
+	"	if (*grcnt != 0)",
+	"	{	return 0;",
+	"	}",
+	"#endif",
+	"	for (q = 0; q < NCORE; q++)",
+	"	{	if (prcnt[q] != 0)", /* not locked, ok if race */
+	"		{	return 0;",
+	"	}	}",
+	"	return 1;",
+	"}",
+	"",
+	"void",
+	"Read_Queue(int q)",
+	"{	SM_frame   *f, *of;",
+	"	int	remember, target_q;",
+	"	SM_results *r;",
+	"	double patience = 0.0;",
+	"",
+	"	target_q = (q + 1) %% NCORE;",
+	"",
+	"	for (;;)",
+	"	{	f = Get_Full_Frame(q);",
+	"		if (!f)	/* 1 second timeout -- and trigger for Query */",
+	"		{	if (someone_crashed(2))",
+	"			{	printf(\"cpu%%d: search terminated [code %%d]\\n\",",
+	"					core_id, search_terminated?*search_terminated:-1);",
+	"				sudden_stop(\"\");",
+	"				pan_exit(1);",
+	"			}",
+	"#ifdef TESTING",
+	"	/* to profile with cc -pg and gprof pan.exe -- set handoff depth beyond maxdepth */",
+	"			exit(0);",
+	"#endif",
+	"			remember = *grfree;",
+	"			if (core_id == 0		/* root can initiate termination */",
+	"			&& remote_party == 0		/* and only the original root */",
+	"			&& query_in_progress == 0	/* unless its already in progress */",
+	"			&& AllQueuesEmpty())",
+	"			{	f = Get_Free_Frame(target_q);",
+	"				query_in_progress = 1;	/* only root process can do this */",
+	"				if (!f) { Uerror(\"Fatal1: no free slot\"); }",
+	"				f->m_boq = QUERY;	/* initiate Query */",
+	"				if (verbose)",
+	"				{  cpu_printf(\"snd QUERY to q%%d (%%d) into slot %%d\\n\",",
+	"					target_q, nstates_get + 1, prfree[target_q]-1);",
+	"				}",
+	"				f->m_vsize = remember + 1;",
+	"				/* number will not change unless we receive more states */",
+	"			} else if (patience++ > OneHour) /* one hour watchdog timer */",
+	"			{	cpu_printf(\"timeout -- giving up\\n\");",
+	"				sudden_stop(\"queue timeout\");",
+	"				pan_exit(1);",
+	"			}",
+	"			if (0) cpu_printf(\"timed out -- try again\\n\");",
+	"			continue;	",
+	"		}",
+	"		patience = 0.0; /* reset watchdog */",
+	"",
+	"		if (f->m_boq == QUERY)",
+	"		{	if (verbose)",
+	"			{	cpu_printf(\"got QUERY on q%%d (%%d <> %%d) from slot %%d\\n\",",
+	"					q, f->m_vsize, nstates_put + 1, prfull[q]-1);",
+	"				snapshot();",
+	"			}",
+	"			remember = f->m_vsize;",
+	"			f->m_vsize = 0;	/* release slot */",
+	"",
+	"			if (core_id == 0 && remote_party == 0)	/* original root cpu0 */",
+	"			{	if (query_in_progress == 1	/* didn't send more states in the interim */",
+	"				&&  *grfree + 1 == remember)	/* no action on global queue meanwhile */",
+	"				{	if (verbose) cpu_printf(\"Termination detected\\n\");",
+	"					if (TargetQ_Full(target_q))",
+	"					{	if (verbose)",
+	"						cpu_printf(\"warning: target q is full\\n\");",
+	"					}",
+	"					f = Get_Free_Frame(target_q);",
+	"					if (!f) { Uerror(\"Fatal2: no free slot\"); }",
+	"					m_clear_frame(f);",
+	"					f->m_boq = QUIT; /* send final Quit, collect stats */",
+	"					f->m_vsize = 111; /* anything non-zero will do */",
+	"					if (verbose)",
+	"					cpu_printf(\"put QUIT on q%%d\\n\", target_q);",
+	"				} else",
+	"				{	if (verbose) cpu_printf(\"Stale Query\\n\");",
+	"#ifdef USE_DISK",
+	"					mem_drain();",
+	"#endif",
+	"				}",
+	"				query_in_progress = 0;",
+	"			} else",
+	"			{	if (TargetQ_Full(target_q))",
+	"				{	if (verbose)",
+	"					cpu_printf(\"warning: forward query - target q full\\n\");",
+	"				}",
+	"				f = Get_Free_Frame(target_q);",
+	"				if (verbose)",
+	"				cpu_printf(\"snd QUERY response to q%%d (%%d <> %%d) in slot %%d\\n\",",
+	"					target_q, remember, *grfree + 1, prfree[target_q]-1);",
+	"				if (!f) { Uerror(\"Fatal4: no free slot\"); }",
+	"",
+	"				if (*grfree + 1 == remember)	/* no action on global queue */",
+	"				{	f->m_boq = QUERY;	/* forward query, to root */",
+	"					f->m_vsize = remember;",
+	"				} else",
+	"				{	f->m_boq = QUERY_F;	/* no match -- busy */",
+	"					f->m_vsize = 112;	/* anything non-zero */",
+	"#ifdef USE_DISK",
+	"					if (dsk_written != dsk_drained)",
+	"					{	mem_drain();",
+	"					}",
+	"#endif",
+	"			}	}",
+	"			continue;",
+	"		}",
+	"",
+	"		if (f->m_boq == QUERY_F)",
+	"		{	if (verbose)",
+	"			{	cpu_printf(\"got QUERY_F on q%%d from slot %%d\\n\", q, prfull[q]-1);",
+	"			}",
+	"			f->m_vsize = 0;	/* release slot */",
+	"",
+	"			if (core_id == 0 && remote_party == 0)		/* original root cpu0 */",
+	"			{	if (verbose) cpu_printf(\"No Match on Query\\n\");",
+	"				query_in_progress = 0;",
+	"			} else",
+	"			{	if (TargetQ_Full(target_q))",
+	"				{	if (verbose) cpu_printf(\"warning: forwarding query_f, target queue full\\n\");",
+	"				}",
+	"				f = Get_Free_Frame(target_q);",
+	"				if (verbose) cpu_printf(\"forward QUERY_F to q%%d into slot %%d\\n\",",
+	"						target_q, prfree[target_q]-1);",
+	"				if (!f) { Uerror(\"Fatal5: no free slot\"); }",
+	"				f->m_boq = QUERY_F;		/* cannot terminate yet */",
+	"				f->m_vsize = 113;		/* anything non-zero */",
+	"			}",
+	"#ifdef USE_DISK",
+	"			if (dsk_written != dsk_drained)",
+	"			{	mem_drain();",
+	"			}",
+	"#endif",
+	"			continue;",
+	"		}",
+	"",
+	"		if (f->m_boq == QUIT)",
+	"		{	if (0) cpu_printf(\"done -- local memcnt %%g Mb\\n\", memcnt/(1048576.));",
+	"			retrieve_info((SM_results *) f); /* collect and combine stats */",
+	"			if (verbose)",
+	"			{	cpu_printf(\"received Quit\\n\");",
+	"				snapshot();",
+	"			}",
+	"			f->m_vsize = 0;	/* release incoming slot */",
+	"			if (core_id != 0)",
+	"			{	f = Get_Free_Frame(target_q); /* new outgoing slot */",
+	"				if (!f) { Uerror(\"Fatal6: no free slot\"); }",
+	"				m_clear_frame(f);	/* start with zeroed stats */",
+	"				record_info((SM_results *) f);",
+	"				f->m_boq = QUIT;	/* forward combined results */",
+	"				f->m_vsize = 114;	/* anything non-zero */",
+	"				if (verbose>1)",
+	"				cpu_printf(\"fwd Results to q%%d\\n\", target_q);",
+	"			}",
+	"			break;			/* successful termination */",
+	"		}",
+	"",
+	"		/* else: 0<= boq <= 255, means STATE transfer */",
+	"		if (unpack_state(f, q) != 0)",
+	"		{	nstates_get++;",
+	"			f->m_vsize = 0;	/* release slot */",
+	"			if (VVERBOSE) cpu_printf(\"Got state\\n\");",
+	"",
+	"			if (search_terminated != NULL",
+	"			&&  *search_terminated == 0)",
+	"			{	new_state();	/* explore successors */",
+	"				memset((uchar *) &cur_Root, 0, sizeof(SM_frame));	/* avoid confusion */",
+	"			} else",
+	"			{	pan_exit(0);",
+	"			}",
+	"		} else",
+	"		{	pan_exit(0);",
+	"	}	}",
+	"	if (verbose) cpu_printf(\"done got %%d put %%d\\n\", nstates_get, nstates_put);",
+	"	sleep_report();",
+	"}",
+	"",
+	"void",
+	"give_up(int unused_x)",
+	"{",
+	"	if (search_terminated != NULL)",
+	"	{	*search_terminated |= 32;	/* give_up */",
+	"	}",
+	"	if (!writing_trail)",
+	"	{	was_interrupted = 1;",
+	"		snapshot();",
+	"		cpu_printf(\"Give Up\\n\");",
+	"		sleep_report();",
+	"		pan_exit(1);",
+	"	} else /* we are already terminating */",
+	"	{	cpu_printf(\"SIGINT\\n\");",
+	"	}",
+	"}",
+	"",
+	"void",
+	"check_overkill(void)",
+	"{",
+	"	vmax_seen = (vmax_seen + 7)/ 8;",
+	"	vmax_seen *= 8;	/* round up to a multiple of 8 */",
+	"",
+	"	if (core_id == 0",
+	"	&&  !remote_party",
+	"	&&  nstates_put > 0",
+	"	&&  VMAX - vmax_seen > 8)",
+	"	{",
+	"#ifdef BITSTATE",
+	"		printf(\"cpu0: max VMAX value seen in this run: \");",
+	"#else",
+	"		printf(\"cpu0: recommend recompiling with \");",
+	"#endif",
+	"		printf(\"-DVMAX=%%d\\n\", vmax_seen);",
+	"	}",
+	"}",
+	"",
+	"void",
+	"mem_put(int q)	/* handoff state to other cpu, workq q */",
+	"{	SM_frame *f;",
+	"	int i, j;",
+	"",
+	"	if (vsize > VMAX)",
+	"	{	vsize = (vsize + 7)/8; vsize *= 8; /* round up */",
+	"		printf(\"pan: recompile with -DVMAX=N with N >= %%d\\n\", (int) vsize);",
+	"		Uerror(\"aborting\");",
+	"	}",
+	"	if (now._nr_pr > PMAX)",
+	"	{	printf(\"pan: recompile with -DPMAX=N with N >= %%d\\n\", now._nr_pr);",
+	"		Uerror(\"aborting\");",
+	"	}",
+	"	if (now._nr_qs > QMAX)",
+	"	{	printf(\"pan: recompile with -DQMAX=N with N >= %%d\\n\", now._nr_qs);",
+	"		Uerror(\"aborting\");",
+	"	}",
+	"	if (vsize > vmax_seen) vmax_seen = vsize;",
+	"	if (now._nr_pr > pmax_seen) pmax_seen = now._nr_pr;",
+	"	if (now._nr_qs > qmax_seen) qmax_seen = now._nr_qs;",
+	"",
+	"	f = Get_Free_Frame(q);	/* not called in likely deadlock states */",
+	"	if (!f) { Uerror(\"Fatal3: no free slot\"); }",
+	"",
+	"	if (VVERBOSE) cpu_printf(\"putting state into q%%d\\n\", q);",
+	"",
+	"	memcpy((uchar *) f->m_now,  (uchar *) &now, vsize);",
+	"#if !defined(NOCOMP) && !defined(HC)",
+	"	memset((uchar *) f->m_mask, 0, (VMAX+7)/8 * sizeof(char));",
+	"	for (i = j = 0; i < VMAX; i++, j = (j+1)%%8)",
+	"	{	if (Mask[i])",
+	"		{	f->m_mask[i/8] |= (1<<j);",
+	"	}	}",
+	"#endif",
+	"	if (now._nr_pr > 0)",
+	"	{ memcpy((uchar *) f->m_p_offset, (uchar *) proc_offset, now._nr_pr * sizeof(OFFT));",
+	"	  memcpy((uchar *) f->m_p_skip,   (uchar *) proc_skip,   now._nr_pr * sizeof(uchar));",
+	"	}",
+	"	if (now._nr_qs > 0)",
+	"	{ memcpy((uchar *) f->m_q_offset, (uchar *) q_offset, now._nr_qs * sizeof(OFFT));",
+	"	  memcpy((uchar *) f->m_q_skip,   (uchar *) q_skip,   now._nr_qs * sizeof(uchar));",
+	"	}",
+	"#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)",
+	"	c_stack((uchar *) f->m_c_stack); /* save unmatched tracked data */",
+	"#endif",
+	"#ifdef FULL_TRAIL",
+	"	f->m_stack = stack_last[core_id];",
+	"#endif",
+	"	f->nr_handoffs = nr_handoffs+1;",
+	"	f->m_tau    = trpt->tau;",
+	"	f->m_o_pm   = trpt->o_pm;",
+	"	f->m_boq    = boq;",
+	"	f->m_vsize  = vsize;	/* must come last - now the other cpu can see it */",
+	"",
+	"	if (query_in_progress == 1)",
+	"		query_in_progress = 2;	/* make sure we know, if a query makes the rounds */",
+	"	nstates_put++;",
+	"}",
+	"",
+	"#ifdef USE_DISK",
+	"int Dsk_W_Nr, Dsk_R_Nr;",
+	"int dsk_file = -1, dsk_read = -1;",
+	"unsigned long dsk_written, dsk_drained;",
+	"char dsk_name[512];",
+	"",
+	"#ifndef BFS_DISK",
+	"#if defined(WIN32) || defined(WIN64)",
+	"	#define RFLAGS	(O_RDONLY|O_BINARY)",
+	"	#define WFLAGS	(O_CREAT|O_WRONLY|O_TRUNC|O_BINARY)",
+	"#else",
+	"	#define RFLAGS	(O_RDONLY)",
+	"	#define WFLAGS	(O_CREAT|O_WRONLY|O_TRUNC)",
+	"#endif",
+	"#endif",
+	"",
+	"void",
+	"dsk_stats(void)",
+	"{	int i;",
+	"",
+	"	if (dsk_written > 0)",
+	"	{	cpu_printf(\"dsk_written %%d states in %%d files\\ncpu%%d: dsk_drained %%6d states\\n\",",
+	"			dsk_written, Dsk_W_Nr, core_id, dsk_drained);",
+	"		close(dsk_read);",
+	"		close(dsk_file);",
+	"		for (i = 0; i < Dsk_W_Nr; i++)",
+	"		{	sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", i, core_id);",
+	"			unlink(dsk_name);",
+	"	}	}",
+	"}",
+	"",
+	"void",
+	"mem_drain(void)",
+	"{	SM_frame *f, g;",
+	"	int q = (core_id + 1) %% NCORE;	/* target q */",
+	"	int sz;",
+	"",
+	"	if (dsk_read < 0",
+	"	||  dsk_written <= dsk_drained)",
+	"	{	return;",
+	"	}",
+	"",
+	"	while (dsk_written > dsk_drained",
+	"	&& TargetQ_NotFull(q))",
+	"	{	f = Get_Free_Frame(q);",
+	"		if (!f) { Uerror(\"Fatal: unhandled condition\"); }",
+	"",
+	"		if ((dsk_drained+1)%%MAX_DSK_FILE == 0)	/* 100K states max per file */",
+	"		{	(void) close(dsk_read); 	/* close current read handle */",
+	"			sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_R_Nr++, core_id);",
+	"			(void) unlink(dsk_name);	/* remove current file */",
+	"			sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_R_Nr, core_id);",
+	"			cpu_printf(\"reading %%s\\n\", dsk_name);",
+	"			dsk_read = open(dsk_name, RFLAGS); /* open next file */",
+	"			if (dsk_read < 0)",
+	"			{	Uerror(\"could not open dsk file\");",
+	"		}	}",
+	"		if (read(dsk_read, &g, sizeof(SM_frame)) != sizeof(SM_frame))",
+	"		{	Uerror(\"bad dsk file read\");",
+	"		}",
+	"		sz = g.m_vsize;",
+	"		g.m_vsize = 0;",
+	"		memcpy(f, &g, sizeof(SM_frame));",
+	"		f->m_vsize = sz;	/* last */",
+	"",
+	"		dsk_drained++;",
+	"	}",
+	"}",
+	"",
+	"void",
+	"mem_file(void)",
+	"{	SM_frame f;",
+	"	int i, j, q = (core_id + 1) %% NCORE;	/* target q */",
+	"",
+	"	if (vsize > VMAX)",
+	"	{	printf(\"pan: recompile with -DVMAX=N with N >= %%d\\n\", vsize);",
+	"		Uerror(\"aborting\");",
+	"	}",
+	"	if (now._nr_pr > PMAX)",
+	"	{	printf(\"pan: recompile with -DPMAX=N with N >= %%d\\n\", now._nr_pr);",
+	"		Uerror(\"aborting\");",
+	"	}",
+	"	if (now._nr_qs > QMAX)",
+	"	{	printf(\"pan: recompile with -DQMAX=N with N >= %%d\\n\", now._nr_qs);",
+	"		Uerror(\"aborting\");",
+	"	}",
+	"",
+	"	if (VVERBOSE) cpu_printf(\"filing state for q%%d\\n\", q);",
+	"",
+	"	memcpy((uchar *) f.m_now,  (uchar *) &now, vsize);",
+	"#if !defined(NOCOMP) && !defined(HC)",
+	"	memset((uchar *) f.m_mask, 0, (VMAX+7)/8 * sizeof(char));",
+	"	for (i = j = 0; i < VMAX; i++, j = (j+1)%%8)",
+	"	{	if (Mask[i])",
+	"		{	f.m_mask[i/8] |= (1<<j);",
+	"	}	}",
+	"#endif",
+	"	if (now._nr_pr > 0)",
+	"	{	memcpy((uchar *)f.m_p_offset, (uchar *)proc_offset, now._nr_pr*sizeof(OFFT));",
+	"		memcpy((uchar *)f.m_p_skip,   (uchar *)proc_skip,   now._nr_pr*sizeof(uchar));",
+	"	}",
+	"	if (now._nr_qs > 0)",
+	"	{	memcpy((uchar *) f.m_q_offset, (uchar *) q_offset, now._nr_qs*sizeof(OFFT));",
+	"		memcpy((uchar *) f.m_q_skip,   (uchar *) q_skip,   now._nr_qs*sizeof(uchar));",
+	"	}",
+	"#if defined(C_States) && (HAS_TRACK==1) && (HAS_STACK==1)",
+	"	c_stack((uchar *) f.m_c_stack); /* save unmatched tracked data */",
+	"#endif",
+	"#ifdef FULL_TRAIL",
+	"	f.m_stack  = stack_last[core_id];",
+	"#endif",
+	"	f.nr_handoffs = nr_handoffs+1;",
+	"	f.m_tau    = trpt->tau;",
+	"	f.m_o_pm   = trpt->o_pm;",
+	"	f.m_boq    = boq;",
+	"	f.m_vsize  = vsize;",
+	"",
+	"	if (query_in_progress == 1)",
+	"	{	query_in_progress = 2;",
+	"	}",
+	"	if (dsk_file < 0)",
+	"	{	sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_W_Nr, core_id);",
+	"		dsk_file = open(dsk_name, WFLAGS, 0644);",
+	"		dsk_read = open(dsk_name, RFLAGS);",
+	"		if (dsk_file < 0 || dsk_read < 0)",
+	"		{	cpu_printf(\"File: <%%s>\\n\", dsk_name);",
+	"			Uerror(\"cannot open diskfile\");",
+	"		}",
+	"		Dsk_W_Nr++; /* nr of next file to open */",
+	"		cpu_printf(\"created temporary diskfile %%s\\n\", dsk_name);",
+	"	} else if ((dsk_written+1)%%MAX_DSK_FILE == 0)",
+	"	{	close(dsk_file); /* close write handle */",
+	"		sprintf(dsk_name, \"Q%%.3d_%%.3d.tmp\", Dsk_W_Nr++, core_id);",
+	"		dsk_file = open(dsk_name, WFLAGS, 0644);",
+	"		if (dsk_file < 0)",
+	"		{	cpu_printf(\"File: <%%s>\\n\", dsk_name);",
+	"			Uerror(\"aborting: cannot open new diskfile\");",
+	"		}",
+	"		cpu_printf(\"created temporary diskfile %%s\\n\", dsk_name);",
+	"	}",
+	"	if (write(dsk_file, &f, sizeof(SM_frame)) != sizeof(SM_frame))",
+	"	{	Uerror(\"aborting -- disk write failed (disk full?)\");",
+	"	}",
+	"	nstates_put++;",
+	"	dsk_written++;",
+	"}",
+	"#endif",
+	"",
+	"int",
+	"mem_hand_off(void)",
+	"{",
+	"	if (search_terminated == NULL",
+	"	||  *search_terminated != 0)	/* not a full crash check */",
+	"	{	pan_exit(0);",
+	"	}",
+	"	iam_alive();		/* on every transition of Down */",
+	"#ifdef USE_DISK",
+	"	mem_drain();		/* maybe call this also on every Up */",
+	"#endif",
+	"	if (depth > z_handoff	/* above handoff limit */",
+	"#ifndef SAFETY",
+	"	&&  !a_cycles		/* not in liveness mode */",
+	"#endif",
+	"#if SYNC",
+	"	&&  boq == -1		/* not mid-rv */",
+	"#endif",
+	"#ifdef VERI",
+	"	&&  (trpt->tau&4)	 /* claim moves first  */",
+	"	&&  !((trpt-1)->tau&128) /* not a stutter move */",
+	"#endif",
+	"	&&  !(trpt->tau&8))	/* not an atomic move */",
+	"	{	int q = (core_id + 1) %% NCORE;	/* circular handoff */",
+	"	#ifdef GENEROUS",
+	"		if (prcnt[q] < LN_FRAMES)", /* not the best strategy */
+	"	#else",
+	"		if (TargetQ_NotFull(q)",
+	"		&& (dfs_phase2 == 0 || prcnt[core_id] > 0))", /* not locked, ok if race */
+	"	#endif",
+	"		{	mem_put(q);",	/* only 1 writer: lock-free */
+	"			return 1;",
+	"		}",
+	"		{	int rval;",
+	"	#ifndef NGQ",
+	"			rval = GlobalQ_HasRoom();",
+	"	#else",
+	"			rval = 0;",
+	"	#endif",
+	"	#ifdef USE_DISK",
+	"			if (rval == 0)",
+	"			{	void mem_file(void);",
+	"				mem_file();",
+	"				rval = 1;",
+	"			}",
+	"	#endif",
+	"			return rval;",
+	"		}",
+	"	}",
+	"	return 0; /* i.e., no handoff */",
+	"}",
+	"",
+	"void",
+	"mem_put_acc(void)	/* liveness mode */",
+	"{	int q = (core_id + 1) %% NCORE;",
+	"",
+	"	if (search_terminated == NULL",
+	"	||  *search_terminated != 0)",
+	"	{	pan_exit(0);",
+	"	}",
+	"#ifdef USE_DISK",
+	"	mem_drain();",
+	"#endif",
+	"	/* some tortured use of preprocessing: */",
+	"#if !defined(NGQ) || defined(USE_DISK)",
+	"	if (TargetQ_Full(q))",
+	"	{",
+	"#endif",
+	"#ifndef NGQ",
+	"		if (GlobalQ_HasRoom())",
+	"		{	return;",
+	"		}",
+	"#endif",
+	"#ifdef USE_DISK",
+	"		mem_file();",
+	"	} else",
+	"#else",
+	"	#if !defined(NGQ) || defined(USE_DISK)",
+	"	}",
+	"	#endif",
+	"#endif",
+	"	{	mem_put(q);",
+	"	}",
+	"}",
+	"",
+	"#if defined(WIN32) || defined(WIN64)", /* visual studio */
+	"void",
+	"init_shm(void)		/* initialize shared work-queues */",
+	"{	char	key[512];",
+	"	int	n, m;",
+	"	int	must_exit = 0;",
+	"",
+	"	if (core_id == 0 && verbose)",
+	"	{	printf(\"cpu0: step 3: allocate shared work-queues %%g Mb\\n\",",
+	"			((double) NCORE * LWQ_SIZE + GWQ_SIZE) / (1048576.));",
+	"	}",
+	"	for (m = 0; m < NR_QS; m++)	/* last q is global 1 */",
+	"	{	double qsize = (m == NCORE) ? GWQ_SIZE : LWQ_SIZE;",
+	"		sprintf(key, \"Global\\\\pan_%%s_%%.3d\", PanSource, m);",
+	"		if (core_id == 0)",	/* root process creates shared memory segments */
+	"		{	shmid[m] = CreateFileMapping(",
+	"				INVALID_HANDLE_VALUE,	/* use paging file */",
+	"				NULL,			/* default security */",
+	"				PAGE_READWRITE,		/* access permissions */",
+	"				0,			/* high-order 4 bytes */",
+	"				qsize,			/* low-order bytes, size in bytes */",
+	"				key);			/* name */",
+	"		} else			/* worker nodes just open these segments */",
+	"		{	shmid[m] = OpenFileMapping(",
+	"				FILE_MAP_ALL_ACCESS,	/* read/write access */",
+	"				FALSE,			/* children do not inherit handle */",
+	"				key);",
+	"		}",
+	"		if (shmid[m] == NULL)",
+	"		{	fprintf(stderr, \"cpu%%d: could not create or open shared queues\\n\",",
+	"				core_id);",
+	"			must_exit = 1;",
+	"			break;",
+	"		}",
+	"		/* attach: */",
+	"		shared_mem[m] = (char *) MapViewOfFile(shmid[m], FILE_MAP_ALL_ACCESS, 0, 0, 0);",
+	"		if (shared_mem[m] == NULL)",
+	"		{ fprintf(stderr, \"cpu%%d: cannot attach shared q%%d (%%d Mb)\\n\",",
+	"			core_id, m+1, (int) (qsize/(1048576.)));",
+	"		  must_exit = 1;",
+	"		  break;",
+	"		}",
+	"",
+	"		memcnt += qsize;",
+	"",
+	"		m_workq[m] = (SM_frame *) shared_mem[m];",
+	"		if (core_id == 0)",
+	"		{	int nframes = (m == NCORE) ? GN_FRAMES : LN_FRAMES;",
+	"			for (n = 0; n < nframes; n++)",
+	"			{	m_workq[m][n].m_vsize = 0;",
+	"				m_workq[m][n].m_boq = 0;",
+	"	}	}	}",
+	"",
+	"	if (must_exit)",
+	"	{	fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
+	"		pan_exit(1);	/* calls cleanup_shm */",
+	"	}",
+	"}",
+	"",
+	"static uchar *",
+	"prep_shmid_S(size_t n)		/* either sets SS or H_tab, WIN32/WIN64 */",
+	"{	char	*rval;",
+	"#ifndef SEP_STATE",
+	"	char	key[512];",
+	"",
+	"	if (verbose && core_id == 0)",
+	"	{",
+	"	#ifdef BITSTATE",
+	"		printf(\"cpu0: step 1: allocate shared bitstate %%g Mb\\n\",",
+	"			(double) n / (1048576.));",
+	"	#else",
+	"		printf(\"cpu0: step 1: allocate shared hastable %%g Mb\\n\",",
+	"			(double) n / (1048576.));",
+	"	#endif",
+	"	}",
+	"	#ifdef MEMLIM",
+	"	if (memcnt + (double) n > memlim)",
+	"	{	printf(\"cpu%%d: S %%8g + %%d Kb exceeds memory limit of %%8g Mb\\n\",",
+	"			core_id, memcnt/1024., n/1024, memlim/(1048576.));",
+	"		printf(\"cpu%%d: insufficient memory -- aborting\\n\", core_id);",
+	"		exit(1);",
+	"	}",
+	"	#endif",
+	"",
+	"	/* make key different from queues: */",
+	"	sprintf(key, \"Global\\\\pan_%%s_%%.3d\", PanSource, NCORE+2); /* different from qs */",
+	"",
+	"	if (core_id == 0)	/* root */",
+	"	{	shmid_S = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,",
+	"#ifdef WIN64",
+	"			PAGE_READWRITE, (n>>32), (n & 0xffffffff), key);",
+	"#else",
+	"			PAGE_READWRITE, 0, n, key);",
+	"#endif",
+	"		memcnt += (double) n;",
+	"	} else			/* worker */",
+	"	{	shmid_S = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, key);",
+	"	}",
+
+	"	if (shmid_S == NULL)",
+	"	{",
+	"	#ifdef BITSTATE",
+	"		fprintf(stderr, \"cpu%%d: cannot %%s shared bitstate\",",
+	"			core_id, core_id?\"open\":\"create\");",
+	"	#else",
+	"		fprintf(stderr, \"cpu%%d: cannot %%s shared hashtable\",",
+	"			core_id, core_id?\"open\":\"create\");",
+	"	#endif",
+	"		fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
+	"		pan_exit(1);",
+	"	}",
+	"",
+	"	rval = (char *) MapViewOfFile(shmid_S, FILE_MAP_ALL_ACCESS, 0, 0, 0);	/* attach */",
+	"	if ((char *) rval == NULL)",
+	"	{ fprintf(stderr, \"cpu%%d: cannot attach shared bitstate or hashtable\\n\", core_id);",
+	"	  fprintf(stderr, \"pan: check './pan --' for usage details\\n\");",
+	"	  pan_exit(1);",
+	"	}",
+	"#else",
+	"	rval = (char *) emalloc(n);",
+	"#endif",
+	"	return (uchar *) rval;",
+	"}",
+	"",
+	"static uchar *",
+	"prep_state_mem(size_t n)		/* WIN32/WIN64 sets memory arena for states */",
+	"{	char	*rval;",
+	"	char	key[512];",
+	"	static int cnt = 3;		/* start larger than earlier ftok calls */",
+	"",
+	"	if (verbose && core_id == 0)",
+	"	{	printf(\"cpu0: step 2+: pre-allocate memory arena %%d of %%g Mb\\n\",",
+	"			cnt-3, (double) n / (1048576.));",
+	"	}",
+	"	#ifdef MEMLIM",
+	"	if (memcnt + (double) n > memlim)",
+	"	{	printf(\"cpu%%d: error: M %%.0f + %%.0f exceeds memory limit of %%.0f Kb\\n\",",
+	"			core_id, memcnt/1024.0, (double) n/1024.0, memlim/1024.0);",
+	"		return NULL;",
+	"	}",
+	"	#endif",
+	"",
+	"	sprintf(key, \"Global\\\\pan_%%s_%%.3d\", PanSource, NCORE+cnt); cnt++;",
+	"",
+	"	if (core_id == 0)",
+	"	{	shmid_M = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,",
+	"#ifdef WIN64",
+	"			PAGE_READWRITE, (n>>32), (n & 0xffffffff), key);",
+	"#else",
+	"			PAGE_READWRITE, 0, n, key);",
+	"#endif",
+	"	} else",
+	"	{	shmid_M = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, key);",
+	"	}",
+	"	if (shmid_M == NULL)",
+	"	{	printf(\"cpu%%d: failed to get pool of shared memory nr %%d of size %%d\\n\",",
+	"			core_id, cnt-3, n);",
+	"		printf(\"pan: check './pan --' for usage details\\n\");",
+	"		return NULL;",
+	"	}",
+	"	rval = (char *) MapViewOfFile(shmid_M, FILE_MAP_ALL_ACCESS, 0, 0, 0);	/* attach */",
+	"",
+	"	if (rval == NULL)",
+	"	{ printf(\"cpu%%d: failed to attach pool of shared memory nr %%d of size %%d\\n\",",
+	"		core_id, cnt-3, n);",
+	"	  return NULL;",
+	"	}",
+	"	return (uchar *) rval;",
+	"}",
+	"",
+	"void",
+	"init_HT(unsigned long n)	/* WIN32/WIN64 version */",
+	"{	volatile char	*x;",
+	"	double  get_mem;",
+	"#ifndef SEP_STATE",
+	"	char	*dc_mem_start;",
+	"#endif",
+	"	if (verbose) printf(\"cpu%%d: initialization for Windows\\n\", core_id);",
+	"",
+"#ifdef SEP_STATE",
+	" #ifndef MEMLIM",
+	"	if (verbose)",
+	"	{	printf(\"cpu0: steps 0,1: no -DMEMLIM set\\n\");",
+	"	}",
+	" #else",
+	"	if (verbose)",
+	"	printf(\"cpu0: steps 0,1: -DMEMLIM=%%d Mb - (hashtable %%g Mb + workqueues %%g Mb)\\n\",",
+	"		MEMLIM, ((double)n/(1048576.)), ((double) NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.));",
+	"#endif",
+	"	get_mem = NCORE * sizeof(double) + (1 + CS_NR) * sizeof(void *)+ 4*sizeof(void *) + 2*sizeof(double);",
+	"	/* NCORE * is_alive + search_terminated + CS_NR * sh_lock + 6 gr vars */",
+	"	get_mem += 4 * NCORE * sizeof(void *);", /* prfree, prfull, prcnt, prmax */
+	" #ifdef FULL_TRAIL",
+	"	get_mem += (NCORE) * sizeof(Stack_Tree *);",
+	"	/* NCORE * stack_last */",
+	" #endif",
+	"	x = (volatile char *) prep_state_mem((size_t) get_mem);",
+	"	shmid_X = (void *) x;",
+	"	if (x == NULL)",
+	"	{	printf(\"cpu0: could not allocate shared memory, see ./pan --\\n\");",
+	"		exit(1);",
+	"	}",
+	"	search_terminated = (volatile unsigned int *) x; /* comes first */",
+	"	x += sizeof(void *); /* maintain alignment */",
+	"",
+	"	is_alive   = (volatile double *) x;",
+	"	x += NCORE * sizeof(double);",
+	"",
+	"	sh_lock   = (volatile int *) x;",
+	"	x += CS_NR * sizeof(void *); /* allow 1 word per entry */",
+	"",
+	"	grfree    = (volatile int *) x;",
+	"	x += sizeof(void *);",
+	"	grfull    = (volatile int *) x;",
+	"	x += sizeof(void *);",
+	"	grcnt    = (volatile int *) x;",
+	"	x += sizeof(void *);",
+	"	grmax    = (volatile int *) x;",
+	"	x += sizeof(void *);",
+	"	prfree = (volatile int *) x;",
+	"	x += NCORE * sizeof(void *);",
+	"	prfull = (volatile int *) x;",
+	"	x += NCORE * sizeof(void *);",
+	"	prcnt = (volatile int *) x;",
+	"	x += NCORE * sizeof(void *);",
+	"	prmax = (volatile int *) x;",
+	"	x += NCORE * sizeof(void *);",
+	"	gr_readmiss    = (volatile double *) x;",
+	"	x += sizeof(double);",
+	"	gr_writemiss    = (volatile double *) x;",
+	"	x += sizeof(double);",
+	"",
+	"	#ifdef FULL_TRAIL",
+	"		stack_last = (volatile Stack_Tree **) x;",
+	"		x += NCORE * sizeof(Stack_Tree *);",
+	"	#endif",
+	"",
+	"	#ifndef BITSTATE",
+	"		H_tab = (H_el **) emalloc(n);",
+	"	#endif",
+"#else",
+	"	#ifndef MEMLIM",
+	"		#warning MEMLIM not set",	/* cannot happen */
+	"		#define MEMLIM	(2048)",
+	"	#endif",
+	"",
+	"	if (core_id == 0 && verbose)",
+	"		printf(\"cpu0: step 0: -DMEMLIM=%%d Mb - (hashtable %%g Mb + workqueues %%g Mb) = %%g Mb for state storage\\n\",",
+	"		MEMLIM, ((double)n/(1048576.)), ((double) NCORE * LWQ_SIZE + GWQ_SIZE)/(1048576.),",
+	"		(memlim - memcnt - (double) n - ((double) NCORE * LWQ_SIZE + GWQ_SIZE))/(1048576.));",
+	"	#ifndef BITSTATE",
+	"		H_tab = (H_el **) prep_shmid_S((size_t) n);	/* hash_table */",
+	"	#endif",
+	"	get_mem = memlim - memcnt - ((double) NCORE) * LWQ_SIZE - GWQ_SIZE;",
+	"	if (get_mem <= 0)",
+	"	{	Uerror(\"internal error -- shared state memory\");",
+	"	}",
+	"",
+	"	if (core_id == 0 && verbose)",
+	"	{	printf(\"cpu0: step 2: shared state memory %%g Mb\\n\",",
+	"			get_mem/(1048576.));",
+	"	}",
+	"	x = dc_mem_start = (char *) prep_state_mem((size_t) get_mem);	/* for states */",
+	"	if (x == NULL)",
+	"	{	printf(\"cpu%%d: insufficient memory -- aborting\\n\", core_id);",
+	"		exit(1);",
+	"	}",
+	"",
+	"	search_terminated = (volatile unsigned int *) x; /* comes first */",
+	"	x += sizeof(void *); /* maintain alignment */",
+	"",
+	"	is_alive   = (volatile double *) x;",
+	"	x += NCORE * sizeof(double);",
+	"",
+	"	sh_lock   = (volatile int *) x;",
+	"	x += CS_NR * sizeof(int);",
+	"",
+	"	grfree    = (volatile int *) x;",
+	"	x += sizeof(void *);",
+	"	grfull    = (volatile int *) x;",
+	"	x += sizeof(void *);",
+	"	grcnt    = (volatile int *) x;",
+	"	x += sizeof(void *);",
+	"	grmax    = (volatile int *) x;",
+	"	x += sizeof(void *);",
+	"	prfree = (volatile int *) x;",
+	"	x += NCORE * sizeof(void *);",
+	"	prfull = (volatile int *) x;",
+	"	x += NCORE * sizeof(void *);",
+	"	prcnt = (volatile int *) x;",
+	"	x += NCORE * sizeof(void *);",
+	"	prmax = (volatile int *) x;",
+	"	x += NCORE * sizeof(void *);",
+	"	gr_readmiss = (volatile double *) x;",
+	"	x += sizeof(double);",
+	"	gr_writemiss = (volatile double *) x;",
+	"	x += sizeof(double);",
+	"",
+	" #ifdef FULL_TRAIL",
+	"	stack_last = (volatile Stack_Tree **) x;",
+	"	x += NCORE * sizeof(Stack_Tree *);",
+	" #endif",
+	"	if (((long)x)&(sizeof(void *)-1))	/* word alignment */",
+	"	{	x += sizeof(void *)-(((long)x)&(sizeof(void *)-1)); /* 64-bit align */",
+	"	}",
+	"",
+	"	#ifdef COLLAPSE",
+	"	ncomps = (unsigned long *) x;",
+	"	x += (256+2) * sizeof(unsigned long);",
+	"	#endif",
+	"",
+	"	dc_shared = (sh_Allocater *) x; /* in shared memory */",
+	"	x += sizeof(sh_Allocater);",
+	"",
+	"	if (core_id == 0)	/* root only */",
+	"	{	dc_shared->dc_id     = shmid_M;",
+	"		dc_shared->dc_start  = (void *) dc_mem_start;",
+	"		dc_shared->dc_arena  = x;",
+	"		dc_shared->pattern   = 1234567;",
+	"		dc_shared->dc_size   = (long) get_mem - (long) (x - dc_mem_start);",
+	"		dc_shared->nxt       = NULL;",
+	"	}",
+"#endif",
+	"}",
+	"",
+	"#if defined(WIN32) || defined(WIN64) || defined(__i386__) || defined(__x86_64__)",
+	"extern BOOLEAN InterlockedBitTestAndSet(LONG volatile* Base, LONG Bit);",
+	"int",
+	"tas(volatile LONG *s)", /* atomic test and set */
+	"{	return InterlockedBitTestAndSet(s, 1);",
+	"}",
+	"#else",
+	"	#error missing definition of test and set operation for this platform",
+	"#endif",
+	"",
+	"void",
+	"cleanup_shm(int val)",
+	"{	int m;",
+	"	static int nibis = 0;",
+	"",
+	"	if (nibis != 0)",
+	"	{	printf(\"cpu%%d: Redundant call to cleanup_shm(%%d)\\n\", core_id, val);",
+	"		return;",
+	"	} else",
+	"	{	nibis = 1;",
+	"	}",
+	"	if (search_terminated != NULL)",
+	"	{	*search_terminated |= 16; /* cleanup_shm */",
+	"	}",
+	"",
+	"	for (m = 0; m < NR_QS; m++)",
+	"	{	if (shmid[m] != NULL)",
+	"		{	UnmapViewOfFile((char *) shared_mem[m]);",
+	"			CloseHandle(shmid[m]);",
+	"	}	}",
+	"#ifdef SEP_STATE",
+	"	UnmapViewOfFile((void *) shmid_X);",
+	"	CloseHandle((void *) shmid_M);",
+	"#else",
+	"	#ifdef BITSTATE",
+	"		if (shmid_S != NULL)",
+	"		{	UnmapViewOfFile(SS);",
+	"			CloseHandle(shmid_S);",
+	"		}",
+	"	#else",
+	"		if (core_id == 0 && verbose)",
+	"		{	printf(\"cpu0: done, %%ld Mb of shared state memory left\\n\",",
+	"				dc_shared->dc_size / (long)(1048576));",
+	"		}",
+	"		if (shmid_S != NULL)",
+	"		{	UnmapViewOfFile(H_tab);",
+	"			CloseHandle(shmid_S);",
+	"		}",
+	"		shmid_M = (void *) (dc_shared->dc_id);",
+	"		UnmapViewOfFile((char *) dc_shared->dc_start);",
+	"		CloseHandle(shmid_M);",
+	"	#endif",
+	"#endif",
+	"	/* detached from shared memory - so cannot use cpu_printf */",
+	"	if (verbose)",
+	"	{	printf(\"cpu%%d: done -- got %%d states from queue\\n\",",
+	"			core_id, nstates_get);",
+	"	}",
+	"}",
+	"",
+	"void",
+	"mem_get(void)",
+	"{	SM_frame   *f;",
+	"	int is_parent;",
+	"",
+	"#if defined(MA) && !defined(SEP_STATE)",
+	"	#error MA requires SEP_STATE in multi-core mode",
+	"#endif",
+	"#ifdef BFS",
+	"	#error instead of -DNCORE -DBFS use -DBFS_PAR",
+	"#endif",
+	"#ifdef SC",
+	"	#error SC is not supported in multi-core mode",
+	"#endif",
+	"	init_shm();	/* we are single threaded when this starts */",
+	"	signal(SIGINT, give_up);	/* windows control-c interrupt */",
+	"",
+	"	if (core_id == 0 && verbose)",
+	"	{	printf(\"cpu0: step 4: creating additional workers (proxy %%d)\\n\",",
+	"			proxy_pid);",
+	"	}",
+	"#if 0",
+	"	if NCORE > 1 the child or the parent should fork N-1 more times",
+	"	the parent is the only process with core_id == 0 and is_parent > 0",
+	"	the others (workers) have is_parent = 0 and core_id = 1..NCORE-1",
+	"#endif",
+	"	if (core_id == 0)			/* root starts up the workers */",
+	"	{	worker_pids[0] = (DWORD) getpid();	/* for completeness */",
+	"		while (++core_id < NCORE)	/* first worker sees core_id = 1 */",
+	"		{	char cmdline[64];",
+	"			STARTUPINFO si = { sizeof(si) };",
+	"			PROCESS_INFORMATION pi;",
+	"",
+	"			if (proxy_pid == core_id)	/* always non-zero */",
+	"			{	sprintf(cmdline, \"pan_proxy.exe -r %%s-Q%%d -Z%%d\",",
+	"					o_cmdline, getpid(), core_id);",
+	"			} else",
+	"			{	sprintf(cmdline, \"pan.exe %%s-Q%%d -Z%%d\",",
+	"					o_cmdline, getpid(), core_id);",
+	"			}",
+	"			if (verbose) printf(\"cpu%%d: spawn %%s\\n\", core_id, cmdline);",
+	"",
+	"			is_parent = CreateProcess(0, cmdline, 0, 0, FALSE, 0, 0, 0, &si, &pi);",
+	"			if (is_parent == 0)",
+	"			{	Uerror(\"fork failed\");",
+	"			}",
+	"			worker_pids[core_id] = pi.dwProcessId;",
+	"			worker_handles[core_id] = pi.hProcess;",
+	"			if (verbose)",
+	"			{	cpu_printf(\"created core %%d, pid %%d\\n\",",
+	"					core_id, pi.dwProcessId);",
+	"			}",
+	"			if (proxy_pid == core_id)	/* we just created the receive half */",
+	"			{	/* add proxy send, store pid in proxy_pid_snd */",
+	"				sprintf(cmdline, \"pan_proxy.exe -s %%s-Q%%d -Z%%d -Y%%d\",",
+	"					o_cmdline, getpid(), core_id, worker_pids[proxy_pid]);",
+	"				if (verbose) printf(\"cpu%%d: spawn %%s\\n\", core_id, cmdline);",
+	"				is_parent = CreateProcess(0, cmdline, 0,0, FALSE, 0,0,0, &si, &pi);",
+	"				if (is_parent == 0)",
+	"				{	Uerror(\"fork failed\");",
+	"				}",
+	"				proxy_pid_snd = pi.dwProcessId;",
+	"				proxy_handle_snd = pi.hProcess;",
+	"				if (verbose)",
+	"				{	cpu_printf(\"created core %%d, pid %%d (send proxy)\\n\",",
+	"						core_id, pi.dwProcessId);",
+	"		}	}	}",
+	"		core_id = 0;		/* reset core_id for root process */",
+	"	} else	/* worker */",
+	"	{	static char db0[16];	/* good for up to 10^6 cores */",
+	"		static char db1[16];",
+	"		tprefix = db0; sprefix = db1;",
+	"		sprintf(tprefix, \"cpu%%d_trail\", core_id);	/* avoid conflicts on file access */",
+	"		sprintf(sprefix, \"cpu%%d_rst\", core_id);",
+	"		memcnt = 0;	/* count only additionally allocated memory */",
+	"	}",
+	"	if (verbose)",
+	"	{	cpu_printf(\"starting core_id %%d -- pid %%d\\n\", core_id, getpid());",
+	"	}",
+	"	if (core_id == 0 && !remote_party)",
+	"	{	new_state();	/* root starts the search */",
+	"		if (verbose)",
+	"		cpu_printf(\"done with 1st dfs, nstates %%g (put %%d states), start reading q\\n\",",
+	"			nstates, nstates_put);",
+	"		dfs_phase2 = 1;",
+	"	}",
+	"	Read_Queue(core_id);	/* all cores */",
+	"",
+	"	if (verbose)",
+	"	{	cpu_printf(\"put %%6d states into queue -- got %%6d\\n\",",
+	"			nstates_put, nstates_get);",
+	"	}",
+	"	done = 1;",
+	"	wrapup();",
+	"	exit(0);",
+	"}",
+	"#endif", /* WIN32 || WIN64 */
+	"",
+	"#ifdef BITSTATE",
+	"void",
+	"init_SS(unsigned long n)",
+	"{",
+	"	SS = (uchar *) prep_shmid_S((size_t) n);",
+	"	init_HT(0L);", /* locks and shared memory for Stack_Tree allocations */
+	"}",
+	"#endif", /* BITSTATE */
+	"",
+	"#endif", /* NCORE>1 */
+	0,
+};
diff -r 51b3bf8bc61b sys/src/cmd/spin/pangen7.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/cmd/spin/pangen7.c	Wed Nov 22 00:21:47 2017 -0800
@@ -0,0 +1,923 @@
+/***** spin: pangen7.c *****/
+
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include "spin.h"
+#include "y.tab.h"
+#include <assert.h>
+#ifndef PC
+#include <unistd.h>
+#endif
+
+extern ProcList	*rdy;
+extern Element *Al_El;
+extern int nclaims, verbose, Strict;
+extern short has_accept;
+
+typedef struct Succ_List Succ_List;
+typedef struct SQueue SQueue;
+typedef struct OneState OneState;
+typedef struct State_Stack State_Stack;
+typedef struct Guard Guard;
+
+struct Succ_List {
+	SQueue	*s;
+	Succ_List *nxt;
+};
+
+struct OneState {
+	int	*combo;	/* the combination of claim states */
+	Succ_List	*succ;	/* list of ptrs to immediate successor states */
+};
+
+struct SQueue {
+	OneState	state;
+	SQueue	*nxt;
+};
+
+struct State_Stack {
+	int *n;
+	State_Stack *nxt;
+};
+
+struct Guard {
+	Lextok *t;
+	Guard *nxt;
+};
+
+static SQueue	*sq, *sd, *render;	/* states move from sq to sd to render to holding */
+static SQueue	*holding, *lasthold;
+static State_Stack *dsts;
+
+static int nst;		/* max nr of states in claims */
+static int *Ist;	/* initial states */
+static int *Nacc;	/* number of accept states in claim */
+static int *Nst;	/* next states */
+static int **reached;	/* n claims x states */
+static int unfolding;	/* to make sure all accept states are reached */
+static int is_accept;	/* remember if the current state is accepting in any claim */
+static int not_printing; /* set during explore_product */
+
+static Element ****matrix;	/* n x two-dimensional arrays state x state */
+static Element **Selfs;	/* self-loop states at end of claims */
+
+static void get_seq(int, Sequence *);
+static void set_el(int n, Element *e);
+static void gen_product(void);
+static void print_state_nm(char *, int *, char *);
+static SQueue *find_state(int *);
+static SQueue *retrieve_state(int *);
+
+static int
+same_state(int *a, int *b)
+{	int i;
+
+	for (i = 0; i < nclaims; i++)
+	{	if (a[i] != b[i])
+		{	return 0;
+	}	}
+	return 1;
+}
+
+static int
+in_stack(SQueue *s, SQueue *in)
+{	SQueue *q;
+
+	for (q = in; q; q = q->nxt)
+	{	if (same_state(q->state.combo, s->state.combo))
+		{	return 1;
+	}	}
+	return 0;
+}
+
+static void
+to_render(SQueue *s)
+{	SQueue *a, *q, *last; /* find in sd/sq and move to render, if not already there */
+	int n;
+
+	for (n = 0; n < nclaims; n++)
+	{	reached[n][ s->state.combo[n] ] |= 2;
+	}
+
+	for (q = render; q; q = q->nxt)
+	{	if (same_state(q->state.combo, s->state.combo))
+		{	return;
+	}	}
+	for (q = holding; q; q = q->nxt)
+	{	if (same_state(q->state.combo, s->state.combo))
+		{	return;
+	}	}
+
+	a = sd;
+more:
+	for (q = a, last = 0; q; last = q, q = q->nxt)
+	{	if (same_state(q->state.combo, s->state.combo))
+		{	if (!last)
+			{	if (a == sd)
+				{	sd = q->nxt;
+				} else if (a == sq)
+				{	sq = q->nxt;
+				} else
+				{	holding = q->nxt;
+				}
+			} else
+			{	last->nxt = q->nxt;
+			}
+			q->nxt = render;
+			render = q;
+			return;
+	}	}
+	if (verbose)
+	{	print_state_nm("looking for: ", s->state.combo, "\n");
+	}
+	(void) find_state(s->state.combo);	/* creates it in sq */
+	if (a != sq)
+	{	a = sq;
+		goto more;
+	}
+	fatal("cannot happen, to_render", 0);
+}
+
+static void
+wrap_text(char *pre, Lextok *t, char *post)
+{
+	printf(pre, (char *) 0);
+	comment(stdout, t, 0);
+	printf(post, (char *) 0);
+}
+
+static State_Stack *
+push_dsts(int *n)
+{	State_Stack *s;
+	int i;
+
+	for (s = dsts; s; s = s->nxt)
+	{	if (same_state(s->n, n))
+		{	if (verbose&64)
+			{	printf("\n");
+				for (s = dsts; s; s = s->nxt)
+				{	print_state_nm("\t", s->n, "\n");
+				}
+				print_state_nm("\t", n, "\n");
+			}
+			return s;
+	}	}
+
+	s = (State_Stack *) emalloc(sizeof(State_Stack));
+	s->n = (int *) emalloc(nclaims * sizeof(int));
+	for (i = 0; i < nclaims; i++)
+		s->n[i] = n[i];
+	s->nxt = dsts;
+	dsts = s;
+	return 0;
+}
+
+static void
+pop_dsts(void)
+{
+	assert(dsts != NULL);
+	dsts = dsts->nxt;
+}
+
+static void
+complete_transition(Succ_List *sl, Guard *g)
+{	Guard *w;
+	int cnt = 0;
+
+	printf("	:: ");
+	for (w = g; w; w = w->nxt)
+	{	if (w->t->ntyp == CONST
+		&&  w->t->val == 1)
+		{	continue;
+		} else if (w->t->ntyp == 'c'
+		&&  w->t->lft->ntyp == CONST
+		&&  w->t->lft->val == 1)
+		{	continue; /* 'true' */
+		}
+
+		if (cnt > 0)
+		{	printf(" && ");
+		}
+		wrap_text("", w->t, "");
+		cnt++;
+	}
+	if (cnt == 0)
+	{	printf("true");
+	}
+	print_state_nm(" -> goto ", sl->s->state.combo, "");
+
+	if (is_accept > 0)
+	{	printf("_U%d\n", (unfolding+1)%nclaims);
+	} else
+	{	printf("_U%d\n", unfolding);
+	}
+}
+
+static void
+state_body(OneState *s, Guard *guard)
+{	Succ_List *sl;
+	State_Stack *y;
+	Guard *g;
+	int i, once;
+
+	for (sl = s->succ; sl; sl = sl->nxt)
+	{	once = 0;
+
+		for (i = 0; i < nclaims; i++)
+		{	Element *e;
+			e = matrix[i][s->combo[i]][sl->s->state.combo[i]];
+
+			/* if one of the claims has a DO or IF move
+			   then pull its target state forward, once
+			 */
+
+			if (!e
+			|| e->n->ntyp == NON_ATOMIC
+			||  e->n->ntyp == DO
+			||  e->n->ntyp == IF)
+			{	s = &(sl->s->state);
+				y = push_dsts(s->combo);
+				if (!y)
+				{	if (once++ == 0)
+					{	assert(s->succ != NULL);
+						state_body(s, guard);
+					}
+					pop_dsts();
+				} else if (!y->nxt)	/* self-loop transition */
+				{	if (!not_printing) printf(" /* self-loop */\n");
+				} else
+				{	/* non_fatal("loop in state body", 0); ** maybe ok */
+				}
+				continue;
+			} else
+			{	g = (Guard *) emalloc(sizeof(Guard));
+				g->t = e->n;
+				g->nxt = guard;
+				guard = g;
+		}	}
+
+		if (guard && !once)
+		{	if (!not_printing) complete_transition(sl, guard);
+			to_render(sl->s);
+	}	}
+}
+
+static struct X {
+	char *s;	int n;
+} spl[] = {
+	{"end",		3 },
+	{"accept",	6 },
+	{0,		0 },
+};
+
+static int slcnt;
+extern Label *labtab;
+
+static ProcList *
+locate_claim(int n)
+{	ProcList *p;
+	int i;
+
+	for (p = rdy, i = 0; p; p = p->nxt, i++) /* find claim name */
+	{	if (i == n)
+		{	break;
+	}	}
+	assert(p && p->b == N_CLAIM);
+
+	return p;
+}
+
+static void
+elim_lab(Element *e)
+{	Label *l, *lst;
+
+	for (l = labtab, lst = NULL; l; lst = l, l = l->nxt)
+	{	if (l->e == e)
+		{	if (lst)
+			{	lst->nxt = l->nxt;
+			} else
+			{	labtab = l->nxt;
+			}
+			break;
+	}	}
+}
+
+static int
+claim_has_accept(ProcList *p)
+{	Label *l;
+
+	for (l = labtab; l; l = l->nxt)
+	{	if (strcmp(l->c->name, p->n->name) == 0
+		&&  strncmp(l->s->name, "accept", 6) == 0)
+		{	return 1;
+	}	}
+	return 0;
+}
+
+static void
+prune_accept(void)
+{	int n;
+
+	for (n = 0; n < nclaims; n++)
+	{	if ((reached[n][Selfs[n]->seqno] & 2) == 0)
+		{	if (verbose)
+			{	printf("claim %d: selfloop not reachable\n", n);
+			}
+			elim_lab(Selfs[n]);
+			Nacc[n] = claim_has_accept(locate_claim(n));
+	}	}
+}
+
+static void
+mk_accepting(int n, Element *e)
+{	ProcList *p;
+	Label *l;
+	int i;
+
+	assert(!Selfs[n]);
+	Selfs[n] = e;
+
+	l = (Label *) emalloc(sizeof(Label));
+	l->s = (Symbol *) emalloc(sizeof(Symbol));
+	l->s->name = "accept00";
+	l->c = (Symbol *) emalloc(sizeof(Symbol));
+	l->uiid = 0;	/* this is not in an inline */
+
+	for (p = rdy, i = 0; p; p = p->nxt, i++) /* find claim name */
+	{	if (i == n)
+		{	l->c->name = p->n->name;
+			break;
+	}	}
+	assert(p && p->b == N_CLAIM);
+	Nacc[n] = 1;
+	has_accept = 1;
+
+	l->e = e;
+	l->nxt = labtab;
+	labtab = l;
+}
+
+static void
+check_special(int *nrs)
+{	ProcList *p;
+	Label *l;
+	int i, j, nmatches;
+	int any_accepts = 0;
+
+	for (i = 0; i < nclaims; i++)
+	{	any_accepts += Nacc[i];
+	}
+
+	is_accept = 0;
+	for (j = 0; spl[j].n; j++) /* 2 special label prefixes */
+	{	nmatches = 0;
+		for (p = rdy, i = 0; p; p = p->nxt, i++) /* check each claim */
+		{	if (p->b != N_CLAIM)
+			{	continue;
+			}
+			/* claim i in state nrs[i], type p->tn, name p->n->name
+			 * either the state has an accept label, or the claim has none,
+			 * so that all its states should be considered accepting
+			 * --- but only if other claims do have accept states!
+			 */
+			if (Strict == 0 && j == 1 && Nacc[i] == 0 && any_accepts > 0)
+			{	if ((verbose&32) && i == unfolding)
+				{	printf("	/* claim %d pseudo-accept */\n", i);
+				}
+				goto is_accepting;
+			}
+			for (l = labtab; l; l = l->nxt)	/* check its labels */
+			{	if (strcmp(l->c->name, p->n->name) == 0  /* right claim */
+				&&  l->e->seqno == nrs[i]		 /* right state */
+				&&  strncmp(l->s->name, spl[j].s, spl[j].n) == 0)
+				{	if (j == 1)	/* accept state */
+					{	char buf[32];
+is_accepting:					if (strchr(p->n->name, ':'))
+						{	sprintf(buf, "N%d", i);
+						} else
+						{	assert(strlen(p->n->name) < sizeof(buf));
+							strcpy(buf, p->n->name);
+						}
+						if (unfolding == 0 && i == 0)
+						{	if (!not_printing)
+							printf("%s_%s_%d:\n",	/* true accept */
+								spl[j].s, buf, slcnt++);
+						} else if (verbose&32)
+						{	if (!not_printing)
+							printf("%s_%s%d:\n",
+								buf, spl[j].s, slcnt++);
+						}
+						if (i == unfolding)
+						{	is_accept++; /* move to next unfolding */
+						}
+					} else
+					{	nmatches++;
+					}
+					break;
+		}	}	}
+		if (j == 0 && nmatches == nclaims)	/* end-state */
+		{	if (!not_printing)
+			{	printf("%s%d:\n", spl[j].s, slcnt++);
+	}	}	}
+}
+
+static int
+render_state(SQueue *q)
+{
+	if (!q || !q->state.succ)
+	{	if (verbose&64)
+		{	printf("	no exit\n");
+		}
+		return 0;
+	}
+
+	check_special(q->state.combo); /* accept or end-state labels */
+
+	dsts = (State_Stack *) 0;
+	push_dsts(q->state.combo);	/* to detect loops */
+
+	if (!not_printing)
+	{	print_state_nm("", q->state.combo, "");	/* the name */
+		printf("_U%d:\n\tdo\n", unfolding);
+	}
+
+	state_body(&(q->state), (Guard *) 0);
+
+	if (!not_printing)
+	{	printf("\tod;\n");
+	}
+	pop_dsts();
+	return 1;
+}
+
+static void
+explore_product(void)
+{	SQueue *q;
+
+	/* all states are in the sd queue */
+
+	q = retrieve_state(Ist);	/* retrieve from the sd q */
+	q->nxt = render;		/* put in render q */
+	render = q;
+	do {
+		q = render;
+		render = render->nxt;
+		q->nxt = 0;		/* remove from render q */
+
+		if (verbose&64)
+		{	print_state_nm("explore: ", q->state.combo, "\n");
+		}
+
+		not_printing = 1;
+		render_state(q);	/* may add new states */
+		not_printing = 0;
+
+		if (lasthold)
+		{	lasthold->nxt = q;
+			lasthold = q;
+		} else
+		{	holding = lasthold = q;
+		}
+	} while (render);
+	assert(!dsts);
+	
+}
+
+static void
+print_product(void)
+{	SQueue *q;
+	int cnt;
+
+	if (unfolding == 0)
+	{	printf("never Product {\n");	/* name expected by iSpin */
+		q = find_state(Ist);	/* should find it in the holding q */
+		assert(q != NULL);
+		q->nxt = holding;	/* put it at the front */
+		holding = q;
+	}
+	render = holding;
+	holding = lasthold = 0;
+
+	printf("/* ============= U%d ============= */\n", unfolding);
+	cnt = 0;
+	do {
+		q = render;
+		render = render->nxt;
+		q->nxt = 0;
+		if (verbose&64)
+		{	print_state_nm("print: ", q->state.combo, "\n");
+		}
+		cnt += render_state(q);
+
+		if (lasthold)
+		{	lasthold->nxt = q;
+			lasthold = q;
+		} else
+		{	holding = lasthold = q;
+		}
+	} while (render);
+	assert(!dsts);
+
+	if (cnt == 0)
+	{	printf("	0;\n");
+	}
+
+	if (unfolding == nclaims-1)
+	{	printf("}\n");
+	}
+}
+
+static void
+prune_dead(void)
+{	Succ_List *sl, *last;
+	SQueue *q;
+	int cnt;
+
+	do {	cnt = 0;
+		for (q = sd; q; q = q->nxt)
+		{	/* if successor is deadend, remove it
+			 * unless it's a move to the end-state of the claim
+			 */
+			last = (Succ_List *) 0;
+			for (sl = q->state.succ; sl; last = sl, sl = sl->nxt)
+			{	if (!sl->s->state.succ)	/* no successor */
+				{	if (!last)
+					{	q->state.succ = sl->nxt;
+					} else
+					{	last->nxt = sl->nxt;
+					}
+					cnt++;
+		}	}	}
+	} while (cnt > 0);
+}
+
+static void
+print_raw(void)
+{	int i, j, n;
+
+	printf("#if 0\n");
+	for (n = 0; n < nclaims; n++)
+	{	printf("C%d:\n", n);
+		for (i = 0; i < nst; i++)
+		{	if (reached[n][i])
+			for (j = 0; j < nst; j++)
+			{	if (matrix[n][i][j])
+				{	if (reached[n][i] & 2) printf("+");
+					if (i == Ist[n]) printf("*");
+					printf("\t%d", i);
+					wrap_text(" -[", matrix[n][i][j]->n, "]->\t");
+					printf("%d\n", j);
+	}	}	}	}
+	printf("#endif\n\n");
+	fflush(stdout);
+}
+
+void
+sync_product(void)
+{	ProcList *p;
+	Element *e;
+	int n, i;
+
+	if (nclaims <= 1) return;
+
+	(void) unlink("pan.pre");
+
+	Ist  = (int *) emalloc(sizeof(int) * nclaims);
+	Nacc = (int *) emalloc(sizeof(int) * nclaims);
+	Nst  = (int *) emalloc(sizeof(int) * nclaims);
+	reached = (int **) emalloc(sizeof(int *) * nclaims);
+	Selfs   = (Element **) emalloc(sizeof(Element *) * nclaims);
+	matrix  = (Element ****) emalloc(sizeof(Element ***) * nclaims); /* claims */
+
+	for (p = rdy, i = 0; p; p = p->nxt, i++)
+	{	if (p->b == N_CLAIM)
+		{	nst = max(p->s->maxel, nst);
+			Nacc[i] = claim_has_accept(p);
+	}	}
+
+	for (n = 0; n < nclaims; n++)
+	{	reached[n] = (int *) emalloc(sizeof(int) * nst);
+		matrix[n] = (Element ***) emalloc(sizeof(Element **) * nst);	/* rows */
+		for (i = 0; i < nst; i++)					/* cols */
+		{	matrix[n][i] = (Element **) emalloc(sizeof(Element *) * nst);
+	}	}
+
+	for (e = Al_El; e; e = e->Nxt)
+	{	e->status &= ~DONE;
+	}
+
+	for (p = rdy, n=0; p; p = p->nxt, n++)
+	{	if (p->b == N_CLAIM)
+		{	/* fill in matrix[n] */
+			e = p->s->frst;
+			Ist[n] = huntele(e, e->status, -1)->seqno;
+
+			reached[n][Ist[n]] = 1|2;
+			get_seq(n, p->s);
+	}	}
+
+	if (verbose)	/* show only the input automata */
+	{	print_raw();
+	}
+
+	gen_product();	/* create product automaton */
+}
+
+static int
+nxt_trans(int n, int cs, int frst)
+{	int j;
+
+	for (j = frst; j < nst; j++)
+	{	if (reached[n][cs]
+		&&  matrix[n][cs][j])
+		{	return j;
+	}	}
+	return -1;
+}
+
+static void
+print_state_nm(char *p, int *s, char *a)
+{	int i;
+	printf("%sP", p);
+	for (i = 0; i < nclaims; i++)
+	{	printf("_%d", s[i]);
+	}
+	printf("%s", a);
+}
+
+static void
+create_transition(OneState *s, SQueue *it)
+{	int n, from, upto;
+	int *F = s->combo;
+	int *T = it->state.combo;
+	Succ_List *sl;
+	Lextok *t;
+
+	if (verbose&64)
+	{	print_state_nm("", F, " ");
+		print_state_nm("-> ", T, "\t");
+	}
+
+	/* check if any of the claims is blocked */
+	/* which makes the state a dead-end */
+	for (n = 0; n < nclaims; n++)
+	{	from = F[n];
+		upto = T[n];
+		t = matrix[n][from][upto]->n;
+		if (verbose&64)
+		{	wrap_text("", t, " ");
+		}
+		if (t->ntyp == 'c'
+		&&  t->lft->ntyp == CONST)
+		{	if (t->lft->val == 0)	/* i.e., false */
+			{	goto done;
+	}	}	}
+
+	sl = (Succ_List *) emalloc(sizeof(Succ_List));
+	sl->s = it;
+	sl->nxt = s->succ;
+	s->succ = sl;
+done:
+	if (verbose&64)
+	{	printf("\n");
+	}
+}
+
+static SQueue *
+find_state(int *cs)
+{	SQueue *nq, *a = sq;
+	int i;
+
+again:	/* check in nq, sq, and then in the render q */
+	for (nq = a; nq; nq = nq->nxt)
+	{	if (same_state(nq->state.combo, cs))
+		{	return nq;	/* found */
+	}	}
+	if (a == sq && sd)
+	{	a = sd;
+		goto again; /* check the other stack too */
+	} else if (a == sd && render)
+	{	a = render;
+		goto again;
+	}
+
+	nq = (SQueue *) emalloc(sizeof(SQueue));
+	nq->state.combo = (int *) emalloc(nclaims * sizeof(int));
+	for (i = 0; i < nclaims; i++)
+	{	nq->state.combo[i] = cs[i];
+	}
+	nq->nxt = sq;	/* add to sq stack */
+	sq = nq;
+
+	return nq;
+}
+
+static SQueue *
+retrieve_state(int *s)
+{	SQueue *nq, *last = NULL;
+
+	for (nq = sd; nq; last = nq, nq = nq->nxt)
+	{	if (same_state(nq->state.combo, s))
+		{	if (last)
+			{	last->nxt = nq->nxt;
+			} else
+			{	sd = nq->nxt;	/* 6.4.0: was sd = nq */
+			}
+			return nq;	/* found */
+	}	}
+
+	fatal("cannot happen: retrieve_state", 0);
+	return (SQueue *) 0;
+}
+
+static void
+all_successors(int n, OneState *cur)
+{	int i, j = 0;
+
+	if (n >= nclaims)
+	{	create_transition(cur, find_state(Nst));
+	} else
+	{	i = cur->combo[n];
+		for (;;)
+		{	j = nxt_trans(n, i, j);
+			if (j < 0) break;
+			Nst[n] = j;
+			all_successors(n+1, cur);
+			j++;
+	}	}
+}
+
+static void
+gen_product(void)
+{	OneState *cur_st;
+	SQueue *q;
+
+	find_state(Ist);	/* create initial state */
+
+	while (sq)
+	{	if (in_stack(sq, sd))
+		{	sq = sq->nxt;
+			continue;
+		}
+		cur_st = &(sq->state);
+
+		q = sq;
+		sq = sq->nxt;	/* delete from sq stack */
+		q->nxt = sd;	/* and move to done stack */
+		sd = q;
+
+		all_successors(0, cur_st);
+	}
+	/* all states are in the sd queue now */
+	prune_dead();
+	explore_product();	/* check if added accept-self-loops are reachable */
+	prune_accept();
+
+	if (verbose)
+	{	print_raw();
+	}
+
+	/* PM: merge states with identical successor lists */
+
+	/* all outgoing transitions from accept-states
+	   from claim n in copy n connect to states in copy (n+1)%nclaims
+	   only accept states from claim 0 in copy 0 are true accept states
+	   in the product
+
+	   PM: what about claims that have no accept states (e.g., restrictions)
+	*/
+
+	for (unfolding = 0; unfolding < nclaims; unfolding++)
+	{	print_product();
+	}
+}
+
+static void
+t_record(int n, Element *e, Element *g)
+{	int from = e->seqno, upto = g?g->seqno:0;
+
+	assert(from >= 0 && from < nst);
+	assert(upto >= 0 && upto < nst);
+
+	matrix[n][from][upto] = e;
+	reached[n][upto] |= 1;
+}
+
+static void
+get_sub(int n, Element *e)
+{
+	if (e->n->ntyp == D_STEP
+	||  e->n->ntyp == ATOMIC)
+	{	fatal("atomic or d_step in never claim product", 0);
+	} 
+	/* NON_ATOMIC */
+	e->n->sl->this->last->nxt = e->nxt;
+	get_seq(n, e->n->sl->this);
+
+	t_record(n, e, e->n->sl->this->frst);
+
+}
+
+static void
+set_el(int n, Element *e)
+{	Element *g;
+
+	if (e->n->ntyp == '@')	/* change to self-loop */
+	{	e->n->ntyp = CONST;
+		e->n->val = 1;	/* true */
+		e->nxt = e;
+		g = e;
+		mk_accepting(n, e);
+	} else
+
+	if (e->n->ntyp == GOTO)
+	{	g = get_lab(e->n, 1);
+		g = huntele(g, e->status, -1);
+	} else if (e->nxt)
+	{	g = huntele(e->nxt, e->status, -1);
+	} else
+	{	g = NULL;
+	}
+
+	t_record(n, e, g);
+}
+
+static void
+get_seq(int n, Sequence *s)
+{	SeqList *h;
+	Element *e;
+
+	e = huntele(s->frst, s->frst->status, -1);
+	for ( ; e; e = e->nxt)
+	{	if (e->status & DONE)
+		{	goto checklast;
+		}
+		e->status |= DONE;
+
+		if (e->n->ntyp == UNLESS)
+		{	fatal("unless stmnt in never claim product", 0);
+		}
+
+		if (e->sub)	/* IF or DO */
+		{	Lextok *x = NULL;
+			Lextok *y = NULL;
+			Lextok *haselse = NULL;
+
+			for (h = e->sub; h; h = h->nxt)
+			{	Lextok *t = h->this->frst->n;
+				if (t->ntyp == ELSE)
+				{	if (verbose&64) printf("else at line %d\n", t->ln);
+					haselse = t;
+					continue;
+				}
+				if (t->ntyp != 'c')
+				{	fatal("product, 'else' combined with non-condition", 0);
+				}
+
+				if (t->lft->ntyp == CONST	/* true */
+				&&  t->lft->val == 1
+				&&  y == NULL)
+				{	y = nn(ZN, CONST, ZN, ZN);
+					y->val = 0;
+				} else
+				{	if (!x)
+						x = t;
+					else
+						x = nn(ZN, OR, x, t);
+					if (verbose&64)
+					{	wrap_text(" [", x, "]\n");
+			}	}	}
+			if (haselse)
+			{	if (!y)
+				{	y = nn(ZN, '!', x, ZN);
+				}
+				if (verbose&64)
+				{	wrap_text(" [else: ", y, "]\n");
+				}
+				haselse->ntyp = 'c';	/* replace else */
+				haselse->lft = y;
+			}
+
+			for (h = e->sub; h; h = h->nxt)
+			{	t_record(n, e, h->this->frst);
+				get_seq(n, h->this);
+			}
+		} else
+		{	if (e->n->ntyp == ATOMIC
+			||  e->n->ntyp == D_STEP
+			||  e->n->ntyp == NON_ATOMIC)
+			{	get_sub(n, e);
+			} else 
+			{	set_el(n, e);
+			}
+		}
+checklast:	if (e == s->last)
+			break;
+	}
+}
diff -r 51b3bf8bc61b sys/src/cmd/spin/pangen7.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/src/cmd/spin/pangen7.h	Wed Nov 22 00:21:47 2017 -0800
@@ -0,0 +1,2413 @@
+/***** spin: pangen7.h *****/
+
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
+
+static const char *pan_par[] = {	/* generates pan.p */
+	"#include <sys/ipc.h>",
+	"#include <sys/shm.h>",
+	"#include <time.h>",	/* for nanosleep */
+	"#include <assert.h>",
+	"#include <limits.h>",
+	"#ifdef BFS_DISK",
+	"#include <unistd.h>",		/* for rmdir */
+	"#include <sys/stat.h>",	/* for mkdir */
+	"#include <sys/types.h>",
+	"#include <fcntl.h>",		/* for open */
+	"#endif",
+	"",
+	"#define Max(a,b)	(((a)>(b))?(a):(b))",
+	"#ifndef WAIT_MAX",
+	"	#define WAIT_MAX	2	/* seconds */",
+	"#endif",
+	"#define BFS_GEN 	2	/* current and next generation */",
+	"",
+	"typedef struct BFS_Slot BFS_Slot;",
+	"typedef struct BFS_shared BFS_shared;",
+	"typedef struct BFS_data BFS_data;",
+	"",
+	"struct BFS_Slot {",
+	" #ifdef BFS_FIFO",
+	"	enum bfs_types	type;		/* message type */",
+	" #endif",
+	"	BFS_State	*s_data;	/* state data */",
+	" #ifndef BFS_QSZ",
+	"	BFS_Slot	*nxt;		/* linked list */",
+	" #endif",
+	"};",
+	"",
+	"struct BFS_data {",
+	"	double memcnt;",
+	"	double nstates;",
+	"	double nlinks;",
+	"	double truncs;",
+	"	ulong mreached;",
+	"	ulong vsize;",
+	"	ulong memory_left;",
+	"	ulong punted;",
+	"	ulong errors;",
+	"	int   override;	/* after crash, if another proc clears locks */",
+	"};",
+	"",
+	"struct BFS_shared {	/* about 13K for BFS_MAXPROCS=16 and BFS_MAXLOCKS=1028 */",
+	"	volatile ulong	quit;	/* set to signal termination -- one word */",
+	"	volatile ulong	started;",
+	"",
+	"	volatile uchar	sh_owner[BFS_MAXLOCKS];		/* optional */",
+	"#ifdef BFS_CHECK",
+	"	volatile uchar	in_count[BFS_MAXLOCKS];		/* optional */",
+	"#endif",
+	"	volatile int	sh_locks[BFS_MAXLOCKS];",
+	"	volatile ulong	wait_count[BFS_MAXLOCKS];	/* optional */",
+	"",
+	"	volatile BFS_data bfs_data[BFS_MAXPROCS];",
+	"	volatile uchar	bfs_flag[BFS_MAXPROCS]; /* running 0, normal exit 1, abnormal 2 */",
+	"	volatile uchar	bfs_idle[BFS_MAXPROCS]; /* set when all input queues are empty */",
+	"#ifdef BFS_DISK",
+	"	volatile uchar	bfs_out_cnt[BFS_MAXPROCS]; /* set when core writes a state */",
+	"#endif",
+	"",
+	"#ifdef BFS_QSZ",
+	"	#define BFS_NORECYCLE",
+	"	#if BFS_QSZ<=0",
+	"		#error BFS_QSZ must be positive",
+	"	#endif",
+	"	#ifdef BFS_FIFO",
+	"		#error BFS_QSZ cannot be combined with BFS_FIFO",
+	"	#endif",
+	"	#ifdef BFS_DISK",
+	"		#error BFS_QSZ cannot be combined with BFS_DISK",
+	"	#endif",
+	"	volatile BFS_Slot bfsq[BFS_GEN][BFS_MAXPROCS][BFS_MAXPROCS][BFS_QSZ];",
+	"	volatile uint bfs_ix[BFS_GEN][BFS_MAXPROCS][BFS_MAXPROCS];",
+	"#else",
+	"	volatile BFS_Slot *head[BFS_GEN][BFS_MAXPROCS][BFS_MAXPROCS];",
+	"#endif",
+	"",
+	"#ifdef BFS_FIFO",
+	"	volatile BFS_Slot *tail[BFS_GEN][BFS_MAXPROCS][BFS_MAXPROCS];",
+	"	volatile BFS_Slot *dels[BFS_GEN][BFS_MAXPROCS][BFS_MAXPROCS];",
+	"#endif",
+	"#ifdef BFS_LOGMEM",
+	"	volatile ulong logmem[1024];",
+	"#endif",
+	"	volatile ulong mem_left;",
+	"	volatile uchar *allocator;	/* start of shared heap, must be last */",
+	"};",
+	"",
+	"enum bfs_types { EMPTY = 0, STATE, DELETED };",
+	"",
+	"extern volatile uchar *bfs_get_shared_mem(key_t, size_t);",
+	"extern BFS_Slot  * bfs_new_slot(BFS_Trail *);",
+	"extern BFS_Slot  * bfs_prep_slot(BFS_Trail *, BFS_Slot *);",
+	"extern BFS_Slot  * bfs_next(void);",
+	"extern BFS_Slot  * bfs_pack_state(Trail *, BFS_Trail *, int, BFS_Slot *);",
+	"extern SV_Hold   * bfs_new_sv(int);",
+	"#if NRUNS>0",
+	"extern EV_Hold   * bfs_new_sv_mask(int);",
+	"#endif",
+	"extern BFS_Trail * bfs_grab_trail(void);",
+	"extern BFS_Trail * bfs_unpack_state(BFS_Slot *);",
+	"extern int         bfs_all_empty(void);",
+	"extern int         bfs_all_idle(void);",
+	"extern int         bfs_all_running(void);",
+	"extern int         bfs_idle_and_empty(void);",
+	"extern size_t	    bfs_find_largest(key_t);",
+	"",
+	"extern void	bfs_clear_locks(void);",
+	"extern void	bfs_drop_shared_memory(void);",
+	"extern void	bfs_explore_state(BFS_Slot *);",
+	"extern void	bfs_initial_state(void);",
+	"extern void	bfs_mark_done(int);",
+	"extern void	bfs_printf(const char *fmt, ...);",
+	"extern void	bfs_push_state(Trail *, BFS_Trail *, int);",
+	"extern void	bfs_recycle(BFS_Slot *);",
+	"extern void	bfs_release_trail(BFS_Trail *);",
+	"extern void	bfs_run(void);",
+	"extern void	bfs_setup_mem(void);",
+	"extern void	bfs_setup(void);",
+	"extern void	bfs_shutdown(const char *);",
+	"extern void	bfs_statistics(void);",
+	"extern void	bfs_store_state(Trail *, short);",
+	"extern void	bfs_set_toggle(void);",
+	"extern void	bfs_update(void);",
+	"",
+	"#ifdef MA",
+	"	#error cannot combine -DMA with -DBFS_PAR",
+	"	/* would require us to parallelize g_store */",
+	"#endif",
+	"#ifdef BCS",
+	"	#error cannot combine -DBCS with -DBFS_PAR",
+	"#endif",
+	"#ifdef BFS_DISK",
+	"	#ifdef BFS_FIFO",
+	"		#error cannot combine BFS_DISK and BFS_FIFO",
+	"	#endif",
+	"	extern void bfs_disk_start(void);",
+	"	extern void bfs_disk_stop(void);",
+	"	extern void bfs_disk_out(void);",
+	"	extern void bfs_disk_inp(void);",
+	"	extern void bfs_disk_iclose(void);",
+	"	extern void bfs_disk_oclose(void);",
+	"	int bfs_out_fd[BFS_MAXPROCS];",
+	"	int bfs_inp_fd[BFS_MAXPROCS];",
+	"#endif",
+	"",
+	"static BFS_shared *shared_memory;",
+	"#ifndef BFS_QSZ",
+	"static BFS_Slot   *bfs_free_slot; /* local free list */",
+	"#endif",
+	"static BFS_Slot    bfs_null;",
+	"static SV_Hold    *bfs_svfree[VECTORSZ];",
+	"static uchar	*bfs_heap;	/* local pointer into heap */",
+	"static ulong	bfs_left;	/* local part of shared heap */",
+	"#if NRUNS>0",
+	"static void	bfs_keep(EV_Hold *);",
+	"#endif",
+	"static long	bfs_sent;	/* nr msgs sent -- local to each process */",
+	"static long	bfs_rcvd;	/* nr msgs rcvd */",
+	"static long	bfs_sleep_cnt;	/* stats */",
+	"static long	bfs_wcount;",
+	"static long	bfs_gcount;",
+	"static ulong	bfs_total_shared;",
+	"#ifdef BFS_STAGGER",
+	" static int	bfs_stage_cnt = 0;",
+	" static void	bfs_stagger_flush(void);",
+	"#endif",
+	"static int	bfs_toggle;	/* local variable, 0 or 1 */",
+	"static int	bfs_qscan;	/* scan input queues in order */",
+	"static ulong	bfs_snapped;",
+	"static int	shared_mem_id;",
+	"#ifndef NOREDUCE",
+	"static int	bfs_nps;	/* no preselection */",
+	"#endif",
+	"ulong	bfs_punt;	/* states dropped for lack of memory */",
+	"#if defined(VERBOSE) || defined(BFS_CHECK)",
+	"static const char *bfs_sname[] = {",
+	"	\"EMPTY\",	/* 0 */",
+	"	\"STATE\",	/* 1 */",
+	"	\"STATE\",	/* 2 = DELETED */",
+	"	0",
+	"};",
+	"#endif",
+	"static const char *bfs_lname[] = { /* match values defined in pangen2.c */",
+	"	\"global lock\",	/* BFS_GLOB  */",
+	"	\"ordinal\",		/* BFS_ORD  */",
+	"	\"shared memory\",	/* BFS_MEM   */",
+	"	\"print to stdout\",	/* BFS_PRINT */",
+	"	\"hashtable\",		/* BFS_STATE */",
+	"	0",
+	"};",
+	"",
+	"static ulong bfs_count[DELETED+1];	/* indexed with bfs_types: EMPTY=0, STATE=1, DELETED=2 */",
+	"",
+	"static int bfs_keep_state;",
+	"",
+	"int Cores = 1;",
+	"int who_am_i = 0;	/* root */",
+	"",
+	"#ifdef L_BOUND",
+	"	int L_bound = L_BOUND;",
+	"#endif",
+	"",
+	"#ifdef BFS_CHECK",
+	"void",
+	"bfs_dump_now(char *s)",
+	"{	int i; char *p = (char *) &now;",
+	"",
+	"	e_critical(BFS_PRINT);",
+	"	printf(\"%%s\\t\", s);",
+	"	printf(\"%%3lu: \", vsize);",
+	"	for (i = 0; i < vsize; i++)",
+	"	{	printf(\"%%3d \", *p++);",
+	"	}",
+	"	printf(\"	%%s\\noffsets:\\t\", s);",
+	"	for (i = 0; i < now._nr_pr; i++)",
+	"	{	printf(\"%%3d \", proc_offset[i]);",
+	"	}",
+	"	printf(\"\\n\");",
+	"	x_critical(BFS_PRINT);",
+	"}",
+	"",
+	"void",
+	"view_state(char *s)	/* debugging */",
+	"{	int i;",
+	"	char *p;",
+	"	e_critical(BFS_PRINT);",
+	"	printf(\"cpu%%02d %%s: \", who_am_i, s);",
+	"	p = (char *)&now;",
+	"	for (i = 0; i < vsize; i++)",
+	"		printf(\"%%3d, \", *p++);",
+	"	printf(\"\\n\"); fflush(stdout);",
+	"	x_critical(BFS_PRINT);",
+	"}",
+	"#endif",
+	"",
+	"void",
+	"bfs_main(int ncores, int cycles)",
+	"{",
+	"	if (cycles)",
+	"	{	fprintf(stderr, \"pan: cycle detection is not supported in this mode\\n\");",
+	"		exit(1);",
+	"	}",
+	"",
+	"	if (ncores == 0)	/* i.e., find out */",
+	"	{	FILE *fd;",
+	"		char buf[512];",
+	"		if ((fd = fopen(\"/proc/cpuinfo\", \"r\")) == NULL)",
+	"		{	/* cannot tell */",
+	"			ncores = Cores; /* use the default */",
+	"		} else",
+	"		{	while (fgets(buf, sizeof(buf), fd))",
+	"			{	if (strncmp(buf, \"processor\", strlen(\"processor\")) == 0)",
+	"				{	ncores++;",
+	"			}	}",
+	"			fclose(fd);",
+	"			ncores--;",
+	"			if (verbose)",
+	"			{	printf(\"pan: %%d available cores\\n\", ncores+1);",
+	"	}	}	}",
+	"	if (ncores >= BFS_MAXPROCS)",
+	"	{	Cores = BFS_MAXPROCS-1; /* why -1? */",
+	"	} else if (ncores <  1)",
+	"	{	Cores = 1;",
+	"	} else",
+	"	{	Cores = ncores;",
+	"	}",
+	"	printf(\"pan: using %%d core%%s\\n\", Cores, (Cores>1)?\"s\":\"\");",
+	"	fflush(stdout);",
+	"#ifdef BFS_DISK",
+	"	bfs_disk_start();",	/* create .spin */
+	"#endif",
+	"	bfs_setup();	/* shared memory segments and fork */",
+	"	bfs_run();",
+	"	if (who_am_i == 0)",
+	"	{	stop_timer(0);",
+	"	}",
+	"	bfs_statistics();",
+	"	bfs_mark_done(1);",
+	"	if (who_am_i == 0)",
+	"	{	report_time();",
+	"#ifdef BFS_DISK",
+	"		bfs_disk_stop();",
+	"#endif",
+	"	}",
+	"#ifdef C_EXIT",
+	"	C_EXIT; /* trust that it defines a fct */",
+	"#endif",
+	"	bfs_drop_shared_memory();",
+	"	exit(0);",
+	"}",
+	"",
+	"void",
+	"bfs_setup_mem(void)",
+	"{	size_t n;",
+	"	key_t key;",
+	"#ifdef BFS_FIFO",
+	"	bfs_null.type = EMPTY;",
+	"#endif",
+	"	ntrpt = (Trail *) emalloc(sizeof(Trail));", /* just once */
+	"",
+	"	if ((key = ftok(\".\", (int) 'L')) == -1)",
+	"	{	perror(\"ftok shared memory\");",
+	"		exit(1);",
+	"	}",
+	"	n = bfs_find_largest(key);",
+	"	bfs_total_shared = (ulong) n;",
+	"",
+	"	shared_memory            = (BFS_shared *) bfs_get_shared_mem(key, n);	/* root */",
+	"	shared_memory->allocator = (uchar *) shared_memory + sizeof(BFS_shared);",
+	"	shared_memory->mem_left  = (ulong) (n - sizeof(BFS_shared));",
+	"}",
+	"",
+	"ulong bfs_LowLim;",
+	"#ifndef BFS_RESERVE",
+	"	#define BFS_RESERVE 5",
+	/* keep memory on global heap in reserve for first few cores */
+	/* that run out of their local allocation of shared mem */
+	/* 1~50 percent, 2~30 percent, 5~20 percent, >Cores=none */
+	"#else",
+	"	#if BFS_RESERVE<1",
+	"	#error BFS_RESERVE must be at least 1",
+	"	#endif",
+	"#endif",
+	"",
+	"void",
+	"bfs_setup(void)	/* executed by root */",
+	"{	int i, j;",
+	"	ulong n;	/* share of shared memory allocated to each core */",
+	"",
+	"	n = shared_memory->mem_left / (Cores + Cores/(BFS_RESERVE)); /* keep some reserve */",
+	"",
+	"	if ((n%%sizeof(void *)) != 0)",
+	"	{       n -= (n%%sizeof(void *)); /* align, without exceeding total */",
+	"	}",
+	"	for (i = 0; i < Cores-1; i++)",
+	"	{	j = fork();",
+	"		if (j == -1)",
+	"		{	bfs_printf(\"fork failed\\n\");",
+	"			exit(1);",
+	"		}",
+	"		if (j == 0)",
+	"		{	who_am_i = i+1;	/* 1..Cores-1 */",
+	"			break;",
+	"	}	}",
+	"",
+	"	e_critical(BFS_MEM);",
+	"	 bfs_heap = (uchar *) shared_memory->allocator;",
+	"	 shared_memory->allocator += n;",
+	"	 shared_memory->mem_left  -= n;",
+	"	x_critical(BFS_MEM);",
+	"",
+	"	bfs_left = n;",
+	"	bfs_runs = 1;",
+	"	bfs_LowLim = n / (2 * (ulong) Cores);", /* 50% */
+	"}",
+	"",
+	"void",
+	"bfs_run(void)",
+	"{	BFS_Slot *v;",
+	"",
+	"#ifdef BFS_DISK",
+	"	bfs_disk_out();",	/* create outqs */
+	"#endif",
+	"	if (who_am_i == 0)",
+	"	{	bfs_initial_state();",
+	"	}",
+	"#ifdef BFS_DISK",
+	"	#ifdef BFS_STAGGER",
+	"	bfs_stagger_flush();",
+	"	#endif",
+	"	bfs_disk_oclose();",	/* sync and close outqs */
+	"#endif",
+	"#ifdef BFS_FIFO",
+	"	static int i_count;",
+	"#endif",
+	"",
+	"	srand(s_rand+HASH_NR);",
+	"	bfs_qscan = 0;",
+	"	bfs_toggle = 1 - bfs_toggle; /* after initial state */",
+	"	e_critical(BFS_GLOB);",
+	"	 shared_memory->started++;",
+	"	x_critical(BFS_GLOB);",
+	"",
+	"	while (shared_memory->started != Cores)	/* wait for all cores to connect */",
+	"	{	usleep(1);",
+	"	}",
+	"",
+	"#ifdef BFS_DISK",
+	"	bfs_disk_out();",
+	"	bfs_disk_inp();",
+	"#endif",
+	"",
+	"	start_timer();",
+	"	while (shared_memory->quit == 0)",
+	"	{	v = bfs_next(); /* get next message from current generation */",
+	"		if (v->s_data) /* v->type == STATE || v->type == DELETED */",
+	"		{	bfs_count[STATE]++;",
+	"#ifdef VERBOSE",
+	"			bfs_printf(\"GOT STATE (depth %%d, nr %%u)\\n\",",
+	"				v->s_data->t_info->o_tt, v->s_data->nr);",
+	"#endif",
+	"			/* last resort: start dropping states when out of memory */",
+	"			if (bfs_left > 1024 || shared_memory->mem_left > 1024)",
+	"			{	bfs_explore_state(v);",
+	"			} else",
+	"			{	static int warned_loss = 0;",
+	"				if (warned_loss == 0 && who_am_i == 0)",
+	"				{	warned_loss++;",
+	"					bfs_printf(\"out of shared memory - losing states\\n\");",
+	"				}",
+	"				bfs_punt++;",
+	"			}",
+	"#if !defined(BFS_FIFO) && !defined(BFS_NORECYCLE)",
+	"			bfs_recycle(v);",
+	"#endif",
+	"#ifdef BFS_FIFO",
+	"			i_count = 0;",
+	"#endif",
+	"		} else",
+	"		{	bfs_count[EMPTY]++;",
+	"#if defined(BFS_FIFO) && defined(BFS_CHECK)",
+	"			assert(v->type == EMPTY);",
+	"#endif",
+	"#ifdef BFS_FIFO",
+	"			if (who_am_i == 0)",
+	"			{	if (bfs_idle_and_empty())",
+	"				{	if (i_count++ > 10)",
+	"					{	shared_memory->quit = 1;",
+	"					}",
+	"					else usleep(1);",
+	"				}",
+	"			} else if (!bfs_all_running())",
+	"			{	bfs_shutdown(\"early termination\");",
+	"			}",
+	"#else",
+	"			if (who_am_i == 0)",
+	"			{	if (bfs_all_idle())		/* wait for it */",
+	"				{	if (!bfs_all_empty())	/* more states to process */",
+	"					{	bfs_set_toggle();",
+	"						goto do_toggle;",
+	"					} else			/* done */",
+	"					{	shared_memory->quit = 1; /* step 4 */",
+	"					}",
+	"				} else",
+	"				{	bfs_sleep_cnt++;",
+	"				}",
+	"			} else",
+	"			{	/* wait for quit or idle bit to be reset by root */",
+	"				while (shared_memory->bfs_idle[who_am_i] == 1",
+	"				&&     shared_memory->quit == 0)",
+	"				{	if (bfs_all_running())",
+	"					{	bfs_sleep_cnt++;",
+	"						usleep(10);	/* new 6.2.3 */",
+	"					} else",
+	"					{	bfs_shutdown(\"early termination\");",
+	"						/* no return */",
+	"				}	}",
+	"do_toggle:			bfs_qscan = 0;",
+	"#ifdef BFS_DISK",
+	"				bfs_disk_iclose();",
+	"				bfs_disk_oclose();",
+	"#endif",
+	"				bfs_toggle = 1 - bfs_toggle;",
+	"#ifdef BFS_DISK",
+	"				bfs_disk_out();",
+	"				bfs_disk_inp();",
+	"#endif",
+	"	#ifdef BFS_CHECK",
+	"				bfs_printf(\"toggle: recv from %%d, send to %%d\\n\",",
+	"					bfs_toggle, 1 - bfs_toggle);",
+	"	#endif",
+	"			}",
+	"#endif",
+	"	}	}",
+	"#ifdef BFS_CHECK",
+	"	bfs_printf(\"done, sent %%5ld recvd %%5ld punt %%5lu sleep: %%ld\\n\",",
+	"		bfs_sent, bfs_rcvd, bfs_punt, bfs_sleep_cnt);",
+	"#endif",
+	"}",
+	"",
+	"void",
+	"bfs_report_mem(void)	/* called from within wrapup() */",
+	"{",
+	"	printf(\"%%9.3f	total shared memory usage\\n\\n\",",
+	"		((double) bfs_total_shared - (double) bfs_left)/(1024.*1024.));",
+	"}",
+	"",
+	"void",
+	"bfs_statistics(void)",
+	"{",
+	"	#ifdef VERBOSE",
+	"	enum bfs_types i;",
+	"	#endif",
+	"	if (verbose)",
+	"		bfs_printf(\"states sent %%7ld recvd %%7ld stored %%8g sleeps: %%4ld, %%4ld, %%ld\\n\",",
+	"			bfs_sent, bfs_rcvd, nstates, bfs_wcount, bfs_gcount, bfs_sleep_cnt);",
+	"	if (0) bfs_printf(\"states punted %%7lu\\n\", bfs_punt);",
+	"	#ifdef VERBOSE",
+	"	for (i = EMPTY; i <= DELETED; i++)",
+	"	{	if (bfs_count[i] > 0)",
+	"		{	bfs_printf(\"%%6s	%%8lu\\n\",",
+	"				bfs_sname[i], bfs_count[i]);",
+	"	}	}",
+	"	#endif",
+	"	bfs_update();",
+	"",
+	"	if (who_am_i == 0 && shared_memory)",
+	"	{	int i; ulong count = 0L;",
+	"		done = 1;",
+	"",
+	"		e_critical(BFS_PRINT);",
+	"		  wrapup();",
+	"		  if (verbose)",
+	"		  {	  printf(\"\\nlock-wait counts:\\n\");",
+	"	 	  	for (i = 0; i < BFS_STATE; i++)",
+	"	 			printf(\"%%16s  %%9lu\\n\",",
+	"					bfs_lname[i], shared_memory->wait_count[i]);",
+	"#ifndef BITSTATE",
+	"		  	for (i = BFS_STATE; i < BFS_MAXLOCKS; i++)",
+	"		  	{	if (0)",
+	"				printf(\"	[%%6d]  %%9lu\\n\",",
+	"					i, shared_memory->wait_count[i]);",
+	"				count += shared_memory->wait_count[i];",
+	"		  	}",
+	"	 	  	printf(\"%%16s  %%9lu (avg per region)\\n\",",
+	"				bfs_lname[BFS_STATE], count/(BFS_MAXLOCKS - BFS_STATE));",
+	"#endif",
+	"		  }",
+	"		  fflush(stdout);",
+	"		x_critical(BFS_PRINT);",
+	"	}",
+	"}",
+	"",
+	"void",
+	"bfs_snapshot(void)",
+	"{	clock_t stop_time;",
+	"	double delta_time;",
+	"	struct tms stop_tm;",
+	"	volatile BFS_data *s;",
+	"",
+	"	e_critical(BFS_PRINT);",
+	"	 printf(\"cpu%%02d Depth= %%7lu States= %%8.3g Transitions= %%8.3g \",",
+	"		who_am_i, mreached, nstates, nstates+truncs);",
+	"	 printf(\"Memory= %%9.3f\\t\", memcnt/1048576.);",
+	"	 printf(\"SharedMLeft= %%4lu \", bfs_left/1048576);",
+	"	 stop_time  = times(&stop_tm);",
+	"	 delta_time = ((double) (stop_time - start_time))/((double) sysconf(_SC_CLK_TCK));",
+	"	 if (delta_time > 0.01)",
+	"	 {	printf(\"t= %%6.3g R= %%6.0g\\n\", delta_time, nstates/delta_time);",
+	"	 } else",
+	"	 {	printf(\"t= %%6.3g R= %%6.0g\\n\", 0., 0.);",
+	"	 }",
+	"	 fflush(stdout);",
+	"	x_critical(BFS_PRINT);",
+	"",
+	"	s = &shared_memory->bfs_data[who_am_i];",
+	"	s->mreached = (ulong) mreached;",
+	"	s->vsize    = (ulong) vsize;",
+	"	s->errors   = (int) errors;",
+	"	s->memcnt   = (double) memcnt;",
+	"	s->nstates  = (double) nstates;",
+	"	s->nlinks   = (double) nlinks;",
+	"	s->truncs   = (double) truncs;",
+	"	s->memory_left = (ulong) bfs_left;",
+	"	s->punted      = (ulong) bfs_punt;",
+	"	bfs_snapped++; /* for bfs_best */",
+	"}",
+	"",
+	"void",
+	"bfs_shutdown(const char *s)",
+	"{",
+	"	bfs_clear_locks(); /* in case we interrupted at a bad point */",
+	"	if (!strstr(s, \"early \") || verbose)",
+	"	{	bfs_printf(\"stop (%%s)\\n\", s);",
+	"	}",
+	"	bfs_update();",
+	"	if (who_am_i == 0)",
+	"	{	wrapup();",
+	"#ifdef BFS_DISK",
+	"		bfs_disk_stop();",
+	"#endif",
+	"	}",
+	"	bfs_mark_done(2);",
+	"	pan_exit(2);",
+	"}",
+	"",
+	"SV_Hold *bfs_free_hold;",
+	"",
+	"SV_Hold *",
+	"bfs_get_hold(void)",
+	"{	SV_Hold *x;",
+	"	if (bfs_free_hold)",
+	"	{	x = bfs_free_hold;",
+	"		bfs_free_hold = bfs_free_hold->nxt;",
+	"	} else",
+	"	{	x = (SV_Hold *) sh_malloc((ulong) sizeof(SV_Hold));",
+	"	}",
+	"	return x;",
+	"}",
+	"",
+	"BFS_Trail *",
+	"bfs_unpack_state(BFS_Slot *n)		/* called in bfs_explore_state */",
+	"{	BFS_Trail *otrpt;",
+	"	BFS_State *bfs_t;",
+	"	int vecsz;",
+	"",
+	"	if (!n || !n->s_data || !n->s_data->t_info)",
+	"	{	bfs_Uerror(\"internal error\");",
+	"	}",
+	"	otrpt = (BFS_Trail *) ((BFS_State *) n->s_data)->t_info;",
+	"",
+	"	trpt->ostate = otrpt->ostate;",
+	"	trpt->st     = otrpt->st;",
+	"	trpt->o_tt   = otrpt->o_tt;",
+	"	trpt->pr     = otrpt->pr;",
+	"	trpt->tau    = otrpt->tau;",
+	"	trpt->o_pm   = otrpt->o_pm;",
+	"	if (trpt->ostate)",
+	"	trpt->o_t    = t_id_lkup[otrpt->t_id];",
+	"#if defined(C_States) && (HAS_TRACK==1)",
+	"	c_revert((uchar *) &(now.c_state[0]));",
+	"#endif",
+	"	if (trpt->o_pm & 4)			/* rv succeeded */",
+	"	{	return (BFS_Trail *) 0;		/* revisit not needed */",
+	"	}",
+	"#ifndef NOREDUCE",
+	"	bfs_nps = 0;",
+	"#endif",
+	"	if (trpt->o_pm & 8)			/* rv attempt failed */",
+	"	{	revrv++;",
+	"		if (trpt->tau&8)",
+	"		{	trpt->tau &= ~8;	/* break atomic */",
+	"#ifndef NOREDUCE",
+	"		} else if (trpt->tau&32)	/* void preselection */",
+	"		{	trpt->tau &= ~32;",
+	"			bfs_nps = 1;		/* no preselection in repeat */",
+	"#endif",
+	"	}	}",
+	"	trpt->o_pm &= ~(4|8);",
+	"	if (trpt->o_tt > mreached)",
+	"	{	static ulong nr = 0L, nc;",
+	"		mreached = trpt->o_tt;",
+	"		nc = (long) nstates/FREQ;",
+	"		if (nc > nr)",
+	"		{	nr = nc;",
+	"			bfs_snapshot();",
+	"	}	}",
+	"	depth = trpt->o_tt;",
+	"	if (depth >= maxdepth)",
+	"	{",
+	"#if SYNC",
+	"		if (boq != -1)",
+	"		{	BFS_Trail *x = (BFS_Trail *) trpt->ostate;",
+	"			if (x) x->o_pm |= 4; /* rv not failing */",
+	"		}",
+	"#endif",
+	"		truncs++;",
+	"		if (!warned)",
+	"		{	warned = 1;",
+	"			bfs_printf(\"error: max search depth too small\\n\");",
+	"		}",
+	"		if (bounded)",
+	"		{	bfs_uerror(\"depth limit reached\");",
+	"		}",
+	"		return (BFS_Trail *) 0;",
+	"	}",
+	"",
+	"	bfs_t = n->s_data;",
+	"#if NRUNS>0",
+	"	vsize = bfs_t->omask->sz;",
+	"#else",
+	"	vsize = ((State *) (bfs_t->osv))->_vsz;",
+	"#endif",
+	"#if SYNC",
+	"	boq   = bfs_t->boq;",
+	"#endif",
+	"",
+	"#if defined(Q_PROVISO) && !defined(BITSTATE) && defined(FULLSTACK)",
+	"	#ifdef USE_TDH",
+	"		if (((uchar *)(bfs_t->lstate)))		/* if BFS_INQ is set */",
+	"		{	*((uchar *) bfs_t->lstate) = 0;	/* turn it off */",
+	"		}",
+	"	#else",
+	"		if (bfs_t->lstate)			/* bfs_par */",
+	"		{	bfs_t->lstate->tagged = 0;	/* bfs_par state removed from q */",
+	"		}",
+	"	#endif",
+	"#endif",
+	"	memcpy((char *) &now, (uchar *) bfs_t->osv, vsize);",
+	"#if !defined(NOCOMP) && !defined(HC) && NRUNS>0",
+	"	Mask = (uchar *) bfs_t->omask->sv;	/* in shared memory */",
+	"#endif",
+	"#ifdef BFS_CHECK",
+	"	if (0) bfs_dump_now(\"got1\");",
+	"#endif",
+	"#ifdef TRIX",
+	"	re_populate();",
+	"#else",
+	"	#if NRUNS>0",
+	"		if (now._nr_pr > 0)",
+	"		{",
+	"		#if VECTORSZ>32000",
+	"			proc_offset = (int *) bfs_t->omask->po;",
+	"		#else",
+	"			proc_offset = (short *) bfs_t->omask->po;",
+	"		#endif",
+	"			proc_skip   = (uchar *) bfs_t->omask->ps;",
+	"		}",
+	"		if (now._nr_qs > 0)",
+	"		{",
+	"		#if VECTORSZ>32000",
+	"			q_offset = (int *) bfs_t->omask->qo;",
+	"		#else",
+	"			q_offset = (short *) bfs_t->omask->qo;",
+	"		#endif",
+	"			q_skip   = (uchar *) bfs_t->omask->qs;",
+	"		}",
+	"	#endif",
+	"#endif",
+	"	vecsz = ((State *) bfs_t->osv)->_vsz;",
+	"#ifdef BFS_CHECK",
+	"	assert(vecsz > 0 && vecsz < VECTORSZ);",
+	"#endif",
+	"	{ SV_Hold *x = bfs_get_hold();",
+	"		x->sv  = bfs_t->osv;",
+	"		x->nxt = bfs_svfree[vecsz];",
+	"		bfs_svfree[vecsz] = x;",
+	"		bfs_t->osv = (State *) 0;",
+	"	}",
+	"#if NRUNS>0",
+	"	bfs_keep(bfs_t->omask);",
+	"#endif",
+	"",
+	"#ifdef BFS_CHECK",
+	"	if (0) bfs_dump_now(\"got2\");",
+	"	if (0) view_state(\"after\");",
+	"#endif",
+	"	return (BFS_Trail *) bfs_t->t_info;",
+	"}",
+	"void",
+	"bfs_initial_state(void)",
+	"{",
+	"#ifdef BFS_CHECK",
+	"	assert(trpt != NULL);",
+	"#endif",
+	"	trpt->ostate = (H_el *) 0;",
+	"	trpt->o_tt   = -1;",
+	"	trpt->tau    = 0;",
+	"#ifdef VERI",
+	"	trpt->tau |= 4;	/* claim moves first */",
+	"#endif",
+	"	bfs_store_state(trpt, boq);	/* initial state : bfs_lib.c */",
+	"}",
+	"",
+	"#ifdef BITSTATE",
+	"		#define bfs_do_store(v, n) b_store(v, n)",
+	"#else",
+	"	#ifdef USE_TDH",
+	"		#define bfs_do_store(v, n) o_store(v, n)",
+	"	#else",
+	"		#define bfs_do_store(v, n) h_store(v, n)",
+	"	#endif",
+	"#endif",
+	"",
+	"#ifdef BFS_SEP_HASH",
+	"int",
+	"bfs_seen_before(void)",
+	"{	/* cannot set trpt->tau |= 64 to mark successors outside stack */",
+	"	/* since the check is done remotely and the trpt value is gone */",
+	" #ifdef VERI",
+	"	if (!trpt->ostate		/* initial state */",
+	"	|| ((trpt->tau&4)		/* starting claim moves(s) */",
+	"	&& !(((BFS_Trail *)trpt->ostate)->tau&4))) /* prev move: prog */",
+	"	{	return 0; /* claim move: mid-state not stored */",
+	"	} /* else */",
+	" #endif",
+	"	if (!bfs_do_store((char *)&now, vsize))	/* sep_hash */",
+	"	{	nstates++;		/* local count */",
+	"		return 0;		/* new state */",
+	"	}",
+	" #ifdef BFS_CHECK",
+	"	bfs_printf(\"seen before\\n\");",
+	" #endif",
+	"	truncs++;",
+	"	return 1;			/* old state */",
+	"}",
+	"#endif",
+	"",
+	"void",
+	"bfs_explore_state(BFS_Slot *v)		/* generate all successors of v */",
+	"{	BFS_Trail *otrpt;",
+	"	Trans *t;",
+	"#ifdef HAS_UNLESS",
+	"	int E_state;",
+	"#endif",
+	"	int tt;",
+	"	short II, To = BASE, From = (short) (now._nr_pr-1);",
+	"	short oboq = boq;",
+	"	uchar _n, _m, ot;",
+	"",
+	"	memset(ntrpt, 0, sizeof(Trail));",
+	"	otrpt = bfs_unpack_state(v); /* BFS_Trail */",
+	"",
+	"	if (!otrpt) { return; } /* e.g., depth limit reached */",
+	"#ifdef L_BOUND",
+	"	#if defined(VERBOSE)",
+	"	bfs_printf(\"Unpacked state with l_bound %%d -- sds %%p\\n\",",
+	"		now._l_bnd, now._l_sds);",
+	"	#endif",
+	"#endif",
+	"",
+	"#if defined(C_States) && (HAS_TRACK==1)",
+	"	c_revert((uchar *) &(now.c_state[0]));",
+	"#endif",
+	"",
+	"#ifdef BFS_SEP_HASH",
+	"	if (bfs_seen_before()) return;",
+	"#endif",
+	"",
+	"#ifdef VERI",	/* could move to just before store_state */
+	"	if (now._nr_pr == 0	/* claim terminated */",
+	"	||  stopstate[((Pclaim *)pptr(0))->_t][((Pclaim *)pptr(0))->_p])",
+	"	{	bfs_uerror(\"end state in claim reached\");",
+	"	}",
+	"#endif",
+	"	trpt->tau &= ~1;	/* timeout off */",
+	"#ifdef VERI",
+	"	if (trpt->tau&4)	/* claim move */",
+	"	{	trpt->tau |= (otrpt->tau)&1; /* inherit from prog move */",
+	"		From = To = 0;	/* claim */",
+	"		goto Repeat_two;",
+	"	}",
+	"#endif",
+	"#ifndef NOREDUCE",
+	"	if (boq == -1 && !(trpt->tau&8) && bfs_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)",
+	"		{	t = trans[ot][tt];",
+	"			if (t->qu[0] != 0)",
+	"			{	if (!q_cond(II, t))",
+	"					continue;",
+	"			}",
+	"			From = To = II;",
+	"			trpt->tau |= 32; /* preselect marker */",
+	"	#ifdef VERBOSE",
+	"			bfs_printf(\"%%3ld: proc %%d PreSelected (tau=%%d)\\n\", ",
+	"				depth, II, trpt->tau);",
+	"	#endif",
+	"			goto Repeat_two;",
+	"	}	}",
+	"	trpt->tau &= ~32;",
+	"#endif",
+	"",
+	"Repeat_one:",
+	"	if (trpt->tau&8)",
+	"	{	From = To = (short ) trpt->pr;	/* atomic */",
+	"	} else",
+	"	{	From = now._nr_pr-1;",
+	"		To = BASE;",
+	"	}",
+	"#if defined(VERI) || !defined(NOREDUCE) || defined(ETIM)",
+	"Repeat_two: /* MainLoop */",
+	"#endif",
+	"	_n = _m = 0;",
+	"	for (II = From; II >= To; II -= 1)	/* all processes */",
+	"	{",
+	"#ifdef BFS_CHECK",
+	"		bfs_printf(\"proc %%d (%%d - %%d)\\n\", II, From, To);",
+	"#endif",
+	"#if SYNC	",
+	"		if (boq != -1 && trpt->pr == II)",
+	"		{	continue;	/* no rendezvous with same proc */",
+	"		}",
+	"#endif",
+	"		this = pptr(II);",
+	"		tt = (int) ((P0 *)this)->_p;",
+	"		ot = (uchar) ((P0 *)this)->_t;",
+	"		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_PRIORITY",
+	"		if (!highest_priority(((P0 *)this)->_pid, II, t))",
+	"		{	continue;",
+	"		}",
+	"#else",
+	"	#ifdef HAS_PROVIDED",
+	"		if (!provided(II, ot, tt, t))",
+	"		{	continue;",
+	"		}",
+	"	#endif",
+	"#endif",
+	"#ifdef HAS_UNLESS",
+	"		E_state = 0;",
+	"#endif",
+	"		for (t = trans[ot][tt]; t; t = t->nxt)	/* all process transitions */",
+	"		{",
+	"#ifdef BFS_CHECK",
+	"			assert(t_id_lkup[t->t_id] == t); /* for reverse lookup in bfs_unpack_state */",
+	"#endif",
+	"#ifdef VERBOSE",
+	"			if (0) bfs_printf(\"\\tproc %%d tr %%d\\n\", II, t->forw);",
+	"#endif",
+	"#ifdef HAS_UNLESS",
+	"			if (E_state > 0",
+	"			&&  E_state != t->e_trans)",
+	"				break;",
+	"#endif",
+	"			/* trpt->o_t = */ 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 VERBOSE",
+	"			e_critical(BFS_PRINT);",
+	"			printf(\"%%3ld: 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);",
+	"			x_critical(BFS_PRINT);",
+	"#endif",
+	"#ifdef HAS_UNLESS",
+	"			E_state = t->e_trans;",
+	"	#if SYNC>0",
+	"			if (t->e_trans > 0 && boq != -1)",
+	"			{ fprintf(efd, \"error:	rendezvous stmnt in the escape clause\\n\");",
+	"			  fprintf(efd, \"	of unless stmnt not compatible with -DBFS\\n\");",
+	"			  pan_exit(1);",
+	"			}",
+	"	#endif",
+	"#endif",
+	"			if (t->st > 0)",
+	"			{	((P0 *)this)->_p = t->st;",
+	"			}",
+	"			/* use the ostate ptr, with type *H_el, to temporarily store *BFS_Trail */",
+	"#ifdef BFS_NOTRAIL",
+	"			ntrpt->ostate = (H_el *) 0;	/* no error-traces in this mode */",
+	"#else",
+	"			ntrpt->ostate = (H_el *) otrpt;	/* parent stackframe */",
+	"#endif",
+	"		/*	ntrpt->st = tt;		* was already set above */",
+	"",
+	"			if (boq == -1 && (t->atom&2))	/* atomic */",
+	"			{	ntrpt->tau = 8;		/* record for next move */",
+	"			} else",
+	"			{	ntrpt->tau = 0;		/* no timeout or preselect etc */",
+	"			}",
+	"#ifdef VERI",
+	"			ntrpt->tau |= trpt->tau&4;	/* if claim, inherit */",
+	"			if (boq == -1 && !(ntrpt->tau&8))	/* unless rv or atomic */",
+	"			{	if (ntrpt->tau&4)	/* claim */",
+	"				{	ntrpt->tau &= ~4; /* switch to prog */",
+	"				} else",
+	"				{	ntrpt->tau |=  4; /* switch to claim */",
+	"			}	}",
+	"#endif",
+	"#ifdef L_BOUND",
+	"			{  uchar obnd = now._l_bnd;",
+	"			   uchar *os  = now._l_sds;",
+	"	#ifdef VERBOSE",
+	"			   bfs_printf(\"saving bound %%d -- sds %%p\\n\", obnd, (void *) os);",
+	"	#endif",
+	"#endif",
+	"",
+	"			   bfs_store_state(ntrpt, oboq);",
+	"#ifdef EVENT_TRACE",
+	"			   now._event = trpt->o_event;",
+	"#endif",
+	"			   /* undo move and generate other successor states */",
+	"			   trpt++;	/* this is where ovals and ipt are set */",
+	"			   do_reverse(t, II, _m);	/* restore now. */",
+	"#ifdef L_BOUND",
+	"	#ifdef VERBOSE",
+	"			   bfs_printf(\"restoring bound %%d -- sds %%p\\n\", obnd, (void *) os);",
+	"	#endif",
+	"			   now._l_bnd = obnd;",
+	"			   now._l_sds = os;",
+	"			}",
+	"#endif",
+	"			trpt--;",
+	"#ifdef VERBOSE",
+	"			e_critical(BFS_PRINT);",
+	"			printf(\"%%3ld: 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, 0);",
+	"			printf(\"tau=%%d,%%d]\\n\", trpt->tau, (trpt-1)->tau);",
+	"			x_critical(BFS_PRINT);",
+	"#endif",
+	"			reached[ot][t->st] = 1;",
+	"			reached[ot][tt]    = 1;",
+	"",
+	"			((P0 *)this)->_p = tt;",
+	"			_n |= _m;",
+	"	}	}",
+	"#ifdef VERBOSE",
+	"	bfs_printf(\"done _n = %%d\\n\", _n);",
+	"#endif",
+	"",
+	"#ifndef NOREDUCE",
+	"	/* preselected - no succ definitely outside stack */",
+	"	if ((trpt->tau&32) && !(trpt->tau&64))",
+	"	{	From = now._nr_pr-1; To = BASE;",
+	"	#ifdef VERBOSE",
+	"		bfs_printf(\"%%3ld: 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 Repeat_two;",
+	"	}",
+	"	trpt->tau &= ~(32|64);",
+	"#endif",
+	"	if (_n == 0",
+	"#ifdef VERI",
+	"	&& !(trpt->tau&4)",
+	"#endif",
+	"	)",
+	"	{	/* no successor states generated */",
+	"		if (boq != -1)				/* was rv move */",
+	"		{	BFS_Trail *x = (BFS_Trail *) trpt->ostate; /* pre-rv state */",
+	"			if (x && ((x->tau&8) || (x->tau&32))) /* break atomic or preselect */",
+	"			{	x->o_pm |= 8;		/* mark failure */",
+	"				this = pptr(otrpt->pr);",
+	"				((P0 *) this)->_p = otrpt->st;	/* reset state */",
+	"				unsend(boq);		/* retract rv offer */",
+	"				boq = -1;",
+	"#ifdef VERBOSE",
+	"				printf(\"repush state\\n\");",
+	"#endif",
+	"				bfs_push_state(NULL, x, x->o_tt); /* repush rv fail */",
+	"			} /* else the rv need not be retried */",
+	"		} else if (now._nr_pr > BASE)		/* possible deadlock */",
+	"		{	if ((trpt->tau&8))		/* atomic step blocked */",
+	"			{	trpt->tau &= ~(1|8);	/* 1=timeout, 8=atomic */",
+	"				goto Repeat_one;",
+	"			}",
+	"#ifdef ETIM",
+	"			/* if timeouts were used in the model */",
+	"			if (!(trpt->tau&1))",
+	"			{	trpt->tau |= 1;		/* enable timeout */",
+	"				goto Repeat_two;",
+	"			}",
+	"#endif",
+	"			if (!noends && !endstate())",
+	"			{	bfs_uerror(\"invalid end state.\");",
+	"			}",
+	"		}",
+	"#ifdef VERI",
+	"		else /* boq == -1 && now._nr_pr == BASE && trpt->tau != 4 */",
+	"		{	trpt->tau |= 4; /* switch to claim for stutter moves */",
+	"	#ifdef VERBOSE",
+	"			printf(\"%%3ld: proc -1 exec -1, (stutter move)\\n\", depth, II);",
+	"	#endif",
+	"			bfs_store_state(trpt, boq);", /* doesn't store it but queues it */
+	"	#ifdef VERBOSE",
+	"			printf(\"%%3ld: proc -1 reverses -1, (stutter move)\\n\", depth, II);",
+	"	#endif",
+	"			trpt->tau &= ~4; /* undo, probably not needed */",
+	"		}",
+	"#endif",
+	"	}",
+	"#ifdef BFS_NOTRAIL",
+	"	bfs_release_trail(otrpt);",
+	"#endif",
+	"}",
+	"#if !defined(BFS_FIFO) && !defined(BFS_NORECYCLE)",
+	"void",
+	"bfs_recycle(BFS_Slot *n)",
+	"{",
+	"	#ifdef BFS_CHECK",
+	"	 assert(n != &bfs_null);",
+	"	#endif",
+	"	n->nxt = bfs_free_slot;",
+	"	bfs_free_slot = n;",
+	"",
+	"	#ifdef BFS_CHECK",
+	"	 bfs_printf(\"recycles %%s -- %%p\\n\",",
+	"		n->s_data?\"STATE\":\"EMPTY\", (void *) n);",
+	"	#endif",
+	"}",
+	"#endif",
+	"#ifdef BFS_FIFO",
+	"int",
+	"bfs_empty(int p)",	/* return Cores if all empty or index of first non-empty q of p */
+	"{	int i;",
+	"	const int dst = 0;",
+	"	for (i = 0; i < Cores; i++)",
+	"	{	if (shared_memory->head[dst][p][i] != (BFS_Slot *) 0)",
+	"		{",
+	"			volatile BFS_Slot *x = shared_memory->head[dst][p][i];",
+	"			while (x && x->type == DELETED)",
+	"			{	x = x->nxt;",
+	"			}",
+	"			if (!x)",
+	"			{	continue;",
+	"			}",
+	"			if (p == who_am_i)",
+	"			{	shared_memory->head[dst][p][i] = x;",
+	"			}",
+	"	#ifdef BFS_CHECK",
+	"			bfs_printf(\"input q [%%d][%%d][%%d] !empty\\n\",",
+	"				dst, p, i);",
+	"	#endif",
+	"			return i;",
+	"	}	}",
+	"	#ifdef BFS_CHECK",
+	"	 bfs_printf(\"all input qs [%%d][%%d][0..max] empty\\n\",",
+	"		dst, p);",
+	"	#endif		",
+	"	return Cores;",
+	"}",
+	"#endif",
+	"#ifdef BFS_DISK",
+	"void",
+	"bfs_ewrite(int fd, const void *p, size_t count)",
+	"{",
+	"	if (write(fd, p, count) != count)",
+	"	{	perror(\"diskwrite\");",
+	"		Uerror(\"aborting\");",
+	"	}",
+	"}",
+	"",
+	"void",
+	"bfs_eread(int fd, void *p, size_t count)",
+	"{",
+	"	if (read(fd, p, count) != count)",
+	"	{	perror(\"diskread\");",
+	"		Uerror(\"aborting\");",
+	"	}",
+	"}",
+	"",
+	"void",
+	"bfs_sink_disk(int who_are_you, BFS_Slot *n)",
+	"{	SV_Hold *x;",
+	"#ifdef VERBOSE",
+	"	bfs_printf(\"sink_disk -> %%d\\n\", who_are_you);",
+	"#endif",
+	"	bfs_ewrite(bfs_out_fd[who_are_you], (const void *) n->s_data->t_info, sizeof(BFS_Trail));",
+	"	bfs_ewrite(bfs_out_fd[who_are_you], (const void *) &vsize, sizeof(ulong));",
+	"	bfs_ewrite(bfs_out_fd[who_are_you], &now, vsize);",
+	"",
+	"	bfs_release_trail(n->s_data->t_info);",
+	"	n->s_data->t_info = (BFS_Trail *) 0;",
+	"",
+	"#if NRUNS>0",
+	"	bfs_ewrite(bfs_out_fd[who_are_you], (const void *) &(n->s_data->omask), sizeof(EV_Hold *));",
+	"#endif",
+	"#ifdef Q_PROVISO",
+	"	bfs_ewrite(bfs_out_fd[who_are_you], (const void *) &(n->s_data->lstate), sizeof(H_el *));",
+	"#endif",
+	"#if SYNC>0",
+	"	bfs_ewrite(bfs_out_fd[who_are_you], (const void *) &(n->s_data->boq), sizeof(short));",
+	"#endif",
+	"#if VERBOSE",
+	"	bfs_ewrite(bfs_out_fd[who_are_you], (const void *) &(n->s_data->nr), sizeof(ulong));",
+	"#endif",
+	"	shared_memory->bfs_out_cnt[who_am_i] = 1;", /* wrote at least one state */
+	"}",
+	"void",
+	"bfs_source_disk(int fd, volatile BFS_Slot *n)",
+	"{	ulong	  nb; /* local temporary */",
+	"	SV_Hold  *x;",
+	"#ifdef VERBOSE",
+	"	bfs_printf(\"source_disk <- %%d\\n\", who_am_i);",
+	"#endif",
+	"	n->s_data->t_info = bfs_grab_trail();",
+	"	bfs_eread(fd, (void *) n->s_data->t_info, sizeof(BFS_Trail));",
+	"	bfs_eread(fd, (void *) &nb, sizeof(ulong));",
+	"",
+	"	x = bfs_new_sv(nb);	/* space for osv isn't already allocated */",
+	"	n->s_data->osv = x->sv;",
+	"	x->sv = (State *) 0;",
+	"	x->nxt = bfs_free_hold;",
+	"	bfs_free_hold = x;",
+	"",
+	"	bfs_eread(fd, (void *) n->s_data->osv, (size_t) nb);",
+	"#if NRUNS>0",
+	"	bfs_eread(fd, (void *) &(n->s_data->omask), sizeof(EV_Hold *));",
+	"#endif",
+	"#ifdef Q_PROVISO",
+	"	bfs_eread(fd, (void *) &(n->s_data->lstate), sizeof(H_el *));",
+	"#endif",
+	"#if SYNC>0",
+	"	bfs_eread(fd, (void *) &(n->s_data->boq), sizeof(short));",
+	"#endif",
+	"#if VERBOSE",
+	"	bfs_eread(fd, (void *) &(n->s_data->nr), sizeof(ulong));",
+	"#endif",
+	"}",
+	"#endif",
+	"",
+	"#ifndef BFS_QSZ",
+	" #ifdef BFS_STAGGER",
+	"static BFS_Slot *bfs_stage[BFS_STAGGER];",
+	"",
+	"static void",
+	"bfs_stagger_flush(void)",
+	"{	int i, who_are_you;",
+	"	int dst = 1 - bfs_toggle;",
+	"	BFS_Slot *n;",
+	"	who_are_you = (rand()%%Cores);", /* important: all to the same cpu, but reversed */
+	"	for (i = bfs_stage_cnt-1; i >= 0; i--)",
+	"	{	n = bfs_stage[i];",
+	" #ifdef BFS_DISK",
+	"		bfs_sink_disk(who_are_you, n);",
+	"		bfs_stage[i] = (BFS_Slot *) 0;",
+	" #endif",
+	"		n->nxt = (BFS_Slot *) shared_memory->head[dst][who_are_you][who_am_i];",
+	"		shared_memory->head[dst][who_are_you][who_am_i] = n;",
+	"		/* bfs_sent++; */",
+	"	}",
+	"	#ifdef VERBOSE",
+	"		bfs_printf(\"stagger flush %%d states to %%d\\n\",",
+	"			bfs_stage_cnt, who_are_you);",
+	"	#endif",
+	"	bfs_stage_cnt = 0;",
+	"}",
+	"",
+	"void",
+	"bfs_stagger_add(BFS_Slot *n)",
+	"{",
+	"	if (bfs_stage_cnt == BFS_STAGGER)",
+	"	{	bfs_stagger_flush();",
+	"	}",
+	"	bfs_stage[bfs_stage_cnt++] = n;",
+	"}",
+	" #endif",
+	"#endif",
+	"",
+	"void",
+	"bfs_push_state(Trail *x, BFS_Trail *y, int tt)",
+	"{	int who_are_you;",
+	"#ifdef BFS_FIFO",
+	"	const int dst = 0;",
+	"#else",
+	"	int dst = 1 - bfs_toggle;",
+	"#endif",
+	"#ifdef BFS_QSZ",
+	"	uint z;",
+	"	if (bfs_keep_state > 0)",
+	"	{	who_are_you = bfs_keep_state - 1;",
+	"	} else",
+	"	{	who_are_you = (rand()%%Cores);",
+	"	}",
+	"	z = shared_memory->bfs_ix[dst][who_are_you][who_am_i];",
+	"	if (z >= BFS_QSZ)",
+	"	{	static int warned_qloss = 0;",
+	"		if (warned_qloss == 0 && who_am_i == 0)",
+	"		{	warned_qloss++;",
+	"			bfs_printf(\"BFS_QSZ too small - losing states\\n\");",
+	"		}",
+	"		bfs_punt++;",
+	"		return;",
+	"	}",
+	"	shared_memory->bfs_ix[dst][who_are_you][who_am_i] = z+1;",
+	"	BFS_Slot *n = bfs_pack_state(x, y, tt, bfs_prep_slot(y, ",
+	"		(BFS_Slot *) &(shared_memory->bfsq[dst][who_are_you][who_am_i][z])));",
+	"#else",
+	"	BFS_Slot *n = bfs_pack_state(x, y, tt, bfs_new_slot(y));",
+	"",
+	" #ifdef BFS_GREEDY",
+	"	who_are_you = who_am_i; /* for testing only */",
+	" #else",
+	"	if (bfs_keep_state > 0)",
+	"	{	who_are_you = bfs_keep_state - 1;",
+	"	} else",
+	"	{",
+	"	#ifdef BFS_STAGGER",
+	"		who_are_you = -1;",
+	"		bfs_stagger_add(n);",
+	"		goto done;",
+	"	#else",
+	"		who_are_you = (rand()%%Cores);",
+	"	#endif",
+	"	}",
+	" #endif",
+	" #ifdef BFS_FIFO",
+	"	  if (!shared_memory->tail[dst][who_are_you][who_am_i])",
+	"	  {	shared_memory->dels[dst][who_are_you][who_am_i] =",
+	"		shared_memory->tail[dst][who_are_you][who_am_i] =",
+	"		shared_memory->head[dst][who_are_you][who_am_i] = n;",
+	"	  } else",
+	"	  {	shared_memory->tail[dst][who_are_you][who_am_i]->nxt = n;",
+	"		shared_memory->tail[dst][who_are_you][who_am_i] = n;",
+	"	  }",
+	"	  shared_memory->bfs_idle[who_are_you] = 0;",
+	" #else",
+	"  #ifdef BFS_DISK",
+	"	  bfs_sink_disk(who_are_you, n);",
+	"  #endif",
+	"	  n->nxt = (BFS_Slot *) shared_memory->head[dst][who_are_you][who_am_i];",
+	"	  shared_memory->head[dst][who_are_you][who_am_i] = n;",
+	" #endif",
+	" #ifdef BFS_STAGGER",
+	"done:",
+	" #endif",
+	"#endif", /* BFS_QSZ */
+	"#ifdef VERBOSE",
+	"	bfs_printf(\"PUT STATE (depth %%ld, nr %%u) to %%d -- s_data: %%p\\n\",",
+	"		tt, n->s_data->nr, who_are_you, n->s_data);",
+	"#endif",
+	"	bfs_sent++;",
+	"}",
+	"",
+	"BFS_Slot *",
+	"bfs_next(void)",
+	"{	volatile BFS_Slot *n = &bfs_null;",
+	" #ifdef BFS_FIFO",
+	"	const int src = 0;",
+	"	bfs_qscan = bfs_empty(who_am_i);",
+	" #else",
+	"	const int src = bfs_toggle;",
+	"  #ifdef BFS_QSZ",
+	"	while (bfs_qscan < Cores",
+	"	&& shared_memory->bfs_ix[src][who_am_i][bfs_qscan] == 0)",
+	"	{	bfs_qscan++;",
+	"	}",
+	"  #else",
+	"	while (bfs_qscan < Cores",
+	"	&& shared_memory->head[src][who_am_i][bfs_qscan] == (BFS_Slot *) 0)",
+	"	{	bfs_qscan++;",
+	"	}",
+	"  #endif",
+	" #endif",
+	"	if (bfs_qscan < Cores)",
+	"	{",
+	" #ifdef BFS_FIFO",			/* no wait for toggles */
+	"		shared_memory->bfs_idle[who_am_i] = 0;",
+	"		for (n = shared_memory->head[src][who_am_i][bfs_qscan]; n; n = n->nxt)",
+	"		{	if (n->type != DELETED)",
+	"			{	break;",
+	"		}	}",
+	"	#ifdef BFS_CHECK",
+	"		assert(n && n->type == STATE); /* q cannot be empty */",
+	"	#endif",
+	"		if (n->nxt)",
+	"		{	shared_memory->head[src][who_am_i][bfs_qscan] = n->nxt;",
+	"		}",	/* else, do not remove it - yet - avoid empty queues */
+	"		n->type = DELETED;",
+	" #else",
+	"	#ifdef BFS_QSZ",
+	"		uint x = --shared_memory->bfs_ix[src][who_am_i][bfs_qscan];",
+	"		n = &(shared_memory->bfsq[src][who_am_i][bfs_qscan][x]);",
+	"	#else",
+	"		n = shared_memory->head[src][who_am_i][bfs_qscan];",
+	"		shared_memory->head[src][who_am_i][bfs_qscan] = n->nxt;",
+	"		#if defined(BFS_FIFO) && defined(BFS_CHECK)",
+	"			assert(n->type == STATE);",
+	"		#endif",
+	"		n->nxt = (BFS_Slot *) 0;",
+	"	#endif",
+	"	#ifdef BFS_DISK",
+	"		/* the states actually show up in reverse order (FIFO iso LIFO) here */",
+	"		/* but that doesnt really matter as long as the count is right */",
+	"		bfs_source_disk(bfs_inp_fd[bfs_qscan], n); /* get the data */",
+	"	#endif",
+
+	" #endif",
+	" #ifdef BFS_CHECK",
+	"		bfs_printf(\"rcv STATE from [%%d][%%d][%%d]\\n\",",
+	"			src, who_am_i, bfs_qscan);",
+	" #endif",
+	"		bfs_rcvd++;",
+	"	} else",
+	"	{",
+	" #if defined(BFS_STAGGER) && !defined(BFS_QSZ)",
+	"		if (bfs_stage_cnt > 0)",
+	"		{	bfs_stagger_flush();",
+	"		}",
+	" #endif",
+	"		shared_memory->bfs_idle[who_am_i] = 1;",
+	" #if defined(BFS_FIFO) && defined(BFS_CHECK)",
+	"		assert(n->type == EMPTY);",
+	" #endif",
+	"	}",
+	"	return (BFS_Slot *) n;",
+	"}",
+	"",
+	"int",
+	"bfs_all_empty(void)",
+	"{	int i;",
+	"#ifdef BFS_DISK",
+	"	for (i = 0; i < Cores; i++)",
+	"	{	if (shared_memory->bfs_out_cnt[i] != 0)",
+	"		{",
+	"  #ifdef VERBOSE",
+	"			bfs_printf(\"bfs_all_empty %%d not empty\\n\", i);",
+	"  #endif",
+	"			return 0;",
+	"	}	}",
+	"#else",
+	"	int p;",
+	"  #ifdef BFS_FIFO",
+	"	const int dst = 0;",
+	"  #else",
+	"	int dst = 1 - bfs_toggle; /* next generation */",
+	"  #endif",
+	"	for (p = 0; p < Cores; p++)",
+	"	for (i = 0; i < Cores; i++)",
+	"  #ifdef BFS_QSZ",
+	"	{	if (shared_memory->bfs_ix[dst][p][i] > 0)",
+	"  #else",
+	"	{	if (shared_memory->head[dst][p][i] != (BFS_Slot *) 0)",
+	"  #endif",
+	"		{	return 0;",
+	"	}	}",
+	"#endif",
+	"#ifdef VERBOSE",
+	"	bfs_printf(\"bfs_all_empty\\n\");",
+	"#endif",
+	"	return 1;",
+	"}",
+	"",
+	"#ifdef BFS_FIFO",
+	"BFS_Slot *",
+	"bfs_sweep(void)",
+	"{	BFS_Slot *n;",
+	"	int i;",
+	"	for (i = 0; i < Cores; i++)",
+	"	for (n = (BFS_Slot *) shared_memory->dels[0][who_am_i][i];",
+	"		n && n != shared_memory->head[0][who_am_i][i];",
+	"		n = n->nxt)",
+	"	{	if (n->type == DELETED && n->nxt)",
+	"		{	shared_memory->dels[0][who_am_i][i] = n->nxt;",
+	"			n->nxt = (BFS_Slot *) 0;",
+	"			return n;",
+	"	}	}",
+	"	return (BFS_Slot *) sh_malloc((ulong) sizeof(BFS_Slot));",
+	"}",
+	"#endif",
+	"",
+	"typedef struct BFS_T_Hold BFS_T_Hold;",
+	"struct BFS_T_Hold {",
+	"	volatile BFS_Trail *t;",
+	"	BFS_T_Hold *nxt;",
+	"};",
+	"BFS_T_Hold *bfs_t_held, *bfs_t_free;",
+	"",
+	"BFS_Trail *",
+	"bfs_grab_trail(void)",			/* call in bfs_source_disk and bfs_new_slot */
+	"{	BFS_Trail *t;",
+	"	BFS_T_Hold *h;",
+	"",
+	"#ifdef VERBOSE",
+	"	bfs_printf(\"grab trail - bfs_t_held %%p\\n\", (void *) bfs_t_held);",
+	"#endif",
+	"	if (bfs_t_held)",
+	"	{	h = bfs_t_held;",
+	"		bfs_t_held = bfs_t_held->nxt;",
+	"		t = (BFS_Trail *) h->t;",
+	"		h->t = (BFS_Trail *) 0; /* make sure it cannot be reused */",
+	"		h->nxt = bfs_t_free;",
+	"		bfs_t_free = h;",
+	"",
+	"	} else",
+	"	{	t = (BFS_Trail *) sh_malloc((ulong) sizeof(BFS_Trail));",
+	"	}",
+	"#ifdef BFS_CHECK",
+	"	assert(t);",
+	"#endif",
+	"	t->ostate = (H_el *) 0;",
+	"#ifdef VERBOSE",
+	"	bfs_printf(\"grab trail %%p\\n\", (void *) t);",
+	"#endif",
+	"	return t;",
+	"}",
+	"",
+	"#if defined(BFS_DISK) || defined(BFS_NOTRAIL)",
+	"void",
+	"bfs_release_trail(BFS_Trail *t)",	/* call in bfs_sink_disk (not bfs_recycle) */
+	"{	BFS_T_Hold *h;",
+	" #ifdef BFS_CHECK",
+	"	assert(t);",
+	" #endif",
+	" #ifdef VERBOSE",
+	"	bfs_printf(\"release trail %%p\\n\", (void *) t);",
+	"	#endif",
+	"	if (bfs_t_free)",
+	"	{	h = bfs_t_free;",
+	"		bfs_t_free = bfs_t_free->nxt;",
+	"	} else",
+	"	{	h = (BFS_T_Hold *) emalloc(sizeof(BFS_T_Hold));",
+	"	}",
+	"	h->t = t;",
+	"	h->nxt = bfs_t_held;",
+	"	bfs_t_held = h;",
+	" #ifdef VERBOSE",
+	"	bfs_printf(\"release trail - bfs_t_held %%p\\n\", (void *) bfs_t_held);",
+	" #endif",
+	"}",
+	"#endif",
+	"",
+	"#ifndef BFS_QSZ",
+	"BFS_Slot *",
+	"bfs_new_slot(BFS_Trail *f)",
+	"{	BFS_Slot *t;",
+	"",
+	"#ifdef BFS_FIFO",
+	"	t = bfs_sweep();",
+	"#else",
+	"	if (bfs_free_slot)	/* local */",
+	"	{	t = bfs_free_slot;",
+	"		bfs_free_slot = bfs_free_slot->nxt;",
+	"		t->nxt = (BFS_Slot *) 0;",
+	"	} else",
+	"	{	t = (BFS_Slot *) sh_malloc((ulong) sizeof(BFS_Slot));",
+	"	}",
+	"#endif",
+	"	if (t->s_data)",
+	"	{	memset(t->s_data, 0, sizeof(BFS_State));",
+	"	} else",
+	"	{	t->s_data = (BFS_State *) sh_malloc((ulong) sizeof(BFS_State));",
+	"	}",
+	"",
+	"	/* we keep a ptr to the frame of parent states, which is */",
+	"	/* used for reconstructing path and recovering failed rvs etc */",
+	"	/* we should not overwrite the data at this address with a memset */",
+	"",
+	"	if (f)",
+	"	{	t->s_data->t_info = f;",
+	"	} else",
+	"	{	t->s_data->t_info = bfs_grab_trail();",
+	"	}",
+	"	return t;",
+	"}",
+	"#else",
+	"BFS_Slot *",
+	"bfs_prep_slot(BFS_Trail *f, BFS_Slot *t)",
+	"{",
+	"	if (t->s_data)",
+	"	{	memset(t->s_data, 0, sizeof(BFS_State));",
+	"	} else",
+	"	{	t->s_data = (BFS_State *) sh_malloc((ulong) sizeof(BFS_State));",
+	"	}",
+	"	if (f)",
+	"	{	t->s_data->t_info = f;",
+	"	} else",
+	"	{	t->s_data->t_info = bfs_grab_trail();",
+	"	}",
+	"	return t;",
+	"}",
+	"#endif",
+	"",
+	"SV_Hold *",
+	"bfs_new_sv(int n)",
+	"{	SV_Hold *h;",
+	"",
+	"	if (bfs_svfree[n])",
+	"	{	h = bfs_svfree[n];",
+	"		bfs_svfree[n] = h->nxt;",
+	"		h->nxt = (SV_Hold *) 0;",
+	"	} else",
+	"	{	h = (SV_Hold *) sh_malloc((ulong) sizeof(SV_Hold));",
+	"#if 0",
+	"		h->sz = n;",
+	"#endif",
+	"		h->sv = (State *) sh_malloc((ulong)(sizeof(State) - VECTORSZ + n));",
+	"	}",
+	"	memcpy((char *)h->sv, (char *)&now, n);",
+	"	return h;",
+	"}",
+	"#if NRUNS>0",
+	"static EV_Hold *kept[VECTORSZ];	/* local */",
+	"",
+	"static void",
+	"bfs_keep(EV_Hold *v)",
+	"{	EV_Hold *h;",
+	"",
+	"	for (h = kept[v->sz]; h; h = h->nxt) /* check local list */",
+	"	{	if (v->nrpr == h->nrpr",
+	"		&&  v->nrqs == h->nrqs",
+	"#if !defined(NOCOMP) && !defined(HC)",
+	"		&&  (v->sv == h->sv || memcmp((char *) v->sv, (char *) h->sv, v->sz) == 0)",
+	"#endif",
+	"#ifdef TRIX",
+	"		)",
+	"#else",
+	"	#if NRUNS>0",
+	"		#if VECTORSZ>32000",
+	"		&&  (memcmp((char *) v->po, (char *) h->po, v->nrpr * sizeof(int)) == 0)",
+	"		&&  (memcmp((char *) v->qo, (char *) h->qo, v->nrqs * sizeof(int)) == 0)",
+	"		#else",
+	"		&&  (memcmp((char *) v->po, (char *) h->po, v->nrpr * sizeof(short)) == 0)",
+	"		&&  (memcmp((char *) v->qo, (char *) h->qo, v->nrqs * sizeof(short)) == 0)",
+	"		#endif",
+	"		&&  (memcmp((char *) v->ps, (char *) h->ps, v->nrpr * sizeof(uchar)) == 0)",
+	"		&&  (memcmp((char *) v->qs, (char *) h->qs, v->nrqs * sizeof(uchar)) == 0))",
+	"	#else",
+	"		)",
+	"	#endif",
+	"#endif",
+	"		{	break;",
+	"	}	}",
+	"",
+	"	if (!h)	/* we don't have one like it yet */",
+	"	{	v->nxt = kept[v->sz];	/* keep the original owner field */",
+	"		kept[v->sz] = v;",
+	"		/* all ptrs inside are to shared memory, but nxt is local */",
+	"	}",
+	"}",
+	"",
+	"EV_Hold *",
+	"bfs_new_sv_mask(int n)",
+	"{	EV_Hold *h;",
+	"",
+	"	for (h = kept[n]; h; h = h->nxt)",
+	"	{	if ((now._nr_pr == h->nrpr)",
+	"		&&  (now._nr_qs == h->nrqs)",
+	"#if !defined(NOCOMP) && !defined(HC) && NRUNS>0",
+	"		&& ((char *) Mask == h->sv || (memcmp((char *) Mask, h->sv, n) == 0))",
+	"#endif",
+	"#ifdef TRIX",
+	"		)",
+	"#else",
+	"	#if NRUNS>0",
+	"		#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))",
+	"	#else",
+	"		)",
+	"	#endif",
+	"#endif",
+	"		{	break;",
+	"	}	}",
+	"",
+	"	if (!h)",
+	"	{	/* once created, the contents are never modified */",
+	"		h = (EV_Hold *) sh_malloc((ulong)sizeof(EV_Hold));",
+	"		h->owner = who_am_i;",
+	"		h->sz = n;",
+	"		h->nrpr = now._nr_pr;",
+	"		h->nrqs = now._nr_qs;",
+	"#if !defined(NOCOMP) && !defined(HC) && NRUNS>0",
+	"		h->sv = (char *) Mask;	/* in shared memory, and never modified */",
+	"#endif",
+	"#if NRUNS>0 && !defined(TRIX)",
+	"		if (now._nr_pr > 0)",
+	"		{	h->ps = (char *) proc_skip;",
+	"			h->po = (char *) proc_offset;",
+	"		}",
+	"		if (now._nr_qs > 0)",
+	"		{	h->qs = (char *) q_skip;",
+	"			h->qo = (char *) q_offset;",
+	"		}",
+	"#endif",
+	"		h->nxt = kept[n];",
+	"		kept[n] = h;",
+	"	}",
+	"	return h;",
+	"}",
+	"#endif", /* NRUNS>0 */
+	"BFS_Slot *",
+	"bfs_pack_state(Trail *f, BFS_Trail *g, int search_depth, BFS_Slot *t)",
+	"{",
+	"#ifdef BFS_CHECK",
+	"	assert(t->s_data != NULL);",
+	"	assert(t->s_data->t_info != NULL);",
+	"	assert(f || g);",
+	"#endif",
+	"	if (!g)",
+	"	{	t->s_data->t_info->ostate = f->ostate;",
+	"		t->s_data->t_info->st   = f->st;",
+	"		t->s_data->t_info->o_tt = search_depth;",
+	"		t->s_data->t_info->pr   = f->pr;",
+	"		t->s_data->t_info->tau  = f->tau;",
+	"		t->s_data->t_info->o_pm = f->o_pm;",
+	"		if (f->o_t)",
+	"		{	t->s_data->t_info->t_id = f->o_t->t_id;",
+	"		} else",
+	"		{	t->s_data->t_info->t_id = -1;",
+	"			t->s_data->t_info->ostate = NULL;",
+	"		}",
+	"	} /* else t->s_data->t_info == g */",
+	"#if SYNC",
+	"	t->s_data->boq = boq;",
+	"#endif",
+	"#ifdef VERBOSE",
+	"	{	static ulong u_cnt;",
+	"		t->s_data->nr = u_cnt++;",
+	"	}",
+	"#endif",
+	"#ifdef TRIX",
+	"	sv_populate(); /* make sure now is up to date */",
+	"#endif",
+	"#ifndef BFS_DISK",
+	"	{ 	SV_Hold *x = bfs_new_sv(vsize);",
+	"		t->s_data->osv = x->sv;",
+	"		x->sv = (State *) 0;",
+	"		x->nxt = bfs_free_hold;",
+	"		bfs_free_hold = x;",
+	"	}",
+	"#endif",
+	"#if NRUNS>0",
+	"	t->s_data->omask = bfs_new_sv_mask(vsize);",
+	"#endif",
+	"",
+	"#if defined(Q_PROVISO) && !defined(BITSTATE) && !defined(NOREDUCE)",
+	"	t->s_data->lstate = Lstate;	/* Lstate is set in o_store or h_store */",
+	"#endif",
+	"#ifdef BFS_FIFO",
+	"	t->type = STATE;",
+	"#endif",
+	"	return t;",
+	"}",
+	"",
+	"void",
+	"bfs_store_state(Trail *t, short oboq)",
+	"{",
+	"#ifdef TRIX",
+	"	sv_populate();",
+	"#endif",
+	"#if defined(VERI) && defined(Q_PROVISO) && !defined(BITSTATE) && defined(FULLSTACK)",
+	"	if (!(t->tau&4)",	/* prog move */
+	"	&&    t->ostate)",	/* not initial state */
+	"	{	t->tau |= ((BFS_Trail *) t->ostate)->tau&64;",
+	"	}	/* lift 64 across claim moves */",
+	"#endif",	
+	"",
+	"#ifdef BFS_SEP_HASH",
+	"	#if SYNC",
+	"	if (boq == -1 && oboq != -1)	/* post-rv */",
+	"	{	BFS_Trail *x =  (BFS_Trail *) trpt->ostate; /* pre-rv state */",
+	"	 	if (x)",
+	"		{	x->o_pm |= 4;	/* rv complete */",
+	"	}	}",
+	"	#endif",
+	"	d_sfh((uchar *)&now, (int) vsize); /* sep-hash -- sets K1 -- overkill */",
+	"	bfs_keep_state = K1%%Cores + 1;",
+	"	bfs_push_state(t, NULL, trpt->o_tt+1);	/* bfs_store_state - sep_hash */",
+	"	bfs_keep_state = 0;",
+	"#else",
+	"	#ifdef VERI",
+#if 0
+		in VERI mode store the state when
+		(!t->ostate || (t->tau&4)) in initial state and after each program move
+
+		i.e., dont store when !(!t->ostate || (t->tau&4)) = (t->ostate && !(t->tau&4))
+		the *first* time that the tau flag is not set:
+		possibly after a series of claim moves in an atomic sequence
+#endif
+	"		if (!(t->tau&4) && t->ostate && (((BFS_Trail *)t->ostate)->tau&4))",
+	"		{	/* do not store intermediate state */",
+	"		#if defined(VERBOSE) && defined(L_BOUND)",
+	"			bfs_printf(\"Un-Stored state bnd %%d -- sds %%p\\n\",",
+	"				now._l_bnd, now._l_sds);",
+	"		#endif",
+	"			bfs_push_state(t, NULL, trpt->o_tt+1);	/* claim move */",
+	"		} else",
+	"	#endif",
+	"		if (!bfs_do_store((char *)&now, vsize))	/* includes bfs_visited */",
+	"		{	nstates++;			/* local count */",
+	"			trpt->tau |= 64;		/* bfs: succ outside stack */",
+	"	#if SYNC",
+	"			if (boq == -1 && oboq != -1)	/* post-rv */",
+	"			{	BFS_Trail *x = ",
+	"			  	(BFS_Trail *) trpt->ostate; /* pre-rv state */",
+	"			  	if (x)",
+	"				{	x->o_pm |= 4;	/* rv complete */",
+	"			}	}",
+	"	#endif",
+	"			bfs_push_state(t, NULL, trpt->o_tt+1);	/* successor */",
+	"		} else",
+	"		{	truncs++;",
+	"	#ifdef BFS_CHECK",
+	"			bfs_printf(\"seen before\\n\");",
+	"	#endif",
+	"	#if defined(Q_PROVISO) && !defined(BITSTATE) && defined(FULLSTACK)",
+	"		#ifdef USE_TDH",
+	"			if (Lstate)",	/* if BFS_INQ is set */
+	"			{	trpt->tau |= 64;",
+	"			}",
+	"		#else",
+	"			if (Lstate && Lstate->tagged)	/* bfs_store_state */",
+	"			{	trpt->tau |= 64;",
+	"			}",
+	"		#endif",
+	"	#endif",
+	"		}",
+	"#endif",
+	"}",
+	"",
+	"/*** support routines ***/",
+	"",
+	"void",
+	"bfs_clear_locks(void)",
+	"{	int i;",
+	"",
+	"	/* clear any locks held by this process only */",
+	"	if (shared_memory)",
+	"	for (i = 0; i < BFS_MAXLOCKS; i++)",
+	"	{	if (shared_memory->sh_owner[i] == who_am_i + 1)",
+	"		{	shared_memory->sh_locks[i] = 0;",
+	"#ifdef BFS_CHECK",
+	"			shared_memory->in_count[i] = 0;",
+	"#endif",
+	"			shared_memory->sh_owner[i] = 0;",
+	"	}	}",
+	"}",
+	"",
+	"void",
+	"e_critical(int which)",
+	"{	int w;",
+	"#ifdef BFS_CHECK",
+	"	assert(which >= 0 && which < BFS_MAXLOCKS);",
+	"#endif",
+	"	if (shared_memory == NULL) return;",
+	"	while (tas(&(shared_memory->sh_locks[which])) != 0)",
+	"	{	w = shared_memory->sh_owner[which]; /* sh_locks[which] could be 0 by now */",
+	"		assert(w >= 0 && w <= BFS_MAXPROCS);",
+	"		if (w > 0 && shared_memory->bfs_flag[w-1] == 2)",
+	"		{	/* multiple processes can get here; only one should do this: */",
+	"			if (tas(&(shared_memory->bfs_data[w - 1].override)) == 0)",
+	"			{	fprintf(stderr, \"cpu%%02d: override lock %%d - held by %%d\\n\",",
+	"				who_am_i, which, shared_memory->sh_owner[which]);",
+	"#ifdef BFS_CHECK",
+	"				shared_memory->in_count[which] = 0;",
+	"#endif",
+	"				shared_memory->sh_locks[which] = 0;",
+	"				shared_memory->sh_owner[which] = 0;",
+	"		}	}",
+	"		shared_memory->wait_count[which]++; /* not atomic of course */",
+	"	}",
+	"#ifdef BFS_CHECK",
+	"	if (shared_memory->in_count[which] != 0)",
+	"	{	fprintf(stderr, \"cpu%%02d: cannot happen lock %%d count %%d\\n\", who_am_i,",
+	"			which, shared_memory->in_count[which]);",
+	"	}",
+	"	shared_memory->in_count[which]++;",
+	"#endif",
+	"	shared_memory->sh_owner[which] = who_am_i+1;",
+	"}",
+	"",
+	"void",
+	"x_critical(int which)",
+	"{",
+	"	if (shared_memory == NULL) return;",
+	"#ifdef BFS_CHECK",
+	"	assert(shared_memory->in_count[which] == 1);",
+	"	shared_memory->in_count[which] = 0;",
+	"#endif",
+	"	shared_memory->sh_locks[which] = 0;",
+	"	shared_memory->sh_owner[which] = 0;",
+	"}",
+	"",
+	"void",
+	"bfs_printf(const char *fmt, ...)",
+	"{	va_list args;",
+	"",
+	"	e_critical(BFS_PRINT);",
+	"#ifdef BFS_CHECK",
+	"	if (1) { int i=who_am_i; while (i-- > 0) printf(\"  \"); }",
+	"#endif",
+	"	printf(\"cpu%%02d: \", who_am_i);",
+	"	va_start(args, fmt);",
+	"	vprintf(fmt, args);",
+	"	va_end(args);",
+	"	fflush(stdout);",
+	"	x_critical(BFS_PRINT);",
+	"}",
+	"",
+	"int",
+	"bfs_all_idle(void)",
+	"{	int i;",
+	"",
+	"	if (shared_memory)",
+	"	for (i = 0; i < Cores; i++)",
+	"	{	if (shared_memory->bfs_flag[i] == 0",
+	"		&&  shared_memory->bfs_idle[i] == 0)",
+	"		{	return 0;",
+	"	}	}",
+	"	return 1;",
+	"}",
+	"",
+	"#ifdef BFS_FIFO",
+	"int",
+	"bfs_idle_and_empty(void)",
+	"{	int p;	/* read-only */",
+	"	for (p = 0; p < Cores; p++)",
+	"	{	if (shared_memory->bfs_flag[p] == 0",
+	"		&&  shared_memory->bfs_idle[p] == 0)",
+	"		{	return 0;",
+	"	}	}",
+	"	for (p = 0; p < Cores; p++)",
+	"	{	if (bfs_empty(p) < Cores)",
+	"		{	return 0;",
+	"	}	}",
+	"	return 1;",
+	"}",
+	"#endif",
+	"",
+	"void",
+	"bfs_set_toggle(void)	/* executed by root */",
+	"{	int i;",
+	"",
+	"	if (shared_memory)",
+	"	for (i = 0; i < Cores; i++)",
+	"	{	shared_memory->bfs_idle[i] = 0;",
+	"	}",
+	"}",
+	"",
+	"int",
+	"bfs_all_running(void)	/* crash detection */",
+	"{	int i;",
+	"	for (i = 0; i < Cores; i++)",
+	"	{	if (!shared_memory || shared_memory->bfs_flag[i] > 1)",
+	"		{	return 0;",
+	"	}	}",
+	"	return 1;",
+	"}",
+	"",
+	"void",
+	"bfs_mark_done(int code)",
+	"{",
+	"	if (shared_memory)",
+	"	{	shared_memory->bfs_flag[who_am_i] = (int) code;",
+	"		shared_memory->quit = 1;",
+	"	}",
+	"}",
+	"",
+	"static uchar *",
+	"bfs_offset(int c)",
+	"{	int   p, N;",
+	"#ifdef COLLAPSE",
+	"	uchar *q = (uchar *) ncomps; /* it is the first object allocated */",
+	"	q += (256+2) * sizeof(ulong); /* preserve contents of ncomps */",
+	"#else",
+	"	uchar *q = (uchar *) &(shared_memory->allocator);",
+	"#endif",
+	"	/* _NP_+1 proctypes, reachability info:",
+	"	 * reached[x : 0 .. _NP_+1][ 0 .. NrStates[x] ]",
+	"	 */",
+	"	for (p = N = 0; p <= _NP_; p++)",
+	"	{	N += NrStates[p];	/* sum for all proctypes */",
+	"	}",
+	"",
+	"	/* space needed per proctype: N bytes */",
+	"	/* rounded up to a multiple of the word size */",
+	"	if ((N%%sizeof(void *)) != 0)	/* aligned */",
+	"	{	N += sizeof(void *) - (N%%sizeof(void *));",
+	"	}",
+	"",
+	"	q += ((c - 1) * (_NP_ + 1) * N);",
+	"	return q;",
+	"}",
+	"",
+	"static void",
+	"bfs_putreached(void)",
+	"{	uchar *q;",
+	"	int p;",
+	"",
+	"	assert(who_am_i > 0);",
+	"",
+	"	q = bfs_offset(who_am_i);",
+	"	for (p = 0; p <= _NP_; p++)",
+	"	{	memcpy((void *) q, (const void *) reached[p], (size_t) NrStates[p]);",
+	"		q += NrStates[p];",
+	"	}",
+	"}",
+	"",
+	"static void",
+	"bfs_getreached(int c)",
+	"{	uchar *q;",
+	"	int p, i;",
+	"",
+	"	assert(who_am_i == 0 && c >= 1 && c < Cores);",
+	"",
+	"	q = (uchar *) bfs_offset(c);",
+	"	for (p = 0; p <= _NP_; p++)",
+	"	for (i = 0; i < NrStates[p]; i++)",
+	"	{	reached[p][i] += *q++; /* update local copy */",
+	"	}",
+	"}",
+	"",
+	"void",
+	"bfs_update(void)",
+	"{	int i;",
+	"	volatile BFS_data *s;",
+	"",
+	"	if (!shared_memory) return;",
+	"",
+	"	s = &shared_memory->bfs_data[who_am_i];",
+	"	if (who_am_i == 0)",
+	"	{	shared_memory->bfs_flag[who_am_i] = 3; /* or else others dont stop */",
+	"		bfs_gcount = 0;",
+	"		for (i = 1; i < Cores; i++) /* start at 1 not 0 */",
+	"		{	while (shared_memory->bfs_flag[i] == 0)",
+	"			{	sleep(1);",
+	"				if (bfs_gcount++ > WAIT_MAX)	/* excessively long wait */",
+	"				{	printf(\"cpu00: give up waiting for cpu%%2d (%%d cores)\\n\", i, Cores);",
+	"					bfs_gcount = 0;",
+	"					break;",
+	"			}	}",
+	"			s = &shared_memory->bfs_data[i];",
+	"			mreached     = Max(mreached, s->mreached);",
+	"			hmax = vsize = Max(vsize,    s->vsize);",
+	"			errors   += s->errors;",
+	"			memcnt   += s->memcnt;",
+	"			nstates  += s->nstates;",
+	"			nlinks   += s->nlinks;",
+	"			truncs   += s->truncs;",
+	"			bfs_left += s->memory_left;",
+	"			bfs_punt += s->punted;",
+	"			bfs_getreached(i);",
+	"		}",
+	"	} else",
+	"	{	s->mreached = (ulong) mreached;",
+	"		s->vsize    = (ulong) vsize;",
+	"		s->errors   = (int) errors;",
+	"		s->memcnt   = (double) memcnt;",
+	"		s->nstates  = (double) nstates;",
+	"		s->nlinks   = (double) nlinks;",
+	"		s->truncs   = (double) truncs;",
+	"		s->memory_left = (ulong) bfs_left;",
+	"		s->punted      = (ulong) bfs_punt;",
+	"		bfs_putreached();",
+	"	}",
+	"}",
+	"",
+	"volatile uchar *",
+	"sh_pre_malloc(ulong n)	/* used before the local heaps are populated */",
+	"{	volatile uchar *ptr = NULL;",
+	"",
+	"	assert(!bfs_runs);",
+	"	if ((n%%sizeof(void *)) != 0)",
+	"	{	n += sizeof(void *) - (n%%sizeof(void *));",
+	"		assert((n%%sizeof(void *)) == 0);",
+	"	}",
+	"",
+	"	e_critical(BFS_MEM);	/* needed? */",
+	"		if (shared_memory->mem_left < n + 7)", /* 7 for possible alignment */
+	"		{	x_critical(BFS_MEM);",
+	"			bfs_printf(\"want %%lu, have %%lu\\n\",",
+	"				n, shared_memory->mem_left);",
+	"			bfs_shutdown(\"out of shared memory\");",
+	"			assert(0); /* should be unreachable */",
+	"		}",
+	"		ptr = shared_memory->allocator;",
+	"#if WS>4", /* align to 8 byte boundary */
+	"		{	int b = (int) ((uint64_t) ptr)&7;",
+	"			if (b != 0)",
+	"			{	ptr += (8-b);",
+	"				shared_memory->allocator = ptr;",
+	"		}	}",
+	"#endif",
+	"		shared_memory->allocator += n;",
+	"		shared_memory->mem_left -= n;",
+	"	x_critical(BFS_MEM);",
+	"",
+	"	bfs_pre_allocated += n;",
+	"",
+	"	return ptr;",
+	"}",
+	"",
+	"volatile uchar *",
+	"sh_malloc(ulong n)",
+	"{	volatile uchar *ptr = NULL;",
+	"#ifdef BFS_CHECK",
+	"	assert(bfs_runs);",
+	"#endif",
+	"	if ((n%%sizeof(void *)) != 0)",
+	"	{	n += sizeof(void *) - (n%%sizeof(void *));",
+	"#ifdef BFS_CHECK",
+	"		assert((n%%sizeof(void *)) == 0);",
+	"#endif",
+	"	}",
+	"",
+	"	/* local heap -- no locks needed */",
+	"	if (bfs_left < n)",
+	"	{	e_critical(BFS_MEM);",
+	"		if (shared_memory->mem_left >= n)",
+	"		{	ptr = (uchar *) shared_memory->allocator;",
+	"			shared_memory->allocator += n;",
+	"			shared_memory->mem_left  -= n;",
+	"			x_critical(BFS_MEM);",
+	"			return ptr;",
+	"		}",
+	"		x_critical(BFS_MEM);",
+	"#ifdef BFS_LOGMEM",
+	"		int i;",
+	"		e_critical(BFS_MEM);",
+	"		for (i = 0; i < 1024; i++)",
+	"		{	if (shared_memory->logmem[i] > 0)",
+	"			{	bfs_printf(\"\tlog[%%d]\t%%d\\n\", i, shared_memory->logmem[i]);",
+	"		}	}",
+	"		x_critical(BFS_MEM);",
+	"#endif",
+	"		bfs_shutdown(\"out of shared memory\"); /* no return */",
+	"	}",
+	"#ifdef BFS_LOGMEM",
+	"	e_critical(BFS_MEM);",
+	"	if (n < 1023)",
+	"	{	shared_memory->logmem[n]++;",
+	"	} else",
+	"	{	shared_memory->logmem[1023]++;",
+	"	}",
+	"	x_critical(BFS_MEM);",
+	"#endif",
+	"	ptr = (uchar *) bfs_heap;",
+	"	bfs_heap += n;",
+	"	bfs_left -= n;",
+	"",
+	"	if (0) printf(\"sh_malloc %%ld\\n\", n);",
+	"	return ptr;",
+	"}",
+	"",
+	"volatile uchar *",
+	"bfs_get_shared_mem(key_t key, size_t n)",
+	"{	char *rval;",
+	"",
+	"	assert(who_am_i == 0);",
+	"",
+	"	shared_mem_id = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL);	/* create */",
+	"	if (shared_mem_id == -1)",
+	"	{	fprintf(stderr, \"cpu%%02d: tried to get %%d MB of shared memory\\n\",",
+	"			who_am_i, (int) n/(1024*1024));",
+	"		perror(\"shmget\");",
+	"		exit(1);",
+	"	}",
+	"	if ((rval = (char *) shmat(shared_mem_id, (void *) 0, 0)) == (char *) -1) /* attach */",
+	"	{	perror(\"shmat\");",
+	"		exit(1);",
+	"	}",
+	"	return (uchar *) rval;",
+	"}",
+	"",
+	"void",
+	"bfs_drop_shared_memory(void)",
+	"{",
+	"	if (who_am_i == 0)",
+	"	{	printf(\"pan: releasing shared memory...\");",
+	"		fflush(stdout);",
+	"	}",
+	"	if (shared_memory)",
+	"	{	shmdt(shared_memory);					/* detach */",
+	"		if (who_am_i == 0)",
+	"		{	shmctl(shared_mem_id, IPC_RMID, (void *) 0);	/* remove */",
+	"	}	}",
+	"	if (who_am_i == 0)",
+	"	{	printf(\"done\\n\");",
+	"		fflush(stdout);",
+	"	}",
+	"}",
+	"",
+	"size_t",
+	"bfs_find_largest(key_t key)",
+	"{	size_t n;",
+	"	const size_t delta = 32*1024*1024;",
+	"	int temp_id = -1;",
+	"	int atleastonce = 0;",
+	"",
+	"	for (n = delta; ; n += delta)",
+	"	{	if (WS <= 4 && n >= 1024*1024*1024)", /* was n >= INT_MAX */
+	"		{	n = 1024*1024*1024;",
+	"			break;",
+	"		}",
+	"#ifdef MEMLIM",
+	"		if ((double) n > memlim)",
+	"		{	n = (size_t) memlim;",
+	"			break;",
+	"		}",
+	"#endif",
+	"		temp_id = shmget(key, n, 0600);		/* check for stale copy */",
+	"		if (temp_id != -1)",
+	"		{	if (shmctl(temp_id, IPC_RMID, ((void *) 0)) < 0) /* remove */",
+	"			{	perror(\"remove_segment_fails 2\");",
+	"				exit(1);",
+	"		}	}",
+	"",
+	"		temp_id = shmget(key, n, 0600 | IPC_CREAT | IPC_EXCL);	/* create new */",
+	"		if (temp_id == -1)",
+	"		{	n -= delta;",
+	"			break;",
+	"		} else",
+	"		{	atleastonce++;",
+	"			if (shmctl(temp_id, IPC_RMID, ((void *) 0)) < 0)",
+	"			{	perror(\"remove_segment_fails 0\");",
+	"				exit(1);",
+	"	}	}	}",
+	"",
+	"	if (!atleastonce)",
+	"	{	printf(\"cpu%%02d: no shared memory n=%%d\\n\", who_am_i, (int) n);",
+	"		exit(1);",
+	"	}",
+	"",
+	"	printf(\"cpu%%02d: largest shared memory segment: %%lu MB\\n\",",
+	"		who_am_i, (ulong) n/(1024*1024));",
+	"#if 0",
+	"	#ifdef BFS_SEP_HASH",
+	"	n /= 2;	/* not n /= Cores because the queues take most memory */",
+	"	printf(\"cpu%%02d: using %%lu MB\\n\", who_am_i, (ulong) n/(1024*1024));",
+	"	#endif",
+	"#endif",
+	"	fflush(stdout);",
+	"",
+	"	if ((n/(1024*1024)) == 32)",
+	"	{ if (sizeof(void *) == 4) 	/* a 32 bit machine */",
+	"	  { fprintf(stderr, \"\\t32MB is the default; increase it to 1 GB with:\\n\");",
+	"	    fprintf(stderr, \"\\tsudo /sbin/sysctl kernel.shmmax=%%d\\n\", (1<<30));",
+	"	    fprintf(stderr, \"\\tsudo /sbin/sysctl kernel.shmall=%%d\\n\", (1<<30)/8192);",
+	"	  } else if (sizeof(void *) == 8)	/* a 64 bit machine */",
+	"	  { fprintf(stderr, \"\\t32MB is the default; increase it to 30 GB with:\\n\");",
+	"	    fprintf(stderr, \"\\tsudo /sbin/sysctl kernel.shmmax=32212254720\\n\");",
+	"	    fprintf(stderr, \"\\tsudo /sbin/sysctl kernel.shmall=7864320\\n\");",
+	"	    fprintf(stderr, \"\\tor for 60 GB:\\n\");",
+	"	    fprintf(stderr, \"\\tsudo /sbin/sysctl kernel.shmmax=60000000000\\n\");",
+	"	    fprintf(stderr, \"\\tsudo /sbin/sysctl kernel.shmall=30000000\\n\");",
+	"	  } else",
+	"	  { fprintf(stderr, \"\\tweird wordsize %%d\\n\", (int) sizeof(void *));",
+	"	} }",
+	"",
+	"	return n;",
+	"}",
+	"#ifdef BFS_DISK",
+	"void",
+	"bfs_disk_start(void)",	/* setup .spin*/
+	"{	int unused = system(\"rm -fr .spin\");",
+	"	if (mkdir(\".spin\", 0777) != 0)",
+	"	{	perror(\"mkdir\");",
+	"		Uerror(\"aborting\");",
+	"	}",
+	"}",
+	"void",
+	"bfs_disk_stop(void)",	/* remove .spin */
+	"{",
+	"	if (system(\"rm -fr .spin\") < 0)",
+	"	{	perror(\"rm -fr .spin/\");",
+	"	}",
+	"}",
+	"void",
+	"bfs_disk_inp(void)", /* this core only */
+	"{	int i; char fnm[16];",
+	"#ifdef VERBOSE",
+	"	bfs_printf(\"inp %%d %%d 0..%%d\\n\", bfs_toggle, who_am_i, Cores);",
+	"#endif",
+	"	for (i = 0; i < Cores; i++)",
+	"	{	sprintf(fnm, \".spin/q%%d_%%d_%%d\", bfs_toggle, who_am_i, i);",
+	"		if ((bfs_inp_fd[i] = open(fnm, 0444)) < 0)",
+	"		{	perror(\"open\");",
+	"			Uerror(fnm);",
+	"	}	}",
+	"}",
+	"void",
+	"bfs_disk_out(void)", /* this core only */
+	"{	int i; char fnm[16];",
+	"#ifdef VERBOSE",
+	"	bfs_printf(\"out %%d 0..%%d %%d\\n\", 1-bfs_toggle, Cores, who_am_i);",
+	"#endif",
+	"	shared_memory->bfs_out_cnt[who_am_i] = 0;",
+	"	for (i = 0; i < Cores; i++)",
+	"	{	sprintf(fnm, \".spin/q%%d_%%d_%%d\", 1-bfs_toggle, i, who_am_i);",
+	"		if ((bfs_out_fd[i] = creat(fnm, 0666)) < 0)",
+	"		{	perror(\"creat\");",
+	"			Uerror(fnm);",
+	"	}	}",
+	"}",
+	"void",
+	"bfs_disk_iclose(void)",
+	"{	int i;",
+	"#ifdef VERBOSE",
+	"	bfs_printf(\"close_inp\\n\");",
+	"#endif",
+	"	for (i = 0; i < Cores; i++)",
+	"	{	if (close(bfs_inp_fd[i]) < 0)",
+	"		{	perror(\"iclose\");",
+	"	}	}",
+	"}",
+	"void",
+	"bfs_disk_oclose(void)",
+	"{	int i;",
+	"#ifdef VERBOSE",
+	"	bfs_printf(\"close_out\\n\");",
+	"#endif",
+	"	for (i = 0; i < Cores; i++)",
+	"	{	if (fsync(bfs_out_fd[i]) < 0)",
+	"		{	perror(\"fsync\");",
+	"		}",
+	"		if (close(bfs_out_fd[i]) < 0)",
+	"		{	perror(\"oclose\");",
+	"	}	}",
+	"}",
+	"#endif",
+	"void",
+	"bfs_write_snap(int fd)",
+	"{	if (write(fd, snap, strlen(snap)) != strlen(snap))",
+	"	{       printf(\"pan: error writing %%s\\n\", fnm);",
+	"		bfs_shutdown(\"file system error\");",
+	"	}",
+	"}",
+	"",
+	"void",
+	"bfs_one_step(BFS_Trail *t, int fd)",
+	"{	if (t && t->t_id != (T_ID) -1)",
+	"	{	sprintf(snap, \"%%d:%%d:%%d\\n\",",
+	"			trcnt++, t->pr, t->t_id);",
+	"		bfs_write_snap(fd);",
+	"	}",
+	"}",
+	"",
+	"void",
+	"bfs_putter(BFS_Trail *t, int fd)",
+	"{	if (t && t != (BFS_Trail *) t->ostate)",
+	"		bfs_putter((BFS_Trail *) t->ostate, fd);",
+	"#ifdef L_BOUND",
+	"	if (depthfound == trcnt)",
+	"	{	strcpy(snap, \"-1:-1:-1\\n\");",
+	"		bfs_write_snap(fd);",
+	"		depthfound = -1;",
+	"	}",
+	"#endif",
+	"	bfs_one_step(t, fd);",
+	"}",
+	"",
+	"void",
+	"bfs_nuerror(char *str)",
+	"{	int fd = make_trail();",
+	"",
+	"	if (fd < 0) return;",
+	"#ifdef VERI",
+	"	sprintf(snap, \"-2:%%d:-2\\n\", (uchar) ((P0 *)pptr(0))->_t);",
+	"	bfs_write_snap(fd);",
+	"#endif",
+	"#ifdef MERGED",
+	"	sprintf(snap, \"-4:-4:-4\\n\");",
+	"	bfs_write_snap(fd);",
+	"#endif",
+	"	trcnt = 1;",
+	"	if (strstr(str, \"invalid\"))",
+	"	{	bfs_putter((BFS_Trail *) trpt->ostate, fd);",
+	"	} else",
+	"	{	BFS_Trail x;",
+	"		memset((char *) &x, 0, sizeof(BFS_Trail));",
+	"		x.pr = trpt->pr;",
+	"		x.t_id = (trpt->o_t)?trpt->o_t->t_id:0;",
+	"		x.ostate = trpt->ostate;",
+	"		bfs_putter(&x, fd);",
+	"	}",
+	"	close(fd);",
+	"	if (errors >= upto && upto != 0)",
+	"	{	bfs_shutdown(str);",
+	"	}",
+	"}",
+	"",
+	"void",
+	"bfs_uerror(char *str)",
+	"{	static char laststr[256];",
+	"",
+	"	errors++;",
+	"	if (strncmp(str, laststr, 254) != 0)",
+	"	{	bfs_printf(\"pan:%%d: %%s (at depth %%ld)\\n\",",
+	"			errors, str, ((depthfound == -1)?depth:depthfound));",
+	"		strncpy(laststr, str, 254);",
+	"	}",
+	"#ifdef HAS_CODE",
+	"	if (readtrail) { wrap_trail(); return; }",
+	"#endif",
+	"	if (every_error != 0 || errors == upto)",
+	"	{	bfs_nuerror(str);",
+	"	}",
+	"	if (errors >= upto && upto != 0)",
+	"	{	bfs_shutdown(\"bfs_uerror\");",
+	"	}",
+	"	depthfound = -1;",
+	"}\n",
+	"void",
+	"bfs_Uerror(char *str)",
+	"{	/* bfs_uerror(str); */",
+	"	bfs_printf(\"pan:%%d: %%s (at depth %%ld)\\n\", ++errors, str,",
+	"		((depthfound == -1)?depth:depthfound));",
+	"	bfs_shutdown(\"bfs_Uerror\");",
+	"}",
+	0,
+};
diff -r 51b3bf8bc61b sys/src/cmd/spin/reprosrc.c
--- a/sys/src/cmd/spin/reprosrc.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/reprosrc.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,22 +1,21 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include <stdio.h>
+#include <assert.h>
 #include "spin.h"
 #include "y.tab.h"
 
 static int indent = 1;
 
+extern YYSTYPE yylval;
 extern ProcList	*rdy;
-void repro_seq(Sequence *);
+static void repro_seq(Sequence *);
 
 void
 doindent(void)
@@ -48,7 +47,7 @@
 	printf(" };\n");
 }
 
-void
+static void
 repro_seq(Sequence *s)
 {	Element *e;
 	Symbol *v;
@@ -96,7 +95,7 @@
 				doindent();
 				if (e->n->ntyp == C_CODE)
 				{	printf("c_code ");
-					plunk_inline(stdout, e->n->sym->name, 1);
+					plunk_inline(stdout, e->n->sym->name, 1, 1);
 				} else if (e->n->ntyp == 'c'
 				       &&  e->n->lft->ntyp == C_EXPR)
 				{	printf("c_expr { ");
@@ -134,3 +133,252 @@
 {
 	repro_proc(rdy);
 }
+
+static int in_decl;
+static int in_c_decl;
+static int in_c_code;
+
+void
+blip(int n, char *b)
+{	char mtxt[1024];
+
+	strcpy(mtxt, "");
+
+	switch (n) {
+	default:	if (n > 0 && n < 256)
+				sprintf(mtxt, "%c", n);
+			else
+				sprintf(mtxt, "<%d?>", n);
+
+			break;
+	case '(':	strcpy(mtxt, "("); in_decl++; break;
+	case ')':	strcpy(mtxt, ")"); in_decl--; break;
+	case '{':	strcpy(mtxt, "{"); break;
+	case '}':	strcpy(mtxt, "}"); break;
+	case '\t':	sprintf(mtxt, "\\t"); break;
+	case '\f':	sprintf(mtxt, "\\f"); break;
+	case '\n':	sprintf(mtxt, "\\n"); break;
+	case '\r':	sprintf(mtxt, "\\r"); break;
+	case 'c':	sprintf(mtxt, "condition"); break;
+	case 's':	sprintf(mtxt, "send"); break;
+	case 'r':	sprintf(mtxt, "recv"); break;
+	case 'R':	sprintf(mtxt, "recv poll"); break;
+	case '@':	sprintf(mtxt, "@"); break;
+	case '?':	sprintf(mtxt, "(x->y:z)"); break;
+	case NEXT:	sprintf(mtxt, "X"); break;
+	case ALWAYS:	sprintf(mtxt, "[]"); break;
+	case EVENTUALLY: sprintf(mtxt, "<>"); break;
+	case IMPLIES:	sprintf(mtxt, "->"); break;
+	case EQUIV:	sprintf(mtxt, "<->"); break;
+	case UNTIL:	sprintf(mtxt, "U"); break;
+	case WEAK_UNTIL: sprintf(mtxt, "W"); break;
+	case IN: sprintf(mtxt, "in"); break;
+	case ACTIVE:	sprintf(mtxt, "active"); break;
+	case AND:	sprintf(mtxt, "&&"); break;
+	case ARROW:	sprintf(mtxt, "->"); break;
+	case ASGN:	sprintf(mtxt, "="); break;
+	case ASSERT:	sprintf(mtxt, "assert"); break;
+	case ATOMIC:	sprintf(mtxt, "atomic"); break;
+	case BREAK:	sprintf(mtxt, "break"); break;
+	case C_CODE:	sprintf(mtxt, "c_code"); in_c_code++; break;
+	case C_DECL:	sprintf(mtxt, "c_decl"); in_c_decl++; break;
+	case C_EXPR:	sprintf(mtxt, "c_expr"); break;
+	case C_STATE:	sprintf(mtxt, "c_state"); break;
+	case C_TRACK:	sprintf(mtxt, "c_track"); break;
+	case CLAIM:	sprintf(mtxt, "never"); break;
+	case CONST:	sprintf(mtxt, "%d", yylval->val); break;
+	case DECR:	sprintf(mtxt, "--"); break;
+	case D_STEP:	sprintf(mtxt, "d_step"); break;
+	case D_PROCTYPE: sprintf(mtxt, "d_proctype"); break;
+	case DO:	sprintf(mtxt, "do"); break;
+	case DOT:	sprintf(mtxt, "."); break;
+	case ELSE:	sprintf(mtxt, "else"); break;
+	case EMPTY:	sprintf(mtxt, "empty"); break;
+	case ENABLED:	sprintf(mtxt, "enabled"); break;
+	case EQ:	sprintf(mtxt, "=="); break;
+	case EVAL:	sprintf(mtxt, "eval"); break;
+	case FI:	sprintf(mtxt, "fi"); break;
+	case FULL:	sprintf(mtxt, "full"); break;
+	case GE:	sprintf(mtxt, ">="); break;
+	case GET_P:	sprintf(mtxt, "get_priority"); break;
+	case GOTO:	sprintf(mtxt, "goto"); break;
+	case GT:	sprintf(mtxt, ">"); break;
+	case HIDDEN:	sprintf(mtxt, "hidden"); break;
+	case IF:	sprintf(mtxt, "if"); break;
+	case INCR:	sprintf(mtxt, "++"); break;
+
+	case INLINE:	sprintf(mtxt, "inline"); break;
+	case INIT:	sprintf(mtxt, "init"); break;
+	case ISLOCAL:	sprintf(mtxt, "local"); break;
+
+	case LABEL:	sprintf(mtxt, "<label-name>"); break;
+
+	case LE:	sprintf(mtxt, "<="); break;
+	case LEN:	sprintf(mtxt, "len"); break;
+	case LSHIFT:	sprintf(mtxt, "<<"); break;
+	case LT:	sprintf(mtxt, "<"); break;
+	case LTL:	sprintf(mtxt, "ltl"); break;
+
+	case NAME:	sprintf(mtxt, "%s", yylval->sym->name); break;
+
+	case XU:	switch (yylval->val) {
+			case XR:	sprintf(mtxt, "xr"); break;
+			case XS:	sprintf(mtxt, "xs"); break;
+			default:	sprintf(mtxt, "<?>"); break;
+			}
+			break;
+
+	case TYPE:	switch (yylval->val) {
+			case BIT:	sprintf(mtxt, "bit"); break;
+			case BYTE:	sprintf(mtxt, "byte"); break;
+			case CHAN:	sprintf(mtxt, "chan"); in_decl++; break;
+			case INT:	sprintf(mtxt, "int"); break;
+			case MTYPE:	sprintf(mtxt, "mtype"); break;
+			case SHORT:	sprintf(mtxt, "short"); break;
+			case UNSIGNED:	sprintf(mtxt, "unsigned"); break;
+			default:	sprintf(mtxt, "<unknown type>"); break;
+			}
+			break;
+
+	case NE:	sprintf(mtxt, "!="); break;
+	case NEG:	sprintf(mtxt, "!"); break;
+	case NEMPTY:	sprintf(mtxt, "nempty"); break;
+	case NFULL:	sprintf(mtxt, "nfull"); break;
+
+	case NON_ATOMIC: sprintf(mtxt, "<sub-sequence>"); break;
+
+	case NONPROGRESS: sprintf(mtxt, "np_"); break;
+	case OD:	sprintf(mtxt, "od"); break;
+	case OF:	sprintf(mtxt, "of"); break;
+	case OR:	sprintf(mtxt, "||"); break;
+	case O_SND:	sprintf(mtxt, "!!"); break;
+	case PC_VAL:	sprintf(mtxt, "pc_value"); break;
+	case PRINT:	sprintf(mtxt, "printf"); break;
+	case PRINTM:	sprintf(mtxt, "printm"); break;
+	case PRIORITY:	sprintf(mtxt, "priority"); break;
+	case PROCTYPE:	sprintf(mtxt, "proctype"); break;
+	case PROVIDED:	sprintf(mtxt, "provided"); break;
+	case RCV:	sprintf(mtxt, "?"); break;
+	case R_RCV:	sprintf(mtxt, "??"); break;
+	case RSHIFT:	sprintf(mtxt, ">>"); break;
+	case RUN:	sprintf(mtxt, "run"); break;
+	case SEP:	sprintf(mtxt, "::"); break;
+	case SEMI:	sprintf(mtxt, ";"); break;
+	case SET_P:	sprintf(mtxt, "set_priority"); break;
+	case SHOW:	sprintf(mtxt, "show"); break;
+	case SND:	sprintf(mtxt, "!"); break;
+
+	case INAME:
+	case UNAME:
+	case PNAME:
+	case STRING:	sprintf(mtxt, "%s", yylval->sym->name); break;
+
+	case TRACE:	sprintf(mtxt, "trace"); break;
+	case TIMEOUT:	sprintf(mtxt, "timeout"); break;
+	case TYPEDEF:	sprintf(mtxt, "typedef"); break;
+	case UMIN:	sprintf(mtxt, "-"); break;
+	case UNLESS:	sprintf(mtxt, "unless"); break;
+	}
+	strcat(b, mtxt);
+}
+
+void
+purge(char *b)
+{
+	if (strlen(b) == 0) return;
+
+	if (b[strlen(b)-1] != ':')	/* label? */
+	{	if (b[0] == ':' && b[1] == ':')
+		{	indent--;
+			doindent();
+			indent++;
+		} else
+		{	doindent();
+		}
+	}
+	printf("%s\n", b);
+	strcpy(b, "");
+
+	in_decl = 0;
+	in_c_code = 0;
+	in_c_decl = 0;
+}
+
+int pp_mode;
+extern int lex(void);
+
+void
+pretty_print(void)
+{	int c, lastc = 0;
+	char buf[1024];
+
+	pp_mode = 1;
+	indent = 0;
+	strcpy(buf, "");
+	while ((c = lex()) != EOF)
+	{
+		if ((lastc == IF || lastc == DO) && c != SEP)
+		{	indent--;	/* c_code if */
+		}
+		if (c == C_DECL  || c == C_STATE
+		||  c == C_TRACK || c == SEP
+		||  c == DO      || c == IF
+		|| (c == TYPE && !in_decl))
+		{	purge(buf); /* start on new line */
+		}
+
+		if (c == '{'
+		&& lastc != OF && lastc != IN
+		&& lastc != ATOMIC && lastc != D_STEP
+		&& lastc != C_CODE && lastc != C_DECL && lastc != C_EXPR)
+		{	purge(buf);
+		}
+
+		if (c == PREPROC)
+		{	int oi = indent;
+			purge(buf);
+			assert(strlen(yylval->sym->name) < sizeof(buf));
+			strcpy(buf, yylval->sym->name);
+			indent = 0;
+			purge(buf);
+			indent = oi;
+			continue;
+		}
+
+		if (c != ':' && c != SEMI
+		&&  c != ',' && c != '('
+		&&  c != '#' && lastc != '#'
+		&&  c != ARROW && lastc != ARROW
+		&&  c != '.' && lastc != '.'
+		&&  c != '!' && lastc != '!'
+		&&  c != SND && lastc != SND
+		&&  c != RCV && lastc != RCV
+		&&  c != O_SND && lastc != O_SND
+		&&  c != R_RCV && lastc != R_RCV
+		&&  (c != ']' || lastc != '[')
+		&&  (c != '>' || lastc != '<')
+		&&  (c != GT || lastc != LT)
+		&&  c != '@' && lastc != '@'
+		&&  c != DO && c != OD && c != IF && c != FI
+		&&  c != SEP && strlen(buf) > 0)
+			strcat(buf, " ");
+
+		if (c == '}' || c == OD || c == FI)
+		{	purge(buf);
+			indent--;
+		}
+		blip(c, buf);
+
+		if (c == '{' || c == DO || c == IF)
+		{	purge(buf);
+			indent++;
+		}
+
+		if (c == '}' || c == BREAK || c == SEMI
+		|| (c == ':' && lastc == NAME))
+		{	purge(buf);
+		}
+		lastc = c;
+	}
+	purge(buf);
+}
diff -r 51b3bf8bc61b sys/src/cmd/spin/run.c
--- a/sys/src/cmd/spin/run.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/run.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,13 +1,10 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include <stdlib.h>
 #include "spin.h"
@@ -16,15 +13,18 @@
 extern RunList	*X, *run;
 extern Symbol	*Fname;
 extern Element	*LastStep;
-extern int	Rvous, lineno, Tval, interactive, MadeChoice;
+extern int	Rvous, lineno, Tval, interactive, MadeChoice, Priority_Sum;
 extern int	TstOnly, verbose, s_trail, xspin, jumpsteps, depth;
-extern int	nproc, nstop, no_print, like_java;
+extern int	analyze, nproc, nstop, no_print, like_java, old_priority_rules;
+extern short	Have_claim;
 
 static long	Seed = 1;
 static int	E_Check = 0, Escape_Check = 0;
 
 static int	eval_sync(Element *);
 static int	pc_enabled(Lextok *n);
+static int	get_priority(Lextok *n);
+static void	set_priority(Lextok *n, Lextok *m);
 extern void	sr_buf(int, int);
 
 void
@@ -42,24 +42,23 @@
 
 Element *
 rev_escape(SeqList *e)
-{	Element *r;
+{	Element *r = (Element *) 0;
 
-	if (!e)
-		return (Element *) 0;
+	if (e)
+	{	if ((r = rev_escape(e->nxt)) == ZE) /* reversed order */
+		{	r = eval_sub(e->this->frst);
+	}	}
 
-	if ((r = rev_escape(e->nxt)) != ZE) /* reversed order */
-		return r;
-
-	return eval_sub(e->this->frst);		
+	return r;		
 }
 
 Element *
 eval_sub(Element *e)
 {	Element *f, *g;
 	SeqList *z;
-	int i, j, k;
+	int i, j, k, only_pos;
 
-	if (!e->n)
+	if (!e || !e->n)
 		return ZE;
 #ifdef DEBUG
 	printf("\n\teval_sub(%d %s: line %d) ",
@@ -69,8 +68,13 @@
 #endif
 	if (e->n->ntyp == GOTO)
 	{	if (Rvous) return ZE;
-		LastStep = e; f = get_lab(e->n, 1);
+		LastStep = e;
+		f = get_lab(e->n, 1);
+		f = huntele(f, e->status, -1); /* 5.2.3: was missing */
 		cross_dsteps(e->n, f->n);
+#ifdef DEBUG
+		printf("GOTO leads to %d\n", f->seqno);
+#endif
 		return f;
 	}
 	if (e->n->ntyp == UNLESS)
@@ -80,6 +84,7 @@
 	{	Element *has_else = ZE;
 		Element *bas_else = ZE;
 		int nr_else = 0, nr_choices = 0;
+		only_pos = -1;
 
 		if (interactive
 		&& !MadeChoice && !E_Check
@@ -89,8 +94,10 @@
 		{	printf("Select stmnt (");
 			whoruns(0); printf(")\n");
 			if (nproc-nstop > 1)
-			printf("\tchoice 0: other process\n");
-		}
+			{	printf("\tchoice 0: other process\n");
+				nr_choices++;
+				only_pos = 0;
+		}	}
 		for (z = e->sub, j=0; z; z = z->nxt)
 		{	j++;
 			if (interactive
@@ -113,13 +120,21 @@
 				if (!Enabled0(z->this->frst))
 					printf("unexecutable, ");
 				else
-					nr_choices++;
+				{	nr_choices++;
+					only_pos = j;
+				}
 				comment(stdout, z->this->frst->n, 0);
 				printf("\n");
 		}	}
 
 		if (nr_choices == 0 && has_else)
-			printf("\tchoice %d: (else)\n", nr_else);
+		{	printf("\tchoice %d: (else)\n", nr_else);
+			only_pos = nr_else;
+		}
+
+		if (nr_choices <= 1 && only_pos != -1 && !MadeChoice)
+		{	MadeChoice = only_pos;
+		}
 
 		if (interactive && depth >= jumpsteps
 		&& !Escape_Check
@@ -132,8 +147,11 @@
 				else
 					printf("Select [0-%d]: ", j);
 				fflush(stdout);
-				scanf("%s", buf);
-				if (isdigit(buf[0]))
+				if (scanf("%64s", buf) <= 0)
+				{	printf("no input\n");
+					return ZE;
+				}
+				if (isdigit((int)buf[0]))
 					k = atoi(buf);
 				else
 				{	if (buf[0] == 'q')
@@ -155,6 +173,7 @@
 			else
 				k = Rand()%j;	/* nondeterminism */
 		}
+
 		has_else = ZE;
 		bas_else = ZE;
 		for (i = 0, z = e->sub; i < j+k; i++)
@@ -215,7 +234,7 @@
 		} else
 		{	SeqList *x;
 			if (!(e->status & (D_ATOM))
-			&&  e->esc && verbose&32)
+			&&  e->esc && (verbose&32))
 			{	printf("Stmnt [");
 				comment(stdout, e->n, 0);
 				printf("] has escape(s): ");
@@ -234,11 +253,18 @@
 			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
+#if 1
+			if (!s_trail)	/* trail determines selections, new 5.2.5 */
+#endif
 			{	Escape_Check++;
 				if (like_java)
 				{	if ((g = rev_escape(e->esc)) != ZE)
 					{	if (verbose&4)
-							printf("\tEscape taken\n");
+						{	printf("\tEscape taken (-J) ");
+							if (g->n && g->n->fn)
+								printf("%s:%d", g->n->fn->name, g->n->ln);
+							printf("\n");
+						}
 						Escape_Check--;
 						return g;
 					}
@@ -246,18 +272,24 @@
 				{	for (x = e->esc; x; x = x->nxt)
 					{	if ((g = eval_sub(x->this->frst)) != ZE)
 						{	if (verbose&4)
-								printf("\tEscape taken\n");
+							{	printf("\tEscape taken ");
+								if (g->n && g->n->fn)
+									printf("%s:%d", g->n->fn->name, g->n->ln);
+								printf("\n");
+							}
 							Escape_Check--;
 							return g;
 				}	}	}
 				Escape_Check--;
 			}
-		
 			switch (e->n->ntyp) {
+			case ASGN:
+				if (check_track(e->n) == STRUCT) { break; }
+				/* else fall thru */
 			case TIMEOUT: case RUN:
 			case PRINT: case PRINTM:
 			case C_CODE: case C_EXPR:
-			case ASGN: case ASSERT:
+			case ASSERT:
 			case 's': case 'r': case 'c':
 				/* toplevel statements only */
 				LastStep = e;
@@ -308,7 +340,8 @@
 		t = Sym_typ(now->rgt);
 		break;
 	}
-	typ_ck(Sym_typ(now->lft), t, "assignment"); 
+	typ_ck(Sym_typ(now->lft), t, "assignment");
+
 	return setval(now->lft, eval(now->rgt));
 }
 
@@ -371,6 +404,10 @@
 	case  NEMPTY: return (qlen(now)>0);
 	case ENABLED: if (s_trail) return 1;
 		      return pc_enabled(now->lft);
+
+	case GET_P: return get_priority(now->lft);
+	case SET_P: set_priority(now->lft->lft, now->lft->rgt); return 1;
+
 	case    EVAL: return eval(now->lft);
 	case  PC_VAL: return pc_value(now->lft);
 	case NONPROGRESS: return nonprogress();
@@ -384,15 +421,21 @@
 	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  ASGN:
+		if (check_track(now) == STRUCT) { return 1; }
+		return assign(now);
 
-	case C_CODE: printf("%s:\t", now->sym->name);
-		     plunk_inline(stdout, now->sym->name, 0);
+	case C_CODE: if (!analyze)
+		     {	printf("%s:\t", now->sym->name);
+		     	plunk_inline(stdout, now->sym->name, 0, 1);
+		     }
 		     return 1; /* uninterpreted */
 
-	case C_EXPR: printf("%s:\t", now->sym->name);
-		     plunk_expr(stdout, now->sym->name);
-		     printf("\n");
+	case C_EXPR: if (!analyze)
+		     {	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;
@@ -407,6 +450,11 @@
 	case   '.': return 1;	/* return label for compound */
 	case   '@': return 0;	/* stop state */
 	case  ELSE: return 1;	/* only hit here in guided trails */
+
+	case ',':	/* reached through option -A with array initializer */
+	case 0:
+		    return 0;	/* not great, but safe */
+
 	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);
@@ -426,7 +474,6 @@
 			j = n->lft->val;
 		else
 			j = eval(n->lft);
-		Buf[0] = '\0';
 		sr_buf(j, 1);
 		dotag(fd, Buf);
 	}
@@ -437,9 +484,9 @@
 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];
+	int i, j; char lbuf[512]; /* matches value in sr_buf() */
+	extern char Buf[];	/* global, size 4096 */
+	char tBuf[4096];	/* match size of global Buf[] */
 
 	Buf[0] = '\0';
 	if (!no_print)
@@ -490,7 +537,7 @@
 		}
 		dotag(fd, Buf);
 	}
-	if (strlen(Buf) > 4096) fatal("printf string too long", 0);
+	if (strlen(Buf) >= 4096) fatal("printf string too long", 0);
 	return 1;
 }
 
@@ -512,6 +559,7 @@
 		verbose = v;
 		return i;
 
+	case SET_P:
 	case C_CODE: case C_EXPR:
 	case PRINT: case PRINTM:
 	case   ASGN: case ASSERT:
@@ -552,6 +600,7 @@
 	case '@':
 		return X->pid == (nproc-nstop-1);
 	case '.':
+	case SET_P:
 		return 1;
 	case GOTO:
 		if (Rvous) return 0;
@@ -594,9 +643,91 @@
 	for (Y = run; Y; Y = Y->nxt)
 		if (--i == pid)
 		{	oX = X; X = Y;
-			result = Enabled0(Y->pc);
+			result = Enabled0(X->pc);
 			X = oX;
 			break;
 		}
 	return result;
 }
+
+int
+pc_highest(Lextok *n)
+{	int i = nproc - nstop;
+	int pid = eval(n);
+	int target = 0, result = 1;
+	RunList *Y, *oX;
+
+	if (X->prov && !eval(X->prov)) return 0; /* can't be highest unless fully enabled */
+
+	for (Y = run; Y; Y = Y->nxt)
+	{	if (--i == pid)
+		{	target = Y->priority;
+			break;
+	}	}
+if (0) printf("highest for pid %d @ priority = %d\n", pid, target);
+
+	oX = X;
+	i = nproc - nstop;
+	for (Y = run; Y; Y = Y->nxt)
+	{	i--;
+if (0) printf("	pid %d @ priority %d\t", Y->pid, Y->priority);
+		if (Y->priority > target)
+		{	X = Y;
+if (0) printf("enabled: %s\n", Enabled0(X->pc)?"yes":"nope");
+if (0) printf("provided: %s\n", eval(X->prov)?"yes":"nope");
+			if (Enabled0(X->pc) && (!X->prov || eval(X->prov)))
+			{	result = 0;
+				break;
+		}	}
+else
+if (0) printf("\n");
+	}
+	X = oX;
+
+	return result;
+}
+
+int
+get_priority(Lextok *n)
+{	int i = nproc - nstop;
+	int pid = eval(n);
+	RunList *Y;
+
+	if (old_priority_rules)
+	{	return 1;
+	}
+
+	for (Y = run; Y; Y = Y->nxt)
+	{	if (--i == pid)
+		{	return Y->priority;
+	}	}
+	return 0;
+}
+
+void
+set_priority(Lextok *n, Lextok *p)
+{	int i = nproc - nstop - Have_claim;
+	int pid = eval(n);
+	RunList *Y;
+
+	if (old_priority_rules)
+	{	return;
+	}
+	for (Y = run; Y; Y = Y->nxt)
+	{	if (--i == pid)
+		{	Priority_Sum -= Y->priority;
+			Y->priority = eval(p);
+			Priority_Sum += Y->priority;
+			if (1)
+			{	printf("%3d: setting priority of proc %d (%s) to %d\n",
+					depth, pid, Y->n->name, Y->priority);
+	}	}	}
+	if (verbose&32)
+	{	printf("\tPid\tName\tPriority\n");
+		for (Y = run; Y; Y = Y->nxt)
+		{	printf("\t%d\t%s\t%d\n",
+				Y->pid,
+				Y->n->name,
+				Y->priority);
+	}	}
+}
diff -r 51b3bf8bc61b sys/src/cmd/spin/sched.c
--- a/sys/src/cmd/spin/sched.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/sched.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,13 +1,10 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include <stdlib.h>
 #include "spin.h"
@@ -19,19 +16,21 @@
 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;
+extern short	has_enabled, has_priority, has_code, replay;
+extern int	limited_vis, product, nclaims, old_priority_rules;
+extern int	old_scope_rules, scope_seq[128], scope_level, has_stdin;
+
+extern int	pc_highest(Lextok *n);
 
 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		nproc=0, nstop=0, Tval=0, Priority_Sum = 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 *);
@@ -42,13 +41,20 @@
 
 	r->n  = p->n;
 	r->tn = p->tn;
+	r->b  = p->b;
 	r->pid = nproc++ - nstop + Skip_claim;
+	r->priority = weight;
+	p->priority = (unsigned char) weight; /* not quite the best place of course */
 
-	if ((verbose&4) || (verbose&32))
-		printf("Starting %s with pid %d\n", p->n->name, r->pid);
-
+	if (!noparams && ((verbose&4) || (verbose&32)))
+	{	printf("Starting %s with pid %d",
+			p->n?p->n->name:"--", r->pid);
+		if (has_priority) printf(" priority %d", r->priority);
+		printf("\n");
+	}
 	if (!p->s)
-		fatal("parsing error, no sequence %s", p->n?p->n->name:"--");
+		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;
@@ -58,14 +64,18 @@
 
 	r->nxt = run;
 	r->prov = p->prov;
-	r->priority = weight;
+	if (weight < 1 || weight > 255)
+	{	fatal("bad process priority, valid range: 1..255", (char *) 0);
+	}
+
 	if (noparams) setlocals(r);
 	Priority_Sum += weight;
+
 	run = r;
 }
 
 ProcList *
-ready(Symbol *n, Lextok *p, Sequence *s, int det, Lextok *prov)
+ready(Symbol *n, Lextok *p, Sequence *s, int det, Lextok *prov, enum btypes b)
 	/* n=name, p=formals, s=body det=deterministic prov=provided */
 {	ProcList *r = (ProcList *) emalloc(sizeof(ProcList));
 	Lextok *fp, *fpt; int j; extern int Npars;
@@ -73,9 +83,15 @@
 	r->n = n;
 	r->p = p;
 	r->s = s;
+	r->b = b;
 	r->prov = prov;
-	r->tn = nrRdy++;
-	r->det = (short) det;
+	r->tn = (short) nrRdy++;
+	n->sc = scope_seq[scope_level];	/* scope_level should be 0 */
+
+	if (det != 0 && det != 1)
+	{	fprintf(stderr, "spin: bad value for det (cannot happen)\n");
+	}
+	r->det = (unsigned char) det;
 	r->nxt = rdy;
 	rdy = r;
 
@@ -128,13 +144,15 @@
 			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);
+		{	printf("proc %d = %s\n",
+				run->pid - Have_claim, run->n->name);
+		}
 		return;
 	}
 
 	if (dumptab
 	||  analyze
+	||  product
 	||  s_trail
 	|| !(verbose&4))
 		return;
@@ -161,9 +179,11 @@
 	Symbol *s = m->sym;	/* proctype name */
 	Lextok *n = m->lft;	/* actual parameters */
 
-	if (m->val < 1) m->val = 1;	/* minimum priority */
+	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 (strcmp(s->name, p->n->name) == 0)
 		{	if (nproc-nstop >= MAXP)
 			{	printf("spin: too many processes (%d max)\n", MAXP);
 				break;
@@ -173,7 +193,7 @@
 			setparams(run, p, n);
 			setlocals(run); /* after setparams */
 			return run->pid - Have_claim + Skip_claim; /* effective simu pid */
-		}
+	}	}
 	return 0; /* process not found */
 }
 
@@ -208,26 +228,29 @@
 	RunList  *r, *q = (RunList *) 0;
 
 	for (p = rdy; p; p = p->nxt)
-		if (p->tn == n
-		&&  strcmp(p->n->name, ":never:") == 0)
+		if (p->tn == n && p->b == N_CLAIM)
 		{	runnable(p, 1, 1);
 			goto found;
 		}
-	printf("spin: couldn't find claim (ignored)\n");
+	printf("spin: couldn't find claim %d (ignored)\n", n);
+	if (verbose&32)
+	for (p = rdy; p; p = p->nxt)
+		printf("\t%d = %s\n", p->tn, p->n->name);
+
 	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:");
+	{	extern char Buf[];
+		depth = 0;
+		sprintf(Buf, "%d:%s", 0, p->n->name);
+		pstext(0, Buf);
 		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 (r->b != N_CLAIM)
+			{	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 */
 
@@ -288,7 +311,7 @@
 		nproc - Have_claim + Skip_claim,
 		(xspin || nproc!=1)?"es":"");
 short_cut:
-	if (xspin) alldone(0);	/* avoid an abort from xspin */
+	if (s_trail || xspin) alldone(0);	/* avoid an abort from xspin */
 	if (fini)  alldone(1);
 }
 
@@ -332,6 +355,24 @@
 	return e;
 }
 
+static int
+x_can_run(void)	/* the currently selected process in X can run */
+{
+	if (X->prov && !eval(X->prov))
+	{
+if (0) printf("pid %d cannot run: not provided\n", X->pid);
+		return 0;
+	}
+	if (has_priority && !old_priority_rules)
+	{	Lextok *n = nn(ZN, CONST, ZN, ZN);
+		n->val = X->pid;
+if (0) printf("pid %d %s run (priority)\n", X->pid, pc_highest(n)?"can":"cannot");
+		return pc_highest(n);
+	}
+if (0) printf("pid %d can run\n", X->pid);
+	return 1;
+}
+
 static RunList *
 pickproc(RunList *Y)
 {	SeqList *z; Element *has_else;
@@ -343,7 +384,25 @@
 		return NULL;
 	}
 	if (!interactive || depth < jumpsteps)
-	{	/* was: j = (int) Rand()%(nproc-nstop); */
+	{	if (has_priority && !old_priority_rules)	/* new 6.3.2 */
+		{	j = Rand()%(nproc-nstop);
+			for (X = run; X; X = X->nxt)
+			{	if (j-- <= 0)
+					break;
+			}
+			if (X == NULL)
+			{	fatal("unexpected, pickproc", (char *)0);
+			}
+			j = nproc - nstop;
+			while (j-- > 0)
+			{	if (x_can_run())
+				{	Y = X;
+					break;
+				}
+				X = (X->nxt)?X->nxt:run;
+			}
+			return Y;
+		}
 		if (Priority_Sum < nproc-nstop)
 			fatal("cannot happen - weights", (char *)0);
 		j = (int) Rand()%Priority_Sum;
@@ -354,6 +413,7 @@
 			X = X->nxt;
 			if (!X) { Y = NULL; X = run; }
 		}
+
 	} else
 	{	int only_choice = -1;
 		int no_choice = 0, proc_no_ch, proc_k;
@@ -365,8 +425,7 @@
 
 			Choices[X->pid] = (short) k;
 
-			if (!X->pc
-			||  (X->prov && !eval(X->prov)))
+			if (!X->pc || !x_can_run())
 			{	if (X == run)
 					Choices[X->pid] = 0;
 				continue;
@@ -457,9 +516,12 @@
 		} else
 		{	char buf[256];
 			fflush(stdout);
-			scanf("%s", buf);
+			if (scanf("%64s", buf) == 0)
+			{	printf("\tno input\n");
+				goto try_again;
+			}
 			j = -1;
-			if (isdigit(buf[0]))
+			if (isdigit((int) buf[0]))
 				j = atoi(buf);
 			else
 			{	if (buf[0] == 'q')
@@ -484,6 +546,26 @@
 }
 
 void
+multi_claims(void)
+{	ProcList *p, *q = NULL;
+
+	if (nclaims > 1)
+	{	printf("  the model contains %d never claims:", nclaims);
+		for (p = rdy; p; p = p->nxt)
+		{	if (p->b == N_CLAIM)
+			{	printf("%s%s", q?", ":" ", p->n->name);
+				q = p;
+		}	}
+		printf("\n");
+		printf("  only one claim is used in a verification run\n");
+		printf("  choose which one with ./pan -a -N name (defaults to -N %s)\n",
+			q?q->n->name:"--");
+		printf("  or use e.g.: spin -search -ltl %s %s\n",
+			q?q->n->name:"--", Fname?Fname->name:"filename");
+	}
+}
+
+void
 sched(void)
 {	Element *e;
 	RunList *Y = NULL;	/* previous process in run queue */
@@ -498,19 +580,33 @@
 		dumplabels();
 		return;
 	}
+	if (has_code && !analyze)
+	{	printf("spin: warning: c_code fragments remain uninterpreted\n");
+		printf("      in random simulations with spin; use ./pan -r instead\n");
+	}
 
 	if (has_enabled && u_sync > 0)
 	{	printf("spin: error, cannot use 'enabled()' in ");
 		printf("models with synchronous channels.\n");
 		nr_errs++;
 	}
-	if (analyze)
+	if (product)
+	{	sync_product();
+		alldone(0);
+	}
+	if (analyze && (!replay || has_code))
 	{	gensrc();
+		multi_claims();
 		return;
-	} else if (s_trail)
+	}
+	if (replay && !has_code)
+	{	return;
+	}
+	if (s_trail)
 	{	match_trail();
 		return;
 	}
+
 	if (claimproc)
 	printf("warning: never claim not used in random simulation\n");
 	if (eventmap)
@@ -543,9 +639,9 @@
 		depth++; LastStep = ZE;
 		oX = X;	/* a rendezvous could change it */
 		go = 1;
-		if (X && X->prov && X->pc
+		if (X->pc
 		&& !(X->pc->status & D_ATOM)
-		&& !eval(X->prov))
+		&& !x_can_run())
 		{	if (!xspin && ((verbose&32) || (verbose&4)))
 			{	p_talk(X->pc, 1);
 				printf("\t<<Not Enabled>>\n");
@@ -557,9 +653,10 @@
 			&& ((verbose&32) || (verbose&4)))
 			{	if (X == oX)
 				if (!(e->status & D_ATOM) || (verbose&32)) /* no talking in d_steps */
-				{	p_talk(X->pc, 1);
+				{	if (!LastStep) LastStep = X->pc;
+					/* A. Tanaka, changed order */
+					p_talk(LastStep, 1);
 					printf("	[");
-					if (!LastStep) LastStep = X->pc;
 					comment(stdout, LastStep->n, 0);
 					printf("]\n");
 				}
@@ -570,7 +667,8 @@
 				if (xspin)
 					printf("\n");
 			}
-			if (oX != X)
+			if (oX != X
+			||  (X->pc->status & (ATOM|D_ATOM)))		/* new 5.0 */
 			{	e = silent_moves(e);
 				notbeyond = 0;
 			}
@@ -587,10 +685,12 @@
 			}
 		} else
 		{	depth--;
-			if (oX->pc->status & D_ATOM)
-			 non_fatal("stmnt in d_step blocks", (char *)0);
-
-			if (X->pc->n->ntyp == '@'
+			if (oX->pc && (oX->pc->status & D_ATOM))
+			{	non_fatal("stmnt in d_step blocks", (char *)0);
+			}
+			if (X->pc
+			&&  X->pc->n
+			&&  X->pc->n->ntyp == '@'
 			&&  X->pid == (nproc-nstop-1))
 			{	if (X != run && Y != NULL)
 					Y->nxt = X->nxt;
@@ -610,14 +710,19 @@
 				X = (X->nxt) ? X->nxt : run;
 			} else
 			{	if (p_blocked(X->pid))
-				{	if (Tval) break;
-					Tval = 1;
-					if (depth >= jumpsteps)
+				{	if (Tval && !has_stdin)
+					{	break;
+					}
+					if (!Tval && depth >= jumpsteps)
 					{	oX = X;
 						X = (RunList *) 0; /* to suppress indent */
 						dotag(stdout, "timeout\n");
 						X = oX;
+						Tval = 1;
 		}	}	}	}
+
+		if (!run || !X) break;	/* new 5.0 */
+
 		Y = pickproc(X);
 		notbeyond = 0;
 	}
@@ -662,7 +767,7 @@
 				printf("	[");
 				comment(stdout, s_was->n, 0);
 				printf("]\n");
-				tmp = orun; orun = X; X = tmp;
+				tmp = orun; /* orun = X; */ X = tmp;
 				if (!LastStep) LastStep = X->pc;
 				p_talk(LastStep, 1);
 				printf("	[");
@@ -692,25 +797,33 @@
 	int i;
 
 	for (t = r->symtab; t; t = t->next)
-		if (strcmp(t->name, s->name) == 0)
+		if (strcmp(t->name, s->name) == 0
+		&& (old_scope_rules
+		 || strcmp((const char *)t->bscp, (const char *)s->bscp) == 0))
 			return;		/* it's already there */
 
 	t = (Symbol *) emalloc(sizeof(Symbol));
 	t->name = s->name;
 	t->type = s->type;
 	t->hidden = s->hidden;
+	t->isarray = s->isarray;
 	t->nbits  = s->nbits;
 	t->nel  = s->nel;
 	t->ini  = s->ini;
 	t->setat = depth;
 	t->context = r->n;
+
+	t->bscp  = (unsigned char *) emalloc(strlen((const char *)s->bscp)+1);
+	strcpy((char *)t->bscp, (const char *)s->bscp);
+
 	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 */
+		{	(void) checkvar(t, 0);	/* initialize it */
+		}
 	} else
 	{	if (s->Sval)
 			fatal("saw preinitialized struct %s", s->name);
@@ -759,7 +872,7 @@
 
 	if (!a)
 		fatal("missing actual parameters: '%s'", p->n->name);
-	if (t->sym->nel != 1)
+	if (t->sym->nel > 1 || t->sym->isarray)
 		fatal("array in parameter list, %s", t->sym->name);
 	k = eval(a->lft);
 
@@ -768,7 +881,7 @@
 	ft = Sym_typ(t);
 
 	if (at != ft && (at == CHAN || ft == CHAN))
-	{	char buf[128], tag1[64], tag2[64];
+	{	char buf[256], tag1[64], tag2[64];
 		(void) sputtype(tag1, ft);
 		(void) sputtype(tag2, at);
 		sprintf(buf, "type-clash in params of %s(..), (%s<-> %s)",
@@ -809,8 +922,11 @@
 		return ZS;
 	}
 	for (r = X->symtab; r; r = r->next)
-		if (strcmp(r->name, s->name) == 0)
-			break;
+	{	if (strcmp(r->name, s->name) == 0
+		&& (old_scope_rules
+		 || strcmp((const char *)r->bscp, (const char *)s->bscp) == 0))
+		{	break;
+	}	}
 	if (!r)
 	{	addsymbol(X, s);
 		r = X->symtab;
@@ -878,7 +994,11 @@
 		printf(" -");
 	else
 		printf("%2d", X->pid - Have_claim);
-	printf(" (%s) ", X->n->name);
+	if (old_priority_rules)
+	{	printf(" (%s) ", X->n->name);
+	} else
+	{	printf(" (%s:%d) ", X->n->name, X->priority);
+	}
 }
 
 static void
@@ -895,6 +1015,7 @@
 void
 p_talk(Element *e, int lnr)
 {	static int lastnever = -1;
+	static char nbuf[128];
 	int newnever = -1;
 
 	if (e && e->n)
@@ -918,9 +1039,22 @@
 
 	whoruns(lnr);
 	if (e)
-	{	printf("line %3d %s (state %d)",
+	{	if (e->n)
+		{	char *ptr = e->n->fn->name;
+			char *qtr = nbuf;
+			while (*ptr != '\0')
+			{	if (*ptr != '"')
+				{	*qtr++ = *ptr;
+				}
+				ptr++;
+			}
+			*qtr = '\0';
+		} else
+		{	strcpy(nbuf, "-");
+		}
+		printf("%s:%d (state %d)",
+			nbuf,
 			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 */
@@ -943,8 +1077,9 @@
 	{	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);
+	if ((i = find_lab(n->sym, n->lft->sym, 1)) == 0)	/* remotelab */
+	{	fatal("unknown labelname: %s", n->sym->name);
+	}
 	return i;
 }
 
@@ -970,7 +1105,8 @@
 	}	}
 
 	if (prno < 0)
-		return 0;	/* non-existing process */
+	{	return 0;	/* non-existing process */
+	}
 #if 0
 	i = nproc - nstop;
 	for (Y = run; Y; Y = Y->nxt)
@@ -978,7 +1114,7 @@
 		printf("	%s: i=%d, prno=%d, ->pid=%d\n", Y->n->name, i, prno, Y->pid);
 	}
 #endif
-	i = nproc - nstop;
+	i = nproc - nstop + Skip_claim;	/* 6.0: added Skip_claim */
 	for (Y = run; Y; Y = Y->nxt)
 	if (--i == prno)
 	{	if (strcmp(Y->n->name, n->lft->sym->name) != 0)
@@ -988,12 +1124,13 @@
 		}
 		if (strcmp(n->sym->name, "_p") == 0)
 		{	if (Y->pc)
-				return Y->pc->seqno;
+			{	return Y->pc->seqno;
+			}
 			/* harmless, can only happen with -t */
 			return 0;
 		}
-#if 1
-		/* new 4.0 allow remote variables */
+
+		/* check remote variables */
 		oX = X;
 		X = Y;
 
@@ -1001,17 +1138,20 @@
 		n->lft = n->rgt;
 
 		os = n->sym;
-		n->sym = findloc(n->sym);
-
+		if (!n->sym->context)
+		{	n->sym->context = Y->n;
+		}
+		{ int rs = old_scope_rules;
+		  old_scope_rules = 1; /* 6.4.0 */
+		  n->sym = findloc(n->sym);
+		  old_scope_rules = rs;
+		}
 		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);
diff -r 51b3bf8bc61b sys/src/cmd/spin/spin.h
--- a/sys/src/cmd/spin/spin.h	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/spin.h	Wed Nov 22 00:21:47 2017 -0800
@@ -1,13 +1,10 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #ifndef SEEN_SPIN_H
 #define SEEN_SPIN_H
@@ -15,6 +12,15 @@
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#if !defined(WIN32) && !defined(WIN64)
+ #include <unistd.h>
+#endif
+#if !defined(PC) && !defined(_PLAN9)
+ #include <memory.h>
+#endif
+
+enum	    { INIV, PUTV, LOGV }; /* used in pangen1.c */
+enum btypes { NONE, N_CLAIM, I_PROC, A_PROC, P_PROC, E_TRACE, N_TRACE };
 
 typedef struct Lextok {
 	unsigned short	ntyp;	/* node type */
@@ -22,6 +28,7 @@
 	int	val;		/* value attribute */
 	int	ln;		/* line number */
 	int	indstep;	/* part of d_step sequence */
+	int	uiid;		/* inline id, if non-zero */
 	struct Symbol	*fn;	/* file name */
 	struct Symbol	*sym;	/* symbol reference */
         struct Sequence *sq;	/* sequence */
@@ -54,6 +61,9 @@
 				  64=treat as if local; 128=read at least once
 				 */
 	unsigned char	colnr;	/* for use with xspin during simulation */
+	unsigned char	isarray; /* set if decl specifies array bound */
+	unsigned char	*bscp;	/* block scope */
+	int	sc;		/* scope seq no -- set only for proctypes */
 	int	nbits;		/* optional width specifier */
 	int	nel;		/* 1 if scalar, >1 if array   */
 	int	setat;		/* last depth value changed   */
@@ -124,7 +134,7 @@
 	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  */
+	unsigned int	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 */
@@ -136,6 +146,7 @@
 	Element	*frst;
 	Element	*last;		/* links onto continuations */
 	Element *extent;	/* last element in original */
+	int	minel;		/* minimum Seqno, set and used only in guided.c */
 	int	maxel;		/* 1+largest id in sequence */
 } Sequence;
 
@@ -148,6 +159,7 @@
 	Symbol	*s;
 	Symbol	*c;
 	Element	*e;
+	int	uiid;		/* non-zero if label appears in an inline */
 	int	visible;	/* label referenced in claim (slice relevant) */
 	struct Label	*nxt;
 } Label;
@@ -157,11 +169,17 @@
 	struct Lbreak	*nxt;
 } Lbreak;
 
+typedef struct L_List {
+	Lextok *n;
+	struct L_List	*nxt;
+} L_List;
+
 typedef struct RunList {
 	Symbol	*n;		/* name            */
 	int	tn;		/* ordinal of type */
 	int	pid;		/* process id      */
 	int	priority;	/* for simulations only */
+	enum btypes b;		/* the type of process */
 	Element	*pc;		/* current stmnt   */
 	Sequence *ps;		/* used by analyzer generator */
 	Lextok	*prov;		/* provided clause */
@@ -174,11 +192,19 @@
 	Lextok	*p;		/* parameters */
 	Sequence *s;		/* body       */
 	Lextok	*prov;		/* provided clause */
+	enum btypes b;		/* e.g., claim, trace, proc */
 	short	tn;		/* ordinal number */
-	short	det;		/* deterministic */
+	unsigned char	det;	/* deterministic */
+	unsigned char   unsafe;	/* contains global var inits */
+	unsigned char	priority; /* process priority, if any */
 	struct ProcList	*nxt;	/* linked list */
 } ProcList;
 
+typedef struct QH {
+	int	n;
+	struct	QH *nxt;
+} QH;
+
 typedef	Lextok *Lexptr;
 
 #define YYSTYPE	Lexptr
@@ -194,7 +220,8 @@
 #define DONE2	 16		/* used in putcode and main*/
 #define D_ATOM	 32		/* deterministic atomic    */
 #define ENDSTATE 64		/* normal endstate         */
-#define CHECK2	128
+#define CHECK2	128		/* status bits for remote ref check */
+#define CHECK3	256		/* status bits for atomic jump check */
 
 #define Nhash	255    		/* slots in symbol hash-table */
 
@@ -216,18 +243,24 @@
 
 #define SOMETHINGBIG	65536
 #define RATHERSMALL	512
+#define MAXSCOPESZ	1024
 
 #ifndef max
-#define max(a,b) (((a)<(b)) ? (b) : (a))
+ #define max(a,b) (((a)<(b)) ? (b) : (a))
 #endif
 
-enum	{ INIV, PUTV, LOGV };	/* for pangen[14].c */
+#ifdef PC
+ #define MFLAGS	"wb"
+#else
+ #define MFLAGS	"w"
+#endif
 
 /***** prototype definitions *****/
 Element	*eval_sub(Element *);
 Element	*get_lab(Lextok *, int);
-Element	*huntele(Element *, int, int);
+Element	*huntele(Element *, unsigned int, int);
 Element	*huntstart(Element *);
+Element *mk_skip(void);
 Element	*target(Element *);
 
 Lextok	*do_unless(Lextok *, Lextok *);
@@ -238,8 +271,9 @@
 Lextok	*rem_lab(Symbol *, Lextok *, Symbol *);
 Lextok	*rem_var(Symbol *, Lextok *, Symbol *, Lextok *);
 Lextok	*tail_add(Lextok *, Lextok *);
+Lextok	*return_statement(Lextok *);
 
-ProcList *ready(Symbol *, Lextok *, Sequence *, int, Lextok *);
+ProcList *ready(Symbol *, Lextok *, Sequence *, int, Lextok *, enum btypes);
 
 SeqList	*seqlist(Sequence *, SeqList *);
 Sequence *close_seq(int);
@@ -250,7 +284,8 @@
 Symbol	*lookup(char *);
 Symbol	*prep_inline(Symbol *, Lextok *);
 
-char	*emalloc(int);
+char	*put_inline(FILE *, char *);
+char	*emalloc(size_t);
 long	Rand(void);
 
 int	any_oper(Lextok *, int);
@@ -258,6 +293,7 @@
 int	c_add_sv(FILE *);
 int	cast_val(int, int, int);
 int	checkvar(Symbol *, int);
+int	check_track(Lextok *);
 int	Cnt_flds(Lextok *);
 int	cnt_mpars(Lextok *);
 int	complete_rendez(void);
@@ -274,12 +310,14 @@
 int	in_bound(Symbol *, int);
 int	interprint(FILE *, Lextok *);
 int	printm(FILE *, Lextok *);
+int	is_inline(void);
 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	pid_is_claim(int);
 int	proper_enabler(Lextok *);
 int	putcode(FILE *, Sequence *, Element *, int, int, int);
 int	q_is_sync(Lextok *);
@@ -298,7 +336,6 @@
 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);
@@ -309,7 +346,6 @@
 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 *);
@@ -321,6 +357,7 @@
 void	checkrun(Symbol *, int);
 void	comment(FILE *, Lextok *, int);
 void	cross_dsteps(Lextok *, Lextok *);
+void	disambiguate(void);
 void	doq(Symbol *, int, RunList *);
 void	dotag(FILE *, char *);
 void	do_locinits(FILE *);
@@ -344,20 +381,22 @@
 void	ini_struct(Symbol *);
 void	loose_ends(void);
 void	make_atomic(Sequence *, int);
+void	mark_last(void);
 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	ntimes(FILE *, int, int, const char *c[]);
 void	open_seq(int);
 void	p_talk(Element *, int);
-void	pickup_inline(Symbol *, Lextok *);
+void	pickup_inline(Symbol *, Lextok *, Lextok *);
 void	plunk_c_decls(FILE *);
 void	plunk_c_fcts(FILE *);
 void	plunk_expr(FILE *, char *);
-void	plunk_inline(FILE *, char *, int);
+void	plunk_inline(FILE *, char *, int, int);
 void	prehint(Symbol *);
 void	preruse(FILE *, Lextok *);
+void	pretty_print(void);
 void	prune_opts(Lextok *);
 void	pstext(int, char *);
 void	pushbreak(void);
@@ -383,17 +422,23 @@
 void	struct_name(Lextok *, Symbol *, int, char *);
 void	symdump(void);
 void	symvar(Symbol *);
+void	sync_product(void);
 void	trackchanuse(Lextok *, Lextok *, int);
 void	trackvar(Lextok *, Lextok *);
 void	trackrun(Lextok *);
-void	trapwonly(Lextok *, char *);	/* spin.y and main.c */
+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 *, ...);
+
+extern	int unlink(const char *);
+
+#define TMP_FILE1 "._s_p_i_n_"
+#define TMP_FILE2 "._n_i_p_s_"
+
 #endif
diff -r 51b3bf8bc61b sys/src/cmd/spin/spin.y
--- a/sys/src/cmd/spin/spin.y	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/spin.y	Wed Nov 22 00:21:47 2017 -0800
@@ -1,47 +1,69 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 %{
 #include "spin.h"
+#include <sys/types.h>
+#ifndef PC
+#include <unistd.h>
+#endif
 #include <stdarg.h>
 
-#define YYDEBUG	0
+#define YYMAXDEPTH	20000	/* default is 10000 */
+#define YYDEBUG		0
 #define Stop	nn(ZN,'@',ZN,ZN)
+#define PART0	"place initialized declaration of "
+#define PART1	"place initialized chan decl of "
+#define PART2	" at start of proctype "
+
+static	Lextok *ltl_to_string(Lextok *);
 
 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	Lextok *for_body(Lextok *, int);
+extern	void for_setup(Lextok *, Lextok *, Lextok *);
+extern	Lextok *for_index(Lextok *, Lextok *);
+extern	Lextok *sel_index(Lextok *, Lextok *, Lextok *);
+extern  void    keep_track_off(Lextok *);
+extern	void	safe_break(void);
+extern	void	restore_break(void);
+extern  int	u_sync, u_async, dumptab, scope_level;
+extern	int	initialization_ok;
+extern	short	has_sorted, has_random, has_enabled, has_pcvalue, has_np, has_priority;
+extern	short	has_code, has_state, has_ltl, has_io;
 extern	void	count_runs(Lextok *);
 extern	void	no_internals(Lextok *);
 extern	void	any_runs(Lextok *);
+extern	void	explain(int);
+extern	void	ltl_list(char *, char *);
 extern	void	validref(Lextok *, Lextok *);
+extern  void	sanity_check(Lextok *);
 extern	char	yytext[];
 
 int	Mpars = 0;	/* max nr of message parameters  */
-int	runsafe = 1;	/* 1 if all run stmnts are in init */
+int	nclaims = 0;	/* nr of never claims */
+int	ltl_mode = 0;	/* set when parsing an ltl formula */
 int	Expand_Ok = 0, realread = 1, IArgs = 0, NamesNotAdded = 0;
+int	in_for = 0, in_seq = 0, par_cnt = 0;
+int	dont_simplify = 0;
 char	*claimproc = (char *) 0;
 char	*eventmap = (char *) 0;
 
-static	int	Embedded = 0, inEventMap = 0, has_ini = 0;
+static	char *ltl_name;
+static	int  Embedded = 0, inEventMap = 0, has_ini = 0;
 
 %}
 
-%token	ASSERT PRINT PRINTM
+%token	ASSERT PRINT PRINTM PREPROC
 %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	RUN LEN ENABLED SET_P GET_P EVAL PC_VAL
+%token	TYPEDEF MTYPE INLINE RETURN LABEL OF
+%token	GOTO BREAK ELSE SEMI ARROW
+%token	IF FI DO OD FOR SELECT IN SEP DOTDOT
 %token	ATOMIC NON_ATOMIC D_STEP UNLESS
 %token  TIMEOUT NONPROGRESS
 %token	ACTIVE PROCTYPE D_PROCTYPE
@@ -50,12 +72,16 @@
 %token	FULL EMPTY NFULL NEMPTY
 %token	CONST TYPE XU			/* val */
 %token	NAME UNAME PNAME INAME		/* sym */
-%token	STRING CLAIM TRACE INIT		/* sym */
+%token	STRING CLAIM TRACE INIT	LTL	/* sym */
 
 %right	ASGN
 %left	SND O_SND RCV R_RCV /* SND doubles as boolean negation */
+%left	IMPLIES EQUIV			/* ltl */
 %left	OR
 %left	AND
+%left	ALWAYS EVENTUALLY		/* ltl */
+%left	UNTIL WEAK_UNTIL RELEASE	/* ltl */
+%right	NEXT				/* ltl */
 %left	'|'
 %left	'^'
 %left	'&'
@@ -81,17 +107,25 @@
 unit	: proc		/* proctype { }       */
 	| init		/* init { }           */
 	| claim		/* never claim        */
+	| ltl		/* ltl formula        */
 	| events	/* event assertions   */
 	| one_decl	/* variables, chans   */
 	| utype		/* user defined types */
 	| c_fcts	/* c functions etc.   */
 	| ns		/* named sequence     */
-	| SEMI		/* optional separator */
+	| semi		/* optional separator */
 	| error
 	;
 
+l_par	: '('		{ par_cnt++; }
+	;
+
+r_par	: ')'		{ par_cnt--; }
+	;
+
+
 proc	: inst		/* optional instantiator */
-	  proctype NAME	{
+	  proctype NAME	{ 
 			  setptype($3, PROCTYPE, ZN);
 			  setpname($3);
 			  context = $3->sym;
@@ -99,20 +133,29 @@
 			  Expand_Ok++; /* expand struct names in decl */
 			  has_ini = 0;
 			}
-	  '(' decl ')'	{ Expand_Ok--;
+	  l_par decl r_par	{ 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;
+				rl = ready($3->sym, $6, $11->sq, $2->val, $10, A_PROC);
 			  	for (j = 0; j < $1->val; j++)
-				runnable(rl, $9?$9->val:1, 1);
+				{	runnable(rl, $9?$9->val:1, 1);
 				announce(":root:");
+				}
 				if (dumptab) $3->sym->ini = $1;
+			  } else
+			  {	rl = ready($3->sym, $6, $11->sq, $2->val, $10, P_PROC);
+			  }
+			  if (rl && has_ini == 1)	/* global initializations, unsafe */
+			  {	/* printf("proctype %s has initialized data\n",
+					$3->sym->name);
+				 */
+				rl->unsafe = 1;
 			  }
 			  context = ZS;
 			}
@@ -124,7 +167,7 @@
 
 inst	: /* empty */	{ $$ = ZN; }
 	| ACTIVE	{ $$ = nn(ZN,CONST,ZN,ZN); $$->val = 1; }
-	| ACTIVE '[' CONST ']' {
+	| ACTIVE '[' const_expr ']' {
 			  $$ = nn(ZN,CONST,ZN,ZN); $$->val = $3->val;
 			  if ($3->val > 255)
 				non_fatal("max nr of processes is 255\n", "");
@@ -133,10 +176,10 @@
 			  $$ = nn(ZN,CONST,ZN,ZN);
 			  $$->val = 0;
 			  if (!$3->sym->type)
-				non_fatal("undeclared variable %s",
+				fatal("undeclared variable %s",
 					$3->sym->name);
 			  else if ($3->sym->ini->ntyp != CONST)
-				non_fatal("need constant initializer for %s\n",
+				fatal("need constant initializer for %s\n",
 					$3->sym->name);
 			  else
 				$$->val = $3->sym->ini->val;
@@ -146,41 +189,84 @@
 init	: INIT		{ context = $1->sym; }
 	  Opt_priority
 	  body		{ ProcList *rl;
-			  rl = ready(context, ZN, $4->sq, 0, ZN);
+			  rl = ready(context, ZN, $4->sq, 0, ZN, I_PROC);
 			  runnable(rl, $3?$3->val:1, 1);
 			  announce(":root:");
 			  context = ZS;
         		}
 	;
 
-claim	: CLAIM		{ context = $1->sym;
-			  if (claimproc)
-				non_fatal("claim %s redefined", claimproc);
+ltl	: LTL optname2	{ ltl_mode = 1; ltl_name = $2->sym->name; }
+	  ltl_body	{ if ($4) ltl_list($2->sym->name, $4->sym->name);
+			  ltl_mode = 0; has_ltl = 1;
+			}
+	;
+
+ltl_body: '{' full_expr OS '}' { $$ = ltl_to_string($2); }
+	| error		{ $$ = NULL; }
+	;
+
+claim	: CLAIM	optname	{ if ($2 != ZN)
+			  {	$1->sym = $2->sym;	/* new 5.3.0 */
+			  }
+			  nclaims++;
+			  context = $1->sym;
+			  if (claimproc && !strcmp(claimproc, $1->sym->name))
+			  {	fatal("claim %s redefined", claimproc);
+			  }
 			  claimproc = $1->sym->name;
 			}
-	  body		{ (void) ready($1->sym, ZN, $3->sq, 0, ZN);
+	  body		{ (void) ready($1->sym, ZN, $4->sq, 0, ZN, N_CLAIM);
         		  context = ZS;
         		}
 	;
 
+optname : /* empty */	{ char tb[32];
+			  memset(tb, 0, 32);
+			  sprintf(tb, "never_%d", nclaims);
+			  $$ = nn(ZN, NAME, ZN, ZN);
+			  $$->sym = lookup(tb);
+			}
+	| NAME		{ $$ = $1; }
+	;
+
+optname2 : /* empty */ { char tb[32]; static int nltl = 0;
+			  memset(tb, 0, 32);
+			  sprintf(tb, "ltl_%d", nltl++);
+			  $$ = nn(ZN, NAME, ZN, ZN);
+			  $$->sym = lookup(tb);
+			}
+	| NAME		{ $$ = $1; }
+	;
+
 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);
+	  body		{
+			  if (strcmp($1->sym->name, ":trace:") == 0)
+			  {	(void) ready($1->sym, ZN, $3->sq, 0, ZN, E_TRACE);
+			  } else
+			  {	(void) ready($1->sym, ZN, $3->sq, 0, ZN, N_TRACE);
+			  }
         		  context = ZS;
 			  inEventMap--;
 			}
 	;
 
-utype	: TYPEDEF NAME		{ if (context)
-				   fatal("typedef %s must be global",
-						$2->sym->name);
+utype	: TYPEDEF NAME '{' 	{  if (context)
+				   { fatal("typedef %s must be global",
+					$2->sym->name);
+				   }
 				   owner = $2->sym;
+				   in_seq = $1->ln;
 				}
-	  '{' decl_lst '}'	{ setuname($5); owner = ZS; }
+	  decl_lst '}'		{ setuname($5);
+				  owner = ZS;
+				  in_seq = 0;
+				}
 	;
 
 nm	: NAME			{ $$ = $1; }
@@ -190,8 +276,8 @@
 				}
 	;
 
-ns	: INLINE nm '('		{ NamesNotAdded++; }
-	  args ')'		{ prep_inline($2->sym, $5);
+ns	: INLINE nm l_par		{ NamesNotAdded++; }
+	  args r_par		{ prep_inline($2->sym, $5);
 				  NamesNotAdded--;
 				}
 	;
@@ -227,6 +313,8 @@
 				  NamesNotAdded--;
 				  $$ = nn(ZN, C_CODE, ZN, ZN);
 				  $$->sym = s;
+				  $$->ln = $1->ln;
+				  $$->fn = $1->fn;
 				  has_code = 1;
 				}
 	| C_DECL		{ Symbol *s;
@@ -236,23 +324,37 @@
 				  s->type = CODE_DECL;
 				  $$ = nn(ZN, C_CODE, ZN, ZN);
 				  $$->sym = s;
+				  $$->ln = $1->ln;
+				  $$->fn = $1->fn;
 				  has_code = 1;
 				}
 	;
 cexpr	: C_EXPR		{ Symbol *s;
 				  NamesNotAdded++;
 				  s = prep_inline(ZS, ZN);
+/* if context is 0 this was inside an ltl formula
+   mark the last inline added to seqnames */
+				  if (!context)
+				  {	mark_last();
+				  }
 				  NamesNotAdded--;
 				  $$ = nn(ZN, C_EXPR, ZN, ZN);
 				  $$->sym = s;
+				  $$->ln = $1->ln;
+				  $$->fn = $1->fn;
 				  no_side_effects(s->name);
 				  has_code = 1;
 				}
 	;
 
-body	: '{'			{ open_seq(1); }
+body	: '{'			{ open_seq(1); in_seq = $1->ln; }
           sequence OS		{ add_seq(Stop); }
-          '}'			{ $$->sq = close_seq(0); }
+          '}'			{ $$->sq = close_seq(0); in_seq = 0;
+				  if (scope_level != 0)
+				  {	non_fatal("missing '}' ?", 0);
+					scope_level = 0;
+				  }
+				}
 	;
 
 sequence: step			{ if ($1) add_seq($1); }
@@ -264,7 +366,11 @@
 	| 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); }
+	| stmnt UNLESS		{ if ($1->ntyp == DO) { safe_break(); } }
+	  stmnt			{ if ($1->ntyp == DO) { restore_break(); }
+				  $$ = do_unless($1, $4);
+				}
+	| error			{ printf("Not a Step\n"); }
 	;
 
 vis	: /* empty */		{ $$ = ZN; }
@@ -277,7 +383,9 @@
 	| ASGN
 	;
 
-one_decl: vis TYPE var_list	{ setptype($3, $2->val, $1); $$ = $3; }
+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);
 				}
@@ -310,26 +418,76 @@
 	| ivar ',' var_list	{ $$ = nn($1, TYPE, ZN, $3); }
 	;
 
+c_list	: CONST			{ $1->ntyp = CONST; $$ = $1; }
+	| CONST ',' c_list	{ $1->ntyp = CONST; $$ = nn($1, ',', $1, $3); }
+	;
+
 ivar    : vardcl           	{ $$ = $1;
 				  $1->sym->ini = nn(ZN,CONST,ZN,ZN);
 				  $1->sym->ini->val = 0;
+				  if (!initialization_ok)
+				  {	Lextok *zx, *xz;
+					zx = nn(ZN, NAME, ZN, ZN);
+					zx->sym = $1->sym;
+					xz = nn(zx, ASGN, zx, $1->sym->ini);
+					keep_track_off(xz);
+					/* make sure zx doesnt turn out to be a STRUCT later */
+					add_seq(xz);
+				  }
 				}
-	| vardcl ASGN expr   	{ $1->sym->ini = $3; $$ = $1;
-				  trackvar($1,$3); has_ini = 1;
+	| vardcl ASGN '{' c_list '}'	{
+				  if (!$1->sym->isarray)
+					fatal("%s must be an array", $1->sym->name);
+				  $$ = $1;
+				  $1->sym->ini = $4;
+				  has_ini = 1;
+				  $1->sym->hidden |= (4|8);	/* conservative */
+				  if (!initialization_ok)
+				  {	Lextok *zx = nn(ZN, NAME, ZN, ZN);
+					zx->sym = $1->sym;
+					add_seq(nn(zx, ASGN, zx, $4));
+				  }
+				}
+	| vardcl ASGN expr   	{ $$ = $1;
+				  $1->sym->ini = $3;
+				  if ($3->ntyp == CONST
+				  || ($3->ntyp == NAME && $3->sym->context))
+				  {	has_ini = 2; /* local init */
+				  } else
+				  {	has_ini = 1; /* possibly global */
+				  }
+				  trackvar($1, $3);
+				  if (any_oper($3, RUN))
+				  {	fatal("cannot use 'run' in var init, saw", (char *) 0);
+				  }
+				  nochan_manip($1, $3, 0);
+				  no_internals($1);
+				  if (!initialization_ok)
+				  {	Lextok *zx = nn(ZN, NAME, ZN, ZN);
+					zx->sym = $1->sym;
+					add_seq(nn(zx, ASGN, zx, $3));
+				  }
 				}
 	| vardcl ASGN ch_init	{ $1->sym->ini = $3;
 				  $$ = $1; has_ini = 1;
+				  if (!initialization_ok)
+				  {	non_fatal(PART1 "'%s'" PART2, $1->sym->name);
+				  }
 				}
 	;
 
-ch_init : '[' CONST ']' OF
-	  '{' typ_list '}'	{ if ($2->val) u_async++;
-				  else u_sync++;
+ch_init : '[' const_expr ']' 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;
+				  $$->ln = $1->ln;
+				  $$->fn = $1->fn;
         			}
 	;
 
@@ -342,13 +500,33 @@
 				  }
 				  $1->sym->nel = 1; $$ = $1;
 				}
-	| NAME '[' CONST ']'	{ $1->sym->nel = $3->val; $$ = $1; }
+	| NAME '[' const_expr ']'	{ $1->sym->nel = $3->val; $1->sym->isarray = 1; $$ = $1; }
+	| NAME '[' NAME ']'	{	/* make an exception for an initialized scalars */
+					$$ = nn(ZN, CONST, ZN, ZN);
+					fprintf(stderr, "spin: %s:%d, warning: '%s' in array bound ",
+						$1->fn->name, $1->ln, $3->sym->name);
+					if ($3->sym->ini->val > 0)
+					{	fprintf(stderr, "evaluated as %d\n", $3->sym->ini->val);
+						$$->val = $3->sym->ini->val;
+					} else
+					{	fprintf(stderr, "evaluated as 8 by default (to avoid zero)\n");
+						$$->val = 8;
+					}
+					$1->sym->nel = $$->val;
+					$1->sym->isarray = 1;
+					$$ = $1;
+				}
 	;
 
 varref	: cmpnd			{ $$ = mk_explicit($1, Expand_Ok, NAME); }
 	;
 
-pfld	: NAME			{ $$ = nn($1, NAME, ZN, ZN); }
+pfld	: NAME			{ $$ = nn($1, NAME, ZN, ZN);
+				  if ($1->sym->isarray && !in_for)
+				  {	non_fatal("missing array index for '%s'",
+						$1->sym->name);
+				  }
+				}
 	| NAME			{ owner = ZS; }
 	  '[' expr ']'		{ $$ = nn($1, NAME, $4, ZN); }
 	;
@@ -363,7 +541,7 @@
 				  Embedded--;
 				  if (!Embedded && !NamesNotAdded
 				  &&  !$1->sym->type)
-				   non_fatal("undeclared variable: %s",
+				   fatal("undeclared variable: %s",
 						$1->sym->name);
 				  if ($3) validref($1, $3->lft);
 				  owner = ZS;
@@ -374,13 +552,21 @@
 	| '.' cmpnd %prec DOT	{ $$ = nn(ZN, '.', $2, ZN); }
 	;
 
-stmnt	: Special		{ $$ = $1; }
-	| Stmnt			{ $$ = $1;
-				  if (inEventMap)
-				   non_fatal("not an event", (char *)0);
+stmnt	: Special		{ $$ = $1; initialization_ok = 0; }
+	| Stmnt			{ $$ = $1; initialization_ok = 0;
+				  if (inEventMap) non_fatal("not an event", (char *)0);
 				}
 	;
 
+for_pre : FOR l_par		{ in_for = 1; }
+	  varref		{ trapwonly($4 /*, "for" */);
+				  pushbreak(); /* moved up */
+				  $$ = $4;
+				}
+	;
+
+for_post: '{' sequence OS '}' ;
+
 Special : varref RCV		{ Expand_Ok++; }
 	  rargs			{ Expand_Ok--; has_io++;
 				  $$ = nn($1,  'r', $1, $4);
@@ -392,13 +578,30 @@
 				  $$->val=0; trackchanuse($4, ZN, 'S');
 				  any_runs($4);
 				}
+	| for_pre ':' expr DOTDOT expr r_par	{
+				  for_setup($1, $3, $5); in_for = 0;
+				}
+	  for_post		{ $$ = for_body($1, 1);
+				}
+	| for_pre IN varref r_par	{ $$ = for_index($1, $3); in_for = 0;
+				}
+	  for_post		{ $$ = for_body($5, 1);
+				}
+	| SELECT l_par varref ':' expr DOTDOT expr r_par {
+				  trapwonly($3 /*, "select" */);
+				  $$ = sel_index($3, $5, $7);
+				}
 	| IF options FI 	{ $$ = nn($1, IF, ZN, ZN);
         			  $$->sl = $2->sl;
+				  $$->ln = $1->ln;
+				  $$->fn = $1->fn;
 				  prune_opts($$);
         			}
 	| DO    		{ pushbreak(); }
           options OD    	{ $$ = nn($1, DO, ZN, ZN);
         			  $$->sl = $3->sl;
+				  $$->ln = $1->ln;
+				  $$->fn = $1->fn;
 				  prune_opts($$);
         			}
 	| BREAK  		{ $$ = nn(ZN, GOTO, ZN, ZN);
@@ -420,9 +623,22 @@
 				  }
 				  $1->sym->type = LABEL;
 				}
+	| NAME ':'		{ $$ = nn($1, ':',ZN,ZN);
+				  if ($1->sym->type != 0
+				  &&  $1->sym->type != LABEL) {
+				  	non_fatal("bad label-name %s",
+					$1->sym->name);
+				  }
+				  $$->lft = nn(ZN, 'c', nn(ZN,CONST,ZN,ZN), ZN);
+				  $$->lft->lft->val = 1; /* skip */
+				  $1->sym->type = LABEL;
+				}
+	| error			{ $$ = nn(ZN, 'c', nn(ZN,CONST,ZN,ZN), ZN);
+				  $$->lft->val = 1; /* skip */
+				}
 	;
 
-Stmnt	: varref ASGN expr	{ $$ = nn($1, ASGN, $1, $3);
+Stmnt	: varref ASGN full_expr	{ $$ = nn($1, ASGN, $1, $3);
 				  trackvar($1, $3);
 				  nochan_manip($1, $3, 0);
 				  no_internals($1);
@@ -443,10 +659,11 @@
 				  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); }
+	| SET_P l_par two_args r_par	{ $$ = nn(ZN, SET_P, $3, ZN); has_priority++; }
+	| PRINT	l_par STRING	{ realread = 0; }
+	  prargs r_par		{ $$ = nn($3, PRINT, $5, ZN); realread = 1; }
+	| PRINTM l_par varref r_par	{ $$ = nn(ZN, PRINTM, $3, ZN); }
+	| PRINTM l_par CONST r_par	{ $$ = nn(ZN, PRINTM, $3, ZN); }
 	| ASSERT full_expr    	{ $$ = nn(ZN, ASSERT, $2, ZN); AST_track($2, 0); }
 	| ccode			{ $$ = $1; }
 	| varref R_RCV		{ Expand_Ok++; }
@@ -480,21 +697,40 @@
 	| ATOMIC   '{'   	{ open_seq(0); }
           sequence OS '}'   	{ $$ = nn($1, ATOMIC, ZN, ZN);
         			  $$->sl = seqlist(close_seq(3), 0);
-        			  make_atomic($$->sl->this, 0);
+				  $$->ln = $1->ln;
+				  $$->fn = $1->fn;
+				  make_atomic($$->sl->this, 0);
         			}
-	| D_STEP '{'		{ open_seq(0); rem_Seq(); }
+	| D_STEP '{'		{ open_seq(0);
+				  rem_Seq();
+				}
           sequence OS '}'   	{ $$ = nn($1, D_STEP, ZN, ZN);
         			  $$->sl = seqlist(close_seq(4), 0);
+				  $$->ln = $1->ln;
+				  $$->fn = $1->fn;
         			  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);
+				  $$->ln = $1->ln;
+				  $$->fn = $1->fn;
         			}
 	| INAME			{ IArgs++; }
-	  '(' args ')'		{ pickup_inline($1->sym, $4); IArgs--; }
+	  l_par args r_par	{ initialization_ok = 0;
+				  pickup_inline($1->sym, $4, ZN);
+				  IArgs--;
+				}
 	  Stmnt			{ $$ = $7; }
+
+	| varref ASGN INAME	{ IArgs++; }
+	  l_par args r_par	{ initialization_ok = 0;
+				  pickup_inline($3->sym, $6, $1);
+				  IArgs--;
+				}
+	  Stmnt			{ $$ = $9; }
+	| RETURN full_expr	{ $$ = return_statement($2); }	
 	;
 
 options : option		{ $$->sl = seqlist($1->sq, 0); }
@@ -503,22 +739,39 @@
 
 option  : SEP   		{ open_seq(0); }
           sequence OS		{ $$ = nn(ZN,0,ZN,ZN);
-				  $$->sq = close_seq(6); }
+				  $$->sq = close_seq(6);
+				  $$->ln = $1->ln;
+				  $$->fn = $1->fn;
+				}
 	;
 
 OS	: /* empty */
-	| SEMI			{ /* redundant semi at end of sequence */ }
+	| semi			{ /* redundant semi at end of sequence */ }
 	;
 
-MS	: SEMI			{ /* at least one semi-colon */ }
-	| MS SEMI		{ /* but more are okay too   */ }
+semi	: SEMI
+	| ARROW
+	;
+
+MS	: semi			{ /* at least one semi-colon */ }
+	| MS semi		{ /* but more are okay too   */ }
 	;
 
 aname	: NAME			{ $$ = $1; }
 	| PNAME			{ $$ = $1; }
 	;
 
-expr    : '(' expr ')'		{ $$ = $2; }
+const_expr:	CONST			{ $$ = $1; }
+	| '-' const_expr %prec UMIN	{ $$ = $2; $$->val = -($2->val); }
+	| l_par const_expr r_par		{ $$ = $2; }
+	| const_expr '+' const_expr	{ $$ = $1; $$->val = $1->val + $3->val; }
+	| const_expr '-' const_expr	{ $$ = $1; $$->val = $1->val - $3->val; }
+	| const_expr '*' const_expr	{ $$ = $1; $$->val = $1->val * $3->val; }
+	| const_expr '/' const_expr	{ $$ = $1; $$->val = $1->val / $3->val; }
+	| const_expr '%' const_expr	{ $$ = $1; $$->val = $1->val % $3->val; }
+	;
+
+expr    : l_par expr r_par		{ $$ = $2; }
 	| expr '+' expr		{ $$ = nn(ZN, '+', $1, $3); }
 	| expr '-' expr		{ $$ = nn(ZN, '-', $1, $3); }
 	| expr '*' expr		{ $$ = nn(ZN, '*', $1, $3); }
@@ -541,28 +794,25 @@
 	| '-' expr %prec UMIN	{ $$ = nn(ZN, UMIN, $2, ZN); }
 	| SND expr %prec NEG	{ $$ = nn(ZN, '!', $2, ZN); }
 
-	| '(' expr SEMI expr ':' expr ')' {
+	| l_par expr ARROW expr ':' expr r_par {
 				  $$ = nn(ZN,  OR, $4, $6);
 				  $$ = nn(ZN, '?', $2, $$);
 				}
 
 	| RUN aname		{ Expand_Ok++;
 				  if (!context)
-				  fatal("used 'run' outside proctype",
+				   fatal("used 'run' outside proctype",
 					(char *) 0);
-				  if (strcmp(context->name, ":init:") != 0)
-					runsafe = 0;
 				}
-	  '(' args ')'
+	  l_par args r_par
 	  Opt_priority		{ Expand_Ok--;
 				  $$ = nn($2, RUN, $5, ZN);
-				  $$->val = ($7) ? $7->val : 1;
+				  $$->val = ($7) ? $7->val : 0;
 				  trackchanuse($5, $2, 'A'); trackrun($$);
 				}
-	| LEN '(' varref ')'	{ $$ = nn($3, LEN, $3, ZN); }
-	| ENABLED '(' expr ')'	{ $$ = nn(ZN, ENABLED, $3, ZN);
-				  has_enabled++;
-				}
+	| LEN l_par varref r_par	{ $$ = nn($3, LEN, $3, ZN); }
+	| ENABLED l_par expr r_par	{ $$ = nn(ZN, ENABLED, $3, ZN); has_enabled++; }
+	| GET_P l_par expr r_par	{ $$ = nn(ZN, GET_P, $3, ZN); has_priority++; }
 	| varref RCV		{ Expand_Ok++; }
 	  '[' rargs ']'		{ Expand_Ok--; has_io++;
 				  $$ = nn($1, 'R', $1, $5);
@@ -572,7 +822,7 @@
 				  $$ = nn($1, 'R', $1, $5);
 				  $$->val = has_random = 1;
 				}
-	| varref		{ $$ = $1; trapwonly($1, "varref"); }
+	| varref		{ $$ = $1; trapwonly($1 /*, "varref" */); }
 	| cexpr			{ $$ = $1; }
 	| CONST 		{ $$ = nn(ZN,CONST,ZN,ZN);
 				  $$->ismtyp = $1->ismtyp;
@@ -582,7 +832,7 @@
 	| NONPROGRESS		{ $$ = nn(ZN,NONPROGRESS, ZN, ZN);
 				  has_np++;
 				}
-	| PC_VAL '(' expr ')'	{ $$ = nn(ZN, PC_VAL, $3, ZN);
+	| PC_VAL l_par expr r_par	{ $$ = nn(ZN, PC_VAL, $3, ZN);
 				  has_pcvalue++;
 				}
 	| PNAME '[' expr ']' '@' NAME
@@ -591,18 +841,51 @@
 	  			{ $$ = 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); }
+	| ltl_expr		{ $$ = $1; /* sanity_check($1); */ }
 	;
 
 Opt_priority:	/* none */	{ $$ = ZN; }
-	| PRIORITY CONST	{ $$ = $2; }
+	| PRIORITY CONST	{ $$ = $2; has_priority++; }
 	;
 
 full_expr:	expr		{ $$ = $1; }
-	|	Expr		{ $$ = $1; }
+	| Expr		{ $$ = $1; }
+	;
+
+ltl_expr: expr UNTIL expr	{ $$ = nn(ZN, UNTIL,   $1, $3); }
+	| expr RELEASE expr	{ $$ = nn(ZN, RELEASE, $1, $3); }
+	| expr WEAK_UNTIL expr	{ $$ = nn(ZN, ALWAYS, $1, ZN);
+				  $$ = nn(ZN, OR, $$, nn(ZN, UNTIL, $1, $3));
+				}
+	| expr IMPLIES expr	{
+				$$ = nn(ZN, '!', $1, ZN);
+				$$ = nn(ZN, OR,  $$, $3);
+				}
+	| expr EQUIV expr	{ $$ = nn(ZN, EQUIV,   $1, $3); }
+	| NEXT expr       %prec NEG { $$ = nn(ZN, NEXT,  $2, ZN); }
+	| ALWAYS expr     %prec NEG { $$ = nn(ZN, ALWAYS,$2, ZN); }
+	| EVENTUALLY expr %prec NEG { $$ = nn(ZN, EVENTUALLY, $2, ZN); }
+	;
+
+	/* an Expr cannot be negated - to protect Probe expressions */
+Expr	: Probe			{ $$ = $1; }
+	| l_par Expr r_par		{ $$ = $2; }
+	| Expr AND Expr		{ $$ = nn(ZN, AND, $1, $3); }
+	| 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 OR  Expr		{ $$ = nn(ZN,  OR, $1, $3); }
+	;
+
+Probe	: FULL l_par varref r_par	{ $$ = nn($3,  FULL, $3, ZN); }
+	| NFULL l_par varref r_par	{ $$ = nn($3, NFULL, $3, ZN); }
+	| EMPTY l_par varref r_par	{ $$ = nn($3, EMPTY, $3, ZN); }
+	| NEMPTY l_par varref r_par	{ $$ = nn($3,NEMPTY, $3, ZN); }
 	;
 
 Opt_enabler:	/* none */	{ $$ = ZN; }
-	| PROVIDED '(' full_expr ')'	{ if (!proper_enabler($3))
+	| PROVIDED l_par full_expr r_par	{ if (!proper_enabler($3))
 				  {	non_fatal("invalid PROVIDED clause",
 						(char *)0);
 					$$ = ZN;
@@ -615,23 +898,6 @@
 				}
 	;
 
-	/* 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)
@@ -647,6 +913,9 @@
 	| basetype ',' typ_list	{ $$ = nn($1, $1->val, ZN, $3); }
 	;
 
+two_args:	expr ',' expr	{ $$ = nn(ZN, ',', $1, $3); }
+	;
+
 args    : /* empty */		{ $$ = ZN; }
 	| arg			{ $$ = $1; }
 	;
@@ -656,7 +925,7 @@
 	;
 
 margs   : arg			{ $$ = $1; }
-	| expr '(' arg ')'	{ if ($1->ntyp == ',')
+	| expr l_par arg r_par	{ if ($1->ntyp == ',')
 					$$ = tail_add($1, $3);
 				  else
 				  	$$ = nn(ZN, ',', $1, $3);
@@ -676,9 +945,9 @@
 	;
 
 rarg	: varref		{ $$ = $1; trackvar($1, $1);
-				  trapwonly($1, "rarg"); }
-	| EVAL '(' expr ')'	{ $$ = nn(ZN,EVAL,$3,ZN);
-				  trapwonly($1, "eval rarg"); }
+				  trapwonly($1 /*, "rarg" */); }
+	| EVAL l_par expr r_par	{ $$ = nn(ZN,EVAL,$3,ZN);
+				  trapwonly($1 /*, "eval rarg" */); }
 	| CONST 		{ $$ = nn(ZN,CONST,ZN,ZN);
 				  $$->ismtyp = $1->ismtyp;
 				  $$->val = $1->val;
@@ -698,12 +967,12 @@
 				  else
 				  	$$ = nn(ZN, ',', $1, $3);
 				}
-	| rarg '(' rargs ')'	{ if ($1->ntyp == ',')
+	| rarg l_par rargs r_par	{ if ($1->ntyp == ',')
 					$$ = tail_add($1, $3);
 				  else
 				  	$$ = nn(ZN, ',', $1, $3);
 				}
-	| '(' rargs ')'		{ $$ = $2; }
+	| l_par rargs r_par		{ $$ = $2; }
 	;
 
 nlst	: NAME			{ $$ = nn($1, NAME, ZN, ZN);
@@ -715,6 +984,138 @@
 	;
 %%
 
+#define binop(n, sop)	fprintf(fd, "("); recursive(fd, n->lft); \
+			fprintf(fd, ") %s (", sop); recursive(fd, n->rgt); \
+			fprintf(fd, ")");
+#define unop(n, sop)	fprintf(fd, "%s (", sop); recursive(fd, n->lft); \
+			fprintf(fd, ")");
+
+static void
+recursive(FILE *fd, Lextok *n)
+{
+	if (n)
+	switch (n->ntyp) {
+	case NEXT:
+		unop(n, "X");
+		break;
+	case ALWAYS:
+		unop(n, "[]");
+		break;
+	case EVENTUALLY:
+		unop(n, "<>");
+		break;
+	case '!':
+		unop(n, "!");
+		break;
+	case UNTIL:
+		binop(n, "U");
+		break;
+	case WEAK_UNTIL:
+		binop(n, "W");
+		break;
+	case RELEASE: /* see http://en.wikipedia.org/wiki/Linear_temporal_logic */
+		binop(n, "V");
+		break;
+	case OR:
+		binop(n, "||");
+		break;
+	case AND:
+		binop(n, "&&");
+		break;
+	case IMPLIES:
+		binop(n, "->");
+		break;
+	case EQUIV:
+		binop(n, "<->");
+		break;
+	case C_EXPR:
+		fprintf(fd, "c_expr { %s }", put_inline(fd, n->sym->name));
+		break;
+	default:
+		comment(fd, n, 0);
+		break;
+	}
+}
+
+static Lextok *
+ltl_to_string(Lextok *n)
+{	Lextok *m = nn(ZN, 0, ZN, ZN);
+	char *retval;
+	char ltl_formula[2048];
+	FILE *tf = fopen(TMP_FILE1, "w+"); /* tmpfile() fails on Windows 7 */
+
+	/* convert the parsed ltl to a string
+	   by writing into a file, using existing functions,
+	   and then passing it to the existing interface for
+	   conversion into a never claim
+	  (this means parsing everything twice, which is
+	   a little redundant, but adds only miniscule overhead)
+	 */
+
+	if (!tf)
+	{	fatal("cannot create temporary file", (char *) 0);
+	}
+	dont_simplify = 1;
+	recursive(tf, n);
+	dont_simplify = 0;
+	(void) fseek(tf, 0L, SEEK_SET);
+
+	memset(ltl_formula, 0, sizeof(ltl_formula));
+	retval = fgets(ltl_formula, sizeof(ltl_formula), tf);
+	fclose(tf);
+
+	(void) unlink(TMP_FILE1);
+
+	if (!retval)
+	{	printf("%p\n", retval);
+		fatal("could not translate ltl ltl_formula", 0);
+	}
+
+	if (1) printf("ltl %s: %s\n", ltl_name, ltl_formula);
+
+	m->sym = lookup(ltl_formula);
+
+	return m;
+}
+
+int
+is_temporal(int t)
+{
+	return (t == EVENTUALLY || t == ALWAYS || t == UNTIL
+	     || t == WEAK_UNTIL || t == RELEASE);
+}
+
+int
+is_boolean(int t)
+{
+	return (t == AND || t == OR || t == IMPLIES || t == EQUIV);
+}
+
+#if 0
+/* flags correct formula like: ltl { true U (true U true) } */
+void
+sanity_check(Lextok *t)	/* check proper embedding of ltl_expr */
+{
+	if (!t) return;
+	sanity_check(t->lft);
+	sanity_check(t->rgt);
+
+	if (t->lft && t->rgt)
+	{	if (!is_boolean(t->ntyp)
+		&&  (is_temporal(t->lft->ntyp)
+		||   is_temporal(t->rgt->ntyp)))
+		{	printf("spin: attempt to apply '");
+			explain(t->ntyp);
+			printf("' to '");
+			explain(t->lft->ntyp);
+			printf("' and '");
+			explain(t->rgt->ntyp);
+			printf("'\n");
+	/*		non_fatal("missing parentheses?", (char *)0); */
+	}	}
+}
+#endif
+
 void
 yyerror(char *fmt, ...)
 {
diff -r 51b3bf8bc61b sys/src/cmd/spin/spinlex.c
--- a/sys/src/cmd/spin/spinlex.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/spinlex.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,15 +1,15 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <ctype.h>
 #include "spin.h"
 #include "y.tab.h"
 
@@ -21,8 +21,11 @@
 	Symbol *nm;		/* name of the type */
 	Lextok *cn;		/* contents */
 	Lextok *params;		/* formal pars if any */
+	Lextok *rval;		/* variable to assign return value, if any */
 	char   **anms;		/* literal text for actual pars */
 	char   *prec;		/* precondition for c_code or c_expr */
+	int    uiid;		/* unique inline id */
+	int    is_expr;		/* c_expr in an ltl formula */
 	int    dln, cln;	/* def and call linenr */
 	Symbol *dfn, *cfn;	/* def and call filename */
 	struct IType *nxt;	/* linked list */
@@ -32,19 +35,24 @@
 	Symbol *s;
 	Symbol *t;
 	Symbol *ival;
+	Symbol *fnm;
+	int	lno;
 	struct C_Added *nxt;
 } C_Added;
 
 extern RunList	*X;
 extern ProcList	*rdy;
-extern Symbol	*Fname;
+extern Symbol	*Fname, *oFname;
 extern Symbol	*context, *owner;
 extern YYSTYPE	yylval;
-extern short	has_last, has_code;
-extern int	verbose, IArgs, hastrack, separate;
+extern short	has_last, has_code, has_priority;
+extern int	verbose, IArgs, hastrack, separate, in_for;
+extern int	implied_semis, ltl_mode, in_seq, par_cnt;
 
 short	has_stack = 0;
 int	lineno  = 1;
+int	scope_seq[128], scope_level = 0;
+char	CurScope[MAXSCOPESZ];
 char	yytext[2048];
 FILE	*yyin, *yyout;
 
@@ -55,45 +63,62 @@
 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; }
+static int	last_token = 0;
 
 #define ValToken(x, y)	{ if (in_comment) goto again; \
-			yylval = nn(ZN,0,ZN,ZN); yylval->val = x; return y; }
+			yylval = nn(ZN,0,ZN,ZN); \
+			yylval->val = x; \
+			last_token = y; \
+			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; }
+			yylval = nn(ZN,0,ZN,ZN); \
+			yylval->sym = x; \
+			last_token = y; \
+			return y; \
+			}
 
-#define ValToken(x, y)	{ yylval = nn(ZN,0,ZN,ZN); yylval->val = x; \
-			if (!in_comment) return y; else goto again; }
+static int  getinline(void);
+static void uninline(void);
 
-#define SymToken(x, y)	{ yylval = nn(ZN,0,ZN,ZN); yylval->sym = x; \
-			if (!in_comment) return y; else goto again; }
-#endif
+static int PushBack;
+static int PushedBack;
+static char pushedback[4096];
 
-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 void
+push_back(char *s)
+{
+	if (PushedBack + strlen(s) > 4094)
+	{	fatal("select statement too large", 0);
+	}
+	strcat(pushedback, s);
+	PushedBack += strlen(s);
+}
 
 static int
 Getchar(void)
 {	int c;
+
+	if (PushedBack > 0 && PushBack < PushedBack)
+	{	c = pushedback[PushBack++];
+		if (PushBack == PushedBack)
+		{	pushedback[0] = '\0';
+			PushBack = PushedBack = 0;
+		}
+		return c;	/* expanded select statement */
+	}
 	if (Inlining<0)
-		c = getc(yyin);
-	else
-		c = getinline();
-#if 1
-	printf("<%c>", c);
+	{	c = getc(yyin);
+	} else
+	{	c = getinline();
+	}
+#if 0
+	if (0)
+	{	printf("<%c:%d>[%d] ", c, c, Inlining);
+	} else
+	{	printf("%c", c);
+	}
 #endif
 	return c;
 }
@@ -101,15 +126,25 @@
 static void
 Ungetch(int c)
 {
+	if (PushedBack > 0 && PushBack > 0)
+	{	PushBack--;
+		return;
+	}
+
 	if (Inlining<0)
-		ungetc(c,yyin);
-	else
-		uninline();
-#if 1
-	printf("<bs>");
-#endif
+	{	ungetc(c,yyin);
+	} else
+	{	uninline();
+	}
+	if (0)
+	{	printf("\n<bs{%d}bs>\n", c);
+	}
 }
-#endif
+
+static int
+notdollar(int c)
+{	return (c != '$' && c != '\n');
+}
 
 static int
 notquote(int c)
@@ -133,15 +168,17 @@
 
 static void
 getword(int first, int (*tst)(int))
-{	int i=0; char c;
+{	int i=0, c;
 
 	yytext[i++]= (char) first;
 	while (tst(c = Getchar()))
-	{	yytext[i++] = c;
+	{	yytext[i++] = (char) c;
 		if (c == '\\')
-			yytext[i++] = Getchar();	/* no tst */
-	}
+		{	c = Getchar();
+			yytext[i++] = (char) c;	/* no tst */
+	}	}
 	yytext[i] = '\0';
+
 	Ungetch(c);
 }
 
@@ -150,7 +187,8 @@
 {	int c;
 
 	if ((c = Getchar()) == tok)
-		return ifyes;
+	{	return ifyes;
+	}
 	Ungetch(c);
 
 	return ifno;
@@ -161,10 +199,11 @@
 static void
 def_inline(Symbol *s, int ln, char *ptr, char *prc, Lextok *nms)
 {	IType *tmp;
-	char *nw = (char *) emalloc((int) strlen(ptr)+1);
+	int  cnt = 0;
+	char *nw = (char *) emalloc(strlen(ptr)+1);
 	strcpy(nw, ptr);
 
-	for (tmp = seqnames; tmp; tmp = tmp->nxt)
+	for (tmp = seqnames; tmp; cnt++, tmp = tmp->nxt)
 		if (!strcmp(s->name, tmp->nm->name))
 		{	non_fatal("procedure name %s redefined",
 				tmp->nm->name);
@@ -179,11 +218,12 @@
 	tmp->cn = (Lextok *) nw;
 	tmp->params = nms;
 	if (strlen(prc) > 0)
-	{	tmp->prec = (char *) emalloc((int) strlen(prc)+1);
+	{	tmp->prec = (char *) emalloc(strlen(prc)+1);
 		strcpy(tmp->prec, prc);
 	}
 	tmp->dln = ln;
 	tmp->dfn = Fname;
+	tmp->uiid = cnt+1;	/* so that 0 means: not an inline */
 	tmp->nxt = seqnames;
 	seqnames = tmp;
 }
@@ -250,6 +290,20 @@
 	return 0;
 }
 
+Lextok *
+return_statement(Lextok *n)
+{
+	if (Inline_stub[Inlining]->rval)
+	{	Lextok *g = nn(ZN, NAME, ZN, ZN);
+		Lextok *h = Inline_stub[Inlining]->rval;
+		g->sym = lookup("rv_");
+		return nn(h, ASGN, h, n);
+	} else
+	{	fatal("return statement outside inline", (char *) 0);
+	}
+	return ZN;
+}
+
 static int
 getinline(void)
 {	int c;
@@ -261,16 +315,20 @@
 			c = *Inliner[Inlining]++;
 		}
 	} else
+	{
 		c = *Inliner[Inlining]++;
+	}
 
 	if (c == '\0')
-	{	lineno = Inline_stub[Inlining]->cln;
+	{
+		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);
+		printf("spin: %s:%d, done inlining %s\n",
+			Fname, lineno, Inline_stub[Inlining+1]->nm->name);
 #endif
 		return Getchar();
 	}
@@ -286,6 +344,16 @@
 		Inliner[Inlining]--;
 }
 
+int
+is_inline(void)
+{
+	if (Inlining < 0)
+		return 0;	/* i.e., not an inline */
+	if (Inline_stub[Inlining] == NULL)
+		fatal("unexpected, inline_stub not set", 0);
+	return Inline_stub[Inlining]->uiid;
+}
+
 IType *
 find_inline(char *s)
 {	IType *tmp;
@@ -295,6 +363,7 @@
 			break;
 	if (!tmp)
 		fatal("cannot happen, missing inline def %s", s);
+
 	return tmp;
 }
 
@@ -306,7 +375,17 @@
 	r->s = s;	/* pointer to a data object */
 	r->t = t;	/* size of object, or "global", or "local proctype_name"  */
 	r->ival = ival;
+	r->lno = lineno;
+	r->fnm = Fname;
 	r->nxt = c_added;
+
+	if(strncmp(r->s->name, "\"unsigned unsigned", 18) == 0)
+	{	int i;
+		for (i = 10; i < 18; i++)
+		{	r->s->name[i] = ' ';
+		}
+	/*	printf("corrected <%s>\n", r->s->name);	*/
+	}
 	c_added = r;
 }
 
@@ -319,6 +398,8 @@
 	r->t = t;
 	r->ival = stackonly;	/* abuse of name */
 	r->nxt = c_tracked;
+	r->fnm = Fname;
+	r->lno = lineno;
 	c_tracked = r;
 
 	if (stackonly != ZS)
@@ -329,36 +410,76 @@
 		     &&  strcmp(stackonly->name, "\"StackOnly\"") != 0)
 			non_fatal("expecting '[Un]Matched', saw %s", stackonly->name);
 		else
-			has_stack = 1;
+			has_stack = 1;	/* unmatched stack */
 	}
 }
 
 char *
-jump_etc(char *op)
-{	char *p = op;
+skip_white(char *p)
+{
+	if (p != NULL)
+	{	while (*p == ' ' || *p == '\t')
+			p++;
+	} else
+	{	fatal("bad format - 1", (char *) 0);
+	}
+	return p;
+}
 
-	/* kludgy - try to get the type separated from the name */
+char *
+skip_nonwhite(char *p)
+{
+	if (p != NULL)
+	{	while (*p != ' ' && *p != '\t')
+			p++;
+	} else
+	{	fatal("bad format - 2", (char *) 0);
+	}
+	return p;
+}
 
-	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 */
+static char *
+jump_etc(C_Added *r)
+{	char *op = r->s->name;
+	char *p = op;
+	char *q = (char *) 0;
+	int oln = lineno;
+	Symbol *ofnm = Fname;
+
+	/* try to get the type separated from the name */
+	lineno = r->lno;
+	Fname  = r->fnm;
+
+	p = skip_white(p);	/* initial white space */
+
+	if (strncmp(p, "enum", strlen("enum")) == 0) /* special case: a two-part typename */
+	{	p += strlen("enum")+1;
+		p = skip_white(p);
+	}
+	if (strncmp(p, "unsigned", strlen("unsigned")) == 0) /* possibly a two-part typename */
+	{	p += strlen("unsigned")+1;
+		q = p = skip_white(p);
+	}
+	p = skip_nonwhite(p);	/* type name */
+	p = skip_white(p);	/* white space */
+	while (*p == '*') p++;	/* decorations */
+	p = skip_white(p);	/* white space */
 
 	if (*p == '\0')
-		fatal("c_state format (%s)", op);
+	{	if (q)
+		{	p = q;	/* unsigned with implied 'int' */
+		} else
+		{	fatal("c_state format (%s)", op);
+	}	}
 
-	if (strchr(p, '[')
-	&&  !strchr(p, '{'))
+	if (strchr(p, '[') && !strchr(p, '{'))
 	{	non_fatal("array initialization error, c_state (%s)", p);
-		return (char *) 0;
+		p = (char *) 0;
 	}
 
+	lineno = oln;
+	Fname = ofnm;
+
 	return p;
 }
 
@@ -379,7 +500,7 @@
 				if (*q == '\\')
 					*q++ = ' '; /* skip over the next */
 			}
-			p = jump_etc(r->s->name);	/* e.g., "int **q" */
+			p = jump_etc(r);	/* e.g., "int **q" */
 			if (p)
 			fprintf(fd, "	now.%s = %s;\n", p, r->ival->name);
 
@@ -391,7 +512,7 @@
 				if (*q == '\\')
 					*q++ = ' '; /* skip over the next */
 			}
-			p = jump_etc(r->s->name);	/* e.g., "int **q" */
+			p = jump_etc(r);	/* e.g., "int **q" */
 			if (p)
 			fprintf(fd, "	%s = %s;\n", p, r->ival->name);	/* no now. prefix */
 
@@ -413,7 +534,7 @@
 				if (*q == '\"')
 					*q = ' ';
 			
-			p = jump_etc(r->s->name);	/* e.g., "int **q" */
+			p = jump_etc(r);	/* e.g., "int **q" */
 
 			q = r->t->name + strlen(" Local");
 			while (*q == ' ' || *q == '\t')
@@ -435,9 +556,9 @@
 			}
 
 			if (p)
-			fprintf(fd, "		((P%d *)this)->%s = %s;\n",
-				tpnr, p, r->ival->name);
-
+			{	fprintf(fd, "\t\t((P%d *)this)->%s = %s;\n",
+					tpnr, p, r->ival->name);
+			}
 		}
 	fprintf(fd, "}\n");
 }
@@ -514,32 +635,38 @@
 }
 
 void
+c_stack_size(FILE *fd)
+{	C_Added *r;
+	int cnt = 0;
+
+	for (r = c_tracked; r; r = r->nxt)
+		if (r->ival != ZS)
+		{	fprintf(fd, "%s%s",
+				(cnt==0)?"":"+", r->t->name);
+			cnt++;
+		}
+	if (cnt == 0)
+	{	fprintf(fd, "WS");
+	}
+}
+
+void
 c_add_stack(FILE *fd)
 {	C_Added *r;
 	int cnt = 0;
 
-	if ((!c_added && !c_tracked) || !has_stack) return;
-
+	if ((!c_added && !c_tracked) || !has_stack)
+	{	return;
+	}
 
 	for (r = c_tracked; r; r = r->nxt)
 		if (r->ival != ZS)
-			cnt++;
+		{	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, "	uchar c_stack[StackSize];\n");
 	}
-
-	if (cnt == 0) fprintf(fd, "WS"); /* can't happen */
-	fprintf(fd, "];\n");
 }
 
 void
@@ -568,6 +695,7 @@
 	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");
+fprintf(fd, "/* XXX p=<%s>, s=<%s>, buf=<%s> r->s->name=<%s>XXX */\n", p, s, buf, r->s->name);
 			while (*p == ' ' || *p == '\t')
 				p++;
 			if (strcmp(p, buf) == 0)
@@ -578,7 +706,7 @@
 c_add_def(FILE *fd)	/* 3 - called in plunk_c_fcts() */
 {	C_Added *r;
 
-	fprintf(fd, "#if defined(C_States) && defined(HAS_TRACK)\n");
+	fprintf(fd, "#if defined(C_States) && (HAS_TRACK==1)\n");
 	for (r = c_added; r; r = r->nxt)
 	{	r->s->name[strlen(r->s->name)-1] = ' ';
 		r->s->name[0] = ' '; /* remove the "s */
@@ -610,9 +738,10 @@
 	}
 
 	if (has_stack)
-	{	fprintf(fd, "void\nc_stack(uchar *p_t_r)\n{\n");
+	{	fprintf(fd, "int cpu_printf(const char *, ...);\n");
+		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, "	cpu_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;
@@ -630,7 +759,7 @@
 
 	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, "	printf(\"c_update %%p\\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
@@ -660,7 +789,7 @@
 	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, "	cpu_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;
@@ -675,7 +804,7 @@
 
 	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, "	printf(\"c_revert %%p\\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
@@ -708,11 +837,13 @@
 	plunk_reverse(fd, p->nxt, matchthis);
 
 	if (!p->nm->context
-	&&   p->nm->type == matchthis)
+	&&   p->nm->type == matchthis
+	&&   p->is_expr == 0)
 	{	fprintf(fd, "\n/* start of %s */\n", p->nm->name);
 		z = (char *) p->cn;
 		while (*z == '\n' || *z == '\r' || *z == '\\')
-			z++;
+		{	z++;
+		}
 		/* e.g.: \#include "..." */
 
 		y = z;
@@ -772,14 +903,28 @@
 	}	}
 }
 
+extern short terse;
+extern short nocast;
+
 void
 plunk_expr(FILE *fd, char *s)
 {	IType *tmp;
+	char *q;
 
 	tmp = find_inline(s);
 	check_inline(tmp);
 
-	fprintf(fd, "%s", (char *) tmp->cn);
+	if (terse && nocast)
+	{	for (q = (char *) tmp->cn; q && *q != '\0'; q++)
+		{	fflush(fd);
+			if (*q == '"')
+			{	fprintf(fd, "\\");
+			}
+			fprintf(fd, "%c", *q);
+		}
+	} else
+	{	fprintf(fd, "%s", (char *) tmp->cn);
+	}
 }
 
 void
@@ -791,9 +936,11 @@
 	{	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, "trpt++; trpt->pr = II; trpt->o_t = t; trpt->st = tt; ");
+			fprintf(fd, "uerror(\"c_expr line %d precondition false: %s\"); continue;",
+				tmp->dln, tmp->prec);
+			fprintf(fd, " } else { printf(\"pan: precondition false: %s\\n\"); ",
+				tmp->prec);
 			fprintf(fd, "_m = 3; goto P999; } } \n\t\t");
 		}
 	} else
@@ -813,8 +960,25 @@
 	||      strchr(bdy, '(') > bdy);	/* possible C-function call */
 }
 
+char *
+put_inline(FILE *fd, char *s)
+{	IType *tmp;
+
+	tmp = find_inline(s);
+	check_inline(tmp);
+	return (char *) tmp->cn;
+}
+
 void
-plunk_inline(FILE *fd, char *s, int how)	/* c_code with precondition */
+mark_last(void)
+{
+	if (seqnames)
+	{	seqnames->is_expr = 1;
+	}
+}
+
+void
+plunk_inline(FILE *fd, char *s, int how, int gencode)	/* c_code with precondition */
 {	IType *tmp;
 
 	tmp = find_inline(s);
@@ -822,16 +986,32 @@
 
 	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, "if (!(%s)) { if (!readtrail) {",
+			tmp->prec);
+		fprintf(fd, " uerror(\"c_code line %d precondition false: %s\"); continue; ",
+			tmp->dln,
+			tmp->prec);
+		fprintf(fd, "} else { ");
+		fprintf(fd, "printf(\"pan: precondition false: %s\\n\"); _m = 3; goto P999; } } ",
+			tmp->prec);
 	}
+
+	if (!gencode)	/* not in d_step */
+	{	fprintf(fd, "\n\t\tsv_save();");
+	}
+
 	fprintf(fd, "%s", (char *) tmp->cn);
 	fprintf(fd, " }\n");
 }
 
+int
+side_scan(char *t, char *pat)
+{	char *r = strstr(t, pat);
+	return (r
+		&& *(r-1) != '"'
+		&& *(r-1) != '\'');
+}
+
 void
 no_side_effects(char *s)
 {	IType *tmp;
@@ -845,9 +1025,9 @@
 	tmp = find_inline(s);
 	t = (char *) tmp->cn;
 
-	if (strchr(t, ';')
-	||  strstr(t, "++")
-	||  strstr(t, "--"))
+	if (side_scan(t, ";")
+	||  side_scan(t, "++")
+	||  side_scan(t, "--"))
 	{
 bad:		lineno = tmp->dln;
 		Fname = tmp->dfn;
@@ -857,8 +1037,10 @@
 	while ((t = strchr(t, '=')) != NULL)
 	{	if (*(t-1) == '!'
 		||  *(t-1) == '>'
-		||  *(t-1) == '<')
-		{	t++;
+		||  *(t-1) == '<'
+		||  *(t-1) == '"'
+		||  *(t-1) == '\'')
+		{	t += 2;
 			continue;
 		}
 		t++;
@@ -869,16 +1051,16 @@
 }
 
 void
-pickup_inline(Symbol *t, Lextok *apars)
+pickup_inline(Symbol *t, Lextok *apars, Lextok *rval)
 {	IType *tmp; Lextok *p, *q; int j;
 
 	tmp = find_inline(t->name);
 
 	if (++Inlining >= MAXINL)
-		fatal("inline fcts too deeply nested", 0);
-
+		fatal("inlines nested too deeply", 0);
 	tmp->cln = lineno;	/* remember calling point */
 	tmp->cfn = Fname;	/* and filename */
+	tmp->rval = rval;
 
 	for (p = apars, q = tmp->params, j = 0; p && q; p = p->rgt, q = q->rgt)
 		j++; /* count them */
@@ -887,7 +1069,7 @@
 
 	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);
+	{	tmp->anms[j] = (char *) emalloc(strlen(IArg_cont[j])+1);
 		strcpy(tmp->anms[j], IArg_cont[j]);
 	}
 
@@ -897,14 +1079,18 @@
 	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);
+	printf("spin: %s:%d, inlining '%s' (from %s:%d)\n",
+		tmp->cfn->name, tmp->cln, t->name, tmp->dfn->name, tmp->dln);
 #endif
 	for (j = 0; j < Inlining; j++)
-		if (Inline_stub[j] == Inline_stub[Inlining])
-		fatal("cyclic inline attempt on: %s", t->name);
+	{	if (Inline_stub[j] == Inline_stub[Inlining])
+		{	fatal("cyclic inline attempt on: %s", t->name);
+	}	}
+	last_token = SEMI;	/* avoid insertion of extra semi */
 }
 
+extern int pp_mode;
+
 static void
 do_directive(int first)
 {	int c = first;	/* handles lines starting with pound */
@@ -930,13 +1116,15 @@
 		fatal("malformed preprocessor directive - .fname", 0);
 
 	if ((c = Getchar()) != '\"')
-		fatal("malformed preprocessor directive - .fname", 0);
+	{	printf("got %c, expected \" -- lineno %d\n", c, lineno);
+		fatal("malformed preprocessor directive - .fname (%s)", yytext);
+	}
 
-	getword(c, notquote);
+	getword(Getchar(), notquote);	/* was getword(c, notquote); */
 	if (Getchar() != '\"')
 		fatal("malformed preprocessor directive - fname.", 0);
 
-	strcat(yytext, "\"");
+	/* strcat(yytext, "\""); */
 	Fname = lookup(yytext);
 done:
 	while (Getchar() != '\n')
@@ -965,41 +1153,44 @@
 			break;
 		}
 	}
-	fatal("cannot happen", (char *) 0);			
+	fatal("cannot happen", (char *) 0); /* unreachable */
 }
 
+
 Symbol *
 prep_inline(Symbol *s, Lextok *nms)
 {	int c, nest = 1, dln, firstchar, cnr;
-	char *p, buf[SOMETHINGBIG], buf2[RATHERSMALL];
+	char *p;
 	Lextok *t;
+	static char Buf1[SOMETHINGBIG], Buf2[RATHERSMALL];
 	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);
+			fatal("bad param to inline %s", 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);
+		s->name = (char *) emalloc(strlen("c_code")+26);
 		sprintf(s->name, "c_code%d", c_code++);
 		s->context = context;
 		s->type = CODE_FRAG;
 	} else
-		s->type = PREDEF;
+	{	s->type = PREDEF;
+	}
 
-	p = &buf[0];
-	buf2[0] = '\0';
+	p = &Buf1[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; } */
+			precondition(&Buf2[0]);	/* e.g., c_code [p] { r = p-r; } */
 			continue;
 		case '{':
 			break;
@@ -1017,19 +1208,22 @@
 	dln = lineno;
 	if (s->type == CODE_FRAG)
 	{	if (verbose&32)
-			sprintf(buf, "\t/* line %d %s */\n\t\t",
+		{	sprintf(Buf1, "\t/* line %d %s */\n\t\t",
 				lineno, Fname->name);
-		else
-			strcpy(buf, "");
+		} else
+		{	strcpy(Buf1, "");
+		}
 	} else
-		sprintf(buf, "\n#line %d %s\n{", lineno, Fname->name);
-	p += strlen(buf);
+	{	sprintf(Buf1, "\n#line %d \"%s\"\n{", lineno, Fname->name);
+	}
+	p += strlen(Buf1);
 	firstchar = 1;
 
 	cnr = 1; /* not zero */
 more:
-	*p++ = c = Getchar();
-	if (p - buf >= SOMETHINGBIG)
+	c = Getchar();
+	*p++ = (char) c;
+	if (p - Buf1 >= SOMETHINGBIG)
 		fatal("inline text too long", 0);
 	switch (c) {
 	case '\n':
@@ -1045,11 +1239,13 @@
 		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",
+			{	*--p = '\0';	/* remove trailing '}' */
+			}	
+			def_inline(s, dln, &Buf1[0], &Buf2[0], nms);
+			if (firstchar)
+			{	printf("%3d: %s, warning: empty inline definition (%s)\n",
 					dln, Fname->name, s->name);
+			}
 			return s;	/* normal return */
 		}
 		break;
@@ -1057,30 +1253,240 @@
 		if (cnr == 0)
 		{	p--;
 			do_directive(c); /* reads to newline */
-			break;
-		} /* else fall through */
-	default:
-		firstchar = 0;
+		} else
+		{	firstchar = 0;
+			cnr++;
+		}
+		break;
 	case '\t':
 	case ' ':
 	case '\f':
 		cnr++;
 		break;
+	case '"':
+		do {
+			c = Getchar();
+			*p++ = (char) c;
+			if (c == '\\')
+			{	*p++ = (char) Getchar();
+			}
+			if (p - Buf1 >= SOMETHINGBIG)
+			{	fatal("inline text too long", 0);
+			}
+		} while (c != '"');	/* end of string */
+		/* *p = '\0'; */
+		break;
+	case '\'':
+		c = Getchar();
+		*p++ = (char) c;
+		if (c == '\\')
+		{	*p++ = (char) Getchar();
+		}
+		c = Getchar();
+		*p++ = (char) c;
+		assert(c == '\'');
+		break;
+	default:
+		firstchar = 0;
+		cnr++;
+		break;
 	}
 	goto more;
 }
 
+static void
+set_cur_scope(void)
+{	int i;
+	char tmpbuf[256];
+
+	strcpy(CurScope, "_");
+
+	if (context)
+	for (i = 0; i < scope_level; i++)
+	{	sprintf(tmpbuf, "%d_", scope_seq[i]);
+		strcat(CurScope, tmpbuf);
+	}
+}
+
 static int
+pre_proc(void)
+{	char b[512];
+	int c, i = 0;
+
+	b[i++] = '#';
+	while ((c = Getchar()) != '\n' && c != EOF)
+	{	b[i++] = (char) c;
+	}
+	b[i] = '\0';
+	yylval = nn(ZN, 0, ZN, ZN);
+	yylval->sym = lookup(b);
+	return PREPROC;
+}
+
+static int specials[] = {
+	'}', ')', ']',
+	OD, FI, ELSE, BREAK,
+	C_CODE, C_EXPR, C_DECL,
+	NAME, CONST, INCR, DECR, 0
+};
+
+int
+follows_token(int c)
+{	int i;
+
+	for (i = 0; specials[i]; i++)
+	{	if (c == specials[i])
+		{	return 1;
+	}	}
+	return 0;
+}
+#define DEFER_LTL
+#ifdef DEFER_LTL
+/* defer ltl formula to the end of the spec
+ * no matter where they appear in the original
+ */
+
+static int deferred = 0;
+static FILE *defer_fd;
+
+int
+get_deferred(void)
+{
+	if (!defer_fd)
+	{	return 0;	/* nothing was deferred */
+	}
+	fclose(defer_fd);
+
+	defer_fd = fopen(TMP_FILE2, "r");
+	if (!defer_fd)
+	{	non_fatal("cannot retrieve deferred ltl formula", (char *) 0);
+		return 0;
+	}
+	fclose(yyin);
+	yyin = defer_fd;
+	return 1;
+}
+
+void
+zap_deferred(void)
+{
+	(void) unlink(TMP_FILE2);
+}
+
+int
+put_deferred(void)
+{	int c, cnt;
+	if (!defer_fd)
+	{	defer_fd = fopen(TMP_FILE2, "w+");
+		if (!defer_fd)
+		{	non_fatal("cannot defer ltl expansion", (char *) 0);
+			return 0;
+	}	}
+	fprintf(defer_fd, "ltl ");
+	cnt = 0;
+	while ((c = getc(yyin)) != EOF)
+	{	if (c == '{')
+		{	cnt++;
+		}
+		if (c == '}')
+		{	cnt--;
+			if (cnt == 0)
+			{	break;
+		}	}
+		fprintf(defer_fd, "%c", c);
+	}
+	fprintf(defer_fd, "}\n");
+	fflush(defer_fd);
+	return 1;
+}
+#endif
+
+#define EXPAND_SELECT
+#ifdef EXPAND_SELECT
+static char tmp_hold[256];
+static int  tmp_has;
+
+void
+new_select(void)
+{	tmp_hold[0] = '\0';
+	tmp_has = 0;
+}
+
+int
+scan_to(int stop, int (*tst)(int), char *buf)
+{	int c, i = 0;
+
+	do {	c = Getchar();
+		if (tmp_has < sizeof(tmp_hold))
+		{	tmp_hold[tmp_has++] = c;
+		}
+		if (c == '\n')
+		{	lineno++;
+		} else if (buf)
+		{	buf[i++] = c;
+		}
+		if (tst && !tst(c) && c != ' ' && c != '\t')
+		{	break;
+		}
+	} while (c != stop && c != EOF);
+
+	if (buf)
+	{	buf[i-1] = '\0';
+	}
+
+	if (c != stop)
+	{	if (0)
+		{	printf("saw: '%c', expected '%c'\n", c, stop);
+		}
+		if (tmp_has < sizeof(tmp_hold))
+		{	tmp_hold[tmp_has] = '\0';
+			push_back(tmp_hold);
+			if (0)
+			{	printf("pushed back: <'%s'>\n", tmp_hold);
+			}
+			return 0; /* internal expansion fails */
+		} else
+		{	fatal("expecting select ( name : constant .. constant )", 0);
+	}	}
+	return 1;		/* success */
+}
+#endif
+
+int
 lex(void)
 {	int c;
-
 again:
 	c = Getchar();
 	yytext[0] = (char) c;
 	yytext[1] = '\0';
 	switch (c) {
+	case EOF:
+#ifdef DEFER_LTL
+		if (!deferred)
+		{	deferred = 1;
+			if (get_deferred())
+			{	goto again;
+			}
+		} else
+		{	zap_deferred();
+		}
+#endif
+		return c;
 	case '\n':		/* newline */
 		lineno++;
+		/* make most semi-colons optional */
+		if (implied_semis
+	/*	&&  context	*/
+		&&  in_seq
+		&&  par_cnt == 0
+		&&  follows_token(last_token))
+		{	if (0)
+			{	printf("insert ; line %d, last_token %d in_seq %d\n",
+				 lineno-1, last_token, in_seq);
+			}
+			ValToken(1, SEMI);
+		}
+		/* else fall thru */
 	case '\r':		/* carriage return */
 		goto again;
 
@@ -1089,6 +1495,10 @@
 
 	case '#':		/* preprocessor directive */
 		if (in_comment) goto again;
+		if (pp_mode)
+		{	last_token = PREPROC;
+			return pre_proc();
+		}
 		do_directive(c);
 		goto again;
 
@@ -1099,6 +1509,13 @@
 		strcat(yytext, "\"");
 		SymToken(lookup(yytext), STRING)
 
+	case '$':
+		getword('\"', notdollar);
+		if (Getchar() != '$')
+			fatal("ltl definition not terminated", yytext);
+		strcat(yytext, "\""); 
+		SymToken(lookup(yytext), STRING)
+
 	case '\'':	/* new 3.0.9 */
 		c = Getchar();
 		if (c == '\\')
@@ -1117,20 +1534,104 @@
 	}
 
 	if (isdigit_(c))
-	{	getword(c, isdigit_);
-		ValToken(atoi(yytext), CONST)
+	{	long int nr;
+		getword(c, isdigit_);
+		errno = 0;
+		nr = strtol(yytext, NULL, 10);
+		if (errno != 0)
+		{	fprintf(stderr, "spin: value out of range: '%s' read as '%d'\n",
+				yytext, (int) nr);
+		}
+		ValToken((int)nr, CONST)
 	}
 
 	if (isalpha_(c) || c == '_')
 	{	getword(c, isalnum_);
 		if (!in_comment)
 		{	c = check_name(yytext);
-			if (c) return c;
+
+#ifdef EXPAND_SELECT
+			if (c == SELECT && Inlining < 0)
+			{	char name[64], from[32], upto[32];
+				int i, a, b;
+				new_select();
+				if (!scan_to('(', 0, 0)
+				||  !scan_to(':', isalnum, name)
+				||  !scan_to('.', isdigit, from)
+				||  !scan_to('.', 0, 0)
+				||  !scan_to(')', isdigit, upto))
+				{	goto not_expanded;
+				}
+				a = atoi(from);
+				b = atoi(upto);
+				if (0)
+				{	printf("Select %s from %d to %d\n",
+						name, a, b);
+				}
+				if (a > b)
+				{	non_fatal("bad range in select statement", 0);
+					goto again;
+				}
+				if (b - a <= 32)
+				{	push_back("if ");
+					for (i = a; i <= b; i++)
+					{	char buf[128];
+						push_back(":: ");
+						sprintf(buf, "%s = %d ",
+							name, i);
+						push_back(buf);
+					}
+					push_back("fi ");
+				} else
+				{	char buf[128];
+					sprintf(buf, "%s = %d; do ",
+						name, a);
+					push_back(buf);
+					sprintf(buf, ":: (%s < %d) -> %s++ ",
+						name, b, name);
+					push_back(buf);
+					push_back(":: break od; ");
+				}
+				goto again;
+			}
+not_expanded:
+#endif
+
+#ifdef DEFER_LTL
+			if (c == LTL && !deferred)
+			{	if (put_deferred())
+				{	goto again;
+			}	}
+#endif
+			if (c)
+			{	last_token = c;
+				return c;
+			}
 			/* else fall through */
 		}
 		goto again;
 	}
 
+	if (ltl_mode)
+	{	switch (c) {
+		case '-': c = follow('>', IMPLIES,    '-'); break;
+		case '[': c = follow(']', ALWAYS,     '['); break;
+		case '<': c = follow('>', EVENTUALLY, '<');
+			  if (c == '<')
+			  {	c = Getchar();
+				if (c == '-')
+				{	c = follow('>', EQUIV, '-');
+					if (c == '-')
+					{	Ungetch(c);
+						c = '<';
+					}
+				} else
+				{	Ungetch(c);
+					c = '<';
+			  }	}
+		default:  break;
+	}	}
+
 	switch (c) {
 	case '/': c = follow('*', 0, '/');
 		  if (!c) { in_comment = 1; goto again; }
@@ -1139,7 +1640,7 @@
 		  if (!c) { in_comment = 0; goto again; }
 		  break;
 	case ':': c = follow(':', SEP, ':'); break;
-	case '-': c = follow('>', SEMI, follow('-', DECR, '-')); break;
+	case '-': c = follow('>', ARROW, follow('-', DECR, '-')); break;
 	case '+': c = follow('+', INCR, '+'); break;
 	case '<': c = follow('<', LSHIFT, follow('=', LE, LT)); break;
 	case '>': c = follow('>', RSHIFT, follow('=', GE, GT)); break;
@@ -1149,12 +1650,35 @@
 	case '&': c = follow('&', AND, '&'); break;
 	case '|': c = follow('|', OR, '|'); break;
 	case ';': c = SEMI; break;
+	case '.': c = follow('.', DOTDOT, '.'); break;
+	case '{': scope_seq[scope_level++]++; set_cur_scope(); break;
+	case '}': scope_level--; set_cur_scope(); break;
 	default : break;
 	}
-	Token(c)
+	ValToken(0, c)
 }
 
 static struct {
+	char *s;	int tok;
+} LTL_syms[] = {
+	/* [], <>, ->, and <-> are intercepted in lex() */
+	{ "U",		UNTIL   },
+	{ "V",		RELEASE },
+	{ "W",		WEAK_UNTIL },
+	{ "X",		NEXT    },
+	{ "always",	ALWAYS  },
+	{ "eventually",	EVENTUALLY },
+	{ "until",	UNTIL   },
+	{ "stronguntil",UNTIL   },
+	{ "weakuntil",	WEAK_UNTIL   },
+	{ "release",	RELEASE },
+	{ "next",	NEXT    },
+	{ "implies",	IMPLIES },
+	{ "equivalent",	EQUIV   },
+	{ 0, 		0       },
+};
+
+static struct {
 	char *s;	int tok;	int val;	char *sym;
 } Names[] = {
 	{"active",	ACTIVE,		0,		0},
@@ -1178,14 +1702,19 @@
 	{"eval",	EVAL,		0,		0},
 	{"false",	CONST,		0,		0},
 	{"fi",		FI,		0,		0},
+	{"for",		FOR,		0,		0},
 	{"full",	FULL,		0,		0},
+	{"get_priority", GET_P,		0,		0},
 	{"goto",	GOTO,		0,		0},
 	{"hidden",	HIDDEN,		0,		":hide:"},
 	{"if",		IF,		0,		0},
+	{"in",		IN,		0,		0},
 	{"init",	INIT,		0,		":init:"},
+	{"inline",	INLINE,		0,		0},
 	{"int",		TYPE,		INT,		0},
 	{"len",		LEN,		0,		0},
 	{"local",	ISLOCAL,	0,		":local:"},
+	{"ltl",		LTL,		0,		":ltl:"},
 	{"mtype",	TYPE,		MTYPE,		0},
 	{"nempty",	NEMPTY,		0,		0},
 	{"never",	CLAIM,		0,		":never:"},
@@ -1201,9 +1730,11 @@
 	{"priority",	PRIORITY,	0,		0},
 	{"proctype",	PROCTYPE,	0,		0},
 	{"provided",	PROVIDED,	0,		0},
+	{"return",	RETURN,		0,		0},
 	{"run",		RUN,		0,		0},
 	{"d_step",	D_STEP,		0,		0},
-	{"inline",	INLINE,		0,		0},
+	{"select",	SELECT,		0,		0},
+	{"set_priority", SET_P,		0,		0},
 	{"short",	TYPE,		SHORT,		0},
 	{"skip",	CONST,		1,		0},
 	{"timeout",	TIMEOUT,	0,		0},
@@ -1223,13 +1754,23 @@
 {	int i;
 
 	yylval = nn(ZN, 0, ZN, ZN);
+
+	if (ltl_mode)
+	{	for (i = 0; LTL_syms[i].s; i++)
+		{	if (strcmp(s, LTL_syms[i].s) == 0)
+			{	return LTL_syms[i].tok;
+	}	}	}
+
 	for (i = 0; Names[i].s; i++)
-		if (strcmp(s, Names[i].s) == 0)
+	{	if (strcmp(s, Names[i].s) == 0)
 		{	yylval->val = Names[i].val;
 			if (Names[i].sym)
 				yylval->sym = lookup(Names[i].sym);
+			if (Names[i].tok == IN && !in_for)
+			{	continue;
+			}
 			return Names[i].tok;
-		}
+	}	}
 
 	if ((yylval->val = ismtype(s)) != 0)
 	{	yylval->ismtyp = 1;
@@ -1239,6 +1780,9 @@
 	if (strcmp(s, "_last") == 0)
 		has_last++;
 
+	if (strcmp(s, "_priority") == 0)
+		has_priority++;
+
 	if (Inlining >= 0 && !ReDiRect)
 	{	Lextok *tt, *t = Inline_stub[Inlining]->params;
 
@@ -1253,19 +1797,29 @@
 				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",
+					printf("spin: %s:%d replacement value: %s\n",
+						oFname->name?oFname->name:"--", lineno, tt->lft->sym->name);
+					fatal("formal par of %s contains replacement value",
 						Inline_stub[Inlining]->nm->name);
 					yylval->ntyp = tt->lft->ntyp;
 					yylval->sym = lookup(tt->lft->sym->name);
 					return NAME;
 				}
+
+			/* check for occurrence of param as field of struct */
+			{ char *ptr = Inline_stub[Inlining]->anms[i];
+				while ((ptr = strstr(ptr, s)) != NULL)
+				{	if (*(ptr-1) == '.'
+					||  *(ptr+strlen(s)) == '.')
+					{	fatal("formal par of %s used in structure name",
+						Inline_stub[Inlining]->nm->name);
+					}
+					ptr++;
+			}	}
 			ReDiRect = Inline_stub[Inlining]->anms[i];
 			return 0;
 	}	 }
@@ -1293,13 +1847,16 @@
 	if (hold)
 	{	c = hold;
 		hold = 0;
+		last_token = c;
 	} else
 	{	c = lex();
 		if (last == ELSE
 		&&  c != SEMI
+		&&  c != ARROW
 		&&  c != FI)
 		{	hold = c;
 			last = 0;
+			last_token = SEMI;
 			return SEMI;
 		}
 		if (last == '}'
@@ -1312,12 +1869,14 @@
 		&&  c != '}'
 		&&  c != UNLESS
 		&&  c != SEMI
+		&&  c != ARROW
 		&&  c != EOF)
 		{	hold = c;
 			last = 0;
+			last_token = SEMI;
 			return SEMI;	/* insert ';' */
 		}
-		if (c == SEMI)
+		if (c == SEMI || c == ARROW)
 		{	/* if context, we're not in a typedef
 			 * because they're global.
 			 * if owner, we're at the end of a ref
@@ -1328,6 +1887,7 @@
 			if (context) owner = ZS;
 			hold = lex();	/* look ahead */
 			if (hold == '}'
+			||  hold == ARROW
 			||  hold == SEMI)
 			{	c = hold; /* omit ';' */
 				hold = 0;
@@ -1346,16 +1906,26 @@
 			{	IArgno = 0;
 				IArg_cont[0][0] = '\0';
 			} else
+			{	assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont));
 				strcat(IArg_cont[IArgno], yytext);
+			}
 		} else if (strcmp(yytext, ")") == 0)
 		{	if (--IArg_nst > 0)
+			{	assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont));
 				strcat(IArg_cont[IArgno], yytext);
+			}
 		} else if (c == CONST && yytext[0] == '\'')
 		{	sprintf(yytext, "'%c'", yylval->val);
+			assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont));
+			strcat(IArg_cont[IArgno], yytext);
+		} else if (c == CONST)
+		{	sprintf(yytext, "%d", yylval->val);
+			assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont));
 			strcat(IArg_cont[IArgno], yytext);
 		} else
 		{
 			switch (c) {
+			case ARROW:	strcpy(yytext, "->"); break; /* NEW */
 			case SEP:	strcpy(yytext, "::"); break;
 			case SEMI:	strcpy(yytext, ";"); break;
 			case DECR:	strcpy(yytext, "--"); break;
@@ -1376,9 +1946,9 @@
 			case AND: 	strcpy(yytext, "&&"); break;
 			case OR:	strcpy(yytext, "||"); break;
 			}
+			assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont));
 			strcat(IArg_cont[IArgno], yytext);
 		}
 	}
-
 	return c;
 }
diff -r 51b3bf8bc61b sys/src/cmd/spin/structs.c
--- a/sys/src/cmd/spin/structs.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/structs.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,13 +1,10 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include "spin.h"
 #include "y.tab.h"
@@ -19,7 +16,7 @@
 } UType;
 
 extern	Symbol	*Fname;
-extern	int	lineno, depth, Expand_Ok;
+extern	int	lineno, depth, Expand_Ok, has_hidden, in_for;
 
 Symbol	*owner;
 
@@ -33,14 +30,16 @@
 setuname(Lextok *n)
 {	UType *tmp;
 
+	if (!owner)
+		fatal("illegal reference inside typedef", (char *) 0);
+
 	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;
@@ -102,21 +101,22 @@
 	{	lineno = n->ln;
 		Fname = n->fn;
 		if (n->sym->type)
-		non_fatal("redeclaration of '%s'", n->sym->name);
+			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);
+			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)
+		{	if (strncmp(vis->sym->name, ":hide:", (size_t) 6) == 0)
+			{	n->sym->hidden |= 1;
+				has_hidden++;
+			} else if (strncmp(vis->sym->name, ":show:", (size_t) 6) == 0)
 				n->sym->hidden |= 2;
-			else if (strncmp(vis->sym->name, ":local:", 7) == 0)
+			else if (strncmp(vis->sym->name, ":local:", (size_t) 7) == 0)
 				n->sym->hidden |= 64;
 		}
 		n->sym->type = STRUCT;	/* classification   */
@@ -196,6 +196,7 @@
 		fatal("non-zero 'rgt' on non-structure", 0);
 
 	ix = eval(tmp->lft);
+/*	printf("%d: ix: %d (%d) %d\n", depth, ix, tl->nel, tl->val[ix]); */
 	if (ix >= tl->nel || ix < 0)
 		fatal("indexing error \'%s\'", tl->name);
 
@@ -222,10 +223,12 @@
 		fatal("indexing error \'%s\'", tl->name);
 
 	if (tl->nbits > 0)
-		a = (a & ((1<<tl->nbits)-1));	
-	tl->val[ix] = a;
-	tl->setat = depth;
+		a = (a & ((1<<tl->nbits)-1));
 
+	if (a != tl->val[ix])
+	{	tl->val[ix] = a;
+		tl->setat = depth;
+	}
 	return 1;
 }
 
@@ -246,7 +249,7 @@
 	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)
+		{	if (tl->sym->nel > 1 || tl->sym->isarray)
 				fatal("array of structures in param list, %s",
 					tl->sym->name);
 			cnt += Cnt_flds(tl->sym->Slst);
@@ -266,9 +269,9 @@
 		return s->type;
 
 	if (!t->rgt
-	||  !t->rgt->ntyp == '.'
+	||   t->rgt->ntyp != '.'	/* gh: had ! in wrong place */
 	||  !t->rgt->lft)
-		return STRUCT;	/* not a field reference */
+		return STRUCT;		/* not a field reference */
 
 	return Sym_typ(t->rgt->lft);
 }
@@ -315,6 +318,7 @@
 	if (!s) return ZN;
 
 	d = (Lextok *) emalloc(sizeof(Lextok));
+	d->uiid = s->uiid;
 	d->ntyp = s->ntyp;
 	d->val  = s->val;
 	d->ln   = s->ln;
@@ -353,7 +357,7 @@
 		goto out;
 	}
 	fprintf(fd, ".%s", tl->name);
-out:	if (tmp->sym->nel > 1)
+out:	if (tmp->sym->nel > 1 || tmp->sym->isarray == 1)
 	{	fprintf(fd, "[%d]", eval(tmp->lft));
 		hiddenarrays = 1;
 	}
@@ -391,7 +395,7 @@
 	}
 	sprintf(lbuf, ".%s", tl->name);
 	strcat(buf, lbuf);
-	if (tmp->sym->nel > 1)
+	if (tmp->sym->nel > 1 || tmp->sym->isarray == 1)
 	{	sprintf(lbuf, "[%d]", eval(tmp->lft));
 		strcat(buf, lbuf);
 	}
@@ -405,10 +409,10 @@
 	extern void Done_case(char *, Symbol *);
 
 	ini_struct(z);
-	if (z->nel == 1)
+	if (z->nel == 1 && z->isarray == 0)
 		sprintf(eprefix, "%s%s.", s, z->name);
 	for (ix = 0; ix < z->nel; ix++)
-	{	if (z->nel > 1)
+	{	if (z->nel > 1 || z->isarray == 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)
@@ -426,10 +430,10 @@
 	int ix;
 
 	ini_struct(z);
-	if (z->nel == 1)
+	if (z->nel == 1 && z->isarray == 0)
 		sprintf(eprefix, "%s%s.", s, z->name);
 	for (ix = 0; ix < z->nel; ix++)
-	{	if (z->nel > 1)
+	{	if (z->nel > 1 || z->isarray == 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)
@@ -443,7 +447,7 @@
 void
 c_struct(FILE *fd, char *ipref, Symbol *z)
 {	Lextok *fp, *tl;
-	char pref[256], eprefix[256];
+	char pref[256], eprefix[300];
 	int ix;
 
 	ini_struct(z);
@@ -452,7 +456,7 @@
 	for (fp = z->Sval[ix]; fp; fp = fp->rgt)
 	for (tl = fp->lft; tl; tl = tl->rgt)
 	{	strcpy(eprefix, ipref);
-		if (z->nel > 1)
+		if (z->nel > 1 || z->isarray == 1)
 		{	/* insert index before last '.' */
 			eprefix[strlen(eprefix)-1] = '\0';
 			sprintf(pref, "[ %d ].", ix);
@@ -476,7 +480,7 @@
 	ini_struct(z);
 
 	for (ix = 0; ix < z->nel; ix++)
-	{	if (z->nel > 1)
+	{	if (z->nel > 1 || z->isarray == 1)
 			sprintf(eprefix, "%s[%d]", prefix, ix);
 		else
 			strcpy(eprefix, prefix);
@@ -484,7 +488,7 @@
 		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];
+			{	char pref[300];
 				strcpy(pref, eprefix);
 				strcat(pref, ".");
 				strcat(pref, tl->sym->name);
@@ -498,7 +502,7 @@
 					if (r)
 					printf("%s(%d):", r->n->name, r->pid);
 					printf("%s.%s", eprefix, tl->sym->name);
-					if (tl->sym->nel > 1)
+					if (tl->sym->nel > 1 || tl->sym->isarray == 1)
 						printf("[%d]", jx);
 					printf(" = ");
 					sr_mesg(stdout, tl->sym->val[jx],
@@ -579,9 +583,11 @@
 	int i, cnt; extern int IArgs;
 
 	if (n->sym->type != STRUCT
+	||  in_for
 	||  is_explicit(n))
 		return n;
 
+
 	if (n->rgt
 	&&  n->rgt->ntyp == '.'
 	&&  n->rgt->lft
diff -r 51b3bf8bc61b sys/src/cmd/spin/sym.c
--- a/sys/src/cmd/spin/sym.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/sym.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,25 +1,27 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include "spin.h"
 #include "y.tab.h"
 
 extern Symbol	*Fname, *owner;
 extern int	lineno, depth, verbose, NamesNotAdded, deadvar;
+extern int	has_hidden, m_loss, old_scope_rules;
 extern short	has_xu;
+extern char	CurScope[MAXSCOPESZ];
 
 Symbol	*context = ZS;
 Ordered	*all_names = (Ordered *)0;
 int	Nid = 0;
 
+Lextok *Mtype = (Lextok *) 0;
+Lextok *runstmnts = ZN;
+
 static Ordered	*last_name = (Ordered *)0;
 static Symbol	*symtab[Nhash+1];
 
@@ -31,12 +33,12 @@
 	return !strcmp(a->name, b->name);
 }
 
-int
-hash(char *s)
-{	int h=0;
+unsigned int
+hash(const char *s)
+{	unsigned int h = 0;
 
 	while (*s)
-	{	h += *s++;
+	{	h += (unsigned int) *s++;
 		h <<= 1;
 		if (h&(Nhash+1))
 			h |= 1;
@@ -44,31 +46,89 @@
 	return h&Nhash;
 }
 
+void
+disambiguate(void)
+{	Ordered *walk;
+	Symbol *sp;
+	char *n, *m;
+
+	if (old_scope_rules)
+		return;
+
+	/* prepend the scope_prefix to the names */
+
+	for (walk = all_names; walk; walk = walk->next)
+	{	sp = walk->entry;
+		if (sp->type != 0
+		&&  sp->type != LABEL
+		&&  strlen((const char *)sp->bscp) > 1)
+		{	if (sp->context)
+			{	m = (char *) emalloc(strlen((const char *)sp->bscp) + 1);
+				sprintf(m, "_%d_", sp->context->sc);
+				if (strcmp((const char *) m, (const char *) sp->bscp) == 0)
+				{	continue;
+				/* 6.2.0: only prepend scope for inner-blocks,
+				   not for top-level locals within a proctype
+				   this means that you can no longer use the same name
+				   for a global and a (top-level) local variable
+				 */
+			}	}
+
+			n = (char *) emalloc(strlen((const char *)sp->name)
+				+ strlen((const char *)sp->bscp) + 1);
+			sprintf(n, "%s%s", sp->bscp, sp->name);
+			sp->name = n;	/* discard the old memory */
+	}	}
+}
+
 Symbol *
 lookup(char *s)
 {	Symbol *sp; Ordered *no;
-	int h = hash(s);
+	unsigned int h = hash(s);
 
+	if (old_scope_rules)
+	{	/* same scope - global refering to global or local to local */
+		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 */
+		}	}
+	} else
+	{	/* added 6.0.0: more traditional, scope rule */
+		for (sp = symtab[h]; sp; sp = sp->next)
+		{	if (strcmp(sp->name, s) == 0
+			&&  samename(sp->context, context)
+			&&  (strcmp((const char *)sp->bscp, CurScope) == 0
+			||   strncmp((const char *)sp->bscp, CurScope, strlen((const char *)sp->bscp)) == 0)
+			&&  samename(sp->owner, owner))
+			{
+				if (!samename(sp->owner, owner))
+				{	printf("spin: different container %s\n", sp->name);
+					printf("	old: %s\n", sp->owner?sp->owner->name:"--");
+					printf("	new: %s\n", owner?owner->name:"--");
+				/*	alldone(1);	*/
+				}
+				return sp;		/* found */
+	}	}	}
+
+	if (context)				/* in proctype, refers to global */
 	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
+	{	if (strcmp(sp->name, s) == 0
 		&& !sp->context
 		&&  samename(sp->owner, owner))
-			return sp;		/* global */
+		{	return sp;		/* global */
+	}	}
 
 	sp = (Symbol *) emalloc(sizeof(Symbol));
-	sp->name = (char *) emalloc((int) strlen(s) + 1);
+	sp->name = (char *) emalloc(strlen(s) + 1);
 	strcpy(sp->name, s);
 	sp->nel = 1;
 	sp->setat = depth;
 	sp->context = context;
 	sp->owner = owner;			/* if fld in struct */
+	sp->bscp = (unsigned char *) emalloc(strlen((const char *)CurScope)+1);
+	strcpy((char *)sp->bscp, CurScope);
 
 	if (NamesNotAdded == 0)
 	{	sp->next = symtab[h];
@@ -109,8 +169,6 @@
 	}
 }
 
-Lextok *runstmnts = ZN;
-
 void
 trackrun(Lextok *n)
 {
@@ -151,11 +209,11 @@
 		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;
+		while (i > 0 && buf[--i] == ' ') buf[i] = '\0';
+		if (i == 0 || strcmp(buf, buf2) == 0) return;
 		prehint(parnm);
 		printf("proctype %s, '%s %s' could be declared",
-			parnm->context->name, buf, parnm->name);
+			parnm->context?parnm->context->name:"", buf, parnm->name);
 		printf(" '%s %s'\n", buf2, parnm->name);
 	}
 }
@@ -178,9 +236,9 @@
 
 	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;
+		{	lineno = n->ln; Fname = n->fn;
+			fatal("redeclaration of '%s'", n->sym->name);
+			lineno = oln;
 		}
 		n->sym->type = (short) t;
 
@@ -201,14 +259,15 @@
 				n->sym->name);
 		}
 		if (vis)
-		{	if (strncmp(vis->sym->name, ":hide:", 6) == 0)
+		{	if (strncmp(vis->sym->name, ":hide:", (size_t) 6) == 0)
 			{	n->sym->hidden |= 1;
+				has_hidden++;
 				if (t == BIT)
 				fatal("bit variable (%s) cannot be hidden",
 					n->sym->name);
-			} else if (strncmp(vis->sym->name, ":show:", 6) == 0)
+			} else if (strncmp(vis->sym->name, ":show:", (size_t) 6) == 0)
 			{	n->sym->hidden |= 2;
-			} else if (strncmp(vis->sym->name, ":local:", 7) == 0)
+			} else if (strncmp(vis->sym->name, ":local:", (size_t) 7) == 0)
 			{	n->sym->hidden |= 64;
 			}
 		}
@@ -268,7 +327,13 @@
 setxus(Lextok *p, int t)
 {	Lextok *m, *n;
 
-	has_xu = 1; 
+	has_xu = 1;
+
+	if (m_loss && t == XS)
+	{	printf("spin: %s:%d, warning, xs tag not compatible with -m (message loss)\n",
+			(p->fn != NULL) ? p->fn->name : "stdin", p->ln);
+	}
+
 	if (!context)
 	{	lineno = p->ln;
 		Fname = p->fn;
@@ -276,6 +341,7 @@
 	}
 	for (m = p; m; m = m->rgt)
 	{	Lextok *Xu_new = (Lextok *) emalloc(sizeof(Lextok));
+		Xu_new->uiid = p->uiid;
 		Xu_new->val = t;
 		Xu_new->lft = m->lft;
 		Xu_new->sym = context;
@@ -297,8 +363,6 @@
 	}
 }
 
-Lextok *Mtype = (Lextok *) 0;
-
 void
 setmtype(Lextok *m)
 {	Lextok *n;
@@ -332,7 +396,7 @@
 	}
 	lineno = oln;
 	if (cnt > 256)
-	fatal("too many mtype elements (>255)", (char *)0);
+		fatal("too many mtype elements (>255)", (char *)0);
 }
 
 int
@@ -389,11 +453,11 @@
 	printf("\t");
 	if (sp->owner) printf("%s.", sp->owner->name);
 	printf("%s", sp->name);
-	if (sp->nel > 1) printf("[%d]", sp->nel);
+	if (sp->nel > 1 || sp->isarray == 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 */
+	else if (sp->type == STRUCT && sp->Snm != NULL) /* Frank Weil, 2.9.8 */
 		printf("\t%s", sp->Snm->name);
 	else
 		printf("\t%d", eval(sp->ini));
@@ -408,8 +472,13 @@
 
 	if (sp->Nid < 0)	/* formal parameter */
 		printf("\t<parameter %d>", -(sp->Nid));
+	else if (sp->type == MTYPE)
+		printf("\t<constant>");
+	else if (sp->isarray)
+		printf("\t<array>");
 	else
 		printf("\t<variable>");
+
 	if (sp->type == CHAN && sp->ini)
 	{	int i;
 		for (m = sp->ini->rgt, i = 0; m; m = m->rgt)
@@ -423,6 +492,11 @@
 			if (m->rgt) printf("\t");
 		}
 	}
+
+	if (!old_scope_rules)
+	{	printf("\t{scope %s}", sp->bscp);
+	}
+
 	printf("\n");
 }
 
@@ -440,11 +514,10 @@
 	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);
+	if (sp->nel > 1 || sp->isarray == 1) printf("[%d]", sp->nel);
 	printf("\t");
 }
 
-
 static struct X {
 	int typ; char *nm;
 } xx[] = {
@@ -521,14 +594,14 @@
 
 			if (!(verbose&32) || has_code) continue;
 
-			printf("spin: warning, %s, ", Fname->name);
+			printf("spin: %s:0, warning, ", 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",
+			printf(", '%s%s' variable is never used (other than in print stmnts)\n",
 				buf, walk->entry->name);
 	}	}
 }
diff -r 51b3bf8bc61b sys/src/cmd/spin/tl.h
--- a/sys/src/cmd/spin/tl.h	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/tl.h	Wed Nov 22 00:21:47 2017 -0800
@@ -1,16 +1,13 @@
 /***** 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.   */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://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>
@@ -66,6 +63,7 @@
 #ifdef NXT
 	, NEXT		/* 269 */
 #endif
+	, CEXPR		/* 270 */
 };
 
 Node	*Canonical(Node *);
@@ -82,11 +80,12 @@
 Symbol	*getsym(Symbol *);
 Symbol	*DoDump(Node *);
 
-char	*emalloc(int);	/* in main.c */
+extern char	*emalloc(size_t);	/* in main.c */
+
+extern unsigned int	hash(const char *);	/* in sym.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);
@@ -100,6 +99,10 @@
 void	Fatal(char *, char *);
 void	fatal(char *, char *);
 void	fsm_print(void);
+void	ini_buchi(void);
+void	ini_cache(void);
+void	ini_rewrt(void);
+void	ini_trans(void);
 void	releasenode(int, Node *);
 void	tfree(void *);
 void	tl_explain(int);
diff -r 51b3bf8bc61b sys/src/cmd/spin/tl_buchi.c
--- a/sys/src/cmd/spin/tl_buchi.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/tl_buchi.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,20 +1,18 @@
 /***** 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.   */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://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;
+extern char *claim_name;
 
 FILE	*tl_out;	/* if standalone: = stdout; */
 
@@ -38,6 +36,13 @@
 static State *never = (State *) 0;
 static int hitsall;
 
+void
+ini_buchi(void)
+{
+	never = (State *) 0;
+	hitsall = 0;
+}
+
 static int
 sametrans(Transition *s, Transition *t)
 {
@@ -58,6 +63,7 @@
 #ifdef NXT
 	case NEXT:
 #endif
+	case CEXPR:
 		return p;
 	case OR:
 		p->lft = Prune(p->lft);
@@ -545,10 +551,22 @@
 	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);
+
+	if (strcmp(t->name->name, "accept_all") == 0)	/* 6.2.4 */
+	{	/* not d_step because there may be remote refs */
+		fprintf(tl_out, "\t:: atomic { (");
+		if (dump_cond(t->cond, t->cond, 1))
+			fprintf(tl_out, "1");
+		fprintf(tl_out, ") -> assert(!(");
+		if (dump_cond(t->cond, t->cond, 1))
+			fprintf(tl_out, "1");
+		fprintf(tl_out, ")) }\n");
+	} else
+	{	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++;
 }
 
@@ -570,11 +588,11 @@
 	&&  Max_Red == 0)
 		fprintf(tl_out, "T0%s:\n", &(b->name->name[6]));
 
-	fprintf(tl_out, "\tif\n");
+	fprintf(tl_out, "\tdo\n");
 	tcnt = 0;
 	rev_trans(b->trans);
 	if (!tcnt) fprintf(tl_out, "\t:: false\n");
-	fprintf(tl_out, "\tfi;\n");
+	fprintf(tl_out, "\tod;\n");
 	Total++;
 }
 
@@ -626,13 +644,13 @@
 	if (tl_clutter) clutter();
 
 	b = findstate("T0_init");
-	if (Max_Red == 0)
+	if (b && (Max_Red == 0))
 		b->accepting = 1;
 
 	mergestates(0); 
 	b = findstate("T0_init");
 
-	fprintf(tl_out, "never {    /* ");
+	fprintf(tl_out, "never %s {    /* ", claim_name?claim_name:"");
 		put_uform();
 	fprintf(tl_out, " */\n");
 
diff -r 51b3bf8bc61b sys/src/cmd/spin/tl_cache.c
--- a/sys/src/cmd/spin/tl_cache.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/tl_cache.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,16 +1,13 @@
 /***** 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.   */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://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"
 
@@ -24,9 +21,18 @@
 static Cache	*stored = (Cache *) 0;
 static unsigned long	Caches, CacheHits;
 
-static int	ismatch(Node *, Node *);
+static int ismatch(Node *, Node *);
+static int sameform(Node *, Node *);
+
 extern void fatal(char *, char *);
-int	sameform(Node *, Node *);
+
+void
+ini_cache(void)
+{
+	stored = (Cache *) 0;
+	Caches = 0;
+	CacheHits = 0;
+}
 
 #if 0
 void
@@ -182,7 +188,7 @@
 	return all_lfts(ntyp, b, a);
 }
 
-int	/* a better isequal() */
+static int	/* a better isequal() */
 sameform(Node *a, Node *b)
 {
 	if (!a && !b) return 1;
@@ -206,6 +212,7 @@
 #ifdef NXT
 	case NEXT:
 #endif
+	case CEXPR:
 		return sameform(a->lft, b->lft);
 	case U_OPER:
 	case V_OPER:
diff -r 51b3bf8bc61b sys/src/cmd/spin/tl_lex.c
--- a/sys/src/cmd/spin/tl_lex.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/tl_lex.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,16 +1,13 @@
 /***** 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.   */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://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>
@@ -18,6 +15,7 @@
 
 static Symbol	*symtab[Nhash+1];
 static int	tl_lex(void);
+extern int tl_peek(int);
 
 extern YYSTYPE	tl_yylval;
 extern char	yytext[];
@@ -26,11 +24,19 @@
 
 static void
 tl_getword(int first, int (*tst)(int))
-{	int i=0; char c;
+{	int i=0; int c;
 
 	yytext[i++] = (char ) first;
-	while (tst(c = tl_Getchar()))
-		yytext[i++] = c;
+
+	c = tl_Getchar();
+	while (c != -1 && tst(c))
+	{	yytext[i++] = (char) c;
+		c = tl_Getchar();
+	}
+
+/*	while (tst(c = tl_Getchar()))
+ *		yytext[i++] = c;
+ */
 	yytext[i] = '\0';
 	tl_UnGetchar();
 }
@@ -54,12 +60,86 @@
 tl_yylex(void)
 {	int c = tl_lex();
 #if 0
-	printf("c = %d\n", c);
+	printf("c = %c (%d)\n", c, c);
 #endif
 	return c;
 }
 
 static int
+is_predicate(int z)
+{	char c, c_prev = z;
+	char want = (z == '{') ? '}' : ')';
+	int i = 0, j, nesting = 0;
+	char peek_buf[512];
+
+	c = tl_peek(i++);	/* look ahead without changing position */
+	while ((c != want || nesting > 0) && c != -1 && i < 2047)
+	{	if (islower((int) c) || c == '_')
+		{	peek_buf[0] = c;
+			j = 1;
+			while (j < (int) sizeof(peek_buf)
+			&&    (isalnum((int)(c = tl_peek(i))) || c == '_'))
+			{	peek_buf[j++] = c;
+				i++;
+			}
+			c = 0;	/* make sure we don't match on z or want on the peekahead */
+			if (j >= (int) sizeof(peek_buf))
+			{	peek_buf[j-1] = '\0';
+				fatal("name '%s' in ltl formula too long", peek_buf);
+			}
+			peek_buf[j] = '\0';
+			if (strcmp(peek_buf, "always") == 0
+			||  strcmp(peek_buf, "equivalent") == 0
+			||  strcmp(peek_buf, "eventually") == 0
+			||  strcmp(peek_buf, "until") == 0
+			||  strcmp(peek_buf, "next") == 0
+			||  strcmp(peek_buf, "c_expr") == 0)
+			{	return 0;
+			}
+		} else
+		{	int c_nxt = tl_peek(i);
+			if (((c == 'U' || c == 'V' || c == 'X')
+			&& !isalnum_(c_prev)
+			&& (c_nxt == -1 || !isalnum_(c_nxt)))
+			||  (c == '<' && c_nxt == '>')
+			||  (c == '<' && c_nxt == '-')
+			||  (c == '-' && c_nxt == '>')
+			||  (c == '[' && c_nxt == ']'))
+			{	return 0;
+		}	}
+
+		if (c == z)
+		{	nesting++;
+		}
+		if (c == want)
+		{	nesting--;
+		}
+		c_prev = c;
+		c = tl_peek(i++);
+	}
+	return 1;
+}
+
+static void
+read_upto_closing(int z)
+{	char c, want = (z == '{') ? '}' : ')';
+	int i = 0, nesting = 0;
+
+	c = tl_Getchar();
+	while ((c != want || nesting > 0) && c != -1 && i < 2047) /* yytext is 2048 */
+	{	yytext[i++] = c;
+		if (c == z)
+		{	nesting++;
+		}
+		if (c == want)
+		{	nesting--;
+		}
+		c = tl_Getchar();
+	}
+	yytext[i] = '\0';
+}
+
+static int
 tl_lex(void)
 {	int c;
 
@@ -74,6 +154,20 @@
 
 	} while (c == ' ');	/* '\t' is removed in tl_main.c */
 
+	if (c == '{' || c == '(')	/* new 6.0.0 */
+	{	if (is_predicate(c))
+		{	read_upto_closing(c);
+			tl_yylval = tl_nn(PREDICATE,ZN,ZN);
+			if (!tl_yylval)
+			{	fatal("unexpected error 4", (char *) 0);
+			}
+			tl_yylval->sym = tl_lookup(yytext);
+			return PREDICATE;
+	}	}
+
+	if (c == '}')
+	{	tl_yyerror("unexpected '}'");
+	}
 	if (islower(c))
 	{	tl_getword(c, isalnum_);
 		if (strcmp("true", yytext) == 0)
@@ -82,10 +176,34 @@
 		if (strcmp("false", yytext) == 0)
 		{	Token(FALSE);
 		}
+		if (strcmp("always", yytext) == 0)
+		{	Token(ALWAYS);
+		}
+		if (strcmp("eventually", yytext) == 0)
+		{	Token(EVENTUALLY);
+		}
+		if (strcmp("until", yytext) == 0)
+		{	Token(U_OPER);
+		}
+#ifdef NXT
+		if (strcmp("next", yytext) == 0)
+		{	Token(NEXT);
+		}
+#endif
+		if (strcmp("c_expr", yytext) == 0)
+		{	Token(CEXPR);
+		}
+		if (strcmp("not", yytext) == 0)
+		{	Token(NOT);
+		}
 		tl_yylval = tl_nn(PREDICATE,ZN,ZN);
+		if (!tl_yylval)
+		{	fatal("unexpected error 5", (char *) 0);
+		}
 		tl_yylval->sym = tl_lookup(yytext);
 		return PREDICATE;
 	}
+
 	if (c == '<')
 	{	c = tl_Getchar();
 		if (c == '>')
@@ -124,7 +242,7 @@
 Symbol *
 tl_lookup(char *s)
 {	Symbol *sp;
-	int h = hash(s);
+	unsigned int h = hash(s);
 
 	for (sp = symtab[h]; sp; sp = sp->next)
 		if (strcmp(sp->name, s) == 0)
diff -r 51b3bf8bc61b sys/src/cmd/spin/tl_main.c
--- a/sys/src/cmd/spin/tl_main.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/tl_main.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,16 +1,13 @@
 /***** 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.   */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://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"
 
@@ -21,7 +18,10 @@
 int	tl_verbose = 0;
 int	tl_terse   = 0;
 int	tl_clutter = 0;
+int	state_cnt = 0;
+
 unsigned long	All_Mem = 0;
+char	*claim_name;
 
 static char	uform[4096];
 static int	hasuform=0, cnt=0;
@@ -38,6 +38,15 @@
 	return -1;
 }
 
+int
+tl_peek(int n)
+{
+	if (cnt+n < hasuform)
+	{	return uform[cnt+n];
+	}
+	return -1;
+}
+
 void
 tl_balanced(void)
 {	int i;
@@ -45,10 +54,21 @@
 
 	for (i = 0; i < hasuform; i++)
 	{	if (uform[i] == '(')
-		{	k++;
+		{	if (i > 0
+			&& ((uform[i-1] == '"'  && uform[i+1] == '"')
+			||  (uform[i-1] == '\'' && uform[i+1] == '\'')))
+			{	continue;
+			}
+			k++;
 		} else if (uform[i] == ')')
-		{	k--;
+		{	if (i > 0
+			&& ((uform[i-1] == '"'  && uform[i+1] == '"')
+			||  (uform[i-1] == '\'' && uform[i+1] == '\'')))
+			{	continue;
+			}
+			k--;
 	}	}
+
 	if (k != 0)
 	{	tl_errs++;
 		tl_yyerror("parentheses not balanced");
@@ -79,18 +99,40 @@
 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 */
+	extern int xspin, s_trail;
+
+	tl_verbose = 0; /* was: tl_verbose = verbose; */
+	if (xspin && s_trail)
+	{	tl_clutter = 1;
+		/* generating claims for a replay should
+		   be done the same as when generating the
+		   pan.c that produced the error-trail */
+	} else
+	{	tl_clutter = 1-xspin;	/* use -X -f to turn off uncluttering */
+	}
+	newstates  = 0;
+	state_cnt  = 0;
+	tl_errs    = 0;
+	tl_terse   = 0;
+	All_Mem = 0;
+	memset(uform, 0, sizeof(uform));
+	hasuform=0;
+	cnt=0;
+	claim_name = (char *) 0;
+
+	ini_buchi();
+	ini_cache();
+	ini_rewrt();
+	ini_trans();
 
 	while (argc > 1 && argv[1][0] == '-')
-	{	switch (argv[1][1]) {
+	{
+		switch (argv[1][1]) {
 		case 'd':	newstates = 1;	/* debugging mode */
 				break;
 		case 'f':	argc--; argv++;
-				for (i = 0; i < argv[1][i]; i++)
+				for (i = 0; argv[1][i]; i++)
 				{	if (argv[1][i] == '\t'
-					||  argv[1][i] == '\"'
 					||  argv[1][i] == '\n')
 						argv[1][i] = ' ';
 				}
@@ -101,6 +143,10 @@
 				break;
 		case 'n':	tl_terse = 1;
 				break;
+		case 'c':	argc--; argv++;
+				claim_name = (char *) emalloc(strlen(argv[1])+1);
+				strcpy(claim_name, argv[1]);
+				break;
 		default :	printf("spin -f: saw '-%c'\n", argv[1][1]);
 				goto nogood;
 		}
@@ -162,6 +208,12 @@
 	case PREDICATE:
 		fprintf(tl_out, "(%s)", n->sym->name);
 		break;
+	case CEXPR:
+		fprintf(tl_out, "c_expr");
+		fprintf(tl_out, " {");
+		dump(n->lft);
+		fprintf(tl_out, "}");
+		break;
 	case -1:
 		fprintf(tl_out, " D ");
 		break;
@@ -189,6 +241,7 @@
 #ifdef NXT
 	case NEXT:	printf("X"); break;
 #endif
+	case CEXPR:	printf("c_expr"); break;
 	case TRUE:	printf("true"); break;
 	case FALSE:	printf("false"); break;
 	case ';':	printf("end of formula"); break;
@@ -202,10 +255,14 @@
 	int i;
 
 	printf("tl_spin: ");
+#if 1
+	printf(s1, s2);	/* prevent a compiler warning */
+#else
 	if (s2)
 		printf(s1, s2);
 	else
 		printf(s1);
+#endif
 	if (tl_yychar != -1 && tl_yychar != 0)
 	{	printf(", saw '");
 		tl_explain(tl_yychar);
diff -r 51b3bf8bc61b sys/src/cmd/spin/tl_mem.c
--- a/sys/src/cmd/spin/tl_mem.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/tl_mem.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,16 +1,13 @@
 /***** 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.   */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://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"
 
diff -r 51b3bf8bc61b sys/src/cmd/spin/tl_parse.c
--- a/sys/src/cmd/spin/tl_parse.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/tl_parse.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,16 +1,13 @@
 /***** 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.   */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://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"
 
@@ -44,11 +41,13 @@
 		ptr = tl_yylval;
 		tl_yychar = tl_yylex();
 		ptr->lft = tl_factor();
+		if (!ptr->lft)
+		{	fatal("malformed expression", (char *) 0);
+		}
 		ptr = push_negation(ptr);
 		break;
 	case ALWAYS:
 		tl_yychar = tl_yylex();
-
 		ptr = tl_factor();
 #ifndef NO_OPT
 		if (ptr->ntyp == FALSE
@@ -73,6 +72,14 @@
 		ptr = tl_nn(NEXT, ptr, ZN);
 		break;
 #endif
+	case CEXPR:
+		tl_yychar = tl_yylex();
+		ptr = tl_factor();
+		if (ptr->ntyp != PREDICATE)
+		{	tl_yyerror("expected {...} after c_expr");
+		}
+		ptr = tl_nn(CEXPR, ptr, ZN);
+		break;
 	case EVENTUALLY:
 		tl_yychar = tl_yylex();
 
@@ -385,7 +392,10 @@
 
 void
 tl_parse(void)
-{	Node *n = tl_formula();
+{	Node *n;
+
+	/* tl_verbose = 1; */
+	n = tl_formula();
 	if (tl_verbose)
 	{	printf("formula: ");
 		dump(n);
diff -r 51b3bf8bc61b sys/src/cmd/spin/tl_rewrt.c
--- a/sys/src/cmd/spin/tl_rewrt.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/tl_rewrt.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,16 +1,13 @@
 /***** 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.   */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://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"
 
@@ -18,6 +15,12 @@
 
 static Node	*can = ZN;
 
+void
+ini_rewrt(void)
+{
+	can = ZN;
+}
+
 Node *
 right_linked(Node *n)
 {
@@ -137,6 +140,9 @@
 	}
 
 	s = DoDump(N);
+	if (!s)
+	{	fatal("unexpected error 6", (char *) 0);
+	}
 	if (can->ntyp != tok)	/* only one element in list so far */
 	{	ptr = &can;
 		goto insert;
@@ -146,7 +152,10 @@
 	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 (t != ZS)
+			cmp = strcmp(s->name, t->name);
+		else
+			cmp = 0;
 		if (cmp == 0)	/* duplicate */
 			return;
 		if (cmp < 0)
diff -r 51b3bf8bc61b sys/src/cmd/spin/tl_trans.c
--- a/sys/src/cmd/spin/tl_trans.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/tl_trans.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,21 +1,18 @@
 /***** 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.   */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://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;
+extern int	tl_errs, tl_verbose, tl_terse, newstates, state_cnt;
 
 int	Stack_mx=0, Max_Red=0, Total=0;
 
@@ -23,7 +20,7 @@
 static Graph	*Nodes_Set = (Graph *) 0;
 static Graph	*Nodes_Stack = (Graph *) 0;
 
-static char	dumpbuf[2048];
+static char	dumpbuf[4096];
 static int	Red_cnt  = 0;
 static int	Lab_cnt  = 0;
 static int	Base     = 0;
@@ -51,6 +48,24 @@
 static void	push_stack(Graph *);
 static void	sdump(Node *);
 
+void
+ini_trans(void)
+{
+	Stack_mx = 0;
+	Max_Red = 0;
+	Total = 0;
+
+	Mapped = (Mapping *) 0;
+	Nodes_Set = (Graph *) 0;
+	Nodes_Stack = (Graph *) 0;
+
+	memset(dumpbuf, 0, sizeof(dumpbuf));
+	Red_cnt  = 0;
+	Lab_cnt  = 0;
+	Base     = 0;
+	Stack_sz = 0;
+}
+
 static void
 dump_graph(Graph *g)
 {	Node *n1;
@@ -101,9 +116,8 @@
 
 static char *
 newname(void)
-{	static int cnt = 0;
-	static char buf[32];
-	sprintf(buf, "S%d", cnt++);
+{	static char buf[32];
+	sprintf(buf, "S%d", state_cnt++);
 	return buf;
 }
 
@@ -132,6 +146,8 @@
 mk_grn(Node *n)
 {	Graph *p;
 
+	if (!n) return;
+
 	n = right_linked(n);
 more:
 	for (p = Nodes_Set; p; p = p->nxt)
@@ -152,6 +168,8 @@
 mk_red(Node *n)
 {	Graph *p;
 
+	if (!n) return;
+
 	n = right_linked(n);
 	for (p = Nodes_Set; p; p = p->nxt)
 	{	if (p->outgoing
@@ -240,6 +258,15 @@
 	q = dupnode(pp);
 	q = rewrite(q);
 
+	if (q->ntyp == CEXPR)
+	{	if (!frst) fprintf(tl_out, " && ");
+		fprintf(tl_out, "c_expr { ");
+		dump_cond(q->lft, r, 1);
+		fprintf(tl_out, " } ");
+		frst = 0;
+		return frst;
+	}
+
 	if (q->ntyp == PREDICATE
 	||  q->ntyp == NOT
 #ifndef NXT
@@ -342,7 +369,7 @@
 fsm_trans(Graph *p, int count, char *curnm)
 {	Graph	*r;
 	Symbol	*s;
-	char	prefix[128], nwnm[128];
+	char	prefix[128], nwnm[256];
 
 	if (!p->outgoing)
 		addtrans(p, curnm, False, "accept_all");
@@ -452,9 +479,11 @@
 
 	ng(tl_lookup("init"), ZS, ZN, ZN, ZN);
 	p1 = pop_stack();
-	p1->nxt = Nodes_Set;
-	p1->Other = p1->Old = orig;
-	Nodes_Set = p1;
+	if (p1)
+	{	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)
@@ -532,6 +561,10 @@
 	case NEXT:	strcat(dumpbuf, "X");
 			goto common1;
 #endif
+	case CEXPR:	strcat(dumpbuf, "c_expr {");
+			sdump(n->lft);
+			strcat(dumpbuf, "}");
+			break;
 	case NOT:	strcat(dumpbuf, "!");
 			goto common1;
 	case TRUE:	strcat(dumpbuf, "T");
@@ -718,10 +751,13 @@
 		break;
 	case PREDICATE:
 	case NOT:
+	case CEXPR:
 		if (can_release) releasenode(1, now);
 		push_stack(g);
 		break;
 	case V_OPER:
+		Assert(now->rgt != ZN, now->ntyp);
+		Assert(now->lft != ZN, now->ntyp);
 		Assert(now->rgt->nxt == ZN, now->ntyp);
 		Assert(now->lft->nxt == ZN, now->ntyp);
 		n1 = now->rgt;
@@ -759,6 +795,7 @@
 
 #ifdef NXT
 	case NEXT:
+		Assert(now->lft != ZN, now->ntyp);
 		nx = dupnode(now->lft);
 		nx->nxt = g->Next;
 		g->Next = nx;
diff -r 51b3bf8bc61b sys/src/cmd/spin/vars.c
--- a/sys/src/cmd/spin/vars.c	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/vars.c	Wed Nov 22 00:21:47 2017 -0800
@@ -1,13 +1,10 @@
 /***** 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            */
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
 
 #include "spin.h"
 #include "y.tab.h"
@@ -17,7 +14,7 @@
 extern Symbol	*Fname;
 extern char	Buf[];
 extern int	lineno, depth, verbose, xspin, limited_vis;
-extern int	analyze, jumpsteps, nproc, nstop, columns;
+extern int	analyze, jumpsteps, nproc, nstop, columns, old_priority_rules;
 extern short	no_arrays, Have_claim;
 extern void	sr_mesg(FILE *, int, int);
 extern void	sr_buf(int, int);
@@ -42,22 +39,54 @@
 	{	if (!X) return 0;
 		return X->pid - Have_claim;
 	}
+	if (strcmp(s->name, "_priority") == 0)
+	{	if (!X) return 0;
+
+		if (old_priority_rules)
+		{	non_fatal("cannot refer to _priority with -o6", (char *) 0);
+			return 1;
+		}
+		return X->priority;
+	}
+
 	if (strcmp(s->name, "_nr_pr") == 0)
-		return nproc-nstop;	/* new 3.3.10 */
+	{	return nproc-nstop;	/* new 3.3.10 */
+	}
 
 	if (s->context && s->type)
-		return getlocal(sn);
+	{	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 (strcmp(v->sym->name, "_last") == 0
+	||  strcmp(v->sym->name, "_p") == 0
+	||  strcmp(v->sym->name, "_pid") == 0
+	||  strcmp(v->sym->name, "_nr_qs") == 0
+	||  strcmp(v->sym->name, "_nr_pr") == 0)
+	{	non_fatal("illegal assignment to %s", v->sym->name);
+	}
+	if (strcmp(v->sym->name, "_priority") == 0)
+	{	if (old_priority_rules)
+		{	non_fatal("cannot refer to _priority with -o6", (char *) 0);
+			return 1;
+		}
+		if (!X)
+		{	non_fatal("no context for _priority", (char *) 0);
+			return 1;
+		}
+		X->priority = n;
+	}
+
 	if (v->sym->context && v->sym->type)
 		return setlocal(v, n);
 	if (!v->sym->type)
@@ -90,6 +119,7 @@
 checkvar(Symbol *s, int n)
 {	int	i, oln = lineno;	/* calls on eval() change it */
 	Symbol	*ofnm = Fname;
+	Lextok  *z, *y;
 
 	if (!in_bound(s, n))
 		return 0;
@@ -101,15 +131,23 @@
 	/* not a STRUCT */
 	if (s->val == (int *) 0)	/* uninitialized */
 	{	s->val = (int *) emalloc(s->nel*sizeof(int));
+		z = s->ini;
 		for (i = 0; i < s->nel; i++)
-		{	if (s->type != CHAN)
-			{	rm_selfrefs(s, s->ini);
-				s->val[i] = eval(s->ini);
+		{	if (z && z->ntyp == ',')
+			{	y = z->lft;
+				z = z->rgt;
+			} else
+			{	y = z;
+			}
+			if (s->type != CHAN)
+			{	rm_selfrefs(s, y);
+				s->val[i] = eval(y);
 			} else if (!analyze)
-				s->val[i] = qmake(s);
-	}	}
+			{	s->val[i] = qmake(s);
+	}	}	}
 	lineno = oln;
 	Fname  = ofnm;
+
 	return 1;
 }
 
@@ -118,14 +156,16 @@
 {	Symbol *s = sn->sym;
 	int i, n = eval(sn->lft);
 
-	if (s->type == 0 && X && (i = find_lab(s, X->n, 0)))
+	if (s->type == 0 && X && (i = find_lab(s, X->n, 0)))	/* getglobal */
 	{	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 */
+	{	return Rval_struct(sn, s, 1); /* 1 = check init */
+	}
 	if (checkvar(s, n))
-		return cast_val(s->type, s->val[n], s->nbits);
+	{	return cast_val(s->type, s->val[n], s->nbits);
+	}
 	return 0;
 }
 
@@ -145,23 +185,26 @@
 	}
 
 	if (v != i+s+ (int) u)
-	{	char buf[32]; sprintf(buf, "%d->%d (%d)", v, i+s+u, t);
+	{	char buf[64]; sprintf(buf, "%d->%d (%d)", v, i+s+(int)u, t);
 		non_fatal("value (%s) truncated in assignment", buf);
 	}
-	return (int)(i+s+u);
+	return (int)(i+s+(int)u);
 }
 
 static int
 setglobal(Lextok *v, int m)
 {
 	if (v->sym->type == STRUCT)
-		(void) Lval_struct(v, v->sym, 1, m);
-	else
+	{	(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;
-	}	}
+		{	int oval = v->sym->val[n];
+			int nval = cast_val(v->sym->type, m, v->sym->nbits);
+			v->sym->val[n] = nval;
+			if (oval != nval)
+			{	v->sym->setat = depth;
+	}	}	}
 	return 1;
 }
 
@@ -215,7 +258,12 @@
 			continue;
 
 		if (sp->type == STRUCT)
-		{	dump_struct(sp, sp->name, 0);
+		{	if ((verbose&4) && !(verbose&64)
+			&&  (sp->setat < depth
+			&&   jumpsteps != depth))
+			{	continue;
+			}
+			dump_struct(sp, sp->name, 0);
 			continue;
 		}
 		for (j = 0; j < sp->nel; j++)
@@ -227,13 +275,15 @@
 			if ((verbose&4) && !(verbose&64)
 			&&  (sp->setat < depth
 			&&   jumpsteps != depth))
-				continue;
+			{	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);
+			if (sp->nel > 1 || sp->isarray) printf("[%d]", j);
 			printf(" = ");
 			sr_mesg(stdout, prefetch,
 				sp->type == MTYPE);
@@ -249,7 +299,7 @@
 				}
 				sr_buf(prefetch, sp->type == MTYPE);
 				if (sp->colnr == 0)
-				{	sp->colnr = maxcolnr;
+				{	sp->colnr = (unsigned char) maxcolnr;
 					maxcolnr = 1+(maxcolnr%10);
 				}
 				colpos = nproc+sp->colnr-1;
@@ -266,7 +316,7 @@
 					depth, colpos);
 				printf("(state 0)\t[printf('MSC: globvar\\\\n')]\n");
 				printf("\t\t%s", sp->name);
-				if (sp->nel > 1) printf("[%d]", j);
+				if (sp->nel > 1 || sp->isarray) printf("[%d]", j);
 				printf(" = %s\n", Buf);
 	}	}	}
 }
@@ -303,8 +353,8 @@
 			dummy->lft->val = i;
 
 			printf("\t\t%s(%d):%s",
-				r->n->name, r->pid, z->name);
-			if (z->nel > 1) printf("[%d]", i);
+				r->n->name, r->pid - Have_claim, z->name);
+			if (z->nel > 1 || z->isarray) printf("[%d]", i);
 			printf(" = ");
 			sr_mesg(stdout, getval(dummy), z->type == MTYPE);
 			printf("\n");
@@ -321,7 +371,7 @@
 				}
 				sr_buf(getval(dummy), z->type==MTYPE);
 				if (z->colnr == 0)
-				{	z->colnr = maxcolnr;
+				{	z->colnr = (unsigned char) maxcolnr;
 					maxcol100  892k  100  892k    0     0   892k      0  0:00:01  0:00:01 --:--:--  659k
nr = 1+(maxcolnr%10);
 				}
 				colpos = nproc+z->colnr-1;
@@ -341,7 +391,7 @@
 				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);
+				if (z->nel > 1 || z->isarray) printf("[%d]", i);
 				printf(" = %s\n", Buf);
 	}	}	}
 }
diff -r 51b3bf8bc61b sys/src/cmd/spin/version.h
--- a/sys/src/cmd/spin/version.h	Mon Nov 20 00:10:35 2017 +0100
+++ b/sys/src/cmd/spin/version.h	Wed Nov 22 00:21:47 2017 -0800
@@ -1,1 +1,9 @@
-#define Version	"Spin Version 4.3.0 -- 22 June 2007"
+/***** spin: version.h *****/
+
+/*
+ * This file is part of the public release of Spin. It is subject to the
+ * terms in the LICENSE file that is included in this source directory.
+ * Tool documentation is available at http://spinroot.com
+ */
+
+#define SpinVersion	"Spin Version 6.4.7 -- 19 August 2017"

-- 
    Ori Bernstein


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2017-11-22  8:23 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-22  8:23 [Patch] Update Spin to most recent version Ori Bernstein

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).