1 /***** spin: pangen7.c *****/
4 * This file is part of the public release of Spin. It is subject to the
5 * terms in the LICENSE file that is included in this source directory.
6 * Tool documentation is available at http://spinroot.com
19 extern Element *Al_El;
20 extern int nclaims, verbose, Strict;
21 extern short has_accept;
23 typedef struct Succ_List Succ_List;
24 typedef struct SQueue SQueue;
25 typedef struct OneState OneState;
26 typedef struct State_Stack State_Stack;
27 typedef struct Guard Guard;
35 int *combo; /* the combination of claim states */
36 Succ_List *succ; /* list of ptrs to immediate successor states */
54 static SQueue *sq, *sd, *render; /* states move from sq to sd to render to holding */
55 static SQueue *holding, *lasthold;
56 static State_Stack *dsts;
58 static int nst; /* max nr of states in claims */
59 static int *Ist; /* initial states */
60 static int *Nacc; /* number of accept states in claim */
61 static int *Nst; /* next states */
62 static int **reached; /* n claims x states */
63 static int unfolding; /* to make sure all accept states are reached */
64 static int is_accept; /* remember if the current state is accepting in any claim */
65 static int not_printing; /* set during explore_product */
67 static Element ****matrix; /* n x two-dimensional arrays state x state */
68 static Element **Selfs; /* self-loop states at end of claims */
70 static void get_seq(int, Sequence *);
71 static void set_el(int n, Element *e);
72 static void gen_product(void);
73 static void print_state_nm(char *, int *, char *);
74 static SQueue *find_state(int *);
75 static SQueue *retrieve_state(int *);
78 same_state(int *a, int *b)
81 for (i = 0; i < nclaims; i++)
89 in_stack(SQueue *s, SQueue *in)
92 for (q = in; q; q = q->nxt)
93 { if (same_state(q->state.combo, s->state.combo))
101 { SQueue *a, *q, *last; /* find in sd/sq and move to render, if not already there */
104 for (n = 0; n < nclaims; n++)
105 { reached[n][ s->state.combo[n] ] |= 2;
108 for (q = render; q; q = q->nxt)
109 { if (same_state(q->state.combo, s->state.combo))
112 for (q = holding; q; q = q->nxt)
113 { if (same_state(q->state.combo, s->state.combo))
119 for (q = a, last = 0; q; last = q, q = q->nxt)
120 { if (same_state(q->state.combo, s->state.combo))
130 { last->nxt = q->nxt;
137 { print_state_nm("looking for: ", s->state.combo, "\n");
139 (void) find_state(s->state.combo); /* creates it in sq */
144 fatal("cannot happen, to_render", 0);
148 wrap_text(char *pre, Lextok *t, char *post)
150 printf(pre, (char *) 0);
151 comment(stdout, t, 0);
152 printf(post, (char *) 0);
160 for (s = dsts; s; s = s->nxt)
161 { if (same_state(s->n, n))
164 for (s = dsts; s; s = s->nxt)
165 { print_state_nm("\t", s->n, "\n");
167 print_state_nm("\t", n, "\n");
172 s = (State_Stack *) emalloc(sizeof(State_Stack));
173 s->n = (int *) emalloc(nclaims * sizeof(int));
174 for (i = 0; i < nclaims; i++)
184 assert(dsts != NULL);
189 complete_transition(Succ_List *sl, Guard *g)
194 for (w = g; w; w = w->nxt)
195 { if (w->t->ntyp == CONST
198 } else if (w->t->ntyp == 'c'
199 && w->t->lft->ntyp == CONST
200 && w->t->lft->val == 1)
201 { continue; /* 'true' */
207 wrap_text("", w->t, "");
213 print_state_nm(" -> goto ", sl->s->state.combo, "");
216 { printf("_U%d\n", (unfolding+1)%nclaims);
218 { printf("_U%d\n", unfolding);
223 state_body(OneState *s, Guard *guard)
229 for (sl = s->succ; sl; sl = sl->nxt)
232 for (i = 0; i < nclaims; i++)
234 e = matrix[i][s->combo[i]][sl->s->state.combo[i]];
236 /* if one of the claims has a DO or IF move
237 then pull its target state forward, once
241 || e->n->ntyp == NON_ATOMIC
244 { s = &(sl->s->state);
245 y = push_dsts(s->combo);
248 { assert(s->succ != NULL);
249 state_body(s, guard);
252 } else if (!y->nxt) /* self-loop transition */
253 { if (!not_printing) printf(" /* self-loop */\n");
255 { /* non_fatal("loop in state body", 0); ** maybe ok */
259 { g = (Guard *) emalloc(sizeof(Guard));
266 { if (!not_printing) complete_transition(sl, guard);
280 extern Label *labtab;
287 for (p = rdy, i = 0; p; p = p->nxt, i++) /* find claim name */
291 assert(p && p->b == N_CLAIM);
300 for (l = labtab, lst = NULL; l; lst = l, l = l->nxt)
312 claim_has_accept(ProcList *p)
315 for (l = labtab; l; l = l->nxt)
316 { if (strcmp(l->c->name, p->n->name) == 0
317 && strncmp(l->s->name, "accept", 6) == 0)
327 for (n = 0; n < nclaims; n++)
328 { if ((reached[n][Selfs[n]->seqno] & 2) == 0)
330 { printf("claim %d: selfloop not reachable\n", n);
333 Nacc[n] = claim_has_accept(locate_claim(n));
338 mk_accepting(int n, Element *e)
346 l = (Label *) emalloc(sizeof(Label));
347 l->s = (Symbol *) emalloc(sizeof(Symbol));
348 l->s->name = "accept00";
349 l->c = (Symbol *) emalloc(sizeof(Symbol));
350 l->uiid = 0; /* this is not in an inline */
352 for (p = rdy, i = 0; p; p = p->nxt, i++) /* find claim name */
354 { l->c->name = p->n->name;
357 assert(p && p->b == N_CLAIM);
367 check_special(int *nrs)
373 for (i = 0; i < nclaims; i++)
374 { any_accepts += Nacc[i];
378 for (j = 0; spl[j].n; j++) /* 2 special label prefixes */
380 for (p = rdy, i = 0; p; p = p->nxt, i++) /* check each claim */
381 { if (p->b != N_CLAIM)
384 /* claim i in state nrs[i], type p->tn, name p->n->name
385 * either the state has an accept label, or the claim has none,
386 * so that all its states should be considered accepting
387 * --- but only if other claims do have accept states!
389 if (Strict == 0 && j == 1 && Nacc[i] == 0 && any_accepts > 0)
390 { if ((verbose&32) && i == unfolding)
391 { printf(" /* claim %d pseudo-accept */\n", i);
395 for (l = labtab; l; l = l->nxt) /* check its labels */
396 { if (strcmp(l->c->name, p->n->name) == 0 /* right claim */
397 && l->e->seqno == nrs[i] /* right state */
398 && strncmp(l->s->name, spl[j].s, spl[j].n) == 0)
399 { if (j == 1) /* accept state */
401 is_accepting: if (strchr(p->n->name, ':'))
402 { sprintf(buf, "N%d", i);
404 { assert(strlen(p->n->name) < sizeof(buf));
405 strcpy(buf, p->n->name);
407 if (unfolding == 0 && i == 0)
409 printf("%s_%s_%d:\n", /* true accept */
410 spl[j].s, buf, slcnt++);
411 } else if (verbose&32)
414 buf, spl[j].s, slcnt++);
417 { is_accept++; /* move to next unfolding */
424 if (j == 0 && nmatches == nclaims) /* end-state */
426 { printf("%s%d:\n", spl[j].s, slcnt++);
431 render_state(SQueue *q)
433 if (!q || !q->state.succ)
435 { printf(" no exit\n");
440 check_special(q->state.combo); /* accept or end-state labels */
442 dsts = (State_Stack *) 0;
443 push_dsts(q->state.combo); /* to detect loops */
446 { print_state_nm("", q->state.combo, ""); /* the name */
447 printf("_U%d:\n\tdo\n", unfolding);
450 state_body(&(q->state), (Guard *) 0);
460 explore_product(void)
463 /* all states are in the sd queue */
465 q = retrieve_state(Ist); /* retrieve from the sd q */
466 q->nxt = render; /* put in render q */
470 render = render->nxt;
471 q->nxt = 0; /* remove from render q */
474 { print_state_nm("explore: ", q->state.combo, "\n");
478 render_state(q); /* may add new states */
485 { holding = lasthold = q;
498 { printf("never Product {\n"); /* name expected by iSpin */
499 q = find_state(Ist); /* should find it in the holding q */
501 q->nxt = holding; /* put it at the front */
505 holding = lasthold = 0;
507 printf("/* ============= U%d ============= */\n", unfolding);
511 render = render->nxt;
514 { print_state_nm("print: ", q->state.combo, "\n");
516 cnt += render_state(q);
522 { holding = lasthold = q;
531 if (unfolding == nclaims-1)
538 { Succ_List *sl, *last;
543 for (q = sd; q; q = q->nxt)
544 { /* if successor is deadend, remove it
545 * unless it's a move to the end-state of the claim
547 last = (Succ_List *) 0;
548 for (sl = q->state.succ; sl; last = sl, sl = sl->nxt)
549 { if (!sl->s->state.succ) /* no successor */
551 { q->state.succ = sl->nxt;
553 { last->nxt = sl->nxt;
565 for (n = 0; n < nclaims; n++)
566 { printf("C%d:\n", n);
567 for (i = 0; i < nst; i++)
569 for (j = 0; j < nst; j++)
570 { if (matrix[n][i][j])
571 { if (reached[n][i] & 2) printf("+");
572 if (i == Ist[n]) printf("*");
574 wrap_text(" -[", matrix[n][i][j]->n, "]->\t");
577 printf("#endif\n\n");
587 if (nclaims <= 1) return;
589 (void) unlink("pan.pre");
591 Ist = (int *) emalloc(sizeof(int) * nclaims);
592 Nacc = (int *) emalloc(sizeof(int) * nclaims);
593 Nst = (int *) emalloc(sizeof(int) * nclaims);
594 reached = (int **) emalloc(sizeof(int *) * nclaims);
595 Selfs = (Element **) emalloc(sizeof(Element *) * nclaims);
596 matrix = (Element ****) emalloc(sizeof(Element ***) * nclaims); /* claims */
598 for (p = rdy, i = 0; p; p = p->nxt, i++)
599 { if (p->b == N_CLAIM)
600 { nst = max(p->s->maxel, nst);
601 Nacc[i] = claim_has_accept(p);
604 for (n = 0; n < nclaims; n++)
605 { reached[n] = (int *) emalloc(sizeof(int) * nst);
606 matrix[n] = (Element ***) emalloc(sizeof(Element **) * nst); /* rows */
607 for (i = 0; i < nst; i++) /* cols */
608 { matrix[n][i] = (Element **) emalloc(sizeof(Element *) * nst);
611 for (e = Al_El; e; e = e->Nxt)
612 { e->status &= ~DONE;
615 for (p = rdy, n=0; p; p = p->nxt, n++)
616 { if (p->b == N_CLAIM)
617 { /* fill in matrix[n] */
619 Ist[n] = huntele(e, e->status, -1)->seqno;
621 reached[n][Ist[n]] = 1|2;
625 if (verbose) /* show only the input automata */
629 gen_product(); /* create product automaton */
633 nxt_trans(int n, int cs, int frst)
636 for (j = frst; j < nst; j++)
645 print_state_nm(char *p, int *s, char *a)
648 for (i = 0; i < nclaims; i++)
649 { printf("_%d", s[i]);
655 create_transition(OneState *s, SQueue *it)
658 int *T = it->state.combo;
663 { print_state_nm("", F, " ");
664 print_state_nm("-> ", T, "\t");
667 /* check if any of the claims is blocked */
668 /* which makes the state a dead-end */
669 for (n = 0; n < nclaims; n++)
672 t = matrix[n][from][upto]->n;
674 { wrap_text("", t, " ");
677 && t->lft->ntyp == CONST)
678 { if (t->lft->val == 0) /* i.e., false */
682 sl = (Succ_List *) emalloc(sizeof(Succ_List));
694 { SQueue *nq, *a = sq;
697 again: /* check in nq, sq, and then in the render q */
698 for (nq = a; nq; nq = nq->nxt)
699 { if (same_state(nq->state.combo, cs))
700 { return nq; /* found */
704 goto again; /* check the other stack too */
705 } else if (a == sd && render)
710 nq = (SQueue *) emalloc(sizeof(SQueue));
711 nq->state.combo = (int *) emalloc(nclaims * sizeof(int));
712 for (i = 0; i < nclaims; i++)
713 { nq->state.combo[i] = cs[i];
715 nq->nxt = sq; /* add to sq stack */
722 retrieve_state(int *s)
723 { SQueue *nq, *last = NULL;
725 for (nq = sd; nq; last = nq, nq = nq->nxt)
726 { if (same_state(nq->state.combo, s))
728 { last->nxt = nq->nxt;
730 { sd = nq->nxt; /* 6.4.0: was sd = nq */
732 return nq; /* found */
735 fatal("cannot happen: retrieve_state", 0);
740 all_successors(int n, OneState *cur)
744 { create_transition(cur, find_state(Nst));
748 { j = nxt_trans(n, i, j);
751 all_successors(n+1, cur);
761 find_state(Ist); /* create initial state */
764 { if (in_stack(sq, sd))
768 cur_st = &(sq->state);
771 sq = sq->nxt; /* delete from sq stack */
772 q->nxt = sd; /* and move to done stack */
775 all_successors(0, cur_st);
777 /* all states are in the sd queue now */
779 explore_product(); /* check if added accept-self-loops are reachable */
786 /* PM: merge states with identical successor lists */
788 /* all outgoing transitions from accept-states
789 from claim n in copy n connect to states in copy (n+1)%nclaims
790 only accept states from claim 0 in copy 0 are true accept states
793 PM: what about claims that have no accept states (e.g., restrictions)
796 for (unfolding = 0; unfolding < nclaims; unfolding++)
802 t_record(int n, Element *e, Element *g)
803 { int from = e->seqno, upto = g?g->seqno:0;
805 assert(from >= 0 && from < nst);
806 assert(upto >= 0 && upto < nst);
808 matrix[n][from][upto] = e;
809 reached[n][upto] |= 1;
813 get_sub(int n, Element *e)
815 if (e->n->ntyp == D_STEP
816 || e->n->ntyp == ATOMIC)
817 { fatal("atomic or d_step in never claim product", 0);
820 e->n->sl->this->last->nxt = e->nxt;
821 get_seq(n, e->n->sl->this);
823 t_record(n, e, e->n->sl->this->frst);
828 set_el(int n, Element *e)
831 if (e->n->ntyp == '@') /* change to self-loop */
832 { e->n->ntyp = CONST;
833 e->n->val = 1; /* true */
839 if (e->n->ntyp == GOTO)
840 { g = get_lab(e->n, 1);
841 g = huntele(g, e->status, -1);
843 { g = huntele(e->nxt, e->status, -1);
852 get_seq(int n, Sequence *s)
856 e = huntele(s->frst, s->frst->status, -1);
857 for ( ; e; e = e->nxt)
858 { if (e->status & DONE)
863 if (e->n->ntyp == UNLESS)
864 { fatal("unless stmnt in never claim product", 0);
867 if (e->sub) /* IF or DO */
870 Lextok *haselse = NULL;
872 for (h = e->sub; h; h = h->nxt)
873 { Lextok *t = h->this->frst->n;
875 { if (verbose&64) printf("else at line %d\n", t->ln);
880 { fatal("product, 'else' combined with non-condition", 0);
883 if (t->lft->ntyp == CONST /* true */
886 { y = nn(ZN, CONST, ZN, ZN);
892 x = nn(ZN, OR, x, t);
894 { wrap_text(" [", x, "]\n");
898 { y = nn(ZN, '!', x, ZN);
901 { wrap_text(" [else: ", y, "]\n");
903 haselse->ntyp = 'c'; /* replace else */
907 for (h = e->sub; h; h = h->nxt)
908 { t_record(n, e, h->this->frst);
912 { if (e->n->ntyp == ATOMIC
913 || e->n->ntyp == D_STEP
914 || e->n->ntyp == NON_ATOMIC)
920 checklast: if (e == s->last)