xref: /plan9-contrib/sys/src/cmd/spin/flow.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
1 /***** spin: flow.c *****/
2 
3 /* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
4 /* All Rights Reserved.  This software is for educational purposes only.  */
5 /* No guarantee whatsoever is expressed or implied by the distribution of */
6 /* this code.  Permission is given to distribute this code provided that  */
7 /* this introductory message is not removed and no monies are exchanged.  */
8 /* Software written by Gerard J. Holzmann.  For tool documentation see:   */
9 /*             http://spinroot.com/                                       */
10 /* Send all bug-reports and/or questions to: bugs@spinroot.com            */
11 
12 #include "spin.h"
13 #ifdef PC
14 #include "y_tab.h"
15 #else
16 #include "y.tab.h"
17 #endif
18 
19 extern Symbol	*Fname;
20 extern int	nr_errs, lineno, verbose;
21 extern short	has_unless, has_badelse;
22 
23 Element *Al_El = ZE;
24 Label	*labtab = (Label *) 0;
25 int	Unique=0, Elcnt=0, DstepStart = -1;
26 
27 static Lbreak	*breakstack = (Lbreak *) 0;
28 static Lextok	*innermost;
29 static SeqList	*cur_s = (SeqList *) 0;
30 static int	break_id=0;
31 
32 static Element	*if_seq(Lextok *);
33 static Element	*new_el(Lextok *);
34 static Element	*unless_seq(Lextok *);
35 static void	add_el(Element *, Sequence *);
36 static void	attach_escape(Sequence *, Sequence *);
37 static void	mov_lab(Symbol *, Element *, Element *);
38 static void	walk_atomic(Element *, Element *, int);
39 
40 void
41 open_seq(int top)
42 {	SeqList *t;
43 	Sequence *s = (Sequence *) emalloc(sizeof(Sequence));
44 
45 	t = seqlist(s, cur_s);
46 	cur_s = t;
47 	if (top) Elcnt = 1;
48 }
49 
50 void
51 rem_Seq(void)
52 {
53 	DstepStart = Unique;
54 }
55 
56 void
57 unrem_Seq(void)
58 {
59 	DstepStart = -1;
60 }
61 
62 static int
63 Rjumpslocal(Element *q, Element *stop)
64 {	Element *lb, *f;
65 	SeqList *h;
66 
67 	/* allow no jumps out of a d_step sequence */
68 	for (f = q; f && f != stop; f = f->nxt)
69 	{	if (f && f->n && f->n->ntyp == GOTO)
70 		{	lb = get_lab(f->n, 0);
71 			if (!lb || lb->Seqno < DstepStart)
72 			{	lineno = f->n->ln;
73 				Fname = f->n->fn;
74 				return 0;
75 		}	}
76 		for (h = f->sub; h; h = h->nxt)
77 		{	if (!Rjumpslocal(h->this->frst, h->this->last))
78 				return 0;
79 
80 	}	}
81 	return 1;
82 }
83 
84 void
85 cross_dsteps(Lextok *a, Lextok *b)
86 {
87 	if (a && b
88 	&&  a->indstep != b->indstep)
89 	{	lineno = a->ln;
90 		Fname  = a->fn;
91 		fatal("jump into d_step sequence", (char *) 0);
92 	}
93 }
94 
95 int
96 is_skip(Lextok *n)
97 {
98 	return (n->ntyp == PRINT
99 	||	n->ntyp == PRINTM
100 	||	(n->ntyp == 'c'
101 		&& n->lft
102 		&& n->lft->ntyp == CONST
103 		&& n->lft->val  == 1));
104 }
105 
106 void
107 check_sequence(Sequence *s)
108 {	Element *e, *le = ZE;
109 	Lextok *n;
110 	int cnt = 0;
111 
112 	for (e = s->frst; e; le = e, e = e->nxt)
113 	{	n = e->n;
114 		if (is_skip(n) && !has_lab(e, 0))
115 		{	cnt++;
116 			if (cnt > 1
117 			&&  n->ntyp != PRINT
118 			&&  n->ntyp != PRINTM)
119 			{	if (verbose&32)
120 					printf("spin: line %d %s, redundant skip\n",
121 						n->ln, n->fn->name);
122 				if (e != s->frst
123 				&&  e != s->last
124 				&&  e != s->extent)
125 				{	e->status |= DONE;	/* not unreachable */
126 					le->nxt = e->nxt;	/* remove it */
127 					e = le;
128 				}
129 			}
130 		} else
131 			cnt = 0;
132 	}
133 }
134 
135 void
136 prune_opts(Lextok *n)
137 {	SeqList *l;
138 	extern Symbol *context;
139 	extern char *claimproc;
140 
141 	if (!n
142 	|| (context && claimproc && strcmp(context->name, claimproc) == 0))
143 		return;
144 
145 	for (l = n->sl; l; l = l->nxt)	/* find sequences of unlabeled skips */
146 		check_sequence(l->this);
147 }
148 
149 Sequence *
150 close_seq(int nottop)
151 {	Sequence *s = cur_s->this;
152 	Symbol *z;
153 
154 	if (nottop > 0 && (z = has_lab(s->frst, 0)))
155 	{	printf("error: (%s:%d) label %s placed incorrectly\n",
156 			(s->frst->n)?s->frst->n->fn->name:"-",
157 			(s->frst->n)?s->frst->n->ln:0,
158 			z->name);
159 		switch (nottop) {
160 		case 1:
161 			printf("=====> stmnt unless Label: stmnt\n");
162 			printf("sorry, cannot jump to the guard of an\n");
163 			printf("escape (it is not a unique state)\n");
164 			break;
165 		case 2:
166 			printf("=====> instead of  ");
167 			printf("\"Label: stmnt unless stmnt\"\n");
168 			printf("=====> always use  ");
169 			printf("\"Label: { stmnt unless stmnt }\"\n");
170 			break;
171 		case 3:
172 			printf("=====> instead of  ");
173 			printf("\"atomic { Label: statement ... }\"\n");
174 			printf("=====> always use  ");
175 			printf("\"Label: atomic { statement ... }\"\n");
176 			break;
177 		case 4:
178 			printf("=====> instead of  ");
179 			printf("\"d_step { Label: statement ... }\"\n");
180 			printf("=====> always use  ");
181 			printf("\"Label: d_step { statement ... }\"\n");
182 			break;
183 		case 5:
184 			printf("=====> instead of  ");
185 			printf("\"{ Label: statement ... }\"\n");
186 			printf("=====> always use  ");
187 			printf("\"Label: { statement ... }\"\n");
188 			break;
189 		case 6:
190 			printf("=====>instead of\n");
191 			printf("	do (or if)\n");
192 			printf("	:: ...\n");
193 			printf("	:: Label: statement\n");
194 			printf("	od (of fi)\n");
195 			printf("=====>always use\n");
196 			printf("Label:	do (or if)\n");
197 			printf("	:: ...\n");
198 			printf("	:: statement\n");
199 			printf("	od (or fi)\n");
200 			break;
201 		case 7:
202 			printf("cannot happen - labels\n");
203 			break;
204 		}
205 		alldone(1);
206 	}
207 
208 	if (nottop == 4
209 	&& !Rjumpslocal(s->frst, s->last))
210 		fatal("non_local jump in d_step sequence", (char *) 0);
211 
212 	cur_s = cur_s->nxt;
213 	s->maxel = Elcnt;
214 	s->extent = s->last;
215 	if (!s->last)
216 		fatal("sequence must have at least one statement", (char *) 0);
217 	return s;
218 }
219 
220 Lextok *
221 do_unless(Lextok *No, Lextok *Es)
222 {	SeqList *Sl;
223 	Lextok *Re = nn(ZN, UNLESS, ZN, ZN);
224 	Re->ln = No->ln;
225 	Re->fn = No->fn;
226 
227 	has_unless++;
228 	if (Es->ntyp == NON_ATOMIC)
229 		Sl = Es->sl;
230 	else
231 	{	open_seq(0); add_seq(Es);
232 		Sl = seqlist(close_seq(1), 0);
233 	}
234 
235 	if (No->ntyp == NON_ATOMIC)
236 	{	No->sl->nxt = Sl;
237 		Sl = No->sl;
238 	} else	if (No->ntyp == ':'
239 		&& (No->lft->ntyp == NON_ATOMIC
240 		||  No->lft->ntyp == ATOMIC
241 		||  No->lft->ntyp == D_STEP))
242 	{
243 		int tok = No->lft->ntyp;
244 
245 		No->lft->sl->nxt = Sl;
246 		Re->sl = No->lft->sl;
247 
248 		open_seq(0); add_seq(Re);
249 		Re = nn(ZN, tok, ZN, ZN);
250 		Re->sl = seqlist(close_seq(7), 0);
251 		Re->ln = No->ln;
252 		Re->fn = No->fn;
253 
254 		Re = nn(No, ':', Re, ZN);	/* lift label */
255 		Re->ln = No->ln;
256 		Re->fn = No->fn;
257 		return Re;
258 	} else
259 	{	open_seq(0); add_seq(No);
260 		Sl = seqlist(close_seq(2), Sl);
261 	}
262 
263 	Re->sl = Sl;
264 	return Re;
265 }
266 
267 SeqList *
268 seqlist(Sequence *s, SeqList *r)
269 {	SeqList *t = (SeqList *) emalloc(sizeof(SeqList));
270 
271 	t->this = s;
272 	t->nxt = r;
273 	return t;
274 }
275 
276 static Element *
277 new_el(Lextok *n)
278 {	Element *m;
279 
280 	if (n)
281 	{	if (n->ntyp == IF || n->ntyp == DO)
282 			return if_seq(n);
283 		if (n->ntyp == UNLESS)
284 			return unless_seq(n);
285 	}
286 	m = (Element *) emalloc(sizeof(Element));
287 	m->n = n;
288 	m->seqno = Elcnt++;
289 	m->Seqno = Unique++;
290 	m->Nxt = Al_El; Al_El = m;
291 	return m;
292 }
293 
294 static int
295 has_chanref(Lextok *n)
296 {
297 	if (!n) return 0;
298 
299 	switch (n->ntyp) {
300 	case 's':	case 'r':
301 #if 0
302 	case 'R':	case LEN:
303 #endif
304 	case FULL:	case NFULL:
305 	case EMPTY:	case NEMPTY:
306 		return 1;
307 	default:
308 		break;
309 	}
310 	if (has_chanref(n->lft))
311 		return 1;
312 
313 	return has_chanref(n->rgt);
314 }
315 
316 void
317 loose_ends(void)	/* properly tie-up ends of sub-sequences */
318 {	Element *e, *f;
319 
320 	for (e = Al_El; e; e = e->Nxt)
321 	{	if (!e->n
322 		||  !e->nxt)
323 			continue;
324 		switch (e->n->ntyp) {
325 		case ATOMIC:
326 		case NON_ATOMIC:
327 		case D_STEP:
328 			f = e->nxt;
329 			while (f && f->n->ntyp == '.')
330 				f = f->nxt;
331 			if (0) printf("link %d, {%d .. %d} -> %d (ntyp=%d) was %d\n",
332 				e->seqno,
333 				e->n->sl->this->frst->seqno,
334 				e->n->sl->this->last->seqno,
335 				f?f->seqno:-1, f?f->n->ntyp:-1,
336 				e->n->sl->this->last->nxt?e->n->sl->this->last->nxt->seqno:-1);
337 			if (!e->n->sl->this->last->nxt)
338 				e->n->sl->this->last->nxt = f;
339 			else
340 			{	if (e->n->sl->this->last->nxt->n->ntyp != GOTO)
341 				{	if (!f || e->n->sl->this->last->nxt->seqno != f->seqno)
342 					non_fatal("unexpected: loose ends", (char *)0);
343 				} else
344 					e->n->sl->this->last = e->n->sl->this->last->nxt;
345 				/*
346 				 * fix_dest can push a goto into the nxt position
347 				 * in that case the goto wins and f is not needed
348 				 * but the last fields needs adjusting
349 				 */
350 			}
351 			break;
352 	}	}
353 }
354 
355 static Element *
356 if_seq(Lextok *n)
357 {	int	tok = n->ntyp;
358 	SeqList	*s  = n->sl;
359 	Element	*e  = new_el(ZN);
360 	Element	*t  = new_el(nn(ZN,'.',ZN,ZN)); /* target */
361 	SeqList	*z, *prev_z = (SeqList *) 0;
362 	SeqList *move_else  = (SeqList *) 0;	/* to end of optionlist */
363 	int	ref_chans = 0;
364 
365 	for (z = s; z; z = z->nxt)
366 	{	if (!z->this->frst)
367 			continue;
368 		if (z->this->frst->n->ntyp == ELSE)
369 		{	if (move_else)
370 				fatal("duplicate `else'", (char *) 0);
371 			if (z->nxt)	/* is not already at the end */
372 			{	move_else = z;
373 				if (prev_z)
374 					prev_z->nxt = z->nxt;
375 				else
376 					s = n->sl = z->nxt;
377 				continue;
378 			}
379 		} else
380 			ref_chans |= has_chanref(z->this->frst->n);
381 		prev_z = z;
382 	}
383 	if (move_else)
384 	{	move_else->nxt = (SeqList *) 0;
385 		/* if there is no prev, then else was at the end */
386 		if (!prev_z) fatal("cannot happen - if_seq", (char *) 0);
387 		prev_z->nxt = move_else;
388 		prev_z = move_else;
389 	}
390 	if (prev_z
391 	&&  ref_chans
392 	&&  prev_z->this->frst->n->ntyp == ELSE)
393 	{	prev_z->this->frst->n->val = 1;
394 		has_badelse++;
395 		non_fatal("dubious use of 'else' combined with i/o,",
396 			(char *)0);
397 		nr_errs--;
398 	}
399 
400 	e->n = nn(n, tok, ZN, ZN);
401 	e->n->sl = s;			/* preserve as info only */
402 	e->sub = s;
403 	for (z = s; z; prev_z = z, z = z->nxt)
404 		add_el(t, z->this);	/* append target */
405 	if (tok == DO)
406 	{	add_el(t, cur_s->this); /* target upfront */
407 		t = new_el(nn(n, BREAK, ZN, ZN)); /* break target */
408 		set_lab(break_dest(), t);	/* new exit  */
409 		breakstack = breakstack->nxt;	/* pop stack */
410 	}
411 	add_el(e, cur_s->this);
412 	add_el(t, cur_s->this);
413 	return e;			/* destination node for label */
414 }
415 
416 static void
417 escape_el(Element *f, Sequence *e)
418 {	SeqList *z;
419 
420 	for (z = f->esc; z; z = z->nxt)
421 		if (z->this == e)
422 			return;	/* already there */
423 
424 	/* cover the lower-level escapes of this state */
425 	for (z = f->esc; z; z = z->nxt)
426 		attach_escape(z->this, e);
427 
428 	/* now attach escape to the state itself */
429 
430 	f->esc = seqlist(e, f->esc);	/* in lifo order... */
431 #ifdef DEBUG
432 	printf("attach %d (", e->frst->Seqno);
433 	comment(stdout, e->frst->n, 0);
434 	printf(")	to %d (", f->Seqno);
435 	comment(stdout, f->n, 0);
436 	printf(")\n");
437 #endif
438 	switch (f->n->ntyp) {
439 	case UNLESS:
440 		attach_escape(f->sub->this, e);
441 		break;
442 	case IF:
443 	case DO:
444 		for (z = f->sub; z; z = z->nxt)
445 			attach_escape(z->this, e);
446 		break;
447 	case D_STEP:
448 		/* attach only to the guard stmnt */
449 		escape_el(f->n->sl->this->frst, e);
450 		break;
451 	case ATOMIC:
452 	case NON_ATOMIC:
453 		/* attach to all stmnts */
454 		attach_escape(f->n->sl->this, e);
455 		break;
456 	}
457 }
458 
459 static void
460 attach_escape(Sequence *n, Sequence *e)
461 {	Element *f;
462 
463 	for (f = n->frst; f; f = f->nxt)
464 	{	escape_el(f, e);
465 		if (f == n->extent)
466 			break;
467 	}
468 }
469 
470 static Element *
471 unless_seq(Lextok *n)
472 {	SeqList	*s  = n->sl;
473 	Element	*e  = new_el(ZN);
474 	Element	*t  = new_el(nn(ZN,'.',ZN,ZN)); /* target */
475 	SeqList	*z;
476 
477 	e->n = nn(n, UNLESS, ZN, ZN);
478 	e->n->sl = s;			/* info only */
479 	e->sub = s;
480 
481 	/* need 2 sequences: normal execution and escape */
482 	if (!s || !s->nxt || s->nxt->nxt)
483 		fatal("unexpected unless structure", (char *)0);
484 
485 	/* append the target state to both */
486 	for (z = s; z; z = z->nxt)
487 		add_el(t, z->this);
488 
489 	/* attach escapes to all states in normal sequence */
490 	attach_escape(s->this, s->nxt->this);
491 
492 	add_el(e, cur_s->this);
493 	add_el(t, cur_s->this);
494 #ifdef DEBUG
495 	printf("unless element (%d,%d):\n", e->Seqno, t->Seqno);
496 	for (z = s; z; z = z->nxt)
497 	{	Element *x; printf("\t%d,%d,%d :: ",
498 		z->this->frst->Seqno,
499 		z->this->extent->Seqno,
500 		z->this->last->Seqno);
501 		for (x = z->this->frst; x; x = x->nxt)
502 			printf("(%d)", x->Seqno);
503 		printf("\n");
504 	}
505 #endif
506 	return e;
507 }
508 
509 Element *
510 mk_skip(void)
511 {	Lextok  *t = nn(ZN, CONST, ZN, ZN);
512 	t->val = 1;
513 	return new_el(nn(ZN, 'c', t, ZN));
514 }
515 
516 static void
517 add_el(Element *e, Sequence *s)
518 {
519 	if (e->n->ntyp == GOTO)
520 	{	Symbol *z = has_lab(e, (1|2|4));
521 		if (z)
522 		{	Element *y; /* insert a skip */
523 			y = mk_skip();
524 			mov_lab(z, e, y); /* inherit label */
525 			add_el(y, s);
526 	}	}
527 #ifdef DEBUG
528 	printf("add_el %d after %d -- ",
529 	e->Seqno, (s->last)?s->last->Seqno:-1);
530 	comment(stdout, e->n, 0);
531 	printf("\n");
532 #endif
533 	if (!s->frst)
534 		s->frst = e;
535 	else
536 		s->last->nxt = e;
537 	s->last = e;
538 }
539 
540 static Element *
541 colons(Lextok *n)
542 {
543 	if (!n)
544 		return ZE;
545 	if (n->ntyp == ':')
546 	{	Element *e = colons(n->lft);
547 		set_lab(n->sym, e);
548 		return e;
549 	}
550 	innermost = n;
551 	return new_el(n);
552 }
553 
554 void
555 add_seq(Lextok *n)
556 {	Element *e;
557 
558 	if (!n) return;
559 	innermost = n;
560 	e = colons(n);
561 	if (innermost->ntyp != IF
562 	&&  innermost->ntyp != DO
563 	&&  innermost->ntyp != UNLESS)
564 		add_el(e, cur_s->this);
565 }
566 
567 void
568 set_lab(Symbol *s, Element *e)
569 {	Label *l; extern Symbol *context;
570 
571 	if (!s) return;
572 	for (l = labtab; l; l = l->nxt)
573 		if (l->s == s && l->c == context)
574 		{	non_fatal("label %s redeclared", s->name);
575 			break;
576 		}
577 	l = (Label *) emalloc(sizeof(Label));
578 	l->s = s;
579 	l->c = context;
580 	l->e = e;
581 	l->nxt = labtab;
582 	labtab = l;
583 }
584 
585 Element *
586 get_lab(Lextok *n, int md)
587 {	Label *l;
588 	Symbol *s = n->sym;
589 
590 	for (l = labtab; l; l = l->nxt)
591 		if (s == l->s)
592 			return (l->e);
593 
594 	lineno = n->ln;
595 	Fname = n->fn;
596 	if (md) fatal("undefined label %s", s->name);
597 	return ZE;
598 }
599 
600 Symbol *
601 has_lab(Element *e, int special)
602 {	Label *l;
603 
604 	for (l = labtab; l; l = l->nxt)
605 	{	if (e != l->e)
606 			continue;
607 		if (special == 0
608 		||  ((special&1) && !strncmp(l->s->name, "accept", 6))
609 		||  ((special&2) && !strncmp(l->s->name, "end", 3))
610 		||  ((special&4) && !strncmp(l->s->name, "progress", 8)))
611 			return (l->s);
612 	}
613 	return ZS;
614 }
615 
616 static void
617 mov_lab(Symbol *z, Element *e, Element *y)
618 {	Label *l;
619 
620 	for (l = labtab; l; l = l->nxt)
621 		if (e == l->e)
622 		{	l->e = y;
623 			return;
624 		}
625 	if (e->n)
626 	{	lineno = e->n->ln;
627 		Fname  = e->n->fn;
628 	}
629 	fatal("cannot happen - mov_lab %s", z->name);
630 }
631 
632 void
633 fix_dest(Symbol *c, Symbol *a)		/* c:label name, a:proctype name */
634 {	Label *l; extern Symbol *context;
635 
636 #if 0
637 	printf("ref to label '%s' in proctype '%s', search:\n",
638 		c->name, a->name);
639 	for (l = labtab; l; l = l->nxt)
640 		printf("	%s in	%s\n", l->s->name, l->c->name);
641 #endif
642 
643 	for (l = labtab; l; l = l->nxt)
644 	{	if (strcmp(c->name, l->s->name) == 0
645 		&&  strcmp(a->name, l->c->name) == 0)	/* ? */
646 			break;
647 	}
648 	if (!l)
649 	{	printf("spin: label '%s' (proctype %s)\n", c->name, a->name);
650 		non_fatal("unknown label '%s'", c->name);
651 		if (context == a)
652 		printf("spin: cannot remote ref a label inside the same proctype\n");
653 		return;
654 	}
655 	if (!l->e || !l->e->n)
656 		fatal("fix_dest error (%s)", c->name);
657 	if (l->e->n->ntyp == GOTO)
658 	{	Element	*y = (Element *) emalloc(sizeof(Element));
659 		int	keep_ln = l->e->n->ln;
660 		Symbol	*keep_fn = l->e->n->fn;
661 
662 		/* insert skip - or target is optimized away */
663 		y->n = l->e->n;		  /* copy of the goto   */
664 		y->seqno = find_maxel(a); /* unique seqno within proc */
665 		y->nxt = l->e->nxt;
666 		y->Seqno = Unique++; y->Nxt = Al_El; Al_El = y;
667 
668 		/* turn the original element+seqno into a skip */
669 		l->e->n = nn(ZN, 'c', nn(ZN, CONST, ZN, ZN), ZN);
670 		l->e->n->ln = l->e->n->lft->ln = keep_ln;
671 		l->e->n->fn = l->e->n->lft->fn = keep_fn;
672 		l->e->n->lft->val = 1;
673 		l->e->nxt = y;		/* append the goto  */
674 	}
675 	l->e->status |= CHECK2;	/* treat as if global */
676 	if (l->e->status & (ATOM | L_ATOM | D_ATOM))
677 	{	non_fatal("cannot reference label inside atomic or d_step (%s)",
678 			c->name);
679 	}
680 }
681 
682 int
683 find_lab(Symbol *s, Symbol *c, int markit)
684 {	Label *l;
685 
686 	for (l = labtab; l; l = l->nxt)
687 	{	if (strcmp(s->name, l->s->name) == 0
688 		&&  strcmp(c->name, l->c->name) == 0)
689 		{	l->visible |= markit;
690 			return (l->e->seqno);
691 	}	}
692 	return 0;
693 }
694 
695 void
696 pushbreak(void)
697 {	Lbreak *r = (Lbreak *) emalloc(sizeof(Lbreak));
698 	Symbol *l;
699 	char buf[64];
700 
701 	sprintf(buf, ":b%d", break_id++);
702 	l = lookup(buf);
703 	r->l = l;
704 	r->nxt = breakstack;
705 	breakstack = r;
706 }
707 
708 Symbol *
709 break_dest(void)
710 {
711 	if (!breakstack)
712 		fatal("misplaced break statement", (char *)0);
713 	return breakstack->l;
714 }
715 
716 void
717 make_atomic(Sequence *s, int added)
718 {	Element *f;
719 
720 	walk_atomic(s->frst, s->last, added);
721 
722 	f = s->last;
723 	switch (f->n->ntyp) {	/* is last step basic stmnt or sequence ? */
724 	case NON_ATOMIC:
725 	case ATOMIC:
726 		/* redo and search for the last step of that sequence */
727 		make_atomic(f->n->sl->this, added);
728 		break;
729 
730 	case UNLESS:
731 		/* escapes are folded into main sequence */
732 		make_atomic(f->sub->this, added);
733 		break;
734 
735 	default:
736 		f->status &= ~ATOM;
737 		f->status |= L_ATOM;
738 		break;
739 	}
740 }
741 
742 static void
743 walk_atomic(Element *a, Element *b, int added)
744 {	Element *f; Symbol *ofn; int oln;
745 	SeqList *h;
746 
747 	ofn = Fname;
748 	oln = lineno;
749 	for (f = a; ; f = f->nxt)
750 	{	f->status |= (ATOM|added);
751 		switch (f->n->ntyp) {
752 		case ATOMIC:
753 			if (verbose&32)
754 			  printf("spin: warning, line %3d %s, atomic inside %s (ignored)\n",
755 			  f->n->ln, f->n->fn->name, (added)?"d_step":"atomic");
756 			goto mknonat;
757 		case D_STEP:
758 			if (!(verbose&32))
759 			{	if (added) goto mknonat;
760 				break;
761 			}
762 			printf("spin: warning, line %3d %s, d_step inside ",
763 			 f->n->ln, f->n->fn->name);
764 			if (added)
765 			{	printf("d_step (ignored)\n");
766 				goto mknonat;
767 			}
768 			printf("atomic\n");
769 			break;
770 		case NON_ATOMIC:
771 mknonat:		f->n->ntyp = NON_ATOMIC; /* can jump here */
772 			h = f->n->sl;
773 			walk_atomic(h->this->frst, h->this->last, added);
774 			break;
775 		case UNLESS:
776 			if (added)
777 			{ printf("spin: error, line %3d %s, unless in d_step (ignored)\n",
778 			 	 f->n->ln, f->n->fn->name);
779 			}
780 		}
781 		for (h = f->sub; h; h = h->nxt)
782 			walk_atomic(h->this->frst, h->this->last, added);
783 		if (f == b)
784 			break;
785 	}
786 	Fname = ofn;
787 	lineno = oln;
788 }
789 
790 void
791 dumplabels(void)
792 {	Label *l;
793 
794 	for (l = labtab; l; l = l->nxt)
795 		if (l->c != 0 && l->s->name[0] != ':')
796 		printf("label	%s	%d	<%s>\n",
797 		l->s->name, l->e->seqno, l->c->name);
798 }
799