xref: /plan9/sys/src/cmd/spin/pangen5.c (revision 00d970127b9d44d2b22f4f656717a212dec1f1d2)
1 /***** spin: pangen5.c *****/
2 
3 /* Copyright (c) 1999-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 #include "y.tab.h"
14 
15 typedef struct BuildStack {
16 	FSM_trans *t;
17 	struct BuildStack *nxt;
18 } BuildStack;
19 
20 extern ProcList	*rdy;
21 extern int verbose, eventmapnr, claimnr, rvopt, export_ast, u_sync;
22 extern Element *Al_El;
23 
24 static FSM_state *fsm_free;
25 static FSM_trans *trans_free;
26 static BuildStack *bs, *bf;
27 static int max_st_id;
28 static int cur_st_id;
29 int o_max;
30 FSM_state *fsm;
31 FSM_state **fsm_tbl;
32 FSM_use   *use_free;
33 
34 static void ana_seq(Sequence *);
35 static void ana_stmnt(FSM_trans *, Lextok *, int);
36 
37 extern void AST_slice(void);
38 extern void AST_store(ProcList *, int);
39 extern int  has_global(Lextok *);
40 extern void exit(int);
41 
42 static void
fsm_table(void)43 fsm_table(void)
44 {	FSM_state *f;
45 	max_st_id += 2;
46 	/* fprintf(stderr, "omax %d, max=%d\n", o_max, max_st_id); */
47 	if (o_max < max_st_id)
48 	{	o_max = max_st_id;
49 		fsm_tbl = (FSM_state **) emalloc(max_st_id * sizeof(FSM_state *));
50 	} else
51 		memset((char *)fsm_tbl, 0, max_st_id * sizeof(FSM_state *));
52 	cur_st_id = max_st_id;
53 	max_st_id = 0;
54 
55 	for (f = fsm; f; f = f->nxt)
56 		fsm_tbl[f->from] = f;
57 }
58 
59 static int
FSM_DFS(int from,FSM_use * u)60 FSM_DFS(int from, FSM_use *u)
61 {	FSM_state *f;
62 	FSM_trans *t;
63 	FSM_use *v;
64 	int n;
65 
66 	if (from == 0)
67 		return 1;
68 
69 	f = fsm_tbl[from];
70 
71 	if (!f)
72 	{	printf("cannot find state %d\n", from);
73 		fatal("fsm_dfs: cannot happen\n", (char *) 0);
74 	}
75 
76 	if (f->seen)
77 		return 1;
78 	f->seen = 1;
79 
80 	for (t = f->t; t; t = t->nxt)
81 	{
82 		for (n = 0; n < 2; n++)
83 		for (v = t->Val[n]; v; v = v->nxt)
84 			if (u->var == v->var)
85 				return n;	/* a read or write */
86 
87 		if (!FSM_DFS(t->to, u))
88 			return 0;
89 	}
90 	return 1;
91 }
92 
93 static void
new_dfs(void)94 new_dfs(void)
95 {	int i;
96 
97 	for (i = 0; i < cur_st_id; i++)
98 		if (fsm_tbl[i])
99 			fsm_tbl[i]->seen = 0;
100 }
101 
102 static int
good_dead(Element * e,FSM_use * u)103 good_dead(Element *e, FSM_use *u)
104 {
105 	switch (u->special) {
106 	case 2:	/* ok if it's a receive */
107 		if (e->n->ntyp == ASGN
108 		&&  e->n->rgt->ntyp == CONST
109 		&&  e->n->rgt->val == 0)
110 			return 0;
111 		break;
112 	case 1:	/* must be able to use oval */
113 		if (e->n->ntyp != 'c'
114 		&&  e->n->ntyp != 'r')
115 			return 0;	/* can't really happen */
116 		break;
117 	}
118 	return 1;
119 }
120 
121 #if 0
122 static int howdeep = 0;
123 #endif
124 
125 static int
eligible(FSM_trans * v)126 eligible(FSM_trans *v)
127 {	Element	*el = ZE;
128 	Lextok	*lt = ZN;
129 
130 	if (v) el = v->step;
131 	if (el) lt = v->step->n;
132 
133 	if (!lt				/* dead end */
134 	||  v->nxt			/* has alternatives */
135 	||  el->esc			/* has an escape */
136 	||  (el->status&CHECK2)		/* remotely referenced */
137 	||  lt->ntyp == ATOMIC
138 	||  lt->ntyp == NON_ATOMIC	/* used for inlines -- should be able to handle this */
139 	||  lt->ntyp == IF
140 	||  lt->ntyp == C_CODE
141 	||  lt->ntyp == C_EXPR
142 	||  has_lab(el, 0)		/* any label at all */
143 
144 	||  lt->ntyp == DO
145 	||  lt->ntyp == UNLESS
146 	||  lt->ntyp == D_STEP
147 	||  lt->ntyp == ELSE
148 	||  lt->ntyp == '@'
149 	||  lt->ntyp == 'c'
150 	||  lt->ntyp == 'r'
151 	||  lt->ntyp == 's')
152 		return 0;
153 
154 	if (!(el->status&(2|4)))	/* not atomic */
155 	{	int unsafe = (el->status&I_GLOB)?1:has_global(el->n);
156 		if (unsafe)
157 			return 0;
158 	}
159 
160 	return 1;
161 }
162 
163 static int
canfill_in(FSM_trans * v)164 canfill_in(FSM_trans *v)
165 {	Element	*el = v->step;
166 	Lextok	*lt = v->step->n;
167 
168 	if (!lt				/* dead end */
169 	||  v->nxt			/* has alternatives */
170 	||  el->esc			/* has an escape */
171 	||  (el->status&CHECK2))	/* remotely referenced */
172 		return 0;
173 
174 	if (!(el->status&(2|4))		/* not atomic */
175 	&&  ((el->status&I_GLOB)
176 	||   has_global(el->n)))	/* and not safe */
177 		return 0;
178 
179 	return 1;
180 }
181 
182 static int
pushbuild(FSM_trans * v)183 pushbuild(FSM_trans *v)
184 {	BuildStack *b;
185 
186 	for (b = bs; b; b = b->nxt)
187 		if (b->t == v)
188 			return 0;
189 	if (bf)
190 	{	b = bf;
191 		bf = bf->nxt;
192 	} else
193 		b = (BuildStack *) emalloc(sizeof(BuildStack));
194 	b->t = v;
195 	b->nxt = bs;
196 	bs = b;
197 	return 1;
198 }
199 
200 static void
popbuild(void)201 popbuild(void)
202 {	BuildStack *f;
203 	if (!bs)
204 		fatal("cannot happen, popbuild", (char *) 0);
205 	f = bs;
206 	bs = bs->nxt;
207 	f->nxt = bf;
208 	bf = f;				/* freelist */
209 }
210 
211 static int
build_step(FSM_trans * v)212 build_step(FSM_trans *v)
213 {	FSM_state *f;
214 	Element	*el;
215 #if 0
216 	Lextok	*lt = ZN;
217 #endif
218 	int	st;
219 	int	r;
220 
221 	if (!v) return -1;
222 
223 	el = v->step;
224 	st = v->to;
225 
226 	if (!el) return -1;
227 
228 	if (v->step->merge)
229 		return v->step->merge;	/* already done */
230 
231 	if (!eligible(v))		/* non-blocking */
232 		return -1;
233 
234 	if (!pushbuild(v))		/* cycle detected */
235 		return -1;		/* break cycle */
236 
237 	f = fsm_tbl[st];
238 #if 0
239 	lt = v->step->n;
240 	if (verbose&32)
241 	{	if (++howdeep == 1)
242 			printf("spin: %s:%d, merge:\n", lt->fn->name, lt->ln);
243 		printf("\t[%d] <seqno %d>\t", howdeep, el->seqno);
244 		comment(stdout, lt, 0);
245 		printf(";\n");
246 	}
247 #endif
248 	r = build_step(f->t);
249 	v->step->merge = (r == -1) ? st : r;
250 #if 0
251 	if (verbose&32)
252 	{	printf("	merge value: %d (st=%d,r=%d, line %d)\n",
253 			v->step->merge, st, r, el->n->ln);
254 		howdeep--;
255 	}
256 #endif
257 	popbuild();
258 
259 	return v->step->merge;
260 }
261 
262 static void
FSM_MERGER(void)263 FSM_MERGER(/* char *pname */ void)	/* find candidates for safely merging steps */
264 {	FSM_state *f, *g;
265 	FSM_trans *t;
266 	Lextok	*lt;
267 
268 	for (f = fsm; f; f = f->nxt)		/* all states */
269 	for (t = f->t; t; t = t->nxt)		/* all edges */
270 	{	if (!t->step) continue;		/* happens with 'unless' */
271 
272 		t->step->merge_in = f->in;	/* ?? */
273 
274 		if (t->step->merge)
275 			continue;
276 		lt = t->step->n;
277 
278 		if (lt->ntyp == 'c'
279 		||  lt->ntyp == 'r'
280 		||  lt->ntyp == 's')	/* blocking stmnts */
281 			continue;	/* handled in 2nd scan */
282 
283 		if (!eligible(t))
284 			continue;
285 
286 		g = fsm_tbl[t->to];
287 		if (!g || !eligible(g->t))
288 		{
289 #define SINGLES
290 #ifdef SINGLES
291 			t->step->merge_single = t->to;
292 #if 0
293 			if ((verbose&32))
294 			{	printf("spin: %s:%d, merge_single:\n\t<seqno %d>\t",
295 					t->step->n->fn->name,
296 					t->step->n->ln,
297 					t->step->seqno);
298 				comment(stdout, t->step->n, 0);
299 				printf(";\n");
300 			}
301 #endif
302 #endif
303 			/* t is an isolated eligible step:
304 			 *
305 			 * a merge_start can connect to a proper
306 			 * merge chain or to a merge_single
307 			 * a merge chain can be preceded by
308 			 * a merge_start, but not by a merge_single
309 			 */
310 
311 			continue;
312 		}
313 
314 		(void) build_step(t);
315 	}
316 
317 	/* 2nd scan -- find possible merge_starts */
318 
319 	for (f = fsm; f; f = f->nxt)		/* all states */
320 	for (t = f->t; t; t = t->nxt)		/* all edges */
321 	{	if (!t->step || t->step->merge)
322 			continue;
323 
324 		lt = t->step->n;
325 #if 0
326 	4.1.3:
327 	an rv send operation inside an atomic, *loses* atomicity
328 	when executed
329 	and should therefore never be merged with a subsequent
330 	statement within the atomic sequence
331 	the same is not true for non-rv send operations
332 #endif
333 
334 		if (lt->ntyp == 'c'	/* potentially blocking stmnts */
335 		||  lt->ntyp == 'r'
336 		||  (lt->ntyp == 's' && u_sync == 0))	/* added !u_sync in 4.1.3 */
337 		{	if (!canfill_in(t))		/* atomic, non-global, etc. */
338 				continue;
339 
340 			g = fsm_tbl[t->to];
341 			if (!g || !g->t || !g->t->step)
342 				continue;
343 			if (g->t->step->merge)
344 				t->step->merge_start = g->t->step->merge;
345 #ifdef SINGLES
346 			else if (g->t->step->merge_single)
347 				t->step->merge_start = g->t->step->merge_single;
348 #endif
349 #if 0
350 			if ((verbose&32)
351 			&& t->step->merge_start)
352 			{	printf("spin: %s:%d, merge_START:\n\t<seqno %d>\t",
353 						lt->fn->name, lt->ln,
354 						t->step->seqno);
355 				comment(stdout, lt, 0);
356 				printf(";\n");
357 			}
358 #endif
359 		}
360 	}
361 }
362 
363 static void
FSM_ANA(void)364 FSM_ANA(void)
365 {	FSM_state *f;
366 	FSM_trans *t;
367 	FSM_use *u, *v, *w;
368 	int n;
369 
370 	for (f = fsm; f; f = f->nxt)		/* all states */
371 	for (t = f->t; t; t = t->nxt)		/* all edges */
372 	for (n = 0; n < 2; n++)			/* reads and writes */
373 	for (u = t->Val[n]; u; u = u->nxt)
374 	{	if (!u->var->context	/* global */
375 		||   u->var->type == CHAN
376 		||   u->var->type == STRUCT)
377 			continue;
378 		new_dfs();
379 		if (FSM_DFS(t->to, u))	/* cannot hit read before hitting write */
380 			u->special = n+1;	/* means, reset to 0 after use */
381 	}
382 
383 	if (!export_ast)
384 	for (f = fsm; f; f = f->nxt)
385 	for (t = f->t; t; t = t->nxt)
386 	for (n = 0; n < 2; n++)
387 	for (u = t->Val[n], w = (FSM_use *) 0; u; )
388 	{	if (u->special)
389 		{	v = u->nxt;
390 			if (!w)			/* remove from list */
391 				t->Val[n] = v;
392 			else
393 				w->nxt = v;
394 #if q
395 			if (verbose&32)
396 			{	printf("%s : %3d:  %d -> %d \t",
397 					t->step->n->fn->name,
398 					t->step->n->ln,
399 					f->from,
400 					t->to);
401 				comment(stdout, t->step->n, 0);
402 				printf("\t%c%d: %s\n", n==0?'R':'L',
403 					u->special, u->var->name);
404 			}
405 #endif
406 			if (good_dead(t->step, u))
407 			{	u->nxt = t->step->dead;	/* insert into dead */
408 				t->step->dead = u;
409 			}
410 			u = v;
411 		} else
412 		{	w = u;
413 			u = u->nxt;
414 	}	}
415 }
416 
417 void
rel_use(FSM_use * u)418 rel_use(FSM_use *u)
419 {
420 	if (!u) return;
421 	rel_use(u->nxt);
422 	u->var = (Symbol *) 0;
423 	u->special = 0;
424 	u->nxt = use_free;
425 	use_free = u;
426 }
427 
428 static void
rel_trans(FSM_trans * t)429 rel_trans(FSM_trans *t)
430 {
431 	if (!t) return;
432 	rel_trans(t->nxt);
433 	rel_use(t->Val[0]);
434 	rel_use(t->Val[1]);
435 	t->Val[0] = t->Val[1] = (FSM_use *) 0;
436 	t->nxt = trans_free;
437 	trans_free = t;
438 }
439 
440 static void
rel_state(FSM_state * f)441 rel_state(FSM_state *f)
442 {
443 	if (!f) return;
444 	rel_state(f->nxt);
445 	rel_trans(f->t);
446 	f->t = (FSM_trans *) 0;
447 	f->nxt = fsm_free;
448 	fsm_free = f;
449 }
450 
451 static void
FSM_DEL(void)452 FSM_DEL(void)
453 {
454 	rel_state(fsm);
455 	fsm = (FSM_state *) 0;
456 }
457 
458 static FSM_state *
mkstate(int s)459 mkstate(int s)
460 {	FSM_state *f;
461 
462 	/* fsm_tbl isn't allocated yet */
463 	for (f = fsm; f; f = f->nxt)
464 		if (f->from == s)
465 			break;
466 	if (!f)
467 	{	if (fsm_free)
468 		{	f = fsm_free;
469 			memset(f, 0, sizeof(FSM_state));
470 			fsm_free = fsm_free->nxt;
471 		} else
472 			f = (FSM_state *) emalloc(sizeof(FSM_state));
473 		f->from = s;
474 		f->t = (FSM_trans *) 0;
475 		f->nxt = fsm;
476 		fsm = f;
477 		if (s > max_st_id)
478 			max_st_id = s;
479 	}
480 	return f;
481 }
482 
483 static FSM_trans *
get_trans(int to)484 get_trans(int to)
485 {	FSM_trans *t;
486 
487 	if (trans_free)
488 	{	t = trans_free;
489 		memset(t, 0, sizeof(FSM_trans));
490 		trans_free = trans_free->nxt;
491 	} else
492 		t = (FSM_trans *) emalloc(sizeof(FSM_trans));
493 
494 	t->to = to;
495 	return t;
496 }
497 
498 static void
FSM_EDGE(int from,int to,Element * e)499 FSM_EDGE(int from, int to, Element *e)
500 {	FSM_state *f;
501 	FSM_trans *t;
502 
503 	f = mkstate(from);	/* find it or else make it */
504 	t = get_trans(to);
505 
506 	t->step = e;
507 	t->nxt = f->t;
508 	f->t = t;
509 
510 	f = mkstate(to);
511 	f->in++;
512 
513 	if (export_ast)
514 	{	t = get_trans(from);
515 		t->step = e;
516 		t->nxt = f->p;	/* from is a predecessor of to */
517 		f->p = t;
518 	}
519 
520 	if (t->step)
521 		ana_stmnt(t, t->step->n, 0);
522 }
523 
524 #define LVAL	1
525 #define RVAL	0
526 
527 static void
ana_var(FSM_trans * t,Lextok * now,int usage)528 ana_var(FSM_trans *t, Lextok *now, int usage)
529 {	FSM_use *u, *v;
530 
531 	if (!t || !now || !now->sym)
532 		return;
533 
534 	if (now->sym->name[0] == '_'
535 	&&  (strcmp(now->sym->name, "_") == 0
536 	||   strcmp(now->sym->name, "_pid") == 0
537 	||   strcmp(now->sym->name, "_last") == 0))
538 		return;
539 
540 	v = t->Val[usage];
541 	for (u = v; u; u = u->nxt)
542 		if (u->var == now->sym)
543 			return;	/* it's already there */
544 
545 	if (!now->lft)
546 	{	/* not for array vars -- it's hard to tell statically
547 		   if the index would, at runtime, evaluate to the
548 		   same values at lval and rval references
549 		*/
550 		if (use_free)
551 		{	u = use_free;
552 			use_free = use_free->nxt;
553 		} else
554 			u = (FSM_use *) emalloc(sizeof(FSM_use));
555 
556 		u->var = now->sym;
557 		u->nxt = t->Val[usage];
558 		t->Val[usage] = u;
559 	} else
560 		 ana_stmnt(t, now->lft, RVAL);	/* index */
561 
562 	if (now->sym->type == STRUCT
563 	&&  now->rgt
564 	&&  now->rgt->lft)
565 		ana_var(t, now->rgt->lft, usage);
566 }
567 
568 static void
ana_stmnt(FSM_trans * t,Lextok * now,int usage)569 ana_stmnt(FSM_trans *t, Lextok *now, int usage)
570 {	Lextok *v;
571 
572 	if (!t || !now) return;
573 
574 	switch (now->ntyp) {
575 	case '.':
576 	case BREAK:
577 	case GOTO:
578 	case CONST:
579 	case TIMEOUT:
580 	case NONPROGRESS:
581 	case  ELSE:
582 	case '@':
583 	case 'q':
584 	case IF:
585 	case DO:
586 	case ATOMIC:
587 	case NON_ATOMIC:
588 	case D_STEP:
589 	case C_CODE:
590 	case C_EXPR:
591 		break;
592 
593 	case '!':
594 	case UMIN:
595 	case '~':
596 	case ENABLED:
597 	case PC_VAL:
598 	case LEN:
599 	case FULL:
600 	case EMPTY:
601 	case NFULL:
602 	case NEMPTY:
603 	case ASSERT:
604 	case 'c':
605 		ana_stmnt(t, now->lft, RVAL);
606 		break;
607 
608 	case '/':
609 	case '*':
610 	case '-':
611 	case '+':
612 	case '%':
613 	case '&':
614 	case '^':
615 	case '|':
616 	case LT:
617 	case GT:
618 	case LE:
619 	case GE:
620 	case NE:
621 	case EQ:
622 	case OR:
623 	case AND:
624 	case LSHIFT:
625 	case RSHIFT:
626 		ana_stmnt(t, now->lft, RVAL);
627 		ana_stmnt(t, now->rgt, RVAL);
628 		break;
629 
630 	case ASGN:
631 		ana_stmnt(t, now->lft, LVAL);
632 		ana_stmnt(t, now->rgt, RVAL);
633 		break;
634 
635 	case PRINT:
636 	case RUN:
637 		for (v = now->lft; v; v = v->rgt)
638 			ana_stmnt(t, v->lft, RVAL);
639 		break;
640 
641 	case PRINTM:
642 		if (now->lft && !now->lft->ismtyp)
643 			ana_stmnt(t, now->lft, RVAL);
644 		break;
645 
646 	case 's':
647 		ana_stmnt(t, now->lft, RVAL);
648 		for (v = now->rgt; v; v = v->rgt)
649 			ana_stmnt(t, v->lft, RVAL);
650 		break;
651 
652 	case 'R':
653 	case 'r':
654 		ana_stmnt(t, now->lft, RVAL);
655 		for (v = now->rgt; v; v = v->rgt)
656 		{	if (v->lft->ntyp == EVAL)
657 				ana_stmnt(t, v->lft->lft, RVAL);
658 			else
659 			if (v->lft->ntyp != CONST
660 			&&  now->ntyp != 'R')		/* was v->lft->ntyp */
661 				ana_stmnt(t, v->lft, LVAL);
662 		}
663 		break;
664 
665 	case '?':
666 		ana_stmnt(t, now->lft, RVAL);
667 		if (now->rgt)
668 		{	ana_stmnt(t, now->rgt->lft, RVAL);
669 			ana_stmnt(t, now->rgt->rgt, RVAL);
670 		}
671 		break;
672 
673 	case NAME:
674 		ana_var(t, now, usage);
675 		break;
676 
677 	case   'p':	/* remote ref */
678 		ana_stmnt(t, now->lft->lft, RVAL);	/* process id */
679 		ana_var(t, now, RVAL);
680 		ana_var(t, now->rgt, RVAL);
681 		break;
682 
683 	default:
684 		printf("spin: %s:%d, bad node type %d (ana_stmnt)\n",
685 			now->fn->name, now->ln, now->ntyp);
686 		fatal("aborting", (char *) 0);
687 	}
688 }
689 
690 void
ana_src(int dataflow,int merger)691 ana_src(int dataflow, int merger)	/* called from main.c and guided.c */
692 {	ProcList *p;
693 	Element *e;
694 #if 0
695 	int counter = 1;
696 #endif
697 	for (p = rdy; p; p = p->nxt)
698 	{
699 		ana_seq(p->s);
700 		fsm_table();
701 
702 		e = p->s->frst;
703 #if 0
704 		if (dataflow || merger)
705 		{	printf("spin: %d, optimizing '%s'",
706 				counter++, p->n->name);
707 			fflush(stdout);
708 		}
709 #endif
710 		if (dataflow)
711 		{	FSM_ANA();
712 		}
713 		if (merger)
714 		{	FSM_MERGER(/* p->n->name */);
715 			huntele(e, e->status, -1)->merge_in = 1; /* start-state */
716 #if 0
717 			printf("\n");
718 #endif
719 		}
720 		if (export_ast)
721 			AST_store(p, huntele(e, e->status, -1)->seqno);
722 
723 		FSM_DEL();
724 	}
725 	for (e = Al_El; e; e = e->Nxt)
726 	{
727 		if (!(e->status&DONE) && (verbose&32))
728 		{	printf("unreachable code: ");
729 			printf("%s:%3d  ", e->n->fn->name, e->n->ln);
730 			comment(stdout, e->n, 0);
731 			printf("\n");
732 		}
733 		e->status &= ~DONE;
734 	}
735 	if (export_ast)
736 	{	AST_slice();
737 		alldone(0);	/* changed in 5.3.0: was exit(0) */
738 	}
739 }
740 
741 void
spit_recvs(FILE * f1,FILE * f2)742 spit_recvs(FILE *f1, FILE *f2)	/* called from pangen2.c */
743 {	Element *e;
744 	Sequence *s;
745 	extern int Unique;
746 
747 	fprintf(f1, "unsigned char Is_Recv[%d];\n", Unique);
748 
749 	fprintf(f2, "void\nset_recvs(void)\n{\n");
750 	for (e = Al_El; e; e = e->Nxt)
751 	{	if (!e->n) continue;
752 
753 		switch (e->n->ntyp) {
754 		case 'r':
755 markit:			fprintf(f2, "\tIs_Recv[%d] = 1;\n", e->Seqno);
756 			break;
757 		case D_STEP:
758 			s = e->n->sl->this;
759 			switch (s->frst->n->ntyp) {
760 			case DO:
761 				fatal("unexpected: do at start of d_step", (char *) 0);
762 			case IF: /* conservative: fall through */
763 			case 'r': goto markit;
764 			}
765 			break;
766 		}
767 	}
768 	fprintf(f2, "}\n");
769 
770 	if (rvopt)
771 	{
772 	fprintf(f2, "int\nno_recvs(int me)\n{\n");
773 	fprintf(f2, "	int h; uchar ot; short tt;\n");
774 	fprintf(f2, "	Trans *t;\n");
775 	fprintf(f2, "	for (h = BASE; h < (int) now._nr_pr; h++)\n");
776 	fprintf(f2, "	{	if (h == me) continue;\n");
777 	fprintf(f2, "		tt = (short) ((P0 *)pptr(h))->_p;\n");
778 	fprintf(f2, "		ot = (uchar) ((P0 *)pptr(h))->_t;\n");
779 	fprintf(f2, "		for (t = trans[ot][tt]; t; t = t->nxt)\n");
780 	fprintf(f2, "			if (Is_Recv[t->t_id]) return 0;\n");
781 	fprintf(f2, "	}\n");
782 	fprintf(f2, "	return 1;\n");
783 	fprintf(f2, "}\n");
784 	}
785 }
786 
787 static void
ana_seq(Sequence * s)788 ana_seq(Sequence *s)
789 {	SeqList *h;
790 	Sequence *t;
791 	Element *e, *g;
792 	int From, To;
793 
794 	for (e = s->frst; e; e = e->nxt)
795 	{	if (e->status & DONE)
796 			goto checklast;
797 
798 		e->status |= DONE;
799 
800 		From = e->seqno;
801 
802 		if (e->n->ntyp == UNLESS)
803 			ana_seq(e->sub->this);
804 		else if (e->sub)
805 		{	for (h = e->sub; h; h = h->nxt)
806 			{	g = huntstart(h->this->frst);
807 				To = g->seqno;
808 
809 				if (g->n->ntyp != 'c'
810 				||  g->n->lft->ntyp != CONST
811 				||  g->n->lft->val != 0
812 				||  g->esc)
813 					FSM_EDGE(From, To, e);
814 				/* else it's a dead link */
815 			}
816 			for (h = e->sub; h; h = h->nxt)
817 				ana_seq(h->this);
818 		} else if (e->n->ntyp == ATOMIC
819 			||  e->n->ntyp == D_STEP
820 			||  e->n->ntyp == NON_ATOMIC)
821 		{
822 			t = e->n->sl->this;
823 			g = huntstart(t->frst);
824 			t->last->nxt = e->nxt;
825 			To = g->seqno;
826 			FSM_EDGE(From, To, e);
827 
828 			ana_seq(t);
829 		} else
830 		{	if (e->n->ntyp == GOTO)
831 			{	g = get_lab(e->n, 1);
832 				g = huntele(g, e->status, -1);
833 				To = g->seqno;
834 			} else if (e->nxt)
835 			{	g = huntele(e->nxt, e->status, -1);
836 				To = g->seqno;
837 			} else
838 				To = 0;
839 
840 			FSM_EDGE(From, To, e);
841 
842 			if (e->esc
843 			&&  e->n->ntyp != GOTO
844 			&&  e->n->ntyp != '.')
845 			for (h = e->esc; h; h = h->nxt)
846 			{	g = huntstart(h->this->frst);
847 				To = g->seqno;
848 				FSM_EDGE(From, To, ZE);
849 				ana_seq(h->this);
850 			}
851 		}
852 
853 checklast:	if (e == s->last)
854 			break;
855 	}
856 }
857