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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 453 FSM_DEL(void) 454 { 455 rel_state(fsmx); 456 fsmx = (FSM_state *) 0; 457 } 458 459 static FSM_state * 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 * 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 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 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 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 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 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 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