xref: /plan9/sys/src/cmd/spin/run.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1219b2ee8SDavid du Colombier /***** spin: run.c *****/
2219b2ee8SDavid du Colombier 
3*7dd7cddfSDavid du Colombier /* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
4*7dd7cddfSDavid du Colombier /* All Rights Reserved.  This software is for educational purposes only.  */
5219b2ee8SDavid du Colombier /* Permission is given to distribute this code provided that this intro-  */
6219b2ee8SDavid du Colombier /* ductory message is not removed and no monies are exchanged.            */
7219b2ee8SDavid du Colombier /* No guarantee is expressed or implied by the distribution of this code. */
8219b2ee8SDavid du Colombier /* Software written by Gerard J. Holzmann as part of the book:            */
9219b2ee8SDavid du Colombier /* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
10219b2ee8SDavid du Colombier /* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
11*7dd7cddfSDavid du Colombier /* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
12219b2ee8SDavid du Colombier 
13*7dd7cddfSDavid du Colombier #include <stdlib.h>
14219b2ee8SDavid du Colombier #include "spin.h"
15*7dd7cddfSDavid du Colombier #ifdef PC
16*7dd7cddfSDavid du Colombier #include "y_tab.h"
17*7dd7cddfSDavid du Colombier #else
18219b2ee8SDavid du Colombier #include "y.tab.h"
19*7dd7cddfSDavid du Colombier #endif
20219b2ee8SDavid du Colombier 
21*7dd7cddfSDavid du Colombier extern RunList	*X, *run;
22219b2ee8SDavid du Colombier extern Symbol	*Fname;
23219b2ee8SDavid du Colombier extern Element	*LastStep;
24*7dd7cddfSDavid du Colombier extern int	Rvous, lineno, Tval, interactive, MadeChoice;
25*7dd7cddfSDavid du Colombier extern int	TstOnly, verbose, s_trail, xspin, jumpsteps, depth;
26*7dd7cddfSDavid du Colombier extern int	nproc, nstop, no_print, like_java;
27219b2ee8SDavid du Colombier 
28219b2ee8SDavid du Colombier static long	Seed = 1;
29*7dd7cddfSDavid du Colombier static int	E_Check = 0, Escape_Check = 0;
30*7dd7cddfSDavid du Colombier 
31*7dd7cddfSDavid du Colombier static int	eval_sync(Element *);
32*7dd7cddfSDavid du Colombier static int	pc_enabled(Lextok *n);
33*7dd7cddfSDavid du Colombier extern void	sr_buf(int, int);
34219b2ee8SDavid du Colombier 
35219b2ee8SDavid du Colombier void
36219b2ee8SDavid du Colombier Srand(unsigned int s)
37219b2ee8SDavid du Colombier {	Seed = s;
38219b2ee8SDavid du Colombier }
39219b2ee8SDavid du Colombier 
40219b2ee8SDavid du Colombier long
41219b2ee8SDavid du Colombier Rand(void)
42219b2ee8SDavid du Colombier {	/* CACM 31(10), Oct 1988 */
43219b2ee8SDavid du Colombier 	Seed = 16807*(Seed%127773) - 2836*(Seed/127773);
44219b2ee8SDavid du Colombier 	if (Seed <= 0) Seed += 2147483647;
45219b2ee8SDavid du Colombier 	return Seed;
46219b2ee8SDavid du Colombier }
47219b2ee8SDavid du Colombier 
48219b2ee8SDavid du Colombier Element *
49*7dd7cddfSDavid du Colombier rev_escape(SeqList *e)
50*7dd7cddfSDavid du Colombier {	Element *r;
51*7dd7cddfSDavid du Colombier 
52*7dd7cddfSDavid du Colombier 	if (!e)
53*7dd7cddfSDavid du Colombier 		return (Element *) 0;
54*7dd7cddfSDavid du Colombier 
55*7dd7cddfSDavid du Colombier 	if (r = rev_escape(e->nxt)) /* reversed order */
56*7dd7cddfSDavid du Colombier 		return r;
57*7dd7cddfSDavid du Colombier 
58*7dd7cddfSDavid du Colombier 	return eval_sub(e->this->frst);
59*7dd7cddfSDavid du Colombier }
60*7dd7cddfSDavid du Colombier 
61*7dd7cddfSDavid du Colombier Element *
62219b2ee8SDavid du Colombier eval_sub(Element *e)
63219b2ee8SDavid du Colombier {	Element *f, *g;
64219b2ee8SDavid du Colombier 	SeqList *z;
65219b2ee8SDavid du Colombier 	int i, j, k;
66219b2ee8SDavid du Colombier 
67219b2ee8SDavid du Colombier 	if (!e->n)
68219b2ee8SDavid du Colombier 		return ZE;
69219b2ee8SDavid du Colombier #ifdef DEBUG
70*7dd7cddfSDavid du Colombier 	printf("\n\teval_sub(%d %s: line %d) ",
71*7dd7cddfSDavid du Colombier 		e->Seqno, e->esc?"+esc":"", e->n?e->n->ln:0);
72219b2ee8SDavid du Colombier 	comment(stdout, e->n, 0);
73219b2ee8SDavid du Colombier 	printf("\n");
74219b2ee8SDavid du Colombier #endif
75219b2ee8SDavid du Colombier 	if (e->n->ntyp == GOTO)
76219b2ee8SDavid du Colombier 	{	if (Rvous) return ZE;
77*7dd7cddfSDavid du Colombier 		LastStep = e; f = get_lab(e->n, 1);
78219b2ee8SDavid du Colombier 		cross_dsteps(e->n, f->n);
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;
86*7dd7cddfSDavid du Colombier 		Element *bas_else = ZE;
87*7dd7cddfSDavid du Colombier 		int nr_else, nr_choices = 0;
88219b2ee8SDavid du Colombier 
89*7dd7cddfSDavid du Colombier 		if (interactive
90*7dd7cddfSDavid du Colombier 		&& !MadeChoice && !E_Check
91*7dd7cddfSDavid du Colombier 		&& !Escape_Check
92*7dd7cddfSDavid du Colombier 		&& !(e->status&(D_ATOM))
93*7dd7cddfSDavid du Colombier 		&& depth >= jumpsteps)
94219b2ee8SDavid du Colombier 		{	printf("Select stmnt (");
95219b2ee8SDavid du Colombier 			whoruns(0); printf(")\n");
96*7dd7cddfSDavid du Colombier 			if (nproc-nstop > 1)
97219b2ee8SDavid du Colombier 			printf("\tchoice 0: other process\n");
98219b2ee8SDavid du Colombier 		}
99219b2ee8SDavid du Colombier 		for (z = e->sub, j=0; z; z = z->nxt)
100219b2ee8SDavid du Colombier 		{	j++;
101*7dd7cddfSDavid du Colombier 			if (interactive
102*7dd7cddfSDavid du Colombier 			&& !MadeChoice && !E_Check
103*7dd7cddfSDavid du Colombier 			&& !Escape_Check
104*7dd7cddfSDavid du Colombier 			&& !(e->status&(D_ATOM))
105*7dd7cddfSDavid du Colombier 			&& depth >= jumpsteps
106219b2ee8SDavid du Colombier 			&& z->this->frst
107*7dd7cddfSDavid du Colombier 			&& (xspin || (verbose&32) || Enabled0(z->this->frst)))
108*7dd7cddfSDavid du Colombier 			{	if (z->this->frst->n->ntyp == ELSE)
109*7dd7cddfSDavid du Colombier 				{	has_else = (Rvous)?ZE:z->this->frst->nxt;
110*7dd7cddfSDavid du Colombier 					nr_else = j;
111*7dd7cddfSDavid du Colombier 					continue;
112*7dd7cddfSDavid du Colombier 				}
113*7dd7cddfSDavid du Colombier 				printf("\tchoice %d: ", j);
114*7dd7cddfSDavid du Colombier #if 0
115*7dd7cddfSDavid du Colombier 				if (z->this->frst->n)
116*7dd7cddfSDavid du Colombier 					printf("line %d, ", z->this->frst->n->ln);
117*7dd7cddfSDavid du Colombier #endif
118219b2ee8SDavid du Colombier 				if (!Enabled0(z->this->frst))
119219b2ee8SDavid du Colombier 					printf("unexecutable, ");
120*7dd7cddfSDavid du Colombier 				else
121*7dd7cddfSDavid du Colombier 					nr_choices++;
122219b2ee8SDavid du Colombier 				comment(stdout, z->this->frst->n, 0);
123219b2ee8SDavid du Colombier 				printf("\n");
124219b2ee8SDavid du Colombier 		}	}
125*7dd7cddfSDavid du Colombier 
126*7dd7cddfSDavid du Colombier 		if (nr_choices == 0 && has_else)
127*7dd7cddfSDavid du Colombier 			printf("\tchoice %d: (else)\n", nr_else);
128*7dd7cddfSDavid du Colombier 
129*7dd7cddfSDavid du Colombier 		if (interactive && depth >= jumpsteps
130*7dd7cddfSDavid du Colombier 		&& !Escape_Check
131*7dd7cddfSDavid du Colombier 		&& !(e->status&(D_ATOM))
132*7dd7cddfSDavid du Colombier 		&& !E_Check)
133*7dd7cddfSDavid du Colombier 		{	if (!MadeChoice)
134*7dd7cddfSDavid du Colombier 			{	char buf[256];
135*7dd7cddfSDavid du Colombier 				if (xspin)
136219b2ee8SDavid du Colombier 					printf("Make Selection %d\n\n", j);
137219b2ee8SDavid du Colombier 				else
138219b2ee8SDavid du Colombier 					printf("Select [0-%d]: ", j);
139219b2ee8SDavid du Colombier 				fflush(stdout);
140*7dd7cddfSDavid du Colombier 				scanf("%s", buf);
141*7dd7cddfSDavid du Colombier 				if (isdigit(buf[0]))
142*7dd7cddfSDavid du Colombier 					k = atoi(buf);
143*7dd7cddfSDavid du Colombier 				else
144*7dd7cddfSDavid du Colombier 				{	if (buf[0] == 'q')
145*7dd7cddfSDavid du Colombier 						alldone(0);
146*7dd7cddfSDavid du Colombier 					k = -1;
147*7dd7cddfSDavid du Colombier 				}
148219b2ee8SDavid du Colombier 			} else
149*7dd7cddfSDavid du Colombier 			{	k = MadeChoice;
150*7dd7cddfSDavid du Colombier 				MadeChoice = 0;
151219b2ee8SDavid du Colombier 			}
152219b2ee8SDavid du Colombier 			if (k < 1 || k > j)
153*7dd7cddfSDavid du Colombier 			{	if (k != 0) printf("\tchoice outside range\n");
154219b2ee8SDavid du Colombier 				return ZE;
155219b2ee8SDavid du Colombier 			}
156219b2ee8SDavid du Colombier 			k--;
157219b2ee8SDavid du Colombier 		} else
158*7dd7cddfSDavid du Colombier 		{	if (e->n && e->n->indstep >= 0)
159*7dd7cddfSDavid du Colombier 				k = 0;	/* select 1st executable guard */
160*7dd7cddfSDavid du Colombier 			else
161219b2ee8SDavid du Colombier 				k = Rand()%j;	/* nondeterminism */
162*7dd7cddfSDavid du Colombier 		}
163*7dd7cddfSDavid du Colombier 		has_else = ZE;
164*7dd7cddfSDavid du Colombier 		bas_else = ZE;
165219b2ee8SDavid du Colombier 		for (i = 0, z = e->sub; i < j+k; i++)
166219b2ee8SDavid du Colombier 		{	if (z->this->frst
167219b2ee8SDavid du Colombier 			&&  z->this->frst->n->ntyp == ELSE)
168*7dd7cddfSDavid du Colombier 			{	bas_else = z->this->frst;
169*7dd7cddfSDavid du Colombier 				has_else = (Rvous)?ZE:bas_else->nxt;
170*7dd7cddfSDavid du Colombier 				if (!interactive || depth < jumpsteps
171*7dd7cddfSDavid du Colombier 				|| Escape_Check
172*7dd7cddfSDavid du Colombier 				|| (e->status&(D_ATOM)))
173219b2ee8SDavid du Colombier 				{	z = (z->nxt)?z->nxt:e->sub;
174219b2ee8SDavid du Colombier 					continue;
175*7dd7cddfSDavid du Colombier 				}
176*7dd7cddfSDavid du Colombier 			}
177219b2ee8SDavid du Colombier 			if (i >= k)
178219b2ee8SDavid du Colombier 			{	if (f = eval_sub(z->this->frst))
179219b2ee8SDavid du Colombier 					return f;
180*7dd7cddfSDavid du Colombier 				else if (interactive && depth >= jumpsteps
181*7dd7cddfSDavid du Colombier 				&& !(e->status&(D_ATOM)))
182*7dd7cddfSDavid du Colombier 				{	if (!E_Check && !Escape_Check)
183*7dd7cddfSDavid du Colombier 						printf("\tunexecutable\n");
184219b2ee8SDavid du Colombier 					return ZE;
185219b2ee8SDavid du Colombier 			}	}
186219b2ee8SDavid du Colombier 			z = (z->nxt)?z->nxt:e->sub;
187219b2ee8SDavid du Colombier 		}
188*7dd7cddfSDavid du Colombier 		LastStep = bas_else;
189219b2ee8SDavid du Colombier 		return has_else;
190219b2ee8SDavid du Colombier 	} else
191219b2ee8SDavid du Colombier 	{	if (e->n->ntyp == ATOMIC
192219b2ee8SDavid du Colombier 		||  e->n->ntyp == D_STEP)
193219b2ee8SDavid du Colombier 		{	f = e->n->sl->this->frst;
194219b2ee8SDavid du Colombier 			g = e->n->sl->this->last;
195219b2ee8SDavid du Colombier 			g->nxt = e->nxt;
196219b2ee8SDavid du Colombier 			if (!(g = eval_sub(f)))	/* atomic guard */
197219b2ee8SDavid du Colombier 				return ZE;
198219b2ee8SDavid du Colombier 			return g;
199219b2ee8SDavid du Colombier 		} else if (e->n->ntyp == NON_ATOMIC)
200219b2ee8SDavid du Colombier 		{	f = e->n->sl->this->frst;
201219b2ee8SDavid du Colombier 			g = e->n->sl->this->last;
202219b2ee8SDavid du Colombier 			g->nxt = e->nxt;		/* close it */
203219b2ee8SDavid du Colombier 			return eval_sub(f);
204219b2ee8SDavid du Colombier 		} else if (e->n->ntyp == '.')
205*7dd7cddfSDavid du Colombier 		{	if (!Rvous) return e->nxt;
206*7dd7cddfSDavid du Colombier 			return eval_sub(e->nxt);
207219b2ee8SDavid du Colombier 		} else
208219b2ee8SDavid du Colombier 		{	SeqList *x;
209*7dd7cddfSDavid du Colombier 			if (!(e->status & (D_ATOM))
210*7dd7cddfSDavid du Colombier 			&&  e->esc && verbose&32)
211*7dd7cddfSDavid du Colombier 			{	printf("Stmnt [");
212219b2ee8SDavid du Colombier 				comment(stdout, e->n, 0);
213*7dd7cddfSDavid du Colombier 				printf("] has escape(s): ");
214219b2ee8SDavid du Colombier 				for (x = e->esc; x; x = x->nxt)
215*7dd7cddfSDavid du Colombier 				{	printf("[");
216*7dd7cddfSDavid du Colombier 					g = x->this->frst;
217*7dd7cddfSDavid du Colombier 					if (g->n->ntyp == ATOMIC
218*7dd7cddfSDavid du Colombier 					||  g->n->ntyp == NON_ATOMIC)
219*7dd7cddfSDavid du Colombier 						g = g->n->sl->this->frst;
220*7dd7cddfSDavid du Colombier 					comment(stdout, g->n, 0);
221*7dd7cddfSDavid du Colombier 					printf("] ");
222*7dd7cddfSDavid du Colombier 				}
223*7dd7cddfSDavid du Colombier 				printf("\n");
224*7dd7cddfSDavid du Colombier 			}
225*7dd7cddfSDavid du Colombier 
226*7dd7cddfSDavid du Colombier 			if (!(e->status & D_ATOM))	/* escapes don't reach inside d_steps */
227*7dd7cddfSDavid du Colombier 			{	Escape_Check++;
228*7dd7cddfSDavid du Colombier 				if (like_java)
229*7dd7cddfSDavid du Colombier 				{	if (g = rev_escape(e->esc))
230*7dd7cddfSDavid du Colombier 					{	if (verbose&4)
231*7dd7cddfSDavid du Colombier 							printf("\tEscape taken\n");
232*7dd7cddfSDavid du Colombier 						Escape_Check--;
233*7dd7cddfSDavid du Colombier 						return g;
234*7dd7cddfSDavid du Colombier 					}
235*7dd7cddfSDavid du Colombier 				} else
236*7dd7cddfSDavid du Colombier 				{	for (x = e->esc; x; x = x->nxt)
237219b2ee8SDavid du Colombier 					{	if (g = eval_sub(x->this->frst))
238219b2ee8SDavid du Colombier 						{	if (verbose&4)
239219b2ee8SDavid du Colombier 								printf("\tEscape taken\n");
240*7dd7cddfSDavid du Colombier 							Escape_Check--;
241219b2ee8SDavid du Colombier 							return g;
242*7dd7cddfSDavid du Colombier 				}	}	}
243*7dd7cddfSDavid du Colombier 				Escape_Check--;
244*7dd7cddfSDavid du Colombier 			}
245*7dd7cddfSDavid du Colombier 
246219b2ee8SDavid du Colombier 			switch (e->n->ntyp) {
247219b2ee8SDavid du Colombier 			case TIMEOUT: case RUN:
248*7dd7cddfSDavid du Colombier 			case PRINT:
249*7dd7cddfSDavid du Colombier 			case ASGN: case ASSERT:
250219b2ee8SDavid du Colombier 			case 's': case 'r': case 'c':
251219b2ee8SDavid du Colombier 				/* toplevel statements only */
252219b2ee8SDavid du Colombier 				LastStep = e;
253219b2ee8SDavid du Colombier 			default:
254219b2ee8SDavid du Colombier 				break;
255219b2ee8SDavid du Colombier 			}
256*7dd7cddfSDavid du Colombier 			if (Rvous)
257*7dd7cddfSDavid du Colombier 			{
258*7dd7cddfSDavid du Colombier 				return (eval_sync(e))?e->nxt:ZE;
259*7dd7cddfSDavid du Colombier 			}
260219b2ee8SDavid du Colombier 			return (eval(e->n))?e->nxt:ZE;
261219b2ee8SDavid du Colombier 		}
262219b2ee8SDavid du Colombier 	}
263*7dd7cddfSDavid du Colombier 	return ZE; /* not reached */
264219b2ee8SDavid du Colombier }
265219b2ee8SDavid du Colombier 
266*7dd7cddfSDavid du Colombier static int
267219b2ee8SDavid du Colombier eval_sync(Element *e)
268219b2ee8SDavid du Colombier {	/* allow only synchronous receives
269*7dd7cddfSDavid du Colombier 	   and related node types    */
270219b2ee8SDavid du Colombier 	Lextok *now = (e)?e->n:ZN;
271219b2ee8SDavid du Colombier 
272219b2ee8SDavid du Colombier 	if (!now
273219b2ee8SDavid du Colombier 	||  now->ntyp != 'r'
274*7dd7cddfSDavid du Colombier 	||  now->val >= 2	/* no rv with a poll */
275219b2ee8SDavid du Colombier 	||  !q_is_sync(now))
276*7dd7cddfSDavid du Colombier 	{
277219b2ee8SDavid du Colombier 		return 0;
278*7dd7cddfSDavid du Colombier 	}
279219b2ee8SDavid du Colombier 
280219b2ee8SDavid du Colombier 	LastStep = e;
281219b2ee8SDavid du Colombier 	return eval(now);
282219b2ee8SDavid du Colombier }
283219b2ee8SDavid du Colombier 
284*7dd7cddfSDavid du Colombier static int
285219b2ee8SDavid du Colombier assign(Lextok *now)
286219b2ee8SDavid du Colombier {	int t;
287219b2ee8SDavid du Colombier 
288219b2ee8SDavid du Colombier 	if (TstOnly) return 1;
289219b2ee8SDavid du Colombier 
290219b2ee8SDavid du Colombier 	switch (now->rgt->ntyp) {
291219b2ee8SDavid du Colombier 	case FULL:	case NFULL:
292219b2ee8SDavid du Colombier 	case EMPTY:	case NEMPTY:
293219b2ee8SDavid du Colombier 	case RUN:	case LEN:
294219b2ee8SDavid du Colombier 		t = BYTE;
295219b2ee8SDavid du Colombier 		break;
296219b2ee8SDavid du Colombier 	default:
297219b2ee8SDavid du Colombier 		t = Sym_typ(now->rgt);
298219b2ee8SDavid du Colombier 		break;
299219b2ee8SDavid du Colombier 	}
300219b2ee8SDavid du Colombier 	typ_ck(Sym_typ(now->lft), t, "assignment");
301219b2ee8SDavid du Colombier 	return setval(now->lft, eval(now->rgt));
302219b2ee8SDavid du Colombier }
303219b2ee8SDavid du Colombier 
304*7dd7cddfSDavid du Colombier static int
305*7dd7cddfSDavid du Colombier nonprogress(void)	/* np_ */
306*7dd7cddfSDavid du Colombier {	RunList	*r;
307*7dd7cddfSDavid du Colombier 
308*7dd7cddfSDavid du Colombier 	for (r = run; r; r = r->nxt)
309*7dd7cddfSDavid du Colombier 	{	if (has_lab(r->pc, 4))	/* 4=progress */
310*7dd7cddfSDavid du Colombier 			return 0;
311*7dd7cddfSDavid du Colombier 	}
312*7dd7cddfSDavid du Colombier 	return 1;
313*7dd7cddfSDavid du Colombier }
314*7dd7cddfSDavid du Colombier 
315219b2ee8SDavid du Colombier int
316219b2ee8SDavid du Colombier eval(Lextok *now)
317219b2ee8SDavid du Colombier {
318219b2ee8SDavid du Colombier 	if (now) {
319219b2ee8SDavid du Colombier 	lineno = now->ln;
320219b2ee8SDavid du Colombier 	Fname  = now->fn;
321219b2ee8SDavid du Colombier #ifdef DEBUG
322219b2ee8SDavid du Colombier 	printf("eval ");
323219b2ee8SDavid du Colombier 	comment(stdout, now, 0);
324219b2ee8SDavid du Colombier 	printf("\n");
325219b2ee8SDavid du Colombier #endif
326219b2ee8SDavid du Colombier 	switch (now->ntyp) {
327219b2ee8SDavid du Colombier 	case CONST: return now->val;
328219b2ee8SDavid du Colombier 	case   '!': return !eval(now->lft);
329219b2ee8SDavid du Colombier 	case  UMIN: return -eval(now->lft);
330219b2ee8SDavid du Colombier 	case   '~': return ~eval(now->lft);
331219b2ee8SDavid du Colombier 
332219b2ee8SDavid du Colombier 	case   '/': return (eval(now->lft) / eval(now->rgt));
333219b2ee8SDavid du Colombier 	case   '*': return (eval(now->lft) * eval(now->rgt));
334219b2ee8SDavid du Colombier 	case   '-': return (eval(now->lft) - eval(now->rgt));
335219b2ee8SDavid du Colombier 	case   '+': return (eval(now->lft) + eval(now->rgt));
336219b2ee8SDavid du Colombier 	case   '%': return (eval(now->lft) % eval(now->rgt));
337219b2ee8SDavid du Colombier 	case    LT: return (eval(now->lft) <  eval(now->rgt));
338219b2ee8SDavid du Colombier 	case    GT: return (eval(now->lft) >  eval(now->rgt));
339219b2ee8SDavid du Colombier 	case   '&': return (eval(now->lft) &  eval(now->rgt));
340*7dd7cddfSDavid du Colombier 	case   '^': return (eval(now->lft) ^  eval(now->rgt));
341219b2ee8SDavid du Colombier 	case   '|': return (eval(now->lft) |  eval(now->rgt));
342219b2ee8SDavid du Colombier 	case    LE: return (eval(now->lft) <= eval(now->rgt));
343219b2ee8SDavid du Colombier 	case    GE: return (eval(now->lft) >= eval(now->rgt));
344219b2ee8SDavid du Colombier 	case    NE: return (eval(now->lft) != eval(now->rgt));
345219b2ee8SDavid du Colombier 	case    EQ: return (eval(now->lft) == eval(now->rgt));
346219b2ee8SDavid du Colombier 	case    OR: return (eval(now->lft) || eval(now->rgt));
347219b2ee8SDavid du Colombier 	case   AND: return (eval(now->lft) && eval(now->rgt));
348219b2ee8SDavid du Colombier 	case LSHIFT: return (eval(now->lft) << eval(now->rgt));
349219b2ee8SDavid du Colombier 	case RSHIFT: return (eval(now->lft) >> eval(now->rgt));
350219b2ee8SDavid du Colombier 	case   '?': return (eval(now->lft) ? eval(now->rgt->lft)
351219b2ee8SDavid du Colombier 					   : eval(now->rgt->rgt));
352219b2ee8SDavid du Colombier 
353219b2ee8SDavid du Colombier 	case     'p': return remotevar(now);	/* only _p allowed */
354219b2ee8SDavid du Colombier 	case     'q': return remotelab(now);
355219b2ee8SDavid du Colombier 	case     'R': return qrecv(now, 0);	/* test only    */
356219b2ee8SDavid du Colombier 	case     LEN: return qlen(now);
357219b2ee8SDavid du Colombier 	case    FULL: return (qfull(now));
358219b2ee8SDavid du Colombier 	case   EMPTY: return (qlen(now)==0);
359219b2ee8SDavid du Colombier 	case   NFULL: return (!qfull(now));
360219b2ee8SDavid du Colombier 	case  NEMPTY: return (qlen(now)>0);
361*7dd7cddfSDavid du Colombier 	case ENABLED: if (s_trail) return 1;
362*7dd7cddfSDavid du Colombier 		      return pc_enabled(now->lft);
363*7dd7cddfSDavid du Colombier 	case    EVAL: return eval(now->lft);
364219b2ee8SDavid du Colombier 	case  PC_VAL: return pc_value(now->lft);
365*7dd7cddfSDavid du Colombier 	case NONPROGRESS: return nonprogress();
366219b2ee8SDavid du Colombier 	case    NAME: return getval(now);
367219b2ee8SDavid du Colombier 
368219b2ee8SDavid du Colombier 	case TIMEOUT: return Tval;
369*7dd7cddfSDavid du Colombier 	case     RUN: return TstOnly?1:enable(now);
370219b2ee8SDavid du Colombier 
371219b2ee8SDavid du Colombier 	case   's': return qsend(now);		/* send         */
372*7dd7cddfSDavid du Colombier 	case   'r': return qrecv(now, 1);	/* receive or poll */
373219b2ee8SDavid du Colombier 	case   'c': return eval(now->lft);	/* condition    */
374*7dd7cddfSDavid du Colombier 	case PRINT: return TstOnly?1:interprint(stdout, now);
375219b2ee8SDavid du Colombier 	case  ASGN: return assign(now);
376219b2ee8SDavid du Colombier 	case ASSERT: if (TstOnly || eval(now->lft)) return 1;
377219b2ee8SDavid du Colombier 		     non_fatal("assertion violated", (char *) 0);
378*7dd7cddfSDavid du Colombier 			printf("spin: text of failed assertion: assert(");
379*7dd7cddfSDavid du Colombier 			comment(stdout, now->lft, 0);
380*7dd7cddfSDavid du Colombier 			printf(")\n");
381*7dd7cddfSDavid du Colombier 		     if (s_trail && !xspin) return 1;
382219b2ee8SDavid du Colombier 		     wrapup(1); /* doesn't return */
383219b2ee8SDavid du Colombier 
384*7dd7cddfSDavid du Colombier 	case  IF: case DO: case BREAK: case UNLESS:	/* compound */
385219b2ee8SDavid du Colombier 	case   '.': return 1;	/* return label for compound */
386219b2ee8SDavid du Colombier 	case   '@': return 0;	/* stop state */
387219b2ee8SDavid du Colombier 	case  ELSE: return 1;	/* only hit here in guided trails */
388219b2ee8SDavid du Colombier 	default   : printf("spin: bad node type %d (run)\n", now->ntyp);
389*7dd7cddfSDavid du Colombier 		    if (s_trail) printf("spin: trail file doesn't match spec?\n");
390219b2ee8SDavid du Colombier 		    fatal("aborting", 0);
391219b2ee8SDavid du Colombier 	}}
392219b2ee8SDavid du Colombier 	return 0;
393219b2ee8SDavid du Colombier }
394219b2ee8SDavid du Colombier 
395219b2ee8SDavid du Colombier int
396*7dd7cddfSDavid du Colombier interprint(FILE *fd, Lextok *n)
397219b2ee8SDavid du Colombier {	Lextok *tmp = n->lft;
398219b2ee8SDavid du Colombier 	char c, *s = n->sym->name;
399*7dd7cddfSDavid du Colombier 	int i, j; char lbuf[16];
400*7dd7cddfSDavid du Colombier 	extern char Buf[];
401*7dd7cddfSDavid du Colombier 	char tBuf[1024];
402219b2ee8SDavid du Colombier 
403*7dd7cddfSDavid du Colombier 	Buf[0] = '\0';
404*7dd7cddfSDavid du Colombier 	if (!no_print)
405*7dd7cddfSDavid du Colombier 	if (!s_trail || depth >= jumpsteps) {
406*7dd7cddfSDavid du Colombier 	for (i = 0; i < (int) strlen(s); i++)
407219b2ee8SDavid du Colombier 		switch (s[i]) {
408219b2ee8SDavid du Colombier 		case '\"': break; /* ignore */
409219b2ee8SDavid du Colombier 		case '\\':
410219b2ee8SDavid du Colombier 			 switch(s[++i]) {
411*7dd7cddfSDavid du Colombier 			 case 't': strcat(Buf, "\t"); break;
412*7dd7cddfSDavid du Colombier 			 case 'n': strcat(Buf, "\n"); break;
413*7dd7cddfSDavid du Colombier 			 default:  goto onechar;
414219b2ee8SDavid du Colombier 			 }
415219b2ee8SDavid du Colombier 			 break;
416219b2ee8SDavid du Colombier 		case  '%':
417219b2ee8SDavid du Colombier 			 if ((c = s[++i]) == '%')
418*7dd7cddfSDavid du Colombier 			 {	strcat(Buf, "%"); /* literal */
419219b2ee8SDavid du Colombier 				break;
420219b2ee8SDavid du Colombier 			 }
421219b2ee8SDavid du Colombier 			 if (!tmp)
422219b2ee8SDavid du Colombier 			 {	non_fatal("too few print args %s", s);
423219b2ee8SDavid du Colombier 				break;
424219b2ee8SDavid du Colombier 			 }
425219b2ee8SDavid du Colombier 			 j = eval(tmp->lft);
426219b2ee8SDavid du Colombier 			 tmp = tmp->rgt;
427219b2ee8SDavid du Colombier 			 switch(c) {
428*7dd7cddfSDavid du Colombier 			 case 'c': sprintf(lbuf, "%c", j); break;
429*7dd7cddfSDavid du Colombier 			 case 'd': sprintf(lbuf, "%d", j); break;
430*7dd7cddfSDavid du Colombier 
431*7dd7cddfSDavid du Colombier 			 case 'e': strcpy(tBuf, Buf);	/* event name */
432*7dd7cddfSDavid du Colombier 				   Buf[0] = '\0';
433*7dd7cddfSDavid du Colombier 				   sr_buf(j, 1);
434*7dd7cddfSDavid du Colombier 				   strcpy(lbuf, Buf);
435*7dd7cddfSDavid du Colombier 				   strcpy(Buf, tBuf);
436*7dd7cddfSDavid du Colombier 				   break;
437*7dd7cddfSDavid du Colombier 
438*7dd7cddfSDavid du Colombier 			 case 'o': sprintf(lbuf, "%o", j); break;
439*7dd7cddfSDavid du Colombier 			 case 'u': sprintf(lbuf, "%u", (unsigned) j); break;
440*7dd7cddfSDavid du Colombier 			 case 'x': sprintf(lbuf, "%x", j); break;
441*7dd7cddfSDavid du Colombier 			 default:  non_fatal("bad print cmd: '%s'", &s[i-1]);
442*7dd7cddfSDavid du Colombier 				   lbuf[0] = '\0'; break;
443*7dd7cddfSDavid du Colombier 			 }
444*7dd7cddfSDavid du Colombier 			 goto append;
445*7dd7cddfSDavid du Colombier 		default:
446*7dd7cddfSDavid du Colombier onechar:		 lbuf[0] = s[i]; lbuf[1] = '\0';
447*7dd7cddfSDavid du Colombier append:			 strcat(Buf, lbuf);
448219b2ee8SDavid du Colombier 			 break;
449219b2ee8SDavid du Colombier 		}
450*7dd7cddfSDavid du Colombier 		dotag(fd, Buf);
451219b2ee8SDavid du Colombier 	}
452*7dd7cddfSDavid du Colombier 	if (strlen(Buf) > 1024) fatal("printf string too long", 0);
453219b2ee8SDavid du Colombier 	return 1;
454219b2ee8SDavid du Colombier }
455219b2ee8SDavid du Colombier 
456*7dd7cddfSDavid du Colombier static int
457219b2ee8SDavid du Colombier Enabled1(Lextok *n)
458219b2ee8SDavid du Colombier {	int i; int v = verbose;
459219b2ee8SDavid du Colombier 
460219b2ee8SDavid du Colombier 	if (n)
461219b2ee8SDavid du Colombier 	switch (n->ntyp) {
462*7dd7cddfSDavid du Colombier 	case 'c':
463*7dd7cddfSDavid du Colombier 		if (has_typ(n->lft, RUN))
464*7dd7cddfSDavid du Colombier 			return 1;	/* conservative */
465*7dd7cddfSDavid du Colombier 		/* else fall through */
466219b2ee8SDavid du Colombier 	default:	/* side-effect free */
467219b2ee8SDavid du Colombier 		verbose = 0;
468*7dd7cddfSDavid du Colombier E_Check++;
469219b2ee8SDavid du Colombier 		i = eval(n);
470*7dd7cddfSDavid du Colombier E_Check--;
471219b2ee8SDavid du Colombier 		verbose = v;
472219b2ee8SDavid du Colombier 		return i;
473219b2ee8SDavid du Colombier 
474*7dd7cddfSDavid du Colombier 	case PRINT: case  ASGN: case ASSERT:
475219b2ee8SDavid du Colombier 		return 1;
476219b2ee8SDavid du Colombier 
477*7dd7cddfSDavid du Colombier 	case 's':
478*7dd7cddfSDavid du Colombier 		if (q_is_sync(n))
479*7dd7cddfSDavid du Colombier 		{	if (Rvous) return 0;
480*7dd7cddfSDavid du Colombier 			TstOnly = 1; verbose = 0;
481*7dd7cddfSDavid du Colombier E_Check++;
482219b2ee8SDavid du Colombier 			i = eval(n);
483*7dd7cddfSDavid du Colombier E_Check--;
484*7dd7cddfSDavid du Colombier 			TstOnly = 0; verbose = v;
485*7dd7cddfSDavid du Colombier 			return i;
486*7dd7cddfSDavid du Colombier 		}
487*7dd7cddfSDavid du Colombier 		return (!qfull(n));
488*7dd7cddfSDavid du Colombier 	case 'r':
489*7dd7cddfSDavid du Colombier 		if (q_is_sync(n))
490*7dd7cddfSDavid du Colombier 			return 0;	/* it's never a user-choice */
491*7dd7cddfSDavid du Colombier 		n->ntyp = 'R'; verbose = 0;
492*7dd7cddfSDavid du Colombier E_Check++;
493*7dd7cddfSDavid du Colombier 		i = eval(n);
494*7dd7cddfSDavid du Colombier E_Check--;
495219b2ee8SDavid du Colombier 		n->ntyp = 'r'; verbose = v;
496219b2ee8SDavid du Colombier 		return i;
497219b2ee8SDavid du Colombier 	}
498219b2ee8SDavid du Colombier 	return 0;
499219b2ee8SDavid du Colombier }
500219b2ee8SDavid du Colombier 
501219b2ee8SDavid du Colombier int
502219b2ee8SDavid du Colombier Enabled0(Element *e)
503219b2ee8SDavid du Colombier {	SeqList *z;
504219b2ee8SDavid du Colombier 
505219b2ee8SDavid du Colombier 	if (!e || !e->n)
506219b2ee8SDavid du Colombier 		return 0;
507219b2ee8SDavid du Colombier 
508219b2ee8SDavid du Colombier 	switch (e->n->ntyp) {
509*7dd7cddfSDavid du Colombier 	case '@':
510*7dd7cddfSDavid du Colombier 		return X->pid == (nproc-nstop-1);
511219b2ee8SDavid du Colombier 	case '.':
512219b2ee8SDavid du Colombier 		return 1;
513219b2ee8SDavid du Colombier 	case GOTO:
514219b2ee8SDavid du Colombier 		if (Rvous) return 0;
515219b2ee8SDavid du Colombier 		return 1;
516219b2ee8SDavid du Colombier 	case UNLESS:
517219b2ee8SDavid du Colombier 		return Enabled0(e->sub->this->frst);
518219b2ee8SDavid du Colombier 	case ATOMIC:
519219b2ee8SDavid du Colombier 	case D_STEP:
520219b2ee8SDavid du Colombier 	case NON_ATOMIC:
521219b2ee8SDavid du Colombier 		return Enabled0(e->n->sl->this->frst);
522219b2ee8SDavid du Colombier 	}
523219b2ee8SDavid du Colombier 	if (e->sub)	/* true for IF, DO, and UNLESS */
524219b2ee8SDavid du Colombier 	{	for (z = e->sub; z; z = z->nxt)
525219b2ee8SDavid du Colombier 			if (Enabled0(z->this->frst))
526219b2ee8SDavid du Colombier 				return 1;
527219b2ee8SDavid du Colombier 		return 0;
528219b2ee8SDavid du Colombier 	}
529219b2ee8SDavid du Colombier 	for (z = e->esc; z; z = z->nxt)
530219b2ee8SDavid du Colombier 	{	if (Enabled0(z->this->frst))
531219b2ee8SDavid du Colombier 			return 1;
532219b2ee8SDavid du Colombier 	}
533*7dd7cddfSDavid du Colombier #if 0
534*7dd7cddfSDavid du Colombier 	printf("enabled1 ");
535*7dd7cddfSDavid du Colombier 	comment(stdout, e->n, 0);
536*7dd7cddfSDavid du Colombier 	printf(" ==> %s\n", Enabled1(e->n)?"yes":"nope");
537*7dd7cddfSDavid du Colombier #endif
538219b2ee8SDavid du Colombier 	return Enabled1(e->n);
539219b2ee8SDavid du Colombier }
540*7dd7cddfSDavid du Colombier 
541*7dd7cddfSDavid du Colombier int
542*7dd7cddfSDavid du Colombier pc_enabled(Lextok *n)
543*7dd7cddfSDavid du Colombier {	int i = nproc - nstop;
544*7dd7cddfSDavid du Colombier 	int pid = eval(n);
545*7dd7cddfSDavid du Colombier 	int result = 0;
546*7dd7cddfSDavid du Colombier 	RunList *Y, *oX;
547*7dd7cddfSDavid du Colombier 
548*7dd7cddfSDavid du Colombier 	for (Y = run; Y; Y = Y->nxt)
549*7dd7cddfSDavid du Colombier 		if (--i == pid)
550*7dd7cddfSDavid du Colombier 		{	oX = X; X = Y;
551*7dd7cddfSDavid du Colombier 			result = Enabled0(Y->pc);
552*7dd7cddfSDavid du Colombier 			X = oX;
553*7dd7cddfSDavid du Colombier 			break;
554*7dd7cddfSDavid du Colombier 		}
555*7dd7cddfSDavid du Colombier 	return result;
556*7dd7cddfSDavid du Colombier }
557