xref: /plan9/sys/src/cmd/spin/dstep.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier /***** spin: dstep.c *****/
2*219b2ee8SDavid du Colombier 
3*219b2ee8SDavid du Colombier /* Copyright (c) 1991,1995 by AT&T Corporation.  All Rights Reserved.     */
4*219b2ee8SDavid du Colombier /* This software is for educational purposes only.                        */
5*219b2ee8SDavid du Colombier /* Permission is given to distribute this code provided that this intro-  */
6*219b2ee8SDavid du Colombier /* ductory message is not removed and no monies are exchanged.            */
7*219b2ee8SDavid du Colombier /* No guarantee is expressed or implied by the distribution of this code. */
8*219b2ee8SDavid du Colombier /* Software written by Gerard J. Holzmann as part of the book:            */
9*219b2ee8SDavid du Colombier /* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
10*219b2ee8SDavid du Colombier /* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
11*219b2ee8SDavid du Colombier /* Send bug-reports and/or questions to: gerard@research.att.com          */
12*219b2ee8SDavid du Colombier 
13*219b2ee8SDavid du Colombier #include "spin.h"
14*219b2ee8SDavid du Colombier #include "y.tab.h"
15*219b2ee8SDavid du Colombier 
16*219b2ee8SDavid du Colombier char	*NextLab[64];
17*219b2ee8SDavid du Colombier int	Level=0, GenCode=0, IsGuard=0, TestOnly=0;
18*219b2ee8SDavid du Colombier int	Tj=0, Jt=0, LastGoto=0;
19*219b2ee8SDavid du Colombier int	Tojump[512], Jumpto[512], Special[512];
20*219b2ee8SDavid du Colombier 
21*219b2ee8SDavid du Colombier void
22*219b2ee8SDavid du Colombier Sourced(int n, int special)
23*219b2ee8SDavid du Colombier {	int i;
24*219b2ee8SDavid du Colombier 	for (i = 0; i < Tj; i++)
25*219b2ee8SDavid du Colombier 		if (Tojump[i] == n)
26*219b2ee8SDavid du Colombier 			return;
27*219b2ee8SDavid du Colombier 	Special[Tj] = special;
28*219b2ee8SDavid du Colombier 	Tojump[Tj++] = n;
29*219b2ee8SDavid du Colombier }
30*219b2ee8SDavid du Colombier 
31*219b2ee8SDavid du Colombier void
32*219b2ee8SDavid du Colombier Dested(int n)
33*219b2ee8SDavid du Colombier {	int i;
34*219b2ee8SDavid du Colombier 
35*219b2ee8SDavid du Colombier 	LastGoto = 1;
36*219b2ee8SDavid du Colombier 	for (i = 0; i < Tj; i++)
37*219b2ee8SDavid du Colombier 		if (Tojump[i] == n)
38*219b2ee8SDavid du Colombier 			return;
39*219b2ee8SDavid du Colombier 	for (i = 0; i < Jt; i++)
40*219b2ee8SDavid du Colombier 		if (Jumpto[i] == n)
41*219b2ee8SDavid du Colombier 			return;
42*219b2ee8SDavid du Colombier 	Jumpto[Jt++] = n;
43*219b2ee8SDavid du Colombier }
44*219b2ee8SDavid du Colombier 
45*219b2ee8SDavid du Colombier void
46*219b2ee8SDavid du Colombier Mopup(FILE *fd)
47*219b2ee8SDavid du Colombier {	int i, j;
48*219b2ee8SDavid du Colombier 	for (i = 0; i < Jt; i++)
49*219b2ee8SDavid du Colombier 	{	for (j = 0; j < Tj; j++)
50*219b2ee8SDavid du Colombier 		{	if (Tojump[j] == Jumpto[i])
51*219b2ee8SDavid du Colombier 				break;
52*219b2ee8SDavid du Colombier 		}
53*219b2ee8SDavid du Colombier 		if (j == Tj)
54*219b2ee8SDavid du Colombier 		{	char buf[12];
55*219b2ee8SDavid du Colombier 			sprintf(buf, "S_%.3d_0", Jumpto[i]);
56*219b2ee8SDavid du Colombier 			non_fatal("goto %s breaks from d_step seq", buf);
57*219b2ee8SDavid du Colombier 	}	}
58*219b2ee8SDavid du Colombier 	for (j = 0; j < Tj; j++)
59*219b2ee8SDavid du Colombier 	{	for (i = 0; i < Jt; i++)
60*219b2ee8SDavid du Colombier 		{	if (Tojump[j] == Jumpto[i])
61*219b2ee8SDavid du Colombier 				break;
62*219b2ee8SDavid du Colombier 		}
63*219b2ee8SDavid du Colombier #ifdef DEBUG
64*219b2ee8SDavid du Colombier 		if (i == Jt && !Special[i])
65*219b2ee8SDavid du Colombier 		{	fprintf(fd, "\t\t/* >>no goto's for S_%.3d_0<< */\n",
66*219b2ee8SDavid du Colombier 			Tojump[j]);
67*219b2ee8SDavid du Colombier 		}
68*219b2ee8SDavid du Colombier #endif
69*219b2ee8SDavid du Colombier 	}
70*219b2ee8SDavid du Colombier 	for (j = i = 0; j < Tj; j++)
71*219b2ee8SDavid du Colombier 	{	if (Special[j])
72*219b2ee8SDavid du Colombier 		{	Tojump[i] = Tojump[j];
73*219b2ee8SDavid du Colombier 			Special[i] = 2;
74*219b2ee8SDavid du Colombier 			i++;
75*219b2ee8SDavid du Colombier 	}	}
76*219b2ee8SDavid du Colombier 	Tj = i;	/* keep only the global exit-labels */
77*219b2ee8SDavid du Colombier 	Jt = 0;
78*219b2ee8SDavid du Colombier }
79*219b2ee8SDavid du Colombier 
80*219b2ee8SDavid du Colombier int
81*219b2ee8SDavid du Colombier FirstTime(int n)
82*219b2ee8SDavid du Colombier {	int i;
83*219b2ee8SDavid du Colombier 	for (i = 0; i < Tj; i++)
84*219b2ee8SDavid du Colombier 		if (Tojump[i] == n)
85*219b2ee8SDavid du Colombier 			return (Special[i] <= 1);
86*219b2ee8SDavid du Colombier 	return 1;
87*219b2ee8SDavid du Colombier }
88*219b2ee8SDavid du Colombier 
89*219b2ee8SDavid du Colombier void
90*219b2ee8SDavid du Colombier illegal(Element *e, char *str)
91*219b2ee8SDavid du Colombier {
92*219b2ee8SDavid du Colombier 	printf("illegal operator in 'step:' '");
93*219b2ee8SDavid du Colombier 	comment(stdout, e->n, 0);
94*219b2ee8SDavid du Colombier 	printf("'\n");
95*219b2ee8SDavid du Colombier 	fatal("saw %s", str);
96*219b2ee8SDavid du Colombier }
97*219b2ee8SDavid du Colombier 
98*219b2ee8SDavid du Colombier void
99*219b2ee8SDavid du Colombier filterbad(Element *e)
100*219b2ee8SDavid du Colombier {
101*219b2ee8SDavid du Colombier 	switch (e->n->ntyp) {
102*219b2ee8SDavid du Colombier 	case ASSERT:
103*219b2ee8SDavid du Colombier 	case PRINT:
104*219b2ee8SDavid du Colombier 	case 'c':
105*219b2ee8SDavid du Colombier 		/* run cannot be completely undone
106*219b2ee8SDavid du Colombier 		 * with sv_save-sv_restor
107*219b2ee8SDavid du Colombier 		 */
108*219b2ee8SDavid du Colombier 		if (any_oper(e->n->lft, RUN))
109*219b2ee8SDavid du Colombier 			illegal(e, "run operator");
110*219b2ee8SDavid du Colombier 		break;
111*219b2ee8SDavid du Colombier 	case '@':
112*219b2ee8SDavid du Colombier 		illegal(e, "process termination");
113*219b2ee8SDavid du Colombier 		break;
114*219b2ee8SDavid du Colombier 	case D_STEP:
115*219b2ee8SDavid du Colombier 		illegal(e, "nested d_step sequence");
116*219b2ee8SDavid du Colombier 		break;
117*219b2ee8SDavid du Colombier 	case ATOMIC:
118*219b2ee8SDavid du Colombier 		illegal(e, "nested atomic sequence");
119*219b2ee8SDavid du Colombier 		break;
120*219b2ee8SDavid du Colombier 	default:
121*219b2ee8SDavid du Colombier 		break;
122*219b2ee8SDavid du Colombier 	}
123*219b2ee8SDavid du Colombier }
124*219b2ee8SDavid du Colombier 
125*219b2ee8SDavid du Colombier int
126*219b2ee8SDavid du Colombier CollectGuards(FILE *fd, Element *e, int inh)
127*219b2ee8SDavid du Colombier {	SeqList *h; Element *ee;
128*219b2ee8SDavid du Colombier 
129*219b2ee8SDavid du Colombier 	for (h = e->sub; h; h = h->nxt)
130*219b2ee8SDavid du Colombier 	{	ee = huntstart(h->this->frst);
131*219b2ee8SDavid du Colombier 		filterbad(ee);
132*219b2ee8SDavid du Colombier 		switch (ee->n->ntyp) {
133*219b2ee8SDavid du Colombier 		case  IF:
134*219b2ee8SDavid du Colombier 			inh += CollectGuards(fd, ee, inh);
135*219b2ee8SDavid du Colombier 			break;
136*219b2ee8SDavid du Colombier 		case '.':
137*219b2ee8SDavid du Colombier 			if (ee->nxt->n->ntyp == DO)
138*219b2ee8SDavid du Colombier 				inh += CollectGuards(fd, ee->nxt, inh);
139*219b2ee8SDavid du Colombier 			break;
140*219b2ee8SDavid du Colombier 		case ELSE:
141*219b2ee8SDavid du Colombier 			if (inh++ > 0) fprintf(fd, " || ");
142*219b2ee8SDavid du Colombier 			fprintf(fd, "(1 /* else */)");
143*219b2ee8SDavid du Colombier 			break;
144*219b2ee8SDavid du Colombier 		case 'c':
145*219b2ee8SDavid du Colombier 			if (inh++ > 0) fprintf(fd, " || ");
146*219b2ee8SDavid du Colombier 			fprintf(fd, "("); TestOnly=1;
147*219b2ee8SDavid du Colombier 			putstmnt(fd, ee->n->lft, e->seqno);
148*219b2ee8SDavid du Colombier 			fprintf(fd, ")"); TestOnly=0;
149*219b2ee8SDavid du Colombier 			break;
150*219b2ee8SDavid du Colombier 		}
151*219b2ee8SDavid du Colombier 	}
152*219b2ee8SDavid du Colombier 	return inh;
153*219b2ee8SDavid du Colombier }
154*219b2ee8SDavid du Colombier 
155*219b2ee8SDavid du Colombier int
156*219b2ee8SDavid du Colombier putcode(FILE *fd, Sequence *s, Element *nxt, int justguards)
157*219b2ee8SDavid du Colombier {	int isg=0;
158*219b2ee8SDavid du Colombier 
159*219b2ee8SDavid du Colombier 	NextLab[0] = "continue";
160*219b2ee8SDavid du Colombier 
161*219b2ee8SDavid du Colombier 	filterbad(s->frst);
162*219b2ee8SDavid du Colombier 
163*219b2ee8SDavid du Colombier 	switch (s->frst->n->ntyp) {
164*219b2ee8SDavid du Colombier 	case UNLESS:
165*219b2ee8SDavid du Colombier 		non_fatal("'unless' inside d_step - ignored", (char *) 0);
166*219b2ee8SDavid du Colombier 		return putcode(fd, s->frst->n->sl->this, nxt, 0);
167*219b2ee8SDavid du Colombier 	case NON_ATOMIC:
168*219b2ee8SDavid du Colombier 		(void) putcode(fd, s->frst->n->sl->this, ZE, 1);
169*219b2ee8SDavid du Colombier 		break;
170*219b2ee8SDavid du Colombier 	case IF:
171*219b2ee8SDavid du Colombier 		fprintf(fd, "if (!(");
172*219b2ee8SDavid du Colombier 		if (!CollectGuards(fd, s->frst, 0))
173*219b2ee8SDavid du Colombier 			fprintf(fd, "1");
174*219b2ee8SDavid du Colombier 		fprintf(fd, "))\n\t\t\tcontinue;");
175*219b2ee8SDavid du Colombier 		isg = 1;
176*219b2ee8SDavid du Colombier 		break;
177*219b2ee8SDavid du Colombier 	case '.':
178*219b2ee8SDavid du Colombier 		if (s->frst->nxt->n->ntyp == DO)
179*219b2ee8SDavid du Colombier 		{	fprintf(fd, "if (!(");
180*219b2ee8SDavid du Colombier 			if (!CollectGuards(fd, s->frst->nxt, 0))
181*219b2ee8SDavid du Colombier 				fprintf(fd, "1");
182*219b2ee8SDavid du Colombier 			fprintf(fd, "))\n\t\t\tcontinue;");
183*219b2ee8SDavid du Colombier 			isg = 1;
184*219b2ee8SDavid du Colombier 		}
185*219b2ee8SDavid du Colombier 		break;
186*219b2ee8SDavid du Colombier 	case 'R':
187*219b2ee8SDavid du Colombier 	case 'r':
188*219b2ee8SDavid du Colombier 	case 's':
189*219b2ee8SDavid du Colombier 		fprintf(fd, "if (!("); TestOnly=1;
190*219b2ee8SDavid du Colombier 		putstmnt(fd, s->frst->n, s->frst->seqno);
191*219b2ee8SDavid du Colombier 		fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
192*219b2ee8SDavid du Colombier 		break;
193*219b2ee8SDavid du Colombier 	case 'c':
194*219b2ee8SDavid du Colombier 		fprintf(fd, "if (!("); TestOnly=1;
195*219b2ee8SDavid du Colombier 		putstmnt(fd, s->frst->n->lft, s->frst->seqno);
196*219b2ee8SDavid du Colombier 		fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
197*219b2ee8SDavid du Colombier 		break;
198*219b2ee8SDavid du Colombier 	}
199*219b2ee8SDavid du Colombier 	if (justguards) return 0;
200*219b2ee8SDavid du Colombier 
201*219b2ee8SDavid du Colombier 	fprintf(fd, "\n#if defined(FULLSTACK) && defined(NOCOMP)\n");
202*219b2ee8SDavid du Colombier 	fprintf(fd, "\t\tif (t->atom&2)\n");
203*219b2ee8SDavid du Colombier 	fprintf(fd, "#endif\n");
204*219b2ee8SDavid du Colombier 	fprintf(fd, "\t\tsv_save((char *)&now);\n");
205*219b2ee8SDavid du Colombier 	putCode(fd, s->frst, s->extent, nxt, isg);
206*219b2ee8SDavid du Colombier 
207*219b2ee8SDavid du Colombier 	if (nxt)
208*219b2ee8SDavid du Colombier 	{	if (FirstTime(nxt->Seqno)
209*219b2ee8SDavid du Colombier 		&& (!(nxt->status & DONE2) || !(nxt->status & D_ATOM)))
210*219b2ee8SDavid du Colombier 		{	fprintf(fd, "S_%.3d_0: /* 1 */\n", nxt->Seqno);
211*219b2ee8SDavid du Colombier 			nxt->status |= DONE2;
212*219b2ee8SDavid du Colombier 			LastGoto = 0;
213*219b2ee8SDavid du Colombier 		}
214*219b2ee8SDavid du Colombier 		Sourced(nxt->Seqno, 1);
215*219b2ee8SDavid du Colombier 		Mopup(fd);
216*219b2ee8SDavid du Colombier 	}
217*219b2ee8SDavid du Colombier 	unskip(s->frst->seqno);
218*219b2ee8SDavid du Colombier 	return LastGoto;
219*219b2ee8SDavid du Colombier }
220*219b2ee8SDavid du Colombier 
221*219b2ee8SDavid du Colombier void
222*219b2ee8SDavid du Colombier putCode(FILE *fd, Element *f, Element *last, Element *next, int isguard)
223*219b2ee8SDavid du Colombier {	Element *e, *N;
224*219b2ee8SDavid du Colombier 	SeqList *h; int i;
225*219b2ee8SDavid du Colombier 	char NextOpt[32];
226*219b2ee8SDavid du Colombier 
227*219b2ee8SDavid du Colombier 	for (e = f; e; e = e->nxt)
228*219b2ee8SDavid du Colombier 	{	if (e->status & DONE2)
229*219b2ee8SDavid du Colombier 			continue;
230*219b2ee8SDavid du Colombier 		e->status |= DONE2;
231*219b2ee8SDavid du Colombier 
232*219b2ee8SDavid du Colombier 		if (!(e->status & D_ATOM))
233*219b2ee8SDavid du Colombier 		{	if (!LastGoto)
234*219b2ee8SDavid du Colombier 			{	fprintf(fd, "\t\tgoto S_%.3d_0;\n", e->Seqno);
235*219b2ee8SDavid du Colombier 				Dested(e->Seqno);
236*219b2ee8SDavid du Colombier 			}
237*219b2ee8SDavid du Colombier 			break;
238*219b2ee8SDavid du Colombier 		}
239*219b2ee8SDavid du Colombier 		fprintf(fd, "S_%.3d_0: /* 2 */\n", e->Seqno);
240*219b2ee8SDavid du Colombier 		Sourced(e->Seqno, 0);
241*219b2ee8SDavid du Colombier 
242*219b2ee8SDavid du Colombier 		if (!e->sub)
243*219b2ee8SDavid du Colombier 		{	filterbad(e);
244*219b2ee8SDavid du Colombier 			switch (e->n->ntyp) {
245*219b2ee8SDavid du Colombier 			case NON_ATOMIC:
246*219b2ee8SDavid du Colombier 				h = e->n->sl;
247*219b2ee8SDavid du Colombier 				putCode(fd, h->this->frst, h->this->extent, e->nxt, 0);
248*219b2ee8SDavid du Colombier 				break;
249*219b2ee8SDavid du Colombier 			case BREAK:
250*219b2ee8SDavid du Colombier 				if (LastGoto) break;
251*219b2ee8SDavid du Colombier 				i = target(huntele(e->nxt, e->status))->Seqno;
252*219b2ee8SDavid du Colombier 				fprintf(fd, "\t\tgoto S_%.3d_0;	/* 'break' */\n", i);
253*219b2ee8SDavid du Colombier 				Dested(i);
254*219b2ee8SDavid du Colombier 				break;
255*219b2ee8SDavid du Colombier 			case GOTO:
256*219b2ee8SDavid du Colombier 				if (LastGoto) break;
257*219b2ee8SDavid du Colombier 				i = huntele(get_lab(e->n,1), e->status)->Seqno;
258*219b2ee8SDavid du Colombier 				fprintf(fd, "\t\tgoto S_%.3d_0;	/* 'goto' */\n", i);
259*219b2ee8SDavid du Colombier 				Dested(i);
260*219b2ee8SDavid du Colombier 				break;
261*219b2ee8SDavid du Colombier 			case '.':
262*219b2ee8SDavid du Colombier 				if (LastGoto) break;
263*219b2ee8SDavid du Colombier 				if (e->nxt->status & DONE2)
264*219b2ee8SDavid du Colombier 				{	i = e->nxt?e->nxt->Seqno:0;
265*219b2ee8SDavid du Colombier 					fprintf(fd, "\t\tgoto S_%.3d_0;	/* '.' */\n", i);
266*219b2ee8SDavid du Colombier 					Dested(i);
267*219b2ee8SDavid du Colombier 				}
268*219b2ee8SDavid du Colombier 				break;
269*219b2ee8SDavid du Colombier 			default:
270*219b2ee8SDavid du Colombier 				putskip(e->seqno);
271*219b2ee8SDavid du Colombier 				GenCode = 1; IsGuard = isguard;
272*219b2ee8SDavid du Colombier 				fprintf(fd, "\t\t");
273*219b2ee8SDavid du Colombier 				putstmnt(fd, e->n, e->seqno);
274*219b2ee8SDavid du Colombier 				fprintf(fd, ";\n");
275*219b2ee8SDavid du Colombier 				GenCode = IsGuard = isguard = LastGoto = 0;
276*219b2ee8SDavid du Colombier 				if (e->n->ntyp == ELSE)
277*219b2ee8SDavid du Colombier 					LastGoto = 1;
278*219b2ee8SDavid du Colombier 				break;
279*219b2ee8SDavid du Colombier 			}
280*219b2ee8SDavid du Colombier 			i = e->nxt?e->nxt->Seqno:0;
281*219b2ee8SDavid du Colombier 			if (e->nxt && e->nxt->status & DONE2 && !LastGoto)
282*219b2ee8SDavid du Colombier 			{	fprintf(fd, "\t\tgoto S_%.3d_0; /* ';' */\n", i);
283*219b2ee8SDavid du Colombier 				Dested(i);
284*219b2ee8SDavid du Colombier 				break;
285*219b2ee8SDavid du Colombier 			}
286*219b2ee8SDavid du Colombier 		} else
287*219b2ee8SDavid du Colombier 		{	for (h = e->sub, i=1; h; h = h->nxt, i++)
288*219b2ee8SDavid du Colombier 			{	sprintf(NextOpt, "goto S_%.3d_%d", e->Seqno, i);
289*219b2ee8SDavid du Colombier 				NextLab[++Level] = NextOpt;
290*219b2ee8SDavid du Colombier 				N = (e->n->ntyp == DO) ? e : e->nxt;
291*219b2ee8SDavid du Colombier 				putCode(fd, h->this->frst, h->this->extent, N, 1);
292*219b2ee8SDavid du Colombier 				Level--;
293*219b2ee8SDavid du Colombier 				fprintf(fd, "%s: /* 3 */\n", &NextOpt[5]);
294*219b2ee8SDavid du Colombier 			}
295*219b2ee8SDavid du Colombier 			if (!LastGoto)
296*219b2ee8SDavid du Colombier 			{	fprintf(fd, "\t\tUerror(\"blocking sel in d_step\");\n");
297*219b2ee8SDavid du Colombier 				LastGoto = 0;
298*219b2ee8SDavid du Colombier 			}
299*219b2ee8SDavid du Colombier 		}
300*219b2ee8SDavid du Colombier 		if (e == last)
301*219b2ee8SDavid du Colombier 		{	if (!LastGoto && next)
302*219b2ee8SDavid du Colombier 			{	fprintf(fd, "\t\tgoto S_%.3d_0;\n", next->Seqno);
303*219b2ee8SDavid du Colombier 				Dested(next->Seqno);
304*219b2ee8SDavid du Colombier 			}
305*219b2ee8SDavid du Colombier 			break;
306*219b2ee8SDavid du Colombier 	}	}
307*219b2ee8SDavid du Colombier }
308