xref: /plan9/sys/src/cmd/spin/tl_rewrt.c (revision 00d970127b9d44d2b22f4f656717a212dec1f1d2)
17dd7cddfSDavid du Colombier /***** tl_spin: tl_rewrt.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;
187dd7cddfSDavid du Colombier 
197dd7cddfSDavid du Colombier static Node	*can = ZN;
207dd7cddfSDavid du Colombier 
21*00d97012SDavid du Colombier void
ini_rewrt(void)22*00d97012SDavid du Colombier ini_rewrt(void)
23*00d97012SDavid du Colombier {
24*00d97012SDavid du Colombier 	can = ZN;
25*00d97012SDavid du Colombier }
26*00d97012SDavid du Colombier 
277dd7cddfSDavid du Colombier Node *
right_linked(Node * n)287dd7cddfSDavid du Colombier right_linked(Node *n)
297dd7cddfSDavid du Colombier {
307dd7cddfSDavid du Colombier 	if (!n) return n;
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier 	if (n->ntyp == AND || n->ntyp == OR)
337dd7cddfSDavid du Colombier 		while (n->lft && n->lft->ntyp == n->ntyp)
347dd7cddfSDavid du Colombier 		{	Node *tmp = n->lft;
357dd7cddfSDavid du Colombier 			n->lft = tmp->rgt;
367dd7cddfSDavid du Colombier 			tmp->rgt = n;
377dd7cddfSDavid du Colombier 			n = tmp;
387dd7cddfSDavid du Colombier 		}
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier 	n->lft = right_linked(n->lft);
417dd7cddfSDavid du Colombier 	n->rgt = right_linked(n->rgt);
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier 	return n;
447dd7cddfSDavid du Colombier }
457dd7cddfSDavid du Colombier 
467dd7cddfSDavid du Colombier Node *
canonical(Node * n)477dd7cddfSDavid du Colombier canonical(Node *n)
487dd7cddfSDavid du Colombier {	Node *m;	/* assumes input is right_linked */
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier 	if (!n) return n;
51312a1df1SDavid du Colombier 	if ((m = in_cache(n)) != ZN)
527dd7cddfSDavid du Colombier 		return m;
537dd7cddfSDavid du Colombier 
547dd7cddfSDavid du Colombier 	n->rgt = canonical(n->rgt);
557dd7cddfSDavid du Colombier 	n->lft = canonical(n->lft);
567dd7cddfSDavid du Colombier 
577dd7cddfSDavid du Colombier 	return cached(n);
587dd7cddfSDavid du Colombier }
597dd7cddfSDavid du Colombier 
607dd7cddfSDavid du Colombier Node *
push_negation(Node * n)617dd7cddfSDavid du Colombier push_negation(Node *n)
627dd7cddfSDavid du Colombier {	Node *m;
637dd7cddfSDavid du Colombier 
647dd7cddfSDavid du Colombier 	Assert(n->ntyp == NOT, n->ntyp);
657dd7cddfSDavid du Colombier 
667dd7cddfSDavid du Colombier 	switch (n->lft->ntyp) {
677dd7cddfSDavid du Colombier 	case TRUE:
687dd7cddfSDavid du Colombier 		Debug("!true => false\n");
697dd7cddfSDavid du Colombier 		releasenode(0, n->lft);
707dd7cddfSDavid du Colombier 		n->lft = ZN;
717dd7cddfSDavid du Colombier 		n->ntyp = FALSE;
727dd7cddfSDavid du Colombier 		break;
737dd7cddfSDavid du Colombier 	case FALSE:
747dd7cddfSDavid du Colombier 		Debug("!false => true\n");
757dd7cddfSDavid du Colombier 		releasenode(0, n->lft);
767dd7cddfSDavid du Colombier 		n->lft = ZN;
777dd7cddfSDavid du Colombier 		n->ntyp = TRUE;
787dd7cddfSDavid du Colombier 		break;
797dd7cddfSDavid du Colombier 	case NOT:
807dd7cddfSDavid du Colombier 		Debug("!!p => p\n");
817dd7cddfSDavid du Colombier 		m = n->lft->lft;
827dd7cddfSDavid du Colombier 		releasenode(0, n->lft);
837dd7cddfSDavid du Colombier 		n->lft = ZN;
847dd7cddfSDavid du Colombier 		releasenode(0, n);
857dd7cddfSDavid du Colombier 		n = m;
867dd7cddfSDavid du Colombier 		break;
877dd7cddfSDavid du Colombier 	case V_OPER:
887dd7cddfSDavid du Colombier 		Debug("!(p V q) => (!p U !q)\n");
897dd7cddfSDavid du Colombier 		n->ntyp = U_OPER;
907dd7cddfSDavid du Colombier 		goto same;
917dd7cddfSDavid du Colombier 	case U_OPER:
927dd7cddfSDavid du Colombier 		Debug("!(p U q) => (!p V !q)\n");
937dd7cddfSDavid du Colombier 		n->ntyp = V_OPER;
947dd7cddfSDavid du Colombier 		goto same;
957dd7cddfSDavid du Colombier #ifdef NXT
967dd7cddfSDavid du Colombier 	case NEXT:
977dd7cddfSDavid du Colombier 		Debug("!X -> X!\n");
987dd7cddfSDavid du Colombier 		n->ntyp = NEXT;
997dd7cddfSDavid du Colombier 		n->lft->ntyp = NOT;
1007dd7cddfSDavid du Colombier 		n->lft = push_negation(n->lft);
1017dd7cddfSDavid du Colombier 		break;
1027dd7cddfSDavid du Colombier #endif
1037dd7cddfSDavid du Colombier 	case  AND:
1047dd7cddfSDavid du Colombier 		Debug("!(p && q) => !p || !q\n");
1057dd7cddfSDavid du Colombier 		n->ntyp = OR;
1067dd7cddfSDavid du Colombier 		goto same;
1077dd7cddfSDavid du Colombier 	case  OR:
1087dd7cddfSDavid du Colombier 		Debug("!(p || q) => !p && !q\n");
1097dd7cddfSDavid du Colombier 		n->ntyp = AND;
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier same:		m = n->lft->rgt;
1127dd7cddfSDavid du Colombier 		n->lft->rgt = ZN;
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier 		n->rgt = Not(m);
1157dd7cddfSDavid du Colombier 		n->lft->ntyp = NOT;
1167dd7cddfSDavid du Colombier 		m = n->lft;
1177dd7cddfSDavid du Colombier 		n->lft = push_negation(m);
1187dd7cddfSDavid du Colombier 		break;
1197dd7cddfSDavid du Colombier 	}
1207dd7cddfSDavid du Colombier 
1217dd7cddfSDavid du Colombier 	return rewrite(n);
1227dd7cddfSDavid du Colombier }
1237dd7cddfSDavid du Colombier 
1247dd7cddfSDavid du Colombier static void
addcan(int tok,Node * n)1257dd7cddfSDavid du Colombier addcan(int tok, Node *n)
1267dd7cddfSDavid du Colombier {	Node	*m, *prev = ZN;
1277dd7cddfSDavid du Colombier 	Node	**ptr;
1287dd7cddfSDavid du Colombier 	Node	*N;
1297dd7cddfSDavid du Colombier 	Symbol	*s, *t; int cmp;
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier 	if (!n) return;
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier 	if (n->ntyp == tok)
1347dd7cddfSDavid du Colombier 	{	addcan(tok, n->rgt);
1357dd7cddfSDavid du Colombier 		addcan(tok, n->lft);
1367dd7cddfSDavid du Colombier 		return;
1377dd7cddfSDavid du Colombier 	}
138312a1df1SDavid du Colombier 
1397dd7cddfSDavid du Colombier 	N = dupnode(n);
1407dd7cddfSDavid du Colombier 	if (!can)
1417dd7cddfSDavid du Colombier 	{	can = N;
1427dd7cddfSDavid du Colombier 		return;
1437dd7cddfSDavid du Colombier 	}
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier 	s = DoDump(N);
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);
155*00d97012SDavid du Colombier 		if (t != ZS)
1567dd7cddfSDavid du Colombier 			cmp = strcmp(s->name, t->name);
157*00d97012SDavid du Colombier 		else
158*00d97012SDavid 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