Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}