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