xref: /plan9-contrib/sys/src/cmd/spin/tl_rewrt.c (revision de2caf28f9ba1a56e70be94a699435d36eb50311)
17dd7cddfSDavid du Colombier /***** tl_spin: tl_rewrt.c *****/
27dd7cddfSDavid 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  *
8*de2caf28SDavid du Colombier  * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper,
9*de2caf28SDavid du Colombier  * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.
10*de2caf28SDavid du Colombier  */
117dd7cddfSDavid du Colombier 
127dd7cddfSDavid du Colombier #include "tl.h"
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier extern int	tl_verbose;
157dd7cddfSDavid du Colombier 
167dd7cddfSDavid du Colombier static Node	*can = ZN;
177dd7cddfSDavid du Colombier 
1800d97012SDavid du Colombier void
ini_rewrt(void)1900d97012SDavid du Colombier ini_rewrt(void)
2000d97012SDavid du Colombier {
2100d97012SDavid du Colombier 	can = ZN;
2200d97012SDavid du Colombier }
2300d97012SDavid du Colombier 
247dd7cddfSDavid du Colombier Node *
right_linked(Node * n)257dd7cddfSDavid du Colombier right_linked(Node *n)
267dd7cddfSDavid du Colombier {
277dd7cddfSDavid du Colombier 	if (!n) return n;
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier 	if (n->ntyp == AND || n->ntyp == OR)
307dd7cddfSDavid du Colombier 		while (n->lft && n->lft->ntyp == n->ntyp)
317dd7cddfSDavid du Colombier 		{	Node *tmp = n->lft;
327dd7cddfSDavid du Colombier 			n->lft = tmp->rgt;
337dd7cddfSDavid du Colombier 			tmp->rgt = n;
347dd7cddfSDavid du Colombier 			n = tmp;
357dd7cddfSDavid du Colombier 		}
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier 	n->lft = right_linked(n->lft);
387dd7cddfSDavid du Colombier 	n->rgt = right_linked(n->rgt);
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier 	return n;
417dd7cddfSDavid du Colombier }
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier Node *
canonical(Node * n)447dd7cddfSDavid du Colombier canonical(Node *n)
457dd7cddfSDavid du Colombier {	Node *m;	/* assumes input is right_linked */
467dd7cddfSDavid du Colombier 
477dd7cddfSDavid du Colombier 	if (!n) return n;
48312a1df1SDavid du Colombier 	if ((m = in_cache(n)) != ZN)
497dd7cddfSDavid du Colombier 		return m;
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier 	n->rgt = canonical(n->rgt);
527dd7cddfSDavid du Colombier 	n->lft = canonical(n->lft);
537dd7cddfSDavid du Colombier 
547dd7cddfSDavid du Colombier 	return cached(n);
557dd7cddfSDavid du Colombier }
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier Node *
push_negation(Node * n)587dd7cddfSDavid du Colombier push_negation(Node *n)
597dd7cddfSDavid du Colombier {	Node *m;
607dd7cddfSDavid du Colombier 
617dd7cddfSDavid du Colombier 	Assert(n->ntyp == NOT, n->ntyp);
627dd7cddfSDavid du Colombier 
637dd7cddfSDavid du Colombier 	switch (n->lft->ntyp) {
647dd7cddfSDavid du Colombier 	case TRUE:
657dd7cddfSDavid du Colombier 		Debug("!true => false\n");
667dd7cddfSDavid du Colombier 		releasenode(0, n->lft);
677dd7cddfSDavid du Colombier 		n->lft = ZN;
687dd7cddfSDavid du Colombier 		n->ntyp = FALSE;
697dd7cddfSDavid du Colombier 		break;
707dd7cddfSDavid du Colombier 	case FALSE:
717dd7cddfSDavid du Colombier 		Debug("!false => true\n");
727dd7cddfSDavid du Colombier 		releasenode(0, n->lft);
737dd7cddfSDavid du Colombier 		n->lft = ZN;
747dd7cddfSDavid du Colombier 		n->ntyp = TRUE;
757dd7cddfSDavid du Colombier 		break;
767dd7cddfSDavid du Colombier 	case NOT:
777dd7cddfSDavid du Colombier 		Debug("!!p => p\n");
787dd7cddfSDavid du Colombier 		m = n->lft->lft;
797dd7cddfSDavid du Colombier 		releasenode(0, n->lft);
807dd7cddfSDavid du Colombier 		n->lft = ZN;
817dd7cddfSDavid du Colombier 		releasenode(0, n);
827dd7cddfSDavid du Colombier 		n = m;
837dd7cddfSDavid du Colombier 		break;
847dd7cddfSDavid du Colombier 	case V_OPER:
857dd7cddfSDavid du Colombier 		Debug("!(p V q) => (!p U !q)\n");
867dd7cddfSDavid du Colombier 		n->ntyp = U_OPER;
877dd7cddfSDavid du Colombier 		goto same;
887dd7cddfSDavid du Colombier 	case U_OPER:
897dd7cddfSDavid du Colombier 		Debug("!(p U q) => (!p V !q)\n");
907dd7cddfSDavid du Colombier 		n->ntyp = V_OPER;
917dd7cddfSDavid du Colombier 		goto same;
927dd7cddfSDavid du Colombier #ifdef NXT
937dd7cddfSDavid du Colombier 	case NEXT:
947dd7cddfSDavid du Colombier 		Debug("!X -> X!\n");
957dd7cddfSDavid du Colombier 		n->ntyp = NEXT;
967dd7cddfSDavid du Colombier 		n->lft->ntyp = NOT;
977dd7cddfSDavid du Colombier 		n->lft = push_negation(n->lft);
987dd7cddfSDavid du Colombier 		break;
997dd7cddfSDavid du Colombier #endif
1007dd7cddfSDavid du Colombier 	case  AND:
1017dd7cddfSDavid du Colombier 		Debug("!(p && q) => !p || !q\n");
1027dd7cddfSDavid du Colombier 		n->ntyp = OR;
1037dd7cddfSDavid du Colombier 		goto same;
1047dd7cddfSDavid du Colombier 	case  OR:
1057dd7cddfSDavid du Colombier 		Debug("!(p || q) => !p && !q\n");
1067dd7cddfSDavid du Colombier 		n->ntyp = AND;
1077dd7cddfSDavid du Colombier 
1087dd7cddfSDavid du Colombier same:		m = n->lft->rgt;
1097dd7cddfSDavid du Colombier 		n->lft->rgt = ZN;
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier 		n->rgt = Not(m);
1127dd7cddfSDavid du Colombier 		n->lft->ntyp = NOT;
1137dd7cddfSDavid du Colombier 		m = n->lft;
1147dd7cddfSDavid du Colombier 		n->lft = push_negation(m);
1157dd7cddfSDavid du Colombier 		break;
1167dd7cddfSDavid du Colombier 	}
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier 	return rewrite(n);
1197dd7cddfSDavid du Colombier }
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier static void
addcan(int tok,Node * n)1227dd7cddfSDavid du Colombier addcan(int tok, Node *n)
1237dd7cddfSDavid du Colombier {	Node	*m, *prev = ZN;
1247dd7cddfSDavid du Colombier 	Node	**ptr;
1257dd7cddfSDavid du Colombier 	Node	*N;
1267dd7cddfSDavid du Colombier 	Symbol	*s, *t; int cmp;
1277dd7cddfSDavid du Colombier 
1287dd7cddfSDavid du Colombier 	if (!n) return;
1297dd7cddfSDavid du Colombier 
1307dd7cddfSDavid du Colombier 	if (n->ntyp == tok)
1317dd7cddfSDavid du Colombier 	{	addcan(tok, n->rgt);
1327dd7cddfSDavid du Colombier 		addcan(tok, n->lft);
1337dd7cddfSDavid du Colombier 		return;
1347dd7cddfSDavid du Colombier 	}
135312a1df1SDavid du Colombier 
1367dd7cddfSDavid du Colombier 	N = dupnode(n);
1377dd7cddfSDavid du Colombier 	if (!can)
1387dd7cddfSDavid du Colombier 	{	can = N;
1397dd7cddfSDavid du Colombier 		return;
1407dd7cddfSDavid du Colombier 	}
1417dd7cddfSDavid du Colombier 
1427dd7cddfSDavid du Colombier 	s = DoDump(N);
143*de2caf28SDavid du Colombier 	if (!s)
144*de2caf28SDavid du Colombier 	{	fatal("unexpected error 6", (char *) 0);
145*de2caf28SDavid du Colombier 	}
1467dd7cddfSDavid du Colombier 	if (can->ntyp != tok)	/* only one element in list so far */
1477dd7cddfSDavid du Colombier 	{	ptr = &can;
1487dd7cddfSDavid du Colombier 		goto insert;
1497dd7cddfSDavid du Colombier 	}
1507dd7cddfSDavid du Colombier 
1517dd7cddfSDavid du Colombier 	/* there are at least 2 elements in list */
1527dd7cddfSDavid du Colombier 	prev = ZN;
1537dd7cddfSDavid du Colombier 	for (m = can; m->ntyp == tok && m->rgt; prev = m, m = m->rgt)
1547dd7cddfSDavid du Colombier 	{	t = DoDump(m->lft);
15500d97012SDavid du Colombier 		if (t != ZS)
1567dd7cddfSDavid du Colombier 			cmp = strcmp(s->name, t->name);
15700d97012SDavid du Colombier 		else
15800d97012SDavid du Colombier 			cmp = 0;
1597dd7cddfSDavid du Colombier 		if (cmp == 0)	/* duplicate */
1607dd7cddfSDavid du Colombier 			return;
1617dd7cddfSDavid du Colombier 		if (cmp < 0)
1627dd7cddfSDavid du Colombier 		{	if (!prev)
1637dd7cddfSDavid du Colombier 			{	can = tl_nn(tok, N, can);
1647dd7cddfSDavid du Colombier 				return;
1657dd7cddfSDavid du Colombier 			} else
1667dd7cddfSDavid du Colombier 			{	ptr = &(prev->rgt);
1677dd7cddfSDavid du Colombier 				goto insert;
1687dd7cddfSDavid du Colombier 	}	}	}
1697dd7cddfSDavid du Colombier 
1707dd7cddfSDavid du Colombier 	/* new entry goes at the end of the list */
1717dd7cddfSDavid du Colombier 	ptr = &(prev->rgt);
1727dd7cddfSDavid du Colombier insert:
1737dd7cddfSDavid du Colombier 	t = DoDump(*ptr);
1747dd7cddfSDavid du Colombier 	cmp = strcmp(s->name, t->name);
1757dd7cddfSDavid du Colombier 	if (cmp == 0)	/* duplicate */
1767dd7cddfSDavid du Colombier 		return;
1777dd7cddfSDavid du Colombier 	if (cmp < 0)
1787dd7cddfSDavid du Colombier 		*ptr = tl_nn(tok, N, *ptr);
1797dd7cddfSDavid du Colombier 	else
1807dd7cddfSDavid du Colombier 		*ptr = tl_nn(tok, *ptr, N);
1817dd7cddfSDavid du Colombier }
1827dd7cddfSDavid du Colombier 
1837dd7cddfSDavid du Colombier static void
marknode(int tok,Node * m)1847dd7cddfSDavid du Colombier marknode(int tok, Node *m)
1857dd7cddfSDavid du Colombier {
1867dd7cddfSDavid du Colombier 	if (m->ntyp != tok)
1877dd7cddfSDavid du Colombier 	{	releasenode(0, m->rgt);
1887dd7cddfSDavid du Colombier 		m->rgt = ZN;
1897dd7cddfSDavid du Colombier 	}
1907dd7cddfSDavid du Colombier 	m->ntyp = -1;
1917dd7cddfSDavid du Colombier }
1927dd7cddfSDavid du Colombier 
1937dd7cddfSDavid du Colombier Node *
Canonical(Node * n)1947dd7cddfSDavid du Colombier Canonical(Node *n)
1957dd7cddfSDavid du Colombier {	Node *m, *p, *k1, *k2, *prev, *dflt = ZN;
1967dd7cddfSDavid du Colombier 	int tok;
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier 	if (!n) return n;
1997dd7cddfSDavid du Colombier 
2007dd7cddfSDavid du Colombier 	tok = n->ntyp;
2017dd7cddfSDavid du Colombier 	if (tok != AND && tok != OR)
2027dd7cddfSDavid du Colombier 		return n;
2037dd7cddfSDavid du Colombier 
2047dd7cddfSDavid du Colombier 	can = ZN;
2057dd7cddfSDavid du Colombier 	addcan(tok, n);
206312a1df1SDavid du Colombier #if 0
2077dd7cddfSDavid du Colombier 	Debug("\nA0: "); Dump(can);
2087dd7cddfSDavid du Colombier 	Debug("\nA1: "); Dump(n); Debug("\n");
2097dd7cddfSDavid du Colombier #endif
2107dd7cddfSDavid du Colombier 	releasenode(1, n);
2117dd7cddfSDavid du Colombier 
2127dd7cddfSDavid du Colombier 	/* mark redundant nodes */
2137dd7cddfSDavid du Colombier 	if (tok == AND)
2147dd7cddfSDavid du Colombier 	{	for (m = can; m; m = (m->ntyp == AND) ? m->rgt : ZN)
2157dd7cddfSDavid du Colombier 		{	k1 = (m->ntyp == AND) ? m->lft : m;
2167dd7cddfSDavid du Colombier 			if (k1->ntyp == TRUE)
2177dd7cddfSDavid du Colombier 			{	marknode(AND, m);
2187dd7cddfSDavid du Colombier 				dflt = True;
2197dd7cddfSDavid du Colombier 				continue;
2207dd7cddfSDavid du Colombier 			}
2217dd7cddfSDavid du Colombier 			if (k1->ntyp == FALSE)
2227dd7cddfSDavid du Colombier 			{	releasenode(1, can);
2237dd7cddfSDavid du Colombier 				can = False;
2247dd7cddfSDavid du Colombier 				goto out;
2257dd7cddfSDavid du Colombier 		}	}
2267dd7cddfSDavid du Colombier 		for (m = can; m; m = (m->ntyp == AND) ? m->rgt : ZN)
2277dd7cddfSDavid du Colombier 		for (p = can; p; p = (p->ntyp == AND) ? p->rgt : ZN)
2287dd7cddfSDavid du Colombier 		{	if (p == m
2297dd7cddfSDavid du Colombier 			||  p->ntyp == -1
2307dd7cddfSDavid du Colombier 			||  m->ntyp == -1)
2317dd7cddfSDavid du Colombier 				continue;
2327dd7cddfSDavid du Colombier 			k1 = (m->ntyp == AND) ? m->lft : m;
2337dd7cddfSDavid du Colombier 			k2 = (p->ntyp == AND) ? p->lft : p;
2347dd7cddfSDavid du Colombier 
2357dd7cddfSDavid du Colombier 			if (isequal(k1, k2))
2367dd7cddfSDavid du Colombier 			{	marknode(AND, p);
2377dd7cddfSDavid du Colombier 				continue;
2387dd7cddfSDavid du Colombier 			}
2397dd7cddfSDavid du Colombier 			if (anywhere(OR, k1, k2))
2407dd7cddfSDavid du Colombier 			{	marknode(AND, p);
2417dd7cddfSDavid du Colombier 				continue;
2427dd7cddfSDavid du Colombier 			}
2437dd7cddfSDavid du Colombier 	}	}
2447dd7cddfSDavid du Colombier 	if (tok == OR)
2457dd7cddfSDavid du Colombier 	{	for (m = can; m; m = (m->ntyp == OR) ? m->rgt : ZN)
2467dd7cddfSDavid du Colombier 		{	k1 = (m->ntyp == OR) ? m->lft : m;
2477dd7cddfSDavid du Colombier 			if (k1->ntyp == FALSE)
2487dd7cddfSDavid du Colombier 			{	marknode(OR, m);
2497dd7cddfSDavid du Colombier 				dflt = False;
2507dd7cddfSDavid du Colombier 				continue;
2517dd7cddfSDavid du Colombier 			}
2527dd7cddfSDavid du Colombier 			if (k1->ntyp == TRUE)
2537dd7cddfSDavid du Colombier 			{	releasenode(1, can);
2547dd7cddfSDavid du Colombier 				can = True;
2557dd7cddfSDavid du Colombier 				goto out;
2567dd7cddfSDavid du Colombier 		}	}
2577dd7cddfSDavid du Colombier 		for (m = can; m; m = (m->ntyp == OR) ? m->rgt : ZN)
2587dd7cddfSDavid du Colombier 		for (p = can; p; p = (p->ntyp == OR) ? p->rgt : ZN)
2597dd7cddfSDavid du Colombier 		{	if (p == m
2607dd7cddfSDavid du Colombier 			||  p->ntyp == -1
2617dd7cddfSDavid du Colombier 			||  m->ntyp == -1)
2627dd7cddfSDavid du Colombier 				continue;
2637dd7cddfSDavid du Colombier 			k1 = (m->ntyp == OR) ? m->lft : m;
2647dd7cddfSDavid du Colombier 			k2 = (p->ntyp == OR) ? p->lft : p;
2657dd7cddfSDavid du Colombier 
2667dd7cddfSDavid du Colombier 			if (isequal(k1, k2))
2677dd7cddfSDavid du Colombier 			{	marknode(OR, p);
2687dd7cddfSDavid du Colombier 				continue;
2697dd7cddfSDavid du Colombier 			}
2707dd7cddfSDavid du Colombier 			if (anywhere(AND, k1, k2))
2717dd7cddfSDavid du Colombier 			{	marknode(OR, p);
2727dd7cddfSDavid du Colombier 				continue;
2737dd7cddfSDavid du Colombier 			}
2747dd7cddfSDavid du Colombier 	}	}
2757dd7cddfSDavid du Colombier 	for (m = can, prev = ZN; m; )	/* remove marked nodes */
2767dd7cddfSDavid du Colombier 	{	if (m->ntyp == -1)
2777dd7cddfSDavid du Colombier 		{	k2 = m->rgt;
2787dd7cddfSDavid du Colombier 			releasenode(0, m);
2797dd7cddfSDavid du Colombier 			if (!prev)
2807dd7cddfSDavid du Colombier 			{	m = can = can->rgt;
2817dd7cddfSDavid du Colombier 			} else
2827dd7cddfSDavid du Colombier 			{	m = prev->rgt = k2;
2837dd7cddfSDavid du Colombier 				/* if deleted the last node in a chain */
2847dd7cddfSDavid du Colombier 				if (!prev->rgt && prev->lft
2857dd7cddfSDavid du Colombier 				&&  (prev->ntyp == AND || prev->ntyp == OR))
2867dd7cddfSDavid du Colombier 				{	k1 = prev->lft;
2877dd7cddfSDavid du Colombier 					prev->ntyp = prev->lft->ntyp;
2887dd7cddfSDavid du Colombier 					prev->sym = prev->lft->sym;
2897dd7cddfSDavid du Colombier 					prev->rgt = prev->lft->rgt;
2907dd7cddfSDavid du Colombier 					prev->lft = prev->lft->lft;
2917dd7cddfSDavid du Colombier 					releasenode(0, k1);
2927dd7cddfSDavid du Colombier 				}
2937dd7cddfSDavid du Colombier 			}
2947dd7cddfSDavid du Colombier 			continue;
2957dd7cddfSDavid du Colombier 		}
2967dd7cddfSDavid du Colombier 		prev = m;
2977dd7cddfSDavid du Colombier 		m = m->rgt;
2987dd7cddfSDavid du Colombier 	}
2997dd7cddfSDavid du Colombier out:
300312a1df1SDavid du Colombier #if 0
3017dd7cddfSDavid du Colombier 	Debug("A2: "); Dump(can); Debug("\n");
3027dd7cddfSDavid du Colombier #endif
3037dd7cddfSDavid du Colombier 	if (!can)
3047dd7cddfSDavid du Colombier 	{	if (!dflt)
3057dd7cddfSDavid du Colombier 			fatal("cannot happen, Canonical", (char *) 0);
3067dd7cddfSDavid du Colombier 		return dflt;
3077dd7cddfSDavid du Colombier 	}
3087dd7cddfSDavid du Colombier 
3097dd7cddfSDavid du Colombier 	return can;
3107dd7cddfSDavid du Colombier }
311