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