tl_buchi.c 13 KB

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