xref: /plan9/sys/src/cmd/spin/tl_buchi.c (revision 00d970127b9d44d2b22f4f656717a212dec1f1d2)
17dd7cddfSDavid du Colombier /***** tl_spin: tl_buchi.c *****/
27dd7cddfSDavid du Colombier 
3312a1df1SDavid du Colombier /* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories.     */
47dd7cddfSDavid du Colombier /* All Rights Reserved.  This software is for educational purposes only.  */
5312a1df1SDavid du Colombier /* No guarantee whatsoever is expressed or implied by the distribution of */
6312a1df1SDavid du Colombier /* this code.  Permission is given to distribute this code provided that  */
7312a1df1SDavid du Colombier /* this introductory message is not removed and no monies are exchanged.  */
8312a1df1SDavid du Colombier /* Software written by Gerard J. Holzmann.  For tool documentation see:   */
9312a1df1SDavid du Colombier /*             http://spinroot.com/                                       */
10312a1df1SDavid du Colombier /* Send all bug-reports and/or questions to: bugs@spinroot.com            */
11312a1df1SDavid du Colombier 
127dd7cddfSDavid du Colombier /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
137dd7cddfSDavid du Colombier /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.   */
147dd7cddfSDavid du Colombier 
157dd7cddfSDavid du Colombier #include "tl.h"
167dd7cddfSDavid du Colombier 
177dd7cddfSDavid du Colombier extern int tl_verbose, tl_clutter, Total, Max_Red;
18*00d97012SDavid du Colombier extern char *claim_name;
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier FILE	*tl_out;	/* if standalone: = stdout; */
217dd7cddfSDavid du Colombier 
227dd7cddfSDavid du Colombier typedef struct Transition {
237dd7cddfSDavid du Colombier 	Symbol *name;
247dd7cddfSDavid du Colombier 	Node *cond;
257dd7cddfSDavid du Colombier 	int redundant, merged, marked;
267dd7cddfSDavid du Colombier 	struct Transition *nxt;
277dd7cddfSDavid du Colombier } Transition;
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier typedef struct State {
307dd7cddfSDavid du Colombier 	Symbol	*name;
317dd7cddfSDavid du Colombier 	Transition *trans;
327dd7cddfSDavid du Colombier 	Graph	*colors;
337dd7cddfSDavid du Colombier 	unsigned char redundant;
347dd7cddfSDavid du Colombier 	unsigned char accepting;
357dd7cddfSDavid du Colombier 	unsigned char reachable;
367dd7cddfSDavid du Colombier 	struct State *nxt;
377dd7cddfSDavid du Colombier } State;
387dd7cddfSDavid du Colombier 
397dd7cddfSDavid du Colombier static State *never = (State *) 0;
407dd7cddfSDavid du Colombier static int hitsall;
417dd7cddfSDavid du Colombier 
42*00d97012SDavid du Colombier void
ini_buchi(void)43*00d97012SDavid du Colombier ini_buchi(void)
44*00d97012SDavid du Colombier {
45*00d97012SDavid du Colombier 	never = (State *) 0;
46*00d97012SDavid du Colombier 	hitsall = 0;
47*00d97012SDavid du Colombier }
48*00d97012SDavid du Colombier 
497dd7cddfSDavid du Colombier static int
sametrans(Transition * s,Transition * t)507dd7cddfSDavid du Colombier sametrans(Transition *s, Transition *t)
517dd7cddfSDavid du Colombier {
527dd7cddfSDavid du Colombier 	if (strcmp(s->name->name, t->name->name) != 0)
537dd7cddfSDavid du Colombier 		return 0;
547dd7cddfSDavid du Colombier 	return isequal(s->cond, t->cond);
557dd7cddfSDavid du Colombier }
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier static Node *
Prune(Node * p)587dd7cddfSDavid du Colombier Prune(Node *p)
597dd7cddfSDavid du Colombier {
607dd7cddfSDavid du Colombier 	if (p)
617dd7cddfSDavid du Colombier 	switch (p->ntyp) {
627dd7cddfSDavid du Colombier 	case PREDICATE:
637dd7cddfSDavid du Colombier 	case NOT:
647dd7cddfSDavid du Colombier 	case FALSE:
657dd7cddfSDavid du Colombier 	case TRUE:
667dd7cddfSDavid du Colombier #ifdef NXT
677dd7cddfSDavid du Colombier 	case NEXT:
687dd7cddfSDavid du Colombier #endif
697dd7cddfSDavid du Colombier 		return p;
707dd7cddfSDavid du Colombier 	case OR:
717dd7cddfSDavid du Colombier 		p->lft = Prune(p->lft);
727dd7cddfSDavid du Colombier 		if (!p->lft)
737dd7cddfSDavid du Colombier 		{	releasenode(1, p->rgt);
747dd7cddfSDavid du Colombier 			return ZN;
757dd7cddfSDavid du Colombier 		}
767dd7cddfSDavid du Colombier 		p->rgt = Prune(p->rgt);
777dd7cddfSDavid du Colombier 		if (!p->rgt)
787dd7cddfSDavid du Colombier 		{	releasenode(1, p->lft);
797dd7cddfSDavid du Colombier 			return ZN;
807dd7cddfSDavid du Colombier 		}
817dd7cddfSDavid du Colombier 		return p;
827dd7cddfSDavid du Colombier 	case AND:
837dd7cddfSDavid du Colombier 		p->lft = Prune(p->lft);
847dd7cddfSDavid du Colombier 		if (!p->lft)
857dd7cddfSDavid du Colombier 			return Prune(p->rgt);
867dd7cddfSDavid du Colombier 		p->rgt = Prune(p->rgt);
877dd7cddfSDavid du Colombier 		if (!p->rgt)
887dd7cddfSDavid du Colombier 			return p->lft;
897dd7cddfSDavid du Colombier 		return p;
907dd7cddfSDavid du Colombier 	}
917dd7cddfSDavid du Colombier 	releasenode(1, p);
927dd7cddfSDavid du Colombier 	return ZN;
937dd7cddfSDavid du Colombier }
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier static State *
findstate(char * nm)967dd7cddfSDavid du Colombier findstate(char *nm)
977dd7cddfSDavid du Colombier {	State *b;
987dd7cddfSDavid du Colombier 	for (b = never; b; b = b->nxt)
997dd7cddfSDavid du Colombier 		if (!strcmp(b->name->name, nm))
1007dd7cddfSDavid du Colombier 			return b;
1017dd7cddfSDavid du Colombier 	if (strcmp(nm, "accept_all"))
1027dd7cddfSDavid du Colombier 	{	if (strncmp(nm, "accept", 6))
1037dd7cddfSDavid du Colombier 		{	int i; char altnm[64];
1047dd7cddfSDavid du Colombier 			for (i = 0; i < 64; i++)
1057dd7cddfSDavid du Colombier 				if (nm[i] == '_')
1067dd7cddfSDavid du Colombier 					break;
1077dd7cddfSDavid du Colombier 			if (i >= 64)
1087dd7cddfSDavid du Colombier 				Fatal("name too long %s", nm);
1097dd7cddfSDavid du Colombier 			sprintf(altnm, "accept%s", &nm[i]);
1107dd7cddfSDavid du Colombier 			return findstate(altnm);
1117dd7cddfSDavid du Colombier 		}
1127dd7cddfSDavid du Colombier 	/*	Fatal("buchi: no state %s", nm); */
1137dd7cddfSDavid du Colombier 	}
1147dd7cddfSDavid du Colombier 	return (State *) 0;
1157dd7cddfSDavid du Colombier }
1167dd7cddfSDavid du Colombier 
1177dd7cddfSDavid du Colombier static void
Dfs(State * b)1187dd7cddfSDavid du Colombier Dfs(State *b)
1197dd7cddfSDavid du Colombier {	Transition *t;
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier 	if (!b || b->reachable) return;
1227dd7cddfSDavid du Colombier 	b->reachable = 1;
1237dd7cddfSDavid du Colombier 
1247dd7cddfSDavid du Colombier 	if (b->redundant)
125312a1df1SDavid du Colombier 		printf("/* redundant state %s */\n",
1267dd7cddfSDavid du Colombier 			b->name->name);
1277dd7cddfSDavid du Colombier 	for (t = b->trans; t; t = t->nxt)
1287dd7cddfSDavid du Colombier 	{	if (!t->redundant)
1297dd7cddfSDavid du Colombier 		{	Dfs(findstate(t->name->name));
1307dd7cddfSDavid du Colombier 			if (!hitsall
1317dd7cddfSDavid du Colombier 			&&  strcmp(t->name->name, "accept_all") == 0)
1327dd7cddfSDavid du Colombier 				hitsall = 1;
1337dd7cddfSDavid du Colombier 		}
1347dd7cddfSDavid du Colombier 	}
1357dd7cddfSDavid du Colombier }
1367dd7cddfSDavid du Colombier 
1377dd7cddfSDavid du Colombier void
retarget(char * from,char * to)1387dd7cddfSDavid du Colombier retarget(char *from, char *to)
1397dd7cddfSDavid du Colombier {	State *b;
1407dd7cddfSDavid du Colombier 	Transition *t;
1417dd7cddfSDavid du Colombier 	Symbol *To = tl_lookup(to);
1427dd7cddfSDavid du Colombier 
1437dd7cddfSDavid du Colombier 	if (tl_verbose) printf("replace %s with %s\n", from, to);
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier 	for (b = never; b; b = b->nxt)
1467dd7cddfSDavid du Colombier 	{	if (!strcmp(b->name->name, from))
147312a1df1SDavid du Colombier 			b->redundant = 1;
148312a1df1SDavid du Colombier 		else
1497dd7cddfSDavid du Colombier 		for (t = b->trans; t; t = t->nxt)
1507dd7cddfSDavid du Colombier 		{	if (!strcmp(t->name->name, from))
1517dd7cddfSDavid du Colombier 				t->name = To;
1527dd7cddfSDavid du Colombier 	}	}
1537dd7cddfSDavid du Colombier }
1547dd7cddfSDavid du Colombier 
1557dd7cddfSDavid du Colombier #ifdef NXT
1567dd7cddfSDavid du Colombier static Node *
nonxt(Node * n)1577dd7cddfSDavid du Colombier nonxt(Node *n)
1587dd7cddfSDavid du Colombier {
1597dd7cddfSDavid du Colombier 	switch (n->ntyp) {
1607dd7cddfSDavid du Colombier 	case U_OPER:
1617dd7cddfSDavid du Colombier 	case V_OPER:
1627dd7cddfSDavid du Colombier 	case NEXT:
1637dd7cddfSDavid du Colombier 		return ZN;
1647dd7cddfSDavid du Colombier 	case OR:
1657dd7cddfSDavid du Colombier 		n->lft = nonxt(n->lft);
1667dd7cddfSDavid du Colombier 		n->rgt = nonxt(n->rgt);
1677dd7cddfSDavid du Colombier 		if (!n->lft || !n->rgt)
1687dd7cddfSDavid du Colombier 			return True;
1697dd7cddfSDavid du Colombier 		return n;
1707dd7cddfSDavid du Colombier 	case AND:
1717dd7cddfSDavid du Colombier 		n->lft = nonxt(n->lft);
1727dd7cddfSDavid du Colombier 		n->rgt = nonxt(n->rgt);
1737dd7cddfSDavid du Colombier 		if (!n->lft)
1747dd7cddfSDavid du Colombier 		{	if (!n->rgt)
1757dd7cddfSDavid du Colombier 				n = ZN;
1767dd7cddfSDavid du Colombier 			else
1777dd7cddfSDavid du Colombier 				n = n->rgt;
1787dd7cddfSDavid du Colombier 		} else if (!n->rgt)
1797dd7cddfSDavid du Colombier 			n = n->lft;
1807dd7cddfSDavid du Colombier 		return n;
1817dd7cddfSDavid du Colombier 	}
1827dd7cddfSDavid du Colombier 	return n;
1837dd7cddfSDavid du Colombier }
1847dd7cddfSDavid du Colombier #endif
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier static Node *
combination(Node * s,Node * t)1877dd7cddfSDavid du Colombier combination(Node *s, Node *t)
1887dd7cddfSDavid du Colombier {	Node *nc;
1897dd7cddfSDavid du Colombier #ifdef NXT
1907dd7cddfSDavid du Colombier 	Node *a = nonxt(s);
1917dd7cddfSDavid du Colombier 	Node *b = nonxt(t);
192312a1df1SDavid du Colombier 
1937dd7cddfSDavid du Colombier 	if (tl_verbose)
1947dd7cddfSDavid du Colombier 	{	printf("\tnonxtA: "); dump(a);
1957dd7cddfSDavid du Colombier 		printf("\n\tnonxtB: "); dump(b);
1967dd7cddfSDavid du Colombier 		printf("\n");
1977dd7cddfSDavid du Colombier 	}
1987dd7cddfSDavid du Colombier 	/* if there's only a X(f), its equivalent to true */
1997dd7cddfSDavid du Colombier 	if (!a || !b)
2007dd7cddfSDavid du Colombier 		nc = True;
2017dd7cddfSDavid du Colombier 	else
2027dd7cddfSDavid du Colombier 		nc = tl_nn(OR, a, b);
2037dd7cddfSDavid du Colombier #else
2047dd7cddfSDavid du Colombier 	nc = tl_nn(OR, s, t);
2057dd7cddfSDavid du Colombier #endif
2067dd7cddfSDavid du Colombier 	if (tl_verbose)
2077dd7cddfSDavid du Colombier 	{	printf("\tcombo: "); dump(nc);
2087dd7cddfSDavid du Colombier 		printf("\n");
2097dd7cddfSDavid du Colombier 	}
2107dd7cddfSDavid du Colombier 	return nc;
2117dd7cddfSDavid du Colombier }
2127dd7cddfSDavid du Colombier 
2137dd7cddfSDavid du Colombier Node *
unclutter(Node * n,char * snm)2147dd7cddfSDavid du Colombier unclutter(Node *n, char *snm)
2157dd7cddfSDavid du Colombier {	Node *t, *s, *v, *u;
2167dd7cddfSDavid du Colombier 	Symbol *w;
2177dd7cddfSDavid du Colombier 
2187dd7cddfSDavid du Colombier 	/* check only simple cases like !q && q */
2197dd7cddfSDavid du Colombier 	for (t = n; t; t = t->rgt)
2207dd7cddfSDavid du Colombier 	{	if (t->rgt)
2217dd7cddfSDavid du Colombier 		{	if (t->ntyp != AND || !t->lft)
2227dd7cddfSDavid du Colombier 				return n;
2237dd7cddfSDavid du Colombier 			if (t->lft->ntyp != PREDICATE
2247dd7cddfSDavid du Colombier #ifdef NXT
2257dd7cddfSDavid du Colombier 			&&  t->lft->ntyp != NEXT
2267dd7cddfSDavid du Colombier #endif
2277dd7cddfSDavid du Colombier 			&&  t->lft->ntyp != NOT)
2287dd7cddfSDavid du Colombier 				return n;
2297dd7cddfSDavid du Colombier 		} else
2307dd7cddfSDavid du Colombier 		{	if (t->ntyp != PREDICATE
2317dd7cddfSDavid du Colombier #ifdef NXT
2327dd7cddfSDavid du Colombier 			&&  t->ntyp != NEXT
2337dd7cddfSDavid du Colombier #endif
2347dd7cddfSDavid du Colombier 			&&  t->ntyp != NOT)
2357dd7cddfSDavid du Colombier 				return n;
2367dd7cddfSDavid du Colombier 		}
2377dd7cddfSDavid du Colombier 	}
2387dd7cddfSDavid du Colombier 
2397dd7cddfSDavid du Colombier 	for (t = n; t; t = t->rgt)
2407dd7cddfSDavid du Colombier 	{	if (t->rgt)
2417dd7cddfSDavid du Colombier 			v = t->lft;
2427dd7cddfSDavid du Colombier 		else
2437dd7cddfSDavid du Colombier 			v = t;
2447dd7cddfSDavid du Colombier 		if (v->ntyp == NOT
2457dd7cddfSDavid du Colombier 		&&  v->lft->ntyp == PREDICATE)
2467dd7cddfSDavid du Colombier 		{	w = v->lft->sym;
2477dd7cddfSDavid du Colombier 			for (s = n; s; s = s->rgt)
2487dd7cddfSDavid du Colombier 			{	if (s == t) continue;
2497dd7cddfSDavid du Colombier 				if (s->rgt)
2507dd7cddfSDavid du Colombier 					u = s->lft;
2517dd7cddfSDavid du Colombier 				else
2527dd7cddfSDavid du Colombier 					u = s;
2537dd7cddfSDavid du Colombier 				if (u->ntyp == PREDICATE
2547dd7cddfSDavid du Colombier 				&&  strcmp(u->sym->name, w->name) == 0)
2557dd7cddfSDavid du Colombier 				{	if (tl_verbose)
2567dd7cddfSDavid du Colombier 					{	printf("BINGO %s:\t", snm);
2577dd7cddfSDavid du Colombier 						dump(n);
2587dd7cddfSDavid du Colombier 						printf("\n");
2597dd7cddfSDavid du Colombier 					}
2607dd7cddfSDavid du Colombier 					return False;
2617dd7cddfSDavid du Colombier 				}
2627dd7cddfSDavid du Colombier 			}
2637dd7cddfSDavid du Colombier 	}	}
2647dd7cddfSDavid du Colombier 	return n;
2657dd7cddfSDavid du Colombier }
2667dd7cddfSDavid du Colombier 
2677dd7cddfSDavid du Colombier static void
clutter(void)2687dd7cddfSDavid du Colombier clutter(void)
2697dd7cddfSDavid du Colombier {	State *p;
2707dd7cddfSDavid du Colombier 	Transition *s;
2717dd7cddfSDavid du Colombier 
2727dd7cddfSDavid du Colombier 	for (p = never; p; p = p->nxt)
2737dd7cddfSDavid du Colombier 	for (s = p->trans; s; s = s->nxt)
2747dd7cddfSDavid du Colombier 	{	s->cond = unclutter(s->cond, p->name->name);
2757dd7cddfSDavid du Colombier 		if (s->cond
2767dd7cddfSDavid du Colombier 		&&  s->cond->ntyp == FALSE)
2777dd7cddfSDavid du Colombier 		{	if (s != p->trans
2787dd7cddfSDavid du Colombier 			||  s->nxt)
2797dd7cddfSDavid du Colombier 				s->redundant = 1;
2807dd7cddfSDavid du Colombier 		}
2817dd7cddfSDavid du Colombier 	}
2827dd7cddfSDavid du Colombier }
2837dd7cddfSDavid du Colombier 
2847dd7cddfSDavid du Colombier static void
showtrans(State * a)2857dd7cddfSDavid du Colombier showtrans(State *a)
2867dd7cddfSDavid du Colombier {	Transition *s;
2877dd7cddfSDavid du Colombier 
2887dd7cddfSDavid du Colombier 	for (s = a->trans; s; s = s->nxt)
2897dd7cddfSDavid du Colombier 	{	printf("%s ", s->name?s->name->name:"-");
2907dd7cddfSDavid du Colombier 		dump(s->cond);
2917dd7cddfSDavid du Colombier 		printf(" %d %d %d\n", s->redundant, s->merged, s->marked);
2927dd7cddfSDavid du Colombier 	}
2937dd7cddfSDavid du Colombier }
2947dd7cddfSDavid du Colombier 
2957dd7cddfSDavid du Colombier static int
mergetrans(void)296312a1df1SDavid du Colombier mergetrans(void)
2977dd7cddfSDavid du Colombier {	State *b;
2987dd7cddfSDavid du Colombier 	Transition *s, *t;
2997dd7cddfSDavid du Colombier 	Node *nc; int cnt = 0;
3007dd7cddfSDavid du Colombier 
3017dd7cddfSDavid du Colombier 	for (b = never; b; b = b->nxt)
3027dd7cddfSDavid du Colombier 	{	if (!b->reachable) continue;
3037dd7cddfSDavid du Colombier 
3047dd7cddfSDavid du Colombier 		for (s = b->trans; s; s = s->nxt)
3057dd7cddfSDavid du Colombier 		{	if (s->redundant) continue;
3067dd7cddfSDavid du Colombier 
3077dd7cddfSDavid du Colombier 			for (t = s->nxt; t; t = t->nxt)
3087dd7cddfSDavid du Colombier 			if (!t->redundant
3097dd7cddfSDavid du Colombier 			&&  !strcmp(s->name->name, t->name->name))
3107dd7cddfSDavid du Colombier 			{	if (tl_verbose)
3117dd7cddfSDavid du Colombier 				{	printf("===\nstate %s, trans to %s redundant\n",
3127dd7cddfSDavid du Colombier 					b->name->name, s->name->name);
3137dd7cddfSDavid du Colombier 					showtrans(b);
3147dd7cddfSDavid du Colombier 					printf(" conditions ");
3157dd7cddfSDavid du Colombier 					dump(s->cond); printf(" <-> ");
3167dd7cddfSDavid du Colombier 					dump(t->cond); printf("\n");
3177dd7cddfSDavid du Colombier 				}
3187dd7cddfSDavid du Colombier 
3197dd7cddfSDavid du Colombier 				if (!s->cond) /* same as T */
3207dd7cddfSDavid du Colombier 				{	releasenode(1, t->cond); /* T or t */
3217dd7cddfSDavid du Colombier 					nc = True;
3227dd7cddfSDavid du Colombier 				} else if (!t->cond)
3237dd7cddfSDavid du Colombier 				{	releasenode(1, s->cond);
3247dd7cddfSDavid du Colombier 					nc = True;
3257dd7cddfSDavid du Colombier 				} else
3267dd7cddfSDavid du Colombier 				{	nc = combination(s->cond, t->cond);
3277dd7cddfSDavid du Colombier 				}
3287dd7cddfSDavid du Colombier 				t->cond = rewrite(nc);
3297dd7cddfSDavid du Colombier 				t->merged = 1;
3307dd7cddfSDavid du Colombier 				s->redundant = 1;
3317dd7cddfSDavid du Colombier 				cnt++;
3327dd7cddfSDavid du Colombier 				break;
3337dd7cddfSDavid du Colombier 	}	}	}
3347dd7cddfSDavid du Colombier 	return cnt;
3357dd7cddfSDavid du Colombier }
3367dd7cddfSDavid du Colombier 
3377dd7cddfSDavid du Colombier static int
all_trans_match(State * a,State * b)3387dd7cddfSDavid du Colombier all_trans_match(State *a, State *b)
3397dd7cddfSDavid du Colombier {	Transition *s, *t;
3407dd7cddfSDavid du Colombier 	int found, result = 0;
3417dd7cddfSDavid du Colombier 
3427dd7cddfSDavid du Colombier 	if (a->accepting != b->accepting)
3437dd7cddfSDavid du Colombier 		goto done;
3447dd7cddfSDavid du Colombier 
3457dd7cddfSDavid du Colombier 	for (s = a->trans; s; s = s->nxt)
3467dd7cddfSDavid du Colombier 	{	if (s->redundant) continue;
3477dd7cddfSDavid du Colombier 		found = 0;
3487dd7cddfSDavid du Colombier 		for (t = b->trans; t; t = t->nxt)
3497dd7cddfSDavid du Colombier 		{	if (t->redundant) continue;
3507dd7cddfSDavid du Colombier 			if (sametrans(s, t))
3517dd7cddfSDavid du Colombier 			{	found = 1;
3527dd7cddfSDavid du Colombier 				t->marked = 1;
3537dd7cddfSDavid du Colombier 				break;
3547dd7cddfSDavid du Colombier 		}	}
3557dd7cddfSDavid du Colombier 		if (!found)
3567dd7cddfSDavid du Colombier 			goto done;
3577dd7cddfSDavid du Colombier 	}
3587dd7cddfSDavid du Colombier 	for (s = b->trans; s; s = s->nxt)
3597dd7cddfSDavid du Colombier 	{	if (s->redundant || s->marked) continue;
3607dd7cddfSDavid du Colombier 		found = 0;
3617dd7cddfSDavid du Colombier 		for (t = a->trans; t; t = t->nxt)
3627dd7cddfSDavid du Colombier 		{	if (t->redundant) continue;
3637dd7cddfSDavid du Colombier 			if (sametrans(s, t))
3647dd7cddfSDavid du Colombier 			{	found = 1;
3657dd7cddfSDavid du Colombier 				break;
3667dd7cddfSDavid du Colombier 		}	}
3677dd7cddfSDavid du Colombier 		if (!found)
3687dd7cddfSDavid du Colombier 			goto done;
3697dd7cddfSDavid du Colombier 	}
3707dd7cddfSDavid du Colombier 	result = 1;
3717dd7cddfSDavid du Colombier done:
3727dd7cddfSDavid du Colombier 	for (s = b->trans; s; s = s->nxt)
3737dd7cddfSDavid du Colombier 		s->marked = 0;
3747dd7cddfSDavid du Colombier 	return result;
3757dd7cddfSDavid du Colombier }
376312a1df1SDavid du Colombier 
377312a1df1SDavid du Colombier #ifndef NO_OPT
3787dd7cddfSDavid du Colombier #define BUCKY
379312a1df1SDavid du Colombier #endif
380312a1df1SDavid du Colombier 
3817dd7cddfSDavid du Colombier #ifdef BUCKY
3827dd7cddfSDavid du Colombier static int
all_bucky(State * a,State * b)3837dd7cddfSDavid du Colombier all_bucky(State *a, State *b)
3847dd7cddfSDavid du Colombier {	Transition *s, *t;
3857dd7cddfSDavid du Colombier 	int found, result = 0;
3867dd7cddfSDavid du Colombier 
3877dd7cddfSDavid du Colombier 	for (s = a->trans; s; s = s->nxt)
3887dd7cddfSDavid du Colombier 	{	if (s->redundant) continue;
3897dd7cddfSDavid du Colombier 		found = 0;
3907dd7cddfSDavid du Colombier 		for (t = b->trans; t; t = t->nxt)
3917dd7cddfSDavid du Colombier 		{	if (t->redundant) continue;
3927dd7cddfSDavid du Colombier 
3937dd7cddfSDavid du Colombier 			if (isequal(s->cond, t->cond))
3947dd7cddfSDavid du Colombier 			{	if (strcmp(s->name->name, b->name->name) == 0
3957dd7cddfSDavid du Colombier 				&&  strcmp(t->name->name, a->name->name) == 0)
3967dd7cddfSDavid du Colombier 				{	found = 1;	/* they point to each other */
3977dd7cddfSDavid du Colombier 					t->marked = 1;
3987dd7cddfSDavid du Colombier 					break;
3997dd7cddfSDavid du Colombier 				}
4007dd7cddfSDavid du Colombier 				if (strcmp(s->name->name, t->name->name) == 0
4017dd7cddfSDavid du Colombier 				&&  strcmp(s->name->name, "accept_all") == 0)
4027dd7cddfSDavid du Colombier 				{	found = 1;
4037dd7cddfSDavid du Colombier 					t->marked = 1;
4047dd7cddfSDavid du Colombier 					break;
4057dd7cddfSDavid du Colombier 				/* same exit from which there is no return */
4067dd7cddfSDavid du Colombier 				}
4077dd7cddfSDavid du Colombier 			}
4087dd7cddfSDavid du Colombier 		}
4097dd7cddfSDavid du Colombier 		if (!found)
4107dd7cddfSDavid du Colombier 			goto done;
4117dd7cddfSDavid du Colombier 	}
4127dd7cddfSDavid du Colombier 	for (s = b->trans; s; s = s->nxt)
4137dd7cddfSDavid du Colombier 	{	if (s->redundant || s->marked) continue;
4147dd7cddfSDavid du Colombier 		found = 0;
4157dd7cddfSDavid du Colombier 		for (t = a->trans; t; t = t->nxt)
4167dd7cddfSDavid du Colombier 		{	if (t->redundant) continue;
4177dd7cddfSDavid du Colombier 
4187dd7cddfSDavid du Colombier 			if (isequal(s->cond, t->cond))
4197dd7cddfSDavid du Colombier 			{	if (strcmp(s->name->name, a->name->name) == 0
4207dd7cddfSDavid du Colombier 				&&  strcmp(t->name->name, b->name->name) == 0)
4217dd7cddfSDavid du Colombier 				{	found = 1;
4227dd7cddfSDavid du Colombier 					t->marked = 1;
4237dd7cddfSDavid du Colombier 					break;
4247dd7cddfSDavid du Colombier 				}
4257dd7cddfSDavid du Colombier 				if (strcmp(s->name->name, t->name->name) == 0
4267dd7cddfSDavid du Colombier 				&&  strcmp(s->name->name, "accept_all") == 0)
4277dd7cddfSDavid du Colombier 				{	found = 1;
4287dd7cddfSDavid du Colombier 					t->marked = 1;
4297dd7cddfSDavid du Colombier 					break;
4307dd7cddfSDavid du Colombier 				}
4317dd7cddfSDavid du Colombier 			}
4327dd7cddfSDavid du Colombier 		}
4337dd7cddfSDavid du Colombier 		if (!found)
4347dd7cddfSDavid du Colombier 			goto done;
4357dd7cddfSDavid du Colombier 	}
4367dd7cddfSDavid du Colombier 	result = 1;
4377dd7cddfSDavid du Colombier done:
4387dd7cddfSDavid du Colombier 	for (s = b->trans; s; s = s->nxt)
4397dd7cddfSDavid du Colombier 		s->marked = 0;
4407dd7cddfSDavid du Colombier 	return result;
4417dd7cddfSDavid du Colombier }
4427dd7cddfSDavid du Colombier 
4437dd7cddfSDavid du Colombier static int
buckyballs(void)4447dd7cddfSDavid du Colombier buckyballs(void)
4457dd7cddfSDavid du Colombier {	State *a, *b, *c, *d;
4467dd7cddfSDavid du Colombier 	int m, cnt=0;
4477dd7cddfSDavid du Colombier 
4487dd7cddfSDavid du Colombier 	do {
4497dd7cddfSDavid du Colombier 		m = 0; cnt++;
4507dd7cddfSDavid du Colombier 		for (a = never; a; a = a->nxt)
4517dd7cddfSDavid du Colombier 		{	if (!a->reachable) continue;
4527dd7cddfSDavid du Colombier 
4537dd7cddfSDavid du Colombier 			if (a->redundant) continue;
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier 			for (b = a->nxt; b; b = b->nxt)
4567dd7cddfSDavid du Colombier 			{	if (!b->reachable) continue;
4577dd7cddfSDavid du Colombier 
4587dd7cddfSDavid du Colombier 				if (b->redundant) continue;
4597dd7cddfSDavid du Colombier 
4607dd7cddfSDavid du Colombier 				if (all_bucky(a, b))
4617dd7cddfSDavid du Colombier 				{	m++;
4627dd7cddfSDavid du Colombier 					if (tl_verbose)
4637dd7cddfSDavid du Colombier 					{	printf("%s bucky match %s\n",
4647dd7cddfSDavid du Colombier 						a->name->name, b->name->name);
4657dd7cddfSDavid du Colombier 					}
4667dd7cddfSDavid du Colombier 
4677dd7cddfSDavid du Colombier 					if (a->accepting && !b->accepting)
468312a1df1SDavid du Colombier 					{	if (strcmp(b->name->name, "T0_init") == 0)
469312a1df1SDavid du Colombier 						{	c = a; d = b;
470312a1df1SDavid du Colombier 							b->accepting = 1;
471312a1df1SDavid du Colombier 						} else
4727dd7cddfSDavid du Colombier 						{	c = b; d = a;
473312a1df1SDavid du Colombier 						}
4747dd7cddfSDavid du Colombier 					} else
4757dd7cddfSDavid du Colombier 					{	c = a; d = b;
4767dd7cddfSDavid du Colombier 					}
4777dd7cddfSDavid du Colombier 
4787dd7cddfSDavid du Colombier 					retarget(c->name->name, d->name->name);
4797dd7cddfSDavid du Colombier 					if (!strncmp(c->name->name, "accept", 6)
4807dd7cddfSDavid du Colombier 					&&  Max_Red == 0)
4817dd7cddfSDavid du Colombier 					{	char buf[64];
4827dd7cddfSDavid du Colombier 						sprintf(buf, "T0%s", &(c->name->name[6]));
4837dd7cddfSDavid du Colombier 						retarget(buf, d->name->name);
4847dd7cddfSDavid du Colombier 					}
4857dd7cddfSDavid du Colombier 					break;
4867dd7cddfSDavid du Colombier 				}
4877dd7cddfSDavid du Colombier 		}	}
4887dd7cddfSDavid du Colombier 	} while (m && cnt < 10);
4897dd7cddfSDavid du Colombier 	return cnt-1;
4907dd7cddfSDavid du Colombier }
4917dd7cddfSDavid du Colombier #endif
4927dd7cddfSDavid du Colombier 
4937dd7cddfSDavid du Colombier static int
mergestates(int v)4947dd7cddfSDavid du Colombier mergestates(int v)
4957dd7cddfSDavid du Colombier {	State *a, *b;
4967dd7cddfSDavid du Colombier 	int m, cnt=0;
497312a1df1SDavid du Colombier 
4987dd7cddfSDavid du Colombier 	if (tl_verbose)
4997dd7cddfSDavid du Colombier 		return 0;
500312a1df1SDavid du Colombier 
5017dd7cddfSDavid du Colombier 	do {
5027dd7cddfSDavid du Colombier 		m = 0; cnt++;
5037dd7cddfSDavid du Colombier 		for (a = never; a; a = a->nxt)
5047dd7cddfSDavid du Colombier 		{	if (v && !a->reachable) continue;
5057dd7cddfSDavid du Colombier 
5067dd7cddfSDavid du Colombier 			if (a->redundant) continue; /* 3.3.10 */
5077dd7cddfSDavid du Colombier 
5087dd7cddfSDavid du Colombier 			for (b = a->nxt; b; b = b->nxt)
5097dd7cddfSDavid du Colombier 			{	if (v && !b->reachable) continue;
5107dd7cddfSDavid du Colombier 
5117dd7cddfSDavid du Colombier 				if (b->redundant) continue; /* 3.3.10 */
5127dd7cddfSDavid du Colombier 
5137dd7cddfSDavid du Colombier 				if (all_trans_match(a, b))
5147dd7cddfSDavid du Colombier 				{	m++;
5157dd7cddfSDavid du Colombier 					if (tl_verbose)
5167dd7cddfSDavid du Colombier 					{	printf("%d: state %s equals state %s\n",
5177dd7cddfSDavid du Colombier 						cnt, a->name->name, b->name->name);
5187dd7cddfSDavid du Colombier 						showtrans(a);
5197dd7cddfSDavid du Colombier 						printf("==\n");
5207dd7cddfSDavid du Colombier 						showtrans(b);
5217dd7cddfSDavid du Colombier 					}
5227dd7cddfSDavid du Colombier 					retarget(a->name->name, b->name->name);
5237dd7cddfSDavid du Colombier 					if (!strncmp(a->name->name, "accept", 6)
5247dd7cddfSDavid du Colombier 					&&  Max_Red == 0)
5257dd7cddfSDavid du Colombier 					{	char buf[64];
5267dd7cddfSDavid du Colombier 						sprintf(buf, "T0%s", &(a->name->name[6]));
5277dd7cddfSDavid du Colombier 						retarget(buf, b->name->name);
5287dd7cddfSDavid du Colombier 					}
5297dd7cddfSDavid du Colombier 					break;
5307dd7cddfSDavid du Colombier 				}
5317dd7cddfSDavid du Colombier #if 0
5327dd7cddfSDavid du Colombier 				else if (tl_verbose)
5337dd7cddfSDavid du Colombier 				{	printf("\n%d: state %s differs from state %s [%d,%d]\n",
534312a1df1SDavid du Colombier 						cnt, a->name->name, b->name->name,
535312a1df1SDavid du Colombier 						a->accepting, b->accepting);
5367dd7cddfSDavid du Colombier 					showtrans(a);
5377dd7cddfSDavid du Colombier 					printf("==\n");
5387dd7cddfSDavid du Colombier 					showtrans(b);
5397dd7cddfSDavid du Colombier 					printf("\n");
5407dd7cddfSDavid du Colombier 				}
5417dd7cddfSDavid du Colombier #endif
5427dd7cddfSDavid du Colombier 		}	}
5437dd7cddfSDavid du Colombier 	} while (m && cnt < 10);
5447dd7cddfSDavid du Colombier 	return cnt-1;
5457dd7cddfSDavid du Colombier }
5467dd7cddfSDavid du Colombier 
5477dd7cddfSDavid du Colombier static int tcnt;
5487dd7cddfSDavid du Colombier 
5497dd7cddfSDavid du Colombier static void
rev_trans(Transition * t)5507dd7cddfSDavid du Colombier rev_trans(Transition *t) /* print transitions  in reverse order... */
5517dd7cddfSDavid du Colombier {
5527dd7cddfSDavid du Colombier 	if (!t) return;
5537dd7cddfSDavid du Colombier 	rev_trans(t->nxt);
5547dd7cddfSDavid du Colombier 
5557dd7cddfSDavid du Colombier 	if (t->redundant && !tl_verbose) return;
5567dd7cddfSDavid du Colombier 	fprintf(tl_out, "\t:: (");
5577dd7cddfSDavid du Colombier 	if (dump_cond(t->cond, t->cond, 1))
5587dd7cddfSDavid du Colombier 		fprintf(tl_out, "1");
5597dd7cddfSDavid du Colombier 	fprintf(tl_out, ") -> goto %s\n", t->name->name);
5607dd7cddfSDavid du Colombier 	tcnt++;
5617dd7cddfSDavid du Colombier }
5627dd7cddfSDavid du Colombier 
5637dd7cddfSDavid du Colombier static void
printstate(State * b)5647dd7cddfSDavid du Colombier printstate(State *b)
5657dd7cddfSDavid du Colombier {
5667dd7cddfSDavid du Colombier 	if (!b || (!tl_verbose && !b->reachable)) return;
5677dd7cddfSDavid du Colombier 
5687dd7cddfSDavid du Colombier 	b->reachable = 0;	/* print only once */
5697dd7cddfSDavid du Colombier 	fprintf(tl_out, "%s:\n", b->name->name);
5707dd7cddfSDavid du Colombier 
571312a1df1SDavid du Colombier 	if (tl_verbose)
572312a1df1SDavid du Colombier 	{	fprintf(tl_out, "	/* ");
573312a1df1SDavid du Colombier 		dump(b->colors->Other);
574312a1df1SDavid du Colombier 		fprintf(tl_out, " */\n");
575312a1df1SDavid du Colombier 	}
576312a1df1SDavid du Colombier 
5777dd7cddfSDavid du Colombier 	if (strncmp(b->name->name, "accept", 6) == 0
5787dd7cddfSDavid du Colombier 	&&  Max_Red == 0)
5797dd7cddfSDavid du Colombier 		fprintf(tl_out, "T0%s:\n", &(b->name->name[6]));
5807dd7cddfSDavid du Colombier 
5817dd7cddfSDavid du Colombier 	fprintf(tl_out, "\tif\n");
5827dd7cddfSDavid du Colombier 	tcnt = 0;
5837dd7cddfSDavid du Colombier 	rev_trans(b->trans);
5847dd7cddfSDavid du Colombier 	if (!tcnt) fprintf(tl_out, "\t:: false\n");
5857dd7cddfSDavid du Colombier 	fprintf(tl_out, "\tfi;\n");
5867dd7cddfSDavid du Colombier 	Total++;
5877dd7cddfSDavid du Colombier }
5887dd7cddfSDavid du Colombier 
5897dd7cddfSDavid du Colombier void
addtrans(Graph * col,char * from,Node * op,char * to)5907dd7cddfSDavid du Colombier addtrans(Graph *col, char *from, Node *op, char *to)
5917dd7cddfSDavid du Colombier {	State *b;
5927dd7cddfSDavid du Colombier 	Transition *t;
5937dd7cddfSDavid du Colombier 
5947dd7cddfSDavid du Colombier 	t = (Transition *) tl_emalloc(sizeof(Transition));
5957dd7cddfSDavid du Colombier 	t->name = tl_lookup(to);
5967dd7cddfSDavid du Colombier 	t->cond = Prune(dupnode(op));
5977dd7cddfSDavid du Colombier 
5987dd7cddfSDavid du Colombier 	if (tl_verbose)
599312a1df1SDavid du Colombier 	{	printf("\n%s <<\t", from); dump(op);
6007dd7cddfSDavid du Colombier 		printf("\n\t"); dump(t->cond);
6017dd7cddfSDavid du Colombier 		printf(">> %s\n", t->name->name);
6027dd7cddfSDavid du Colombier 	}
6037dd7cddfSDavid du Colombier 	if (t->cond) t->cond = rewrite(t->cond);
6047dd7cddfSDavid du Colombier 
6057dd7cddfSDavid du Colombier 	for (b = never; b; b = b->nxt)
6067dd7cddfSDavid du Colombier 		if (!strcmp(b->name->name, from))
6077dd7cddfSDavid du Colombier 		{	t->nxt = b->trans;
6087dd7cddfSDavid du Colombier 			b->trans = t;
6097dd7cddfSDavid du Colombier 			return;
6107dd7cddfSDavid du Colombier 		}
6117dd7cddfSDavid du Colombier 	b = (State *) tl_emalloc(sizeof(State));
6127dd7cddfSDavid du Colombier 	b->name   = tl_lookup(from);
6137dd7cddfSDavid du Colombier 	b->colors = col;
6147dd7cddfSDavid du Colombier 	b->trans  = t;
6157dd7cddfSDavid du Colombier 	if (!strncmp(from, "accept", 6))
6167dd7cddfSDavid du Colombier 		b->accepting = 1;
6177dd7cddfSDavid du Colombier 	b->nxt = never;
6187dd7cddfSDavid du Colombier 	never  = b;
6197dd7cddfSDavid du Colombier }
6207dd7cddfSDavid du Colombier 
6217dd7cddfSDavid du Colombier static void
clr_reach(void)6227dd7cddfSDavid du Colombier clr_reach(void)
6237dd7cddfSDavid du Colombier {	State *p;
6247dd7cddfSDavid du Colombier 	for (p = never; p; p = p->nxt)
6257dd7cddfSDavid du Colombier 		p->reachable = 0;
6267dd7cddfSDavid du Colombier 	hitsall = 0;
6277dd7cddfSDavid du Colombier }
6287dd7cddfSDavid du Colombier 
6297dd7cddfSDavid du Colombier void
fsm_print(void)6307dd7cddfSDavid du Colombier fsm_print(void)
6317dd7cddfSDavid du Colombier {	State *b; int cnt1, cnt2=0;
6327dd7cddfSDavid du Colombier 	extern void put_uform(void);
6337dd7cddfSDavid du Colombier 
6347dd7cddfSDavid du Colombier 	if (tl_clutter) clutter();
6357dd7cddfSDavid du Colombier 
6367dd7cddfSDavid du Colombier 	b = findstate("T0_init");
637*00d97012SDavid du Colombier 	if (b && (Max_Red == 0))
6387dd7cddfSDavid du Colombier 		b->accepting = 1;
6397dd7cddfSDavid du Colombier 
6407dd7cddfSDavid du Colombier 	mergestates(0);
6417dd7cddfSDavid du Colombier 	b = findstate("T0_init");
6427dd7cddfSDavid du Colombier 
643*00d97012SDavid du Colombier 	fprintf(tl_out, "never %s {    /* ", claim_name?claim_name:"");
6447dd7cddfSDavid du Colombier 		put_uform();
6457dd7cddfSDavid du Colombier 	fprintf(tl_out, " */\n");
6467dd7cddfSDavid du Colombier 
6477dd7cddfSDavid du Colombier 	do {
6487dd7cddfSDavid du Colombier 		clr_reach();
6497dd7cddfSDavid du Colombier 		Dfs(b);
650312a1df1SDavid du Colombier 		cnt1 = mergetrans();
6517dd7cddfSDavid du Colombier 		cnt2 = mergestates(1);
6527dd7cddfSDavid du Colombier 		if (tl_verbose)
6537dd7cddfSDavid du Colombier 			printf("/* >>%d,%d<< */\n", cnt1, cnt2);
6547dd7cddfSDavid du Colombier 	} while (cnt2 > 0);
6557dd7cddfSDavid du Colombier 
6567dd7cddfSDavid du Colombier #ifdef BUCKY
6577dd7cddfSDavid du Colombier 	buckyballs();
6587dd7cddfSDavid du Colombier 	clr_reach();
6597dd7cddfSDavid du Colombier 	Dfs(b);
6607dd7cddfSDavid du Colombier #endif
661312a1df1SDavid du Colombier 	if (b && b->accepting)
6627dd7cddfSDavid du Colombier 		fprintf(tl_out, "accept_init:\n");
6637dd7cddfSDavid du Colombier 
6647dd7cddfSDavid du Colombier 	if (!b && !never)
6657dd7cddfSDavid du Colombier 	{	fprintf(tl_out, "	0 /* false */;\n");
6667dd7cddfSDavid du Colombier 	} else
6677dd7cddfSDavid du Colombier 	{	printstate(b);	/* init state must be first */
6687dd7cddfSDavid du Colombier 		for (b = never; b; b = b->nxt)
6697dd7cddfSDavid du Colombier 			printstate(b);
6707dd7cddfSDavid du Colombier 	}
6717dd7cddfSDavid du Colombier 	if (hitsall)
6727dd7cddfSDavid du Colombier 	fprintf(tl_out, "accept_all:\n	skip\n");
6737dd7cddfSDavid du Colombier 	fprintf(tl_out, "}\n");
6747dd7cddfSDavid du Colombier }
675