xref: /plan9-contrib/sys/src/cmd/spin/pangen7.c (revision de2caf28f9ba1a56e70be94a699435d36eb50311)
100d97012SDavid du Colombier /***** spin: pangen7.c *****/
200d97012SDavid du Colombier 
3*de2caf28SDavid du Colombier /*
4*de2caf28SDavid du Colombier  * This file is part of the public release of Spin. It is subject to the
5*de2caf28SDavid du Colombier  * terms in the LICENSE file that is included in this source directory.
6*de2caf28SDavid du Colombier  * Tool documentation is available at http://spinroot.com
7*de2caf28SDavid du Colombier  */
800d97012SDavid du Colombier 
900d97012SDavid du Colombier #include <stdlib.h>
10*de2caf28SDavid du Colombier #include <assert.h>
1100d97012SDavid du Colombier #include "spin.h"
1200d97012SDavid du Colombier #include "y.tab.h"
1300d97012SDavid du Colombier #include <assert.h>
14*de2caf28SDavid du Colombier #ifndef PC
1500d97012SDavid du Colombier #include <unistd.h>
1600d97012SDavid du Colombier #endif
1700d97012SDavid du Colombier 
18*de2caf28SDavid du Colombier extern ProcList	*ready;
1900d97012SDavid du Colombier extern Element *Al_El;
2000d97012SDavid du Colombier extern int nclaims, verbose, Strict;
21*de2caf28SDavid du Colombier extern short has_accept;
2200d97012SDavid du Colombier 
2300d97012SDavid du Colombier typedef struct Succ_List Succ_List;
2400d97012SDavid du Colombier typedef struct SQueue SQueue;
2500d97012SDavid du Colombier typedef struct OneState OneState;
2600d97012SDavid du Colombier typedef struct State_Stack State_Stack;
2700d97012SDavid du Colombier typedef struct Guard Guard;
2800d97012SDavid du Colombier 
2900d97012SDavid du Colombier struct Succ_List {
3000d97012SDavid du Colombier 	SQueue	*s;
3100d97012SDavid du Colombier 	Succ_List *nxt;
3200d97012SDavid du Colombier };
3300d97012SDavid du Colombier 
3400d97012SDavid du Colombier struct OneState {
3500d97012SDavid du Colombier 	int	*combo;	/* the combination of claim states */
3600d97012SDavid du Colombier 	Succ_List	*succ;	/* list of ptrs to immediate successor states */
3700d97012SDavid du Colombier };
3800d97012SDavid du Colombier 
3900d97012SDavid du Colombier struct SQueue {
4000d97012SDavid du Colombier 	OneState	state;
4100d97012SDavid du Colombier 	SQueue	*nxt;
4200d97012SDavid du Colombier };
4300d97012SDavid du Colombier 
4400d97012SDavid du Colombier struct State_Stack {
4500d97012SDavid du Colombier 	int *n;
4600d97012SDavid du Colombier 	State_Stack *nxt;
4700d97012SDavid du Colombier };
4800d97012SDavid du Colombier 
4900d97012SDavid du Colombier struct Guard {
5000d97012SDavid du Colombier 	Lextok *t;
5100d97012SDavid du Colombier 	Guard *nxt;
5200d97012SDavid du Colombier };
5300d97012SDavid du Colombier 
54*de2caf28SDavid du Colombier static SQueue	*sq, *sd, *render;	/* states move from sq to sd to render to holding */
55*de2caf28SDavid du Colombier static SQueue	*holding, *lasthold;
56*de2caf28SDavid du Colombier static State_Stack *dsts;
5700d97012SDavid du Colombier 
58*de2caf28SDavid du Colombier static int nst;		/* max nr of states in claims */
59*de2caf28SDavid du Colombier static int *Ist;	/* initial states */
60*de2caf28SDavid du Colombier static int *Nacc;	/* number of accept states in claim */
61*de2caf28SDavid du Colombier static int *Nst;	/* next states */
62*de2caf28SDavid du Colombier static int **reached;	/* n claims x states */
63*de2caf28SDavid du Colombier static int unfolding;	/* to make sure all accept states are reached */
64*de2caf28SDavid du Colombier static int is_accept;	/* remember if the current state is accepting in any claim */
65*de2caf28SDavid du Colombier static int not_printing; /* set during explore_product */
6600d97012SDavid du Colombier 
67*de2caf28SDavid du Colombier static Element ****matrix;	/* n x two-dimensional arrays state x state */
68*de2caf28SDavid du Colombier static Element **Selfs;	/* self-loop states at end of claims */
6900d97012SDavid du Colombier 
7000d97012SDavid du Colombier static void get_seq(int, Sequence *);
7100d97012SDavid du Colombier static void set_el(int n, Element *e);
7200d97012SDavid du Colombier static void gen_product(void);
7300d97012SDavid du Colombier static void print_state_nm(char *, int *, char *);
7400d97012SDavid du Colombier static SQueue *find_state(int *);
7500d97012SDavid du Colombier static SQueue *retrieve_state(int *);
7600d97012SDavid du Colombier 
7700d97012SDavid du Colombier static int
same_state(int * a,int * b)7800d97012SDavid du Colombier same_state(int *a, int *b)
7900d97012SDavid du Colombier {	int i;
8000d97012SDavid du Colombier 
8100d97012SDavid du Colombier 	for (i = 0; i < nclaims; i++)
8200d97012SDavid du Colombier 	{	if (a[i] != b[i])
8300d97012SDavid du Colombier 		{	return 0;
8400d97012SDavid du Colombier 	}	}
8500d97012SDavid du Colombier 	return 1;
8600d97012SDavid du Colombier }
8700d97012SDavid du Colombier 
8800d97012SDavid du Colombier static int
in_stack(SQueue * s,SQueue * in)8900d97012SDavid du Colombier in_stack(SQueue *s, SQueue *in)
9000d97012SDavid du Colombier {	SQueue *q;
9100d97012SDavid du Colombier 
9200d97012SDavid du Colombier 	for (q = in; q; q = q->nxt)
9300d97012SDavid du Colombier 	{	if (same_state(q->state.combo, s->state.combo))
9400d97012SDavid du Colombier 		{	return 1;
9500d97012SDavid du Colombier 	}	}
9600d97012SDavid du Colombier 	return 0;
9700d97012SDavid du Colombier }
9800d97012SDavid du Colombier 
9900d97012SDavid du Colombier static void
to_render(SQueue * s)10000d97012SDavid du Colombier to_render(SQueue *s)
10100d97012SDavid du Colombier {	SQueue *a, *q, *last; /* find in sd/sq and move to render, if not already there */
10200d97012SDavid du Colombier 	int n;
10300d97012SDavid du Colombier 
10400d97012SDavid du Colombier 	for (n = 0; n < nclaims; n++)
10500d97012SDavid du Colombier 	{	reached[n][ s->state.combo[n] ] |= 2;
10600d97012SDavid du Colombier 	}
10700d97012SDavid du Colombier 
10800d97012SDavid du Colombier 	for (q = render; q; q = q->nxt)
10900d97012SDavid du Colombier 	{	if (same_state(q->state.combo, s->state.combo))
11000d97012SDavid du Colombier 		{	return;
11100d97012SDavid du Colombier 	}	}
11200d97012SDavid du Colombier 	for (q = holding; q; q = q->nxt)
11300d97012SDavid du Colombier 	{	if (same_state(q->state.combo, s->state.combo))
11400d97012SDavid du Colombier 		{	return;
11500d97012SDavid du Colombier 	}	}
11600d97012SDavid du Colombier 
11700d97012SDavid du Colombier 	a = sd;
11800d97012SDavid du Colombier more:
11900d97012SDavid du Colombier 	for (q = a, last = 0; q; last = q, q = q->nxt)
12000d97012SDavid du Colombier 	{	if (same_state(q->state.combo, s->state.combo))
12100d97012SDavid du Colombier 		{	if (!last)
12200d97012SDavid du Colombier 			{	if (a == sd)
12300d97012SDavid du Colombier 				{	sd = q->nxt;
12400d97012SDavid du Colombier 				} else if (a == sq)
12500d97012SDavid du Colombier 				{	sq = q->nxt;
12600d97012SDavid du Colombier 				} else
12700d97012SDavid du Colombier 				{	holding = q->nxt;
12800d97012SDavid du Colombier 				}
12900d97012SDavid du Colombier 			} else
13000d97012SDavid du Colombier 			{	last->nxt = q->nxt;
13100d97012SDavid du Colombier 			}
13200d97012SDavid du Colombier 			q->nxt = render;
13300d97012SDavid du Colombier 			render = q;
13400d97012SDavid du Colombier 			return;
13500d97012SDavid du Colombier 	}	}
13600d97012SDavid du Colombier 	if (verbose)
13700d97012SDavid du Colombier 	{	print_state_nm("looking for: ", s->state.combo, "\n");
13800d97012SDavid du Colombier 	}
13900d97012SDavid du Colombier 	(void) find_state(s->state.combo);	/* creates it in sq */
14000d97012SDavid du Colombier 	if (a != sq)
14100d97012SDavid du Colombier 	{	a = sq;
14200d97012SDavid du Colombier 		goto more;
14300d97012SDavid du Colombier 	}
14400d97012SDavid du Colombier 	fatal("cannot happen, to_render", 0);
14500d97012SDavid du Colombier }
14600d97012SDavid du Colombier 
14700d97012SDavid du Colombier static void
wrap_text(char * pre,Lextok * t,char * post)14800d97012SDavid du Colombier wrap_text(char *pre, Lextok *t, char *post)
14900d97012SDavid du Colombier {
150*de2caf28SDavid du Colombier 	printf(pre, (char *) 0);
15100d97012SDavid du Colombier 	comment(stdout, t, 0);
152*de2caf28SDavid du Colombier 	printf(post, (char *) 0);
15300d97012SDavid du Colombier }
15400d97012SDavid du Colombier 
15500d97012SDavid du Colombier static State_Stack *
push_dsts(int * n)15600d97012SDavid du Colombier push_dsts(int *n)
15700d97012SDavid du Colombier {	State_Stack *s;
15800d97012SDavid du Colombier 	int i;
15900d97012SDavid du Colombier 
16000d97012SDavid du Colombier 	for (s = dsts; s; s = s->nxt)
16100d97012SDavid du Colombier 	{	if (same_state(s->n, n))
16200d97012SDavid du Colombier 		{	if (verbose&64)
16300d97012SDavid du Colombier 			{	printf("\n");
16400d97012SDavid du Colombier 				for (s = dsts; s; s = s->nxt)
16500d97012SDavid du Colombier 				{	print_state_nm("\t", s->n, "\n");
16600d97012SDavid du Colombier 				}
16700d97012SDavid du Colombier 				print_state_nm("\t", n, "\n");
16800d97012SDavid du Colombier 			}
16900d97012SDavid du Colombier 			return s;
17000d97012SDavid du Colombier 	}	}
17100d97012SDavid du Colombier 
17200d97012SDavid du Colombier 	s = (State_Stack *) emalloc(sizeof(State_Stack));
17300d97012SDavid du Colombier 	s->n = (int *) emalloc(nclaims * sizeof(int));
17400d97012SDavid du Colombier 	for (i = 0; i < nclaims; i++)
17500d97012SDavid du Colombier 		s->n[i] = n[i];
17600d97012SDavid du Colombier 	s->nxt = dsts;
17700d97012SDavid du Colombier 	dsts = s;
17800d97012SDavid du Colombier 	return 0;
17900d97012SDavid du Colombier }
18000d97012SDavid du Colombier 
18100d97012SDavid du Colombier static void
pop_dsts(void)18200d97012SDavid du Colombier pop_dsts(void)
18300d97012SDavid du Colombier {
184*de2caf28SDavid du Colombier 	assert(dsts != NULL);
18500d97012SDavid du Colombier 	dsts = dsts->nxt;
18600d97012SDavid du Colombier }
18700d97012SDavid du Colombier 
18800d97012SDavid du Colombier static void
complete_transition(Succ_List * sl,Guard * g)18900d97012SDavid du Colombier complete_transition(Succ_List *sl, Guard *g)
19000d97012SDavid du Colombier {	Guard *w;
19100d97012SDavid du Colombier 	int cnt = 0;
19200d97012SDavid du Colombier 
19300d97012SDavid du Colombier 	printf("	:: ");
19400d97012SDavid du Colombier 	for (w = g; w; w = w->nxt)
19500d97012SDavid du Colombier 	{	if (w->t->ntyp == CONST
19600d97012SDavid du Colombier 		&&  w->t->val == 1)
19700d97012SDavid du Colombier 		{	continue;
19800d97012SDavid du Colombier 		} else if (w->t->ntyp == 'c'
19900d97012SDavid du Colombier 		&&  w->t->lft->ntyp == CONST
20000d97012SDavid du Colombier 		&&  w->t->lft->val == 1)
20100d97012SDavid du Colombier 		{	continue; /* 'true' */
20200d97012SDavid du Colombier 		}
20300d97012SDavid du Colombier 
20400d97012SDavid du Colombier 		if (cnt > 0)
20500d97012SDavid du Colombier 		{	printf(" && ");
20600d97012SDavid du Colombier 		}
20700d97012SDavid du Colombier 		wrap_text("", w->t, "");
20800d97012SDavid du Colombier 		cnt++;
20900d97012SDavid du Colombier 	}
21000d97012SDavid du Colombier 	if (cnt == 0)
21100d97012SDavid du Colombier 	{	printf("true");
21200d97012SDavid du Colombier 	}
21300d97012SDavid du Colombier 	print_state_nm(" -> goto ", sl->s->state.combo, "");
21400d97012SDavid du Colombier 
21500d97012SDavid du Colombier 	if (is_accept > 0)
21600d97012SDavid du Colombier 	{	printf("_U%d\n", (unfolding+1)%nclaims);
21700d97012SDavid du Colombier 	} else
21800d97012SDavid du Colombier 	{	printf("_U%d\n", unfolding);
21900d97012SDavid du Colombier 	}
22000d97012SDavid du Colombier }
22100d97012SDavid du Colombier 
22200d97012SDavid du Colombier static void
state_body(OneState * s,Guard * guard)22300d97012SDavid du Colombier state_body(OneState *s, Guard *guard)
22400d97012SDavid du Colombier {	Succ_List *sl;
22500d97012SDavid du Colombier 	State_Stack *y;
22600d97012SDavid du Colombier 	Guard *g;
22700d97012SDavid du Colombier 	int i, once;
22800d97012SDavid du Colombier 
22900d97012SDavid du Colombier 	for (sl = s->succ; sl; sl = sl->nxt)
23000d97012SDavid du Colombier 	{	once = 0;
23100d97012SDavid du Colombier 
23200d97012SDavid du Colombier 		for (i = 0; i < nclaims; i++)
23300d97012SDavid du Colombier 		{	Element *e;
23400d97012SDavid du Colombier 			e = matrix[i][s->combo[i]][sl->s->state.combo[i]];
23500d97012SDavid du Colombier 
23600d97012SDavid du Colombier 			/* if one of the claims has a DO or IF move
23700d97012SDavid du Colombier 			   then pull its target state forward, once
23800d97012SDavid du Colombier 			 */
23900d97012SDavid du Colombier 
24000d97012SDavid du Colombier 			if (!e
24100d97012SDavid du Colombier 			|| e->n->ntyp == NON_ATOMIC
24200d97012SDavid du Colombier 			||  e->n->ntyp == DO
24300d97012SDavid du Colombier 			||  e->n->ntyp == IF)
24400d97012SDavid du Colombier 			{	s = &(sl->s->state);
24500d97012SDavid du Colombier 				y = push_dsts(s->combo);
24600d97012SDavid du Colombier 				if (!y)
24700d97012SDavid du Colombier 				{	if (once++ == 0)
248*de2caf28SDavid du Colombier 					{	assert(s->succ != NULL);
24900d97012SDavid du Colombier 						state_body(s, guard);
25000d97012SDavid du Colombier 					}
25100d97012SDavid du Colombier 					pop_dsts();
25200d97012SDavid du Colombier 				} else if (!y->nxt)	/* self-loop transition */
25300d97012SDavid du Colombier 				{	if (!not_printing) printf(" /* self-loop */\n");
25400d97012SDavid du Colombier 				} else
25500d97012SDavid du Colombier 				{	/* non_fatal("loop in state body", 0); ** maybe ok */
25600d97012SDavid du Colombier 				}
25700d97012SDavid du Colombier 				continue;
25800d97012SDavid du Colombier 			} else
25900d97012SDavid du Colombier 			{	g = (Guard *) emalloc(sizeof(Guard));
26000d97012SDavid du Colombier 				g->t = e->n;
26100d97012SDavid du Colombier 				g->nxt = guard;
26200d97012SDavid du Colombier 				guard = g;
26300d97012SDavid du Colombier 		}	}
26400d97012SDavid du Colombier 
26500d97012SDavid du Colombier 		if (guard && !once)
26600d97012SDavid du Colombier 		{	if (!not_printing) complete_transition(sl, guard);
26700d97012SDavid du Colombier 			to_render(sl->s);
26800d97012SDavid du Colombier 	}	}
26900d97012SDavid du Colombier }
27000d97012SDavid du Colombier 
271*de2caf28SDavid du Colombier static struct X_tbl {
27200d97012SDavid du Colombier 	char *s;	int n;
27300d97012SDavid du Colombier } spl[] = {
27400d97012SDavid du Colombier 	{"end",		3 },
27500d97012SDavid du Colombier 	{"accept",	6 },
27600d97012SDavid du Colombier 	{0,		0 },
27700d97012SDavid du Colombier };
27800d97012SDavid du Colombier 
27900d97012SDavid du Colombier static int slcnt;
28000d97012SDavid du Colombier extern Label *labtab;
28100d97012SDavid du Colombier 
28200d97012SDavid du Colombier static ProcList *
locate_claim(int n)28300d97012SDavid du Colombier locate_claim(int n)
28400d97012SDavid du Colombier {	ProcList *p;
28500d97012SDavid du Colombier 	int i;
28600d97012SDavid du Colombier 
287*de2caf28SDavid du Colombier 	for (p = ready, i = 0; p; p = p->nxt, i++) /* find claim name */
28800d97012SDavid du Colombier 	{	if (i == n)
28900d97012SDavid du Colombier 		{	break;
29000d97012SDavid du Colombier 	}	}
29100d97012SDavid du Colombier 	assert(p && p->b == N_CLAIM);
29200d97012SDavid du Colombier 
29300d97012SDavid du Colombier 	return p;
29400d97012SDavid du Colombier }
29500d97012SDavid du Colombier 
29600d97012SDavid du Colombier static void
elim_lab(Element * e)29700d97012SDavid du Colombier elim_lab(Element *e)
29800d97012SDavid du Colombier {	Label *l, *lst;
29900d97012SDavid du Colombier 
30000d97012SDavid du Colombier 	for (l = labtab, lst = NULL; l; lst = l, l = l->nxt)
30100d97012SDavid du Colombier 	{	if (l->e == e)
30200d97012SDavid du Colombier 		{	if (lst)
30300d97012SDavid du Colombier 			{	lst->nxt = l->nxt;
30400d97012SDavid du Colombier 			} else
30500d97012SDavid du Colombier 			{	labtab = l->nxt;
30600d97012SDavid du Colombier 			}
30700d97012SDavid du Colombier 			break;
30800d97012SDavid du Colombier 	}	}
30900d97012SDavid du Colombier }
31000d97012SDavid du Colombier 
31100d97012SDavid du Colombier static int
claim_has_accept(ProcList * p)31200d97012SDavid du Colombier claim_has_accept(ProcList *p)
31300d97012SDavid du Colombier {	Label *l;
31400d97012SDavid du Colombier 
31500d97012SDavid du Colombier 	for (l = labtab; l; l = l->nxt)
31600d97012SDavid du Colombier 	{	if (strcmp(l->c->name, p->n->name) == 0
31700d97012SDavid du Colombier 		&&  strncmp(l->s->name, "accept", 6) == 0)
31800d97012SDavid du Colombier 		{	return 1;
31900d97012SDavid du Colombier 	}	}
32000d97012SDavid du Colombier 	return 0;
32100d97012SDavid du Colombier }
32200d97012SDavid du Colombier 
32300d97012SDavid du Colombier static void
prune_accept(void)32400d97012SDavid du Colombier prune_accept(void)
32500d97012SDavid du Colombier {	int n;
32600d97012SDavid du Colombier 
32700d97012SDavid du Colombier 	for (n = 0; n < nclaims; n++)
32800d97012SDavid du Colombier 	{	if ((reached[n][Selfs[n]->seqno] & 2) == 0)
32900d97012SDavid du Colombier 		{	if (verbose)
33000d97012SDavid du Colombier 			{	printf("claim %d: selfloop not reachable\n", n);
33100d97012SDavid du Colombier 			}
33200d97012SDavid du Colombier 			elim_lab(Selfs[n]);
33300d97012SDavid du Colombier 			Nacc[n] = claim_has_accept(locate_claim(n));
33400d97012SDavid du Colombier 	}	}
33500d97012SDavid du Colombier }
33600d97012SDavid du Colombier 
33700d97012SDavid du Colombier static void
mk_accepting(int n,Element * e)33800d97012SDavid du Colombier mk_accepting(int n, Element *e)
33900d97012SDavid du Colombier {	ProcList *p;
34000d97012SDavid du Colombier 	Label *l;
34100d97012SDavid du Colombier 	int i;
34200d97012SDavid du Colombier 
34300d97012SDavid du Colombier 	assert(!Selfs[n]);
34400d97012SDavid du Colombier 	Selfs[n] = e;
34500d97012SDavid du Colombier 
34600d97012SDavid du Colombier 	l = (Label *) emalloc(sizeof(Label));
34700d97012SDavid du Colombier 	l->s = (Symbol *) emalloc(sizeof(Symbol));
34800d97012SDavid du Colombier 	l->s->name = "accept00";
34900d97012SDavid du Colombier 	l->c = (Symbol *) emalloc(sizeof(Symbol));
35000d97012SDavid du Colombier 	l->uiid = 0;	/* this is not in an inline */
35100d97012SDavid du Colombier 
352*de2caf28SDavid du Colombier 	for (p = ready, i = 0; p; p = p->nxt, i++) /* find claim name */
35300d97012SDavid du Colombier 	{	if (i == n)
35400d97012SDavid du Colombier 		{	l->c->name = p->n->name;
35500d97012SDavid du Colombier 			break;
35600d97012SDavid du Colombier 	}	}
35700d97012SDavid du Colombier 	assert(p && p->b == N_CLAIM);
35800d97012SDavid du Colombier 	Nacc[n] = 1;
359*de2caf28SDavid du Colombier 	has_accept = 1;
36000d97012SDavid du Colombier 
36100d97012SDavid du Colombier 	l->e = e;
36200d97012SDavid du Colombier 	l->nxt = labtab;
36300d97012SDavid du Colombier 	labtab = l;
36400d97012SDavid du Colombier }
36500d97012SDavid du Colombier 
36600d97012SDavid du Colombier static void
check_special(int * nrs)36700d97012SDavid du Colombier check_special(int *nrs)
36800d97012SDavid du Colombier {	ProcList *p;
36900d97012SDavid du Colombier 	Label *l;
37000d97012SDavid du Colombier 	int i, j, nmatches;
37100d97012SDavid du Colombier 	int any_accepts = 0;
37200d97012SDavid du Colombier 
37300d97012SDavid du Colombier 	for (i = 0; i < nclaims; i++)
37400d97012SDavid du Colombier 	{	any_accepts += Nacc[i];
37500d97012SDavid du Colombier 	}
37600d97012SDavid du Colombier 
37700d97012SDavid du Colombier 	is_accept = 0;
37800d97012SDavid du Colombier 	for (j = 0; spl[j].n; j++) /* 2 special label prefixes */
37900d97012SDavid du Colombier 	{	nmatches = 0;
380*de2caf28SDavid du Colombier 		for (p = ready, i = 0; p; p = p->nxt, i++) /* check each claim */
38100d97012SDavid du Colombier 		{	if (p->b != N_CLAIM)
38200d97012SDavid du Colombier 			{	continue;
38300d97012SDavid du Colombier 			}
38400d97012SDavid du Colombier 			/* claim i in state nrs[i], type p->tn, name p->n->name
38500d97012SDavid du Colombier 			 * either the state has an accept label, or the claim has none,
38600d97012SDavid du Colombier 			 * so that all its states should be considered accepting
38700d97012SDavid du Colombier 			 * --- but only if other claims do have accept states!
38800d97012SDavid du Colombier 			 */
38900d97012SDavid du Colombier 			if (Strict == 0 && j == 1 && Nacc[i] == 0 && any_accepts > 0)
39000d97012SDavid du Colombier 			{	if ((verbose&32) && i == unfolding)
39100d97012SDavid du Colombier 				{	printf("	/* claim %d pseudo-accept */\n", i);
39200d97012SDavid du Colombier 				}
39300d97012SDavid du Colombier 				goto is_accepting;
39400d97012SDavid du Colombier 			}
39500d97012SDavid du Colombier 			for (l = labtab; l; l = l->nxt)	/* check its labels */
39600d97012SDavid du Colombier 			{	if (strcmp(l->c->name, p->n->name) == 0  /* right claim */
39700d97012SDavid du Colombier 				&&  l->e->seqno == nrs[i]		 /* right state */
39800d97012SDavid du Colombier 				&&  strncmp(l->s->name, spl[j].s, spl[j].n) == 0)
39900d97012SDavid du Colombier 				{	if (j == 1)	/* accept state */
40000d97012SDavid du Colombier 					{	char buf[32];
40100d97012SDavid du Colombier is_accepting:					if (strchr(p->n->name, ':'))
40200d97012SDavid du Colombier 						{	sprintf(buf, "N%d", i);
40300d97012SDavid du Colombier 						} else
404*de2caf28SDavid du Colombier 						{	assert(strlen(p->n->name) < sizeof(buf));
405*de2caf28SDavid du Colombier 							strcpy(buf, p->n->name);
40600d97012SDavid du Colombier 						}
40700d97012SDavid du Colombier 						if (unfolding == 0 && i == 0)
40800d97012SDavid du Colombier 						{	if (!not_printing)
40900d97012SDavid du Colombier 							printf("%s_%s_%d:\n",	/* true accept */
41000d97012SDavid du Colombier 								spl[j].s, buf, slcnt++);
41100d97012SDavid du Colombier 						} else if (verbose&32)
41200d97012SDavid du Colombier 						{	if (!not_printing)
41300d97012SDavid du Colombier 							printf("%s_%s%d:\n",
41400d97012SDavid du Colombier 								buf, spl[j].s, slcnt++);
41500d97012SDavid du Colombier 						}
41600d97012SDavid du Colombier 						if (i == unfolding)
41700d97012SDavid du Colombier 						{	is_accept++; /* move to next unfolding */
41800d97012SDavid du Colombier 						}
41900d97012SDavid du Colombier 					} else
42000d97012SDavid du Colombier 					{	nmatches++;
42100d97012SDavid du Colombier 					}
42200d97012SDavid du Colombier 					break;
42300d97012SDavid du Colombier 		}	}	}
42400d97012SDavid du Colombier 		if (j == 0 && nmatches == nclaims)	/* end-state */
42500d97012SDavid du Colombier 		{	if (!not_printing)
42600d97012SDavid du Colombier 			{	printf("%s%d:\n", spl[j].s, slcnt++);
42700d97012SDavid du Colombier 	}	}	}
42800d97012SDavid du Colombier }
42900d97012SDavid du Colombier 
43000d97012SDavid du Colombier static int
render_state(SQueue * q)43100d97012SDavid du Colombier render_state(SQueue *q)
43200d97012SDavid du Colombier {
43300d97012SDavid du Colombier 	if (!q || !q->state.succ)
43400d97012SDavid du Colombier 	{	if (verbose&64)
43500d97012SDavid du Colombier 		{	printf("	no exit\n");
43600d97012SDavid du Colombier 		}
43700d97012SDavid du Colombier 		return 0;
43800d97012SDavid du Colombier 	}
43900d97012SDavid du Colombier 
44000d97012SDavid du Colombier 	check_special(q->state.combo); /* accept or end-state labels */
44100d97012SDavid du Colombier 
44200d97012SDavid du Colombier 	dsts = (State_Stack *) 0;
44300d97012SDavid du Colombier 	push_dsts(q->state.combo);	/* to detect loops */
44400d97012SDavid du Colombier 
44500d97012SDavid du Colombier 	if (!not_printing)
44600d97012SDavid du Colombier 	{	print_state_nm("", q->state.combo, "");	/* the name */
44700d97012SDavid du Colombier 		printf("_U%d:\n\tdo\n", unfolding);
44800d97012SDavid du Colombier 	}
44900d97012SDavid du Colombier 
45000d97012SDavid du Colombier 	state_body(&(q->state), (Guard *) 0);
45100d97012SDavid du Colombier 
45200d97012SDavid du Colombier 	if (!not_printing)
45300d97012SDavid du Colombier 	{	printf("\tod;\n");
45400d97012SDavid du Colombier 	}
45500d97012SDavid du Colombier 	pop_dsts();
45600d97012SDavid du Colombier 	return 1;
45700d97012SDavid du Colombier }
45800d97012SDavid du Colombier 
45900d97012SDavid du Colombier static void
explore_product(void)46000d97012SDavid du Colombier explore_product(void)
46100d97012SDavid du Colombier {	SQueue *q;
46200d97012SDavid du Colombier 
46300d97012SDavid du Colombier 	/* all states are in the sd queue */
46400d97012SDavid du Colombier 
46500d97012SDavid du Colombier 	q = retrieve_state(Ist);	/* retrieve from the sd q */
46600d97012SDavid du Colombier 	q->nxt = render;		/* put in render q */
46700d97012SDavid du Colombier 	render = q;
46800d97012SDavid du Colombier 	do {
46900d97012SDavid du Colombier 		q = render;
47000d97012SDavid du Colombier 		render = render->nxt;
47100d97012SDavid du Colombier 		q->nxt = 0;		/* remove from render q */
47200d97012SDavid du Colombier 
47300d97012SDavid du Colombier 		if (verbose&64)
47400d97012SDavid du Colombier 		{	print_state_nm("explore: ", q->state.combo, "\n");
47500d97012SDavid du Colombier 		}
47600d97012SDavid du Colombier 
47700d97012SDavid du Colombier 		not_printing = 1;
47800d97012SDavid du Colombier 		render_state(q);	/* may add new states */
47900d97012SDavid du Colombier 		not_printing = 0;
48000d97012SDavid du Colombier 
48100d97012SDavid du Colombier 		if (lasthold)
48200d97012SDavid du Colombier 		{	lasthold->nxt = q;
48300d97012SDavid du Colombier 			lasthold = q;
48400d97012SDavid du Colombier 		} else
48500d97012SDavid du Colombier 		{	holding = lasthold = q;
48600d97012SDavid du Colombier 		}
48700d97012SDavid du Colombier 	} while (render);
48800d97012SDavid du Colombier 	assert(!dsts);
48900d97012SDavid du Colombier 
49000d97012SDavid du Colombier }
49100d97012SDavid du Colombier 
49200d97012SDavid du Colombier static void
print_product(void)49300d97012SDavid du Colombier print_product(void)
49400d97012SDavid du Colombier {	SQueue *q;
49500d97012SDavid du Colombier 	int cnt;
49600d97012SDavid du Colombier 
49700d97012SDavid du Colombier 	if (unfolding == 0)
49800d97012SDavid du Colombier 	{	printf("never Product {\n");	/* name expected by iSpin */
49900d97012SDavid du Colombier 		q = find_state(Ist);	/* should find it in the holding q */
500*de2caf28SDavid du Colombier 		assert(q != NULL);
50100d97012SDavid du Colombier 		q->nxt = holding;	/* put it at the front */
50200d97012SDavid du Colombier 		holding = q;
50300d97012SDavid du Colombier 	}
50400d97012SDavid du Colombier 	render = holding;
50500d97012SDavid du Colombier 	holding = lasthold = 0;
50600d97012SDavid du Colombier 
50700d97012SDavid du Colombier 	printf("/* ============= U%d ============= */\n", unfolding);
50800d97012SDavid du Colombier 	cnt = 0;
50900d97012SDavid du Colombier 	do {
51000d97012SDavid du Colombier 		q = render;
51100d97012SDavid du Colombier 		render = render->nxt;
51200d97012SDavid du Colombier 		q->nxt = 0;
51300d97012SDavid du Colombier 		if (verbose&64)
51400d97012SDavid du Colombier 		{	print_state_nm("print: ", q->state.combo, "\n");
51500d97012SDavid du Colombier 		}
51600d97012SDavid du Colombier 		cnt += render_state(q);
51700d97012SDavid du Colombier 
51800d97012SDavid du Colombier 		if (lasthold)
51900d97012SDavid du Colombier 		{	lasthold->nxt = q;
52000d97012SDavid du Colombier 			lasthold = q;
52100d97012SDavid du Colombier 		} else
52200d97012SDavid du Colombier 		{	holding = lasthold = q;
52300d97012SDavid du Colombier 		}
52400d97012SDavid du Colombier 	} while (render);
52500d97012SDavid du Colombier 	assert(!dsts);
52600d97012SDavid du Colombier 
52700d97012SDavid du Colombier 	if (cnt == 0)
52800d97012SDavid du Colombier 	{	printf("	0;\n");
52900d97012SDavid du Colombier 	}
53000d97012SDavid du Colombier 
53100d97012SDavid du Colombier 	if (unfolding == nclaims-1)
53200d97012SDavid du Colombier 	{	printf("}\n");
53300d97012SDavid du Colombier 	}
53400d97012SDavid du Colombier }
53500d97012SDavid du Colombier 
53600d97012SDavid du Colombier static void
prune_dead(void)53700d97012SDavid du Colombier prune_dead(void)
53800d97012SDavid du Colombier {	Succ_List *sl, *last;
53900d97012SDavid du Colombier 	SQueue *q;
54000d97012SDavid du Colombier 	int cnt;
54100d97012SDavid du Colombier 
54200d97012SDavid du Colombier 	do {	cnt = 0;
54300d97012SDavid du Colombier 		for (q = sd; q; q = q->nxt)
54400d97012SDavid du Colombier 		{	/* if successor is deadend, remove it
54500d97012SDavid du Colombier 			 * unless it's a move to the end-state of the claim
54600d97012SDavid du Colombier 			 */
54700d97012SDavid du Colombier 			last = (Succ_List *) 0;
54800d97012SDavid du Colombier 			for (sl = q->state.succ; sl; last = sl, sl = sl->nxt)
54900d97012SDavid du Colombier 			{	if (!sl->s->state.succ)	/* no successor */
55000d97012SDavid du Colombier 				{	if (!last)
55100d97012SDavid du Colombier 					{	q->state.succ = sl->nxt;
55200d97012SDavid du Colombier 					} else
55300d97012SDavid du Colombier 					{	last->nxt = sl->nxt;
55400d97012SDavid du Colombier 					}
55500d97012SDavid du Colombier 					cnt++;
55600d97012SDavid du Colombier 		}	}	}
55700d97012SDavid du Colombier 	} while (cnt > 0);
55800d97012SDavid du Colombier }
55900d97012SDavid du Colombier 
56000d97012SDavid du Colombier static void
print_raw(void)56100d97012SDavid du Colombier print_raw(void)
56200d97012SDavid du Colombier {	int i, j, n;
56300d97012SDavid du Colombier 
56400d97012SDavid du Colombier 	printf("#if 0\n");
56500d97012SDavid du Colombier 	for (n = 0; n < nclaims; n++)
56600d97012SDavid du Colombier 	{	printf("C%d:\n", n);
56700d97012SDavid du Colombier 		for (i = 0; i < nst; i++)
56800d97012SDavid du Colombier 		{	if (reached[n][i])
56900d97012SDavid du Colombier 			for (j = 0; j < nst; j++)
57000d97012SDavid du Colombier 			{	if (matrix[n][i][j])
57100d97012SDavid du Colombier 				{	if (reached[n][i] & 2) printf("+");
57200d97012SDavid du Colombier 					if (i == Ist[n]) printf("*");
57300d97012SDavid du Colombier 					printf("\t%d", i);
57400d97012SDavid du Colombier 					wrap_text(" -[", matrix[n][i][j]->n, "]->\t");
57500d97012SDavid du Colombier 					printf("%d\n", j);
57600d97012SDavid du Colombier 	}	}	}	}
57700d97012SDavid du Colombier 	printf("#endif\n\n");
57800d97012SDavid du Colombier 	fflush(stdout);
57900d97012SDavid du Colombier }
58000d97012SDavid du Colombier 
58100d97012SDavid du Colombier void
sync_product(void)58200d97012SDavid du Colombier sync_product(void)
58300d97012SDavid du Colombier {	ProcList *p;
58400d97012SDavid du Colombier 	Element *e;
58500d97012SDavid du Colombier 	int n, i;
58600d97012SDavid du Colombier 
58700d97012SDavid du Colombier 	if (nclaims <= 1) return;
58800d97012SDavid du Colombier 
58900d97012SDavid du Colombier 	(void) unlink("pan.pre");
59000d97012SDavid du Colombier 
59100d97012SDavid du Colombier 	Ist  = (int *) emalloc(sizeof(int) * nclaims);
59200d97012SDavid du Colombier 	Nacc = (int *) emalloc(sizeof(int) * nclaims);
59300d97012SDavid du Colombier 	Nst  = (int *) emalloc(sizeof(int) * nclaims);
59400d97012SDavid du Colombier 	reached = (int **) emalloc(sizeof(int *) * nclaims);
59500d97012SDavid du Colombier 	Selfs   = (Element **) emalloc(sizeof(Element *) * nclaims);
59600d97012SDavid du Colombier 	matrix  = (Element ****) emalloc(sizeof(Element ***) * nclaims); /* claims */
59700d97012SDavid du Colombier 
598*de2caf28SDavid du Colombier 	for (p = ready, i = 0; p; p = p->nxt, i++)
59900d97012SDavid du Colombier 	{	if (p->b == N_CLAIM)
60000d97012SDavid du Colombier 		{	nst = max(p->s->maxel, nst);
60100d97012SDavid du Colombier 			Nacc[i] = claim_has_accept(p);
60200d97012SDavid du Colombier 	}	}
60300d97012SDavid du Colombier 
60400d97012SDavid du Colombier 	for (n = 0; n < nclaims; n++)
60500d97012SDavid du Colombier 	{	reached[n] = (int *) emalloc(sizeof(int) * nst);
60600d97012SDavid du Colombier 		matrix[n] = (Element ***) emalloc(sizeof(Element **) * nst);	/* rows */
60700d97012SDavid du Colombier 		for (i = 0; i < nst; i++)					/* cols */
60800d97012SDavid du Colombier 		{	matrix[n][i] = (Element **) emalloc(sizeof(Element *) * nst);
60900d97012SDavid du Colombier 	}	}
61000d97012SDavid du Colombier 
61100d97012SDavid du Colombier 	for (e = Al_El; e; e = e->Nxt)
61200d97012SDavid du Colombier 	{	e->status &= ~DONE;
61300d97012SDavid du Colombier 	}
61400d97012SDavid du Colombier 
615*de2caf28SDavid du Colombier 	for (p = ready, n=0; p; p = p->nxt, n++)
61600d97012SDavid du Colombier 	{	if (p->b == N_CLAIM)
61700d97012SDavid du Colombier 		{	/* fill in matrix[n] */
61800d97012SDavid du Colombier 			e = p->s->frst;
61900d97012SDavid du Colombier 			Ist[n] = huntele(e, e->status, -1)->seqno;
62000d97012SDavid du Colombier 
62100d97012SDavid du Colombier 			reached[n][Ist[n]] = 1|2;
62200d97012SDavid du Colombier 			get_seq(n, p->s);
62300d97012SDavid du Colombier 	}	}
62400d97012SDavid du Colombier 
62500d97012SDavid du Colombier 	if (verbose)	/* show only the input automata */
62600d97012SDavid du Colombier 	{	print_raw();
62700d97012SDavid du Colombier 	}
62800d97012SDavid du Colombier 
62900d97012SDavid du Colombier 	gen_product();	/* create product automaton */
63000d97012SDavid du Colombier }
63100d97012SDavid du Colombier 
63200d97012SDavid du Colombier static int
nxt_trans(int n,int cs,int frst)63300d97012SDavid du Colombier nxt_trans(int n, int cs, int frst)
63400d97012SDavid du Colombier {	int j;
63500d97012SDavid du Colombier 
63600d97012SDavid du Colombier 	for (j = frst; j < nst; j++)
63700d97012SDavid du Colombier 	{	if (reached[n][cs]
63800d97012SDavid du Colombier 		&&  matrix[n][cs][j])
63900d97012SDavid du Colombier 		{	return j;
64000d97012SDavid du Colombier 	}	}
64100d97012SDavid du Colombier 	return -1;
64200d97012SDavid du Colombier }
64300d97012SDavid du Colombier 
64400d97012SDavid du Colombier static void
print_state_nm(char * p,int * s,char * a)64500d97012SDavid du Colombier print_state_nm(char *p, int *s, char *a)
64600d97012SDavid du Colombier {	int i;
64700d97012SDavid du Colombier 	printf("%sP", p);
64800d97012SDavid du Colombier 	for (i = 0; i < nclaims; i++)
64900d97012SDavid du Colombier 	{	printf("_%d", s[i]);
65000d97012SDavid du Colombier 	}
65100d97012SDavid du Colombier 	printf("%s", a);
65200d97012SDavid du Colombier }
65300d97012SDavid du Colombier 
65400d97012SDavid du Colombier static void
create_transition(OneState * s,SQueue * it)65500d97012SDavid du Colombier create_transition(OneState *s, SQueue *it)
65600d97012SDavid du Colombier {	int n, from, upto;
65700d97012SDavid du Colombier 	int *F = s->combo;
65800d97012SDavid du Colombier 	int *T = it->state.combo;
65900d97012SDavid du Colombier 	Succ_List *sl;
66000d97012SDavid du Colombier 	Lextok *t;
66100d97012SDavid du Colombier 
66200d97012SDavid du Colombier 	if (verbose&64)
66300d97012SDavid du Colombier 	{	print_state_nm("", F, " ");
66400d97012SDavid du Colombier 		print_state_nm("-> ", T, "\t");
66500d97012SDavid du Colombier 	}
66600d97012SDavid du Colombier 
66700d97012SDavid du Colombier 	/* check if any of the claims is blocked */
66800d97012SDavid du Colombier 	/* which makes the state a dead-end */
66900d97012SDavid du Colombier 	for (n = 0; n < nclaims; n++)
67000d97012SDavid du Colombier 	{	from = F[n];
67100d97012SDavid du Colombier 		upto = T[n];
67200d97012SDavid du Colombier 		t = matrix[n][from][upto]->n;
67300d97012SDavid du Colombier 		if (verbose&64)
67400d97012SDavid du Colombier 		{	wrap_text("", t, " ");
67500d97012SDavid du Colombier 		}
67600d97012SDavid du Colombier 		if (t->ntyp == 'c'
67700d97012SDavid du Colombier 		&&  t->lft->ntyp == CONST)
67800d97012SDavid du Colombier 		{	if (t->lft->val == 0)	/* i.e., false */
67900d97012SDavid du Colombier 			{	goto done;
68000d97012SDavid du Colombier 	}	}	}
68100d97012SDavid du Colombier 
68200d97012SDavid du Colombier 	sl = (Succ_List *) emalloc(sizeof(Succ_List));
68300d97012SDavid du Colombier 	sl->s = it;
68400d97012SDavid du Colombier 	sl->nxt = s->succ;
68500d97012SDavid du Colombier 	s->succ = sl;
68600d97012SDavid du Colombier done:
68700d97012SDavid du Colombier 	if (verbose&64)
68800d97012SDavid du Colombier 	{	printf("\n");
68900d97012SDavid du Colombier 	}
69000d97012SDavid du Colombier }
69100d97012SDavid du Colombier 
69200d97012SDavid du Colombier static SQueue *
find_state(int * cs)69300d97012SDavid du Colombier find_state(int *cs)
69400d97012SDavid du Colombier {	SQueue *nq, *a = sq;
69500d97012SDavid du Colombier 	int i;
69600d97012SDavid du Colombier 
69700d97012SDavid du Colombier again:	/* check in nq, sq, and then in the render q */
69800d97012SDavid du Colombier 	for (nq = a; nq; nq = nq->nxt)
69900d97012SDavid du Colombier 	{	if (same_state(nq->state.combo, cs))
70000d97012SDavid du Colombier 		{	return nq;	/* found */
70100d97012SDavid du Colombier 	}	}
70200d97012SDavid du Colombier 	if (a == sq && sd)
70300d97012SDavid du Colombier 	{	a = sd;
70400d97012SDavid du Colombier 		goto again; /* check the other stack too */
70500d97012SDavid du Colombier 	} else if (a == sd && render)
70600d97012SDavid du Colombier 	{	a = render;
70700d97012SDavid du Colombier 		goto again;
70800d97012SDavid du Colombier 	}
70900d97012SDavid du Colombier 
71000d97012SDavid du Colombier 	nq = (SQueue *) emalloc(sizeof(SQueue));
71100d97012SDavid du Colombier 	nq->state.combo = (int *) emalloc(nclaims * sizeof(int));
71200d97012SDavid du Colombier 	for (i = 0; i < nclaims; i++)
71300d97012SDavid du Colombier 	{	nq->state.combo[i] = cs[i];
71400d97012SDavid du Colombier 	}
71500d97012SDavid du Colombier 	nq->nxt = sq;	/* add to sq stack */
71600d97012SDavid du Colombier 	sq = nq;
71700d97012SDavid du Colombier 
71800d97012SDavid du Colombier 	return nq;
71900d97012SDavid du Colombier }
72000d97012SDavid du Colombier 
72100d97012SDavid du Colombier static SQueue *
retrieve_state(int * s)72200d97012SDavid du Colombier retrieve_state(int *s)
72300d97012SDavid du Colombier {	SQueue *nq, *last = NULL;
72400d97012SDavid du Colombier 
72500d97012SDavid du Colombier 	for (nq = sd; nq; last = nq, nq = nq->nxt)
72600d97012SDavid du Colombier 	{	if (same_state(nq->state.combo, s))
72700d97012SDavid du Colombier 		{	if (last)
72800d97012SDavid du Colombier 			{	last->nxt = nq->nxt;
72900d97012SDavid du Colombier 			} else
730*de2caf28SDavid du Colombier 			{	sd = nq->nxt;	/* 6.4.0: was sd = nq */
73100d97012SDavid du Colombier 			}
73200d97012SDavid du Colombier 			return nq;	/* found */
73300d97012SDavid du Colombier 	}	}
73400d97012SDavid du Colombier 
73500d97012SDavid du Colombier 	fatal("cannot happen: retrieve_state", 0);
73600d97012SDavid du Colombier 	return (SQueue *) 0;
73700d97012SDavid du Colombier }
73800d97012SDavid du Colombier 
73900d97012SDavid du Colombier static void
all_successors(int n,OneState * cur)74000d97012SDavid du Colombier all_successors(int n, OneState *cur)
74100d97012SDavid du Colombier {	int i, j = 0;
74200d97012SDavid du Colombier 
74300d97012SDavid du Colombier 	if (n >= nclaims)
74400d97012SDavid du Colombier 	{	create_transition(cur, find_state(Nst));
74500d97012SDavid du Colombier 	} else
74600d97012SDavid du Colombier 	{	i = cur->combo[n];
74700d97012SDavid du Colombier 		for (;;)
74800d97012SDavid du Colombier 		{	j = nxt_trans(n, i, j);
74900d97012SDavid du Colombier 			if (j < 0) break;
75000d97012SDavid du Colombier 			Nst[n] = j;
75100d97012SDavid du Colombier 			all_successors(n+1, cur);
75200d97012SDavid du Colombier 			j++;
75300d97012SDavid du Colombier 	}	}
75400d97012SDavid du Colombier }
75500d97012SDavid du Colombier 
75600d97012SDavid du Colombier static void
gen_product(void)75700d97012SDavid du Colombier gen_product(void)
75800d97012SDavid du Colombier {	OneState *cur_st;
75900d97012SDavid du Colombier 	SQueue *q;
76000d97012SDavid du Colombier 
76100d97012SDavid du Colombier 	find_state(Ist);	/* create initial state */
76200d97012SDavid du Colombier 
76300d97012SDavid du Colombier 	while (sq)
76400d97012SDavid du Colombier 	{	if (in_stack(sq, sd))
76500d97012SDavid du Colombier 		{	sq = sq->nxt;
76600d97012SDavid du Colombier 			continue;
76700d97012SDavid du Colombier 		}
76800d97012SDavid du Colombier 		cur_st = &(sq->state);
76900d97012SDavid du Colombier 
77000d97012SDavid du Colombier 		q = sq;
77100d97012SDavid du Colombier 		sq = sq->nxt;	/* delete from sq stack */
77200d97012SDavid du Colombier 		q->nxt = sd;	/* and move to done stack */
77300d97012SDavid du Colombier 		sd = q;
77400d97012SDavid du Colombier 
77500d97012SDavid du Colombier 		all_successors(0, cur_st);
77600d97012SDavid du Colombier 	}
77700d97012SDavid du Colombier 	/* all states are in the sd queue now */
77800d97012SDavid du Colombier 	prune_dead();
77900d97012SDavid du Colombier 	explore_product();	/* check if added accept-self-loops are reachable */
78000d97012SDavid du Colombier 	prune_accept();
78100d97012SDavid du Colombier 
78200d97012SDavid du Colombier 	if (verbose)
78300d97012SDavid du Colombier 	{	print_raw();
78400d97012SDavid du Colombier 	}
78500d97012SDavid du Colombier 
78600d97012SDavid du Colombier 	/* PM: merge states with identical successor lists */
78700d97012SDavid du Colombier 
78800d97012SDavid du Colombier 	/* all outgoing transitions from accept-states
78900d97012SDavid du Colombier 	   from claim n in copy n connect to states in copy (n+1)%nclaims
79000d97012SDavid du Colombier 	   only accept states from claim 0 in copy 0 are true accept states
79100d97012SDavid du Colombier 	   in the product
79200d97012SDavid du Colombier 
79300d97012SDavid du Colombier 	   PM: what about claims that have no accept states (e.g., restrictions)
79400d97012SDavid du Colombier 	*/
79500d97012SDavid du Colombier 
79600d97012SDavid du Colombier 	for (unfolding = 0; unfolding < nclaims; unfolding++)
79700d97012SDavid du Colombier 	{	print_product();
79800d97012SDavid du Colombier 	}
79900d97012SDavid du Colombier }
80000d97012SDavid du Colombier 
80100d97012SDavid du Colombier static void
t_record(int n,Element * e,Element * g)80200d97012SDavid du Colombier t_record(int n, Element *e, Element *g)
80300d97012SDavid du Colombier {	int from = e->seqno, upto = g?g->seqno:0;
80400d97012SDavid du Colombier 
80500d97012SDavid du Colombier 	assert(from >= 0 && from < nst);
80600d97012SDavid du Colombier 	assert(upto >= 0 && upto < nst);
80700d97012SDavid du Colombier 
80800d97012SDavid du Colombier 	matrix[n][from][upto] = e;
80900d97012SDavid du Colombier 	reached[n][upto] |= 1;
81000d97012SDavid du Colombier }
81100d97012SDavid du Colombier 
81200d97012SDavid du Colombier static void
get_sub(int n,Element * e)81300d97012SDavid du Colombier get_sub(int n, Element *e)
81400d97012SDavid du Colombier {
81500d97012SDavid du Colombier 	if (e->n->ntyp == D_STEP
81600d97012SDavid du Colombier 	||  e->n->ntyp == ATOMIC)
81700d97012SDavid du Colombier 	{	fatal("atomic or d_step in never claim product", 0);
81800d97012SDavid du Colombier 	}
81900d97012SDavid du Colombier 	/* NON_ATOMIC */
82000d97012SDavid du Colombier 	e->n->sl->this->last->nxt = e->nxt;
82100d97012SDavid du Colombier 	get_seq(n, e->n->sl->this);
82200d97012SDavid du Colombier 
82300d97012SDavid du Colombier 	t_record(n, e, e->n->sl->this->frst);
82400d97012SDavid du Colombier 
82500d97012SDavid du Colombier }
82600d97012SDavid du Colombier 
82700d97012SDavid du Colombier static void
set_el(int n,Element * e)82800d97012SDavid du Colombier set_el(int n, Element *e)
82900d97012SDavid du Colombier {	Element *g;
83000d97012SDavid du Colombier 
83100d97012SDavid du Colombier 	if (e->n->ntyp == '@')	/* change to self-loop */
83200d97012SDavid du Colombier 	{	e->n->ntyp = CONST;
83300d97012SDavid du Colombier 		e->n->val = 1;	/* true */
83400d97012SDavid du Colombier 		e->nxt = e;
83500d97012SDavid du Colombier 		g = e;
83600d97012SDavid du Colombier 		mk_accepting(n, e);
83700d97012SDavid du Colombier 	} else
83800d97012SDavid du Colombier 
83900d97012SDavid du Colombier 	if (e->n->ntyp == GOTO)
84000d97012SDavid du Colombier 	{	g = get_lab(e->n, 1);
84100d97012SDavid du Colombier 		g = huntele(g, e->status, -1);
84200d97012SDavid du Colombier 	} else if (e->nxt)
84300d97012SDavid du Colombier 	{	g = huntele(e->nxt, e->status, -1);
84400d97012SDavid du Colombier 	} else
84500d97012SDavid du Colombier 	{	g = NULL;
84600d97012SDavid du Colombier 	}
84700d97012SDavid du Colombier 
84800d97012SDavid du Colombier 	t_record(n, e, g);
84900d97012SDavid du Colombier }
85000d97012SDavid du Colombier 
85100d97012SDavid du Colombier static void
get_seq(int n,Sequence * s)85200d97012SDavid du Colombier get_seq(int n, Sequence *s)
85300d97012SDavid du Colombier {	SeqList *h;
85400d97012SDavid du Colombier 	Element *e;
85500d97012SDavid du Colombier 
85600d97012SDavid du Colombier 	e = huntele(s->frst, s->frst->status, -1);
85700d97012SDavid du Colombier 	for ( ; e; e = e->nxt)
85800d97012SDavid du Colombier 	{	if (e->status & DONE)
85900d97012SDavid du Colombier 		{	goto checklast;
86000d97012SDavid du Colombier 		}
86100d97012SDavid du Colombier 		e->status |= DONE;
86200d97012SDavid du Colombier 
86300d97012SDavid du Colombier 		if (e->n->ntyp == UNLESS)
86400d97012SDavid du Colombier 		{	fatal("unless stmnt in never claim product", 0);
86500d97012SDavid du Colombier 		}
86600d97012SDavid du Colombier 
86700d97012SDavid du Colombier 		if (e->sub)	/* IF or DO */
86800d97012SDavid du Colombier 		{	Lextok *x = NULL;
86900d97012SDavid du Colombier 			Lextok *y = NULL;
87000d97012SDavid du Colombier 			Lextok *haselse = NULL;
87100d97012SDavid du Colombier 
87200d97012SDavid du Colombier 			for (h = e->sub; h; h = h->nxt)
87300d97012SDavid du Colombier 			{	Lextok *t = h->this->frst->n;
87400d97012SDavid du Colombier 				if (t->ntyp == ELSE)
87500d97012SDavid du Colombier 				{	if (verbose&64) printf("else at line %d\n", t->ln);
87600d97012SDavid du Colombier 					haselse = t;
87700d97012SDavid du Colombier 					continue;
87800d97012SDavid du Colombier 				}
87900d97012SDavid du Colombier 				if (t->ntyp != 'c')
88000d97012SDavid du Colombier 				{	fatal("product, 'else' combined with non-condition", 0);
88100d97012SDavid du Colombier 				}
88200d97012SDavid du Colombier 
88300d97012SDavid du Colombier 				if (t->lft->ntyp == CONST	/* true */
88400d97012SDavid du Colombier 				&&  t->lft->val == 1
88500d97012SDavid du Colombier 				&&  y == NULL)
88600d97012SDavid du Colombier 				{	y = nn(ZN, CONST, ZN, ZN);
88700d97012SDavid du Colombier 					y->val = 0;
88800d97012SDavid du Colombier 				} else
88900d97012SDavid du Colombier 				{	if (!x)
89000d97012SDavid du Colombier 						x = t;
89100d97012SDavid du Colombier 					else
89200d97012SDavid du Colombier 						x = nn(ZN, OR, x, t);
89300d97012SDavid du Colombier 					if (verbose&64)
89400d97012SDavid du Colombier 					{	wrap_text(" [", x, "]\n");
89500d97012SDavid du Colombier 			}	}	}
89600d97012SDavid du Colombier 			if (haselse)
89700d97012SDavid du Colombier 			{	if (!y)
89800d97012SDavid du Colombier 				{	y = nn(ZN, '!', x, ZN);
89900d97012SDavid du Colombier 				}
90000d97012SDavid du Colombier 				if (verbose&64)
90100d97012SDavid du Colombier 				{	wrap_text(" [else: ", y, "]\n");
90200d97012SDavid du Colombier 				}
90300d97012SDavid du Colombier 				haselse->ntyp = 'c';	/* replace else */
90400d97012SDavid du Colombier 				haselse->lft = y;
90500d97012SDavid du Colombier 			}
90600d97012SDavid du Colombier 
90700d97012SDavid du Colombier 			for (h = e->sub; h; h = h->nxt)
90800d97012SDavid du Colombier 			{	t_record(n, e, h->this->frst);
90900d97012SDavid du Colombier 				get_seq(n, h->this);
91000d97012SDavid du Colombier 			}
91100d97012SDavid du Colombier 		} else
91200d97012SDavid du Colombier 		{	if (e->n->ntyp == ATOMIC
91300d97012SDavid du Colombier 			||  e->n->ntyp == D_STEP
91400d97012SDavid du Colombier 			||  e->n->ntyp == NON_ATOMIC)
91500d97012SDavid du Colombier 			{	get_sub(n, e);
91600d97012SDavid du Colombier 			} else
91700d97012SDavid du Colombier 			{	set_el(n, e);
91800d97012SDavid du Colombier 			}
91900d97012SDavid du Colombier 		}
92000d97012SDavid du Colombier checklast:	if (e == s->last)
92100d97012SDavid du Colombier 			break;
92200d97012SDavid du Colombier 	}
92300d97012SDavid du Colombier }
924