xref: /plan9/sys/src/cmd/spin/run.c (revision 00d970127b9d44d2b22f4f656717a212dec1f1d2)
1219b2ee8SDavid du Colombier /***** spin: run.c *****/
2219b2ee8SDavid du Colombier 
3312a1df1SDavid du Colombier /* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
47dd7cddfSDavid du Colombier /* All Rights Reserved.  This software is for educational purposes only.  */
5312a1df1SDavid du Colombier /* No guarantee whatsoever is expressed or implied by the distribution of */
6312a1df1SDavid du Colombier /* this code.  Permission is given to distribute this code provided that  */
7312a1df1SDavid du Colombier /* this introductory message is not removed and no monies are exchanged.  */
8312a1df1SDavid du Colombier /* Software written by Gerard J. Holzmann.  For tool documentation see:   */
9312a1df1SDavid du Colombier /*             http://spinroot.com/                                       */
10312a1df1SDavid du Colombier /* Send all bug-reports and/or questions to: bugs@spinroot.com            */
11219b2ee8SDavid du Colombier 
127dd7cddfSDavid du Colombier #include <stdlib.h>
13219b2ee8SDavid du Colombier #include "spin.h"
14219b2ee8SDavid du Colombier #include "y.tab.h"
15219b2ee8SDavid du Colombier 
167dd7cddfSDavid du Colombier extern RunList	*X, *run;
17219b2ee8SDavid du Colombier extern Symbol	*Fname;
18219b2ee8SDavid du Colombier extern Element	*LastStep;
197dd7cddfSDavid du Colombier extern int	Rvous, lineno, Tval, interactive, MadeChoice;
207dd7cddfSDavid du Colombier extern int	TstOnly, verbose, s_trail, xspin, jumpsteps, depth;
21*00d97012SDavid du Colombier extern int	analyze, nproc, nstop, no_print, like_java;
22219b2ee8SDavid du Colombier 
23219b2ee8SDavid du Colombier static long	Seed = 1;
247dd7cddfSDavid du Colombier static int	E_Check = 0, Escape_Check = 0;
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier static int	eval_sync(Element *);
277dd7cddfSDavid du Colombier static int	pc_enabled(Lextok *n);
287dd7cddfSDavid du Colombier extern void	sr_buf(int, int);
29219b2ee8SDavid du Colombier 
30219b2ee8SDavid du Colombier void
Srand(unsigned int s)31219b2ee8SDavid du Colombier Srand(unsigned int s)
32219b2ee8SDavid du Colombier {	Seed = s;
33219b2ee8SDavid du Colombier }
34219b2ee8SDavid du Colombier 
35219b2ee8SDavid du Colombier long
Rand(void)36219b2ee8SDavid du Colombier Rand(void)
37219b2ee8SDavid du Colombier {	/* CACM 31(10), Oct 1988 */
38219b2ee8SDavid du Colombier 	Seed = 16807*(Seed%127773) - 2836*(Seed/127773);
39219b2ee8SDavid du Colombier 	if (Seed <= 0) Seed += 2147483647;
40219b2ee8SDavid du Colombier 	return Seed;
41219b2ee8SDavid du Colombier }
42219b2ee8SDavid du Colombier 
43219b2ee8SDavid du Colombier Element *
rev_escape(SeqList * e)447dd7cddfSDavid du Colombier rev_escape(SeqList *e)
457dd7cddfSDavid du Colombier {	Element *r;
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier 	if (!e)
487dd7cddfSDavid du Colombier 		return (Element *) 0;
497dd7cddfSDavid du Colombier 
50312a1df1SDavid du Colombier 	if ((r = rev_escape(e->nxt)) != ZE) /* reversed order */
517dd7cddfSDavid du Colombier 		return r;
527dd7cddfSDavid du Colombier 
537dd7cddfSDavid du Colombier 	return eval_sub(e->this->frst);
547dd7cddfSDavid du Colombier }
557dd7cddfSDavid du Colombier 
567dd7cddfSDavid du Colombier Element *
eval_sub(Element * e)57219b2ee8SDavid du Colombier eval_sub(Element *e)
58219b2ee8SDavid du Colombier {	Element *f, *g;
59219b2ee8SDavid du Colombier 	SeqList *z;
60*00d97012SDavid du Colombier 	int i, j, k, only_pos;
61219b2ee8SDavid du Colombier 
62*00d97012SDavid du Colombier 	if (!e || !e->n)
63219b2ee8SDavid du Colombier 		return ZE;
64219b2ee8SDavid du Colombier #ifdef DEBUG
657dd7cddfSDavid du Colombier 	printf("\n\teval_sub(%d %s: line %d) ",
667dd7cddfSDavid du Colombier 		e->Seqno, e->esc?"+esc":"", e->n?e->n->ln:0);
67219b2ee8SDavid du Colombier 	comment(stdout, e->n, 0);
68219b2ee8SDavid du Colombier 	printf("\n");
69219b2ee8SDavid du Colombier #endif
70219b2ee8SDavid du Colombier 	if (e->n->ntyp == GOTO)
71219b2ee8SDavid du Colombier 	{	if (Rvous) return ZE;
72*00d97012SDavid du Colombier 		LastStep = e;
73*00d97012SDavid du Colombier 		f = get_lab(e->n, 1);
74*00d97012SDavid du Colombier 		f = huntele(f, e->status, -1); /* 5.2.3: was missing */
75219b2ee8SDavid du Colombier 		cross_dsteps(e->n, f->n);
76*00d97012SDavid du Colombier #ifdef DEBUG
77*00d97012SDavid du Colombier 		printf("GOTO leads to %d\n", f->seqno);
78*00d97012SDavid du Colombier #endif
79219b2ee8SDavid du Colombier 		return f;
80219b2ee8SDavid du Colombier 	}
81219b2ee8SDavid du Colombier 	if (e->n->ntyp == UNLESS)
82219b2ee8SDavid du Colombier 	{	/* escapes were distributed into sequence */
83219b2ee8SDavid du Colombier 		return eval_sub(e->sub->this->frst);
84219b2ee8SDavid du Colombier 	} else if (e->sub)	/* true for IF, DO, and UNLESS */
85219b2ee8SDavid du Colombier 	{	Element *has_else = ZE;
867dd7cddfSDavid du Colombier 		Element *bas_else = ZE;
87312a1df1SDavid du Colombier 		int nr_else = 0, nr_choices = 0;
88*00d97012SDavid du Colombier 		only_pos = -1;
89219b2ee8SDavid du Colombier 
907dd7cddfSDavid du Colombier 		if (interactive
917dd7cddfSDavid du Colombier 		&& !MadeChoice && !E_Check
927dd7cddfSDavid du Colombier 		&& !Escape_Check
937dd7cddfSDavid du Colombier 		&& !(e->status&(D_ATOM))
947dd7cddfSDavid du Colombier 		&& depth >= jumpsteps)
95219b2ee8SDavid du Colombier 		{	printf("Select stmnt (");
96219b2ee8SDavid du Colombier 			whoruns(0); printf(")\n");
977dd7cddfSDavid du Colombier 			if (nproc-nstop > 1)
98*00d97012SDavid du Colombier 			{	printf("\tchoice 0: other process\n");
99*00d97012SDavid du Colombier 				nr_choices++;
100*00d97012SDavid du Colombier 				only_pos = 0;
101*00d97012SDavid du Colombier 		}	}
102219b2ee8SDavid du Colombier 		for (z = e->sub, j=0; z; z = z->nxt)
103219b2ee8SDavid du Colombier 		{	j++;
1047dd7cddfSDavid du Colombier 			if (interactive
1057dd7cddfSDavid du Colombier 			&& !MadeChoice && !E_Check
1067dd7cddfSDavid du Colombier 			&& !Escape_Check
1077dd7cddfSDavid du Colombier 			&& !(e->status&(D_ATOM))
1087dd7cddfSDavid du Colombier 			&& depth >= jumpsteps
109219b2ee8SDavid du Colombier 			&& z->this->frst
1107dd7cddfSDavid du Colombier 			&& (xspin || (verbose&32) || Enabled0(z->this->frst)))
1117dd7cddfSDavid du Colombier 			{	if (z->this->frst->n->ntyp == ELSE)
1127dd7cddfSDavid du Colombier 				{	has_else = (Rvous)?ZE:z->this->frst->nxt;
1137dd7cddfSDavid du Colombier 					nr_else = j;
1147dd7cddfSDavid du Colombier 					continue;
1157dd7cddfSDavid du Colombier 				}
1167dd7cddfSDavid du Colombier 				printf("\tchoice %d: ", j);
1177dd7cddfSDavid du Colombier #if 0
1187dd7cddfSDavid du Colombier 				if (z->this->frst->n)
1197dd7cddfSDavid du Colombier 					printf("line %d, ", z->this->frst->n->ln);
1207dd7cddfSDavid du Colombier #endif
121219b2ee8SDavid du Colombier 				if (!Enabled0(z->this->frst))
122219b2ee8SDavid du Colombier 					printf("unexecutable, ");
1237dd7cddfSDavid du Colombier 				else
124*00d97012SDavid du Colombier 				{	nr_choices++;
125*00d97012SDavid du Colombier 					only_pos = j;
126*00d97012SDavid du Colombier 				}
127219b2ee8SDavid du Colombier 				comment(stdout, z->this->frst->n, 0);
128219b2ee8SDavid du Colombier 				printf("\n");
129219b2ee8SDavid du Colombier 		}	}
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier 		if (nr_choices == 0 && has_else)
132*00d97012SDavid du Colombier 		{	printf("\tchoice %d: (else)\n", nr_else);
133*00d97012SDavid du Colombier 			only_pos = nr_else;
134*00d97012SDavid du Colombier 		}
135*00d97012SDavid du Colombier 
136*00d97012SDavid du Colombier 		if (nr_choices <= 1 && only_pos != -1 && !MadeChoice)
137*00d97012SDavid du Colombier 		{	MadeChoice = only_pos;
138*00d97012SDavid du Colombier 		}
1397dd7cddfSDavid du Colombier 
1407dd7cddfSDavid du Colombier 		if (interactive && depth >= jumpsteps
1417dd7cddfSDavid du Colombier 		&& !Escape_Check
1427dd7cddfSDavid du Colombier 		&& !(e->status&(D_ATOM))
1437dd7cddfSDavid du Colombier 		&& !E_Check)
1447dd7cddfSDavid du Colombier 		{	if (!MadeChoice)
1457dd7cddfSDavid du Colombier 			{	char buf[256];
1467dd7cddfSDavid du Colombier 				if (xspin)
147219b2ee8SDavid du Colombier 					printf("Make Selection %d\n\n", j);
148219b2ee8SDavid du Colombier 				else
149219b2ee8SDavid du Colombier 					printf("Select [0-%d]: ", j);
150219b2ee8SDavid du Colombier 				fflush(stdout);
151*00d97012SDavid du Colombier 				if (scanf("%64s", buf) <= 0)
152*00d97012SDavid du Colombier 				{	printf("no input\n");
153*00d97012SDavid du Colombier 					return ZE;
154*00d97012SDavid du Colombier 				}
155*00d97012SDavid du Colombier 				if (isdigit((int)buf[0]))
1567dd7cddfSDavid du Colombier 					k = atoi(buf);
1577dd7cddfSDavid du Colombier 				else
1587dd7cddfSDavid du Colombier 				{	if (buf[0] == 'q')
1597dd7cddfSDavid du Colombier 						alldone(0);
1607dd7cddfSDavid du Colombier 					k = -1;
1617dd7cddfSDavid du Colombier 				}
162219b2ee8SDavid du Colombier 			} else
1637dd7cddfSDavid du Colombier 			{	k = MadeChoice;
1647dd7cddfSDavid du Colombier 				MadeChoice = 0;
165219b2ee8SDavid du Colombier 			}
166219b2ee8SDavid du Colombier 			if (k < 1 || k > j)
1677dd7cddfSDavid du Colombier 			{	if (k != 0) printf("\tchoice outside range\n");
168219b2ee8SDavid du Colombier 				return ZE;
169219b2ee8SDavid du Colombier 			}
170219b2ee8SDavid du Colombier 			k--;
171219b2ee8SDavid du Colombier 		} else
1727dd7cddfSDavid du Colombier 		{	if (e->n && e->n->indstep >= 0)
1737dd7cddfSDavid du Colombier 				k = 0;	/* select 1st executable guard */
1747dd7cddfSDavid du Colombier 			else
175219b2ee8SDavid du Colombier 				k = Rand()%j;	/* nondeterminism */
1767dd7cddfSDavid du Colombier 		}
177*00d97012SDavid du Colombier 
1787dd7cddfSDavid du Colombier 		has_else = ZE;
1797dd7cddfSDavid du Colombier 		bas_else = ZE;
180219b2ee8SDavid du Colombier 		for (i = 0, z = e->sub; i < j+k; i++)
181219b2ee8SDavid du Colombier 		{	if (z->this->frst
182219b2ee8SDavid du Colombier 			&&  z->this->frst->n->ntyp == ELSE)
1837dd7cddfSDavid du Colombier 			{	bas_else = z->this->frst;
1847dd7cddfSDavid du Colombier 				has_else = (Rvous)?ZE:bas_else->nxt;
1857dd7cddfSDavid du Colombier 				if (!interactive || depth < jumpsteps
1867dd7cddfSDavid du Colombier 				|| Escape_Check
1877dd7cddfSDavid du Colombier 				|| (e->status&(D_ATOM)))
188219b2ee8SDavid du Colombier 				{	z = (z->nxt)?z->nxt:e->sub;
189219b2ee8SDavid du Colombier 					continue;
1907dd7cddfSDavid du Colombier 				}
1917dd7cddfSDavid du Colombier 			}
192312a1df1SDavid du Colombier 			if (z->this->frst
193312a1df1SDavid du Colombier 			&&  ((z->this->frst->n->ntyp == ATOMIC
194312a1df1SDavid du Colombier 			  ||  z->this->frst->n->ntyp == D_STEP)
195312a1df1SDavid du Colombier 			  &&  z->this->frst->n->sl->this->frst->n->ntyp == ELSE))
196312a1df1SDavid du Colombier 			{	bas_else = z->this->frst->n->sl->this->frst;
197312a1df1SDavid du Colombier 				has_else = (Rvous)?ZE:bas_else->nxt;
198312a1df1SDavid du Colombier 				if (!interactive || depth < jumpsteps
199312a1df1SDavid du Colombier 				|| Escape_Check
200312a1df1SDavid du Colombier 				|| (e->status&(D_ATOM)))
201312a1df1SDavid du Colombier 				{	z = (z->nxt)?z->nxt:e->sub;
202312a1df1SDavid du Colombier 					continue;
203312a1df1SDavid du Colombier 				}
204312a1df1SDavid du Colombier 			}
205219b2ee8SDavid du Colombier 			if (i >= k)
206312a1df1SDavid du Colombier 			{	if ((f = eval_sub(z->this->frst)) != ZE)
207219b2ee8SDavid du Colombier 					return f;
2087dd7cddfSDavid du Colombier 				else if (interactive && depth >= jumpsteps
2097dd7cddfSDavid du Colombier 				&& !(e->status&(D_ATOM)))
2107dd7cddfSDavid du Colombier 				{	if (!E_Check && !Escape_Check)
2117dd7cddfSDavid du Colombier 						printf("\tunexecutable\n");
212219b2ee8SDavid du Colombier 					return ZE;
213219b2ee8SDavid du Colombier 			}	}
214219b2ee8SDavid du Colombier 			z = (z->nxt)?z->nxt:e->sub;
215219b2ee8SDavid du Colombier 		}
2167dd7cddfSDavid du Colombier 		LastStep = bas_else;
217219b2ee8SDavid du Colombier 		return has_else;
218219b2ee8SDavid du Colombier 	} else
219219b2ee8SDavid du Colombier 	{	if (e->n->ntyp == ATOMIC
220219b2ee8SDavid du Colombier 		||  e->n->ntyp == D_STEP)
221219b2ee8SDavid du Colombier 		{	f = e->n->sl->this->frst;
222219b2ee8SDavid du Colombier 			g = e->n->sl->this->last;
223219b2ee8SDavid du Colombier 			g->nxt = e->nxt;
224219b2ee8SDavid du Colombier 			if (!(g = eval_sub(f)))	/* atomic guard */
225219b2ee8SDavid du Colombier 				return ZE;
226219b2ee8SDavid du Colombier 			return g;
227219b2ee8SDavid du Colombier 		} else if (e->n->ntyp == NON_ATOMIC)
228219b2ee8SDavid du Colombier 		{	f = e->n->sl->this->frst;
229219b2ee8SDavid du Colombier 			g = e->n->sl->this->last;
230219b2ee8SDavid du Colombier 			g->nxt = e->nxt;		/* close it */
231219b2ee8SDavid du Colombier 			return eval_sub(f);
232219b2ee8SDavid du Colombier 		} else if (e->n->ntyp == '.')
2337dd7cddfSDavid du Colombier 		{	if (!Rvous) return e->nxt;
2347dd7cddfSDavid du Colombier 			return eval_sub(e->nxt);
235219b2ee8SDavid du Colombier 		} else
236219b2ee8SDavid du Colombier 		{	SeqList *x;
2377dd7cddfSDavid du Colombier 			if (!(e->status & (D_ATOM))
2387dd7cddfSDavid du Colombier 			&&  e->esc && verbose&32)
2397dd7cddfSDavid du Colombier 			{	printf("Stmnt [");
240219b2ee8SDavid du Colombier 				comment(stdout, e->n, 0);
2417dd7cddfSDavid du Colombier 				printf("] has escape(s): ");
242219b2ee8SDavid du Colombier 				for (x = e->esc; x; x = x->nxt)
2437dd7cddfSDavid du Colombier 				{	printf("[");
2447dd7cddfSDavid du Colombier 					g = x->this->frst;
2457dd7cddfSDavid du Colombier 					if (g->n->ntyp == ATOMIC
2467dd7cddfSDavid du Colombier 					||  g->n->ntyp == NON_ATOMIC)
2477dd7cddfSDavid du Colombier 						g = g->n->sl->this->frst;
2487dd7cddfSDavid du Colombier 					comment(stdout, g->n, 0);
2497dd7cddfSDavid du Colombier 					printf("] ");
2507dd7cddfSDavid du Colombier 				}
2517dd7cddfSDavid du Colombier 				printf("\n");
2527dd7cddfSDavid du Colombier 			}
253312a1df1SDavid du Colombier #if 0
2547dd7cddfSDavid du Colombier 			if (!(e->status & D_ATOM))	/* escapes don't reach inside d_steps */
255312a1df1SDavid du Colombier 			/* 4.2.4: only the guard of a d_step can have an escape */
256312a1df1SDavid du Colombier #endif
257*00d97012SDavid du Colombier #if 1
258*00d97012SDavid du Colombier 			if (!s_trail)	/* trail determines selections, new 5.2.5 */
259*00d97012SDavid du Colombier #endif
2607dd7cddfSDavid du Colombier 			{	Escape_Check++;
2617dd7cddfSDavid du Colombier 				if (like_java)
262312a1df1SDavid du Colombier 				{	if ((g = rev_escape(e->esc)) != ZE)
2637dd7cddfSDavid du Colombier 					{	if (verbose&4)
2647dd7cddfSDavid du Colombier 							printf("\tEscape taken\n");
2657dd7cddfSDavid du Colombier 						Escape_Check--;
2667dd7cddfSDavid du Colombier 						return g;
2677dd7cddfSDavid du Colombier 					}
2687dd7cddfSDavid du Colombier 				} else
2697dd7cddfSDavid du Colombier 				{	for (x = e->esc; x; x = x->nxt)
270312a1df1SDavid du Colombier 					{	if ((g = eval_sub(x->this->frst)) != ZE)
271219b2ee8SDavid du Colombier 						{	if (verbose&4)
272*00d97012SDavid du Colombier 							{	printf("\tEscape taken ");
273*00d97012SDavid du Colombier 								if (g->n && g->n->fn)
274*00d97012SDavid du Colombier 									printf("%s:%d", g->n->fn->name, g->n->ln);
275*00d97012SDavid du Colombier 								printf("\n");
276*00d97012SDavid du Colombier 							}
2777dd7cddfSDavid du Colombier 							Escape_Check--;
278219b2ee8SDavid du Colombier 							return g;
2797dd7cddfSDavid du Colombier 				}	}	}
2807dd7cddfSDavid du Colombier 				Escape_Check--;
2817dd7cddfSDavid du Colombier 			}
2827dd7cddfSDavid du Colombier 
283219b2ee8SDavid du Colombier 			switch (e->n->ntyp) {
284219b2ee8SDavid du Colombier 			case TIMEOUT: case RUN:
285312a1df1SDavid du Colombier 			case PRINT: case PRINTM:
286312a1df1SDavid du Colombier 			case C_CODE: case C_EXPR:
2877dd7cddfSDavid du Colombier 			case ASGN: case ASSERT:
288219b2ee8SDavid du Colombier 			case 's': case 'r': case 'c':
289219b2ee8SDavid du Colombier 				/* toplevel statements only */
290219b2ee8SDavid du Colombier 				LastStep = e;
291219b2ee8SDavid du Colombier 			default:
292219b2ee8SDavid du Colombier 				break;
293219b2ee8SDavid du Colombier 			}
2947dd7cddfSDavid du Colombier 			if (Rvous)
2957dd7cddfSDavid du Colombier 			{
2967dd7cddfSDavid du Colombier 				return (eval_sync(e))?e->nxt:ZE;
2977dd7cddfSDavid du Colombier 			}
298219b2ee8SDavid du Colombier 			return (eval(e->n))?e->nxt:ZE;
299219b2ee8SDavid du Colombier 		}
300219b2ee8SDavid du Colombier 	}
3017dd7cddfSDavid du Colombier 	return ZE; /* not reached */
302219b2ee8SDavid du Colombier }
303219b2ee8SDavid du Colombier 
3047dd7cddfSDavid du Colombier static int
eval_sync(Element * e)305219b2ee8SDavid du Colombier eval_sync(Element *e)
306219b2ee8SDavid du Colombier {	/* allow only synchronous receives
3077dd7cddfSDavid du Colombier 	   and related node types    */
308219b2ee8SDavid du Colombier 	Lextok *now = (e)?e->n:ZN;
309219b2ee8SDavid du Colombier 
310219b2ee8SDavid du Colombier 	if (!now
311219b2ee8SDavid du Colombier 	||  now->ntyp != 'r'
3127dd7cddfSDavid du Colombier 	||  now->val >= 2	/* no rv with a poll */
313219b2ee8SDavid du Colombier 	||  !q_is_sync(now))
3147dd7cddfSDavid du Colombier 	{
315219b2ee8SDavid du Colombier 		return 0;
3167dd7cddfSDavid du Colombier 	}
317219b2ee8SDavid du Colombier 
318219b2ee8SDavid du Colombier 	LastStep = e;
319219b2ee8SDavid du Colombier 	return eval(now);
320219b2ee8SDavid du Colombier }
321219b2ee8SDavid du Colombier 
3227dd7cddfSDavid du Colombier static int
assign(Lextok * now)323219b2ee8SDavid du Colombier assign(Lextok *now)
324219b2ee8SDavid du Colombier {	int t;
325219b2ee8SDavid du Colombier 
326219b2ee8SDavid du Colombier 	if (TstOnly) return 1;
327219b2ee8SDavid du Colombier 
328219b2ee8SDavid du Colombier 	switch (now->rgt->ntyp) {
329219b2ee8SDavid du Colombier 	case FULL:	case NFULL:
330219b2ee8SDavid du Colombier 	case EMPTY:	case NEMPTY:
331219b2ee8SDavid du Colombier 	case RUN:	case LEN:
332219b2ee8SDavid du Colombier 		t = BYTE;
333219b2ee8SDavid du Colombier 		break;
334219b2ee8SDavid du Colombier 	default:
335219b2ee8SDavid du Colombier 		t = Sym_typ(now->rgt);
336219b2ee8SDavid du Colombier 		break;
337219b2ee8SDavid du Colombier 	}
338219b2ee8SDavid du Colombier 	typ_ck(Sym_typ(now->lft), t, "assignment");
339219b2ee8SDavid du Colombier 	return setval(now->lft, eval(now->rgt));
340219b2ee8SDavid du Colombier }
341219b2ee8SDavid du Colombier 
3427dd7cddfSDavid du Colombier static int
nonprogress(void)3437dd7cddfSDavid du Colombier nonprogress(void)	/* np_ */
3447dd7cddfSDavid du Colombier {	RunList	*r;
3457dd7cddfSDavid du Colombier 
3467dd7cddfSDavid du Colombier 	for (r = run; r; r = r->nxt)
3477dd7cddfSDavid du Colombier 	{	if (has_lab(r->pc, 4))	/* 4=progress */
3487dd7cddfSDavid du Colombier 			return 0;
3497dd7cddfSDavid du Colombier 	}
3507dd7cddfSDavid du Colombier 	return 1;
3517dd7cddfSDavid du Colombier }
3527dd7cddfSDavid du Colombier 
353219b2ee8SDavid du Colombier int
eval(Lextok * now)354219b2ee8SDavid du Colombier eval(Lextok *now)
355219b2ee8SDavid du Colombier {
356219b2ee8SDavid du Colombier 	if (now) {
357219b2ee8SDavid du Colombier 	lineno = now->ln;
358219b2ee8SDavid du Colombier 	Fname  = now->fn;
359219b2ee8SDavid du Colombier #ifdef DEBUG
360219b2ee8SDavid du Colombier 	printf("eval ");
361219b2ee8SDavid du Colombier 	comment(stdout, now, 0);
362219b2ee8SDavid du Colombier 	printf("\n");
363219b2ee8SDavid du Colombier #endif
364219b2ee8SDavid du Colombier 	switch (now->ntyp) {
365219b2ee8SDavid du Colombier 	case CONST: return now->val;
366219b2ee8SDavid du Colombier 	case   '!': return !eval(now->lft);
367219b2ee8SDavid du Colombier 	case  UMIN: return -eval(now->lft);
368219b2ee8SDavid du Colombier 	case   '~': return ~eval(now->lft);
369219b2ee8SDavid du Colombier 
370219b2ee8SDavid du Colombier 	case   '/': return (eval(now->lft) / eval(now->rgt));
371219b2ee8SDavid du Colombier 	case   '*': return (eval(now->lft) * eval(now->rgt));
372219b2ee8SDavid du Colombier 	case   '-': return (eval(now->lft) - eval(now->rgt));
373219b2ee8SDavid du Colombier 	case   '+': return (eval(now->lft) + eval(now->rgt));
374219b2ee8SDavid du Colombier 	case   '%': return (eval(now->lft) % eval(now->rgt));
375219b2ee8SDavid du Colombier 	case    LT: return (eval(now->lft) <  eval(now->rgt));
376219b2ee8SDavid du Colombier 	case    GT: return (eval(now->lft) >  eval(now->rgt));
377219b2ee8SDavid du Colombier 	case   '&': return (eval(now->lft) &  eval(now->rgt));
3787dd7cddfSDavid du Colombier 	case   '^': return (eval(now->lft) ^  eval(now->rgt));
379219b2ee8SDavid du Colombier 	case   '|': return (eval(now->lft) |  eval(now->rgt));
380219b2ee8SDavid du Colombier 	case    LE: return (eval(now->lft) <= eval(now->rgt));
381219b2ee8SDavid du Colombier 	case    GE: return (eval(now->lft) >= eval(now->rgt));
382219b2ee8SDavid du Colombier 	case    NE: return (eval(now->lft) != eval(now->rgt));
383219b2ee8SDavid du Colombier 	case    EQ: return (eval(now->lft) == eval(now->rgt));
384219b2ee8SDavid du Colombier 	case    OR: return (eval(now->lft) || eval(now->rgt));
385219b2ee8SDavid du Colombier 	case   AND: return (eval(now->lft) && eval(now->rgt));
386219b2ee8SDavid du Colombier 	case LSHIFT: return (eval(now->lft) << eval(now->rgt));
387219b2ee8SDavid du Colombier 	case RSHIFT: return (eval(now->lft) >> eval(now->rgt));
388219b2ee8SDavid du Colombier 	case   '?': return (eval(now->lft) ? eval(now->rgt->lft)
389219b2ee8SDavid du Colombier 					   : eval(now->rgt->rgt));
390219b2ee8SDavid du Colombier 
391312a1df1SDavid du Colombier 	case     'p': return remotevar(now);	/* _p for remote reference */
392219b2ee8SDavid du Colombier 	case     'q': return remotelab(now);
393219b2ee8SDavid du Colombier 	case     'R': return qrecv(now, 0);	/* test only    */
394219b2ee8SDavid du Colombier 	case     LEN: return qlen(now);
395219b2ee8SDavid du Colombier 	case    FULL: return (qfull(now));
396219b2ee8SDavid du Colombier 	case   EMPTY: return (qlen(now)==0);
397219b2ee8SDavid du Colombier 	case   NFULL: return (!qfull(now));
398219b2ee8SDavid du Colombier 	case  NEMPTY: return (qlen(now)>0);
3997dd7cddfSDavid du Colombier 	case ENABLED: if (s_trail) return 1;
4007dd7cddfSDavid du Colombier 		      return pc_enabled(now->lft);
4017dd7cddfSDavid du Colombier 	case    EVAL: return eval(now->lft);
402219b2ee8SDavid du Colombier 	case  PC_VAL: return pc_value(now->lft);
4037dd7cddfSDavid du Colombier 	case NONPROGRESS: return nonprogress();
404219b2ee8SDavid du Colombier 	case    NAME: return getval(now);
405219b2ee8SDavid du Colombier 
406219b2ee8SDavid du Colombier 	case TIMEOUT: return Tval;
4077dd7cddfSDavid du Colombier 	case     RUN: return TstOnly?1:enable(now);
408219b2ee8SDavid du Colombier 
409219b2ee8SDavid du Colombier 	case   's': return qsend(now);		/* send         */
4107dd7cddfSDavid du Colombier 	case   'r': return qrecv(now, 1);	/* receive or poll */
411219b2ee8SDavid du Colombier 	case   'c': return eval(now->lft);	/* condition    */
4127dd7cddfSDavid du Colombier 	case PRINT: return TstOnly?1:interprint(stdout, now);
413312a1df1SDavid du Colombier 	case PRINTM: return TstOnly?1:printm(stdout, now);
414219b2ee8SDavid du Colombier 	case  ASGN: return assign(now);
415312a1df1SDavid du Colombier 
416*00d97012SDavid du Colombier 	case C_CODE: if (!analyze)
417*00d97012SDavid du Colombier 		     {	printf("%s:\t", now->sym->name);
418*00d97012SDavid du Colombier 		     	plunk_inline(stdout, now->sym->name, 0, 1);
419*00d97012SDavid du Colombier 		     }
420312a1df1SDavid du Colombier 		     return 1; /* uninterpreted */
421312a1df1SDavid du Colombier 
422*00d97012SDavid du Colombier 	case C_EXPR: if (!analyze)
423*00d97012SDavid du Colombier 		     {	printf("%s:\t", now->sym->name);
424312a1df1SDavid du Colombier 		     	plunk_expr(stdout, now->sym->name);
425312a1df1SDavid du Colombier 		     	printf("\n");
426*00d97012SDavid du Colombier 		     }
427312a1df1SDavid du Colombier 		     return 1; /* uninterpreted */
428312a1df1SDavid du Colombier 
429219b2ee8SDavid du Colombier 	case ASSERT: if (TstOnly || eval(now->lft)) return 1;
430219b2ee8SDavid du Colombier 		     non_fatal("assertion violated", (char *) 0);
4317dd7cddfSDavid du Colombier 			printf("spin: text of failed assertion: assert(");
4327dd7cddfSDavid du Colombier 			comment(stdout, now->lft, 0);
4337dd7cddfSDavid du Colombier 			printf(")\n");
4347dd7cddfSDavid du Colombier 		     if (s_trail && !xspin) return 1;
435219b2ee8SDavid du Colombier 		     wrapup(1); /* doesn't return */
436219b2ee8SDavid du Colombier 
4377dd7cddfSDavid du Colombier 	case  IF: case DO: case BREAK: case UNLESS:	/* compound */
438219b2ee8SDavid du Colombier 	case   '.': return 1;	/* return label for compound */
439219b2ee8SDavid du Colombier 	case   '@': return 0;	/* stop state */
440219b2ee8SDavid du Colombier 	case  ELSE: return 1;	/* only hit here in guided trails */
441219b2ee8SDavid du Colombier 	default   : printf("spin: bad node type %d (run)\n", now->ntyp);
4427dd7cddfSDavid du Colombier 		    if (s_trail) printf("spin: trail file doesn't match spec?\n");
443219b2ee8SDavid du Colombier 		    fatal("aborting", 0);
444219b2ee8SDavid du Colombier 	}}
445219b2ee8SDavid du Colombier 	return 0;
446219b2ee8SDavid du Colombier }
447219b2ee8SDavid du Colombier 
448219b2ee8SDavid du Colombier int
printm(FILE * fd,Lextok * n)449312a1df1SDavid du Colombier printm(FILE *fd, Lextok *n)
450312a1df1SDavid du Colombier {	extern char Buf[];
451312a1df1SDavid du Colombier 	int j;
452312a1df1SDavid du Colombier 
453312a1df1SDavid du Colombier 	Buf[0] = '\0';
454312a1df1SDavid du Colombier 	if (!no_print)
455312a1df1SDavid du Colombier 	if (!s_trail || depth >= jumpsteps) {
456312a1df1SDavid du Colombier 		if (n->lft->ismtyp)
457312a1df1SDavid du Colombier 			j = n->lft->val;
458312a1df1SDavid du Colombier 		else
459312a1df1SDavid du Colombier 			j = eval(n->lft);
460312a1df1SDavid du Colombier 		sr_buf(j, 1);
461312a1df1SDavid du Colombier 		dotag(fd, Buf);
462312a1df1SDavid du Colombier 	}
463312a1df1SDavid du Colombier 	return 1;
464312a1df1SDavid du Colombier }
465312a1df1SDavid du Colombier 
466312a1df1SDavid du Colombier int
interprint(FILE * fd,Lextok * n)4677dd7cddfSDavid du Colombier interprint(FILE *fd, Lextok *n)
468219b2ee8SDavid du Colombier {	Lextok *tmp = n->lft;
469219b2ee8SDavid du Colombier 	char c, *s = n->sym->name;
470*00d97012SDavid du Colombier 	int i, j; char lbuf[512]; /* matches value in sr_buf() */
471*00d97012SDavid du Colombier 	extern char Buf[];	/* global, size 4096 */
472*00d97012SDavid du Colombier 	char tBuf[4096];	/* match size of global Buf[] */
473219b2ee8SDavid du Colombier 
4747dd7cddfSDavid du Colombier 	Buf[0] = '\0';
4757dd7cddfSDavid du Colombier 	if (!no_print)
4767dd7cddfSDavid du Colombier 	if (!s_trail || depth >= jumpsteps) {
4777dd7cddfSDavid du Colombier 	for (i = 0; i < (int) strlen(s); i++)
478219b2ee8SDavid du Colombier 		switch (s[i]) {
479219b2ee8SDavid du Colombier 		case '\"': break; /* ignore */
480219b2ee8SDavid du Colombier 		case '\\':
481219b2ee8SDavid du Colombier 			 switch(s[++i]) {
4827dd7cddfSDavid du Colombier 			 case 't': strcat(Buf, "\t"); break;
4837dd7cddfSDavid du Colombier 			 case 'n': strcat(Buf, "\n"); break;
4847dd7cddfSDavid du Colombier 			 default:  goto onechar;
485219b2ee8SDavid du Colombier 			 }
486219b2ee8SDavid du Colombier 			 break;
487219b2ee8SDavid du Colombier 		case  '%':
488219b2ee8SDavid du Colombier 			 if ((c = s[++i]) == '%')
4897dd7cddfSDavid du Colombier 			 {	strcat(Buf, "%"); /* literal */
490219b2ee8SDavid du Colombier 				break;
491219b2ee8SDavid du Colombier 			 }
492219b2ee8SDavid du Colombier 			 if (!tmp)
493219b2ee8SDavid du Colombier 			 {	non_fatal("too few print args %s", s);
494219b2ee8SDavid du Colombier 				break;
495219b2ee8SDavid du Colombier 			 }
496219b2ee8SDavid du Colombier 			 j = eval(tmp->lft);
497219b2ee8SDavid du Colombier 			 tmp = tmp->rgt;
498219b2ee8SDavid du Colombier 			 switch(c) {
4997dd7cddfSDavid du Colombier 			 case 'c': sprintf(lbuf, "%c", j); break;
5007dd7cddfSDavid du Colombier 			 case 'd': sprintf(lbuf, "%d", j); break;
5017dd7cddfSDavid du Colombier 
5027dd7cddfSDavid du Colombier 			 case 'e': strcpy(tBuf, Buf);	/* event name */
5037dd7cddfSDavid du Colombier 				   Buf[0] = '\0';
5047dd7cddfSDavid du Colombier 				   sr_buf(j, 1);
5057dd7cddfSDavid du Colombier 				   strcpy(lbuf, Buf);
5067dd7cddfSDavid du Colombier 				   strcpy(Buf, tBuf);
5077dd7cddfSDavid du Colombier 				   break;
5087dd7cddfSDavid du Colombier 
5097dd7cddfSDavid du Colombier 			 case 'o': sprintf(lbuf, "%o", j); break;
5107dd7cddfSDavid du Colombier 			 case 'u': sprintf(lbuf, "%u", (unsigned) j); break;
5117dd7cddfSDavid du Colombier 			 case 'x': sprintf(lbuf, "%x", j); break;
5127dd7cddfSDavid du Colombier 			 default:  non_fatal("bad print cmd: '%s'", &s[i-1]);
5137dd7cddfSDavid du Colombier 				   lbuf[0] = '\0'; break;
5147dd7cddfSDavid du Colombier 			 }
5157dd7cddfSDavid du Colombier 			 goto append;
5167dd7cddfSDavid du Colombier 		default:
5177dd7cddfSDavid du Colombier onechar:		 lbuf[0] = s[i]; lbuf[1] = '\0';
5187dd7cddfSDavid du Colombier append:			 strcat(Buf, lbuf);
519219b2ee8SDavid du Colombier 			 break;
520219b2ee8SDavid du Colombier 		}
5217dd7cddfSDavid du Colombier 		dotag(fd, Buf);
522219b2ee8SDavid du Colombier 	}
523*00d97012SDavid du Colombier 	if (strlen(Buf) >= 4096) fatal("printf string too long", 0);
524219b2ee8SDavid du Colombier 	return 1;
525219b2ee8SDavid du Colombier }
526219b2ee8SDavid du Colombier 
5277dd7cddfSDavid du Colombier static int
Enabled1(Lextok * n)528219b2ee8SDavid du Colombier Enabled1(Lextok *n)
529219b2ee8SDavid du Colombier {	int i; int v = verbose;
530219b2ee8SDavid du Colombier 
531219b2ee8SDavid du Colombier 	if (n)
532219b2ee8SDavid du Colombier 	switch (n->ntyp) {
5337dd7cddfSDavid du Colombier 	case 'c':
5347dd7cddfSDavid du Colombier 		if (has_typ(n->lft, RUN))
5357dd7cddfSDavid du Colombier 			return 1;	/* conservative */
5367dd7cddfSDavid du Colombier 		/* else fall through */
537219b2ee8SDavid du Colombier 	default:	/* side-effect free */
538219b2ee8SDavid du Colombier 		verbose = 0;
5397dd7cddfSDavid du Colombier 		E_Check++;
540219b2ee8SDavid du Colombier 		i = eval(n);
5417dd7cddfSDavid du Colombier 		E_Check--;
542219b2ee8SDavid du Colombier 		verbose = v;
543219b2ee8SDavid du Colombier 		return i;
544219b2ee8SDavid du Colombier 
545312a1df1SDavid du Colombier 	case C_CODE: case C_EXPR:
546312a1df1SDavid du Colombier 	case PRINT: case PRINTM:
547312a1df1SDavid du Colombier 	case   ASGN: case ASSERT:
548219b2ee8SDavid du Colombier 		return 1;
549219b2ee8SDavid du Colombier 
5507dd7cddfSDavid du Colombier 	case 's':
5517dd7cddfSDavid du Colombier 		if (q_is_sync(n))
5527dd7cddfSDavid du Colombier 		{	if (Rvous) return 0;
5537dd7cddfSDavid du Colombier 			TstOnly = 1; verbose = 0;
5547dd7cddfSDavid du Colombier 			E_Check++;
555219b2ee8SDavid du Colombier 			i = eval(n);
5567dd7cddfSDavid du Colombier 			E_Check--;
5577dd7cddfSDavid du Colombier 			TstOnly = 0; verbose = v;
5587dd7cddfSDavid du Colombier 			return i;
5597dd7cddfSDavid du Colombier 		}
5607dd7cddfSDavid du Colombier 		return (!qfull(n));
5617dd7cddfSDavid du Colombier 	case 'r':
5627dd7cddfSDavid du Colombier 		if (q_is_sync(n))
5637dd7cddfSDavid du Colombier 			return 0;	/* it's never a user-choice */
5647dd7cddfSDavid du Colombier 		n->ntyp = 'R'; verbose = 0;
5657dd7cddfSDavid du Colombier 		E_Check++;
5667dd7cddfSDavid du Colombier 		i = eval(n);
5677dd7cddfSDavid du Colombier 		E_Check--;
568219b2ee8SDavid du Colombier 		n->ntyp = 'r'; verbose = v;
569219b2ee8SDavid du Colombier 		return i;
570219b2ee8SDavid du Colombier 	}
571219b2ee8SDavid du Colombier 	return 0;
572219b2ee8SDavid du Colombier }
573219b2ee8SDavid du Colombier 
574219b2ee8SDavid du Colombier int
Enabled0(Element * e)575219b2ee8SDavid du Colombier Enabled0(Element *e)
576219b2ee8SDavid du Colombier {	SeqList *z;
577219b2ee8SDavid du Colombier 
578219b2ee8SDavid du Colombier 	if (!e || !e->n)
579219b2ee8SDavid du Colombier 		return 0;
580219b2ee8SDavid du Colombier 
581219b2ee8SDavid du Colombier 	switch (e->n->ntyp) {
5827dd7cddfSDavid du Colombier 	case '@':
5837dd7cddfSDavid du Colombier 		return X->pid == (nproc-nstop-1);
584219b2ee8SDavid du Colombier 	case '.':
585219b2ee8SDavid du Colombier 		return 1;
586219b2ee8SDavid du Colombier 	case GOTO:
587219b2ee8SDavid du Colombier 		if (Rvous) return 0;
588219b2ee8SDavid du Colombier 		return 1;
589219b2ee8SDavid du Colombier 	case UNLESS:
590219b2ee8SDavid du Colombier 		return Enabled0(e->sub->this->frst);
591219b2ee8SDavid du Colombier 	case ATOMIC:
592219b2ee8SDavid du Colombier 	case D_STEP:
593219b2ee8SDavid du Colombier 	case NON_ATOMIC:
594219b2ee8SDavid du Colombier 		return Enabled0(e->n->sl->this->frst);
595219b2ee8SDavid du Colombier 	}
596219b2ee8SDavid du Colombier 	if (e->sub)	/* true for IF, DO, and UNLESS */
597219b2ee8SDavid du Colombier 	{	for (z = e->sub; z; z = z->nxt)
598219b2ee8SDavid du Colombier 			if (Enabled0(z->this->frst))
599219b2ee8SDavid du Colombier 				return 1;
600219b2ee8SDavid du Colombier 		return 0;
601219b2ee8SDavid du Colombier 	}
602219b2ee8SDavid du Colombier 	for (z = e->esc; z; z = z->nxt)
603219b2ee8SDavid du Colombier 	{	if (Enabled0(z->this->frst))
604219b2ee8SDavid du Colombier 			return 1;
605219b2ee8SDavid du Colombier 	}
6067dd7cddfSDavid du Colombier #if 0
6077dd7cddfSDavid du Colombier 	printf("enabled1 ");
6087dd7cddfSDavid du Colombier 	comment(stdout, e->n, 0);
6097dd7cddfSDavid du Colombier 	printf(" ==> %s\n", Enabled1(e->n)?"yes":"nope");
6107dd7cddfSDavid du Colombier #endif
611219b2ee8SDavid du Colombier 	return Enabled1(e->n);
612219b2ee8SDavid du Colombier }
6137dd7cddfSDavid du Colombier 
6147dd7cddfSDavid du Colombier int
pc_enabled(Lextok * n)6157dd7cddfSDavid du Colombier pc_enabled(Lextok *n)
6167dd7cddfSDavid du Colombier {	int i = nproc - nstop;
6177dd7cddfSDavid du Colombier 	int pid = eval(n);
6187dd7cddfSDavid du Colombier 	int result = 0;
6197dd7cddfSDavid du Colombier 	RunList *Y, *oX;
6207dd7cddfSDavid du Colombier 
621312a1df1SDavid du Colombier 	if (pid == X->pid)
622312a1df1SDavid du Colombier 		fatal("used: enabled(pid=thisproc) [%s]", X->n->name);
623312a1df1SDavid du Colombier 
6247dd7cddfSDavid du Colombier 	for (Y = run; Y; Y = Y->nxt)
6257dd7cddfSDavid du Colombier 		if (--i == pid)
6267dd7cddfSDavid du Colombier 		{	oX = X; X = Y;
6277dd7cddfSDavid du Colombier 			result = Enabled0(Y->pc);
6287dd7cddfSDavid du Colombier 			X = oX;
6297dd7cddfSDavid du Colombier 			break;
6307dd7cddfSDavid du Colombier 		}
6317dd7cddfSDavid du Colombier 	return result;
6327dd7cddfSDavid du Colombier }
633*00d97012SDavid du Colombier 
634