tl_buchi.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. /***** tl_spin: tl_buchi.c *****/
  2. /* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories */
  3. /* All Rights Reserved. This software is for educational purposes only. */
  4. /* Permission is given to distribute this code provided that this intro- */
  5. /* ductory message is not removed and no monies are exchanged. */
  6. /* No guarantee is expressed or implied by the distribution of this code. */
  7. /* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A. */
  8. /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
  9. /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
  10. /* Send bug-reports and/or questions to: gerard@research.bell-labs.com */
  11. #include "tl.h"
  12. extern int tl_verbose, tl_clutter, Total, Max_Red;
  13. FILE *tl_out; /* if standalone: = stdout; */
  14. typedef struct Transition {
  15. Symbol *name;
  16. Node *cond;
  17. int redundant, merged, marked;
  18. struct Transition *nxt;
  19. } Transition;
  20. typedef struct State {
  21. Symbol *name;
  22. Transition *trans;
  23. Graph *colors;
  24. unsigned char redundant;
  25. unsigned char accepting;
  26. unsigned char reachable;
  27. struct State *nxt;
  28. } State;
  29. static State *never = (State *) 0;
  30. static int hitsall;
  31. static int
  32. sametrans(Transition *s, Transition *t)
  33. {
  34. if (strcmp(s->name->name, t->name->name) != 0)
  35. return 0;
  36. return isequal(s->cond, t->cond);
  37. }
  38. static Node *
  39. Prune(Node *p)
  40. {
  41. if (p)
  42. switch (p->ntyp) {
  43. case PREDICATE:
  44. case NOT:
  45. case FALSE:
  46. case TRUE:
  47. #ifdef NXT
  48. case NEXT:
  49. #endif
  50. return p;
  51. case OR:
  52. p->lft = Prune(p->lft);
  53. if (!p->lft)
  54. { releasenode(1, p->rgt);
  55. return ZN;
  56. }
  57. p->rgt = Prune(p->rgt);
  58. if (!p->rgt)
  59. { releasenode(1, p->lft);
  60. return ZN;
  61. }
  62. return p;
  63. case AND:
  64. p->lft = Prune(p->lft);
  65. if (!p->lft)
  66. return Prune(p->rgt);
  67. p->rgt = Prune(p->rgt);
  68. if (!p->rgt)
  69. return p->lft;
  70. return p;
  71. #if 0
  72. /* 3.3.9 */
  73. case V_OPER:
  74. releasenode(1, p->lft);
  75. return Prune(p->rgt);
  76. #endif
  77. }
  78. releasenode(1, p);
  79. return ZN;
  80. }
  81. static State *
  82. findstate(char *nm)
  83. { State *b;
  84. for (b = never; b; b = b->nxt)
  85. if (!strcmp(b->name->name, nm))
  86. return b;
  87. if (strcmp(nm, "accept_all"))
  88. { if (strncmp(nm, "accept", 6))
  89. { int i; char altnm[64];
  90. for (i = 0; i < 64; i++)
  91. if (nm[i] == '_')
  92. break;
  93. if (i >= 64)
  94. Fatal("name too long %s", nm);
  95. sprintf(altnm, "accept%s", &nm[i]);
  96. return findstate(altnm);
  97. }
  98. /* Fatal("buchi: no state %s", nm); */
  99. }
  100. return (State *) 0;
  101. }
  102. static void
  103. Dfs(State *b)
  104. { Transition *t;
  105. if (!b || b->reachable) return;
  106. b->reachable = 1;
  107. if (b->redundant)
  108. printf("spin: internal error, Dfs hits redundant state %s\n",
  109. b->name->name);
  110. for (t = b->trans; t; t = t->nxt)
  111. { if (!t->redundant)
  112. { Dfs(findstate(t->name->name));
  113. if (!hitsall
  114. && strcmp(t->name->name, "accept_all") == 0)
  115. hitsall = 1;
  116. }
  117. }
  118. }
  119. void
  120. retarget(char *from, char *to)
  121. { State *b;
  122. Transition *t;
  123. Symbol *To = tl_lookup(to);
  124. if (tl_verbose) printf("replace %s with %s\n", from, to);
  125. for (b = never; b; b = b->nxt)
  126. { if (!strcmp(b->name->name, from))
  127. { b->redundant = 1;
  128. for (t = b->trans; t; t = t->nxt)
  129. { /* releasenode(1, t->cond); */
  130. t->cond = ZN;
  131. }
  132. } else
  133. for (t = b->trans; t; t = t->nxt)
  134. { if (!strcmp(t->name->name, from))
  135. t->name = To;
  136. } }
  137. }
  138. #ifdef NXT
  139. static Node *
  140. nonxt(Node *n)
  141. {
  142. switch (n->ntyp) {
  143. case U_OPER:
  144. case V_OPER:
  145. case NEXT:
  146. return ZN;
  147. case OR:
  148. n->lft = nonxt(n->lft);
  149. n->rgt = nonxt(n->rgt);
  150. if (!n->lft || !n->rgt)
  151. return True;
  152. return n;
  153. case AND:
  154. n->lft = nonxt(n->lft);
  155. n->rgt = nonxt(n->rgt);
  156. if (!n->lft)
  157. { if (!n->rgt)
  158. n = ZN;
  159. else
  160. n = n->rgt;
  161. } else if (!n->rgt)
  162. n = n->lft;
  163. return n;
  164. }
  165. return n;
  166. }
  167. #endif
  168. static Node *
  169. combination(Node *s, Node *t)
  170. { Node *nc;
  171. #ifdef NXT
  172. Node *a = nonxt(s);
  173. Node *b = nonxt(t);
  174. #if 1
  175. if (tl_verbose)
  176. { printf("\tnonxtA: "); dump(a);
  177. printf("\n\tnonxtB: "); dump(b);
  178. printf("\n");
  179. }
  180. /* if there's only a X(f), its equivalent to true */
  181. if (!a || !b)
  182. nc = True;
  183. else
  184. nc = tl_nn(OR, a, b);
  185. #else
  186. if (!a)
  187. { releasenode(1, s);
  188. if (!b)
  189. { releasenode(1, t);
  190. nc = False;
  191. } else
  192. { nc = b;
  193. }
  194. } else if (!b)
  195. { releasenode(1, t);
  196. nc = a;
  197. } else
  198. { nc = tl_nn(OR, a, b);
  199. }
  200. #endif
  201. #else
  202. nc = tl_nn(OR, s, t);
  203. #endif
  204. if (tl_verbose)
  205. { printf("\tcombo: "); dump(nc);
  206. printf("\n");
  207. }
  208. return nc;
  209. }
  210. Node *
  211. unclutter(Node *n, char *snm)
  212. { Node *t, *s, *v, *u;
  213. Symbol *w;
  214. /* check only simple cases like !q && q */
  215. for (t = n; t; t = t->rgt)
  216. { if (t->rgt)
  217. { if (t->ntyp != AND || !t->lft)
  218. return n;
  219. if (t->lft->ntyp != PREDICATE
  220. #ifdef NXT
  221. && t->lft->ntyp != NEXT
  222. #endif
  223. && t->lft->ntyp != NOT)
  224. return n;
  225. } else
  226. { if (t->ntyp != PREDICATE
  227. #ifdef NXT
  228. && t->ntyp != NEXT
  229. #endif
  230. && t->ntyp != NOT)
  231. return n;
  232. }
  233. }
  234. for (t = n; t; t = t->rgt)
  235. { if (t->rgt)
  236. v = t->lft;
  237. else
  238. v = t;
  239. if (v->ntyp == NOT
  240. && v->lft->ntyp == PREDICATE)
  241. { w = v->lft->sym;
  242. for (s = n; s; s = s->rgt)
  243. { if (s == t) continue;
  244. if (s->rgt)
  245. u = s->lft;
  246. else
  247. u = s;
  248. if (u->ntyp == PREDICATE
  249. && strcmp(u->sym->name, w->name) == 0)
  250. { if (tl_verbose)
  251. { printf("BINGO %s:\t", snm);
  252. dump(n);
  253. printf("\n");
  254. }
  255. return False;
  256. }
  257. }
  258. } }
  259. return n;
  260. }
  261. static void
  262. clutter(void)
  263. { State *p;
  264. Transition *s;
  265. for (p = never; p; p = p->nxt)
  266. for (s = p->trans; s; s = s->nxt)
  267. { s->cond = unclutter(s->cond, p->name->name);
  268. if (s->cond
  269. && s->cond->ntyp == FALSE)
  270. { if (s != p->trans
  271. || s->nxt)
  272. s->redundant = 1;
  273. }
  274. }
  275. }
  276. static void
  277. showtrans(State *a)
  278. { Transition *s;
  279. for (s = a->trans; s; s = s->nxt)
  280. { printf("%s ", s->name?s->name->name:"-");
  281. dump(s->cond);
  282. printf(" %d %d %d\n", s->redundant, s->merged, s->marked);
  283. }
  284. }
  285. static int
  286. mergetrans(int v)
  287. { State *b;
  288. Transition *s, *t;
  289. Node *nc; int cnt = 0;
  290. for (b = never; b; b = b->nxt)
  291. { if (!b->reachable) continue;
  292. for (s = b->trans; s; s = s->nxt)
  293. { if (s->redundant) continue;
  294. for (t = s->nxt; t; t = t->nxt)
  295. if (!t->redundant
  296. && !strcmp(s->name->name, t->name->name))
  297. { if (tl_verbose)
  298. { printf("===\nstate %s, trans to %s redundant\n",
  299. b->name->name, s->name->name);
  300. showtrans(b);
  301. printf(" conditions ");
  302. dump(s->cond); printf(" <-> ");
  303. dump(t->cond); printf("\n");
  304. }
  305. if (!s->cond) /* same as T */
  306. { releasenode(1, t->cond); /* T or t */
  307. nc = True;
  308. } else if (!t->cond)
  309. { releasenode(1, s->cond);
  310. nc = True;
  311. } else
  312. { nc = combination(s->cond, t->cond);
  313. }
  314. t->cond = rewrite(nc);
  315. t->merged = 1;
  316. s->redundant = 1;
  317. cnt++;
  318. break;
  319. } } }
  320. return cnt;
  321. }
  322. static int
  323. all_trans_match(State *a, State *b)
  324. { Transition *s, *t;
  325. int found, result = 0;
  326. if (a->accepting != b->accepting)
  327. goto done;
  328. for (s = a->trans; s; s = s->nxt)
  329. { if (s->redundant) continue;
  330. found = 0;
  331. for (t = b->trans; t; t = t->nxt)
  332. { if (t->redundant) continue;
  333. if (sametrans(s, t))
  334. { found = 1;
  335. t->marked = 1;
  336. break;
  337. } }
  338. if (!found)
  339. goto done;
  340. }
  341. for (s = b->trans; s; s = s->nxt)
  342. { if (s->redundant || s->marked) continue;
  343. found = 0;
  344. for (t = a->trans; t; t = t->nxt)
  345. { if (t->redundant) continue;
  346. if (sametrans(s, t))
  347. { found = 1;
  348. break;
  349. } }
  350. if (!found)
  351. goto done;
  352. }
  353. result = 1;
  354. done:
  355. for (s = b->trans; s; s = s->nxt)
  356. s->marked = 0;
  357. return result;
  358. }
  359. #define BUCKY
  360. #ifdef BUCKY
  361. static int
  362. all_bucky(State *a, State *b)
  363. { Transition *s, *t;
  364. int found, result = 0;
  365. for (s = a->trans; s; s = s->nxt)
  366. { if (s->redundant) continue;
  367. found = 0;
  368. for (t = b->trans; t; t = t->nxt)
  369. { if (t->redundant) continue;
  370. if (isequal(s->cond, t->cond))
  371. { if (strcmp(s->name->name, b->name->name) == 0
  372. && strcmp(t->name->name, a->name->name) == 0)
  373. { found = 1; /* they point to each other */
  374. t->marked = 1;
  375. break;
  376. }
  377. if (strcmp(s->name->name, t->name->name) == 0
  378. && strcmp(s->name->name, "accept_all") == 0)
  379. { found = 1;
  380. t->marked = 1;
  381. break;
  382. /* same exit from which there is no return */
  383. }
  384. }
  385. }
  386. if (!found)
  387. goto done;
  388. }
  389. for (s = b->trans; s; s = s->nxt)
  390. { if (s->redundant || s->marked) continue;
  391. found = 0;
  392. for (t = a->trans; t; t = t->nxt)
  393. { if (t->redundant) continue;
  394. if (isequal(s->cond, t->cond))
  395. { if (strcmp(s->name->name, a->name->name) == 0
  396. && strcmp(t->name->name, b->name->name) == 0)
  397. { found = 1;
  398. t->marked = 1;
  399. break;
  400. }
  401. if (strcmp(s->name->name, t->name->name) == 0
  402. && strcmp(s->name->name, "accept_all") == 0)
  403. { found = 1;
  404. t->marked = 1;
  405. break;
  406. }
  407. }
  408. }
  409. if (!found)
  410. goto done;
  411. }
  412. result = 1;
  413. done:
  414. for (s = b->trans; s; s = s->nxt)
  415. s->marked = 0;
  416. return result;
  417. }
  418. static int
  419. buckyballs(void)
  420. { State *a, *b, *c, *d;
  421. int m, cnt=0;
  422. do {
  423. m = 0; cnt++;
  424. for (a = never; a; a = a->nxt)
  425. { if (!a->reachable) continue;
  426. if (a->redundant) continue;
  427. for (b = a->nxt; b; b = b->nxt)
  428. { if (!b->reachable) continue;
  429. if (b->redundant) continue;
  430. if (all_bucky(a, b))
  431. { m++;
  432. if (tl_verbose)
  433. { printf("%s bucky match %s\n",
  434. a->name->name, b->name->name);
  435. }
  436. if (a->accepting && !b->accepting)
  437. { c = b; d = a;
  438. } else
  439. { c = a; d = b;
  440. }
  441. retarget(c->name->name, d->name->name);
  442. if (!strncmp(c->name->name, "accept", 6)
  443. && Max_Red == 0)
  444. { char buf[64];
  445. sprintf(buf, "T0%s", &(c->name->name[6]));
  446. retarget(buf, d->name->name);
  447. }
  448. break;
  449. }
  450. } }
  451. } while (m && cnt < 10);
  452. return cnt-1;
  453. }
  454. #endif
  455. static int
  456. mergestates(int v)
  457. { State *a, *b;
  458. int m, cnt=0;
  459. #if 1
  460. if (tl_verbose)
  461. return 0;
  462. #endif
  463. do {
  464. m = 0; cnt++;
  465. for (a = never; a; a = a->nxt)
  466. { if (v && !a->reachable) continue;
  467. if (a->redundant) continue; /* 3.3.10 */
  468. for (b = a->nxt; b; b = b->nxt)
  469. { if (v && !b->reachable) continue;
  470. if (b->redundant) continue; /* 3.3.10 */
  471. if (all_trans_match(a, b))
  472. { m++;
  473. if (tl_verbose)
  474. { printf("%d: state %s equals state %s\n",
  475. cnt, a->name->name, b->name->name);
  476. showtrans(a);
  477. printf("==\n");
  478. showtrans(b);
  479. }
  480. retarget(a->name->name, b->name->name);
  481. if (!strncmp(a->name->name, "accept", 6)
  482. && Max_Red == 0)
  483. { char buf[64];
  484. sprintf(buf, "T0%s", &(a->name->name[6]));
  485. retarget(buf, b->name->name);
  486. }
  487. break;
  488. }
  489. #if 0
  490. else if (tl_verbose)
  491. { printf("\n%d: state %s differs from state %s [%d,%d]\n",
  492. cnt, a->name->name, b->name->name, a->accepting, b->accepting);
  493. showtrans(a);
  494. printf("==\n");
  495. showtrans(b);
  496. printf("\n");
  497. }
  498. #endif
  499. } }
  500. } while (m && cnt < 10);
  501. return cnt-1;
  502. }
  503. static int tcnt;
  504. static void
  505. rev_trans(Transition *t) /* print transitions in reverse order... */
  506. {
  507. if (!t) return;
  508. rev_trans(t->nxt);
  509. if (t->redundant && !tl_verbose) return;
  510. fprintf(tl_out, "\t:: (");
  511. if (dump_cond(t->cond, t->cond, 1))
  512. fprintf(tl_out, "1");
  513. fprintf(tl_out, ") -> goto %s\n", t->name->name);
  514. tcnt++;
  515. }
  516. static void
  517. printstate(State *b)
  518. {
  519. if (!b || (!tl_verbose && !b->reachable)) return;
  520. b->reachable = 0; /* print only once */
  521. fprintf(tl_out, "%s:\n", b->name->name);
  522. if (strncmp(b->name->name, "accept", 6) == 0
  523. && Max_Red == 0)
  524. fprintf(tl_out, "T0%s:\n", &(b->name->name[6]));
  525. fprintf(tl_out, "\tif\n");
  526. tcnt = 0;
  527. rev_trans(b->trans);
  528. if (!tcnt) fprintf(tl_out, "\t:: false\n");
  529. fprintf(tl_out, "\tfi;\n");
  530. Total++;
  531. }
  532. void
  533. addtrans(Graph *col, char *from, Node *op, char *to)
  534. { State *b;
  535. Transition *t;
  536. t = (Transition *) tl_emalloc(sizeof(Transition));
  537. t->name = tl_lookup(to);
  538. t->cond = Prune(dupnode(op));
  539. if (tl_verbose)
  540. { printf("\n<<\t"); dump(op);
  541. printf("\n\t"); dump(t->cond);
  542. printf(">> %s\n", t->name->name);
  543. }
  544. if (t->cond) t->cond = rewrite(t->cond);
  545. for (b = never; b; b = b->nxt)
  546. if (!strcmp(b->name->name, from))
  547. { t->nxt = b->trans;
  548. b->trans = t;
  549. return;
  550. }
  551. b = (State *) tl_emalloc(sizeof(State));
  552. b->name = tl_lookup(from);
  553. b->colors = col;
  554. b->trans = t;
  555. if (!strncmp(from, "accept", 6))
  556. b->accepting = 1;
  557. b->nxt = never;
  558. never = b;
  559. }
  560. static void
  561. clr_reach(void)
  562. { State *p;
  563. for (p = never; p; p = p->nxt)
  564. p->reachable = 0;
  565. hitsall = 0;
  566. }
  567. void
  568. fsm_print(void)
  569. { State *b; int cnt1, cnt2=0;
  570. extern void put_uform(void);
  571. if (tl_clutter) clutter();
  572. b = findstate("T0_init");
  573. if (Max_Red == 0)
  574. b->accepting = 1;
  575. mergestates(0);
  576. b = findstate("T0_init");
  577. fprintf(tl_out, "never { /* ");
  578. put_uform();
  579. fprintf(tl_out, " */\n");
  580. do {
  581. clr_reach();
  582. Dfs(b);
  583. cnt1 = mergetrans(1);
  584. cnt2 = mergestates(1);
  585. if (tl_verbose)
  586. printf("/* >>%d,%d<< */\n", cnt1, cnt2);
  587. } while (cnt2 > 0);
  588. #ifdef BUCKY
  589. buckyballs();
  590. clr_reach();
  591. Dfs(b);
  592. #endif
  593. if (Max_Red == 0)
  594. fprintf(tl_out, "accept_init:\n");
  595. if (!b && !never)
  596. { fprintf(tl_out, " 0 /* false */;\n");
  597. } else
  598. { printstate(b); /* init state must be first */
  599. for (b = never; b; b = b->nxt)
  600. printstate(b);
  601. }
  602. if (hitsall)
  603. fprintf(tl_out, "accept_all:\n skip\n");
  604. fprintf(tl_out, "}\n");
  605. }