tl_buchi.c 13 KB

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