xref: /plan9-contrib/sys/src/cmd/spin/flow.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier /***** spin: flow.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 Element *Al_El = ZE;
17*219b2ee8SDavid du Colombier Label	*labtab = (Label *) 0;
18*219b2ee8SDavid du Colombier Lbreak	*breakstack = (Lbreak *) 0;
19*219b2ee8SDavid du Colombier Lextok	*innermost;
20*219b2ee8SDavid du Colombier SeqList	*cur_s = (SeqList *) 0;
21*219b2ee8SDavid du Colombier int	Elcnt=0, Unique=0, break_id=0;
22*219b2ee8SDavid du Colombier int	DstepStart = -1;
23*219b2ee8SDavid du Colombier 
24*219b2ee8SDavid du Colombier extern Symbol	*Fname;
25*219b2ee8SDavid du Colombier extern int	lineno, has_unless;
26*219b2ee8SDavid du Colombier 
27*219b2ee8SDavid du Colombier void
28*219b2ee8SDavid du Colombier open_seq(int top)
29*219b2ee8SDavid du Colombier {	SeqList *t;
30*219b2ee8SDavid du Colombier 	Sequence *s = (Sequence *) emalloc(sizeof(Sequence));
31*219b2ee8SDavid du Colombier 
32*219b2ee8SDavid du Colombier 	t = seqlist(s, cur_s);
33*219b2ee8SDavid du Colombier 	cur_s = t;
34*219b2ee8SDavid du Colombier 	if (top) Elcnt = 1;
35*219b2ee8SDavid du Colombier }
36*219b2ee8SDavid du Colombier 
37*219b2ee8SDavid du Colombier void
38*219b2ee8SDavid du Colombier rem_Seq(void)
39*219b2ee8SDavid du Colombier {
40*219b2ee8SDavid du Colombier 	DstepStart = Unique;
41*219b2ee8SDavid du Colombier }
42*219b2ee8SDavid du Colombier 
43*219b2ee8SDavid du Colombier void
44*219b2ee8SDavid du Colombier unrem_Seq(void)
45*219b2ee8SDavid du Colombier {
46*219b2ee8SDavid du Colombier 	DstepStart = -1;
47*219b2ee8SDavid du Colombier }
48*219b2ee8SDavid du Colombier 
49*219b2ee8SDavid du Colombier int
50*219b2ee8SDavid du Colombier Rjumpslocal(Element *q, Element *stop)
51*219b2ee8SDavid du Colombier {	Element *lb, *f;
52*219b2ee8SDavid du Colombier 	SeqList *h;
53*219b2ee8SDavid du Colombier 
54*219b2ee8SDavid du Colombier 	/* allow no jumps out of a d_step sequence */
55*219b2ee8SDavid du Colombier 	for (f = q; f && f != stop; f = f->nxt)
56*219b2ee8SDavid du Colombier 	{	if (f && f->n && f->n->ntyp == GOTO)
57*219b2ee8SDavid du Colombier 		{	lb = get_lab(f->n, 0);
58*219b2ee8SDavid du Colombier 			if (!lb || lb->Seqno < DstepStart)
59*219b2ee8SDavid du Colombier 			{	lineno = f->n->ln;
60*219b2ee8SDavid du Colombier 				Fname = f->n->fn;
61*219b2ee8SDavid du Colombier 				return 0;
62*219b2ee8SDavid du Colombier 		}	}
63*219b2ee8SDavid du Colombier 		for (h = f->sub; h; h = h->nxt)
64*219b2ee8SDavid du Colombier 		{	if (!Rjumpslocal(h->this->frst, h->this->last))
65*219b2ee8SDavid du Colombier 				return 0;
66*219b2ee8SDavid du Colombier 
67*219b2ee8SDavid du Colombier 	}	}
68*219b2ee8SDavid du Colombier 	return 1;
69*219b2ee8SDavid du Colombier }
70*219b2ee8SDavid du Colombier 
71*219b2ee8SDavid du Colombier void
72*219b2ee8SDavid du Colombier cross_dsteps(Lextok *a, Lextok *b)
73*219b2ee8SDavid du Colombier {
74*219b2ee8SDavid du Colombier 	if (a && b
75*219b2ee8SDavid du Colombier 	&&  a->indstep != b->indstep)
76*219b2ee8SDavid du Colombier 	{	lineno = a->ln;
77*219b2ee8SDavid du Colombier 		Fname  = a->fn;
78*219b2ee8SDavid du Colombier 		fatal("jump into d_step sequence", (char *) 0);
79*219b2ee8SDavid du Colombier 	}
80*219b2ee8SDavid du Colombier }
81*219b2ee8SDavid du Colombier 
82*219b2ee8SDavid du Colombier Sequence *
83*219b2ee8SDavid du Colombier close_seq(int nottop)
84*219b2ee8SDavid du Colombier {	Sequence *s = cur_s->this;
85*219b2ee8SDavid du Colombier 	Symbol *z;
86*219b2ee8SDavid du Colombier 
87*219b2ee8SDavid du Colombier 	if (nottop > 0 && (z = has_lab(s->frst)))
88*219b2ee8SDavid du Colombier 	{	printf("error: (%s:%d) label %s placed incorrectly\n",
89*219b2ee8SDavid du Colombier 			(s->frst->n)?s->frst->n->fn->name:"-",
90*219b2ee8SDavid du Colombier 			(s->frst->n)?s->frst->n->ln:0,
91*219b2ee8SDavid du Colombier 			z->name);
92*219b2ee8SDavid du Colombier 		switch (nottop) {
93*219b2ee8SDavid du Colombier 		case 1:
94*219b2ee8SDavid du Colombier 			printf("=====> stmnt unless Label: stmnt\n");
95*219b2ee8SDavid du Colombier 			printf("sorry, cannot jump to the guard of an\n");
96*219b2ee8SDavid du Colombier 			printf("escape (it is not a unique state)\n");
97*219b2ee8SDavid du Colombier 			break;
98*219b2ee8SDavid du Colombier 		case 2:
99*219b2ee8SDavid du Colombier 			printf("=====> instead of  ");
100*219b2ee8SDavid du Colombier 			printf("\"Label: stmnt unless stmnt\"\n");
101*219b2ee8SDavid du Colombier 			printf("=====> always use  ");
102*219b2ee8SDavid du Colombier 			printf("\"Label: { stmnt unless stmnt }\"\n");
103*219b2ee8SDavid du Colombier 			break;
104*219b2ee8SDavid du Colombier 		case 3:
105*219b2ee8SDavid du Colombier 			printf("=====> instead of  ");
106*219b2ee8SDavid du Colombier 			printf("\"atomic { Label: statement ... }\"\n");
107*219b2ee8SDavid du Colombier 			printf("=====> always use  ");
108*219b2ee8SDavid du Colombier 			printf("\"Label: atomic { statement ... }\"\n");
109*219b2ee8SDavid du Colombier 			break;
110*219b2ee8SDavid du Colombier 		case 4:
111*219b2ee8SDavid du Colombier 			printf("=====> instead of  ");
112*219b2ee8SDavid du Colombier 			printf("\"d_step { Label: statement ... }\"\n");
113*219b2ee8SDavid du Colombier 			printf("=====> always use  ");
114*219b2ee8SDavid du Colombier 			printf("\"Label: d_step { statement ... }\"\n");
115*219b2ee8SDavid du Colombier 			break;
116*219b2ee8SDavid du Colombier 		case 5:
117*219b2ee8SDavid du Colombier 			printf("=====> instead of  ");
118*219b2ee8SDavid du Colombier 			printf("\"{ Label: statement ... }\"\n");
119*219b2ee8SDavid du Colombier 			printf("=====> always use  ");
120*219b2ee8SDavid du Colombier 			printf("\"Label: { statement ... }\"\n");
121*219b2ee8SDavid du Colombier 			break;
122*219b2ee8SDavid du Colombier 		case 6:
123*219b2ee8SDavid du Colombier 			printf("=====>instead of\n");
124*219b2ee8SDavid du Colombier 			printf("	do (or if)\n");
125*219b2ee8SDavid du Colombier 			printf("	:: ...\n");
126*219b2ee8SDavid du Colombier 			printf("	:: Label: statement\n");
127*219b2ee8SDavid du Colombier 			printf("	od (of fi)\n");
128*219b2ee8SDavid du Colombier 			printf("=====>always use\n");
129*219b2ee8SDavid du Colombier 			printf("Label:	do (or if)\n");
130*219b2ee8SDavid du Colombier 			printf("	:: ...\n");
131*219b2ee8SDavid du Colombier 			printf("	:: statement\n");
132*219b2ee8SDavid du Colombier 			printf("	od (or fi)\n");
133*219b2ee8SDavid du Colombier 			break;
134*219b2ee8SDavid du Colombier 		case 7:
135*219b2ee8SDavid du Colombier 			printf("cannot happen - labels\n");
136*219b2ee8SDavid du Colombier 			break;
137*219b2ee8SDavid du Colombier 		}
138*219b2ee8SDavid du Colombier 		exit(1);
139*219b2ee8SDavid du Colombier 	}
140*219b2ee8SDavid du Colombier 
141*219b2ee8SDavid du Colombier 	if (nottop == 4
142*219b2ee8SDavid du Colombier 	&& !Rjumpslocal(s->frst, s->last))
143*219b2ee8SDavid du Colombier 		fatal("non_local jump in d_step sequence", (char *) 0);
144*219b2ee8SDavid du Colombier 
145*219b2ee8SDavid du Colombier 	cur_s = cur_s->nxt;
146*219b2ee8SDavid du Colombier 	s->maxel = Elcnt;
147*219b2ee8SDavid du Colombier 	s->extent = s->last;
148*219b2ee8SDavid du Colombier 	return s;
149*219b2ee8SDavid du Colombier }
150*219b2ee8SDavid du Colombier 
151*219b2ee8SDavid du Colombier Lextok *
152*219b2ee8SDavid du Colombier do_unless(Lextok *No, Lextok *Es)
153*219b2ee8SDavid du Colombier {	SeqList *Sl;
154*219b2ee8SDavid du Colombier 	Lextok *Re = nn(ZN, UNLESS, ZN, ZN);
155*219b2ee8SDavid du Colombier 	Re->ln = No->ln;
156*219b2ee8SDavid du Colombier 	Re->fn = No->fn;
157*219b2ee8SDavid du Colombier 
158*219b2ee8SDavid du Colombier 	has_unless++;
159*219b2ee8SDavid du Colombier 	if (Es->ntyp == NON_ATOMIC)
160*219b2ee8SDavid du Colombier 		Sl = Es->sl;
161*219b2ee8SDavid du Colombier 	else
162*219b2ee8SDavid du Colombier 	{	open_seq(0); add_seq(Es);
163*219b2ee8SDavid du Colombier 		Sl = seqlist(close_seq(1), 0);
164*219b2ee8SDavid du Colombier 	}
165*219b2ee8SDavid du Colombier 
166*219b2ee8SDavid du Colombier 	if (No->ntyp == NON_ATOMIC)
167*219b2ee8SDavid du Colombier 	{	No->sl->nxt = Sl;
168*219b2ee8SDavid du Colombier 		Sl = No->sl;
169*219b2ee8SDavid du Colombier 	} else	if (No->ntyp == ':'
170*219b2ee8SDavid du Colombier 		&& (No->lft->ntyp == NON_ATOMIC
171*219b2ee8SDavid du Colombier 		||  No->lft->ntyp == ATOMIC
172*219b2ee8SDavid du Colombier 		||  No->lft->ntyp == D_STEP))
173*219b2ee8SDavid du Colombier 	{
174*219b2ee8SDavid du Colombier 		int tok = No->lft->ntyp;
175*219b2ee8SDavid du Colombier 
176*219b2ee8SDavid du Colombier 		No->lft->sl->nxt = Sl;
177*219b2ee8SDavid du Colombier 		Re->sl = No->lft->sl;
178*219b2ee8SDavid du Colombier 
179*219b2ee8SDavid du Colombier 		open_seq(0); add_seq(Re);
180*219b2ee8SDavid du Colombier 		Re = nn(ZN, tok, ZN, ZN);
181*219b2ee8SDavid du Colombier 		Re->sl = seqlist(close_seq(7), 0);
182*219b2ee8SDavid du Colombier 		Re->ln = No->ln;
183*219b2ee8SDavid du Colombier 		Re->fn = No->fn;
184*219b2ee8SDavid du Colombier 
185*219b2ee8SDavid du Colombier 		Re = nn(No, ':', Re, ZN);	/* lift label */
186*219b2ee8SDavid du Colombier 		Re->ln = No->ln;
187*219b2ee8SDavid du Colombier 		Re->fn = No->fn;
188*219b2ee8SDavid du Colombier 		return Re;
189*219b2ee8SDavid du Colombier 	} else
190*219b2ee8SDavid du Colombier 	{	open_seq(0); add_seq(No);
191*219b2ee8SDavid du Colombier 		Sl = seqlist(close_seq(2), Sl);
192*219b2ee8SDavid du Colombier 	}
193*219b2ee8SDavid du Colombier 
194*219b2ee8SDavid du Colombier 	Re->sl = Sl;
195*219b2ee8SDavid du Colombier 	return Re;
196*219b2ee8SDavid du Colombier }
197*219b2ee8SDavid du Colombier 
198*219b2ee8SDavid du Colombier SeqList *
199*219b2ee8SDavid du Colombier seqlist(Sequence *s, SeqList *r)
200*219b2ee8SDavid du Colombier {	SeqList *t = (SeqList *) emalloc(sizeof(SeqList));
201*219b2ee8SDavid du Colombier 
202*219b2ee8SDavid du Colombier 	t->this = s;
203*219b2ee8SDavid du Colombier 	t->nxt = r;
204*219b2ee8SDavid du Colombier 	return t;
205*219b2ee8SDavid du Colombier }
206*219b2ee8SDavid du Colombier 
207*219b2ee8SDavid du Colombier Element *
208*219b2ee8SDavid du Colombier new_el(Lextok *n)
209*219b2ee8SDavid du Colombier {	Element *m;
210*219b2ee8SDavid du Colombier 
211*219b2ee8SDavid du Colombier 	if (n)
212*219b2ee8SDavid du Colombier 	{	if (n->ntyp == IF || n->ntyp == DO)
213*219b2ee8SDavid du Colombier 			return if_seq(n);
214*219b2ee8SDavid du Colombier 		if (n->ntyp == UNLESS)
215*219b2ee8SDavid du Colombier 			return unless_seq(n);
216*219b2ee8SDavid du Colombier 	}
217*219b2ee8SDavid du Colombier 	m = (Element *) emalloc(sizeof(Element));
218*219b2ee8SDavid du Colombier 	m->n = n;
219*219b2ee8SDavid du Colombier 	m->seqno = Elcnt++;
220*219b2ee8SDavid du Colombier 	m->Seqno = Unique++;
221*219b2ee8SDavid du Colombier 	m->Nxt = Al_El; Al_El = m;
222*219b2ee8SDavid du Colombier 	return m;
223*219b2ee8SDavid du Colombier }
224*219b2ee8SDavid du Colombier 
225*219b2ee8SDavid du Colombier Element *
226*219b2ee8SDavid du Colombier if_seq(Lextok *n)
227*219b2ee8SDavid du Colombier {	int	tok = n->ntyp;
228*219b2ee8SDavid du Colombier 	SeqList	*s  = n->sl;
229*219b2ee8SDavid du Colombier 	Element	*e  = new_el(ZN);
230*219b2ee8SDavid du Colombier 	Element	*t  = new_el(nn(ZN,'.',ZN,ZN)); /* target */
231*219b2ee8SDavid du Colombier 	SeqList	*z, *prev_z = (SeqList *) 0;
232*219b2ee8SDavid du Colombier 	SeqList *move_else  = (SeqList *) 0;	/* to end of optionlist */
233*219b2ee8SDavid du Colombier 	int	has_probes = 0;
234*219b2ee8SDavid du Colombier 
235*219b2ee8SDavid du Colombier 	for (z = s; z; z = z->nxt)
236*219b2ee8SDavid du Colombier 	{	if (z->this->frst->n->ntyp == ELSE)
237*219b2ee8SDavid du Colombier 		{	if (move_else)
238*219b2ee8SDavid du Colombier 				fatal("duplicate `else'", (char *) 0);
239*219b2ee8SDavid du Colombier 			if (z->nxt)	/* is not already at the end */
240*219b2ee8SDavid du Colombier 			{	move_else = z;
241*219b2ee8SDavid du Colombier 				if (prev_z)
242*219b2ee8SDavid du Colombier 					prev_z->nxt = z->nxt;
243*219b2ee8SDavid du Colombier 				else
244*219b2ee8SDavid du Colombier 					s = n->sl = z->nxt;
245*219b2ee8SDavid du Colombier 				continue;
246*219b2ee8SDavid du Colombier 			}
247*219b2ee8SDavid du Colombier 		} else
248*219b2ee8SDavid du Colombier 		{	has_probes |= has_typ(z->this->frst->n, FULL);
249*219b2ee8SDavid du Colombier 			has_probes |= has_typ(z->this->frst->n, NFULL);
250*219b2ee8SDavid du Colombier 			has_probes |= has_typ(z->this->frst->n, EMPTY);
251*219b2ee8SDavid du Colombier 			has_probes |= has_typ(z->this->frst->n, NEMPTY);
252*219b2ee8SDavid du Colombier 		}
253*219b2ee8SDavid du Colombier 		prev_z = z;
254*219b2ee8SDavid du Colombier 	}
255*219b2ee8SDavid du Colombier 	if (move_else)
256*219b2ee8SDavid du Colombier 	{	move_else->nxt = (SeqList *) 0;
257*219b2ee8SDavid du Colombier 		/* if there is no prev, then else was at the end */
258*219b2ee8SDavid du Colombier 		if (!prev_z) fatal("cannot happen - if_seq", (char *) 0);
259*219b2ee8SDavid du Colombier 		prev_z->nxt = move_else;
260*219b2ee8SDavid du Colombier 		prev_z = move_else;
261*219b2ee8SDavid du Colombier 	}
262*219b2ee8SDavid du Colombier 	if (prev_z
263*219b2ee8SDavid du Colombier 	&&  has_probes
264*219b2ee8SDavid du Colombier 	&&  prev_z->this->frst->n->ntyp == ELSE)
265*219b2ee8SDavid du Colombier 		prev_z->this->frst->n->val = 1;
266*219b2ee8SDavid du Colombier 
267*219b2ee8SDavid du Colombier 	e->n = nn(n, tok, ZN, ZN);
268*219b2ee8SDavid du Colombier 	e->n->sl = s;			/* preserve as info only */
269*219b2ee8SDavid du Colombier 	e->sub = s;
270*219b2ee8SDavid du Colombier 	for (z = s; z; prev_z = z, z = z->nxt)
271*219b2ee8SDavid du Colombier 		add_el(t, z->this);	/* append target */
272*219b2ee8SDavid du Colombier 	if (tok == DO)
273*219b2ee8SDavid du Colombier 	{	add_el(t, cur_s->this); /* target upfront */
274*219b2ee8SDavid du Colombier 		t = new_el(nn(n, BREAK, ZN, ZN)); /* break target */
275*219b2ee8SDavid du Colombier 		set_lab(break_dest(), t);	/* new exit  */
276*219b2ee8SDavid du Colombier 		breakstack = breakstack->nxt;	/* pop stack */
277*219b2ee8SDavid du Colombier 	}
278*219b2ee8SDavid du Colombier 	add_el(e, cur_s->this);
279*219b2ee8SDavid du Colombier 	add_el(t, cur_s->this);
280*219b2ee8SDavid du Colombier 	return e;	/* destination node for label */
281*219b2ee8SDavid du Colombier }
282*219b2ee8SDavid du Colombier 
283*219b2ee8SDavid du Colombier void
284*219b2ee8SDavid du Colombier attach_escape(Sequence *n, Sequence *e)
285*219b2ee8SDavid du Colombier {	Element *f; SeqList *z;
286*219b2ee8SDavid du Colombier 
287*219b2ee8SDavid du Colombier 	for (f = n->frst; f; f = f->nxt)
288*219b2ee8SDavid du Colombier 	{	f->esc = seqlist(e, f->esc);	/* but, this is lifo order... */
289*219b2ee8SDavid du Colombier #ifdef DEBUG
290*219b2ee8SDavid du Colombier 		printf("attach %d (", e->frst->Seqno);
291*219b2ee8SDavid du Colombier 		comment(stdout, e->frst->n, 0);
292*219b2ee8SDavid du Colombier 		printf(")	to %d (", f->Seqno);
293*219b2ee8SDavid du Colombier 		comment(stdout, f->n, 0);
294*219b2ee8SDavid du Colombier 		printf(")\n");
295*219b2ee8SDavid du Colombier #endif
296*219b2ee8SDavid du Colombier 		if (f->n->ntyp == UNLESS)
297*219b2ee8SDavid du Colombier 		{	attach_escape(f->sub->this, e);
298*219b2ee8SDavid du Colombier 		} else
299*219b2ee8SDavid du Colombier 		if (f->n->ntyp == IF
300*219b2ee8SDavid du Colombier 		||  f->n->ntyp == DO)
301*219b2ee8SDavid du Colombier 		{	for (z = f->sub; z; z = z->nxt)
302*219b2ee8SDavid du Colombier 				attach_escape(z->this, e);
303*219b2ee8SDavid du Colombier 		} else
304*219b2ee8SDavid du Colombier 		if (f->n->ntyp == ATOMIC
305*219b2ee8SDavid du Colombier 		||  f->n->ntyp == D_STEP
306*219b2ee8SDavid du Colombier 		||  f->n->ntyp == NON_ATOMIC)
307*219b2ee8SDavid du Colombier 		{	attach_escape(f->n->sl->this, e);
308*219b2ee8SDavid du Colombier 		}
309*219b2ee8SDavid du Colombier 		if (f == n->extent) break;
310*219b2ee8SDavid du Colombier 	}
311*219b2ee8SDavid du Colombier }
312*219b2ee8SDavid du Colombier 
313*219b2ee8SDavid du Colombier Element *
314*219b2ee8SDavid du Colombier unless_seq(Lextok *n)
315*219b2ee8SDavid du Colombier {	SeqList	*s  = n->sl;
316*219b2ee8SDavid du Colombier 	Element	*e  = new_el(ZN);
317*219b2ee8SDavid du Colombier 	Element	*t  = new_el(nn(ZN,'.',ZN,ZN)); /* target */
318*219b2ee8SDavid du Colombier 	SeqList	*z;
319*219b2ee8SDavid du Colombier 
320*219b2ee8SDavid du Colombier 	e->n = nn(n, UNLESS, ZN, ZN);
321*219b2ee8SDavid du Colombier 	e->n->sl = s;			/* info only */
322*219b2ee8SDavid du Colombier 	e->sub = s;
323*219b2ee8SDavid du Colombier 
324*219b2ee8SDavid du Colombier 	/*
325*219b2ee8SDavid du Colombier 	 * check that there are precisely two sequences:
326*219b2ee8SDavid du Colombier 	 * the normal execution and the escape.
327*219b2ee8SDavid du Colombier 	 */
328*219b2ee8SDavid du Colombier 	if (!s || !s->nxt || s->nxt->nxt)
329*219b2ee8SDavid du Colombier 		fatal("unexpected unless structure", (char *)0);
330*219b2ee8SDavid du Colombier 	/*
331*219b2ee8SDavid du Colombier 	 * append the target state to both
332*219b2ee8SDavid du Colombier 	 */
333*219b2ee8SDavid du Colombier 	for (z = s; z; z = z->nxt)
334*219b2ee8SDavid du Colombier 		add_el(t, z->this);
335*219b2ee8SDavid du Colombier 	/*
336*219b2ee8SDavid du Colombier 	 * distributed the escape sequence over all states in
337*219b2ee8SDavid du Colombier 	 * the normal execution sequence
338*219b2ee8SDavid du Colombier 	 */
339*219b2ee8SDavid du Colombier 	attach_escape(s->this, s->nxt->this);
340*219b2ee8SDavid du Colombier 
341*219b2ee8SDavid du Colombier 	add_el(e, cur_s->this);
342*219b2ee8SDavid du Colombier 	add_el(t, cur_s->this);
343*219b2ee8SDavid du Colombier #ifdef DEBUG
344*219b2ee8SDavid du Colombier 	printf("unless element (%d,%d):\n", e->Seqno, t->Seqno);
345*219b2ee8SDavid du Colombier 	for (z = s; z; z = z->nxt)
346*219b2ee8SDavid du Colombier 	{	Element *x; printf("\t%d,%d,%d :: ",
347*219b2ee8SDavid du Colombier 		z->this->frst->Seqno,
348*219b2ee8SDavid du Colombier 		z->this->extent->Seqno,
349*219b2ee8SDavid du Colombier 		z->this->last->Seqno);
350*219b2ee8SDavid du Colombier 		for (x = z->this->frst; x; x = x->nxt)
351*219b2ee8SDavid du Colombier 			printf("(%d)", x->Seqno);
352*219b2ee8SDavid du Colombier 		printf("\n");
353*219b2ee8SDavid du Colombier 	}
354*219b2ee8SDavid du Colombier #endif
355*219b2ee8SDavid du Colombier 	return e;
356*219b2ee8SDavid du Colombier }
357*219b2ee8SDavid du Colombier 
358*219b2ee8SDavid du Colombier Element *
359*219b2ee8SDavid du Colombier mk_skip(void)
360*219b2ee8SDavid du Colombier {	Lextok  *t = nn(ZN, CONST, ZN, ZN);
361*219b2ee8SDavid du Colombier 	t->val = 1;
362*219b2ee8SDavid du Colombier 	return new_el(nn(ZN, 'c', t, ZN));
363*219b2ee8SDavid du Colombier }
364*219b2ee8SDavid du Colombier 
365*219b2ee8SDavid du Colombier void
366*219b2ee8SDavid du Colombier add_el(Element *e, Sequence *s)
367*219b2ee8SDavid du Colombier {
368*219b2ee8SDavid du Colombier 	if (e->n->ntyp == GOTO)
369*219b2ee8SDavid du Colombier 	{	Symbol *z;
370*219b2ee8SDavid du Colombier 		if ((z = has_lab(e))
371*219b2ee8SDavid du Colombier 		&& (strncmp(z->name, "progress", 8) == 0
372*219b2ee8SDavid du Colombier 		||  strncmp(z->name, "accept", 6) == 0
373*219b2ee8SDavid du Colombier 		||  strncmp(z->name, "end", 3) == 0))
374*219b2ee8SDavid du Colombier 		{	Element *y; /* insert a skip */
375*219b2ee8SDavid du Colombier 			y = mk_skip();
376*219b2ee8SDavid du Colombier 			mov_lab(z, e, y); /* inherit label */
377*219b2ee8SDavid du Colombier 			add_el(y, s);
378*219b2ee8SDavid du Colombier 	}	}
379*219b2ee8SDavid du Colombier #ifdef DEBUG
380*219b2ee8SDavid du Colombier 	printf("add_el %d after %d -- ",
381*219b2ee8SDavid du Colombier 	e->Seqno, (s->last)?s->last->Seqno:-1);
382*219b2ee8SDavid du Colombier 	comment(stdout, e->n, 0);
383*219b2ee8SDavid du Colombier 	printf("\n");
384*219b2ee8SDavid du Colombier #endif
385*219b2ee8SDavid du Colombier 	if (!s->frst)
386*219b2ee8SDavid du Colombier 		s->frst = e;
387*219b2ee8SDavid du Colombier 	else
388*219b2ee8SDavid du Colombier 		s->last->nxt = e;
389*219b2ee8SDavid du Colombier 	s->last = e;
390*219b2ee8SDavid du Colombier }
391*219b2ee8SDavid du Colombier 
392*219b2ee8SDavid du Colombier Element *
393*219b2ee8SDavid du Colombier colons(Lextok *n)
394*219b2ee8SDavid du Colombier {
395*219b2ee8SDavid du Colombier 	if (!n)
396*219b2ee8SDavid du Colombier 		return ZE;
397*219b2ee8SDavid du Colombier 	if (n->ntyp == ':')
398*219b2ee8SDavid du Colombier 	{	Element *e = colons(n->lft);
399*219b2ee8SDavid du Colombier 		set_lab(n->sym, e);
400*219b2ee8SDavid du Colombier 		return e;
401*219b2ee8SDavid du Colombier 	}
402*219b2ee8SDavid du Colombier 	innermost = n;
403*219b2ee8SDavid du Colombier 	return new_el(n);
404*219b2ee8SDavid du Colombier }
405*219b2ee8SDavid du Colombier 
406*219b2ee8SDavid du Colombier void
407*219b2ee8SDavid du Colombier add_seq(Lextok *n)
408*219b2ee8SDavid du Colombier {	Element *e;
409*219b2ee8SDavid du Colombier 
410*219b2ee8SDavid du Colombier 	if (!n) return;
411*219b2ee8SDavid du Colombier 	innermost = n;
412*219b2ee8SDavid du Colombier 	e = colons(n);
413*219b2ee8SDavid du Colombier 	if (innermost->ntyp != IF
414*219b2ee8SDavid du Colombier 	&&  innermost->ntyp != DO
415*219b2ee8SDavid du Colombier 	&&  innermost->ntyp != UNLESS)
416*219b2ee8SDavid du Colombier 		add_el(e, cur_s->this);
417*219b2ee8SDavid du Colombier }
418*219b2ee8SDavid du Colombier 
419*219b2ee8SDavid du Colombier void
420*219b2ee8SDavid du Colombier set_lab(Symbol *s, Element *e)
421*219b2ee8SDavid du Colombier {	Label *l; extern Symbol *context;
422*219b2ee8SDavid du Colombier 
423*219b2ee8SDavid du Colombier 	if (!s) return;
424*219b2ee8SDavid du Colombier 	l = (Label *) emalloc(sizeof(Label));
425*219b2ee8SDavid du Colombier 	l->s = s;
426*219b2ee8SDavid du Colombier 	l->c = context;
427*219b2ee8SDavid du Colombier 	l->e = e;
428*219b2ee8SDavid du Colombier 	l->nxt = labtab;
429*219b2ee8SDavid du Colombier 	labtab = l;
430*219b2ee8SDavid du Colombier }
431*219b2ee8SDavid du Colombier 
432*219b2ee8SDavid du Colombier Element *
433*219b2ee8SDavid du Colombier get_lab(Lextok *n, int md)
434*219b2ee8SDavid du Colombier {	Label *l;
435*219b2ee8SDavid du Colombier 	Symbol *s = n->sym;
436*219b2ee8SDavid du Colombier 
437*219b2ee8SDavid du Colombier 	for (l = labtab; l; l = l->nxt)
438*219b2ee8SDavid du Colombier 		if (s == l->s)
439*219b2ee8SDavid du Colombier 			return (l->e);
440*219b2ee8SDavid du Colombier 	lineno = n->ln;
441*219b2ee8SDavid du Colombier 	Fname = n->fn;
442*219b2ee8SDavid du Colombier 	if (md) fatal("undefined label %s", s->name);
443*219b2ee8SDavid du Colombier 	return ZE;
444*219b2ee8SDavid du Colombier }
445*219b2ee8SDavid du Colombier 
446*219b2ee8SDavid du Colombier Symbol *
447*219b2ee8SDavid du Colombier has_lab(Element *e)
448*219b2ee8SDavid du Colombier {	Label *l;
449*219b2ee8SDavid du Colombier 
450*219b2ee8SDavid du Colombier 	for (l = labtab; l; l = l->nxt)
451*219b2ee8SDavid du Colombier 		if (e == l->e)
452*219b2ee8SDavid du Colombier 			return (l->s);
453*219b2ee8SDavid du Colombier 	return ZS;
454*219b2ee8SDavid du Colombier }
455*219b2ee8SDavid du Colombier 
456*219b2ee8SDavid du Colombier void
457*219b2ee8SDavid du Colombier mov_lab(Symbol *z, Element *e, Element *y)
458*219b2ee8SDavid du Colombier {	Label *l;
459*219b2ee8SDavid du Colombier 
460*219b2ee8SDavid du Colombier 	for (l = labtab; l; l = l->nxt)
461*219b2ee8SDavid du Colombier 		if (e == l->e)
462*219b2ee8SDavid du Colombier 		{	l->e = y;
463*219b2ee8SDavid du Colombier 			return;
464*219b2ee8SDavid du Colombier 		}
465*219b2ee8SDavid du Colombier 	if (e->n)
466*219b2ee8SDavid du Colombier 	{	lineno = e->n->ln;
467*219b2ee8SDavid du Colombier 		Fname  = e->n->fn;
468*219b2ee8SDavid du Colombier 	}
469*219b2ee8SDavid du Colombier 	fatal("cannot happen - mov_lab %s", z->name);
470*219b2ee8SDavid du Colombier }
471*219b2ee8SDavid du Colombier 
472*219b2ee8SDavid du Colombier void
473*219b2ee8SDavid du Colombier fix_dest(Symbol *c, Symbol *a)	/* label, proctype */
474*219b2ee8SDavid du Colombier {	Label *l;
475*219b2ee8SDavid du Colombier 
476*219b2ee8SDavid du Colombier 
477*219b2ee8SDavid du Colombier 	for (l = labtab; l; l = l->nxt)
478*219b2ee8SDavid du Colombier 	{	if (strcmp(c->name, l->s->name) == 0
479*219b2ee8SDavid du Colombier 		&&  strcmp(a->name, l->c->name) == 0)
480*219b2ee8SDavid du Colombier 			break;
481*219b2ee8SDavid du Colombier 	}
482*219b2ee8SDavid du Colombier 
483*219b2ee8SDavid du Colombier 	if (!l)
484*219b2ee8SDavid du Colombier 	{	non_fatal("unknown label '%s'", c->name);
485*219b2ee8SDavid du Colombier 		return;
486*219b2ee8SDavid du Colombier 	}
487*219b2ee8SDavid du Colombier 	if (!l->e || !l->e->n)
488*219b2ee8SDavid du Colombier 		fatal("fix_dest error (%s)", c->name);
489*219b2ee8SDavid du Colombier 	if (l->e->n->ntyp == GOTO)
490*219b2ee8SDavid du Colombier 	{	Element	*y = (Element *) emalloc(sizeof(Element));
491*219b2ee8SDavid du Colombier 		int	keep_ln = l->e->n->ln;
492*219b2ee8SDavid du Colombier 		Symbol	*keep_fn = l->e->n->fn;
493*219b2ee8SDavid du Colombier 
494*219b2ee8SDavid du Colombier 		/* insert skip - or target is optimized away */
495*219b2ee8SDavid du Colombier 		y->n = l->e->n;		  /* copy of the goto   */
496*219b2ee8SDavid du Colombier 		y->seqno = find_maxel(a); /* unique seqno within proc */
497*219b2ee8SDavid du Colombier 		y->nxt = l->e->nxt;
498*219b2ee8SDavid du Colombier 		y->Seqno = Unique++; y->Nxt = Al_El; Al_El = y;
499*219b2ee8SDavid du Colombier 
500*219b2ee8SDavid du Colombier 		/* turn the original element+seqno into a skip */
501*219b2ee8SDavid du Colombier 		l->e->n = nn(ZN, 'c', nn(ZN, CONST, ZN, ZN), ZN);
502*219b2ee8SDavid du Colombier 		l->e->n->ln = l->e->n->lft->ln = keep_ln;
503*219b2ee8SDavid du Colombier 		l->e->n->fn = l->e->n->lft->fn = keep_fn;
504*219b2ee8SDavid du Colombier 		l->e->n->lft->val = 1;
505*219b2ee8SDavid du Colombier 		l->e->nxt = y;		/* append the goto  */
506*219b2ee8SDavid du Colombier 	}
507*219b2ee8SDavid du Colombier }
508*219b2ee8SDavid du Colombier 
509*219b2ee8SDavid du Colombier int
510*219b2ee8SDavid du Colombier find_lab(Symbol *s, Symbol *c)
511*219b2ee8SDavid du Colombier {	Label *l;
512*219b2ee8SDavid du Colombier 
513*219b2ee8SDavid du Colombier 	for (l = labtab; l; l = l->nxt)
514*219b2ee8SDavid du Colombier 	{	if (strcmp(s->name, l->s->name) == 0
515*219b2ee8SDavid du Colombier 		&&  strcmp(c->name, l->c->name) == 0)
516*219b2ee8SDavid du Colombier 			return (l->e->seqno);
517*219b2ee8SDavid du Colombier 	}
518*219b2ee8SDavid du Colombier 	return 0;
519*219b2ee8SDavid du Colombier }
520*219b2ee8SDavid du Colombier 
521*219b2ee8SDavid du Colombier void
522*219b2ee8SDavid du Colombier pushbreak(void)
523*219b2ee8SDavid du Colombier {	Lbreak *r = (Lbreak *) emalloc(sizeof(Lbreak));
524*219b2ee8SDavid du Colombier 	Symbol *l;
525*219b2ee8SDavid du Colombier 	char buf[32];
526*219b2ee8SDavid du Colombier 
527*219b2ee8SDavid du Colombier 	sprintf(buf, ":b%d", break_id++);
528*219b2ee8SDavid du Colombier 	l = lookup(buf);
529*219b2ee8SDavid du Colombier 	r->l = l;
530*219b2ee8SDavid du Colombier 	r->nxt = breakstack;
531*219b2ee8SDavid du Colombier 	breakstack = r;
532*219b2ee8SDavid du Colombier }
533*219b2ee8SDavid du Colombier 
534*219b2ee8SDavid du Colombier Symbol *
535*219b2ee8SDavid du Colombier break_dest(void)
536*219b2ee8SDavid du Colombier {
537*219b2ee8SDavid du Colombier 	if (!breakstack)
538*219b2ee8SDavid du Colombier 		fatal("misplaced break statement", (char *)0);
539*219b2ee8SDavid du Colombier 	return breakstack->l;
540*219b2ee8SDavid du Colombier }
541*219b2ee8SDavid du Colombier 
542*219b2ee8SDavid du Colombier void
543*219b2ee8SDavid du Colombier make_atomic(Sequence *s, int added)
544*219b2ee8SDavid du Colombier {
545*219b2ee8SDavid du Colombier 	walk_atomic(s->frst, s->last, added);
546*219b2ee8SDavid du Colombier 	s->last->status &= ~ATOM;
547*219b2ee8SDavid du Colombier 	s->last->status |= L_ATOM;
548*219b2ee8SDavid du Colombier }
549*219b2ee8SDavid du Colombier 
550*219b2ee8SDavid du Colombier void
551*219b2ee8SDavid du Colombier walk_atomic(Element *a, Element *b, int added)
552*219b2ee8SDavid du Colombier {	Element *f;
553*219b2ee8SDavid du Colombier 	SeqList *h;
554*219b2ee8SDavid du Colombier 	char *str = (added)?"d_step":"atomic";
555*219b2ee8SDavid du Colombier 
556*219b2ee8SDavid du Colombier 	for (f = a; ; f = f->nxt)
557*219b2ee8SDavid du Colombier 	{	f->status |= (ATOM|added);
558*219b2ee8SDavid du Colombier 		switch (f->n->ntyp) {
559*219b2ee8SDavid du Colombier 		case ATOMIC:
560*219b2ee8SDavid du Colombier 			lineno = f->n->ln;
561*219b2ee8SDavid du Colombier 			Fname = f->n->fn;
562*219b2ee8SDavid du Colombier 			non_fatal("atomic inside %s", str);
563*219b2ee8SDavid du Colombier 			break;
564*219b2ee8SDavid du Colombier 		case D_STEP:
565*219b2ee8SDavid du Colombier 			lineno = f->n->ln;
566*219b2ee8SDavid du Colombier 			Fname = f->n->fn;
567*219b2ee8SDavid du Colombier 			non_fatal("d_step inside %s", str);
568*219b2ee8SDavid du Colombier 			break;
569*219b2ee8SDavid du Colombier 		case NON_ATOMIC:
570*219b2ee8SDavid du Colombier 			h = f->n->sl;
571*219b2ee8SDavid du Colombier 			walk_atomic(h->this->frst, h->this->last, added);
572*219b2ee8SDavid du Colombier 			break;
573*219b2ee8SDavid du Colombier 		}
574*219b2ee8SDavid du Colombier 
575*219b2ee8SDavid du Colombier 		for (h = f->sub; h; h = h->nxt)
576*219b2ee8SDavid du Colombier 			walk_atomic(h->this->frst, h->this->last, added);
577*219b2ee8SDavid du Colombier 		if (f == b)
578*219b2ee8SDavid du Colombier 			break;
579*219b2ee8SDavid du Colombier 	}
580*219b2ee8SDavid du Colombier }
581*219b2ee8SDavid du Colombier 
582*219b2ee8SDavid du Colombier void
583*219b2ee8SDavid du Colombier dumplabels(void)
584*219b2ee8SDavid du Colombier {	Label *l;
585*219b2ee8SDavid du Colombier 
586*219b2ee8SDavid du Colombier 	for (l = labtab; l; l = l->nxt)
587*219b2ee8SDavid du Colombier 		if (l->c != 0 && l->s->name[0] != ':')
588*219b2ee8SDavid du Colombier 		printf("label	%s	%d	<%s>\n",
589*219b2ee8SDavid du Colombier 		l->s->name, l->e->seqno, l->c->name);
590*219b2ee8SDavid du Colombier }
591