pangen7.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  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. /***** spin: pangen7.c *****/
  10. /* Copyright (c) 1989-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. /* pangen7.c: Version 5.3.0 2010, synchronous product of never claims */
  19. #include <stdlib.h>
  20. #include "spin.h"
  21. #include "y.tab.h"
  22. #include <assert.h>
  23. #ifdef PC
  24. extern int unlink(const char *);
  25. #else
  26. #include <unistd.h>
  27. #endif
  28. extern ProcList *rdy;
  29. extern Element *Al_El;
  30. extern int nclaims, verbose, Strict;
  31. typedef struct Succ_List Succ_List;
  32. typedef struct SQueue SQueue;
  33. typedef struct OneState OneState;
  34. typedef struct State_Stack State_Stack;
  35. typedef struct Guard Guard;
  36. struct Succ_List {
  37. SQueue *s;
  38. Succ_List *nxt;
  39. };
  40. struct OneState {
  41. int *combo; /* the combination of claim states */
  42. Succ_List *succ; /* list of ptrs to immediate successor states */
  43. };
  44. struct SQueue {
  45. OneState state;
  46. SQueue *nxt;
  47. };
  48. struct State_Stack {
  49. int *n;
  50. State_Stack *nxt;
  51. };
  52. struct Guard {
  53. Lextok *t;
  54. Guard *nxt;
  55. };
  56. SQueue *sq, *sd, *render; /* states move from sq to sd to render to holding */
  57. SQueue *holding, *lasthold;
  58. State_Stack *dsts;
  59. int nst; /* max nr of states in claims */
  60. int *Ist; /* initial states */
  61. int *Nacc; /* number of accept states in claim */
  62. int *Nst; /* next states */
  63. int **reached; /* n claims x states */
  64. int unfolding; /* to make sure all accept states are reached */
  65. int is_accept; /* remember if the current state is accepting in any claim */
  66. int not_printing; /* set during explore_product */
  67. Element ****matrix; /* n x two-dimensional arrays state x state */
  68. Element **Selfs; /* self-loop states at end of claims */
  69. static void get_seq(int, Sequence *);
  70. static void set_el(int n, Element *e);
  71. static void gen_product(void);
  72. static void print_state_nm(char *, int *, char *);
  73. static SQueue *find_state(int *);
  74. static SQueue *retrieve_state(int *);
  75. static int
  76. same_state(int *a, int *b)
  77. { int i;
  78. for (i = 0; i < nclaims; i++)
  79. { if (a[i] != b[i])
  80. { return 0;
  81. } }
  82. return 1;
  83. }
  84. static int
  85. in_stack(SQueue *s, SQueue *in)
  86. { SQueue *q;
  87. for (q = in; q; q = q->nxt)
  88. { if (same_state(q->state.combo, s->state.combo))
  89. { return 1;
  90. } }
  91. return 0;
  92. }
  93. static void
  94. to_render(SQueue *s)
  95. { SQueue *a, *q, *last; /* find in sd/sq and move to render, if not already there */
  96. int n;
  97. for (n = 0; n < nclaims; n++)
  98. { reached[n][ s->state.combo[n] ] |= 2;
  99. }
  100. for (q = render; q; q = q->nxt)
  101. { if (same_state(q->state.combo, s->state.combo))
  102. { return;
  103. } }
  104. for (q = holding; q; q = q->nxt)
  105. { if (same_state(q->state.combo, s->state.combo))
  106. { return;
  107. } }
  108. a = sd;
  109. more:
  110. for (q = a, last = 0; q; last = q, q = q->nxt)
  111. { if (same_state(q->state.combo, s->state.combo))
  112. { if (!last)
  113. { if (a == sd)
  114. { sd = q->nxt;
  115. } else if (a == sq)
  116. { sq = q->nxt;
  117. } else
  118. { holding = q->nxt;
  119. }
  120. } else
  121. { last->nxt = q->nxt;
  122. }
  123. q->nxt = render;
  124. render = q;
  125. return;
  126. } }
  127. if (verbose)
  128. { print_state_nm("looking for: ", s->state.combo, "\n");
  129. }
  130. (void) find_state(s->state.combo); /* creates it in sq */
  131. if (a != sq)
  132. { a = sq;
  133. goto more;
  134. }
  135. fatal("cannot happen, to_render", 0);
  136. }
  137. static void
  138. wrap_text(char *pre, Lextok *t, char *post)
  139. {
  140. printf(pre);
  141. comment(stdout, t, 0);
  142. printf(post);
  143. }
  144. static State_Stack *
  145. push_dsts(int *n)
  146. { State_Stack *s;
  147. int i;
  148. for (s = dsts; s; s = s->nxt)
  149. { if (same_state(s->n, n))
  150. { if (verbose&64)
  151. { printf("\n");
  152. for (s = dsts; s; s = s->nxt)
  153. { print_state_nm("\t", s->n, "\n");
  154. }
  155. print_state_nm("\t", n, "\n");
  156. }
  157. return s;
  158. } }
  159. s = (State_Stack *) emalloc(sizeof(State_Stack));
  160. s->n = (int *) emalloc(nclaims * sizeof(int));
  161. for (i = 0; i < nclaims; i++)
  162. s->n[i] = n[i];
  163. s->nxt = dsts;
  164. dsts = s;
  165. return 0;
  166. }
  167. static void
  168. pop_dsts(void)
  169. {
  170. assert(dsts);
  171. dsts = dsts->nxt;
  172. }
  173. static void
  174. complete_transition(Succ_List *sl, Guard *g)
  175. { Guard *w;
  176. int cnt = 0;
  177. printf(" :: ");
  178. for (w = g; w; w = w->nxt)
  179. { if (w->t->ntyp == CONST
  180. && w->t->val == 1)
  181. { continue;
  182. } else if (w->t->ntyp == 'c'
  183. && w->t->lft->ntyp == CONST
  184. && w->t->lft->val == 1)
  185. { continue; /* 'true' */
  186. }
  187. if (cnt > 0)
  188. { printf(" && ");
  189. }
  190. wrap_text("", w->t, "");
  191. cnt++;
  192. }
  193. if (cnt == 0)
  194. { printf("true");
  195. }
  196. print_state_nm(" -> goto ", sl->s->state.combo, "");
  197. if (is_accept > 0)
  198. { printf("_U%d\n", (unfolding+1)%nclaims);
  199. } else
  200. { printf("_U%d\n", unfolding);
  201. }
  202. }
  203. static void
  204. state_body(OneState *s, Guard *guard)
  205. { Succ_List *sl;
  206. State_Stack *y;
  207. Guard *g;
  208. int i, once;
  209. for (sl = s->succ; sl; sl = sl->nxt)
  210. { once = 0;
  211. for (i = 0; i < nclaims; i++)
  212. { Element *e;
  213. e = matrix[i][s->combo[i]][sl->s->state.combo[i]];
  214. /* if one of the claims has a DO or IF move
  215. then pull its target state forward, once
  216. */
  217. if (!e
  218. || e->n->ntyp == NON_ATOMIC
  219. || e->n->ntyp == DO
  220. || e->n->ntyp == IF)
  221. { s = &(sl->s->state);
  222. y = push_dsts(s->combo);
  223. if (!y)
  224. { if (once++ == 0)
  225. { assert(s->succ);
  226. state_body(s, guard);
  227. }
  228. pop_dsts();
  229. } else if (!y->nxt) /* self-loop transition */
  230. { if (!not_printing) printf(" /* self-loop */\n");
  231. } else
  232. { /* non_fatal("loop in state body", 0); ** maybe ok */
  233. }
  234. continue;
  235. } else
  236. { g = (Guard *) emalloc(sizeof(Guard));
  237. g->t = e->n;
  238. g->nxt = guard;
  239. guard = g;
  240. } }
  241. if (guard && !once)
  242. { if (!not_printing) complete_transition(sl, guard);
  243. to_render(sl->s);
  244. } }
  245. }
  246. static struct X {
  247. char *s; int n;
  248. } spl[] = {
  249. {"end", 3 },
  250. {"accept", 6 },
  251. {0, 0 },
  252. };
  253. static int slcnt;
  254. extern Label *labtab;
  255. static ProcList *
  256. locate_claim(int n)
  257. { ProcList *p;
  258. int i;
  259. for (p = rdy, i = 0; p; p = p->nxt, i++) /* find claim name */
  260. { if (i == n)
  261. { break;
  262. } }
  263. assert(p && p->b == N_CLAIM);
  264. return p;
  265. }
  266. static void
  267. elim_lab(Element *e)
  268. { Label *l, *lst;
  269. for (l = labtab, lst = NULL; l; lst = l, l = l->nxt)
  270. { if (l->e == e)
  271. { if (lst)
  272. { lst->nxt = l->nxt;
  273. } else
  274. { labtab = l->nxt;
  275. }
  276. break;
  277. } }
  278. }
  279. static int
  280. claim_has_accept(ProcList *p)
  281. { Label *l;
  282. for (l = labtab; l; l = l->nxt)
  283. { if (strcmp(l->c->name, p->n->name) == 0
  284. && strncmp(l->s->name, "accept", 6) == 0)
  285. { return 1;
  286. } }
  287. return 0;
  288. }
  289. static void
  290. prune_accept(void)
  291. { int n;
  292. for (n = 0; n < nclaims; n++)
  293. { if ((reached[n][Selfs[n]->seqno] & 2) == 0)
  294. { if (verbose)
  295. { printf("claim %d: selfloop not reachable\n", n);
  296. }
  297. elim_lab(Selfs[n]);
  298. Nacc[n] = claim_has_accept(locate_claim(n));
  299. } }
  300. }
  301. static void
  302. mk_accepting(int n, Element *e)
  303. { ProcList *p;
  304. Label *l;
  305. int i;
  306. assert(!Selfs[n]);
  307. Selfs[n] = e;
  308. l = (Label *) emalloc(sizeof(Label));
  309. l->s = (Symbol *) emalloc(sizeof(Symbol));
  310. l->s->name = "accept00";
  311. l->c = (Symbol *) emalloc(sizeof(Symbol));
  312. l->uiid = 0; /* this is not in an inline */
  313. for (p = rdy, i = 0; p; p = p->nxt, i++) /* find claim name */
  314. { if (i == n)
  315. { l->c->name = p->n->name;
  316. break;
  317. } }
  318. assert(p && p->b == N_CLAIM);
  319. Nacc[n] = 1;
  320. l->e = e;
  321. l->nxt = labtab;
  322. labtab = l;
  323. }
  324. static void
  325. check_special(int *nrs)
  326. { ProcList *p;
  327. Label *l;
  328. int i, j, nmatches;
  329. int any_accepts = 0;
  330. for (i = 0; i < nclaims; i++)
  331. { any_accepts += Nacc[i];
  332. }
  333. is_accept = 0;
  334. for (j = 0; spl[j].n; j++) /* 2 special label prefixes */
  335. { nmatches = 0;
  336. for (p = rdy, i = 0; p; p = p->nxt, i++) /* check each claim */
  337. { if (p->b != N_CLAIM)
  338. { continue;
  339. }
  340. /* claim i in state nrs[i], type p->tn, name p->n->name
  341. * either the state has an accept label, or the claim has none,
  342. * so that all its states should be considered accepting
  343. * --- but only if other claims do have accept states!
  344. */
  345. if (Strict == 0 && j == 1 && Nacc[i] == 0 && any_accepts > 0)
  346. { if ((verbose&32) && i == unfolding)
  347. { printf(" /* claim %d pseudo-accept */\n", i);
  348. }
  349. goto is_accepting;
  350. }
  351. for (l = labtab; l; l = l->nxt) /* check its labels */
  352. { if (strcmp(l->c->name, p->n->name) == 0 /* right claim */
  353. && l->e->seqno == nrs[i] /* right state */
  354. && strncmp(l->s->name, spl[j].s, spl[j].n) == 0)
  355. { if (j == 1) /* accept state */
  356. { char buf[32];
  357. is_accepting: if (strchr(p->n->name, ':'))
  358. { sprintf(buf, "N%d", i);
  359. } else
  360. { strcpy(buf, p->n->name);
  361. }
  362. if (unfolding == 0 && i == 0)
  363. { if (!not_printing)
  364. printf("%s_%s_%d:\n", /* true accept */
  365. spl[j].s, buf, slcnt++);
  366. } else if (verbose&32)
  367. { if (!not_printing)
  368. printf("%s_%s%d:\n",
  369. buf, spl[j].s, slcnt++);
  370. }
  371. if (i == unfolding)
  372. { is_accept++; /* move to next unfolding */
  373. }
  374. } else
  375. { nmatches++;
  376. }
  377. break;
  378. } } }
  379. if (j == 0 && nmatches == nclaims) /* end-state */
  380. { if (!not_printing)
  381. { printf("%s%d:\n", spl[j].s, slcnt++);
  382. } } }
  383. }
  384. static int
  385. render_state(SQueue *q)
  386. {
  387. if (!q || !q->state.succ)
  388. { if (verbose&64)
  389. { printf(" no exit\n");
  390. }
  391. return 0;
  392. }
  393. check_special(q->state.combo); /* accept or end-state labels */
  394. dsts = (State_Stack *) 0;
  395. push_dsts(q->state.combo); /* to detect loops */
  396. if (!not_printing)
  397. { print_state_nm("", q->state.combo, ""); /* the name */
  398. printf("_U%d:\n\tdo\n", unfolding);
  399. }
  400. state_body(&(q->state), (Guard *) 0);
  401. if (!not_printing)
  402. { printf("\tod;\n");
  403. }
  404. pop_dsts();
  405. return 1;
  406. }
  407. static void
  408. explore_product(void)
  409. { SQueue *q;
  410. /* all states are in the sd queue */
  411. q = retrieve_state(Ist); /* retrieve from the sd q */
  412. q->nxt = render; /* put in render q */
  413. render = q;
  414. do {
  415. q = render;
  416. render = render->nxt;
  417. q->nxt = 0; /* remove from render q */
  418. if (verbose&64)
  419. { print_state_nm("explore: ", q->state.combo, "\n");
  420. }
  421. not_printing = 1;
  422. render_state(q); /* may add new states */
  423. not_printing = 0;
  424. if (lasthold)
  425. { lasthold->nxt = q;
  426. lasthold = q;
  427. } else
  428. { holding = lasthold = q;
  429. }
  430. } while (render);
  431. assert(!dsts);
  432. }
  433. static void
  434. print_product(void)
  435. { SQueue *q;
  436. int cnt;
  437. if (unfolding == 0)
  438. { printf("never Product {\n"); /* name expected by iSpin */
  439. q = find_state(Ist); /* should find it in the holding q */
  440. assert(q);
  441. q->nxt = holding; /* put it at the front */
  442. holding = q;
  443. }
  444. render = holding;
  445. holding = lasthold = 0;
  446. printf("/* ============= U%d ============= */\n", unfolding);
  447. cnt = 0;
  448. do {
  449. q = render;
  450. render = render->nxt;
  451. q->nxt = 0;
  452. if (verbose&64)
  453. { print_state_nm("print: ", q->state.combo, "\n");
  454. }
  455. cnt += render_state(q);
  456. if (lasthold)
  457. { lasthold->nxt = q;
  458. lasthold = q;
  459. } else
  460. { holding = lasthold = q;
  461. }
  462. } while (render);
  463. assert(!dsts);
  464. if (cnt == 0)
  465. { printf(" 0;\n");
  466. }
  467. if (unfolding == nclaims-1)
  468. { printf("}\n");
  469. }
  470. }
  471. static void
  472. prune_dead(void)
  473. { Succ_List *sl, *last;
  474. SQueue *q;
  475. int cnt;
  476. do { cnt = 0;
  477. for (q = sd; q; q = q->nxt)
  478. { /* if successor is deadend, remove it
  479. * unless it's a move to the end-state of the claim
  480. */
  481. last = (Succ_List *) 0;
  482. for (sl = q->state.succ; sl; last = sl, sl = sl->nxt)
  483. { if (!sl->s->state.succ) /* no successor */
  484. { if (!last)
  485. { q->state.succ = sl->nxt;
  486. } else
  487. { last->nxt = sl->nxt;
  488. }
  489. cnt++;
  490. } } }
  491. } while (cnt > 0);
  492. }
  493. static void
  494. print_raw(void)
  495. { int i, j, n;
  496. printf("#if 0\n");
  497. for (n = 0; n < nclaims; n++)
  498. { printf("C%d:\n", n);
  499. for (i = 0; i < nst; i++)
  500. { if (reached[n][i])
  501. for (j = 0; j < nst; j++)
  502. { if (matrix[n][i][j])
  503. { if (reached[n][i] & 2) printf("+");
  504. if (i == Ist[n]) printf("*");
  505. printf("\t%d", i);
  506. wrap_text(" -[", matrix[n][i][j]->n, "]->\t");
  507. printf("%d\n", j);
  508. } } } }
  509. printf("#endif\n\n");
  510. fflush(stdout);
  511. }
  512. void
  513. sync_product(void)
  514. { ProcList *p;
  515. Element *e;
  516. int n, i;
  517. if (nclaims <= 1) return;
  518. (void) unlink("pan.pre");
  519. Ist = (int *) emalloc(sizeof(int) * nclaims);
  520. Nacc = (int *) emalloc(sizeof(int) * nclaims);
  521. Nst = (int *) emalloc(sizeof(int) * nclaims);
  522. reached = (int **) emalloc(sizeof(int *) * nclaims);
  523. Selfs = (Element **) emalloc(sizeof(Element *) * nclaims);
  524. matrix = (Element ****) emalloc(sizeof(Element ***) * nclaims); /* claims */
  525. for (p = rdy, i = 0; p; p = p->nxt, i++)
  526. { if (p->b == N_CLAIM)
  527. { nst = max(p->s->maxel, nst);
  528. Nacc[i] = claim_has_accept(p);
  529. } }
  530. for (n = 0; n < nclaims; n++)
  531. { reached[n] = (int *) emalloc(sizeof(int) * nst);
  532. matrix[n] = (Element ***) emalloc(sizeof(Element **) * nst); /* rows */
  533. for (i = 0; i < nst; i++) /* cols */
  534. { matrix[n][i] = (Element **) emalloc(sizeof(Element *) * nst);
  535. } }
  536. for (e = Al_El; e; e = e->Nxt)
  537. { e->status &= ~DONE;
  538. }
  539. for (p = rdy, n=0; p; p = p->nxt, n++)
  540. { if (p->b == N_CLAIM)
  541. { /* fill in matrix[n] */
  542. e = p->s->frst;
  543. Ist[n] = huntele(e, e->status, -1)->seqno;
  544. reached[n][Ist[n]] = 1|2;
  545. get_seq(n, p->s);
  546. } }
  547. if (verbose) /* show only the input automata */
  548. { print_raw();
  549. }
  550. gen_product(); /* create product automaton */
  551. }
  552. static int
  553. nxt_trans(int n, int cs, int frst)
  554. { int j;
  555. for (j = frst; j < nst; j++)
  556. { if (reached[n][cs]
  557. && matrix[n][cs][j])
  558. { return j;
  559. } }
  560. return -1;
  561. }
  562. static void
  563. print_state_nm(char *p, int *s, char *a)
  564. { int i;
  565. printf("%sP", p);
  566. for (i = 0; i < nclaims; i++)
  567. { printf("_%d", s[i]);
  568. }
  569. printf("%s", a);
  570. }
  571. static void
  572. create_transition(OneState *s, SQueue *it)
  573. { int n, from, upto;
  574. int *F = s->combo;
  575. int *T = it->state.combo;
  576. Succ_List *sl;
  577. Lextok *t;
  578. if (verbose&64)
  579. { print_state_nm("", F, " ");
  580. print_state_nm("-> ", T, "\t");
  581. }
  582. /* check if any of the claims is blocked */
  583. /* which makes the state a dead-end */
  584. for (n = 0; n < nclaims; n++)
  585. { from = F[n];
  586. upto = T[n];
  587. t = matrix[n][from][upto]->n;
  588. if (verbose&64)
  589. { wrap_text("", t, " ");
  590. }
  591. if (t->ntyp == 'c'
  592. && t->lft->ntyp == CONST)
  593. { if (t->lft->val == 0) /* i.e., false */
  594. { goto done;
  595. } } }
  596. sl = (Succ_List *) emalloc(sizeof(Succ_List));
  597. sl->s = it;
  598. sl->nxt = s->succ;
  599. s->succ = sl;
  600. done:
  601. if (verbose&64)
  602. { printf("\n");
  603. }
  604. }
  605. static SQueue *
  606. find_state(int *cs)
  607. { SQueue *nq, *a = sq;
  608. int i;
  609. again: /* check in nq, sq, and then in the render q */
  610. for (nq = a; nq; nq = nq->nxt)
  611. { if (same_state(nq->state.combo, cs))
  612. { return nq; /* found */
  613. } }
  614. if (a == sq && sd)
  615. { a = sd;
  616. goto again; /* check the other stack too */
  617. } else if (a == sd && render)
  618. { a = render;
  619. goto again;
  620. }
  621. nq = (SQueue *) emalloc(sizeof(SQueue));
  622. nq->state.combo = (int *) emalloc(nclaims * sizeof(int));
  623. for (i = 0; i < nclaims; i++)
  624. { nq->state.combo[i] = cs[i];
  625. }
  626. nq->nxt = sq; /* add to sq stack */
  627. sq = nq;
  628. return nq;
  629. }
  630. static SQueue *
  631. retrieve_state(int *s)
  632. { SQueue *nq, *last = NULL;
  633. for (nq = sd; nq; last = nq, nq = nq->nxt)
  634. { if (same_state(nq->state.combo, s))
  635. { if (last)
  636. { last->nxt = nq->nxt;
  637. } else
  638. { sd = nq;
  639. }
  640. return nq; /* found */
  641. } }
  642. fatal("cannot happen: retrieve_state", 0);
  643. return (SQueue *) 0;
  644. }
  645. static void
  646. all_successors(int n, OneState *cur)
  647. { int i, j = 0;
  648. if (n >= nclaims)
  649. { create_transition(cur, find_state(Nst));
  650. } else
  651. { i = cur->combo[n];
  652. for (;;)
  653. { j = nxt_trans(n, i, j);
  654. if (j < 0) break;
  655. Nst[n] = j;
  656. all_successors(n+1, cur);
  657. j++;
  658. } }
  659. }
  660. static void
  661. gen_product(void)
  662. { OneState *cur_st;
  663. SQueue *q;
  664. find_state(Ist); /* create initial state */
  665. while (sq)
  666. { if (in_stack(sq, sd))
  667. { sq = sq->nxt;
  668. continue;
  669. }
  670. cur_st = &(sq->state);
  671. q = sq;
  672. sq = sq->nxt; /* delete from sq stack */
  673. q->nxt = sd; /* and move to done stack */
  674. sd = q;
  675. all_successors(0, cur_st);
  676. }
  677. /* all states are in the sd queue now */
  678. prune_dead();
  679. explore_product(); /* check if added accept-self-loops are reachable */
  680. prune_accept();
  681. if (verbose)
  682. { print_raw();
  683. }
  684. /* PM: merge states with identical successor lists */
  685. /* all outgoing transitions from accept-states
  686. from claim n in copy n connect to states in copy (n+1)%nclaims
  687. only accept states from claim 0 in copy 0 are true accept states
  688. in the product
  689. PM: what about claims that have no accept states (e.g., restrictions)
  690. */
  691. for (unfolding = 0; unfolding < nclaims; unfolding++)
  692. { print_product();
  693. }
  694. }
  695. static void
  696. t_record(int n, Element *e, Element *g)
  697. { int from = e->seqno, upto = g?g->seqno:0;
  698. assert(from >= 0 && from < nst);
  699. assert(upto >= 0 && upto < nst);
  700. matrix[n][from][upto] = e;
  701. reached[n][upto] |= 1;
  702. }
  703. static void
  704. get_sub(int n, Element *e)
  705. {
  706. if (e->n->ntyp == D_STEP
  707. || e->n->ntyp == ATOMIC)
  708. { fatal("atomic or d_step in never claim product", 0);
  709. }
  710. /* NON_ATOMIC */
  711. e->n->sl->this->last->nxt = e->nxt;
  712. get_seq(n, e->n->sl->this);
  713. t_record(n, e, e->n->sl->this->frst);
  714. }
  715. static void
  716. set_el(int n, Element *e)
  717. { Element *g;
  718. if (e->n->ntyp == '@') /* change to self-loop */
  719. { e->n->ntyp = CONST;
  720. e->n->val = 1; /* true */
  721. e->nxt = e;
  722. g = e;
  723. mk_accepting(n, e);
  724. } else
  725. if (e->n->ntyp == GOTO)
  726. { g = get_lab(e->n, 1);
  727. g = huntele(g, e->status, -1);
  728. } else if (e->nxt)
  729. { g = huntele(e->nxt, e->status, -1);
  730. } else
  731. { g = NULL;
  732. }
  733. t_record(n, e, g);
  734. }
  735. static void
  736. get_seq(int n, Sequence *s)
  737. { SeqList *h;
  738. Element *e;
  739. e = huntele(s->frst, s->frst->status, -1);
  740. for ( ; e; e = e->nxt)
  741. { if (e->status & DONE)
  742. { goto checklast;
  743. }
  744. e->status |= DONE;
  745. if (e->n->ntyp == UNLESS)
  746. { fatal("unless stmnt in never claim product", 0);
  747. }
  748. if (e->sub) /* IF or DO */
  749. { Lextok *x = NULL;
  750. Lextok *y = NULL;
  751. Lextok *haselse = NULL;
  752. for (h = e->sub; h; h = h->nxt)
  753. { Lextok *t = h->this->frst->n;
  754. if (t->ntyp == ELSE)
  755. { if (verbose&64) printf("else at line %d\n", t->ln);
  756. haselse = t;
  757. continue;
  758. }
  759. if (t->ntyp != 'c')
  760. { fatal("product, 'else' combined with non-condition", 0);
  761. }
  762. if (t->lft->ntyp == CONST /* true */
  763. && t->lft->val == 1
  764. && y == NULL)
  765. { y = nn(ZN, CONST, ZN, ZN);
  766. y->val = 0;
  767. } else
  768. { if (!x)
  769. x = t;
  770. else
  771. x = nn(ZN, OR, x, t);
  772. if (verbose&64)
  773. { wrap_text(" [", x, "]\n");
  774. } } }
  775. if (haselse)
  776. { if (!y)
  777. { y = nn(ZN, '!', x, ZN);
  778. }
  779. if (verbose&64)
  780. { wrap_text(" [else: ", y, "]\n");
  781. }
  782. haselse->ntyp = 'c'; /* replace else */
  783. haselse->lft = y;
  784. }
  785. for (h = e->sub; h; h = h->nxt)
  786. { t_record(n, e, h->this->frst);
  787. get_seq(n, h->this);
  788. }
  789. } else
  790. { if (e->n->ntyp == ATOMIC
  791. || e->n->ntyp == D_STEP
  792. || e->n->ntyp == NON_ATOMIC)
  793. { get_sub(n, e);
  794. } else
  795. { set_el(n, e);
  796. }
  797. }
  798. checklast: if (e == s->last)
  799. break;
  800. }
  801. }