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