--- /dev/null
+/***** spin: pangen4.c *****/
+
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */
+/* All Rights Reserved. This software is for educational purposes only. */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code. Permission is given to distribute this code provided that */
+/* this introductory message is not removed and no monies are exchanged. */
+/* Software written by Gerard J. Holzmann. For tool documentation see: */
+/* http://spinroot.com/ */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com */
+
+#include "spin.h"
+#include "y.tab.h"
+
+extern FILE *tc, *tb;
+extern Queue *qtab;
+extern Symbol *Fname;
+extern int lineno, m_loss, Pid, eventmapnr, multi_oval;
+extern short nocast, has_provided, has_sorted;
+extern char *R13[], *R14[], *R15[];
+
+static void check_proc(Lextok *, int);
+
+void
+undostmnt(Lextok *now, int m)
+{ Lextok *v;
+ int i, j;
+
+ if (!now)
+ { fprintf(tb, "0");
+ return;
+ }
+ lineno = now->ln;
+ Fname = now->fn;
+ switch (now->ntyp) {
+ case CONST: case '!': case UMIN:
+ case '~': case '/': case '*':
+ case '-': case '+': case '%':
+ case LT: case GT: case '&':
+ case '|': case LE: case GE:
+ case NE: case EQ: case OR:
+ case AND: case LSHIFT: case RSHIFT:
+ case TIMEOUT: case LEN: case NAME:
+ case FULL: case EMPTY: case 'R':
+ case NFULL: case NEMPTY: case ENABLED:
+ case '?': case PC_VAL: case '^':
+ case C_EXPR:
+ case NONPROGRESS:
+ putstmnt(tb, now, m);
+ break;
+
+ case RUN:
+ fprintf(tb, "delproc(0, now._nr_pr-1)");
+ break;
+
+ case 's':
+ if (Pid == eventmapnr) break;
+
+ if (m_loss)
+ fprintf(tb, "if (_m == 2) ");
+ putname(tb, "_m = unsend(", now->lft, m, ")");
+ break;
+
+ case 'r':
+ if (Pid == eventmapnr) break;
+
+ for (v = now->rgt, i=j=0; v; v = v->rgt, i++)
+ if (v->lft->ntyp != CONST
+ && v->lft->ntyp != EVAL)
+ j++;
+ if (j == 0 && now->val >= 2)
+ break; /* poll without side-effect */
+
+ { int ii = 0, jj;
+
+ for (v = now->rgt; v; v = v->rgt)
+ if ((v->lft->ntyp != CONST
+ && v->lft->ntyp != EVAL))
+ ii++; /* nr of things bupped */
+ if (now->val == 1)
+ { ii++;
+ jj = multi_oval - ii - 1;
+ fprintf(tb, "XX = trpt->bup.oval");
+ if (multi_oval > 0)
+ { fprintf(tb, "s[%d]", jj);
+ jj++;
+ }
+ fprintf(tb, ";\n\t\t");
+ } else
+ { fprintf(tb, "XX = 1;\n\t\t");
+ jj = multi_oval - ii - 1;
+ }
+
+ if (now->val < 2) /* not for channel poll */
+ for (v = now->rgt, i = 0; v; v = v->rgt, i++)
+ { switch(v->lft->ntyp) {
+ case CONST:
+ case EVAL:
+ fprintf(tb, "unrecv");
+ putname(tb, "(", now->lft, m, ", XX-1, ");
+ fprintf(tb, "%d, ", i);
+ if (v->lft->ntyp == EVAL)
+ undostmnt(v->lft->lft, m);
+ else
+ undostmnt(v->lft, m);
+ fprintf(tb, ", %d);\n\t\t", (i==0)?1:0);
+ break;
+ default:
+ fprintf(tb, "unrecv");
+ putname(tb, "(", now->lft, m, ", XX-1, ");
+ fprintf(tb, "%d, ", i);
+ if (v->lft->sym
+ && !strcmp(v->lft->sym->name, "_"))
+ { fprintf(tb, "trpt->bup.oval");
+ if (multi_oval > 0)
+ fprintf(tb, "s[%d]", jj);
+ } else
+ putstmnt(tb, v->lft, m);
+
+ fprintf(tb, ", %d);\n\t\t", (i==0)?1:0);
+ if (multi_oval > 0)
+ jj++;
+ break;
+ } }
+ jj = multi_oval - ii - 1;
+
+ if (now->val == 1 && multi_oval > 0)
+ jj++; /* new 3.4.0 */
+
+ for (v = now->rgt, i = 0; v; v = v->rgt, i++)
+ { switch(v->lft->ntyp) {
+ case CONST:
+ case EVAL:
+ break;
+ default:
+ if (!v->lft->sym
+ || strcmp(v->lft->sym->name, "_") != 0)
+ { nocast=1; putstmnt(tb,v->lft,m);
+ nocast=0; fprintf(tb, " = trpt->bup.oval");
+ if (multi_oval > 0)
+ fprintf(tb, "s[%d]", jj);
+ fprintf(tb, ";\n\t\t");
+ }
+ if (multi_oval > 0)
+ jj++;
+ break;
+ } }
+ multi_oval -= ii;
+ }
+ break;
+
+ case '@':
+ fprintf(tb, "p_restor(II);\n\t\t");
+ break;
+
+ case ASGN:
+ nocast=1; putstmnt(tb,now->lft,m);
+ nocast=0; fprintf(tb, " = trpt->bup.oval");
+ if (multi_oval > 0)
+ { multi_oval--;
+ fprintf(tb, "s[%d]", multi_oval-1);
+ }
+ check_proc(now->rgt, m);
+ break;
+
+ case 'c':
+ check_proc(now->lft, m);
+ break;
+
+ case '.':
+ case GOTO:
+ case ELSE:
+ case BREAK:
+ break;
+
+ case C_CODE:
+ fprintf(tb, "sv_restor();\n");
+ break;
+
+ case ASSERT:
+ case PRINT:
+ check_proc(now, m);
+ break;
+ case PRINTM:
+ break;
+
+ default:
+ printf("spin: bad node type %d (.b)\n", now->ntyp);
+ alldone(1);
+ }
+}
+
+int
+any_undo(Lextok *now)
+{ /* is there anything to undo on a return move? */
+ if (!now) return 1;
+ switch (now->ntyp) {
+ case 'c': return any_oper(now->lft, RUN);
+ case ASSERT:
+ case PRINT: return any_oper(now, RUN);
+
+ case PRINTM:
+ case '.':
+ case GOTO:
+ case ELSE:
+ case BREAK: return 0;
+ default: return 1;
+ }
+}
+
+int
+any_oper(Lextok *now, int oper)
+{ /* check if an expression contains oper operator */
+ if (!now) return 0;
+ if (now->ntyp == oper)
+ return 1;
+ return (any_oper(now->lft, oper) || any_oper(now->rgt, oper));
+}
+
+static void
+check_proc(Lextok *now, int m)
+{
+ if (!now)
+ return;
+ if (now->ntyp == '@' || now->ntyp == RUN)
+ { fprintf(tb, ";\n\t\t");
+ undostmnt(now, m);
+ }
+ check_proc(now->lft, m);
+ check_proc(now->rgt, m);
+}
+
+void
+genunio(void)
+{ char buf1[256];
+ Queue *q; int i;
+
+ ntimes(tc, 0, 1, R13);
+ for (q = qtab; q; q = q->nxt)
+ { fprintf(tc, "\tcase %d:\n", q->qid);
+
+ if (has_sorted)
+ { sprintf(buf1, "((Q%d *)z)->contents", q->qid);
+ fprintf(tc, "#ifdef HAS_SORTED\n");
+ fprintf(tc, "\t\tj = trpt->ipt;\n"); /* ipt was bup.oval */
+ fprintf(tc, "#endif\n");
+ fprintf(tc, "\t\tfor (k = j; k < ((Q%d *)z)->Qlen; k++)\n",
+ q->qid);
+ fprintf(tc, "\t\t{\n");
+ for (i = 0; i < q->nflds; i++)
+ fprintf(tc, "\t\t\t%s[k].fld%d = %s[k+1].fld%d;\n",
+ buf1, i, buf1, i);
+ fprintf(tc, "\t\t}\n");
+ fprintf(tc, "\t\tj = ((Q0 *)z)->Qlen;\n");
+ }
+
+ sprintf(buf1, "((Q%d *)z)->contents[j].fld", q->qid);
+ for (i = 0; i < q->nflds; i++)
+ fprintf(tc, "\t\t%s%d = 0;\n", buf1, i);
+ if (q->nslots==0)
+ { /* check if rendezvous succeeded, 1 level down */
+ fprintf(tc, "\t\t_m = (trpt+1)->o_m;\n");
+ fprintf(tc, "\t\tif (_m) (trpt-1)->o_pm |= 1;\n");
+ fprintf(tc, "\t\tUnBlock;\n");
+ } else
+ fprintf(tc, "\t\t_m = trpt->o_m;\n");
+
+ fprintf(tc, "\t\tbreak;\n");
+ }
+ ntimes(tc, 0, 1, R14);
+ for (q = qtab; q; q = q->nxt)
+ { sprintf(buf1, "((Q%d *)z)->contents", q->qid);
+ fprintf(tc, " case %d:\n", q->qid);
+ if (q->nslots == 0)
+ fprintf(tc, "\t\tif (strt) boq = from+1;\n");
+ else if (q->nslots > 1) /* shift */
+ { fprintf(tc, "\t\tif (strt && slot<%d)\n",
+ q->nslots-1);
+ fprintf(tc, "\t\t{\tfor (j--; j>=slot; j--)\n");
+ fprintf(tc, "\t\t\t{");
+ for (i = 0; i < q->nflds; i++)
+ { fprintf(tc, "\t%s[j+1].fld%d =\n\t\t\t",
+ buf1, i);
+ fprintf(tc, "\t%s[j].fld%d;\n\t\t\t",
+ buf1, i);
+ }
+ fprintf(tc, "}\n\t\t}\n");
+ }
+ strcat(buf1, "[slot].fld");
+ fprintf(tc, "\t\tif (strt) {\n");
+ for (i = 0; i < q->nflds; i++)
+ fprintf(tc, "\t\t\t%s%d = 0;\n", buf1, i);
+ fprintf(tc, "\t\t}\n");
+ if (q->nflds == 1) /* set */
+ fprintf(tc, "\t\tif (fld == 0) %s0 = fldvar;\n",
+ buf1);
+ else
+ { fprintf(tc, "\t\tswitch (fld) {\n");
+ for (i = 0; i < q->nflds; i++)
+ { fprintf(tc, "\t\tcase %d:\t%s", i, buf1);
+ fprintf(tc, "%d = fldvar; break;\n", i);
+ }
+ fprintf(tc, "\t\t}\n");
+ }
+ fprintf(tc, "\t\tbreak;\n");
+ }
+ ntimes(tc, 0, 1, R15);
+}
+
+extern void explain(int);
+
+int
+proper_enabler(Lextok *n)
+{
+ if (!n) return 1;
+ switch (n->ntyp) {
+ case NEMPTY: case FULL:
+ case NFULL: case EMPTY:
+ case LEN: case 'R':
+ case NAME:
+ has_provided = 1;
+ if (strcmp(n->sym->name, "_pid") == 0)
+ return 1;
+ return (!(n->sym->context));
+
+ case C_EXPR:
+ case CONST:
+ case TIMEOUT:
+ has_provided = 1;
+ return 1;
+
+ case ENABLED: case PC_VAL:
+ return proper_enabler(n->lft);
+
+ case '!': case UMIN: case '~':
+ return proper_enabler(n->lft);
+
+ case '/': case '*': case '-': case '+':
+ case '%': case LT: case GT: case '&': case '^':
+ case '|': case LE: case GE: case NE: case '?':
+ case EQ: case OR: case AND: case LSHIFT:
+ case RSHIFT: case 'c':
+ return proper_enabler(n->lft) && proper_enabler(n->rgt);
+ default:
+ break;
+ }
+ printf("spin: saw ");
+ explain(n->ntyp);
+ printf("\n");
+ return 0;
+}