spin: Update to most recent version. (thanks Ori_B)

from Ori_B:

There were a small number of changes needed from the tarball
on spinroot.org:

  - The mkfile needed to be updated
  - Memory.h needed to not be included
  - It needed to invoke /bin/cpp instead of gcc -E
  - It depended on `yychar`, which our yacc doesn't
    provide.

I'm still figuring out how to use spin, but it seems to do
the right thing when testing a few of the examples:

	% cd $home/src/Spin/Examples/
	% spin -a peterson.pml
	% pcc pan.c -D_POSIX_SOURCE
	% ./6.out

	(Spin Version 6.4.7 -- 19 August 2017)
		+ Partial Order Reduction

	Full statespace search for:
		never claim         	- (none specified)
		assertion violations	+
		acceptance   cycles 	- (not selected)
		invalid end states	+

	State-vector 32 byte, depth reached 24, errors: 0
	40 states, stored
	27 states, matched
	67 transitions (= stored+matched)
		0 atomic steps
	hash conflicts:         0 (resolved)

	Stats on memory usage (in Megabytes):
	0.002	equivalent memory usage for states (stored*(State-vector + overhead))
	0.292	actual memory usage for states
	128.000	memory used for hash table (-w24)
	0.534	memory used for DFS stack (-m10000)
	128.730	total actual memory usage


	unreached in proctype user
		/tmp/Spin/Examples/peterson.pml:20, state 10, "-end-"
		(1 of 10 states)

	pan: elapsed time 1.25 seconds
	pan: rate        32 states/second
This commit is contained in:
cinap_lenrek 2017-11-22 21:09:31 +01:00
parent 077e719dfb
commit 28e9566dc5
40 changed files with 19245 additions and 3936 deletions

View file

@ -1,27 +1,25 @@
/***** spin: dstep.c *****/ /***** spin: dstep.c *****/
/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 <assert.h>
#include "spin.h" #include "spin.h"
#include "y.tab.h" #include "y.tab.h"
#define MAXDSTEP 1024 /* was 512 */ #define MAXDSTEP 2048 /* was 512 */
char *NextLab[64]; char *NextLab[64]; /* must match value in pangen2.c:41 */
int Level=0, GenCode=0, IsGuard=0, TestOnly=0; int Level=0, GenCode=0, IsGuard=0, TestOnly=0;
static int Tj=0, Jt=0, LastGoto=0; static int Tj=0, Jt=0, LastGoto=0;
static int Tojump[MAXDSTEP], Jumpto[MAXDSTEP], Special[MAXDSTEP]; static int Tojump[MAXDSTEP], Jumpto[MAXDSTEP], Special[MAXDSTEP];
static void putCode(FILE *, Element *, Element *, Element *, int); static void putCode(FILE *, Element *, Element *, Element *, int);
extern int Pid, claimnr, separate, OkBreak; extern int Pid, separate, OkBreak;
static void static void
Sourced(int n, int special) Sourced(int n, int special)
@ -59,7 +57,7 @@ Mopup(FILE *fd)
if (Tojump[j] == Jumpto[i]) if (Tojump[j] == Jumpto[i])
break; break;
if (j == Tj) if (j == Tj)
{ char buf[12]; { char buf[16];
if (Jumpto[i] == OkBreak) if (Jumpto[i] == OkBreak)
{ if (!LastGoto) { if (!LastGoto)
fprintf(fd, "S_%.3d_0: /* break-dest */\n", fprintf(fd, "S_%.3d_0: /* break-dest */\n",
@ -80,10 +78,11 @@ Mopup(FILE *fd)
} }
for (j = i = 0; j < Tj; j++) for (j = i = 0; j < Tj; j++)
if (Special[j]) if (Special[j])
{ Tojump[i] = Tojump[j]; { if (i >= MAXDSTEP)
{ fatal("cannot happen (dstep.c)", (char *)0);
}
Tojump[i] = Tojump[j];
Special[i] = 2; Special[i] = 2;
if (i >= MAXDSTEP)
fatal("cannot happen (dstep.c)", (char *)0);
i++; i++;
} }
Tj = i; /* keep only the global exit-labels */ Tj = i; /* keep only the global exit-labels */
@ -164,7 +163,7 @@ CollectGuards(FILE *fd, Element *e, int inh)
break; break;
case ELSE: case ELSE:
if (inh++ > 0) fprintf(fd, " || "); if (inh++ > 0) fprintf(fd, " || ");
/* 4.2.5 */ if (Pid != claimnr) /* 4.2.5 */ if (!pid_is_claim(Pid))
fprintf(fd, "(boq == -1 /* else */)"); fprintf(fd, "(boq == -1 /* else */)");
else else
fprintf(fd, "(1 /* else */)"); fprintf(fd, "(1 /* else */)");
@ -184,17 +183,17 @@ CollectGuards(FILE *fd, Element *e, int inh)
case 's': case 's':
if (inh++ > 0) fprintf(fd, " || "); if (inh++ > 0) fprintf(fd, " || ");
fprintf(fd, "("); TestOnly=1; fprintf(fd, "("); TestOnly=1;
/* 4.2.1 */ if (Pid != claimnr) fprintf(fd, "(boq == -1) && "); /* 4.2.1 */ if (!pid_is_claim(Pid)) fprintf(fd, "(boq == -1) && ");
putstmnt(fd, ee->n, ee->seqno); putstmnt(fd, ee->n, ee->seqno);
fprintf(fd, ")"); TestOnly=0; fprintf(fd, ")"); TestOnly=0;
break; break;
case 'c': case 'c':
if (inh++ > 0) fprintf(fd, " || "); if (inh++ > 0) fprintf(fd, " || ");
fprintf(fd, "("); TestOnly=1; fprintf(fd, "("); TestOnly=1;
if (Pid != claimnr) if (!pid_is_claim(Pid))
fprintf(fd, "(boq == -1 && "); fprintf(fd, "(boq == -1 && ");
putstmnt(fd, ee->n->lft, e->seqno); putstmnt(fd, ee->n->lft, e->seqno);
if (Pid != claimnr) if (!pid_is_claim(Pid))
fprintf(fd, ")"); fprintf(fd, ")");
fprintf(fd, ")"); TestOnly=0; fprintf(fd, ")"); TestOnly=0;
break; break;
@ -204,7 +203,8 @@ CollectGuards(FILE *fd, Element *e, int inh)
int int
putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno) putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno)
{ int isg=0; char buf[64]; { int isg=0;
static char buf[64];
NextLab[0] = "continue"; NextLab[0] = "continue";
filterbad(s->frst); filterbad(s->frst);
@ -215,6 +215,7 @@ putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno)
return putcode(fd, s->frst->n->sl->this, nxt, 0, ln, seqno); return putcode(fd, s->frst->n->sl->this, nxt, 0, ln, seqno);
case NON_ATOMIC: case NON_ATOMIC:
(void) putcode(fd, s->frst->n->sl->this, ZE, 1, ln, seqno); (void) putcode(fd, s->frst->n->sl->this, ZE, 1, ln, seqno);
if (justguards) return 0; /* 6.2.5 */
break; break;
case IF: case IF:
fprintf(fd, "if (!("); fprintf(fd, "if (!(");
@ -245,7 +246,7 @@ putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno)
case 's': case 's':
fprintf(fd, "if ("); fprintf(fd, "if (");
#if 1 #if 1
/* 4.2.1 */ if (Pid != claimnr) fprintf(fd, "(boq != -1) || "); /* 4.2.1 */ if (!pid_is_claim(Pid)) fprintf(fd, "(boq != -1) || ");
#endif #endif
fprintf(fd, "!("); TestOnly=1; fprintf(fd, "!("); TestOnly=1;
putstmnt(fd, s->frst->n, s->frst->seqno); putstmnt(fd, s->frst->n, s->frst->seqno);
@ -253,7 +254,7 @@ putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno)
break; break;
case 'c': case 'c':
fprintf(fd, "if (!("); fprintf(fd, "if (!(");
if (Pid != claimnr) fprintf(fd, "boq == -1 && "); if (!pid_is_claim(Pid)) fprintf(fd, "boq == -1 && ");
TestOnly=1; TestOnly=1;
putstmnt(fd, s->frst->n->lft, s->frst->seqno); putstmnt(fd, s->frst->n->lft, s->frst->seqno);
fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0; fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
@ -262,19 +263,31 @@ putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno)
fprintf(fd, "if (boq != -1 || ("); fprintf(fd, "if (boq != -1 || (");
if (separate != 2) fprintf(fd, "trpt->"); if (separate != 2) fprintf(fd, "trpt->");
fprintf(fd, "o_pm&1))\n\t\t\tcontinue;"); fprintf(fd, "o_pm&1))\n\t\t\tcontinue;");
{ extern FILE *th;
fprintf(th, "#ifndef ELSE_IN_GUARD\n");
fprintf(th, " #define ELSE_IN_GUARD\n");
fprintf(th, "#endif\n");
}
break; break;
case ASGN: /* new 3.0.8 */ case ASGN: /* new 3.0.8 */
fprintf(fd, "IfNotBlocked"); fprintf(fd, "IfNotBlocked");
break; break;
default:
fprintf(fd, "/* default %d */\n\t\t", s->frst->n->ntyp);
} }
/* 6.2.5 : before TstOnly */
fprintf(fd, "\n\n\t\treached[%d][%d] = 1;\n\t\t", Pid, seqno);
fprintf(fd, "reached[%d][t->st] = 1;\n\t\t", Pid); /* next state */
fprintf(fd, "reached[%d][tt] = 1;\n", Pid); /* current state */
/* 6.2.5 : before sv_save() */
if (s->frst->n->ntyp != NON_ATOMIC)
fprintf(fd, "\n\t\tif (TstOnly) return 1;\n"); /* if called from enabled() */
if (justguards) return 0; if (justguards) return 0;
fprintf(fd, "\n\t\tsv_save();\n\t\t"); fprintf(fd, "\n\t\tsv_save();\n\t\t");
#if 1
fprintf(fd, "reached[%d][%d] = 1;\n\t\t", Pid, seqno);
fprintf(fd, "reached[%d][t->st] = 1;\n\t\t", Pid); /* true next state */
fprintf(fd, "reached[%d][tt] = 1;\n", Pid); /* true current state */
#endif
sprintf(buf, "Uerror(\"block in d_step seq, line %d\")", ln); sprintf(buf, "Uerror(\"block in d_step seq, line %d\")", ln);
NextLab[0] = buf; NextLab[0] = buf;
putCode(fd, s->frst, s->extent, nxt, isg); putCode(fd, s->frst, s->extent, nxt, isg);
@ -359,7 +372,7 @@ putCode(FILE *fd, Element *f, Element *last, Element *next, int isguard)
case '.': case '.':
if (LastGoto) break; if (LastGoto) break;
if (e->nxt && (e->nxt->status & DONE2)) if (e->nxt && (e->nxt->status & DONE2))
{ i = e->nxt?e->nxt->Seqno:0; { i = e->nxt->Seqno;
fprintf(fd, "\t\tgoto S_%.3d_0;", i); fprintf(fd, "\t\tgoto S_%.3d_0;", i);
fprintf(fd, " /* '.' */\n"); fprintf(fd, " /* '.' */\n");
Dested(i); Dested(i);
@ -375,7 +388,7 @@ putCode(FILE *fd, Element *f, Element *last, Element *next, int isguard)
break; break;
} }
i = e->nxt?e->nxt->Seqno:0; i = e->nxt?e->nxt->Seqno:0;
if (e->nxt && e->nxt->status & DONE2 && !LastGoto) if (e->nxt && (e->nxt->status & DONE2) && !LastGoto)
{ fprintf(fd, "\t\tgoto S_%.3d_0; ", i); { fprintf(fd, "\t\tgoto S_%.3d_0; ", i);
fprintf(fd, "/* ';' */\n"); fprintf(fd, "/* ';' */\n");
Dested(i); Dested(i);

View file

@ -1,24 +1,24 @@
/***** spin: flow.c *****/ /***** spin: flow.c *****/
/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 "spin.h"
#include "y.tab.h" #include "y.tab.h"
extern Symbol *Fname; extern Symbol *Fname;
extern int nr_errs, lineno, verbose; extern int nr_errs, lineno, verbose, in_for, old_scope_rules, s_trail;
extern short has_unless, has_badelse; extern short has_unless, has_badelse, has_xu;
extern char CurScope[MAXSCOPESZ];
Element *Al_El = ZE; Element *Al_El = ZE;
Label *labtab = (Label *) 0; Label *labtab = (Label *) 0;
int Unique=0, Elcnt=0, DstepStart = -1; int Unique = 0, Elcnt = 0, DstepStart = -1;
int initialization_ok = 1;
short has_accept;
static Lbreak *breakstack = (Lbreak *) 0; static Lbreak *breakstack = (Lbreak *) 0;
static Lextok *innermost; static Lextok *innermost;
@ -37,10 +37,16 @@ void
open_seq(int top) open_seq(int top)
{ SeqList *t; { SeqList *t;
Sequence *s = (Sequence *) emalloc(sizeof(Sequence)); Sequence *s = (Sequence *) emalloc(sizeof(Sequence));
s->minel = -1;
t = seqlist(s, cur_s); t = seqlist(s, cur_s);
cur_s = t; cur_s = t;
if (top) Elcnt = 1; if (top)
{ Elcnt = 1;
initialization_ok = 1;
} else
{ initialization_ok = 0;
}
} }
void void
@ -84,6 +90,7 @@ cross_dsteps(Lextok *a, Lextok *b)
&& a->indstep != b->indstep) && a->indstep != b->indstep)
{ lineno = a->ln; { lineno = a->ln;
Fname = a->fn; Fname = a->fn;
if (!s_trail)
fatal("jump into d_step sequence", (char *) 0); fatal("jump into d_step sequence", (char *) 0);
} }
} }
@ -113,8 +120,8 @@ check_sequence(Sequence *s)
&& n->ntyp != PRINT && n->ntyp != PRINT
&& n->ntyp != PRINTM) && n->ntyp != PRINTM)
{ if (verbose&32) { if (verbose&32)
printf("spin: line %d %s, redundant skip\n", printf("spin: %s:%d, redundant skip\n",
n->ln, n->fn->name); n->fn->name, n->ln);
if (e != s->frst if (e != s->frst
&& e != s->last && e != s->last
&& e != s->extent) && e != s->extent)
@ -147,7 +154,11 @@ close_seq(int nottop)
{ Sequence *s = cur_s->this; { Sequence *s = cur_s->this;
Symbol *z; Symbol *z;
if (nottop > 0 && (z = has_lab(s->frst, 0))) if (nottop == 0) /* end of proctype body */
{ initialization_ok = 1;
}
if (nottop > 0 && s->frst && (z = has_lab(s->frst, 0)))
{ printf("error: (%s:%d) label %s placed incorrectly\n", { printf("error: (%s:%d) label %s placed incorrectly\n",
(s->frst->n)?s->frst->n->fn->name:"-", (s->frst->n)?s->frst->n->fn->name:"-",
(s->frst->n)?s->frst->n->ln:0, (s->frst->n)?s->frst->n->ln:0,
@ -183,12 +194,12 @@ close_seq(int nottop)
printf("\"Label: { statement ... }\"\n"); printf("\"Label: { statement ... }\"\n");
break; break;
case 6: case 6:
printf("=====>instead of\n"); printf("=====> instead of\n");
printf(" do (or if)\n"); printf(" do (or if)\n");
printf(" :: ...\n"); printf(" :: ...\n");
printf(" :: Label: statement\n"); printf(" :: Label: statement\n");
printf(" od (of fi)\n"); printf(" od (of fi)\n");
printf("=====>always use\n"); printf("=====> use\n");
printf("Label: do (or if)\n"); printf("Label: do (or if)\n");
printf(" :: ...\n"); printf(" :: ...\n");
printf(" :: statement\n"); printf(" :: statement\n");
@ -198,8 +209,9 @@ close_seq(int nottop)
printf("cannot happen - labels\n"); printf("cannot happen - labels\n");
break; break;
} }
alldone(1); if (nottop != 6)
} { alldone(1);
} }
if (nottop == 4 if (nottop == 4
&& !Rjumpslocal(s->frst, s->last)) && !Rjumpslocal(s->frst, s->last))
@ -217,13 +229,14 @@ Lextok *
do_unless(Lextok *No, Lextok *Es) do_unless(Lextok *No, Lextok *Es)
{ SeqList *Sl; { SeqList *Sl;
Lextok *Re = nn(ZN, UNLESS, ZN, ZN); Lextok *Re = nn(ZN, UNLESS, ZN, ZN);
Re->ln = No->ln; Re->ln = No->ln;
Re->fn = No->fn; Re->fn = No->fn;
has_unless++; has_unless++;
if (Es->ntyp == NON_ATOMIC) if (Es->ntyp == NON_ATOMIC)
Sl = Es->sl; { Sl = Es->sl;
else } else
{ open_seq(0); add_seq(Es); { open_seq(0); add_seq(Es);
Sl = seqlist(close_seq(1), 0); Sl = seqlist(close_seq(1), 0);
} }
@ -348,6 +361,31 @@ loose_ends(void) /* properly tie-up ends of sub-sequences */
} } } }
} }
void
popbreak(void)
{
if (!breakstack)
fatal("cannot happen, breakstack", (char *) 0);
breakstack = breakstack->nxt; /* pop stack */
}
static Lbreak *ob = (Lbreak *) 0;
void
safe_break(void)
{
ob = breakstack;
popbreak();
}
void
restore_break(void)
{
breakstack = ob;
ob = (Lbreak *) 0;
}
static Element * static Element *
if_seq(Lextok *n) if_seq(Lextok *n)
{ int tok = n->ntyp; { int tok = n->ntyp;
@ -388,21 +426,26 @@ if_seq(Lextok *n)
&& prev_z->this->frst->n->ntyp == ELSE) && prev_z->this->frst->n->ntyp == ELSE)
{ prev_z->this->frst->n->val = 1; { prev_z->this->frst->n->val = 1;
has_badelse++; has_badelse++;
non_fatal("dubious use of 'else' combined with i/o,", if (has_xu)
(char *)0); { fatal("invalid use of 'else' combined with i/o and xr/xs assertions,",
(char *)0);
} else
{ non_fatal("dubious use of 'else' combined with i/o,",
(char *)0);
}
nr_errs--; nr_errs--;
} }
e->n = nn(n, tok, ZN, ZN); e->n = nn(n, tok, ZN, ZN);
e->n->sl = s; /* preserve as info only */ e->n->sl = s; /* preserve as info only */
e->sub = s; e->sub = s;
for (z = s; z; prev_z = z, z = z->nxt) for (z = s; z; z = z->nxt)
add_el(t, z->this); /* append target */ add_el(t, z->this); /* append target */
if (tok == DO) if (tok == DO)
{ add_el(t, cur_s->this); /* target upfront */ { add_el(t, cur_s->this); /* target upfront */
t = new_el(nn(n, BREAK, ZN, ZN)); /* break target */ t = new_el(nn(n, BREAK, ZN, ZN)); /* break target */
set_lab(break_dest(), t); /* new exit */ set_lab(break_dest(), t); /* new exit */
breakstack = breakstack->nxt; /* pop stack */ popbreak();
} }
add_el(e, cur_s->this); add_el(e, cur_s->this);
add_el(t, cur_s->this); add_el(t, cur_s->this);
@ -563,33 +606,86 @@ add_seq(Lextok *n)
void void
set_lab(Symbol *s, Element *e) set_lab(Symbol *s, Element *e)
{ Label *l; extern Symbol *context; { Label *l; extern Symbol *context;
int cur_uiid = is_inline();
if (!s) return; if (!s) return;
for (l = labtab; l; l = l->nxt) for (l = labtab; l; l = l->nxt)
if (l->s == s && l->c == context) { if (strcmp(l->s->name, s->name) == 0
&& l->c == context
&& (old_scope_rules || strcmp((const char *) s->bscp, (const char *) l->s->bscp) == 0)
&& l->uiid == cur_uiid)
{ non_fatal("label %s redeclared", s->name); { non_fatal("label %s redeclared", s->name);
break; break;
} } }
if (strncmp(s->name, "accept", 6) == 0
&& strncmp(s->name, "accept_all", 10) != 0)
{ has_accept = 1;
}
l = (Label *) emalloc(sizeof(Label)); l = (Label *) emalloc(sizeof(Label));
l->s = s; l->s = s;
l->c = context; l->c = context;
l->e = e; l->e = e;
l->uiid = cur_uiid;
l->nxt = labtab; l->nxt = labtab;
labtab = l; labtab = l;
} }
static Label *
get_labspec(Lextok *n)
{ Symbol *s = n->sym;
Label *l, *anymatch = (Label *) 0;
int ln;
/*
* try to find a label with the same inline id (uiid)
* but if it doesn't exist, return any other match
* within the same scope
*/
for (l = labtab; l; l = l->nxt)
{ if (strcmp(l->s->name, s->name) == 0 /* labelname matches */
&& s->context == l->s->context) /* same scope */
{
#if 0
if (anymatch && n->uiid == anymatch->uiid)
{ if (0) non_fatal("label %s re-declared", s->name);
}
if (0)
{ printf("Label %s uiid now::then %d :: %d bcsp %s :: %s\n",
s->name, n->uiid, l->uiid, s->bscp, l->s->bscp);
printf("get_labspec match on %s %s (bscp goto %s - label %s)\n",
s->name, s->context->name, s->bscp, l->s->bscp);
}
#endif
/* same block scope */
if (strcmp((const char *) s->bscp, (const char *) l->s->bscp) == 0)
{ return l; /* definite match */
}
/* higher block scope */
ln = strlen((const char *) l->s->bscp);
if (strncmp((const char *) s->bscp, (const char *) l->s->bscp, ln) == 0)
{ anymatch = l; /* possible match */
} else if (!anymatch)
{ anymatch = l; /* somewhere else in same context */
} } }
return anymatch; /* return best match */
}
Element * Element *
get_lab(Lextok *n, int md) get_lab(Lextok *n, int md)
{ Label *l; { Label *l = get_labspec(n);
Symbol *s = n->sym;
for (l = labtab; l; l = l->nxt) if (l != (Label *) 0)
if (s == l->s) { return (l->e);
return (l->e); }
lineno = n->ln; if (md)
Fname = n->fn; { lineno = n->ln;
if (md) fatal("undefined label %s", s->name); Fname = n->fn;
fatal("undefined label %s", n->sym->name);
}
return ZE; return ZE;
} }
@ -670,21 +766,46 @@ fix_dest(Symbol *c, Symbol *a) /* c:label name, a:proctype name */
} }
l->e->status |= CHECK2; /* treat as if global */ l->e->status |= CHECK2; /* treat as if global */
if (l->e->status & (ATOM | L_ATOM | D_ATOM)) if (l->e->status & (ATOM | L_ATOM | D_ATOM))
{ non_fatal("cannot reference label inside atomic or d_step (%s)", { printf("spin: %s:%d, warning, reference to label ",
c->name); Fname->name, lineno);
printf("from inside atomic or d_step (%s)\n", c->name);
} }
} }
int int
find_lab(Symbol *s, Symbol *c, int markit) find_lab(Symbol *s, Symbol *c, int markit)
{ Label *l; { Label *l, *pm = (Label *) 0, *apm = (Label *) 0;
int ln;
/* generally called for remote references in never claims */
for (l = labtab; l; l = l->nxt) for (l = labtab; l; l = l->nxt)
{ if (strcmp(s->name, l->s->name) == 0 {
if (strcmp(s->name, l->s->name) == 0
&& strcmp(c->name, l->c->name) == 0) && strcmp(c->name, l->c->name) == 0)
{ l->visible |= markit; { ln = strlen((const char *) l->s->bscp);
return (l->e->seqno); if (0)
} } { printf("want '%s' in context '%s', scope ref '%s' - label '%s'\n",
s->name, c->name, s->bscp, l->s->bscp);
}
/* same or higher block scope */
if (strcmp((const char *) s->bscp, (const char *) l->s->bscp) == 0)
{ pm = l; /* definite match */
break;
}
if (strncmp((const char *) s->bscp, (const char *) l->s->bscp, ln) == 0)
{ pm = l; /* possible match */
} else
{ apm = l; /* remote */
} } }
if (pm)
{ pm->visible |= markit;
return pm->e->seqno;
}
if (apm)
{ apm->visible |= markit;
return apm->e->seqno;
} /* else printf("Not Found\n"); */
return 0; return 0;
} }
@ -735,6 +856,226 @@ make_atomic(Sequence *s, int added)
} }
} }
#if 0
static int depth = 0;
void dump_sym(Symbol *, char *);
void
dump_lex(Lextok *t, char *s)
{ int i;
depth++;
printf(s);
for (i = 0; i < depth; i++)
printf("\t");
explain(t->ntyp);
if (t->ntyp == NAME) printf(" %s ", t->sym->name);
if (t->ntyp == CONST) printf(" %d ", t->val);
if (t->ntyp == STRUCT)
{ dump_sym(t->sym, "\n:Z:");
}
if (t->lft)
{ dump_lex(t->lft, "\nL");
}
if (t->rgt)
{ dump_lex(t->rgt, "\nR");
}
depth--;
}
void
dump_sym(Symbol *z, char *s)
{ int i;
char txt[64];
depth++;
printf(s);
for (i = 0; i < depth; i++)
printf("\t");
if (z->type == CHAN)
{ if (z->ini && z->ini->rgt && z->ini->rgt->sym)
{ /* dump_sym(z->ini->rgt->sym, "\n:I:"); -- could also be longer list */
if (z->ini->rgt->rgt
|| !z->ini->rgt->sym)
fatal("chan %s in for should have only one field (a typedef)", z->name);
printf(" -- %s %p -- ", z->ini->rgt->sym->name, z->ini->rgt->sym);
}
} else if (z->type == STRUCT)
{ if (z->Snm)
printf(" == %s %p == ", z->Snm->name, z->Snm);
else
{ if (z->Slst)
dump_lex(z->Slst, "\n:X:");
if (z->ini)
dump_lex(z->ini, "\n:I:");
}
}
depth--;
}
#endif
int
match_struct(Symbol *s, Symbol *t)
{
if (!t
|| !t->ini
|| !t->ini->rgt
|| !t->ini->rgt->sym
|| t->ini->rgt->rgt)
{ fatal("chan %s in for should have only one field (a typedef)", t?t->name:"--");
}
/* we already know that s is a STRUCT */
if (0)
{ printf("index type %s %p ==\n", s->Snm->name, s->Snm);
printf("chan type %s %p --\n\n", t->ini->rgt->sym->name, t->ini->rgt->sym);
}
return (s->Snm == t->ini->rgt->sym);
}
void
valid_name(Lextok *a3, Lextok *a5, Lextok *a8, char *tp)
{
if (a3->ntyp != NAME)
{ fatal("%s ( .name : from .. to ) { ... }", tp);
}
if (a3->sym->type == CHAN
|| a3->sym->type == STRUCT
|| a3->sym->isarray != 0)
{ fatal("bad index in for-construct %s", a3->sym->name);
}
if (a5->ntyp == CONST && a8->ntyp == CONST && a5->val > a8->val)
{ non_fatal("start value for %s exceeds end-value", a3->sym->name);
}
}
void
for_setup(Lextok *a3, Lextok *a5, Lextok *a8)
{ /* for ( a3 : a5 .. a8 ) */
valid_name(a3, a5, a8, "for");
/* a5->ntyp = a8->ntyp = CONST; */
add_seq(nn(a3, ASGN, a3, a5)); /* start value */
open_seq(0);
add_seq(nn(ZN, 'c', nn(a3, LE, a3, a8), ZN)); /* condition */
}
Lextok *
for_index(Lextok *a3, Lextok *a5)
{ Lextok *z0, *z1, *z2, *z3;
Symbol *tmp_cnt;
char tmp_nm[MAXSCOPESZ+16];
/* for ( a3 in a5 ) { ... } */
if (a3->ntyp != NAME)
{ fatal("for ( .name in name ) { ... }", (char *) 0);
}
if (a5->ntyp != NAME)
{ fatal("for ( %s in .name ) { ... }", a3->sym->name);
}
if (a3->sym->type == STRUCT)
{ if (a5->sym->type != CHAN)
{ fatal("for ( %s in .channel_name ) { ... }",
a3->sym->name);
}
z0 = a5->sym->ini;
if (!z0
|| z0->val <= 0
|| z0->rgt->ntyp != STRUCT
|| z0->rgt->rgt != NULL)
{ fatal("bad channel type %s in for", a5->sym->name);
}
if (!match_struct(a3->sym, a5->sym))
{ fatal("type of %s does not match chan", a3->sym->name);
}
z1 = nn(ZN, CONST, ZN, ZN); z1->val = 0;
z2 = nn(a5, LEN, a5, ZN);
sprintf(tmp_nm, "_f0r_t3mp%s", CurScope); /* make sure it's unique */
tmp_cnt = lookup(tmp_nm);
if (z0->val > 255) /* check nr of slots, i.e. max length */
{ tmp_cnt->type = SHORT; /* should be rare */
} else
{ tmp_cnt->type = BYTE;
}
z3 = nn(ZN, NAME, ZN, ZN);
z3->sym = tmp_cnt;
add_seq(nn(z3, ASGN, z3, z1)); /* start value 0 */
open_seq(0);
add_seq(nn(ZN, 'c', nn(z3, LT, z3, z2), ZN)); /* condition */
/* retrieve message from the right slot -- for now: rotate contents */
in_for = 0;
add_seq(nn(a5, 'r', a5, expand(a3, 1))); /* receive */
add_seq(nn(a5, 's', a5, expand(a3, 1))); /* put back in to rotate */
in_for = 1;
return z3;
} else
{ if (a5->sym->isarray == 0
|| a5->sym->nel <= 0)
{ fatal("bad arrayname %s", a5->sym->name);
}
z1 = nn(ZN, CONST, ZN, ZN); z1->val = 0;
z2 = nn(ZN, CONST, ZN, ZN); z2->val = a5->sym->nel - 1;
for_setup(a3, z1, z2);
return a3;
}
}
Lextok *
for_body(Lextok *a3, int with_else)
{ Lextok *t1, *t2, *t0, *rv;
rv = nn(ZN, CONST, ZN, ZN); rv->val = 1;
rv = nn(ZN, '+', a3, rv);
rv = nn(a3, ASGN, a3, rv);
add_seq(rv); /* initial increment */
/* completed loop body, main sequence */
t1 = nn(ZN, 0, ZN, ZN);
t1->sq = close_seq(8);
open_seq(0); /* add else -> break sequence */
if (with_else)
{ add_seq(nn(ZN, ELSE, ZN, ZN));
}
t2 = nn(ZN, GOTO, ZN, ZN);
t2->sym = break_dest();
add_seq(t2);
t2 = nn(ZN, 0, ZN, ZN);
t2->sq = close_seq(9);
t0 = nn(ZN, 0, ZN, ZN);
t0->sl = seqlist(t2->sq, seqlist(t1->sq, 0));
rv = nn(ZN, DO, ZN, ZN);
rv->sl = t0->sl;
return rv;
}
Lextok *
sel_index(Lextok *a3, Lextok *a5, Lextok *a7)
{ /* select ( a3 : a5 .. a7 ) */
valid_name(a3, a5, a7, "select");
/* a5->ntyp = a7->ntyp = CONST; */
add_seq(nn(a3, ASGN, a3, a5)); /* start value */
open_seq(0);
add_seq(nn(ZN, 'c', nn(a3, LT, a3, a7), ZN)); /* condition */
pushbreak(); /* new 6.2.1 */
return for_body(a3, 0); /* no else, just a non-deterministic break */
}
static void static void
walk_atomic(Element *a, Element *b, int added) walk_atomic(Element *a, Element *b, int added)
{ Element *f; Symbol *ofn; int oln; { Element *f; Symbol *ofn; int oln;
@ -747,16 +1088,16 @@ walk_atomic(Element *a, Element *b, int added)
switch (f->n->ntyp) { switch (f->n->ntyp) {
case ATOMIC: case ATOMIC:
if (verbose&32) if (verbose&32)
printf("spin: warning, line %3d %s, atomic inside %s (ignored)\n", printf("spin: %s:%d, warning, atomic inside %s (ignored)\n",
f->n->ln, f->n->fn->name, (added)?"d_step":"atomic"); f->n->fn->name, f->n->ln, (added)?"d_step":"atomic");
goto mknonat; goto mknonat;
case D_STEP: case D_STEP:
if (!(verbose&32)) if (!(verbose&32))
{ if (added) goto mknonat; { if (added) goto mknonat;
break; break;
} }
printf("spin: warning, line %3d %s, d_step inside ", printf("spin: %s:%d, warning, d_step inside ",
f->n->ln, f->n->fn->name); f->n->fn->name, f->n->ln);
if (added) if (added)
{ printf("d_step (ignored)\n"); { printf("d_step (ignored)\n");
goto mknonat; goto mknonat;
@ -770,8 +1111,8 @@ mknonat: f->n->ntyp = NON_ATOMIC; /* can jump here */
break; break;
case UNLESS: case UNLESS:
if (added) if (added)
{ printf("spin: error, line %3d %s, unless in d_step (ignored)\n", { printf("spin: error, %s:%d, unless in d_step (ignored)\n",
f->n->ln, f->n->fn->name); f->n->fn->name, f->n->ln);
} }
} }
for (h = f->sub; h; h = h->nxt) for (h = f->sub; h; h = h->nxt)
@ -789,6 +1130,15 @@ dumplabels(void)
for (l = labtab; l; l = l->nxt) for (l = labtab; l; l = l->nxt)
if (l->c != 0 && l->s->name[0] != ':') if (l->c != 0 && l->s->name[0] != ':')
printf("label %s %d <%s>\n", { printf("label %s %d ",
l->s->name, l->e->seqno, l->c->name); l->s->name, l->e->seqno);
if (l->uiid == 0)
printf("<%s>", l->c->name);
else
printf("<%s i%d>", l->c->name, l->uiid);
if (!old_scope_rules)
{ printf("\t{scope %s}", l->s->bscp);
}
printf("\n");
}
} }

View file

@ -1,17 +1,15 @@
/***** spin: guided.c *****/ /***** spin: guided.c *****/
/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 "spin.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <limits.h>
#include "y.tab.h" #include "y.tab.h"
extern RunList *run, *X; extern RunList *run, *X;
@ -19,8 +17,9 @@ extern Element *Al_El;
extern Symbol *Fname, *oFname; extern Symbol *Fname, *oFname;
extern int verbose, lineno, xspin, jumpsteps, depth, merger, cutoff; extern int verbose, lineno, xspin, jumpsteps, depth, merger, cutoff;
extern int nproc, nstop, Tval, ntrail, columns; extern int nproc, nstop, Tval, ntrail, columns;
extern short Have_claim, Skip_claim; extern short Have_claim, Skip_claim, has_code;
extern void ana_src(int, int); extern void ana_src(int, int);
extern char **trailfilename;
int TstOnly = 0, pno; int TstOnly = 0, pno;
@ -73,12 +72,70 @@ not_claim(void)
return (!Have_claim || !X || X->pid != 0); return (!Have_claim || !X || X->pid != 0);
} }
int globmin = INT_MAX;
int globmax = 0;
int
find_min(Sequence *s)
{ SeqList *l;
Element *e;
if (s->minel < 0)
{ s->minel = INT_MAX;
for (e = s->frst; e; e = e->nxt)
{ if (e->status & 512)
{ continue;
}
e->status |= 512;
if (e->n->ntyp == ATOMIC
|| e->n->ntyp == NON_ATOMIC
|| e->n->ntyp == D_STEP)
{ int n = find_min(e->n->sl->this);
if (n < s->minel)
{ s->minel = n;
}
} else if (e->Seqno < s->minel)
{ s->minel = e->Seqno;
}
for (l = e->sub; l; l = l->nxt)
{ int n = find_min(l->this);
if (n < s->minel)
{ s->minel = n;
} } }
}
if (s->minel < globmin)
{ globmin = s->minel;
}
return s->minel;
}
int
find_max(Sequence *s)
{
if (s->last->Seqno > globmax)
{ globmax = s->last->Seqno;
}
return s->last->Seqno;
}
void void
match_trail(void) match_trail(void)
{ int i, a, nst; { int i, a, nst;
Element *dothis; Element *dothis;
char snap[512], *q; char snap[512], *q;
if (has_code)
{ printf("spin: important:\n");
printf(" =======================================warning====\n");
printf(" this model contains embedded c code statements\n");
printf(" these statements will not be executed when the trail\n");
printf(" is replayed in this way -- they are just printed,\n");
printf(" which will likely lead to inaccurate variable values.\n");
printf(" for an accurate replay use: ./pan -r\n");
printf(" =======================================warning====\n\n");
}
/* /*
* if source model name is leader.pml * if source model name is leader.pml
* look for the trail file under these names: * look for the trail file under these names:
@ -88,10 +145,18 @@ match_trail(void)
* leader.tra * leader.tra
*/ */
if (ntrail) if (trailfilename)
sprintf(snap, "%s%d.trail", oFname->name, ntrail); { if (strlen(*trailfilename) < sizeof(snap))
else { strcpy(snap, (const char *) *trailfilename);
sprintf(snap, "%s.trail", oFname->name); } else
{ fatal("filename %s too long", *trailfilename);
}
} else
{ if (ntrail)
sprintf(snap, "%s%d.trail", oFname->name, ntrail);
else
sprintf(snap, "%s.trail", oFname->name);
}
if ((fd = fopen(snap, "r")) == NULL) if ((fd = fopen(snap, "r")) == NULL)
{ snap[strlen(snap)-2] = '\0'; /* .tra */ { snap[strlen(snap)-2] = '\0'; /* .tra */
@ -118,9 +183,9 @@ match_trail(void)
} } } }
okay: okay:
if (xspin == 0 && newer(oFname->name, snap)) if (xspin == 0 && newer(oFname->name, snap))
printf("spin: warning, \"%s\" is newer than %s\n", { printf("spin: warning, \"%s\" is newer than %s\n",
oFname->name, snap); oFname->name, snap);
}
Tval = 1; Tval = 1;
/* /*
@ -132,10 +197,23 @@ okay:
hookup(); hookup();
while (fscanf(fd, "%d:%d:%d\n", &depth, &pno, &nst) == 3) while (fscanf(fd, "%d:%d:%d\n", &depth, &pno, &nst) == 3)
{ if (depth == -2) { start_claim(pno); continue; } { if (depth == -2)
if (depth == -4) { merger = 1; ana_src(0, 1); continue; }
if (depth == -1)
{ if (verbose) { if (verbose)
{ printf("starting claim %d\n", pno);
}
start_claim(pno);
continue;
}
if (depth == -4)
{ if (verbose)
{ printf("using statement merging\n");
}
merger = 1;
ana_src(0, 1);
continue;
}
if (depth == -1)
{ if (1 || verbose)
{ if (columns == 2) { if (columns == 2)
dotag(stdout, " CYCLE>\n"); dotag(stdout, " CYCLE>\n");
else else
@ -188,16 +266,50 @@ okay:
pno - Have_claim, i, nst, dothis->n->ntyp); pno - Have_claim, i, nst, dothis->n->ntyp);
lost_trail(); lost_trail();
} }
if (0 && !xspin && (verbose&32))
{ printf("step %d i=%d pno %d stmnt %d\n", depth, i, pno, nst);
}
for (X = run; X; X = X->nxt) for (X = run; X; X = X->nxt)
{ if (--i == pno) { if (--i == pno)
break; break;
} }
if (!X) if (!X)
{ printf("%3d: no process %d ", depth, pno - Have_claim); { if (verbose&32)
printf("(state %d)\n", nst); { printf("%3d: no process %d (stmnt %d)\n", depth, pno - Have_claim, nst);
lost_trail(); printf(" max %d (%d - %d + %d) claim %d ",
nproc - nstop + Skip_claim,
nproc, nstop, Skip_claim, Have_claim);
printf("active processes:\n");
for (X = run; X; X = X->nxt)
{ printf("\tpid %d\tproctype %s\n", X->pid, X->n->name);
}
printf("\n");
continue;
} else
{ printf("%3d:\tproc %d (?) ", depth, pno);
lost_trail();
}
} else
{ int min_seq = find_min(X->ps);
int max_seq = find_max(X->ps);
if (nst < min_seq || nst > max_seq)
{ printf("%3d: error: invalid statement", depth);
if (verbose&32)
{ printf(": pid %d:%d (%s:%d:%d) stmnt %d (valid range %d .. %d)",
pno, X->pid, X->n->name, X->tn, X->b, nst, min_seq, max_seq);
}
printf("\n");
continue;
/* lost_trail(); */
}
X->pc = dothis;
} }
X->pc = dothis;
lineno = dothis->n->ln; lineno = dothis->n->ln;
Fname = dothis->n->fn; Fname = dothis->n->fn;
@ -271,7 +383,7 @@ keepgoing: if (dothis->merge_start)
} } } }
if (Have_claim && X && X->pid == 0 if (Have_claim && X && X->pid == 0
&& dothis && dothis->n && dothis->n
&& lastclaim != dothis->n->ln) && lastclaim != dothis->n->ln)
{ lastclaim = dothis->n->ln; { lastclaim = dothis->n->ln;
if (columns == 2) if (columns == 2)

File diff suppressed because it is too large Load diff

View file

@ -1,14 +1,12 @@
/***** spin: mesg.c *****/ /***** spin: mesg.c *****/
/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 <stdlib.h>
#include "spin.h" #include "spin.h"
#include "y.tab.h" #include "y.tab.h"
@ -24,9 +22,10 @@ extern int lineno, depth, xspin, m_loss, jumpsteps;
extern int nproc, nstop; extern int nproc, nstop;
extern short Have_claim; extern short Have_claim;
QH *qh;
Queue *qtab = (Queue *) 0; /* linked list of queues */ Queue *qtab = (Queue *) 0; /* linked list of queues */
Queue *ltab[MAXQ]; /* linear list of queues */ Queue *ltab[MAXQ]; /* linear list of queues */
int nqs = 0, firstrow = 1; int nqs = 0, firstrow = 1, has_stdin = 0;
char Buf[4096]; char Buf[4096];
static Lextok *n_rem = (Lextok *) 0; static Lextok *n_rem = (Lextok *) 0;
@ -73,7 +72,7 @@ qmake(Symbol *s)
return eval(s->ini); return eval(s->ini);
q = (Queue *) emalloc(sizeof(Queue)); q = (Queue *) emalloc(sizeof(Queue));
q->qid = ++nqs; q->qid = (short) ++nqs;
q->nslots = s->ini->val; q->nslots = s->ini->val;
q->nflds = cnt_mpars(s->ini->rgt); q->nflds = cnt_mpars(s->ini->rgt);
q->setat = depth; q->setat = depth;
@ -130,7 +129,7 @@ qsend(Lextok *n)
if (whichq == -1) if (whichq == -1)
{ printf("Error: sending to an uninitialized chan\n"); { printf("Error: sending to an uninitialized chan\n");
whichq = 0; /* whichq = 0; */
return 0; return 0;
} }
if (whichq < MAXQ && whichq >= 0 && ltab[whichq]) if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
@ -143,6 +142,37 @@ qsend(Lextok *n)
return 0; return 0;
} }
#ifndef PC
#include <termios.h>
static struct termios initial_settings, new_settings;
void
peek_ch_init(void)
{
tcgetattr(0,&initial_settings);
new_settings = initial_settings;
new_settings.c_lflag &= ~ICANON;
new_settings.c_lflag &= ~ECHO;
new_settings.c_lflag &= ~ISIG;
new_settings.c_cc[VMIN] = 0;
new_settings.c_cc[VTIME] = 0;
}
int
peek_ch(void)
{ int n;
has_stdin = 1;
tcsetattr(0, TCSANOW, &new_settings);
n = getchar();
tcsetattr(0, TCSANOW, &initial_settings);
return n;
}
#endif
int int
qrecv(Lextok *n, int full) qrecv(Lextok *n, int full)
{ int whichq = eval(n->lft)-1; { int whichq = eval(n->lft)-1;
@ -150,22 +180,37 @@ qrecv(Lextok *n, int full)
if (whichq == -1) if (whichq == -1)
{ if (n->sym && !strcmp(n->sym->name, "STDIN")) { if (n->sym && !strcmp(n->sym->name, "STDIN"))
{ Lextok *m; { Lextok *m;
#ifndef PC
static int did_once = 0;
if (!did_once) /* 6.2.4 */
{ peek_ch_init();
did_once = 1;
}
#endif
if (TstOnly) return 1; if (TstOnly) return 1;
for (m = n->rgt; m; m = m->rgt) for (m = n->rgt; m; m = m->rgt)
if (m->lft->ntyp != CONST && m->lft->ntyp != EVAL) if (m->lft->ntyp != CONST && m->lft->ntyp != EVAL)
{ int c = getchar(); {
#ifdef PC
int c = getchar();
#else
int c = peek_ch(); /* 6.2.4, was getchar(); */
#endif
if (c == 27 || c == 3) /* escape or control-c */
{ printf("quit\n");
exit(0);
} /* else: non-blocking */
if (c == EOF) return 0; /* no char available */
(void) setval(m->lft, c); (void) setval(m->lft, c);
} else } else
fatal("invalid use of STDIN", (char *)0); { fatal("invalid use of STDIN", (char *)0);
}
whichq = 0;
return 1; return 1;
} }
printf("Error: receiving from an uninitialized chan %s\n", printf("Error: receiving from an uninitialized chan %s\n",
n->sym?n->sym->name:""); n->sym?n->sym->name:"");
whichq = 0; /* whichq = 0; */
return 0; return 0;
} }
if (whichq < MAXQ && whichq >= 0 && ltab[whichq]) if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
@ -185,9 +230,11 @@ sa_snd(Queue *q, Lextok *n) /* sorted asynchronous */
for (j = 0, m = n->rgt; m && j < q->nflds; m = m->rgt, j++) for (j = 0, m = n->rgt; m && j < q->nflds; m = m->rgt, j++)
{ New = cast_val(q->fld_width[j], eval(m->lft), 0); { New = cast_val(q->fld_width[j], eval(m->lft), 0);
Old = q->contents[i*q->nflds+j]; Old = q->contents[i*q->nflds+j];
if (New == Old) continue; if (New == Old)
if (New > Old) break; /* inner loop */ continue;
if (New < Old) goto found; if (New > Old)
break; /* inner loop */
goto found; /* New < Old */
} }
found: found:
for (j = q->qlen-1; j >= i; j--) for (j = q->qlen-1; j >= i; j--)
@ -204,7 +251,8 @@ void
typ_ck(int ft, int at, char *s) typ_ck(int ft, int at, char *s)
{ {
if ((verbose&32) && ft != at if ((verbose&32) && ft != at
&& (ft == CHAN || at == CHAN)) && (ft == CHAN || at == CHAN)
&& (at != PREDEF || strcmp(s, "recv") != 0))
{ char buf[128], tag1[64], tag2[64]; { char buf[128], tag1[64], tag2[64];
(void) sputtype(tag1, ft); (void) sputtype(tag1, ft);
(void) sputtype(tag2, at); (void) sputtype(tag2, at);
@ -383,7 +431,7 @@ s_snd(Queue *q, Lextok *n)
return 1; return 1;
} }
void static void
channm(Lextok *n) channm(Lextok *n)
{ char lbuf[512]; { char lbuf[512];
@ -394,7 +442,11 @@ channm(Lextok *n)
else if (n->sym->type == STRUCT) else if (n->sym->type == STRUCT)
{ Symbol *r = n->sym; { Symbol *r = n->sym;
if (r->context) if (r->context)
r = findloc(r); { r = findloc(r);
if (!r)
{ strcat(Buf, "*?*");
return;
} }
ini_struct(r); ini_struct(r);
printf("%s", r->name); printf("%s", r->name);
strcpy(lbuf, ""); strcpy(lbuf, "");
@ -422,7 +474,11 @@ difcolumns(Lextok *n, char *tr, int v, int j, Queue *q)
sr_buf(v, q->fld_width[j] == MTYPE); sr_buf(v, q->fld_width[j] == MTYPE);
if (j == q->nflds - 1) if (j == q->nflds - 1)
{ int cnr; { int cnr;
if (s_trail) cnr = pno; else cnr = X?X->pid - Have_claim:0; if (s_trail)
{ cnr = pno;
} else
{ cnr = X?X->pid - Have_claim:0;
}
if (tr[0] == '[') strcat(Buf, "]"); if (tr[0] == '[') strcat(Buf, "]");
pstext(cnr, Buf); pstext(cnr, Buf);
} }
@ -458,12 +514,6 @@ docolumns(Lextok *n, char *tr, int v, int j, Queue *q)
} }
} }
typedef struct QH {
int n;
struct QH *nxt;
} QH;
QH *qh;
void void
qhide(int q) qhide(int q)
{ QH *p = (QH *) emalloc(sizeof(QH)); { QH *p = (QH *) emalloc(sizeof(QH));
@ -483,7 +533,7 @@ qishidden(int q)
static void static void
sr_talk(Lextok *n, int v, char *tr, char *a, int j, Queue *q) sr_talk(Lextok *n, int v, char *tr, char *a, int j, Queue *q)
{ char s[64]; { char s[128];
if (qishidden(eval(n->lft))) if (qishidden(eval(n->lft)))
return; return;
@ -510,9 +560,20 @@ sr_talk(Lextok *n, int v, char *tr, char *a, int j, Queue *q)
} }
if (j == 0) if (j == 0)
{ whoruns(1); { char snm[128];
printf("line %3d %s %s", whoruns(1);
n->ln, n->fn->name, s); { char *ptr = n->fn->name;
char *qtr = snm;
while (*ptr != '\0')
{ if (*ptr != '\"')
{ *qtr++ = *ptr;
}
ptr++;
}
*qtr = '\0';
printf("%s:%d %s",
snm, n->ln, s);
}
} else } else
printf(","); printf(",");
sr_mesg(stdout, v, q->fld_width[j] == MTYPE); sr_mesg(stdout, v, q->fld_width[j] == MTYPE);
@ -554,7 +615,11 @@ void
sr_mesg(FILE *fd, int v, int j) sr_mesg(FILE *fd, int v, int j)
{ Buf[0] ='\0'; { Buf[0] ='\0';
sr_buf(v, j); sr_buf(v, j);
#if 1
fprintf(fd, Buf, (char *) 0); /* prevent compiler warning */
#else
fprintf(fd, Buf); fprintf(fd, Buf);
#endif
} }
void void
@ -572,10 +637,15 @@ doq(Symbol *s, int n, RunList *r)
continue; continue;
if (q->nslots == 0) if (q->nslots == 0)
continue; /* rv q always empty */ continue; /* rv q always empty */
#if 0
if (q->qlen == 0) /* new 7/10 -- dont show if queue is empty */
{ continue;
}
#endif
printf("\t\tqueue %d (", q->qid); printf("\t\tqueue %d (", q->qid);
if (r) if (r)
printf("%s(%d):", r->n->name, r->pid - Have_claim); printf("%s(%d):", r->n->name, r->pid - Have_claim);
if (s->nel != 1) if (s->nel > 1 || s->isarray)
printf("%s[%d]): ", s->name, n); printf("%s[%d]): ", s->name, n);
else else
printf("%s): ", s->name); printf("%s): ", s->name);
@ -609,7 +679,11 @@ nochan_manip(Lextok *p, Lextok *n, int d)
} }
} }
if (!n || n->ntyp == LEN || n->ntyp == RUN) /* ok on the rhs of an assignment: */
if (!n || n->ntyp == LEN || n->ntyp == RUN
|| n->ntyp == FULL || n->ntyp == NFULL
|| n->ntyp == EMPTY || n->ntyp == NEMPTY
|| n->ntyp == 'R')
return; return;
if (n->sym && n->sym->type == CHAN) if (n->sym && n->sym->type == CHAN)
@ -627,6 +701,121 @@ nochan_manip(Lextok *p, Lextok *n, int d)
nochan_manip(p, n->rgt, 1); nochan_manip(p, n->rgt, 1);
} }
typedef struct BaseName {
char *str;
int cnt;
struct BaseName *nxt;
} BaseName;
static BaseName *bsn;
void
newbasename(char *s)
{ BaseName *b;
/* printf("+++++++++%s\n", s); */
for (b = bsn; b; b = b->nxt)
if (strcmp(b->str, s) == 0)
{ b->cnt++;
return;
}
b = (BaseName *) emalloc(sizeof(BaseName));
b->str = emalloc(strlen(s)+1);
b->cnt = 1;
strcpy(b->str, s);
b->nxt = bsn;
bsn = b;
}
void
delbasename(char *s)
{ BaseName *b, *prv = (BaseName *) 0;
for (b = bsn; b; prv = b, b = b->nxt)
{ if (strcmp(b->str, s) == 0)
{ b->cnt--;
if (b->cnt == 0)
{ if (prv)
{ prv->nxt = b->nxt;
} else
{ bsn = b->nxt;
} }
/* printf("---------%s\n", s); */
break;
} }
}
void
checkindex(char *s, char *t)
{ BaseName *b;
/* printf("xxx Check %s (%s)\n", s, t); */
for (b = bsn; b; b = b->nxt)
{
/* printf(" %s\n", b->str); */
if (strcmp(b->str, s) == 0)
{ non_fatal("do not index an array with itself (%s)", t);
break;
} }
}
void
scan_tree(Lextok *t, char *mn, char *mx)
{ char sv[512];
char tmp[32];
int oln = lineno;
if (!t) return;
lineno = t->ln;
if (t->ntyp == NAME)
{ strcat(mn, t->sym->name);
strcat(mx, t->sym->name);
if (t->lft) /* array index */
{ strcat(mn, "[]");
newbasename(mn);
strcpy(sv, mn); /* save */
strcpy(mn, ""); /* clear */
strcat(mx, "[");
scan_tree(t->lft, mn, mx); /* index */
strcat(mx, "]");
checkindex(mn, mx); /* match against basenames */
strcpy(mn, sv); /* restore */
delbasename(mn);
}
if (t->rgt) /* structure element */
{ scan_tree(t->rgt, mn, mx);
}
} else if (t->ntyp == CONST)
{ strcat(mn, "1"); /* really: t->val */
sprintf(tmp, "%d", t->val);
strcat(mx, tmp);
} else if (t->ntyp == '.')
{ strcat(mn, ".");
strcat(mx, ".");
scan_tree(t->lft, mn, mx);
} else
{ strcat(mn, "??");
strcat(mx, "??");
}
lineno = oln;
}
void
no_nested_array_refs(Lextok *n) /* a [ a[1] ] with a[1] = 1, causes trouble in pan.b */
{ char mn[512];
char mx[512];
/* printf("==================================ZAP\n"); */
bsn = (BaseName *) 0; /* start new list */
strcpy(mn, "");
strcpy(mx, "");
scan_tree(n, mn, mx);
/* printf("==> %s\n", mn); */
}
void void
no_internals(Lextok *n) no_internals(Lextok *n)
{ char *sp; { char *sp;
@ -638,7 +827,10 @@ no_internals(Lextok *n)
sp = n->sym->name; sp = n->sym->name;
if ((strlen(sp) == strlen("_nr_pr") && strcmp(sp, "_nr_pr") == 0) if ((strlen(sp) == strlen("_nr_pr") && strcmp(sp, "_nr_pr") == 0)
|| (strlen(sp) == strlen("_pid") && strcmp(sp, "_pid") == 0)
|| (strlen(sp) == strlen("_p") && strcmp(sp, "_p") == 0)) || (strlen(sp) == strlen("_p") && strcmp(sp, "_p") == 0))
{ fatal("attempt to assign value to system variable %s", sp); { fatal("invalid assignment to %s", sp);
} }
no_nested_array_refs(n);
} }

View file

@ -8,14 +8,14 @@ SPIN_OS=\
guided.$O\ guided.$O\
main.$O\ main.$O\
mesg.$O\ mesg.$O\
msc_tcl.$O\
pangen1.$O\ pangen1.$O\
pangen2.$O\ pangen2.$O\
pangen3.$O\ pangen3.$O\
pangen4.$O\ pangen4.$O\
pangen5.$O\ pangen5.$O\
pangen6.$O\ pangen6.$O\
pc_zpp.$O\ pangen7.$O\
ps_msc.$O\
reprosrc.$O\ reprosrc.$O\
run.$O\ run.$O\
sched.$O\ sched.$O\
@ -45,7 +45,7 @@ BIN=/$objtype/bin
</sys/src/cmd/mkone </sys/src/cmd/mkone
CC=pcc -c CC=pcc -c
CFLAGS=-B -D_POSIX_SOURCE CFLAGS=-B -D_POSIX_SOURCE -D_PLAN9
YFLAGS=-S -d YFLAGS=-S -d
$SPIN_OS: spin.h $SPIN_OS: spin.h

376
sys/src/cmd/spin/msc_tcl.c Normal file
View file

@ -0,0 +1,376 @@
/***** spin: msc_tcl.c *****/
/*
* This file is part of the public release of Spin. It is subject to the
* terms in the LICENSE file that is included in this source directory.
* Tool documentation is available at http://spinroot.com
*/
#include <stdlib.h>
#include "spin.h"
#include "version.h"
#define MW 500 /* page width */
#define RH 100 /* right margin */
#define WW 80 /* distance between process lines */
#define HH 12 /* vertical distance between steps */
#define LW 2 /* line width of message arrows */
#define RVC "darkred" /* rendezvous arrows */
#define MPC "darkblue" /* asynchronous message passing arrow */
#define GRC "lightgrey" /* grid lines */
static int MH = 600; /* anticipated page-length */
static FILE *pfd;
static char **I; /* initial procs */
static int *D,*R; /* maps between depth (stepnr) and ldepth (msc-step) */
static short *M; /* x location of each box at index y */
static short *T; /* y index of match for each box at index y */
static char **L; /* text labels */
static int ProcLine[256]; /* active processes */
static int UsedLine[256]; /* process line has at least one entry */
static int ldepth = 1;
static int maxx, TotSteps = 2*4096; /* max nr of steps for simulation output */
static float Scaler = (float) 1.0;
static int xscale = 2;
static int yscale = 1;
static int no_box;
extern int ntrail, s_trail, pno, depth;
extern Symbol *oFname;
extern void exit(int);
extern void putpostlude(void);
static void putpages(void);
static void
psline(int x0, int y0, int x1, int y1, char *color)
{ char *side = "last";
if (x0 == x1) /* gridline */
{ fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags grid -width 1 \n",
xscale*(x0+1)*WW-20, yscale*y0+20,
xscale*(x1+1)*WW-20, yscale*y1+20, color);
fprintf(pfd, ".c lower grid\n");
} else
{ int xm = xscale*(x0+1)*WW + (xscale*(x1 - x0)*WW)/2 - 20; /* mid x */
if (y1 - y0 <= HH+20)
{ y1 = y0+20; /* close enough to horizontal - looks better */
}
fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags mesg -width %d\n",
xscale*(x0+1)*WW-20, yscale*y0+20+10,
xm, yscale*y0+20+10, color, LW);
if (y1 != y0+20)
{ fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags mesg -width %d\n",
xm, yscale*y0+20+10,
xm, yscale*y1+20-10, color, LW);
}
fprintf(pfd, ".c create line %d %d %d %d -fill %s -width %d ",
xm, yscale*y1+20-10,
xscale*(x1+1)*WW-20, yscale*y1+20-10, color, LW);
if (strcmp(color, RVC) == 0)
{ side = "both";
}
fprintf(pfd, "-arrow %s -arrowshape {5 5 5} -tags mesg\n", side);
fprintf(pfd, ".c raise mesg\n");
}
}
static void
colbox(int ix, int iy, int w, int h_unused, char *color)
{ int x = ix*WW;
int y = iy*HH;
if (ix < 0 || ix > 255)
{ fatal("msc_tcl: unexpected\n", (char *) 0);
}
if (ProcLine[ix] < iy)
{ /* if (ProcLine[ix] > 0) */
{ psline(ix-1, ProcLine[ix]*HH+HH+4,
ix-1, iy*HH-HH, GRC);
}
fprintf(pfd, "# ProcLine[%d] from %d to %d (Used %d nobox %d)\n",
ix, ProcLine[ix], iy, UsedLine[ix], no_box);
ProcLine[ix] = iy;
} else
{ fprintf(pfd, "# ProcLine[%d] stays at %d (Used %d nobox %d)\n",
ix, ProcLine[ix], UsedLine[ix], no_box);
}
if (UsedLine[ix])
{ no_box = 2;
}
if (strcmp(color, "black") == 0)
{ if (no_box == 0) /* shadow */
{ fprintf(pfd, ".c create rectangle %d %d %d %d -fill black\n",
xscale*x-(xscale*4*w/3)-20+4, (yscale*y-10)+20+2,
xscale*x+(xscale*4*w/3)-20, (yscale*y+10)+20+2);
}
} else
{ if (no_box == 0) /* box with outline */
{ fprintf(pfd, ".c create rectangle %d %d %d %d -fill ivory\n",
xscale*x-(xscale*4*w/3)-20, (yscale*y-10)+20,
xscale*x+(xscale*4*w/3)-20, (yscale*y+10)+20);
UsedLine[ix]++;
} else /* no outline */
{ fprintf(pfd, ".c create rectangle %d %d %d %d -fill white -width 0\n",
xscale*x-(xscale*4*w/3)-20, (yscale*y-10)+20,
xscale*x+(xscale*4*w/3)-20, (yscale*y+10)+20);
} }
if (no_box > 0)
{ no_box--;
}
}
static void
stepnumber(int i)
{ int y = (yscale*i*HH) + 20;
fprintf(pfd, ".c create text %d %d -fill #eef -text \"%d\"\n",
-10+(xscale*WW)/2, y, i);
/* horizontal dashed grid line */
fprintf(pfd, ".c create line %d %d %d %d -fill #eef -dash {6 4}\n",
-20+WW*xscale, y, (maxx+1)*WW*xscale-20, y);
}
static void
spitbox(int ix, int y, char *s)
{ float bw; /* box width */
char d[256], *t, *z;
int a, i, x = ix+1;
char *color = "black";
if (y > 0)
{ stepnumber(y);
}
bw = (float)1.8*(float)strlen(s); /* guess at default font width */
colbox(x, y, (int) (bw+1.0), 5, "black");
if (s[0] == '~')
{ switch (s[1]) {
default :
case 'R': color = "red"; break;
case 'B': color = "blue"; break;
case 'G': color = "green"; break;
}
s += 2;
} else if (strchr(s, '!'))
{ color = "ivory";
} else if (strchr(s, '?'))
{ color = "azure";
} else
{ color = "pink";
if (sscanf(s, "%d:%250s", &a, d) == 2
&& a >= 0 && a < TotSteps)
{ if (!I[a] || strlen(I[a]) <= strlen(s))
{ I[a] = (char *) emalloc((int) strlen(s)+1);
}
strcpy(I[a], s);
} }
colbox(x, y, (int) bw, 4, color);
z = t = (char *) emalloc(2*strlen(s)+1);
for (i = 0; i < (int) strlen(s); i++)
{ if (s[i] == '\n')
{ continue;
}
if (s[i] == '[' || s[i] == ']')
{ *t++ = '\\';
}
*t++ = s[i];
}
fprintf(pfd, ".c create text %d %d -text \"%s\"\n",
xscale*x*WW-20, yscale*y*HH+20, z);
}
static void
putpages(void)
{ int i, lasti=0; float nmh;
if (maxx*xscale*WW > MW-RH/2)
{ Scaler = (float) (MW-RH/2) / (float) (maxx*xscale*WW);
nmh = (float) MH; nmh /= Scaler; MH = (int) nmh;
fprintf(pfd, "# Scaler %f, MH %d\n", Scaler, MH);
}
if (ldepth >= TotSteps)
{ ldepth = TotSteps-1;
}
/* W: (maxx+2)*xscale*WW */
/* H: ldepth*HH*yscale+50 */
fprintf(pfd, "wm title . \"scenario\"\n");
fprintf(pfd, "wm geometry . %dx600+650+100\n", (maxx+2)*xscale*WW);
fprintf(pfd, "canvas .c -width 800 -height 800 \\\n");
fprintf(pfd, " -scrollregion {0c -1c 30c 100c} \\\n");
fprintf(pfd, " -xscrollcommand \".hscroll set\" \\\n");
fprintf(pfd, " -yscrollcommand \".vscroll set\" \\\n");
fprintf(pfd, " -bg white -relief raised -bd 2\n");
fprintf(pfd, "scrollbar .vscroll -relief sunken ");
fprintf(pfd, " -command \".c yview\"\n");
fprintf(pfd, "scrollbar .hscroll -relief sunken -orient horiz ");
fprintf(pfd, " -command \".c xview\"\n");
fprintf(pfd, "pack append . \\\n");
fprintf(pfd, " .vscroll {right filly} \\\n");
fprintf(pfd, " .hscroll {bottom fillx} \\\n");
fprintf(pfd, " .c {top expand fill}\n");
fprintf(pfd, ".c yview moveto 0\n");
for (i = TotSteps-1; i >= 0; i--)
{ if (I[i])
{ spitbox(i, -1, I[i]);
} }
for (i = 0; i <= ldepth; i++)
{ if (!M[i] && !L[i])
{ continue; /* no box */
}
if (T[i] > 0) /* arrow */
{ if (T[i] == i) /* rv handshake */
{ psline( M[lasti], lasti*HH,
M[i], i*HH, RVC);
} else
{ psline( M[i], i*HH,
M[T[i]], T[i]*HH, MPC);
} }
if (L[i])
{ spitbox(M[i], i, L[i]);
lasti = i;
} }
}
static void
putbox(int x)
{
if (ldepth >= TotSteps)
{ fprintf(stderr, "max length of %d steps exceeded - ps file truncated\n",
TotSteps);
putpostlude();
}
M[ldepth] = x;
if (x > maxx)
{ maxx = x;
fprintf(pfd, "# maxx %d\n", x);
}
}
/* functions called externally: */
extern int WhatSeed(void);
void
putpostlude(void)
{ char cmd[512];
putpages();
fprintf(pfd, ".c lower grid\n");
fprintf(pfd, ".c raise mesg\n");
fclose(pfd);
fprintf(stderr, "seed used: -n%d\n", WhatSeed());
sprintf(cmd, "wish -f %s.tcl &", oFname?oFname->name:"msc");
fprintf(stderr, "%s\n", cmd);
(void) unlink("pan.pre");
exit (system(cmd));
}
void
putprelude(void)
{ char snap[256]; FILE *fd;
sprintf(snap, "%s.tcl", oFname?oFname->name:"msc");
if (!(pfd = fopen(snap, MFLAGS)))
{ fatal("cannot create file '%s'", snap);
}
if (s_trail)
{ if (ntrail)
sprintf(snap, "%s%d.trail", oFname?oFname->name:"msc", ntrail);
else
sprintf(snap, "%s.trail", oFname?oFname->name:"msc");
if (!(fd = fopen(snap, "r")))
{ snap[strlen(snap)-2] = '\0';
if (!(fd = fopen(snap, "r")))
fatal("cannot open trail file", (char *) 0);
}
TotSteps = 1;
while (fgets(snap, 256, fd)) TotSteps++;
fclose(fd);
}
TotSteps *= 2;
R = (int *) emalloc(TotSteps * sizeof(int));
D = (int *) emalloc(TotSteps * sizeof(int));
M = (short *) emalloc(TotSteps * sizeof(short));
T = (short *) emalloc(TotSteps * sizeof(short));
L = (char **) emalloc(TotSteps * sizeof(char *));
I = (char **) emalloc(TotSteps * sizeof(char *));
}
void
putarrow(int from, int to)
{
/* from rv if from == to */
/* which means that D[from] == D[to] */
/* which means that T[x] == x */
if (from < TotSteps
&& to < TotSteps
&& D[from] < TotSteps)
{ T[D[from]] = D[to];
}
}
void
pstext(int x, char *s)
{ char *tmp = emalloc((int) strlen(s)+1);
strcpy(tmp, s);
if (depth == 0)
{ I[x] = tmp;
} else
{ if (depth >= TotSteps || ldepth >= TotSteps)
{ fprintf(stderr, "spin: error: max nr of %d steps exceeded\n",
TotSteps);
fatal("use -uN to limit steps", (char *) 0);
}
putbox(x);
D[depth] = ldepth;
R[ldepth] = depth;
L[ldepth] = tmp;
ldepth += 2;
}
}
void
dotag(FILE *fd, char *s)
{ extern int columns, notabs; extern RunList *X;
int i = (!strncmp(s, "MSC: ", 5))?5:0;
int pid = s_trail ? pno : (X?X->pid:0);
if (columns == 2)
{ pstext(pid, &s[i]);
} else
{ if (!notabs)
{ printf(" ");
for (i = 0; i <= pid; i++)
{ printf(" ");
} }
fprintf(fd, "%s", s);
fflush(fd);
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,20 @@
/***** spin: pangen3.c *****/ /***** spin: pangen3.c *****/
/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 "spin.h"
#include "y.tab.h" #include "y.tab.h"
#include <assert.h>
extern FILE *th; extern FILE *th, *tc;
extern int claimnr, eventmapnr; extern int eventmapnr, old_priority_rules;
typedef struct SRC { typedef struct SRC {
short ln, st; /* linenr, statenr */ int ln, st; /* linenr, statenr */
Symbol *fn; /* filename */ Symbol *fn; /* filename */
struct SRC *nxt; struct SRC *nxt;
} SRC; } SRC;
@ -28,16 +26,18 @@ static int lastfrom;
static SRC *frst = (SRC *) 0; static SRC *frst = (SRC *) 0;
static SRC *skip = (SRC *) 0; static SRC *skip = (SRC *) 0;
extern int ltl_mode;
extern void sr_mesg(FILE *, int, int); extern void sr_mesg(FILE *, int, int);
static void static void
putnr(int n) putnr(int n)
{ {
if (col++ == 8) if (col++ == 8)
{ fprintf(th, "\n\t"); { fprintf(tc, "\n\t"); /* was th */
col = 1; col = 1;
} }
fprintf(th, "%3d, ", n); fprintf(tc, "%3d, ", n); /* was th */
} }
static void static void
@ -47,7 +47,7 @@ putfnm(int j, Symbol *s)
return; return;
if (lastfnm) if (lastfnm)
fprintf(th, "{ %s, %d, %d },\n\t", fprintf(tc, "{ \"%s\", %d, %d },\n\t", /* was th */
lastfnm->name, lastfnm->name,
lastfrom, lastfrom,
j-1); j-1);
@ -59,73 +59,118 @@ static void
putfnm_flush(int j) putfnm_flush(int j)
{ {
if (lastfnm) if (lastfnm)
fprintf(th, "{ %s, %d, %d }\n", fprintf(tc, "{ \"%s\", %d, %d }\n", /* was th */
lastfnm->name, lastfnm->name,
lastfrom, j); lastfrom, j);
} }
static SRC *
newsrc(int m, SRC *n)
{ SRC *tmp;
tmp = (SRC *) emalloc(sizeof(SRC));
tmp->st = m;
tmp->nxt = n;
return tmp;
}
void void
putskip(int m) /* states that need not be reached */ putskip(int m) /* states that need not be reached */
{ SRC *tmp; { SRC *tmp, *lst = (SRC *)0;
/* 6.4.0: now an ordered list */
for (tmp = skip; tmp; tmp = tmp->nxt) for (tmp = skip; tmp; lst = tmp, tmp = tmp->nxt)
if (tmp->st == m) { if (tmp->st == m)
return; { return;
tmp = (SRC *) emalloc(sizeof(SRC)); }
tmp->st = (short) m; if (tmp->st > m) /* insert before */
tmp->nxt = skip; { if (tmp == skip)
skip = tmp; { tmp = newsrc(m, skip);
skip = tmp;
} else
{ assert(lst);
tmp = newsrc(m, lst->nxt);
lst->nxt = tmp;
}
return;
} }
/* insert at the end */
if (lst)
{ lst->nxt = newsrc(m, 0);
} else /* empty list */
{ skip = newsrc(m, 0);
}
} }
void void
unskip(int m) /* a state that needs to be reached after all */ unskip(int m) /* a state that needs to be reached after all */
{ SRC *tmp, *lst=(SRC *)0; { SRC *tmp, *lst = (SRC *)0;
for (tmp = skip; tmp; lst = tmp, tmp = tmp->nxt) for (tmp = skip; tmp; lst = tmp, tmp = tmp->nxt)
if (tmp->st == m) { if (tmp->st == m)
{ if (tmp == skip) { if (tmp == skip)
skip = skip->nxt; skip = skip->nxt;
else else if (lst) /* always true, but helps coverity */
lst->nxt = tmp->nxt; lst->nxt = tmp->nxt;
break; break;
} }
if (tmp->st > m)
{ break; /* m is not in list */
} }
} }
void void
putsrc(Element *e) /* match states to source lines */ putsrc(Element *e) /* match states to source lines */
{ SRC *tmp; { SRC *tmp, *lst = (SRC *)0;
int n, m; int n, m;
if (!e || !e->n) return; if (!e || !e->n) return;
n = e->n->ln; n = e->n->ln;
m = e->seqno; m = e->seqno;
/* 6.4.0: now an ordered list */
for (tmp = frst; tmp; tmp = tmp->nxt) for (tmp = frst; tmp; lst = tmp, tmp = tmp->nxt)
if (tmp->st == m) { if (tmp->st == m)
{ if (tmp->ln != n || tmp->fn != e->n->fn) { if (tmp->ln != n || tmp->fn != e->n->fn)
printf("putsrc mismatch %d - %d, file %s\n", n, printf("putsrc mismatch seqno %d, line %d - %d, file %s\n", m, n,
tmp->ln, tmp->fn->name); tmp->ln, tmp->fn->name);
return; return;
} }
tmp = (SRC *) emalloc(sizeof(SRC)); if (tmp->st > m) /* insert before */
tmp->ln = (short) n; { if (tmp == frst)
tmp->st = (short) m; { tmp = newsrc(m, frst);
frst = tmp;
} else
{ assert(lst);
tmp = newsrc(m, lst->nxt);
lst->nxt = tmp;
}
tmp->ln = n;
tmp->fn = e->n->fn;
return;
} }
/* insert at the end */
tmp = newsrc(m, lst?lst->nxt:0);
tmp->ln = n;
tmp->fn = e->n->fn; tmp->fn = e->n->fn;
tmp->nxt = frst; if (lst)
frst = tmp; { lst->nxt = tmp;
} else
{ frst = tmp;
}
} }
static void static void
dumpskip(int n, int m) dumpskip(int n, int m)
{ SRC *tmp, *lst; { SRC *tmp, *lst;
FILE *tz = tc; /* was th */
int j; int j;
fprintf(th, "uchar reached%d [] = {\n\t", m); fprintf(tz, "uchar reached%d [] = {\n\t", m);
tmp = skip;
lst = (SRC *) 0;
for (j = 0, col = 0; j <= n; j++) for (j = 0, col = 0; j <= n; j++)
{ lst = (SRC *) 0; { /* find j in the sorted list */
for (tmp = skip; tmp; lst = tmp, tmp = tmp->nxt) for ( ; tmp; lst = tmp, tmp = tmp->nxt)
if (tmp->st == j) { if (tmp->st == j)
{ putnr(1); { putnr(1);
if (lst) if (lst)
lst->nxt = tmp->nxt; lst->nxt = tmp->nxt;
@ -133,12 +178,17 @@ dumpskip(int n, int m)
skip = tmp->nxt; skip = tmp->nxt;
break; break;
} }
if (tmp->st > j)
{ putnr(0);
break; /* j is not in the list */
} }
if (!tmp) if (!tmp)
putnr(0); { putnr(0);
} } }
fprintf(th, "};\n"); fprintf(tz, "};\n");
if (m == claimnr) fprintf(tz, "uchar *loopstate%d;\n", m);
fprintf(th, "#define reached_claim reached%d\n", m);
if (m == eventmapnr) if (m == eventmapnr)
fprintf(th, "#define reached_event reached%d\n", m); fprintf(th, "#define reached_event reached%d\n", m);
@ -149,27 +199,34 @@ void
dumpsrc(int n, int m) dumpsrc(int n, int m)
{ SRC *tmp, *lst; { SRC *tmp, *lst;
int j; int j;
static int did_claim = 0;
FILE *tz = tc; /* was th */
fprintf(th, "short src_ln%d [] = {\n\t", m); fprintf(tz, "\nshort src_ln%d [] = {\n\t", m);
tmp = frst;
for (j = 0, col = 0; j <= n; j++) for (j = 0, col = 0; j <= n; j++)
{ lst = (SRC *) 0; { for ( ; tmp; tmp = tmp->nxt)
for (tmp = frst; tmp; lst = tmp, tmp = tmp->nxt) { if (tmp->st == j)
if (tmp->st == j)
{ putnr(tmp->ln); { putnr(tmp->ln);
break; break;
} }
if (tmp->st > j)
{ putnr(0);
break;
} }
if (!tmp) if (!tmp)
putnr(0); { putnr(0);
} } }
fprintf(th, "};\n"); fprintf(tz, "};\n");
lastfnm = (Symbol *) 0; lastfnm = (Symbol *) 0;
lastdef.name = "\"-\""; lastdef.name = "-";
fprintf(th, "S_F_MAP src_file%d [] = {\n\t", m); fprintf(tz, "S_F_MAP src_file%d [] = {\n\t", m);
tmp = frst;
lst = (SRC *) 0;
for (j = 0, col = 0; j <= n; j++) for (j = 0, col = 0; j <= n; j++)
{ lst = (SRC *) 0; { for ( ; tmp; lst = tmp, tmp = tmp->nxt)
for (tmp = frst; tmp; lst = tmp, tmp = tmp->nxt) { if (tmp->st == j)
if (tmp->st == j)
{ putfnm(j, tmp->fn); { putfnm(j, tmp->fn);
if (lst) if (lst)
lst->nxt = tmp->nxt; lst->nxt = tmp->nxt;
@ -177,14 +234,20 @@ dumpsrc(int n, int m)
frst = tmp->nxt; frst = tmp->nxt;
break; break;
} }
if (tmp->st > j)
{ putfnm(j, &lastdef);
break;
} }
if (!tmp) if (!tmp)
putfnm(j, &lastdef); { putfnm(j, &lastdef);
} } }
putfnm_flush(j); putfnm_flush(j);
fprintf(th, "};\n"); fprintf(tz, "};\n");
if (m == claimnr) if (pid_is_claim(m) && !did_claim)
fprintf(th, "#define src_claim src_ln%d\n", m); { fprintf(tz, "short *src_claim;\n");
did_claim++;
}
if (m == eventmapnr) if (m == eventmapnr)
fprintf(th, "#define src_event src_ln%d\n", m); fprintf(th, "#define src_event src_ln%d\n", m);
@ -237,7 +300,27 @@ comwork(FILE *fd, Lextok *now, int m)
case GT: Cat1(">"); break; case GT: Cat1(">"); break;
case LT: Cat1("<"); break; case LT: Cat1("<"); break;
case NE: Cat1("!="); break; case NE: Cat1("!="); break;
case EQ: Cat1("=="); break; case EQ:
if (ltl_mode
&& now->lft->ntyp == 'p'
&& now->rgt->ntyp == 'q') /* remote ref */
{ Lextok *p = now->lft->lft;
fprintf(fd, "(");
fprintf(fd, "%s", p->sym->name);
if (p->lft)
{ fprintf(fd, "[");
putstmnt(fd, p->lft, 0); /* pid */
fprintf(fd, "]");
}
fprintf(fd, "@");
fprintf(fd, "%s", now->rgt->sym->name);
fprintf(fd, ")");
break;
}
Cat1("==");
break;
case OR: Cat1("||"); break; case OR: Cat1("||"); break;
case AND: Cat1("&&"); break; case AND: Cat1("&&"); break;
case LSHIFT: Cat1("<<"); break; case LSHIFT: Cat1("<<"); break;
@ -298,6 +381,22 @@ comwork(FILE *fd, Lextok *now, int m)
case ENABLED: Cat3("enabled(", now->lft, ")"); case ENABLED: Cat3("enabled(", now->lft, ")");
break; break;
case GET_P: if (old_priority_rules)
{ fprintf(fd, "1");
} else
{ Cat3("get_priority(", now->lft, ")");
}
break;
case SET_P: if (!old_priority_rules)
{ fprintf(fd, "set_priority(");
comwork(fd, now->lft->lft, m);
fprintf(fd, ", ");
comwork(fd, now->lft->rgt, m);
fprintf(fd, ")");
}
break;
case EVAL: Cat3("eval(", now->lft, ")"); case EVAL: Cat3("eval(", now->lft, ")");
break; break;
@ -320,12 +419,14 @@ comwork(FILE *fd, Lextok *now, int m)
} }
break; break;
case ASGN: comwork(fd,now->lft,m); case ASGN:
if (check_track(now) == STRUCT) { break; }
comwork(fd,now->lft,m);
fprintf(fd," = "); fprintf(fd," = ");
comwork(fd,now->rgt,m); comwork(fd,now->rgt,m);
break; break;
case PRINT: { char c, buf[512]; case PRINT: { char c, buf[1024];
strncpy(buf, now->sym->name, 510); strncpy(buf, now->sym->name, 510);
for (i = j = 0; i < 510; i++, j++) for (i = j = 0; i < 510; i++, j++)
{ c = now->sym->name[i]; { c = now->sym->name[i];
@ -349,9 +450,23 @@ comwork(FILE *fd, Lextok *now, int m)
comwork(fd, now->lft, m); comwork(fd, now->lft, m);
fprintf(fd, ")"); fprintf(fd, ")");
break; break;
case NAME: putname(fd, "", now, m, ""); case NAME:
putname(fd, "", now, m, "");
break; break;
case 'p': putremote(fd, now, m);
case 'p':
if (ltl_mode)
{ fprintf(fd, "%s", now->lft->sym->name); /* proctype */
if (now->lft->lft)
{ fprintf(fd, "[");
putstmnt(fd, now->lft->lft, 0); /* pid */
fprintf(fd, "]");
}
fprintf(fd, ":"); /* remote varref */
fprintf(fd, "%s", now->sym->name); /* varname */
break;
}
putremote(fd, now, m);
break; break;
case 'q': fprintf(fd, "%s", now->sym->name); case 'q': fprintf(fd, "%s", now->sym->name);
break; break;
@ -366,7 +481,7 @@ comwork(FILE *fd, Lextok *now, int m)
case ELSE: fprintf(fd, "else"); break; case ELSE: fprintf(fd, "else"); break;
case '@': fprintf(fd, "-end-"); break; case '@': fprintf(fd, "-end-"); break;
case D_STEP: fprintf(fd, "D_STEP"); break; case D_STEP: fprintf(fd, "D_STEP%d", now->ln); break;
case ATOMIC: fprintf(fd, "ATOMIC"); break; case ATOMIC: fprintf(fd, "ATOMIC"); break;
case NON_ATOMIC: fprintf(fd, "sub-sequence"); break; case NON_ATOMIC: fprintf(fd, "sub-sequence"); break;
case IF: fprintf(fd, "IF"); break; case IF: fprintf(fd, "IF"); break;

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,10 @@
/***** spin: pangen4.c *****/ /***** spin: pangen4.c *****/
/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 "spin.h"
#include "y.tab.h" #include "y.tab.h"
@ -17,7 +14,7 @@ extern Queue *qtab;
extern Symbol *Fname; extern Symbol *Fname;
extern int lineno, m_loss, Pid, eventmapnr, multi_oval; extern int lineno, m_loss, Pid, eventmapnr, multi_oval;
extern short nocast, has_provided, has_sorted; extern short nocast, has_provided, has_sorted;
extern char *R13[], *R14[], *R15[]; extern const char *R13[], *R14[], *R15[];
static void check_proc(Lextok *, int); static void check_proc(Lextok *, int);
@ -44,7 +41,7 @@ undostmnt(Lextok *now, int m)
case FULL: case EMPTY: case 'R': case FULL: case EMPTY: case 'R':
case NFULL: case NEMPTY: case ENABLED: case NFULL: case NEMPTY: case ENABLED:
case '?': case PC_VAL: case '^': case '?': case PC_VAL: case '^':
case C_EXPR: case C_EXPR: case GET_P:
case NONPROGRESS: case NONPROGRESS:
putstmnt(tb, now, m); putstmnt(tb, now, m);
break; break;
@ -153,7 +150,14 @@ undostmnt(Lextok *now, int m)
fprintf(tb, "p_restor(II);\n\t\t"); fprintf(tb, "p_restor(II);\n\t\t");
break; break;
case SET_P:
fprintf(tb, "((P0 *)pptr((trpt->o_priority >> 8)))");
fprintf(tb, "->_priority = trpt->o_priority & 255");
break;
case ASGN: case ASGN:
if (check_track(now) == STRUCT) { break; }
nocast=1; putstmnt(tb,now->lft,m); nocast=1; putstmnt(tb,now->lft,m);
nocast=0; fprintf(tb, " = trpt->bup.oval"); nocast=0; fprintf(tb, " = trpt->bup.oval");
if (multi_oval > 0) if (multi_oval > 0)
@ -307,6 +311,8 @@ genunio(void)
ntimes(tc, 0, 1, R15); ntimes(tc, 0, 1, R15);
} }
extern void explain(int);
int int
proper_enabler(Lextok *n) proper_enabler(Lextok *n)
{ {
@ -317,15 +323,19 @@ proper_enabler(Lextok *n)
case LEN: case 'R': case LEN: case 'R':
case NAME: case NAME:
has_provided = 1; has_provided = 1;
if (strcmp(n->sym->name, "_pid") == 0) if (strcmp(n->sym->name, "_pid") == 0
|| strcmp(n->sym->name, "_priority") == 0)
return 1; return 1;
return (!(n->sym->context)); return (!(n->sym->context));
case CONST: case TIMEOUT: case C_EXPR:
case CONST:
case TIMEOUT:
has_provided = 1; has_provided = 1;
return 1; return 1;
case ENABLED: case PC_VAL: case ENABLED: case PC_VAL:
case GET_P: /* not SET_P */
return proper_enabler(n->lft); return proper_enabler(n->lft);
case '!': case UMIN: case '~': case '!': case UMIN: case '~':
@ -335,10 +345,14 @@ proper_enabler(Lextok *n)
case '%': case LT: case GT: case '&': case '^': case '%': case LT: case GT: case '&': case '^':
case '|': case LE: case GE: case NE: case '?': case '|': case LE: case GE: case NE: case '?':
case EQ: case OR: case AND: case LSHIFT: case EQ: case OR: case AND: case LSHIFT:
case RSHIFT: case 'c': case RSHIFT: case 'c': /* case ',': */
return proper_enabler(n->lft) && proper_enabler(n->rgt); return proper_enabler(n->lft) && proper_enabler(n->rgt);
default: default:
break; break;
} }
printf("spin: saw ");
explain(n->ntyp);
printf("\n");
return 0; return 0;
} }

View file

@ -1,24 +1,21 @@
/***** spin: pangen4.h *****/ /***** spin: pangen4.h *****/
/* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* this introductory message is not removed and no monies are exchanged. */ *
/* Software written by Gerard J. Holzmann. For tool documentation see: */ * The DFA code below was written by Anuj Puri and Gerard J. Holzmann in
/* http://spinroot.com/ */ * May 1997, and was inspired by earlier work on data compression using
/* Send all bug-reports and/or questions to: bugs@spinroot.com */ * sharing tree data structures and graph-encoded sets by J-Ch. Gregoire
* (INRS Telecom, Quebec, Canada) and D.Zampunieris (Univ.Namur, Belgium)
* The splay routine code included here is based on the public domain
* version written by D. Sleator <sleator@cs.cmu.edu> in 1992.
*/
/* The DFA code below was written by Anuj Puri and Gerard J. Holzmann in */ static const char *Dfa[] = {
/* May 1997, and was inspired by earlier work on data compression using */
/* sharing tree data structures and graph-encoded sets by J-Ch. Gregoire */
/* (INRS Telecom, Quebec, Canada) and D.Zampunieris (Univ.Namur, Belgium) */
/* The splay routine code included here is based on the public domain */
/* version written by D. Sleator <sleator@cs.cmu.edu> in 1992. */
static char *Dfa[] = {
"#ifdef MA", "#ifdef MA",
#if 0
"/*", "/*",
"#include <stdio.h>", "#include <stdio.h>",
"#define uchar unsigned char", "#define uchar unsigned char",
@ -26,6 +23,7 @@ static char *Dfa[] = {
"#define ulong unsigned long", "#define ulong unsigned long",
"#define ushort unsigned short", "#define ushort unsigned short",
"", "",
#endif
"#define TWIDTH 256", "#define TWIDTH 256",
"#define HASH(y,n) (n)*(((long)y))", "#define HASH(y,n) (n)*(((long)y))",
"#define INRANGE(e,h) ((h>=e->From && h<=e->To)||(e->s==1 && e->S==h))", "#define INRANGE(e,h) ((h>=e->From && h<=e->To)||(e->s==1 && e->S==h))",
@ -466,7 +464,7 @@ static char *Dfa[] = {
" for (j = 0; j < TWIDTH; j++)", " for (j = 0; j < TWIDTH; j++)",
" for (i = 0; i < dfa_depth+1; i++)", " for (i = 0; i < dfa_depth+1; i++)",
" cnt += tree_stats(layers[i*TWIDTH+j]);", " cnt += tree_stats(layers[i*TWIDTH+j]);",
" printf(\"Minimized Automaton:\t%%6d nodes and %%6g edges\\n\",", " printf(\"Minimized Automaton:\t%%6lu nodes and %%6g edges\\n\",",
" nr_states, cnt);", " nr_states, cnt);",
"}", "}",
"", "",

View file

@ -1,13 +1,10 @@
/***** spin: pangen5.c *****/ /***** spin: pangen5.c *****/
/* Copyright (c) 1999-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 "spin.h"
#include "y.tab.h" #include "y.tab.h"
@ -140,6 +137,7 @@ eligible(FSM_trans *v)
|| lt->ntyp == C_CODE || lt->ntyp == C_CODE
|| lt->ntyp == C_EXPR || lt->ntyp == C_EXPR
|| has_lab(el, 0) /* any label at all */ || has_lab(el, 0) /* any label at all */
|| lt->ntyp == SET_P /* to prevent multiple set_p merges */
|| lt->ntyp == DO || lt->ntyp == DO
|| lt->ntyp == UNLESS || lt->ntyp == UNLESS
@ -211,13 +209,18 @@ popbuild(void)
static int static int
build_step(FSM_trans *v) build_step(FSM_trans *v)
{ FSM_state *f; { FSM_state *f;
Element *el = v->step; Element *el;
#if 0 #if 0
Lextok *lt = ZN; Lextok *lt = ZN;
#endif #endif
int st = v->to; int st;
int r; int r;
if (!v) return -1;
el = v->step;
st = v->to;
if (!el) return -1; if (!el) return -1;
if (v->step->merge) if (v->step->merge)
@ -234,9 +237,7 @@ build_step(FSM_trans *v)
lt = v->step->n; lt = v->step->n;
if (verbose&32) if (verbose&32)
{ if (++howdeep == 1) { if (++howdeep == 1)
printf("spin: %s, line %3d, merge:\n", printf("spin: %s:%d, merge:\n", lt->fn->name, lt->ln);
lt->fn->name,
lt->ln);
printf("\t[%d] <seqno %d>\t", howdeep, el->seqno); printf("\t[%d] <seqno %d>\t", howdeep, el->seqno);
comment(stdout, lt, 0); comment(stdout, lt, 0);
printf(";\n"); printf(";\n");
@ -257,7 +258,7 @@ build_step(FSM_trans *v)
} }
static void static void
FSM_MERGER(char *pname_unused) /* find candidates for safely merging steps */ FSM_MERGER(/* char *pname */ void) /* find candidates for safely merging steps */
{ FSM_state *f, *g; { FSM_state *f, *g;
FSM_trans *t; FSM_trans *t;
Lextok *lt; Lextok *lt;
@ -281,14 +282,14 @@ FSM_MERGER(char *pname_unused) /* find candidates for safely merging steps */
continue; continue;
g = fsm_tbl[t->to]; g = fsm_tbl[t->to];
if (!eligible(g->t)) if (!g || !eligible(g->t))
{ {
#define SINGLES #define SINGLES
#ifdef SINGLES #ifdef SINGLES
t->step->merge_single = t->to; t->step->merge_single = t->to;
#if 0 #if 0
if ((verbose&32)) if ((verbose&32))
{ printf("spin: %s, line %3d, merge_single:\n\t<seqno %d>\t", { printf("spin: %s:%d, merge_single:\n\t<seqno %d>\t",
t->step->n->fn->name, t->step->n->fn->name,
t->step->n->ln, t->step->n->ln,
t->step->seqno); t->step->seqno);
@ -321,14 +322,17 @@ FSM_MERGER(char *pname_unused) /* find candidates for safely merging steps */
lt = t->step->n; lt = t->step->n;
#if 0 #if 0
4.1.3: 4.1.3:
an rv send operation inside an atomic, *loses* atomicity an rv send operation ('s') inside an atomic, *loses* atomicity
when executed when executed, and should therefore never be merged with a subsequent
and should therefore never be merged with a subsequent
statement within the atomic sequence statement within the atomic sequence
the same is not true for non-rv send operations the same is not true for non-rv send operations;
6.2.2:
RUN statements can start a new process at a higher priority level
which interferes with statement merging, so it too is not a suitable
merge target
#endif #endif
if (lt->ntyp == 'c' /* potentially blocking stmnts */ if ((lt->ntyp == 'c' && !any_oper(lt->lft, RUN)) /* 2nd clause 6.2.2 */
|| lt->ntyp == 'r' || lt->ntyp == 'r'
|| (lt->ntyp == 's' && u_sync == 0)) /* added !u_sync in 4.1.3 */ || (lt->ntyp == 's' && u_sync == 0)) /* added !u_sync in 4.1.3 */
{ if (!canfill_in(t)) /* atomic, non-global, etc. */ { if (!canfill_in(t)) /* atomic, non-global, etc. */
@ -346,9 +350,8 @@ FSM_MERGER(char *pname_unused) /* find candidates for safely merging steps */
#if 0 #if 0
if ((verbose&32) if ((verbose&32)
&& t->step->merge_start) && t->step->merge_start)
{ printf("spin: %s, line %3d, merge_START:\n\t<seqno %d>\t", { printf("spin: %s:%d, merge_START:\n\t<seqno %d>\t",
lt->fn->name, lt->fn->name, lt->ln,
lt->ln,
t->step->seqno); t->step->seqno);
comment(stdout, lt, 0); comment(stdout, lt, 0);
printf(";\n"); printf(";\n");
@ -532,6 +535,7 @@ ana_var(FSM_trans *t, Lextok *now, int usage)
if (now->sym->name[0] == '_' if (now->sym->name[0] == '_'
&& (strcmp(now->sym->name, "_") == 0 && (strcmp(now->sym->name, "_") == 0
|| strcmp(now->sym->name, "_pid") == 0 || strcmp(now->sym->name, "_pid") == 0
|| strcmp(now->sym->name, "_priority") == 0
|| strcmp(now->sym->name, "_last") == 0)) || strcmp(now->sym->name, "_last") == 0))
return; return;
@ -588,10 +592,17 @@ ana_stmnt(FSM_trans *t, Lextok *now, int usage)
case C_EXPR: case C_EXPR:
break; break;
case ',': /* reached with SET_P and array initializers */
if (now->lft && now->lft->rgt)
{ ana_stmnt(t, now->lft->rgt, RVAL);
}
break;
case '!': case '!':
case UMIN: case UMIN:
case '~': case '~':
case ENABLED: case ENABLED:
case GET_P:
case PC_VAL: case PC_VAL:
case LEN: case LEN:
case FULL: case FULL:
@ -603,6 +614,11 @@ ana_stmnt(FSM_trans *t, Lextok *now, int usage)
ana_stmnt(t, now->lft, RVAL); ana_stmnt(t, now->lft, RVAL);
break; break;
case SET_P:
ana_stmnt(t, now->lft, RVAL); /* ',' */
ana_stmnt(t, now->lft->rgt, RVAL);
break;
case '/': case '/':
case '*': case '*':
case '-': case '-':
@ -626,8 +642,11 @@ ana_stmnt(FSM_trans *t, Lextok *now, int usage)
break; break;
case ASGN: case ASGN:
if (check_track(now) == STRUCT) { break; }
ana_stmnt(t, now->lft, LVAL); ana_stmnt(t, now->lft, LVAL);
ana_stmnt(t, now->rgt, RVAL); if (now->rgt->ntyp)
ana_stmnt(t, now->rgt, RVAL);
break; break;
case PRINT: case PRINT:
@ -679,7 +698,8 @@ ana_stmnt(FSM_trans *t, Lextok *now, int usage)
break; break;
default: default:
printf("spin: bad node type %d line %d (ana_stmnt)\n", now->ntyp, now->ln); printf("spin: %s:%d, bad node type %d (ana_stmnt)\n",
now->fn->name, now->ln, now->ntyp);
fatal("aborting", (char *) 0); fatal("aborting", (char *) 0);
} }
} }
@ -692,10 +712,7 @@ ana_src(int dataflow, int merger) /* called from main.c and guided.c */
int counter = 1; int counter = 1;
#endif #endif
for (p = rdy; p; p = p->nxt) for (p = rdy; p; p = p->nxt)
{ if (p->tn == eventmapnr {
|| p->tn == claimnr)
continue;
ana_seq(p->s); ana_seq(p->s);
fsm_table(); fsm_table();
@ -711,7 +728,7 @@ ana_src(int dataflow, int merger) /* called from main.c and guided.c */
{ FSM_ANA(); { FSM_ANA();
} }
if (merger) if (merger)
{ FSM_MERGER(p->n->name); { FSM_MERGER(/* p->n->name */);
huntele(e, e->status, -1)->merge_in = 1; /* start-state */ huntele(e, e->status, -1)->merge_in = 1; /* start-state */
#if 0 #if 0
printf("\n"); printf("\n");
@ -726,8 +743,7 @@ ana_src(int dataflow, int merger) /* called from main.c and guided.c */
{ {
if (!(e->status&DONE) && (verbose&32)) if (!(e->status&DONE) && (verbose&32))
{ printf("unreachable code: "); { printf("unreachable code: ");
printf("%s, line %3d: ", printf("%s:%3d ", e->n->fn->name, e->n->ln);
e->n->fn->name, e->n->ln);
comment(stdout, e->n, 0); comment(stdout, e->n, 0);
printf("\n"); printf("\n");
} }
@ -735,7 +751,7 @@ ana_src(int dataflow, int merger) /* called from main.c and guided.c */
} }
if (export_ast) if (export_ast)
{ AST_slice(); { AST_slice();
exit(0); alldone(0); /* changed in 5.3.0: was exit(0) */
} }
} }
@ -831,9 +847,15 @@ ana_seq(Sequence *s)
{ if (e->n->ntyp == GOTO) { if (e->n->ntyp == GOTO)
{ g = get_lab(e->n, 1); { g = get_lab(e->n, 1);
g = huntele(g, e->status, -1); g = huntele(g, e->status, -1);
if (!g)
{ fatal("unexpected error 2", (char *) 0);
}
To = g->seqno; To = g->seqno;
} else if (e->nxt) } else if (e->nxt)
{ g = huntele(e->nxt, e->status, -1); { g = huntele(e->nxt, e->status, -1);
if (!g)
{ fatal("unexpected error 3", (char *) 0);
}
To = g->seqno; To = g->seqno;
} else } else
To = 0; To = 0;

View file

@ -1,15 +1,12 @@
/***** spin: pangen5.h *****/ /***** spin: pangen5.h *****/
/* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 */
static char *Xpt[] = { static const char *Xpt[] = {
"#if defined(MA) && (defined(W_XPT) || defined(R_XPT))", "#if defined(MA) && (defined(W_XPT) || defined(R_XPT))",
"static Vertex **temptree;", "static Vertex **temptree;",
"static char wbuf[4096];", "static char wbuf[4096];",
@ -80,7 +77,7 @@ static char *Xpt[] = {
" int i, j; uchar c;", " int i, j; uchar c;",
" static uchar xwarned = 0;", " static uchar xwarned = 0;",
"", "",
" sprintf(nm, \"%%s.xpt\", Source);", " sprintf(nm, \"%%s.xpt\", PanSource);",
" if ((fd = creat(nm, 0666)) <= 0)", " if ((fd = creat(nm, 0666)) <= 0)",
" if (!xwarned)", " if (!xwarned)",
" { xwarned = 1;", " { xwarned = 1;",
@ -136,7 +133,7 @@ static char *Xpt[] = {
" stacker[dfa_depth-1] = 0; r = dfa_store(stacker);", " stacker[dfa_depth-1] = 0; r = dfa_store(stacker);",
" stacker[dfa_depth-1] = 4; j = dfa_member(dfa_depth-1);", " stacker[dfa_depth-1] = 4; j = dfa_member(dfa_depth-1);",
" if (r != 1 || j != 0)", " if (r != 1 || j != 0)",
" { printf(\"%%d: \", stackcnt);", " { printf(\"%%lu: \", stackcnt);",
" for (i = 0; i < dfa_depth; i++)", " for (i = 0; i < dfa_depth; i++)",
" printf(\"%%d,\", stacker[i]);", " printf(\"%%d,\", stacker[i]);",
" printf(\" -- not a stackstate <o:%%d,4:%%d>\\n\", r, j);", " printf(\" -- not a stackstate <o:%%d,4:%%d>\\n\", r, j);",
@ -372,7 +369,7 @@ static char *Xpt[] = {
" int i, j;", " int i, j;",
"", "",
" wcnt = 0;", " wcnt = 0;",
" sprintf(nm, \"%%s.xpt\", Source);", " sprintf(nm, \"%%s.xpt\", PanSource);",
" if ((fd = open(nm, 0)) < 0) /* O_RDONLY */", " if ((fd = open(nm, 0)) < 0) /* O_RDONLY */",
" Uerror(\"cannot open checkpoint file\");", " Uerror(\"cannot open checkpoint file\");",
"", "",
@ -416,7 +413,7 @@ static char *Xpt[] = {
" x_cleanup(d);", " x_cleanup(d);",
" close(fd);", " close(fd);",
"", "",
" printf(\"pan: removed %%d stackstates\\n\", stackcnt);", " printf(\"pan: removed %%lu stackstates\\n\", stackcnt);",
" nstates -= (double) stackcnt;", " nstates -= (double) stackcnt;",
"}", "}",
"#endif", "#endif",

View file

@ -1,20 +1,10 @@
/***** spin: pangen6.c *****/ /***** spin: pangen6.c *****/
/* Copyright (c) 2000-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 */
/* Abstract syntax tree analysis / slicing (spin option -A) */
/* AST_store stores the fsms's for each proctype */
/* AST_track keeps track of variables used in properties */
/* AST_slice starts the slicing algorithm */
/* it first collects more info and then calls */
/* AST_criteria to process the slice criteria */
#include "spin.h" #include "spin.h"
#include "y.tab.h" #include "y.tab.h"
@ -90,7 +80,6 @@ static Slicer *slicer;
static Slicer *rel_vars; /* all relevant variables */ static Slicer *rel_vars; /* all relevant variables */
static int AST_Changes; static int AST_Changes;
static int AST_Round; static int AST_Round;
static FSM_state no_state;
static RPN *rpn; static RPN *rpn;
static int in_recv = 0; static int in_recv = 0;
@ -145,7 +134,7 @@ name_def_indices(Lextok *n, int code)
{ {
if (!n || !n->sym) return; if (!n || !n->sym) return;
if (n->sym->nel != 1) if (n->sym->nel > 1 || n->sym->isarray)
def_use(n->lft, code); /* process the index */ def_use(n->lft, code); /* process the index */
if (n->sym->type == STRUCT /* and possible deeper ones */ if (n->sym->type == STRUCT /* and possible deeper ones */
@ -202,6 +191,8 @@ def_use(Lextok *now, int code)
case '~': case '~':
case 'c': case 'c':
case ENABLED: case ENABLED:
case SET_P:
case GET_P:
case ASSERT: case ASSERT:
case EVAL: case EVAL:
def_use(now->lft, USE|code); def_use(now->lft, USE|code);
@ -503,7 +494,7 @@ AST_mutual(Lextok *a, Lextok *b, int toplevel)
if (strcmp(as->name, bs->name) != 0) if (strcmp(as->name, bs->name) != 0)
return 0; return 0;
if (as->type == STRUCT && a->rgt && b->rgt) if (as->type == STRUCT && a->rgt && b->rgt) /* we know that a and b are not null */
return AST_mutual(a->rgt->lft, b->rgt->lft, 0); return AST_mutual(a->rgt->lft, b->rgt->lft, 0);
return 1; return 1;
@ -545,14 +536,14 @@ AST_other(AST *a) /* check chan params in asgns and recvs */
case 'r': case 'r':
/* guess sends where name may originate */ /* guess sends where name may originate */
for (cl = chanlist; cl; cl = cl->nxt) /* all sends */ for (cl = chanlist; cl; cl = cl->nxt) /* all sends */
{ int a = AST_nrpar(cl->s); { int aa = AST_nrpar(cl->s);
int b = AST_nrpar(t->step->n); int bb = AST_nrpar(t->step->n);
if (a != b) /* matching nrs of params */ if (aa != bb) /* matching nrs of params */
continue; continue;
a = AST_ord(cl->s, cl->n); aa = AST_ord(cl->s, cl->n);
b = AST_ord(t->step->n, u->n); bb = AST_ord(t->step->n, u->n);
if (a != b) /* same position in parlist */ if (aa != bb) /* same position in parlist */
continue; continue;
AST_add_alias(cl->n, 4); /* RCV assume possible match */ AST_add_alias(cl->n, 4); /* RCV assume possible match */
@ -692,9 +683,7 @@ AST_relevant(Lextok *n)
} }
for (a = ast; a; a = a->nxt) /* all other stmnts */ for (a = ast; a; a = a->nxt) /* all other stmnts */
{ if (strcmp(a->p->n->name, ":never:") != 0 { if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE)
&& strcmp(a->p->n->name, ":trace:") != 0
&& strcmp(a->p->n->name, ":notrace:") != 0)
for (f = a->fsm; f; f = f->nxt) for (f = a->fsm; f; f = f->nxt)
for (t = f->t; t; t = t->nxt) for (t = f->t; t; t = t->nxt)
{ if (!(t->relevant&1)) { if (!(t->relevant&1))
@ -786,10 +775,8 @@ AST_tagruns(void)
*/ */
for (a = ast; a; a = a->nxt) for (a = ast; a; a = a->nxt)
{ if (strcmp(a->p->n->name, ":never:") == 0 { if (a->p->b == N_CLAIM || a->p->b == I_PROC
|| strcmp(a->p->n->name, ":trace:") == 0 || a->p->b == E_TRACE || a->p->b == N_TRACE)
|| strcmp(a->p->n->name, ":notrace:") == 0
|| strcmp(a->p->n->name, ":init:") == 0)
{ a->relevant |= 1; /* the proctype is relevant */ { a->relevant |= 1; /* the proctype is relevant */
continue; continue;
} }
@ -823,9 +810,9 @@ AST_report(AST *a, Element *e) /* ALSO deduce irrelevant vars */
printf("spin: redundant in proctype %s (for given property):\n", printf("spin: redundant in proctype %s (for given property):\n",
a->p->n->name); a->p->n->name);
} }
printf(" line %3d %s (state %d)", printf(" %s:%d (state %d)",
e->n?e->n->ln:-1,
e->n?e->n->fn->name:"-", e->n?e->n->fn->name:"-",
e->n?e->n->ln:-1,
e->seqno); e->seqno);
printf(" ["); printf(" [");
comment(stdout, e->n, 0); comment(stdout, e->n, 0);
@ -1016,7 +1003,8 @@ name_AST_track(Lextok *n, int code)
printf(" -- %d\n", code); printf(" -- %d\n", code);
#endif #endif
if (in_recv && (code&DEF) && (code&USE)) if (in_recv && (code&DEF) && (code&USE))
{ printf("spin: error: DEF and USE of same var in rcv stmnt: "); { printf("spin: %s:%d, error: DEF and USE of same var in rcv stmnt: ",
n->fn->name, n->ln);
AST_var(n, n->sym, 1); AST_var(n, n->sym, 1);
printf(" -- %d\n", code); printf(" -- %d\n", code);
nr_errs++; nr_errs++;
@ -1065,6 +1053,8 @@ AST_track(Lextok *now, int code) /* called from main.c */
case '~': case '~':
case 'c': case 'c':
case ENABLED: case ENABLED:
case SET_P:
case GET_P:
case ASSERT: case ASSERT:
AST_track(now->lft, USE|code); AST_track(now->lft, USE|code);
break; break;
@ -1075,8 +1065,8 @@ AST_track(Lextok *now, int code) /* called from main.c */
case NAME: case NAME:
name_AST_track(now, code); name_AST_track(now, code);
if (now->sym->nel != 1) if (now->sym->nel > 1 || now->sym->isarray)
AST_track(now->lft, USE|code); /* index */ AST_track(now->lft, USE); /* index, was USE|code */
break; break;
case 'R': case 'R':
@ -1569,7 +1559,8 @@ AST_ctrl(AST *a)
{ t->relevant &= ~2; /* clear mark */ { t->relevant &= ~2; /* clear mark */
if (verbose&32) if (verbose&32)
{ printf("\t\tnomark "); { printf("\t\tnomark ");
comment(stdout, t->step->n, 0); if (t->step && t->step->n)
comment(stdout, t->step->n, 0);
printf("\n"); printf("\n");
} } } } } }
@ -1601,7 +1592,8 @@ AST_ctrl(AST *a)
t->relevant |= 2; /* lift */ t->relevant |= 2; /* lift */
if (verbose&32) if (verbose&32)
{ printf("\t\t\tliftmark "); { printf("\t\t\tliftmark ");
comment(stdout, t->step->n, 0); if (t->step && t->step->n)
comment(stdout, t->step->n, 0);
printf("\n"); printf("\n");
} }
AST_spread(a, t->to); /* and spread to all guards */ AST_spread(a, t->to); /* and spread to all guards */
@ -1621,10 +1613,9 @@ AST_control_dep(void)
{ AST *a; { AST *a;
for (a = ast; a; a = a->nxt) for (a = ast; a; a = a->nxt)
if (strcmp(a->p->n->name, ":never:") != 0 { if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE)
&& strcmp(a->p->n->name, ":trace:") != 0 { AST_ctrl(a);
&& strcmp(a->p->n->name, ":notrace:") != 0) } }
AST_ctrl(a);
} }
static void static void
@ -1634,9 +1625,7 @@ AST_prelabel(void)
FSM_trans *t; FSM_trans *t;
for (a = ast; a; a = a->nxt) for (a = ast; a; a = a->nxt)
{ if (strcmp(a->p->n->name, ":never:") != 0 { if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE)
&& strcmp(a->p->n->name, ":trace:") != 0
&& strcmp(a->p->n->name, ":notrace:") != 0)
for (f = a->fsm; f; f = f->nxt) for (f = a->fsm; f; f = f->nxt)
for (t = f->t; t; t = t->nxt) for (t = f->t; t; t = t->nxt)
{ if (t->step { if (t->step
@ -1692,8 +1681,7 @@ AST_slice(void)
int spurious = 0; int spurious = 0;
if (!slicer) if (!slicer)
{ non_fatal("no slice criteria (or no claim) specified", { printf("spin: warning: no slice criteria found (no assertions and no claim)\n");
(char *) 0);
spurious = 1; spurious = 1;
} }
AST_dorelevant(); /* mark procs refered to in remote refs */ AST_dorelevant(); /* mark procs refered to in remote refs */
@ -1730,9 +1718,7 @@ void
AST_store(ProcList *p, int start_state) AST_store(ProcList *p, int start_state)
{ AST *n_ast; { AST *n_ast;
if (strcmp(p->n->name, ":never:") != 0 if (p->b != N_CLAIM && p->b != E_TRACE && p->b != N_TRACE)
&& strcmp(p->n->name, ":trace:") != 0
&& strcmp(p->n->name, ":notrace:") != 0)
{ n_ast = (AST *) emalloc(sizeof(AST)); { n_ast = (AST *) emalloc(sizeof(AST));
n_ast->p = p; n_ast->p = p;
n_ast->i_st = start_state; n_ast->i_st = start_state;
@ -1809,12 +1795,10 @@ AST_par_init(void) /* parameter passing -- hidden assignments */
int cnt; int cnt;
for (a = ast; a; a = a->nxt) for (a = ast; a; a = a->nxt)
{ if (strcmp(a->p->n->name, ":never:") == 0 { if (a->p->b == N_CLAIM || a->p->b == I_PROC
|| strcmp(a->p->n->name, ":trace:") == 0 || a->p->b == E_TRACE || a->p->b == N_TRACE)
|| strcmp(a->p->n->name, ":notrace:") == 0 { continue; /* has no params */
|| strcmp(a->p->n->name, ":init:") == 0) }
continue; /* have no params */
cnt = 0; cnt = 0;
for (f = a->p->p; f; f = f->rgt) /* types */ for (f = a->p->p; f; f = f->rgt) /* types */
for (t = f->lft; t; t = t->rgt) /* formals */ for (t = f->lft; t; t = t->rgt) /* formals */
@ -1845,9 +1829,8 @@ AST_var_init(void) /* initialized vars (not chans) - hidden assignments */
} } } }
for (a = ast; a; a = a->nxt) for (a = ast; a; a = a->nxt)
{ if (strcmp(a->p->n->name, ":never:") != 0 { if (a->p->b != N_CLAIM
&& strcmp(a->p->n->name, ":trace:") != 0 && a->p->b != E_TRACE && a->p->b != N_TRACE) /* has no locals */
&& strcmp(a->p->n->name, ":notrace:") != 0) /* claim has no locals */
for (walk = all_names; walk; walk = walk->next) for (walk = all_names; walk; walk = walk->next)
{ sp = walk->entry; { sp = walk->entry;
if (sp if (sp
@ -1995,7 +1978,7 @@ subgraph(AST *a, FSM_state *f, int out)
h = fsm_tbl[out]; h = fsm_tbl[out];
i = f->from / BPW; i = f->from / BPW;
j = f->from % BPW; j = f->from % BPW; /* assert(j <= 32); else lshift undefined? */
g = h->mod; g = h->mod;
if (verbose&32) if (verbose&32)
@ -2023,28 +2006,30 @@ act_dom(AST *a)
d. the dominator is reachable, and not equal to this node d. the dominator is reachable, and not equal to this node
#endif #endif
for (t = f->p, i = 0; t; t = t->nxt) for (t = f->p, i = 0; t; t = t->nxt)
i += fsm_tbl[t->to]->seen; { i += fsm_tbl[t->to]->seen;
if (i <= 1) continue; /* a. */ }
if (i <= 1)
{ continue; /* a. */
}
for (cnt = 1; cnt < a->nstates; cnt++) /* 0 is endstate */ for (cnt = 1; cnt < a->nstates; cnt++) /* 0 is endstate */
{ if (cnt == f->from { if (cnt == f->from
|| !fsm_tbl[cnt]->seen) || !fsm_tbl[cnt]->seen)
continue; /* c. */ { continue; /* c. */
}
i = cnt / BPW; i = cnt / BPW;
j = cnt % BPW; j = cnt % BPW; /* assert(j <= 32); */
if (!(f->dom[i]&(1<<j))) if (!(f->dom[i]&(1<<j)))
continue; { continue;
}
for (t = fsm_tbl[cnt]->t, i = 0; t; t = t->nxt) for (t = fsm_tbl[cnt]->t, i = 0; t; t = t->nxt)
i += fsm_tbl[t->to]->seen; { i += fsm_tbl[t->to]->seen;
}
if (i <= 1) if (i <= 1)
continue; /* b. */ { continue; /* b. */
}
if (f->mod) /* final check in 2nd phase */ if (f->mod) /* final check in 2nd phase */
subgraph(a, f, cnt); /* possible entry-exit pair */ { subgraph(a, f, cnt); /* possible entry-exit pair */
} } } }
}
} }
static void static void
@ -2178,27 +2163,26 @@ init_dom(AST *a)
for (f = a->fsm; f; f = f->nxt) for (f = a->fsm; f; f = f->nxt)
{ if (!f->seen) continue; { if (!f->seen) continue;
f->dom = (ulong *) f->dom = (ulong *) emalloc(a->nwords * sizeof(ulong));
emalloc(a->nwords * sizeof(ulong));
if (f->from == a->i_st) if (f->from == a->i_st)
{ i = a->i_st / BPW; { i = a->i_st / BPW;
j = a->i_st % BPW; j = a->i_st % BPW; /* assert(j <= 32); */
f->dom[i] = (1<<j); /* (1) */ f->dom[i] = (1<<j); /* (1) */
} else /* (2) */ } else /* (2) */
{ for (i = 0; i < a->nwords; i++) { for (i = 0; i < a->nwords; i++)
f->dom[i] = (ulong) ~0; /* all 1's */ { f->dom[i] = (ulong) ~0; /* all 1's */
}
if (a->nstates % BPW) if (a->nstates % BPW)
for (i = (a->nstates % BPW); i < (int) BPW; i++) for (i = (a->nstates % BPW); i < (int) BPW; i++)
f->dom[a->nwords-1] &= ~(1<<i); /* clear tail */ { f->dom[a->nwords-1] &= ~(1<< ((ulong) i)); /* clear tail */
}
for (cnt = 0; cnt < a->nstates; cnt++) for (cnt = 0; cnt < a->nstates; cnt++)
if (!fsm_tbl[cnt]->seen) { if (!fsm_tbl[cnt]->seen)
{ i = cnt / BPW; { i = cnt / BPW;
j = cnt % BPW; j = cnt % BPW; /* assert(j <= 32); */
f->dom[i] &= ~(1<<j); f->dom[i] &= ~(1<< ((ulong) j));
} } } } } } }
} }
static int static int
@ -2226,7 +2210,7 @@ dom_perculate(AST *a, FSM_state *f)
} }
i = f->from / BPW; i = f->from / BPW;
j = f->from % BPW; j = f->from % BPW; /* assert(j <= 32); */
ndom[i] |= (1<<j); /* (5a) */ ndom[i] |= (1<<j); /* (5a) */
for (i = 0; i < a->nwords; i++) for (i = 0; i < a->nwords; i++)
@ -2261,6 +2245,7 @@ AST_dominant(void)
FSM_trans *t; FSM_trans *t;
AST *a; AST *a;
int oi; int oi;
static FSM_state no_state;
#if 0 #if 0
find dominators find dominators
Aho, Sethi, & Ullman, Compilers - principles, techniques, and tools Aho, Sethi, & Ullman, Compilers - principles, techniques, and tools

2878
sys/src/cmd/spin/pangen6.h Normal file

File diff suppressed because it is too large Load diff

923
sys/src/cmd/spin/pangen7.c Normal file
View file

@ -0,0 +1,923 @@
/***** spin: pangen7.c *****/
/*
* This file is part of the public release of Spin. It is subject to the
* terms in the LICENSE file that is included in this source directory.
* Tool documentation is available at http://spinroot.com
*/
#include <stdlib.h>
#include <assert.h>
#include "spin.h"
#include "y.tab.h"
#include <assert.h>
#ifndef PC
#include <unistd.h>
#endif
extern ProcList *rdy;
extern Element *Al_El;
extern int nclaims, verbose, Strict;
extern short has_accept;
typedef struct Succ_List Succ_List;
typedef struct SQueue SQueue;
typedef struct OneState OneState;
typedef struct State_Stack State_Stack;
typedef struct Guard Guard;
struct Succ_List {
SQueue *s;
Succ_List *nxt;
};
struct OneState {
int *combo; /* the combination of claim states */
Succ_List *succ; /* list of ptrs to immediate successor states */
};
struct SQueue {
OneState state;
SQueue *nxt;
};
struct State_Stack {
int *n;
State_Stack *nxt;
};
struct Guard {
Lextok *t;
Guard *nxt;
};
static SQueue *sq, *sd, *render; /* states move from sq to sd to render to holding */
static SQueue *holding, *lasthold;
static State_Stack *dsts;
static int nst; /* max nr of states in claims */
static int *Ist; /* initial states */
static int *Nacc; /* number of accept states in claim */
static int *Nst; /* next states */
static int **reached; /* n claims x states */
static int unfolding; /* to make sure all accept states are reached */
static int is_accept; /* remember if the current state is accepting in any claim */
static int not_printing; /* set during explore_product */
static Element ****matrix; /* n x two-dimensional arrays state x state */
static Element **Selfs; /* self-loop states at end of claims */
static void get_seq(int, Sequence *);
static void set_el(int n, Element *e);
static void gen_product(void);
static void print_state_nm(char *, int *, char *);
static SQueue *find_state(int *);
static SQueue *retrieve_state(int *);
static int
same_state(int *a, int *b)
{ int i;
for (i = 0; i < nclaims; i++)
{ if (a[i] != b[i])
{ return 0;
} }
return 1;
}
static int
in_stack(SQueue *s, SQueue *in)
{ SQueue *q;
for (q = in; q; q = q->nxt)
{ if (same_state(q->state.combo, s->state.combo))
{ return 1;
} }
return 0;
}
static void
to_render(SQueue *s)
{ SQueue *a, *q, *last; /* find in sd/sq and move to render, if not already there */
int n;
for (n = 0; n < nclaims; n++)
{ reached[n][ s->state.combo[n] ] |= 2;
}
for (q = render; q; q = q->nxt)
{ if (same_state(q->state.combo, s->state.combo))
{ return;
} }
for (q = holding; q; q = q->nxt)
{ if (same_state(q->state.combo, s->state.combo))
{ return;
} }
a = sd;
more:
for (q = a, last = 0; q; last = q, q = q->nxt)
{ if (same_state(q->state.combo, s->state.combo))
{ if (!last)
{ if (a == sd)
{ sd = q->nxt;
} else if (a == sq)
{ sq = q->nxt;
} else
{ holding = q->nxt;
}
} else
{ last->nxt = q->nxt;
}
q->nxt = render;
render = q;
return;
} }
if (verbose)
{ print_state_nm("looking for: ", s->state.combo, "\n");
}
(void) find_state(s->state.combo); /* creates it in sq */
if (a != sq)
{ a = sq;
goto more;
}
fatal("cannot happen, to_render", 0);
}
static void
wrap_text(char *pre, Lextok *t, char *post)
{
printf(pre, (char *) 0);
comment(stdout, t, 0);
printf(post, (char *) 0);
}
static State_Stack *
push_dsts(int *n)
{ State_Stack *s;
int i;
for (s = dsts; s; s = s->nxt)
{ if (same_state(s->n, n))
{ if (verbose&64)
{ printf("\n");
for (s = dsts; s; s = s->nxt)
{ print_state_nm("\t", s->n, "\n");
}
print_state_nm("\t", n, "\n");
}
return s;
} }
s = (State_Stack *) emalloc(sizeof(State_Stack));
s->n = (int *) emalloc(nclaims * sizeof(int));
for (i = 0; i < nclaims; i++)
s->n[i] = n[i];
s->nxt = dsts;
dsts = s;
return 0;
}
static void
pop_dsts(void)
{
assert(dsts != NULL);
dsts = dsts->nxt;
}
static void
complete_transition(Succ_List *sl, Guard *g)
{ Guard *w;
int cnt = 0;
printf(" :: ");
for (w = g; w; w = w->nxt)
{ if (w->t->ntyp == CONST
&& w->t->val == 1)
{ continue;
} else if (w->t->ntyp == 'c'
&& w->t->lft->ntyp == CONST
&& w->t->lft->val == 1)
{ continue; /* 'true' */
}
if (cnt > 0)
{ printf(" && ");
}
wrap_text("", w->t, "");
cnt++;
}
if (cnt == 0)
{ printf("true");
}
print_state_nm(" -> goto ", sl->s->state.combo, "");
if (is_accept > 0)
{ printf("_U%d\n", (unfolding+1)%nclaims);
} else
{ printf("_U%d\n", unfolding);
}
}
static void
state_body(OneState *s, Guard *guard)
{ Succ_List *sl;
State_Stack *y;
Guard *g;
int i, once;
for (sl = s->succ; sl; sl = sl->nxt)
{ once = 0;
for (i = 0; i < nclaims; i++)
{ Element *e;
e = matrix[i][s->combo[i]][sl->s->state.combo[i]];
/* if one of the claims has a DO or IF move
then pull its target state forward, once
*/
if (!e
|| e->n->ntyp == NON_ATOMIC
|| e->n->ntyp == DO
|| e->n->ntyp == IF)
{ s = &(sl->s->state);
y = push_dsts(s->combo);
if (!y)
{ if (once++ == 0)
{ assert(s->succ != NULL);
state_body(s, guard);
}
pop_dsts();
} else if (!y->nxt) /* self-loop transition */
{ if (!not_printing) printf(" /* self-loop */\n");
} else
{ /* non_fatal("loop in state body", 0); ** maybe ok */
}
continue;
} else
{ g = (Guard *) emalloc(sizeof(Guard));
g->t = e->n;
g->nxt = guard;
guard = g;
} }
if (guard && !once)
{ if (!not_printing) complete_transition(sl, guard);
to_render(sl->s);
} }
}
static struct X {
char *s; int n;
} spl[] = {
{"end", 3 },
{"accept", 6 },
{0, 0 },
};
static int slcnt;
extern Label *labtab;
static ProcList *
locate_claim(int n)
{ ProcList *p;
int i;
for (p = rdy, i = 0; p; p = p->nxt, i++) /* find claim name */
{ if (i == n)
{ break;
} }
assert(p && p->b == N_CLAIM);
return p;
}
static void
elim_lab(Element *e)
{ Label *l, *lst;
for (l = labtab, lst = NULL; l; lst = l, l = l->nxt)
{ if (l->e == e)
{ if (lst)
{ lst->nxt = l->nxt;
} else
{ labtab = l->nxt;
}
break;
} }
}
static int
claim_has_accept(ProcList *p)
{ Label *l;
for (l = labtab; l; l = l->nxt)
{ if (strcmp(l->c->name, p->n->name) == 0
&& strncmp(l->s->name, "accept", 6) == 0)
{ return 1;
} }
return 0;
}
static void
prune_accept(void)
{ int n;
for (n = 0; n < nclaims; n++)
{ if ((reached[n][Selfs[n]->seqno] & 2) == 0)
{ if (verbose)
{ printf("claim %d: selfloop not reachable\n", n);
}
elim_lab(Selfs[n]);
Nacc[n] = claim_has_accept(locate_claim(n));
} }
}
static void
mk_accepting(int n, Element *e)
{ ProcList *p;
Label *l;
int i;
assert(!Selfs[n]);
Selfs[n] = e;
l = (Label *) emalloc(sizeof(Label));
l->s = (Symbol *) emalloc(sizeof(Symbol));
l->s->name = "accept00";
l->c = (Symbol *) emalloc(sizeof(Symbol));
l->uiid = 0; /* this is not in an inline */
for (p = rdy, i = 0; p; p = p->nxt, i++) /* find claim name */
{ if (i == n)
{ l->c->name = p->n->name;
break;
} }
assert(p && p->b == N_CLAIM);
Nacc[n] = 1;
has_accept = 1;
l->e = e;
l->nxt = labtab;
labtab = l;
}
static void
check_special(int *nrs)
{ ProcList *p;
Label *l;
int i, j, nmatches;
int any_accepts = 0;
for (i = 0; i < nclaims; i++)
{ any_accepts += Nacc[i];
}
is_accept = 0;
for (j = 0; spl[j].n; j++) /* 2 special label prefixes */
{ nmatches = 0;
for (p = rdy, i = 0; p; p = p->nxt, i++) /* check each claim */
{ if (p->b != N_CLAIM)
{ continue;
}
/* claim i in state nrs[i], type p->tn, name p->n->name
* either the state has an accept label, or the claim has none,
* so that all its states should be considered accepting
* --- but only if other claims do have accept states!
*/
if (Strict == 0 && j == 1 && Nacc[i] == 0 && any_accepts > 0)
{ if ((verbose&32) && i == unfolding)
{ printf(" /* claim %d pseudo-accept */\n", i);
}
goto is_accepting;
}
for (l = labtab; l; l = l->nxt) /* check its labels */
{ if (strcmp(l->c->name, p->n->name) == 0 /* right claim */
&& l->e->seqno == nrs[i] /* right state */
&& strncmp(l->s->name, spl[j].s, spl[j].n) == 0)
{ if (j == 1) /* accept state */
{ char buf[32];
is_accepting: if (strchr(p->n->name, ':'))
{ sprintf(buf, "N%d", i);
} else
{ assert(strlen(p->n->name) < sizeof(buf));
strcpy(buf, p->n->name);
}
if (unfolding == 0 && i == 0)
{ if (!not_printing)
printf("%s_%s_%d:\n", /* true accept */
spl[j].s, buf, slcnt++);
} else if (verbose&32)
{ if (!not_printing)
printf("%s_%s%d:\n",
buf, spl[j].s, slcnt++);
}
if (i == unfolding)
{ is_accept++; /* move to next unfolding */
}
} else
{ nmatches++;
}
break;
} } }
if (j == 0 && nmatches == nclaims) /* end-state */
{ if (!not_printing)
{ printf("%s%d:\n", spl[j].s, slcnt++);
} } }
}
static int
render_state(SQueue *q)
{
if (!q || !q->state.succ)
{ if (verbose&64)
{ printf(" no exit\n");
}
return 0;
}
check_special(q->state.combo); /* accept or end-state labels */
dsts = (State_Stack *) 0;
push_dsts(q->state.combo); /* to detect loops */
if (!not_printing)
{ print_state_nm("", q->state.combo, ""); /* the name */
printf("_U%d:\n\tdo\n", unfolding);
}
state_body(&(q->state), (Guard *) 0);
if (!not_printing)
{ printf("\tod;\n");
}
pop_dsts();
return 1;
}
static void
explore_product(void)
{ SQueue *q;
/* all states are in the sd queue */
q = retrieve_state(Ist); /* retrieve from the sd q */
q->nxt = render; /* put in render q */
render = q;
do {
q = render;
render = render->nxt;
q->nxt = 0; /* remove from render q */
if (verbose&64)
{ print_state_nm("explore: ", q->state.combo, "\n");
}
not_printing = 1;
render_state(q); /* may add new states */
not_printing = 0;
if (lasthold)
{ lasthold->nxt = q;
lasthold = q;
} else
{ holding = lasthold = q;
}
} while (render);
assert(!dsts);
}
static void
print_product(void)
{ SQueue *q;
int cnt;
if (unfolding == 0)
{ printf("never Product {\n"); /* name expected by iSpin */
q = find_state(Ist); /* should find it in the holding q */
assert(q != NULL);
q->nxt = holding; /* put it at the front */
holding = q;
}
render = holding;
holding = lasthold = 0;
printf("/* ============= U%d ============= */\n", unfolding);
cnt = 0;
do {
q = render;
render = render->nxt;
q->nxt = 0;
if (verbose&64)
{ print_state_nm("print: ", q->state.combo, "\n");
}
cnt += render_state(q);
if (lasthold)
{ lasthold->nxt = q;
lasthold = q;
} else
{ holding = lasthold = q;
}
} while (render);
assert(!dsts);
if (cnt == 0)
{ printf(" 0;\n");
}
if (unfolding == nclaims-1)
{ printf("}\n");
}
}
static void
prune_dead(void)
{ Succ_List *sl, *last;
SQueue *q;
int cnt;
do { cnt = 0;
for (q = sd; q; q = q->nxt)
{ /* if successor is deadend, remove it
* unless it's a move to the end-state of the claim
*/
last = (Succ_List *) 0;
for (sl = q->state.succ; sl; last = sl, sl = sl->nxt)
{ if (!sl->s->state.succ) /* no successor */
{ if (!last)
{ q->state.succ = sl->nxt;
} else
{ last->nxt = sl->nxt;
}
cnt++;
} } }
} while (cnt > 0);
}
static void
print_raw(void)
{ int i, j, n;
printf("#if 0\n");
for (n = 0; n < nclaims; n++)
{ printf("C%d:\n", n);
for (i = 0; i < nst; i++)
{ if (reached[n][i])
for (j = 0; j < nst; j++)
{ if (matrix[n][i][j])
{ if (reached[n][i] & 2) printf("+");
if (i == Ist[n]) printf("*");
printf("\t%d", i);
wrap_text(" -[", matrix[n][i][j]->n, "]->\t");
printf("%d\n", j);
} } } }
printf("#endif\n\n");
fflush(stdout);
}
void
sync_product(void)
{ ProcList *p;
Element *e;
int n, i;
if (nclaims <= 1) return;
(void) unlink("pan.pre");
Ist = (int *) emalloc(sizeof(int) * nclaims);
Nacc = (int *) emalloc(sizeof(int) * nclaims);
Nst = (int *) emalloc(sizeof(int) * nclaims);
reached = (int **) emalloc(sizeof(int *) * nclaims);
Selfs = (Element **) emalloc(sizeof(Element *) * nclaims);
matrix = (Element ****) emalloc(sizeof(Element ***) * nclaims); /* claims */
for (p = rdy, i = 0; p; p = p->nxt, i++)
{ if (p->b == N_CLAIM)
{ nst = max(p->s->maxel, nst);
Nacc[i] = claim_has_accept(p);
} }
for (n = 0; n < nclaims; n++)
{ reached[n] = (int *) emalloc(sizeof(int) * nst);
matrix[n] = (Element ***) emalloc(sizeof(Element **) * nst); /* rows */
for (i = 0; i < nst; i++) /* cols */
{ matrix[n][i] = (Element **) emalloc(sizeof(Element *) * nst);
} }
for (e = Al_El; e; e = e->Nxt)
{ e->status &= ~DONE;
}
for (p = rdy, n=0; p; p = p->nxt, n++)
{ if (p->b == N_CLAIM)
{ /* fill in matrix[n] */
e = p->s->frst;
Ist[n] = huntele(e, e->status, -1)->seqno;
reached[n][Ist[n]] = 1|2;
get_seq(n, p->s);
} }
if (verbose) /* show only the input automata */
{ print_raw();
}
gen_product(); /* create product automaton */
}
static int
nxt_trans(int n, int cs, int frst)
{ int j;
for (j = frst; j < nst; j++)
{ if (reached[n][cs]
&& matrix[n][cs][j])
{ return j;
} }
return -1;
}
static void
print_state_nm(char *p, int *s, char *a)
{ int i;
printf("%sP", p);
for (i = 0; i < nclaims; i++)
{ printf("_%d", s[i]);
}
printf("%s", a);
}
static void
create_transition(OneState *s, SQueue *it)
{ int n, from, upto;
int *F = s->combo;
int *T = it->state.combo;
Succ_List *sl;
Lextok *t;
if (verbose&64)
{ print_state_nm("", F, " ");
print_state_nm("-> ", T, "\t");
}
/* check if any of the claims is blocked */
/* which makes the state a dead-end */
for (n = 0; n < nclaims; n++)
{ from = F[n];
upto = T[n];
t = matrix[n][from][upto]->n;
if (verbose&64)
{ wrap_text("", t, " ");
}
if (t->ntyp == 'c'
&& t->lft->ntyp == CONST)
{ if (t->lft->val == 0) /* i.e., false */
{ goto done;
} } }
sl = (Succ_List *) emalloc(sizeof(Succ_List));
sl->s = it;
sl->nxt = s->succ;
s->succ = sl;
done:
if (verbose&64)
{ printf("\n");
}
}
static SQueue *
find_state(int *cs)
{ SQueue *nq, *a = sq;
int i;
again: /* check in nq, sq, and then in the render q */
for (nq = a; nq; nq = nq->nxt)
{ if (same_state(nq->state.combo, cs))
{ return nq; /* found */
} }
if (a == sq && sd)
{ a = sd;
goto again; /* check the other stack too */
} else if (a == sd && render)
{ a = render;
goto again;
}
nq = (SQueue *) emalloc(sizeof(SQueue));
nq->state.combo = (int *) emalloc(nclaims * sizeof(int));
for (i = 0; i < nclaims; i++)
{ nq->state.combo[i] = cs[i];
}
nq->nxt = sq; /* add to sq stack */
sq = nq;
return nq;
}
static SQueue *
retrieve_state(int *s)
{ SQueue *nq, *last = NULL;
for (nq = sd; nq; last = nq, nq = nq->nxt)
{ if (same_state(nq->state.combo, s))
{ if (last)
{ last->nxt = nq->nxt;
} else
{ sd = nq->nxt; /* 6.4.0: was sd = nq */
}
return nq; /* found */
} }
fatal("cannot happen: retrieve_state", 0);
return (SQueue *) 0;
}
static void
all_successors(int n, OneState *cur)
{ int i, j = 0;
if (n >= nclaims)
{ create_transition(cur, find_state(Nst));
} else
{ i = cur->combo[n];
for (;;)
{ j = nxt_trans(n, i, j);
if (j < 0) break;
Nst[n] = j;
all_successors(n+1, cur);
j++;
} }
}
static void
gen_product(void)
{ OneState *cur_st;
SQueue *q;
find_state(Ist); /* create initial state */
while (sq)
{ if (in_stack(sq, sd))
{ sq = sq->nxt;
continue;
}
cur_st = &(sq->state);
q = sq;
sq = sq->nxt; /* delete from sq stack */
q->nxt = sd; /* and move to done stack */
sd = q;
all_successors(0, cur_st);
}
/* all states are in the sd queue now */
prune_dead();
explore_product(); /* check if added accept-self-loops are reachable */
prune_accept();
if (verbose)
{ print_raw();
}
/* PM: merge states with identical successor lists */
/* all outgoing transitions from accept-states
from claim n in copy n connect to states in copy (n+1)%nclaims
only accept states from claim 0 in copy 0 are true accept states
in the product
PM: what about claims that have no accept states (e.g., restrictions)
*/
for (unfolding = 0; unfolding < nclaims; unfolding++)
{ print_product();
}
}
static void
t_record(int n, Element *e, Element *g)
{ int from = e->seqno, upto = g?g->seqno:0;
assert(from >= 0 && from < nst);
assert(upto >= 0 && upto < nst);
matrix[n][from][upto] = e;
reached[n][upto] |= 1;
}
static void
get_sub(int n, Element *e)
{
if (e->n->ntyp == D_STEP
|| e->n->ntyp == ATOMIC)
{ fatal("atomic or d_step in never claim product", 0);
}
/* NON_ATOMIC */
e->n->sl->this->last->nxt = e->nxt;
get_seq(n, e->n->sl->this);
t_record(n, e, e->n->sl->this->frst);
}
static void
set_el(int n, Element *e)
{ Element *g;
if (e->n->ntyp == '@') /* change to self-loop */
{ e->n->ntyp = CONST;
e->n->val = 1; /* true */
e->nxt = e;
g = e;
mk_accepting(n, e);
} else
if (e->n->ntyp == GOTO)
{ g = get_lab(e->n, 1);
g = huntele(g, e->status, -1);
} else if (e->nxt)
{ g = huntele(e->nxt, e->status, -1);
} else
{ g = NULL;
}
t_record(n, e, g);
}
static void
get_seq(int n, Sequence *s)
{ SeqList *h;
Element *e;
e = huntele(s->frst, s->frst->status, -1);
for ( ; e; e = e->nxt)
{ if (e->status & DONE)
{ goto checklast;
}
e->status |= DONE;
if (e->n->ntyp == UNLESS)
{ fatal("unless stmnt in never claim product", 0);
}
if (e->sub) /* IF or DO */
{ Lextok *x = NULL;
Lextok *y = NULL;
Lextok *haselse = NULL;
for (h = e->sub; h; h = h->nxt)
{ Lextok *t = h->this->frst->n;
if (t->ntyp == ELSE)
{ if (verbose&64) printf("else at line %d\n", t->ln);
haselse = t;
continue;
}
if (t->ntyp != 'c')
{ fatal("product, 'else' combined with non-condition", 0);
}
if (t->lft->ntyp == CONST /* true */
&& t->lft->val == 1
&& y == NULL)
{ y = nn(ZN, CONST, ZN, ZN);
y->val = 0;
} else
{ if (!x)
x = t;
else
x = nn(ZN, OR, x, t);
if (verbose&64)
{ wrap_text(" [", x, "]\n");
} } }
if (haselse)
{ if (!y)
{ y = nn(ZN, '!', x, ZN);
}
if (verbose&64)
{ wrap_text(" [else: ", y, "]\n");
}
haselse->ntyp = 'c'; /* replace else */
haselse->lft = y;
}
for (h = e->sub; h; h = h->nxt)
{ t_record(n, e, h->this->frst);
get_seq(n, h->this);
}
} else
{ if (e->n->ntyp == ATOMIC
|| e->n->ntyp == D_STEP
|| e->n->ntyp == NON_ATOMIC)
{ get_sub(n, e);
} else
{ set_el(n, e);
}
}
checklast: if (e == s->last)
break;
}
}

2413
sys/src/cmd/spin/pangen7.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,22 +1,21 @@
/***** spin: reprosrc.c *****/ /***** spin: reprosrc.c *****/
/* Copyright (c) 2002-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 <stdio.h> #include <stdio.h>
#include <assert.h>
#include "spin.h" #include "spin.h"
#include "y.tab.h" #include "y.tab.h"
static int indent = 1; static int indent = 1;
extern YYSTYPE yylval;
extern ProcList *rdy; extern ProcList *rdy;
void repro_seq(Sequence *); static void repro_seq(Sequence *);
void void
doindent(void) doindent(void)
@ -48,7 +47,7 @@ repro_sub(Element *e)
printf(" };\n"); printf(" };\n");
} }
void static void
repro_seq(Sequence *s) repro_seq(Sequence *s)
{ Element *e; { Element *e;
Symbol *v; Symbol *v;
@ -96,7 +95,7 @@ repro_seq(Sequence *s)
doindent(); doindent();
if (e->n->ntyp == C_CODE) if (e->n->ntyp == C_CODE)
{ printf("c_code "); { printf("c_code ");
plunk_inline(stdout, e->n->sym->name, 1); plunk_inline(stdout, e->n->sym->name, 1, 1);
} else if (e->n->ntyp == 'c' } else if (e->n->ntyp == 'c'
&& e->n->lft->ntyp == C_EXPR) && e->n->lft->ntyp == C_EXPR)
{ printf("c_expr { "); { printf("c_expr { ");
@ -134,3 +133,252 @@ repro_src(void)
{ {
repro_proc(rdy); repro_proc(rdy);
} }
static int in_decl;
static int in_c_decl;
static int in_c_code;
void
blip(int n, char *b)
{ char mtxt[1024];
strcpy(mtxt, "");
switch (n) {
default: if (n > 0 && n < 256)
sprintf(mtxt, "%c", n);
else
sprintf(mtxt, "<%d?>", n);
break;
case '(': strcpy(mtxt, "("); in_decl++; break;
case ')': strcpy(mtxt, ")"); in_decl--; break;
case '{': strcpy(mtxt, "{"); break;
case '}': strcpy(mtxt, "}"); break;
case '\t': sprintf(mtxt, "\\t"); break;
case '\f': sprintf(mtxt, "\\f"); break;
case '\n': sprintf(mtxt, "\\n"); break;
case '\r': sprintf(mtxt, "\\r"); break;
case 'c': sprintf(mtxt, "condition"); break;
case 's': sprintf(mtxt, "send"); break;
case 'r': sprintf(mtxt, "recv"); break;
case 'R': sprintf(mtxt, "recv poll"); break;
case '@': sprintf(mtxt, "@"); break;
case '?': sprintf(mtxt, "(x->y:z)"); break;
case NEXT: sprintf(mtxt, "X"); break;
case ALWAYS: sprintf(mtxt, "[]"); break;
case EVENTUALLY: sprintf(mtxt, "<>"); break;
case IMPLIES: sprintf(mtxt, "->"); break;
case EQUIV: sprintf(mtxt, "<->"); break;
case UNTIL: sprintf(mtxt, "U"); break;
case WEAK_UNTIL: sprintf(mtxt, "W"); break;
case IN: sprintf(mtxt, "in"); break;
case ACTIVE: sprintf(mtxt, "active"); break;
case AND: sprintf(mtxt, "&&"); break;
case ARROW: sprintf(mtxt, "->"); break;
case ASGN: sprintf(mtxt, "="); break;
case ASSERT: sprintf(mtxt, "assert"); break;
case ATOMIC: sprintf(mtxt, "atomic"); break;
case BREAK: sprintf(mtxt, "break"); break;
case C_CODE: sprintf(mtxt, "c_code"); in_c_code++; break;
case C_DECL: sprintf(mtxt, "c_decl"); in_c_decl++; break;
case C_EXPR: sprintf(mtxt, "c_expr"); break;
case C_STATE: sprintf(mtxt, "c_state"); break;
case C_TRACK: sprintf(mtxt, "c_track"); break;
case CLAIM: sprintf(mtxt, "never"); break;
case CONST: sprintf(mtxt, "%d", yylval->val); break;
case DECR: sprintf(mtxt, "--"); break;
case D_STEP: sprintf(mtxt, "d_step"); break;
case D_PROCTYPE: sprintf(mtxt, "d_proctype"); break;
case DO: sprintf(mtxt, "do"); break;
case DOT: sprintf(mtxt, "."); break;
case ELSE: sprintf(mtxt, "else"); break;
case EMPTY: sprintf(mtxt, "empty"); break;
case ENABLED: sprintf(mtxt, "enabled"); break;
case EQ: sprintf(mtxt, "=="); break;
case EVAL: sprintf(mtxt, "eval"); break;
case FI: sprintf(mtxt, "fi"); break;
case FULL: sprintf(mtxt, "full"); break;
case GE: sprintf(mtxt, ">="); break;
case GET_P: sprintf(mtxt, "get_priority"); break;
case GOTO: sprintf(mtxt, "goto"); break;
case GT: sprintf(mtxt, ">"); break;
case HIDDEN: sprintf(mtxt, "hidden"); break;
case IF: sprintf(mtxt, "if"); break;
case INCR: sprintf(mtxt, "++"); break;
case INLINE: sprintf(mtxt, "inline"); break;
case INIT: sprintf(mtxt, "init"); break;
case ISLOCAL: sprintf(mtxt, "local"); break;
case LABEL: sprintf(mtxt, "<label-name>"); break;
case LE: sprintf(mtxt, "<="); break;
case LEN: sprintf(mtxt, "len"); break;
case LSHIFT: sprintf(mtxt, "<<"); break;
case LT: sprintf(mtxt, "<"); break;
case LTL: sprintf(mtxt, "ltl"); break;
case NAME: sprintf(mtxt, "%s", yylval->sym->name); break;
case XU: switch (yylval->val) {
case XR: sprintf(mtxt, "xr"); break;
case XS: sprintf(mtxt, "xs"); break;
default: sprintf(mtxt, "<?>"); break;
}
break;
case TYPE: switch (yylval->val) {
case BIT: sprintf(mtxt, "bit"); break;
case BYTE: sprintf(mtxt, "byte"); break;
case CHAN: sprintf(mtxt, "chan"); in_decl++; break;
case INT: sprintf(mtxt, "int"); break;
case MTYPE: sprintf(mtxt, "mtype"); break;
case SHORT: sprintf(mtxt, "short"); break;
case UNSIGNED: sprintf(mtxt, "unsigned"); break;
default: sprintf(mtxt, "<unknown type>"); break;
}
break;
case NE: sprintf(mtxt, "!="); break;
case NEG: sprintf(mtxt, "!"); break;
case NEMPTY: sprintf(mtxt, "nempty"); break;
case NFULL: sprintf(mtxt, "nfull"); break;
case NON_ATOMIC: sprintf(mtxt, "<sub-sequence>"); break;
case NONPROGRESS: sprintf(mtxt, "np_"); break;
case OD: sprintf(mtxt, "od"); break;
case OF: sprintf(mtxt, "of"); break;
case OR: sprintf(mtxt, "||"); break;
case O_SND: sprintf(mtxt, "!!"); break;
case PC_VAL: sprintf(mtxt, "pc_value"); break;
case PRINT: sprintf(mtxt, "printf"); break;
case PRINTM: sprintf(mtxt, "printm"); break;
case PRIORITY: sprintf(mtxt, "priority"); break;
case PROCTYPE: sprintf(mtxt, "proctype"); break;
case PROVIDED: sprintf(mtxt, "provided"); break;
case RCV: sprintf(mtxt, "?"); break;
case R_RCV: sprintf(mtxt, "??"); break;
case RSHIFT: sprintf(mtxt, ">>"); break;
case RUN: sprintf(mtxt, "run"); break;
case SEP: sprintf(mtxt, "::"); break;
case SEMI: sprintf(mtxt, ";"); break;
case SET_P: sprintf(mtxt, "set_priority"); break;
case SHOW: sprintf(mtxt, "show"); break;
case SND: sprintf(mtxt, "!"); break;
case INAME:
case UNAME:
case PNAME:
case STRING: sprintf(mtxt, "%s", yylval->sym->name); break;
case TRACE: sprintf(mtxt, "trace"); break;
case TIMEOUT: sprintf(mtxt, "timeout"); break;
case TYPEDEF: sprintf(mtxt, "typedef"); break;
case UMIN: sprintf(mtxt, "-"); break;
case UNLESS: sprintf(mtxt, "unless"); break;
}
strcat(b, mtxt);
}
void
purge(char *b)
{
if (strlen(b) == 0) return;
if (b[strlen(b)-1] != ':') /* label? */
{ if (b[0] == ':' && b[1] == ':')
{ indent--;
doindent();
indent++;
} else
{ doindent();
}
}
printf("%s\n", b);
strcpy(b, "");
in_decl = 0;
in_c_code = 0;
in_c_decl = 0;
}
int pp_mode;
extern int lex(void);
void
pretty_print(void)
{ int c, lastc = 0;
char buf[1024];
pp_mode = 1;
indent = 0;
strcpy(buf, "");
while ((c = lex()) != EOF)
{
if ((lastc == IF || lastc == DO) && c != SEP)
{ indent--; /* c_code if */
}
if (c == C_DECL || c == C_STATE
|| c == C_TRACK || c == SEP
|| c == DO || c == IF
|| (c == TYPE && !in_decl))
{ purge(buf); /* start on new line */
}
if (c == '{'
&& lastc != OF && lastc != IN
&& lastc != ATOMIC && lastc != D_STEP
&& lastc != C_CODE && lastc != C_DECL && lastc != C_EXPR)
{ purge(buf);
}
if (c == PREPROC)
{ int oi = indent;
purge(buf);
assert(strlen(yylval->sym->name) < sizeof(buf));
strcpy(buf, yylval->sym->name);
indent = 0;
purge(buf);
indent = oi;
continue;
}
if (c != ':' && c != SEMI
&& c != ',' && c != '('
&& c != '#' && lastc != '#'
&& c != ARROW && lastc != ARROW
&& c != '.' && lastc != '.'
&& c != '!' && lastc != '!'
&& c != SND && lastc != SND
&& c != RCV && lastc != RCV
&& c != O_SND && lastc != O_SND
&& c != R_RCV && lastc != R_RCV
&& (c != ']' || lastc != '[')
&& (c != '>' || lastc != '<')
&& (c != GT || lastc != LT)
&& c != '@' && lastc != '@'
&& c != DO && c != OD && c != IF && c != FI
&& c != SEP && strlen(buf) > 0)
strcat(buf, " ");
if (c == '}' || c == OD || c == FI)
{ purge(buf);
indent--;
}
blip(c, buf);
if (c == '{' || c == DO || c == IF)
{ purge(buf);
indent++;
}
if (c == '}' || c == BREAK || c == SEMI
|| (c == ':' && lastc == NAME))
{ purge(buf);
}
lastc = c;
}
purge(buf);
}

View file

@ -1,13 +1,10 @@
/***** spin: run.c *****/ /***** spin: run.c *****/
/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 <stdlib.h> #include <stdlib.h>
#include "spin.h" #include "spin.h"
@ -16,15 +13,18 @@
extern RunList *X, *run; extern RunList *X, *run;
extern Symbol *Fname; extern Symbol *Fname;
extern Element *LastStep; extern Element *LastStep;
extern int Rvous, lineno, Tval, interactive, MadeChoice; extern int Rvous, lineno, Tval, interactive, MadeChoice, Priority_Sum;
extern int TstOnly, verbose, s_trail, xspin, jumpsteps, depth; extern int TstOnly, verbose, s_trail, xspin, jumpsteps, depth;
extern int nproc, nstop, no_print, like_java; extern int analyze, nproc, nstop, no_print, like_java, old_priority_rules;
extern short Have_claim;
static long Seed = 1; static long Seed = 1;
static int E_Check = 0, Escape_Check = 0; static int E_Check = 0, Escape_Check = 0;
static int eval_sync(Element *); static int eval_sync(Element *);
static int pc_enabled(Lextok *n); static int pc_enabled(Lextok *n);
static int get_priority(Lextok *n);
static void set_priority(Lextok *n, Lextok *m);
extern void sr_buf(int, int); extern void sr_buf(int, int);
void void
@ -42,24 +42,23 @@ Rand(void)
Element * Element *
rev_escape(SeqList *e) rev_escape(SeqList *e)
{ Element *r; { Element *r = (Element *) 0;
if (!e) if (e)
return (Element *) 0; { if ((r = rev_escape(e->nxt)) == ZE) /* reversed order */
{ r = eval_sub(e->this->frst);
} }
if ((r = rev_escape(e->nxt)) != ZE) /* reversed order */ return r;
return r;
return eval_sub(e->this->frst);
} }
Element * Element *
eval_sub(Element *e) eval_sub(Element *e)
{ Element *f, *g; { Element *f, *g;
SeqList *z; SeqList *z;
int i, j, k; int i, j, k, only_pos;
if (!e->n) if (!e || !e->n)
return ZE; return ZE;
#ifdef DEBUG #ifdef DEBUG
printf("\n\teval_sub(%d %s: line %d) ", printf("\n\teval_sub(%d %s: line %d) ",
@ -69,8 +68,13 @@ eval_sub(Element *e)
#endif #endif
if (e->n->ntyp == GOTO) if (e->n->ntyp == GOTO)
{ if (Rvous) return ZE; { if (Rvous) return ZE;
LastStep = e; f = get_lab(e->n, 1); LastStep = e;
f = get_lab(e->n, 1);
f = huntele(f, e->status, -1); /* 5.2.3: was missing */
cross_dsteps(e->n, f->n); cross_dsteps(e->n, f->n);
#ifdef DEBUG
printf("GOTO leads to %d\n", f->seqno);
#endif
return f; return f;
} }
if (e->n->ntyp == UNLESS) if (e->n->ntyp == UNLESS)
@ -80,6 +84,7 @@ eval_sub(Element *e)
{ Element *has_else = ZE; { Element *has_else = ZE;
Element *bas_else = ZE; Element *bas_else = ZE;
int nr_else = 0, nr_choices = 0; int nr_else = 0, nr_choices = 0;
only_pos = -1;
if (interactive if (interactive
&& !MadeChoice && !E_Check && !MadeChoice && !E_Check
@ -89,8 +94,10 @@ eval_sub(Element *e)
{ printf("Select stmnt ("); { printf("Select stmnt (");
whoruns(0); printf(")\n"); whoruns(0); printf(")\n");
if (nproc-nstop > 1) if (nproc-nstop > 1)
printf("\tchoice 0: other process\n"); { printf("\tchoice 0: other process\n");
} nr_choices++;
only_pos = 0;
} }
for (z = e->sub, j=0; z; z = z->nxt) for (z = e->sub, j=0; z; z = z->nxt)
{ j++; { j++;
if (interactive if (interactive
@ -113,13 +120,21 @@ eval_sub(Element *e)
if (!Enabled0(z->this->frst)) if (!Enabled0(z->this->frst))
printf("unexecutable, "); printf("unexecutable, ");
else else
nr_choices++; { nr_choices++;
only_pos = j;
}
comment(stdout, z->this->frst->n, 0); comment(stdout, z->this->frst->n, 0);
printf("\n"); printf("\n");
} } } }
if (nr_choices == 0 && has_else) if (nr_choices == 0 && has_else)
printf("\tchoice %d: (else)\n", nr_else); { printf("\tchoice %d: (else)\n", nr_else);
only_pos = nr_else;
}
if (nr_choices <= 1 && only_pos != -1 && !MadeChoice)
{ MadeChoice = only_pos;
}
if (interactive && depth >= jumpsteps if (interactive && depth >= jumpsteps
&& !Escape_Check && !Escape_Check
@ -132,8 +147,11 @@ eval_sub(Element *e)
else else
printf("Select [0-%d]: ", j); printf("Select [0-%d]: ", j);
fflush(stdout); fflush(stdout);
scanf("%s", buf); if (scanf("%64s", buf) <= 0)
if (isdigit(buf[0])) { printf("no input\n");
return ZE;
}
if (isdigit((int)buf[0]))
k = atoi(buf); k = atoi(buf);
else else
{ if (buf[0] == 'q') { if (buf[0] == 'q')
@ -155,6 +173,7 @@ eval_sub(Element *e)
else else
k = Rand()%j; /* nondeterminism */ k = Rand()%j; /* nondeterminism */
} }
has_else = ZE; has_else = ZE;
bas_else = ZE; bas_else = ZE;
for (i = 0, z = e->sub; i < j+k; i++) for (i = 0, z = e->sub; i < j+k; i++)
@ -215,7 +234,7 @@ eval_sub(Element *e)
} else } else
{ SeqList *x; { SeqList *x;
if (!(e->status & (D_ATOM)) if (!(e->status & (D_ATOM))
&& e->esc && verbose&32) && e->esc && (verbose&32))
{ printf("Stmnt ["); { printf("Stmnt [");
comment(stdout, e->n, 0); comment(stdout, e->n, 0);
printf("] has escape(s): "); printf("] has escape(s): ");
@ -233,12 +252,19 @@ eval_sub(Element *e)
#if 0 #if 0
if (!(e->status & D_ATOM)) /* escapes don't reach inside d_steps */ if (!(e->status & D_ATOM)) /* escapes don't reach inside d_steps */
/* 4.2.4: only the guard of a d_step can have an escape */ /* 4.2.4: only the guard of a d_step can have an escape */
#endif
#if 1
if (!s_trail) /* trail determines selections, new 5.2.5 */
#endif #endif
{ Escape_Check++; { Escape_Check++;
if (like_java) if (like_java)
{ if ((g = rev_escape(e->esc)) != ZE) { if ((g = rev_escape(e->esc)) != ZE)
{ if (verbose&4) { if (verbose&4)
printf("\tEscape taken\n"); { printf("\tEscape taken (-J) ");
if (g->n && g->n->fn)
printf("%s:%d", g->n->fn->name, g->n->ln);
printf("\n");
}
Escape_Check--; Escape_Check--;
return g; return g;
} }
@ -246,18 +272,24 @@ eval_sub(Element *e)
{ for (x = e->esc; x; x = x->nxt) { for (x = e->esc; x; x = x->nxt)
{ if ((g = eval_sub(x->this->frst)) != ZE) { if ((g = eval_sub(x->this->frst)) != ZE)
{ if (verbose&4) { if (verbose&4)
printf("\tEscape taken\n"); { printf("\tEscape taken ");
if (g->n && g->n->fn)
printf("%s:%d", g->n->fn->name, g->n->ln);
printf("\n");
}
Escape_Check--; Escape_Check--;
return g; return g;
} } } } } }
Escape_Check--; Escape_Check--;
} }
switch (e->n->ntyp) { switch (e->n->ntyp) {
case ASGN:
if (check_track(e->n) == STRUCT) { break; }
/* else fall thru */
case TIMEOUT: case RUN: case TIMEOUT: case RUN:
case PRINT: case PRINTM: case PRINT: case PRINTM:
case C_CODE: case C_EXPR: case C_CODE: case C_EXPR:
case ASGN: case ASSERT: case ASSERT:
case 's': case 'r': case 'c': case 's': case 'r': case 'c':
/* toplevel statements only */ /* toplevel statements only */
LastStep = e; LastStep = e;
@ -308,7 +340,8 @@ assign(Lextok *now)
t = Sym_typ(now->rgt); t = Sym_typ(now->rgt);
break; break;
} }
typ_ck(Sym_typ(now->lft), t, "assignment"); typ_ck(Sym_typ(now->lft), t, "assignment");
return setval(now->lft, eval(now->rgt)); return setval(now->lft, eval(now->rgt));
} }
@ -371,6 +404,10 @@ eval(Lextok *now)
case NEMPTY: return (qlen(now)>0); case NEMPTY: return (qlen(now)>0);
case ENABLED: if (s_trail) return 1; case ENABLED: if (s_trail) return 1;
return pc_enabled(now->lft); return pc_enabled(now->lft);
case GET_P: return get_priority(now->lft);
case SET_P: set_priority(now->lft->lft, now->lft->rgt); return 1;
case EVAL: return eval(now->lft); case EVAL: return eval(now->lft);
case PC_VAL: return pc_value(now->lft); case PC_VAL: return pc_value(now->lft);
case NONPROGRESS: return nonprogress(); case NONPROGRESS: return nonprogress();
@ -384,15 +421,21 @@ eval(Lextok *now)
case 'c': return eval(now->lft); /* condition */ case 'c': return eval(now->lft); /* condition */
case PRINT: return TstOnly?1:interprint(stdout, now); case PRINT: return TstOnly?1:interprint(stdout, now);
case PRINTM: return TstOnly?1:printm(stdout, now); case PRINTM: return TstOnly?1:printm(stdout, now);
case ASGN: return assign(now); case ASGN:
if (check_track(now) == STRUCT) { return 1; }
return assign(now);
case C_CODE: printf("%s:\t", now->sym->name); case C_CODE: if (!analyze)
plunk_inline(stdout, now->sym->name, 0); { printf("%s:\t", now->sym->name);
plunk_inline(stdout, now->sym->name, 0, 1);
}
return 1; /* uninterpreted */ return 1; /* uninterpreted */
case C_EXPR: printf("%s:\t", now->sym->name); case C_EXPR: if (!analyze)
plunk_expr(stdout, now->sym->name); { printf("%s:\t", now->sym->name);
printf("\n"); plunk_expr(stdout, now->sym->name);
printf("\n");
}
return 1; /* uninterpreted */ return 1; /* uninterpreted */
case ASSERT: if (TstOnly || eval(now->lft)) return 1; case ASSERT: if (TstOnly || eval(now->lft)) return 1;
@ -407,6 +450,11 @@ eval(Lextok *now)
case '.': return 1; /* return label for compound */ case '.': return 1; /* return label for compound */
case '@': return 0; /* stop state */ case '@': return 0; /* stop state */
case ELSE: return 1; /* only hit here in guided trails */ case ELSE: return 1; /* only hit here in guided trails */
case ',': /* reached through option -A with array initializer */
case 0:
return 0; /* not great, but safe */
default : printf("spin: bad node type %d (run)\n", now->ntyp); default : printf("spin: bad node type %d (run)\n", now->ntyp);
if (s_trail) printf("spin: trail file doesn't match spec?\n"); if (s_trail) printf("spin: trail file doesn't match spec?\n");
fatal("aborting", 0); fatal("aborting", 0);
@ -426,7 +474,6 @@ printm(FILE *fd, Lextok *n)
j = n->lft->val; j = n->lft->val;
else else
j = eval(n->lft); j = eval(n->lft);
Buf[0] = '\0';
sr_buf(j, 1); sr_buf(j, 1);
dotag(fd, Buf); dotag(fd, Buf);
} }
@ -437,9 +484,9 @@ int
interprint(FILE *fd, Lextok *n) interprint(FILE *fd, Lextok *n)
{ Lextok *tmp = n->lft; { Lextok *tmp = n->lft;
char c, *s = n->sym->name; char c, *s = n->sym->name;
int i, j; char lbuf[512]; int i, j; char lbuf[512]; /* matches value in sr_buf() */
extern char Buf[]; extern char Buf[]; /* global, size 4096 */
char tBuf[4096]; char tBuf[4096]; /* match size of global Buf[] */
Buf[0] = '\0'; Buf[0] = '\0';
if (!no_print) if (!no_print)
@ -490,7 +537,7 @@ append: strcat(Buf, lbuf);
} }
dotag(fd, Buf); dotag(fd, Buf);
} }
if (strlen(Buf) > 4096) fatal("printf string too long", 0); if (strlen(Buf) >= 4096) fatal("printf string too long", 0);
return 1; return 1;
} }
@ -512,6 +559,7 @@ Enabled1(Lextok *n)
verbose = v; verbose = v;
return i; return i;
case SET_P:
case C_CODE: case C_EXPR: case C_CODE: case C_EXPR:
case PRINT: case PRINTM: case PRINT: case PRINTM:
case ASGN: case ASSERT: case ASGN: case ASSERT:
@ -552,6 +600,7 @@ Enabled0(Element *e)
case '@': case '@':
return X->pid == (nproc-nstop-1); return X->pid == (nproc-nstop-1);
case '.': case '.':
case SET_P:
return 1; return 1;
case GOTO: case GOTO:
if (Rvous) return 0; if (Rvous) return 0;
@ -594,9 +643,91 @@ pc_enabled(Lextok *n)
for (Y = run; Y; Y = Y->nxt) for (Y = run; Y; Y = Y->nxt)
if (--i == pid) if (--i == pid)
{ oX = X; X = Y; { oX = X; X = Y;
result = Enabled0(Y->pc); result = Enabled0(X->pc);
X = oX; X = oX;
break; break;
} }
return result; return result;
} }
int
pc_highest(Lextok *n)
{ int i = nproc - nstop;
int pid = eval(n);
int target = 0, result = 1;
RunList *Y, *oX;
if (X->prov && !eval(X->prov)) return 0; /* can't be highest unless fully enabled */
for (Y = run; Y; Y = Y->nxt)
{ if (--i == pid)
{ target = Y->priority;
break;
} }
if (0) printf("highest for pid %d @ priority = %d\n", pid, target);
oX = X;
i = nproc - nstop;
for (Y = run; Y; Y = Y->nxt)
{ i--;
if (0) printf(" pid %d @ priority %d\t", Y->pid, Y->priority);
if (Y->priority > target)
{ X = Y;
if (0) printf("enabled: %s\n", Enabled0(X->pc)?"yes":"nope");
if (0) printf("provided: %s\n", eval(X->prov)?"yes":"nope");
if (Enabled0(X->pc) && (!X->prov || eval(X->prov)))
{ result = 0;
break;
} }
else
if (0) printf("\n");
}
X = oX;
return result;
}
int
get_priority(Lextok *n)
{ int i = nproc - nstop;
int pid = eval(n);
RunList *Y;
if (old_priority_rules)
{ return 1;
}
for (Y = run; Y; Y = Y->nxt)
{ if (--i == pid)
{ return Y->priority;
} }
return 0;
}
void
set_priority(Lextok *n, Lextok *p)
{ int i = nproc - nstop - Have_claim;
int pid = eval(n);
RunList *Y;
if (old_priority_rules)
{ return;
}
for (Y = run; Y; Y = Y->nxt)
{ if (--i == pid)
{ Priority_Sum -= Y->priority;
Y->priority = eval(p);
Priority_Sum += Y->priority;
if (1)
{ printf("%3d: setting priority of proc %d (%s) to %d\n",
depth, pid, Y->n->name, Y->priority);
} } }
if (verbose&32)
{ printf("\tPid\tName\tPriority\n");
for (Y = run; Y; Y = Y->nxt)
{ printf("\t%d\t%s\t%d\n",
Y->pid,
Y->n->name,
Y->priority);
} }
}

View file

@ -1,13 +1,10 @@
/***** spin: sched.c *****/ /***** spin: sched.c *****/
/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 <stdlib.h> #include <stdlib.h>
#include "spin.h" #include "spin.h"
@ -19,19 +16,21 @@ extern Ordered *all_names;
extern Symbol *Fname, *context; extern Symbol *Fname, *context;
extern int lineno, nr_errs, dumptab, xspin, jumpsteps, columns; extern int lineno, nr_errs, dumptab, xspin, jumpsteps, columns;
extern int u_sync, Elcnt, interactive, TstOnly, cutoff; extern int u_sync, Elcnt, interactive, TstOnly, cutoff;
extern short has_enabled; extern short has_enabled, has_priority, has_code, replay;
extern int limited_vis; extern int limited_vis, product, nclaims, old_priority_rules;
extern int old_scope_rules, scope_seq[128], scope_level, has_stdin;
extern int pc_highest(Lextok *n);
RunList *X = (RunList *) 0; RunList *X = (RunList *) 0;
RunList *run = (RunList *) 0; RunList *run = (RunList *) 0;
RunList *LastX = (RunList *) 0; /* previous executing proc */ RunList *LastX = (RunList *) 0; /* previous executing proc */
ProcList *rdy = (ProcList *) 0; ProcList *rdy = (ProcList *) 0;
Element *LastStep = ZE; Element *LastStep = ZE;
int nproc=0, nstop=0, Tval=0; int nproc=0, nstop=0, Tval=0, Priority_Sum = 0;
int Rvous=0, depth=0, nrRdy=0, MadeChoice; int Rvous=0, depth=0, nrRdy=0, MadeChoice;
short Have_claim=0, Skip_claim=0; short Have_claim=0, Skip_claim=0;
static int Priority_Sum = 0;
static void setlocals(RunList *); static void setlocals(RunList *);
static void setparams(RunList *, ProcList *, Lextok *); static void setparams(RunList *, ProcList *, Lextok *);
static void talk(RunList *); static void talk(RunList *);
@ -42,13 +41,20 @@ runnable(ProcList *p, int weight, int noparams)
r->n = p->n; r->n = p->n;
r->tn = p->tn; r->tn = p->tn;
r->b = p->b;
r->pid = nproc++ - nstop + Skip_claim; r->pid = nproc++ - nstop + Skip_claim;
r->priority = weight;
p->priority = (unsigned char) weight; /* not quite the best place of course */
if ((verbose&4) || (verbose&32)) if (!noparams && ((verbose&4) || (verbose&32)))
printf("Starting %s with pid %d\n", p->n->name, r->pid); { printf("Starting %s with pid %d",
p->n?p->n->name:"--", r->pid);
if (has_priority) printf(" priority %d", r->priority);
printf("\n");
}
if (!p->s) if (!p->s)
fatal("parsing error, no sequence %s", p->n?p->n->name:"--"); fatal("parsing error, no sequence %s",
p->n?p->n->name:"--");
r->pc = huntele(p->s->frst, p->s->frst->status, -1); r->pc = huntele(p->s->frst, p->s->frst->status, -1);
r->ps = p->s; r->ps = p->s;
@ -58,14 +64,18 @@ runnable(ProcList *p, int weight, int noparams)
r->nxt = run; r->nxt = run;
r->prov = p->prov; r->prov = p->prov;
r->priority = weight; if (weight < 1 || weight > 255)
{ fatal("bad process priority, valid range: 1..255", (char *) 0);
}
if (noparams) setlocals(r); if (noparams) setlocals(r);
Priority_Sum += weight; Priority_Sum += weight;
run = r; run = r;
} }
ProcList * ProcList *
ready(Symbol *n, Lextok *p, Sequence *s, int det, Lextok *prov) ready(Symbol *n, Lextok *p, Sequence *s, int det, Lextok *prov, enum btypes b)
/* n=name, p=formals, s=body det=deterministic prov=provided */ /* n=name, p=formals, s=body det=deterministic prov=provided */
{ ProcList *r = (ProcList *) emalloc(sizeof(ProcList)); { ProcList *r = (ProcList *) emalloc(sizeof(ProcList));
Lextok *fp, *fpt; int j; extern int Npars; Lextok *fp, *fpt; int j; extern int Npars;
@ -73,9 +83,15 @@ ready(Symbol *n, Lextok *p, Sequence *s, int det, Lextok *prov)
r->n = n; r->n = n;
r->p = p; r->p = p;
r->s = s; r->s = s;
r->b = b;
r->prov = prov; r->prov = prov;
r->tn = nrRdy++; r->tn = (short) nrRdy++;
r->det = (short) det; n->sc = scope_seq[scope_level]; /* scope_level should be 0 */
if (det != 0 && det != 1)
{ fprintf(stderr, "spin: bad value for det (cannot happen)\n");
}
r->det = (unsigned char) det;
r->nxt = rdy; r->nxt = rdy;
rdy = r; rdy = r;
@ -128,13 +144,15 @@ announce(char *w)
run->pid - Have_claim, run->n->name); run->pid - Have_claim, run->n->name);
pstext(run->pid - Have_claim, Buf); pstext(run->pid - Have_claim, Buf);
} else } else
printf("proc %d = %s\n", { printf("proc %d = %s\n",
run->pid - Have_claim, run->n->name); run->pid - Have_claim, run->n->name);
}
return; return;
} }
if (dumptab if (dumptab
|| analyze || analyze
|| product
|| s_trail || s_trail
|| !(verbose&4)) || !(verbose&4))
return; return;
@ -161,9 +179,11 @@ enable(Lextok *m)
Symbol *s = m->sym; /* proctype name */ Symbol *s = m->sym; /* proctype name */
Lextok *n = m->lft; /* actual parameters */ Lextok *n = m->lft; /* actual parameters */
if (m->val < 1) m->val = 1; /* minimum priority */ if (m->val < 1)
{ m->val = 1; /* minimum priority */
}
for (p = rdy; p; p = p->nxt) for (p = rdy; p; p = p->nxt)
if (strcmp(s->name, p->n->name) == 0) { if (strcmp(s->name, p->n->name) == 0)
{ if (nproc-nstop >= MAXP) { if (nproc-nstop >= MAXP)
{ printf("spin: too many processes (%d max)\n", MAXP); { printf("spin: too many processes (%d max)\n", MAXP);
break; break;
@ -173,7 +193,7 @@ enable(Lextok *m)
setparams(run, p, n); setparams(run, p, n);
setlocals(run); /* after setparams */ setlocals(run); /* after setparams */
return run->pid - Have_claim + Skip_claim; /* effective simu pid */ return run->pid - Have_claim + Skip_claim; /* effective simu pid */
} } }
return 0; /* process not found */ return 0; /* process not found */
} }
@ -208,26 +228,29 @@ start_claim(int n)
RunList *r, *q = (RunList *) 0; RunList *r, *q = (RunList *) 0;
for (p = rdy; p; p = p->nxt) for (p = rdy; p; p = p->nxt)
if (p->tn == n if (p->tn == n && p->b == N_CLAIM)
&& strcmp(p->n->name, ":never:") == 0)
{ runnable(p, 1, 1); { runnable(p, 1, 1);
goto found; goto found;
} }
printf("spin: couldn't find claim (ignored)\n"); printf("spin: couldn't find claim %d (ignored)\n", n);
if (verbose&32)
for (p = rdy; p; p = p->nxt)
printf("\t%d = %s\n", p->tn, p->n->name);
Skip_claim = 1; Skip_claim = 1;
goto done; goto done;
found: found:
/* move claim to far end of runlist, and reassign it pid 0 */ /* move claim to far end of runlist, and reassign it pid 0 */
if (columns == 2) if (columns == 2)
{ depth = 0; { extern char Buf[];
pstext(0, "0::never:"); depth = 0;
sprintf(Buf, "%d:%s", 0, p->n->name);
pstext(0, Buf);
for (r = run; r; r = r->nxt) for (r = run; r; r = r->nxt)
{ if (!strcmp(r->n->name, ":never:")) { if (r->b != N_CLAIM)
continue; { sprintf(Buf, "%d:%s", r->pid+1, r->n->name);
sprintf(Buf, "%d:%s", pstext(r->pid+1, Buf);
r->pid+1, r->n->name); } } }
pstext(r->pid+1, Buf);
} }
if (run->pid == 0) return; /* it is the first process started */ if (run->pid == 0) return; /* it is the first process started */
@ -288,7 +311,7 @@ wrapup(int fini)
nproc - Have_claim + Skip_claim, nproc - Have_claim + Skip_claim,
(xspin || nproc!=1)?"es":""); (xspin || nproc!=1)?"es":"");
short_cut: short_cut:
if (xspin) alldone(0); /* avoid an abort from xspin */ if (s_trail || xspin) alldone(0); /* avoid an abort from xspin */
if (fini) alldone(1); if (fini) alldone(1);
} }
@ -332,6 +355,24 @@ silent_moves(Element *e)
return e; return e;
} }
static int
x_can_run(void) /* the currently selected process in X can run */
{
if (X->prov && !eval(X->prov))
{
if (0) printf("pid %d cannot run: not provided\n", X->pid);
return 0;
}
if (has_priority && !old_priority_rules)
{ Lextok *n = nn(ZN, CONST, ZN, ZN);
n->val = X->pid;
if (0) printf("pid %d %s run (priority)\n", X->pid, pc_highest(n)?"can":"cannot");
return pc_highest(n);
}
if (0) printf("pid %d can run\n", X->pid);
return 1;
}
static RunList * static RunList *
pickproc(RunList *Y) pickproc(RunList *Y)
{ SeqList *z; Element *has_else; { SeqList *z; Element *has_else;
@ -343,7 +384,25 @@ pickproc(RunList *Y)
return NULL; return NULL;
} }
if (!interactive || depth < jumpsteps) if (!interactive || depth < jumpsteps)
{ /* was: j = (int) Rand()%(nproc-nstop); */ { if (has_priority && !old_priority_rules) /* new 6.3.2 */
{ j = Rand()%(nproc-nstop);
for (X = run; X; X = X->nxt)
{ if (j-- <= 0)
break;
}
if (X == NULL)
{ fatal("unexpected, pickproc", (char *)0);
}
j = nproc - nstop;
while (j-- > 0)
{ if (x_can_run())
{ Y = X;
break;
}
X = (X->nxt)?X->nxt:run;
}
return Y;
}
if (Priority_Sum < nproc-nstop) if (Priority_Sum < nproc-nstop)
fatal("cannot happen - weights", (char *)0); fatal("cannot happen - weights", (char *)0);
j = (int) Rand()%Priority_Sum; j = (int) Rand()%Priority_Sum;
@ -354,6 +413,7 @@ pickproc(RunList *Y)
X = X->nxt; X = X->nxt;
if (!X) { Y = NULL; X = run; } if (!X) { Y = NULL; X = run; }
} }
} else } else
{ int only_choice = -1; { int only_choice = -1;
int no_choice = 0, proc_no_ch, proc_k; int no_choice = 0, proc_no_ch, proc_k;
@ -365,8 +425,7 @@ try_more: for (X = run, k = 1; X; X = X->nxt)
Choices[X->pid] = (short) k; Choices[X->pid] = (short) k;
if (!X->pc if (!X->pc || !x_can_run())
|| (X->prov && !eval(X->prov)))
{ if (X == run) { if (X == run)
Choices[X->pid] = 0; Choices[X->pid] = 0;
continue; continue;
@ -457,9 +516,12 @@ try_more: for (X = run, k = 1; X; X = X->nxt)
} else } else
{ char buf[256]; { char buf[256];
fflush(stdout); fflush(stdout);
scanf("%s", buf); if (scanf("%64s", buf) == 0)
{ printf("\tno input\n");
goto try_again;
}
j = -1; j = -1;
if (isdigit(buf[0])) if (isdigit((int) buf[0]))
j = atoi(buf); j = atoi(buf);
else else
{ if (buf[0] == 'q') { if (buf[0] == 'q')
@ -483,6 +545,26 @@ try_more: for (X = run, k = 1; X; X = X->nxt)
return Y; return Y;
} }
void
multi_claims(void)
{ ProcList *p, *q = NULL;
if (nclaims > 1)
{ printf(" the model contains %d never claims:", nclaims);
for (p = rdy; p; p = p->nxt)
{ if (p->b == N_CLAIM)
{ printf("%s%s", q?", ":" ", p->n->name);
q = p;
} }
printf("\n");
printf(" only one claim is used in a verification run\n");
printf(" choose which one with ./pan -a -N name (defaults to -N %s)\n",
q?q->n->name:"--");
printf(" or use e.g.: spin -search -ltl %s %s\n",
q?q->n->name:"--", Fname?Fname->name:"filename");
}
}
void void
sched(void) sched(void)
{ Element *e; { Element *e;
@ -498,19 +580,33 @@ sched(void)
dumplabels(); dumplabels();
return; return;
} }
if (has_code && !analyze)
{ printf("spin: warning: c_code fragments remain uninterpreted\n");
printf(" in random simulations with spin; use ./pan -r instead\n");
}
if (has_enabled && u_sync > 0) if (has_enabled && u_sync > 0)
{ printf("spin: error, cannot use 'enabled()' in "); { printf("spin: error, cannot use 'enabled()' in ");
printf("models with synchronous channels.\n"); printf("models with synchronous channels.\n");
nr_errs++; nr_errs++;
} }
if (analyze) if (product)
{ sync_product();
alldone(0);
}
if (analyze && (!replay || has_code))
{ gensrc(); { gensrc();
multi_claims();
return; return;
} else if (s_trail) }
if (replay && !has_code)
{ return;
}
if (s_trail)
{ match_trail(); { match_trail();
return; return;
} }
if (claimproc) if (claimproc)
printf("warning: never claim not used in random simulation\n"); printf("warning: never claim not used in random simulation\n");
if (eventmap) if (eventmap)
@ -543,9 +639,9 @@ sched(void)
depth++; LastStep = ZE; depth++; LastStep = ZE;
oX = X; /* a rendezvous could change it */ oX = X; /* a rendezvous could change it */
go = 1; go = 1;
if (X && X->prov && X->pc if (X->pc
&& !(X->pc->status & D_ATOM) && !(X->pc->status & D_ATOM)
&& !eval(X->prov)) && !x_can_run())
{ if (!xspin && ((verbose&32) || (verbose&4))) { if (!xspin && ((verbose&32) || (verbose&4)))
{ p_talk(X->pc, 1); { p_talk(X->pc, 1);
printf("\t<<Not Enabled>>\n"); printf("\t<<Not Enabled>>\n");
@ -557,9 +653,10 @@ sched(void)
&& ((verbose&32) || (verbose&4))) && ((verbose&32) || (verbose&4)))
{ if (X == oX) { if (X == oX)
if (!(e->status & D_ATOM) || (verbose&32)) /* no talking in d_steps */ if (!(e->status & D_ATOM) || (verbose&32)) /* no talking in d_steps */
{ p_talk(X->pc, 1); { if (!LastStep) LastStep = X->pc;
/* A. Tanaka, changed order */
p_talk(LastStep, 1);
printf(" ["); printf(" [");
if (!LastStep) LastStep = X->pc;
comment(stdout, LastStep->n, 0); comment(stdout, LastStep->n, 0);
printf("]\n"); printf("]\n");
} }
@ -570,7 +667,8 @@ sched(void)
if (xspin) if (xspin)
printf("\n"); printf("\n");
} }
if (oX != X) if (oX != X
|| (X->pc->status & (ATOM|D_ATOM))) /* new 5.0 */
{ e = silent_moves(e); { e = silent_moves(e);
notbeyond = 0; notbeyond = 0;
} }
@ -587,10 +685,12 @@ sched(void)
} }
} else } else
{ depth--; { depth--;
if (oX->pc->status & D_ATOM) if (oX->pc && (oX->pc->status & D_ATOM))
non_fatal("stmnt in d_step blocks", (char *)0); { non_fatal("stmnt in d_step blocks", (char *)0);
}
if (X->pc->n->ntyp == '@' if (X->pc
&& X->pc->n
&& X->pc->n->ntyp == '@'
&& X->pid == (nproc-nstop-1)) && X->pid == (nproc-nstop-1))
{ if (X != run && Y != NULL) { if (X != run && Y != NULL)
Y->nxt = X->nxt; Y->nxt = X->nxt;
@ -610,14 +710,19 @@ sched(void)
X = (X->nxt) ? X->nxt : run; X = (X->nxt) ? X->nxt : run;
} else } else
{ if (p_blocked(X->pid)) { if (p_blocked(X->pid))
{ if (Tval) break; { if (Tval && !has_stdin)
Tval = 1; { break;
if (depth >= jumpsteps) }
if (!Tval && depth >= jumpsteps)
{ oX = X; { oX = X;
X = (RunList *) 0; /* to suppress indent */ X = (RunList *) 0; /* to suppress indent */
dotag(stdout, "timeout\n"); dotag(stdout, "timeout\n");
X = oX; X = oX;
Tval = 1;
} } } } } } } }
if (!run || !X) break; /* new 5.0 */
Y = pickproc(X); Y = pickproc(X);
notbeyond = 0; notbeyond = 0;
} }
@ -662,7 +767,7 @@ complete_rendez(void)
printf(" ["); printf(" [");
comment(stdout, s_was->n, 0); comment(stdout, s_was->n, 0);
printf("]\n"); printf("]\n");
tmp = orun; orun = X; X = tmp; tmp = orun; /* orun = X; */ X = tmp;
if (!LastStep) LastStep = X->pc; if (!LastStep) LastStep = X->pc;
p_talk(LastStep, 1); p_talk(LastStep, 1);
printf(" ["); printf(" [");
@ -692,25 +797,33 @@ addsymbol(RunList *r, Symbol *s)
int i; int i;
for (t = r->symtab; t; t = t->next) for (t = r->symtab; t; t = t->next)
if (strcmp(t->name, s->name) == 0) if (strcmp(t->name, s->name) == 0
&& (old_scope_rules
|| strcmp((const char *)t->bscp, (const char *)s->bscp) == 0))
return; /* it's already there */ return; /* it's already there */
t = (Symbol *) emalloc(sizeof(Symbol)); t = (Symbol *) emalloc(sizeof(Symbol));
t->name = s->name; t->name = s->name;
t->type = s->type; t->type = s->type;
t->hidden = s->hidden; t->hidden = s->hidden;
t->isarray = s->isarray;
t->nbits = s->nbits; t->nbits = s->nbits;
t->nel = s->nel; t->nel = s->nel;
t->ini = s->ini; t->ini = s->ini;
t->setat = depth; t->setat = depth;
t->context = r->n; t->context = r->n;
t->bscp = (unsigned char *) emalloc(strlen((const char *)s->bscp)+1);
strcpy((char *)t->bscp, (const char *)s->bscp);
if (s->type != STRUCT) if (s->type != STRUCT)
{ if (s->val) /* if already initialized, copy info */ { if (s->val) /* if already initialized, copy info */
{ t->val = (int *) emalloc(s->nel*sizeof(int)); { t->val = (int *) emalloc(s->nel*sizeof(int));
for (i = 0; i < s->nel; i++) for (i = 0; i < s->nel; i++)
t->val[i] = s->val[i]; t->val[i] = s->val[i];
} else } else
(void) checkvar(t, 0); /* initialize it */ { (void) checkvar(t, 0); /* initialize it */
}
} else } else
{ if (s->Sval) { if (s->Sval)
fatal("saw preinitialized struct %s", s->name); fatal("saw preinitialized struct %s", s->name);
@ -759,7 +872,7 @@ oneparam(RunList *r, Lextok *t, Lextok *a, ProcList *p)
if (!a) if (!a)
fatal("missing actual parameters: '%s'", p->n->name); fatal("missing actual parameters: '%s'", p->n->name);
if (t->sym->nel != 1) if (t->sym->nel > 1 || t->sym->isarray)
fatal("array in parameter list, %s", t->sym->name); fatal("array in parameter list, %s", t->sym->name);
k = eval(a->lft); k = eval(a->lft);
@ -768,7 +881,7 @@ oneparam(RunList *r, Lextok *t, Lextok *a, ProcList *p)
ft = Sym_typ(t); ft = Sym_typ(t);
if (at != ft && (at == CHAN || ft == CHAN)) if (at != ft && (at == CHAN || ft == CHAN))
{ char buf[128], tag1[64], tag2[64]; { char buf[256], tag1[64], tag2[64];
(void) sputtype(tag1, ft); (void) sputtype(tag1, ft);
(void) sputtype(tag2, at); (void) sputtype(tag2, at);
sprintf(buf, "type-clash in params of %s(..), (%s<-> %s)", sprintf(buf, "type-clash in params of %s(..), (%s<-> %s)",
@ -809,8 +922,11 @@ findloc(Symbol *s)
return ZS; return ZS;
} }
for (r = X->symtab; r; r = r->next) for (r = X->symtab; r; r = r->next)
if (strcmp(r->name, s->name) == 0) { if (strcmp(r->name, s->name) == 0
break; && (old_scope_rules
|| strcmp((const char *)r->bscp, (const char *)s->bscp) == 0))
{ break;
} }
if (!r) if (!r)
{ addsymbol(X, s); { addsymbol(X, s);
r = X->symtab; r = X->symtab;
@ -878,7 +994,11 @@ whoruns(int lnr)
printf(" -"); printf(" -");
else else
printf("%2d", X->pid - Have_claim); printf("%2d", X->pid - Have_claim);
printf(" (%s) ", X->n->name); if (old_priority_rules)
{ printf(" (%s) ", X->n->name);
} else
{ printf(" (%s:%d) ", X->n->name, X->priority);
}
} }
static void static void
@ -895,6 +1015,7 @@ talk(RunList *r)
void void
p_talk(Element *e, int lnr) p_talk(Element *e, int lnr)
{ static int lastnever = -1; { static int lastnever = -1;
static char nbuf[128];
int newnever = -1; int newnever = -1;
if (e && e->n) if (e && e->n)
@ -918,9 +1039,22 @@ p_talk(Element *e, int lnr)
whoruns(lnr); whoruns(lnr);
if (e) if (e)
{ printf("line %3d %s (state %d)", { if (e->n)
{ char *ptr = e->n->fn->name;
char *qtr = nbuf;
while (*ptr != '\0')
{ if (*ptr != '"')
{ *qtr++ = *ptr;
}
ptr++;
}
*qtr = '\0';
} else
{ strcpy(nbuf, "-");
}
printf("%s:%d (state %d)",
nbuf,
e->n?e->n->ln:-1, e->n?e->n->ln:-1,
e->n?e->n->fn->name:"-",
e->seqno); e->seqno);
if (!xspin if (!xspin
&& ((e->status&ENDSTATE) || has_lab(e, 2))) /* 2=end */ && ((e->status&ENDSTATE) || has_lab(e, 2))) /* 2=end */
@ -943,8 +1077,9 @@ remotelab(Lextok *n)
{ fatal("remote ref to label '%s' inside d_step", { fatal("remote ref to label '%s' inside d_step",
n->sym->name); n->sym->name);
} }
if ((i = find_lab(n->sym, n->lft->sym, 1)) == 0) if ((i = find_lab(n->sym, n->lft->sym, 1)) == 0) /* remotelab */
fatal("unknown labelname: %s", n->sym->name); { fatal("unknown labelname: %s", n->sym->name);
}
return i; return i;
} }
@ -970,7 +1105,8 @@ remotevar(Lextok *n)
} } } }
if (prno < 0) if (prno < 0)
return 0; /* non-existing process */ { return 0; /* non-existing process */
}
#if 0 #if 0
i = nproc - nstop; i = nproc - nstop;
for (Y = run; Y; Y = Y->nxt) for (Y = run; Y; Y = Y->nxt)
@ -978,7 +1114,7 @@ remotevar(Lextok *n)
printf(" %s: i=%d, prno=%d, ->pid=%d\n", Y->n->name, i, prno, Y->pid); printf(" %s: i=%d, prno=%d, ->pid=%d\n", Y->n->name, i, prno, Y->pid);
} }
#endif #endif
i = nproc - nstop; i = nproc - nstop + Skip_claim; /* 6.0: added Skip_claim */
for (Y = run; Y; Y = Y->nxt) for (Y = run; Y; Y = Y->nxt)
if (--i == prno) if (--i == prno)
{ if (strcmp(Y->n->name, n->lft->sym->name) != 0) { if (strcmp(Y->n->name, n->lft->sym->name) != 0)
@ -988,12 +1124,13 @@ remotevar(Lextok *n)
} }
if (strcmp(n->sym->name, "_p") == 0) if (strcmp(n->sym->name, "_p") == 0)
{ if (Y->pc) { if (Y->pc)
return Y->pc->seqno; { return Y->pc->seqno;
}
/* harmless, can only happen with -t */ /* harmless, can only happen with -t */
return 0; return 0;
} }
#if 1
/* new 4.0 allow remote variables */ /* check remote variables */
oX = X; oX = X;
X = Y; X = Y;
@ -1001,17 +1138,20 @@ remotevar(Lextok *n)
n->lft = n->rgt; n->lft = n->rgt;
os = n->sym; os = n->sym;
n->sym = findloc(n->sym); if (!n->sym->context)
{ n->sym->context = Y->n;
}
{ int rs = old_scope_rules;
old_scope_rules = 1; /* 6.4.0 */
n->sym = findloc(n->sym);
old_scope_rules = rs;
}
i = getval(n); i = getval(n);
n->sym = os; n->sym = os;
n->lft = onl; n->lft = onl;
X = oX; X = oX;
return i; return i;
#else
break;
#endif
} }
printf("remote ref: %s[%d] ", n->lft->sym->name, prno-added); printf("remote ref: %s[%d] ", n->lft->sym->name, prno-added);
non_fatal("%s not found", n->sym->name); non_fatal("%s not found", n->sym->name);

View file

@ -1,13 +1,10 @@
/***** spin: spin.h *****/ /***** spin: spin.h *****/
/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 */
#ifndef SEEN_SPIN_H #ifndef SEEN_SPIN_H
#define SEEN_SPIN_H #define SEEN_SPIN_H
@ -15,6 +12,15 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#if !defined(WIN32) && !defined(WIN64)
#include <unistd.h>
#endif
#if !defined(PC) && !defined(_PLAN9)
#include <memory.h>
#endif
enum { INIV, PUTV, LOGV }; /* used in pangen1.c */
enum btypes { NONE, N_CLAIM, I_PROC, A_PROC, P_PROC, E_TRACE, N_TRACE };
typedef struct Lextok { typedef struct Lextok {
unsigned short ntyp; /* node type */ unsigned short ntyp; /* node type */
@ -22,6 +28,7 @@ typedef struct Lextok {
int val; /* value attribute */ int val; /* value attribute */
int ln; /* line number */ int ln; /* line number */
int indstep; /* part of d_step sequence */ int indstep; /* part of d_step sequence */
int uiid; /* inline id, if non-zero */
struct Symbol *fn; /* file name */ struct Symbol *fn; /* file name */
struct Symbol *sym; /* symbol reference */ struct Symbol *sym; /* symbol reference */
struct Sequence *sq; /* sequence */ struct Sequence *sq; /* sequence */
@ -54,6 +61,9 @@ typedef struct Symbol {
64=treat as if local; 128=read at least once 64=treat as if local; 128=read at least once
*/ */
unsigned char colnr; /* for use with xspin during simulation */ unsigned char colnr; /* for use with xspin during simulation */
unsigned char isarray; /* set if decl specifies array bound */
unsigned char *bscp; /* block scope */
int sc; /* scope seq no -- set only for proctypes */
int nbits; /* optional width specifier */ int nbits; /* optional width specifier */
int nel; /* 1 if scalar, >1 if array */ int nel; /* 1 if scalar, >1 if array */
int setat; /* last depth value changed */ int setat; /* last depth value changed */
@ -124,7 +134,7 @@ typedef struct Element {
int merge_single; int merge_single;
short merge_in; /* nr of incoming edges */ short merge_in; /* nr of incoming edges */
short merge_mark; /* state was generated in merge sequence */ short merge_mark; /* state was generated in merge sequence */
unsigned char status; /* used by analyzer generator */ unsigned int status; /* used by analyzer generator */
struct FSM_use *dead; /* optional dead variable list */ struct FSM_use *dead; /* optional dead variable list */
struct SeqList *sub; /* subsequences, for compounds */ struct SeqList *sub; /* subsequences, for compounds */
struct SeqList *esc; /* zero or more escape sequences */ struct SeqList *esc; /* zero or more escape sequences */
@ -136,6 +146,7 @@ typedef struct Sequence {
Element *frst; Element *frst;
Element *last; /* links onto continuations */ Element *last; /* links onto continuations */
Element *extent; /* last element in original */ Element *extent; /* last element in original */
int minel; /* minimum Seqno, set and used only in guided.c */
int maxel; /* 1+largest id in sequence */ int maxel; /* 1+largest id in sequence */
} Sequence; } Sequence;
@ -148,6 +159,7 @@ typedef struct Label {
Symbol *s; Symbol *s;
Symbol *c; Symbol *c;
Element *e; Element *e;
int uiid; /* non-zero if label appears in an inline */
int visible; /* label referenced in claim (slice relevant) */ int visible; /* label referenced in claim (slice relevant) */
struct Label *nxt; struct Label *nxt;
} Label; } Label;
@ -157,11 +169,17 @@ typedef struct Lbreak {
struct Lbreak *nxt; struct Lbreak *nxt;
} Lbreak; } Lbreak;
typedef struct L_List {
Lextok *n;
struct L_List *nxt;
} L_List;
typedef struct RunList { typedef struct RunList {
Symbol *n; /* name */ Symbol *n; /* name */
int tn; /* ordinal of type */ int tn; /* ordinal of type */
int pid; /* process id */ int pid; /* process id */
int priority; /* for simulations only */ int priority; /* for simulations only */
enum btypes b; /* the type of process */
Element *pc; /* current stmnt */ Element *pc; /* current stmnt */
Sequence *ps; /* used by analyzer generator */ Sequence *ps; /* used by analyzer generator */
Lextok *prov; /* provided clause */ Lextok *prov; /* provided clause */
@ -174,11 +192,19 @@ typedef struct ProcList {
Lextok *p; /* parameters */ Lextok *p; /* parameters */
Sequence *s; /* body */ Sequence *s; /* body */
Lextok *prov; /* provided clause */ Lextok *prov; /* provided clause */
enum btypes b; /* e.g., claim, trace, proc */
short tn; /* ordinal number */ short tn; /* ordinal number */
short det; /* deterministic */ unsigned char det; /* deterministic */
unsigned char unsafe; /* contains global var inits */
unsigned char priority; /* process priority, if any */
struct ProcList *nxt; /* linked list */ struct ProcList *nxt; /* linked list */
} ProcList; } ProcList;
typedef struct QH {
int n;
struct QH *nxt;
} QH;
typedef Lextok *Lexptr; typedef Lextok *Lexptr;
#define YYSTYPE Lexptr #define YYSTYPE Lexptr
@ -194,7 +220,8 @@ typedef Lextok *Lexptr;
#define DONE2 16 /* used in putcode and main*/ #define DONE2 16 /* used in putcode and main*/
#define D_ATOM 32 /* deterministic atomic */ #define D_ATOM 32 /* deterministic atomic */
#define ENDSTATE 64 /* normal endstate */ #define ENDSTATE 64 /* normal endstate */
#define CHECK2 128 #define CHECK2 128 /* status bits for remote ref check */
#define CHECK3 256 /* status bits for atomic jump check */
#define Nhash 255 /* slots in symbol hash-table */ #define Nhash 255 /* slots in symbol hash-table */
@ -216,18 +243,24 @@ typedef Lextok *Lexptr;
#define SOMETHINGBIG 65536 #define SOMETHINGBIG 65536
#define RATHERSMALL 512 #define RATHERSMALL 512
#define MAXSCOPESZ 1024
#ifndef max #ifndef max
#define max(a,b) (((a)<(b)) ? (b) : (a)) #define max(a,b) (((a)<(b)) ? (b) : (a))
#endif #endif
enum { INIV, PUTV, LOGV }; /* for pangen[14].c */ #ifdef PC
#define MFLAGS "wb"
#else
#define MFLAGS "w"
#endif
/***** prototype definitions *****/ /***** prototype definitions *****/
Element *eval_sub(Element *); Element *eval_sub(Element *);
Element *get_lab(Lextok *, int); Element *get_lab(Lextok *, int);
Element *huntele(Element *, int, int); Element *huntele(Element *, unsigned int, int);
Element *huntstart(Element *); Element *huntstart(Element *);
Element *mk_skip(void);
Element *target(Element *); Element *target(Element *);
Lextok *do_unless(Lextok *, Lextok *); Lextok *do_unless(Lextok *, Lextok *);
@ -238,8 +271,9 @@ Lextok *nn(Lextok *, int, Lextok *, Lextok *);
Lextok *rem_lab(Symbol *, Lextok *, Symbol *); Lextok *rem_lab(Symbol *, Lextok *, Symbol *);
Lextok *rem_var(Symbol *, Lextok *, Symbol *, Lextok *); Lextok *rem_var(Symbol *, Lextok *, Symbol *, Lextok *);
Lextok *tail_add(Lextok *, Lextok *); Lextok *tail_add(Lextok *, Lextok *);
Lextok *return_statement(Lextok *);
ProcList *ready(Symbol *, Lextok *, Sequence *, int, Lextok *); ProcList *ready(Symbol *, Lextok *, Sequence *, int, Lextok *, enum btypes);
SeqList *seqlist(Sequence *, SeqList *); SeqList *seqlist(Sequence *, SeqList *);
Sequence *close_seq(int); Sequence *close_seq(int);
@ -250,7 +284,8 @@ Symbol *has_lab(Element *, int);
Symbol *lookup(char *); Symbol *lookup(char *);
Symbol *prep_inline(Symbol *, Lextok *); Symbol *prep_inline(Symbol *, Lextok *);
char *emalloc(int); char *put_inline(FILE *, char *);
char *emalloc(size_t);
long Rand(void); long Rand(void);
int any_oper(Lextok *, int); int any_oper(Lextok *, int);
@ -258,6 +293,7 @@ int any_undo(Lextok *);
int c_add_sv(FILE *); int c_add_sv(FILE *);
int cast_val(int, int, int); int cast_val(int, int, int);
int checkvar(Symbol *, int); int checkvar(Symbol *, int);
int check_track(Lextok *);
int Cnt_flds(Lextok *); int Cnt_flds(Lextok *);
int cnt_mpars(Lextok *); int cnt_mpars(Lextok *);
int complete_rendez(void); int complete_rendez(void);
@ -274,12 +310,14 @@ int has_typ(Lextok *, int);
int in_bound(Symbol *, int); int in_bound(Symbol *, int);
int interprint(FILE *, Lextok *); int interprint(FILE *, Lextok *);
int printm(FILE *, Lextok *); int printm(FILE *, Lextok *);
int is_inline(void);
int ismtype(char *); int ismtype(char *);
int isproctype(char *); int isproctype(char *);
int isutype(char *); int isutype(char *);
int Lval_struct(Lextok *, Symbol *, int, int); int Lval_struct(Lextok *, Symbol *, int, int);
int main(int, char **); int main(int, char **);
int pc_value(Lextok *); int pc_value(Lextok *);
int pid_is_claim(int);
int proper_enabler(Lextok *); int proper_enabler(Lextok *);
int putcode(FILE *, Sequence *, Element *, int, int, int); int putcode(FILE *, Sequence *, Element *, int, int, int);
int q_is_sync(Lextok *); int q_is_sync(Lextok *);
@ -298,7 +336,6 @@ int Sym_typ(Lextok *);
int tl_main(int, char *[]); int tl_main(int, char *[]);
int Width_set(int *, int, Lextok *); int Width_set(int *, int, Lextok *);
int yyparse(void); int yyparse(void);
int yywrap(void);
int yylex(void); int yylex(void);
void AST_track(Lextok *, int); void AST_track(Lextok *, int);
@ -309,7 +346,6 @@ void c_state(Symbol *, Symbol *, Symbol *);
void c_add_def(FILE *); void c_add_def(FILE *);
void c_add_loc(FILE *, char *); void c_add_loc(FILE *, char *);
void c_add_locinit(FILE *, int, char *); void c_add_locinit(FILE *, int, char *);
void c_add_use(FILE *);
void c_chandump(FILE *); void c_chandump(FILE *);
void c_preview(void); void c_preview(void);
void c_struct(FILE *, char *, Symbol *); void c_struct(FILE *, char *, Symbol *);
@ -321,6 +357,7 @@ void check_param_count(int, Lextok *);
void checkrun(Symbol *, int); void checkrun(Symbol *, int);
void comment(FILE *, Lextok *, int); void comment(FILE *, Lextok *, int);
void cross_dsteps(Lextok *, Lextok *); void cross_dsteps(Lextok *, Lextok *);
void disambiguate(void);
void doq(Symbol *, int, RunList *); void doq(Symbol *, int, RunList *);
void dotag(FILE *, char *); void dotag(FILE *, char *);
void do_locinits(FILE *); void do_locinits(FILE *);
@ -344,20 +381,22 @@ void genunio(void);
void ini_struct(Symbol *); void ini_struct(Symbol *);
void loose_ends(void); void loose_ends(void);
void make_atomic(Sequence *, int); void make_atomic(Sequence *, int);
void mark_last(void);
void match_trail(void); void match_trail(void);
void no_side_effects(char *); void no_side_effects(char *);
void nochan_manip(Lextok *, Lextok *, int); void nochan_manip(Lextok *, Lextok *, int);
void non_fatal(char *, char *); void non_fatal(char *, char *);
void ntimes(FILE *, int, int, char *c[]); void ntimes(FILE *, int, int, const char *c[]);
void open_seq(int); void open_seq(int);
void p_talk(Element *, int); void p_talk(Element *, int);
void pickup_inline(Symbol *, Lextok *); void pickup_inline(Symbol *, Lextok *, Lextok *);
void plunk_c_decls(FILE *); void plunk_c_decls(FILE *);
void plunk_c_fcts(FILE *); void plunk_c_fcts(FILE *);
void plunk_expr(FILE *, char *); void plunk_expr(FILE *, char *);
void plunk_inline(FILE *, char *, int); void plunk_inline(FILE *, char *, int, int);
void prehint(Symbol *); void prehint(Symbol *);
void preruse(FILE *, Lextok *); void preruse(FILE *, Lextok *);
void pretty_print(void);
void prune_opts(Lextok *); void prune_opts(Lextok *);
void pstext(int, char *); void pstext(int, char *);
void pushbreak(void); void pushbreak(void);
@ -383,17 +422,23 @@ void start_claim(int);
void struct_name(Lextok *, Symbol *, int, char *); void struct_name(Lextok *, Symbol *, int, char *);
void symdump(void); void symdump(void);
void symvar(Symbol *); void symvar(Symbol *);
void sync_product(void);
void trackchanuse(Lextok *, Lextok *, int); void trackchanuse(Lextok *, Lextok *, int);
void trackvar(Lextok *, Lextok *); void trackvar(Lextok *, Lextok *);
void trackrun(Lextok *); void trackrun(Lextok *);
void trapwonly(Lextok *, char *); /* spin.y and main.c */ void trapwonly(Lextok * /* , char * */); /* spin.y and main.c */
void typ2c(Symbol *); void typ2c(Symbol *);
void typ_ck(int, int, char *); void typ_ck(int, int, char *);
void undostmnt(Lextok *, int); void undostmnt(Lextok *, int);
void unrem_Seq(void); void unrem_Seq(void);
void unskip(int); void unskip(int);
void varcheck(Element *, Element *);
void whoruns(int); void whoruns(int);
void wrapup(int); void wrapup(int);
void yyerror(char *, ...); void yyerror(char *, ...);
extern int unlink(const char *);
#define TMP_FILE1 "._s_p_i_n_"
#define TMP_FILE2 "._n_i_p_s_"
#endif #endif

View file

@ -1,47 +1,69 @@
/***** spin: spin.y *****/ /***** spin: spin.y *****/
/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 "spin.h"
#include <sys/types.h>
#ifndef PC
#include <unistd.h>
#endif
#include <stdarg.h> #include <stdarg.h>
#define YYDEBUG 0 #define YYMAXDEPTH 20000 /* default is 10000 */
#define YYDEBUG 0
#define Stop nn(ZN,'@',ZN,ZN) #define Stop nn(ZN,'@',ZN,ZN)
#define PART0 "place initialized declaration of "
#define PART1 "place initialized chan decl of "
#define PART2 " at start of proctype "
static Lextok *ltl_to_string(Lextok *);
extern Symbol *context, *owner; extern Symbol *context, *owner;
extern int u_sync, u_async, dumptab; extern Lextok *for_body(Lextok *, int);
extern short has_sorted, has_random, has_enabled, has_pcvalue, has_np; extern void for_setup(Lextok *, Lextok *, Lextok *);
extern short has_code, has_state, has_io; extern Lextok *for_index(Lextok *, Lextok *);
extern Lextok *sel_index(Lextok *, Lextok *, Lextok *);
extern void keep_track_off(Lextok *);
extern void safe_break(void);
extern void restore_break(void);
extern int u_sync, u_async, dumptab, scope_level;
extern int initialization_ok;
extern short has_sorted, has_random, has_enabled, has_pcvalue, has_np, has_priority;
extern short has_code, has_state, has_ltl, has_io;
extern void count_runs(Lextok *); extern void count_runs(Lextok *);
extern void no_internals(Lextok *); extern void no_internals(Lextok *);
extern void any_runs(Lextok *); extern void any_runs(Lextok *);
extern void explain(int);
extern void ltl_list(char *, char *);
extern void validref(Lextok *, Lextok *); extern void validref(Lextok *, Lextok *);
extern void sanity_check(Lextok *);
extern char yytext[]; extern char yytext[];
int Mpars = 0; /* max nr of message parameters */ int Mpars = 0; /* max nr of message parameters */
int runsafe = 1; /* 1 if all run stmnts are in init */ int nclaims = 0; /* nr of never claims */
int ltl_mode = 0; /* set when parsing an ltl formula */
int Expand_Ok = 0, realread = 1, IArgs = 0, NamesNotAdded = 0; int Expand_Ok = 0, realread = 1, IArgs = 0, NamesNotAdded = 0;
int in_for = 0, in_seq = 0, par_cnt = 0;
int dont_simplify = 0;
char *claimproc = (char *) 0; char *claimproc = (char *) 0;
char *eventmap = (char *) 0; char *eventmap = (char *) 0;
static int Embedded = 0, inEventMap = 0, has_ini = 0; static char *ltl_name;
static int Embedded = 0, inEventMap = 0, has_ini = 0;
%} %}
%token ASSERT PRINT PRINTM %token ASSERT PRINT PRINTM PREPROC
%token C_CODE C_DECL C_EXPR C_STATE C_TRACK %token C_CODE C_DECL C_EXPR C_STATE C_TRACK
%token RUN LEN ENABLED EVAL PC_VAL %token RUN LEN ENABLED SET_P GET_P EVAL PC_VAL
%token TYPEDEF MTYPE INLINE LABEL OF %token TYPEDEF MTYPE INLINE RETURN LABEL OF
%token GOTO BREAK ELSE SEMI %token GOTO BREAK ELSE SEMI ARROW
%token IF FI DO OD SEP %token IF FI DO OD FOR SELECT IN SEP DOTDOT
%token ATOMIC NON_ATOMIC D_STEP UNLESS %token ATOMIC NON_ATOMIC D_STEP UNLESS
%token TIMEOUT NONPROGRESS %token TIMEOUT NONPROGRESS
%token ACTIVE PROCTYPE D_PROCTYPE %token ACTIVE PROCTYPE D_PROCTYPE
@ -50,12 +72,16 @@ static int Embedded = 0, inEventMap = 0, has_ini = 0;
%token FULL EMPTY NFULL NEMPTY %token FULL EMPTY NFULL NEMPTY
%token CONST TYPE XU /* val */ %token CONST TYPE XU /* val */
%token NAME UNAME PNAME INAME /* sym */ %token NAME UNAME PNAME INAME /* sym */
%token STRING CLAIM TRACE INIT /* sym */ %token STRING CLAIM TRACE INIT LTL /* sym */
%right ASGN %right ASGN
%left SND O_SND RCV R_RCV /* SND doubles as boolean negation */ %left SND O_SND RCV R_RCV /* SND doubles as boolean negation */
%left IMPLIES EQUIV /* ltl */
%left OR %left OR
%left AND %left AND
%left ALWAYS EVENTUALLY /* ltl */
%left UNTIL WEAK_UNTIL RELEASE /* ltl */
%right NEXT /* ltl */
%left '|' %left '|'
%left '^' %left '^'
%left '&' %left '&'
@ -81,17 +107,25 @@ units : unit
unit : proc /* proctype { } */ unit : proc /* proctype { } */
| init /* init { } */ | init /* init { } */
| claim /* never claim */ | claim /* never claim */
| ltl /* ltl formula */
| events /* event assertions */ | events /* event assertions */
| one_decl /* variables, chans */ | one_decl /* variables, chans */
| utype /* user defined types */ | utype /* user defined types */
| c_fcts /* c functions etc. */ | c_fcts /* c functions etc. */
| ns /* named sequence */ | ns /* named sequence */
| SEMI /* optional separator */ | semi /* optional separator */
| error | error
; ;
l_par : '(' { par_cnt++; }
;
r_par : ')' { par_cnt--; }
;
proc : inst /* optional instantiator */ proc : inst /* optional instantiator */
proctype NAME { proctype NAME {
setptype($3, PROCTYPE, ZN); setptype($3, PROCTYPE, ZN);
setpname($3); setpname($3);
context = $3->sym; context = $3->sym;
@ -99,20 +133,29 @@ proc : inst /* optional instantiator */
Expand_Ok++; /* expand struct names in decl */ Expand_Ok++; /* expand struct names in decl */
has_ini = 0; has_ini = 0;
} }
'(' decl ')' { Expand_Ok--; l_par decl r_par { Expand_Ok--;
if (has_ini) if (has_ini)
fatal("initializer in parameter list", (char *) 0); fatal("initializer in parameter list", (char *) 0);
} }
Opt_priority Opt_priority
Opt_enabler Opt_enabler
body { ProcList *rl; body { ProcList *rl;
rl = ready($3->sym, $6, $11->sq, $2->val, $10);
if ($1 != ZN && $1->val > 0) if ($1 != ZN && $1->val > 0)
{ int j; { int j;
rl = ready($3->sym, $6, $11->sq, $2->val, $10, A_PROC);
for (j = 0; j < $1->val; j++) for (j = 0; j < $1->val; j++)
runnable(rl, $9?$9->val:1, 1); { runnable(rl, $9?$9->val:1, 1);
announce(":root:"); announce(":root:");
}
if (dumptab) $3->sym->ini = $1; if (dumptab) $3->sym->ini = $1;
} else
{ rl = ready($3->sym, $6, $11->sq, $2->val, $10, P_PROC);
}
if (rl && has_ini == 1) /* global initializations, unsafe */
{ /* printf("proctype %s has initialized data\n",
$3->sym->name);
*/
rl->unsafe = 1;
} }
context = ZS; context = ZS;
} }
@ -124,7 +167,7 @@ proctype: PROCTYPE { $$ = nn(ZN,CONST,ZN,ZN); $$->val = 0; }
inst : /* empty */ { $$ = ZN; } inst : /* empty */ { $$ = ZN; }
| ACTIVE { $$ = nn(ZN,CONST,ZN,ZN); $$->val = 1; } | ACTIVE { $$ = nn(ZN,CONST,ZN,ZN); $$->val = 1; }
| ACTIVE '[' CONST ']' { | ACTIVE '[' const_expr ']' {
$$ = nn(ZN,CONST,ZN,ZN); $$->val = $3->val; $$ = nn(ZN,CONST,ZN,ZN); $$->val = $3->val;
if ($3->val > 255) if ($3->val > 255)
non_fatal("max nr of processes is 255\n", ""); non_fatal("max nr of processes is 255\n", "");
@ -133,10 +176,10 @@ inst : /* empty */ { $$ = ZN; }
$$ = nn(ZN,CONST,ZN,ZN); $$ = nn(ZN,CONST,ZN,ZN);
$$->val = 0; $$->val = 0;
if (!$3->sym->type) if (!$3->sym->type)
non_fatal("undeclared variable %s", fatal("undeclared variable %s",
$3->sym->name); $3->sym->name);
else if ($3->sym->ini->ntyp != CONST) else if ($3->sym->ini->ntyp != CONST)
non_fatal("need constant initializer for %s\n", fatal("need constant initializer for %s\n",
$3->sym->name); $3->sym->name);
else else
$$->val = $3->sym->ini->val; $$->val = $3->sym->ini->val;
@ -146,41 +189,84 @@ inst : /* empty */ { $$ = ZN; }
init : INIT { context = $1->sym; } init : INIT { context = $1->sym; }
Opt_priority Opt_priority
body { ProcList *rl; body { ProcList *rl;
rl = ready(context, ZN, $4->sq, 0, ZN); rl = ready(context, ZN, $4->sq, 0, ZN, I_PROC);
runnable(rl, $3?$3->val:1, 1); runnable(rl, $3?$3->val:1, 1);
announce(":root:"); announce(":root:");
context = ZS; context = ZS;
} }
; ;
claim : CLAIM { context = $1->sym; ltl : LTL optname2 { ltl_mode = 1; ltl_name = $2->sym->name; }
if (claimproc) ltl_body { if ($4) ltl_list($2->sym->name, $4->sym->name);
non_fatal("claim %s redefined", claimproc); ltl_mode = 0; has_ltl = 1;
}
;
ltl_body: '{' full_expr OS '}' { $$ = ltl_to_string($2); }
| error { $$ = NULL; }
;
claim : CLAIM optname { if ($2 != ZN)
{ $1->sym = $2->sym; /* new 5.3.0 */
}
nclaims++;
context = $1->sym;
if (claimproc && !strcmp(claimproc, $1->sym->name))
{ fatal("claim %s redefined", claimproc);
}
claimproc = $1->sym->name; claimproc = $1->sym->name;
} }
body { (void) ready($1->sym, ZN, $3->sq, 0, ZN); body { (void) ready($1->sym, ZN, $4->sq, 0, ZN, N_CLAIM);
context = ZS; context = ZS;
} }
; ;
optname : /* empty */ { char tb[32];
memset(tb, 0, 32);
sprintf(tb, "never_%d", nclaims);
$$ = nn(ZN, NAME, ZN, ZN);
$$->sym = lookup(tb);
}
| NAME { $$ = $1; }
;
optname2 : /* empty */ { char tb[32]; static int nltl = 0;
memset(tb, 0, 32);
sprintf(tb, "ltl_%d", nltl++);
$$ = nn(ZN, NAME, ZN, ZN);
$$->sym = lookup(tb);
}
| NAME { $$ = $1; }
;
events : TRACE { context = $1->sym; events : TRACE { context = $1->sym;
if (eventmap) if (eventmap)
non_fatal("trace %s redefined", eventmap); non_fatal("trace %s redefined", eventmap);
eventmap = $1->sym->name; eventmap = $1->sym->name;
inEventMap++; inEventMap++;
} }
body { (void) ready($1->sym, ZN, $3->sq, 0, ZN); body {
if (strcmp($1->sym->name, ":trace:") == 0)
{ (void) ready($1->sym, ZN, $3->sq, 0, ZN, E_TRACE);
} else
{ (void) ready($1->sym, ZN, $3->sq, 0, ZN, N_TRACE);
}
context = ZS; context = ZS;
inEventMap--; inEventMap--;
} }
; ;
utype : TYPEDEF NAME { if (context) utype : TYPEDEF NAME '{' { if (context)
fatal("typedef %s must be global", { fatal("typedef %s must be global",
$2->sym->name); $2->sym->name);
}
owner = $2->sym; owner = $2->sym;
in_seq = $1->ln;
}
decl_lst '}' { setuname($5);
owner = ZS;
in_seq = 0;
} }
'{' decl_lst '}' { setuname($5); owner = ZS; }
; ;
nm : NAME { $$ = $1; } nm : NAME { $$ = $1; }
@ -190,8 +276,8 @@ nm : NAME { $$ = $1; }
} }
; ;
ns : INLINE nm '(' { NamesNotAdded++; } ns : INLINE nm l_par { NamesNotAdded++; }
args ')' { prep_inline($2->sym, $5); args r_par { prep_inline($2->sym, $5);
NamesNotAdded--; NamesNotAdded--;
} }
; ;
@ -227,6 +313,8 @@ ccode : C_CODE { Symbol *s;
NamesNotAdded--; NamesNotAdded--;
$$ = nn(ZN, C_CODE, ZN, ZN); $$ = nn(ZN, C_CODE, ZN, ZN);
$$->sym = s; $$->sym = s;
$$->ln = $1->ln;
$$->fn = $1->fn;
has_code = 1; has_code = 1;
} }
| C_DECL { Symbol *s; | C_DECL { Symbol *s;
@ -236,23 +324,37 @@ ccode : C_CODE { Symbol *s;
s->type = CODE_DECL; s->type = CODE_DECL;
$$ = nn(ZN, C_CODE, ZN, ZN); $$ = nn(ZN, C_CODE, ZN, ZN);
$$->sym = s; $$->sym = s;
$$->ln = $1->ln;
$$->fn = $1->fn;
has_code = 1; has_code = 1;
} }
; ;
cexpr : C_EXPR { Symbol *s; cexpr : C_EXPR { Symbol *s;
NamesNotAdded++; NamesNotAdded++;
s = prep_inline(ZS, ZN); s = prep_inline(ZS, ZN);
/* if context is 0 this was inside an ltl formula
mark the last inline added to seqnames */
if (!context)
{ mark_last();
}
NamesNotAdded--; NamesNotAdded--;
$$ = nn(ZN, C_EXPR, ZN, ZN); $$ = nn(ZN, C_EXPR, ZN, ZN);
$$->sym = s; $$->sym = s;
$$->ln = $1->ln;
$$->fn = $1->fn;
no_side_effects(s->name); no_side_effects(s->name);
has_code = 1; has_code = 1;
} }
; ;
body : '{' { open_seq(1); } body : '{' { open_seq(1); in_seq = $1->ln; }
sequence OS { add_seq(Stop); } sequence OS { add_seq(Stop); }
'}' { $$->sq = close_seq(0); } '}' { $$->sq = close_seq(0); in_seq = 0;
if (scope_level != 0)
{ non_fatal("missing '}' ?", 0);
scope_level = 0;
}
}
; ;
sequence: step { if ($1) add_seq($1); } sequence: step { if ($1) add_seq($1); }
@ -264,7 +366,11 @@ step : one_decl { $$ = ZN; }
| NAME ':' one_decl { fatal("label preceding declaration,", (char *)0); } | NAME ':' one_decl { fatal("label preceding declaration,", (char *)0); }
| NAME ':' XU { fatal("label predecing xr/xs claim,", 0); } | NAME ':' XU { fatal("label predecing xr/xs claim,", 0); }
| stmnt { $$ = $1; } | stmnt { $$ = $1; }
| stmnt UNLESS stmnt { $$ = do_unless($1, $3); } | stmnt UNLESS { if ($1->ntyp == DO) { safe_break(); } }
stmnt { if ($1->ntyp == DO) { restore_break(); }
$$ = do_unless($1, $4);
}
| error { printf("Not a Step\n"); }
; ;
vis : /* empty */ { $$ = ZN; } vis : /* empty */ { $$ = ZN; }
@ -277,7 +383,9 @@ asgn: /* empty */
| ASGN | ASGN
; ;
one_decl: vis TYPE var_list { setptype($3, $2->val, $1); $$ = $3; } one_decl: vis TYPE var_list { setptype($3, $2->val, $1);
$$ = $3;
}
| vis UNAME var_list { setutype($3, $2->sym, $1); | vis UNAME var_list { setutype($3, $2->sym, $1);
$$ = expand($3, Expand_Ok); $$ = expand($3, Expand_Ok);
} }
@ -310,26 +418,76 @@ var_list: ivar { $$ = nn($1, TYPE, ZN, ZN); }
| ivar ',' var_list { $$ = nn($1, TYPE, ZN, $3); } | ivar ',' var_list { $$ = nn($1, TYPE, ZN, $3); }
; ;
c_list : CONST { $1->ntyp = CONST; $$ = $1; }
| CONST ',' c_list { $1->ntyp = CONST; $$ = nn($1, ',', $1, $3); }
;
ivar : vardcl { $$ = $1; ivar : vardcl { $$ = $1;
$1->sym->ini = nn(ZN,CONST,ZN,ZN); $1->sym->ini = nn(ZN,CONST,ZN,ZN);
$1->sym->ini->val = 0; $1->sym->ini->val = 0;
if (!initialization_ok)
{ Lextok *zx, *xz;
zx = nn(ZN, NAME, ZN, ZN);
zx->sym = $1->sym;
xz = nn(zx, ASGN, zx, $1->sym->ini);
keep_track_off(xz);
/* make sure zx doesnt turn out to be a STRUCT later */
add_seq(xz);
}
} }
| vardcl ASGN expr { $1->sym->ini = $3; $$ = $1; | vardcl ASGN '{' c_list '}' {
trackvar($1,$3); has_ini = 1; if (!$1->sym->isarray)
fatal("%s must be an array", $1->sym->name);
$$ = $1;
$1->sym->ini = $4;
has_ini = 1;
$1->sym->hidden |= (4|8); /* conservative */
if (!initialization_ok)
{ Lextok *zx = nn(ZN, NAME, ZN, ZN);
zx->sym = $1->sym;
add_seq(nn(zx, ASGN, zx, $4));
}
}
| vardcl ASGN expr { $$ = $1;
$1->sym->ini = $3;
if ($3->ntyp == CONST
|| ($3->ntyp == NAME && $3->sym->context))
{ has_ini = 2; /* local init */
} else
{ has_ini = 1; /* possibly global */
}
trackvar($1, $3);
if (any_oper($3, RUN))
{ fatal("cannot use 'run' in var init, saw", (char *) 0);
}
nochan_manip($1, $3, 0);
no_internals($1);
if (!initialization_ok)
{ Lextok *zx = nn(ZN, NAME, ZN, ZN);
zx->sym = $1->sym;
add_seq(nn(zx, ASGN, zx, $3));
}
} }
| vardcl ASGN ch_init { $1->sym->ini = $3; | vardcl ASGN ch_init { $1->sym->ini = $3;
$$ = $1; has_ini = 1; $$ = $1; has_ini = 1;
if (!initialization_ok)
{ non_fatal(PART1 "'%s'" PART2, $1->sym->name);
}
} }
; ;
ch_init : '[' CONST ']' OF ch_init : '[' const_expr ']' OF
'{' typ_list '}' { if ($2->val) u_async++; '{' typ_list '}' { if ($2->val)
else u_sync++; u_async++;
else
u_sync++;
{ int i = cnt_mpars($6); { int i = cnt_mpars($6);
Mpars = max(Mpars, i); Mpars = max(Mpars, i);
} }
$$ = nn(ZN, CHAN, ZN, $6); $$ = nn(ZN, CHAN, ZN, $6);
$$->val = $2->val; $$->val = $2->val;
$$->ln = $1->ln;
$$->fn = $1->fn;
} }
; ;
@ -342,13 +500,33 @@ vardcl : NAME { $1->sym->nel = 1; $$ = $1; }
} }
$1->sym->nel = 1; $$ = $1; $1->sym->nel = 1; $$ = $1;
} }
| NAME '[' CONST ']' { $1->sym->nel = $3->val; $$ = $1; } | NAME '[' const_expr ']' { $1->sym->nel = $3->val; $1->sym->isarray = 1; $$ = $1; }
| NAME '[' NAME ']' { /* make an exception for an initialized scalars */
$$ = nn(ZN, CONST, ZN, ZN);
fprintf(stderr, "spin: %s:%d, warning: '%s' in array bound ",
$1->fn->name, $1->ln, $3->sym->name);
if ($3->sym->ini->val > 0)
{ fprintf(stderr, "evaluated as %d\n", $3->sym->ini->val);
$$->val = $3->sym->ini->val;
} else
{ fprintf(stderr, "evaluated as 8 by default (to avoid zero)\n");
$$->val = 8;
}
$1->sym->nel = $$->val;
$1->sym->isarray = 1;
$$ = $1;
}
; ;
varref : cmpnd { $$ = mk_explicit($1, Expand_Ok, NAME); } varref : cmpnd { $$ = mk_explicit($1, Expand_Ok, NAME); }
; ;
pfld : NAME { $$ = nn($1, NAME, ZN, ZN); } pfld : NAME { $$ = nn($1, NAME, ZN, ZN);
if ($1->sym->isarray && !in_for)
{ non_fatal("missing array index for '%s'",
$1->sym->name);
}
}
| NAME { owner = ZS; } | NAME { owner = ZS; }
'[' expr ']' { $$ = nn($1, NAME, $4, ZN); } '[' expr ']' { $$ = nn($1, NAME, $4, ZN); }
; ;
@ -363,7 +541,7 @@ cmpnd : pfld { Embedded++;
Embedded--; Embedded--;
if (!Embedded && !NamesNotAdded if (!Embedded && !NamesNotAdded
&& !$1->sym->type) && !$1->sym->type)
non_fatal("undeclared variable: %s", fatal("undeclared variable: %s",
$1->sym->name); $1->sym->name);
if ($3) validref($1, $3->lft); if ($3) validref($1, $3->lft);
owner = ZS; owner = ZS;
@ -374,13 +552,21 @@ sfld : /* empty */ { $$ = ZN; }
| '.' cmpnd %prec DOT { $$ = nn(ZN, '.', $2, ZN); } | '.' cmpnd %prec DOT { $$ = nn(ZN, '.', $2, ZN); }
; ;
stmnt : Special { $$ = $1; } stmnt : Special { $$ = $1; initialization_ok = 0; }
| Stmnt { $$ = $1; | Stmnt { $$ = $1; initialization_ok = 0;
if (inEventMap) if (inEventMap) non_fatal("not an event", (char *)0);
non_fatal("not an event", (char *)0);
} }
; ;
for_pre : FOR l_par { in_for = 1; }
varref { trapwonly($4 /*, "for" */);
pushbreak(); /* moved up */
$$ = $4;
}
;
for_post: '{' sequence OS '}' ;
Special : varref RCV { Expand_Ok++; } Special : varref RCV { Expand_Ok++; }
rargs { Expand_Ok--; has_io++; rargs { Expand_Ok--; has_io++;
$$ = nn($1, 'r', $1, $4); $$ = nn($1, 'r', $1, $4);
@ -392,13 +578,30 @@ Special : varref RCV { Expand_Ok++; }
$$->val=0; trackchanuse($4, ZN, 'S'); $$->val=0; trackchanuse($4, ZN, 'S');
any_runs($4); any_runs($4);
} }
| for_pre ':' expr DOTDOT expr r_par {
for_setup($1, $3, $5); in_for = 0;
}
for_post { $$ = for_body($1, 1);
}
| for_pre IN varref r_par { $$ = for_index($1, $3); in_for = 0;
}
for_post { $$ = for_body($5, 1);
}
| SELECT l_par varref ':' expr DOTDOT expr r_par {
trapwonly($3 /*, "select" */);
$$ = sel_index($3, $5, $7);
}
| IF options FI { $$ = nn($1, IF, ZN, ZN); | IF options FI { $$ = nn($1, IF, ZN, ZN);
$$->sl = $2->sl; $$->sl = $2->sl;
$$->ln = $1->ln;
$$->fn = $1->fn;
prune_opts($$); prune_opts($$);
} }
| DO { pushbreak(); } | DO { pushbreak(); }
options OD { $$ = nn($1, DO, ZN, ZN); options OD { $$ = nn($1, DO, ZN, ZN);
$$->sl = $3->sl; $$->sl = $3->sl;
$$->ln = $1->ln;
$$->fn = $1->fn;
prune_opts($$); prune_opts($$);
} }
| BREAK { $$ = nn(ZN, GOTO, ZN, ZN); | BREAK { $$ = nn(ZN, GOTO, ZN, ZN);
@ -420,9 +623,22 @@ Special : varref RCV { Expand_Ok++; }
} }
$1->sym->type = LABEL; $1->sym->type = LABEL;
} }
| NAME ':' { $$ = nn($1, ':',ZN,ZN);
if ($1->sym->type != 0
&& $1->sym->type != LABEL) {
non_fatal("bad label-name %s",
$1->sym->name);
}
$$->lft = nn(ZN, 'c', nn(ZN,CONST,ZN,ZN), ZN);
$$->lft->lft->val = 1; /* skip */
$1->sym->type = LABEL;
}
| error { $$ = nn(ZN, 'c', nn(ZN,CONST,ZN,ZN), ZN);
$$->lft->val = 1; /* skip */
}
; ;
Stmnt : varref ASGN expr { $$ = nn($1, ASGN, $1, $3); Stmnt : varref ASGN full_expr { $$ = nn($1, ASGN, $1, $3);
trackvar($1, $3); trackvar($1, $3);
nochan_manip($1, $3, 0); nochan_manip($1, $3, 0);
no_internals($1); no_internals($1);
@ -443,10 +659,11 @@ Stmnt : varref ASGN expr { $$ = nn($1, ASGN, $1, $3);
if ($1->sym->type == CHAN) if ($1->sym->type == CHAN)
fatal("arithmetic on chan id's", (char *)0); fatal("arithmetic on chan id's", (char *)0);
} }
| PRINT '(' STRING { realread = 0; } | SET_P l_par two_args r_par { $$ = nn(ZN, SET_P, $3, ZN); has_priority++; }
prargs ')' { $$ = nn($3, PRINT, $5, ZN); realread = 1; } | PRINT l_par STRING { realread = 0; }
| PRINTM '(' varref ')' { $$ = nn(ZN, PRINTM, $3, ZN); } prargs r_par { $$ = nn($3, PRINT, $5, ZN); realread = 1; }
| PRINTM '(' CONST ')' { $$ = nn(ZN, PRINTM, $3, ZN); } | PRINTM l_par varref r_par { $$ = nn(ZN, PRINTM, $3, ZN); }
| PRINTM l_par CONST r_par { $$ = nn(ZN, PRINTM, $3, ZN); }
| ASSERT full_expr { $$ = nn(ZN, ASSERT, $2, ZN); AST_track($2, 0); } | ASSERT full_expr { $$ = nn(ZN, ASSERT, $2, ZN); AST_track($2, 0); }
| ccode { $$ = $1; } | ccode { $$ = $1; }
| varref R_RCV { Expand_Ok++; } | varref R_RCV { Expand_Ok++; }
@ -480,21 +697,40 @@ Stmnt : varref ASGN expr { $$ = nn($1, ASGN, $1, $3);
| ATOMIC '{' { open_seq(0); } | ATOMIC '{' { open_seq(0); }
sequence OS '}' { $$ = nn($1, ATOMIC, ZN, ZN); sequence OS '}' { $$ = nn($1, ATOMIC, ZN, ZN);
$$->sl = seqlist(close_seq(3), 0); $$->sl = seqlist(close_seq(3), 0);
make_atomic($$->sl->this, 0); $$->ln = $1->ln;
$$->fn = $1->fn;
make_atomic($$->sl->this, 0);
} }
| D_STEP '{' { open_seq(0); rem_Seq(); } | D_STEP '{' { open_seq(0);
rem_Seq();
}
sequence OS '}' { $$ = nn($1, D_STEP, ZN, ZN); sequence OS '}' { $$ = nn($1, D_STEP, ZN, ZN);
$$->sl = seqlist(close_seq(4), 0); $$->sl = seqlist(close_seq(4), 0);
$$->ln = $1->ln;
$$->fn = $1->fn;
make_atomic($$->sl->this, D_ATOM); make_atomic($$->sl->this, D_ATOM);
unrem_Seq(); unrem_Seq();
} }
| '{' { open_seq(0); } | '{' { open_seq(0); }
sequence OS '}' { $$ = nn(ZN, NON_ATOMIC, ZN, ZN); sequence OS '}' { $$ = nn(ZN, NON_ATOMIC, ZN, ZN);
$$->sl = seqlist(close_seq(5), 0); $$->sl = seqlist(close_seq(5), 0);
$$->ln = $1->ln;
$$->fn = $1->fn;
} }
| INAME { IArgs++; } | INAME { IArgs++; }
'(' args ')' { pickup_inline($1->sym, $4); IArgs--; } l_par args r_par { initialization_ok = 0;
pickup_inline($1->sym, $4, ZN);
IArgs--;
}
Stmnt { $$ = $7; } Stmnt { $$ = $7; }
| varref ASGN INAME { IArgs++; }
l_par args r_par { initialization_ok = 0;
pickup_inline($3->sym, $6, $1);
IArgs--;
}
Stmnt { $$ = $9; }
| RETURN full_expr { $$ = return_statement($2); }
; ;
options : option { $$->sl = seqlist($1->sq, 0); } options : option { $$->sl = seqlist($1->sq, 0); }
@ -503,22 +739,39 @@ options : option { $$->sl = seqlist($1->sq, 0); }
option : SEP { open_seq(0); } option : SEP { open_seq(0); }
sequence OS { $$ = nn(ZN,0,ZN,ZN); sequence OS { $$ = nn(ZN,0,ZN,ZN);
$$->sq = close_seq(6); } $$->sq = close_seq(6);
$$->ln = $1->ln;
$$->fn = $1->fn;
}
; ;
OS : /* empty */ OS : /* empty */
| SEMI { /* redundant semi at end of sequence */ } | semi { /* redundant semi at end of sequence */ }
; ;
MS : SEMI { /* at least one semi-colon */ } semi : SEMI
| MS SEMI { /* but more are okay too */ } | ARROW
;
MS : semi { /* at least one semi-colon */ }
| MS semi { /* but more are okay too */ }
; ;
aname : NAME { $$ = $1; } aname : NAME { $$ = $1; }
| PNAME { $$ = $1; } | PNAME { $$ = $1; }
; ;
expr : '(' expr ')' { $$ = $2; } const_expr: CONST { $$ = $1; }
| '-' const_expr %prec UMIN { $$ = $2; $$->val = -($2->val); }
| l_par const_expr r_par { $$ = $2; }
| const_expr '+' const_expr { $$ = $1; $$->val = $1->val + $3->val; }
| const_expr '-' const_expr { $$ = $1; $$->val = $1->val - $3->val; }
| const_expr '*' const_expr { $$ = $1; $$->val = $1->val * $3->val; }
| const_expr '/' const_expr { $$ = $1; $$->val = $1->val / $3->val; }
| const_expr '%' const_expr { $$ = $1; $$->val = $1->val % $3->val; }
;
expr : l_par expr r_par { $$ = $2; }
| expr '+' expr { $$ = nn(ZN, '+', $1, $3); } | expr '+' expr { $$ = nn(ZN, '+', $1, $3); }
| expr '-' expr { $$ = nn(ZN, '-', $1, $3); } | expr '-' expr { $$ = nn(ZN, '-', $1, $3); }
| expr '*' expr { $$ = nn(ZN, '*', $1, $3); } | expr '*' expr { $$ = nn(ZN, '*', $1, $3); }
@ -541,28 +794,25 @@ expr : '(' expr ')' { $$ = $2; }
| '-' expr %prec UMIN { $$ = nn(ZN, UMIN, $2, ZN); } | '-' expr %prec UMIN { $$ = nn(ZN, UMIN, $2, ZN); }
| SND expr %prec NEG { $$ = nn(ZN, '!', $2, ZN); } | SND expr %prec NEG { $$ = nn(ZN, '!', $2, ZN); }
| '(' expr SEMI expr ':' expr ')' { | l_par expr ARROW expr ':' expr r_par {
$$ = nn(ZN, OR, $4, $6); $$ = nn(ZN, OR, $4, $6);
$$ = nn(ZN, '?', $2, $$); $$ = nn(ZN, '?', $2, $$);
} }
| RUN aname { Expand_Ok++; | RUN aname { Expand_Ok++;
if (!context) if (!context)
fatal("used 'run' outside proctype", fatal("used 'run' outside proctype",
(char *) 0); (char *) 0);
if (strcmp(context->name, ":init:") != 0)
runsafe = 0;
} }
'(' args ')' l_par args r_par
Opt_priority { Expand_Ok--; Opt_priority { Expand_Ok--;
$$ = nn($2, RUN, $5, ZN); $$ = nn($2, RUN, $5, ZN);
$$->val = ($7) ? $7->val : 1; $$->val = ($7) ? $7->val : 0;
trackchanuse($5, $2, 'A'); trackrun($$); trackchanuse($5, $2, 'A'); trackrun($$);
} }
| LEN '(' varref ')' { $$ = nn($3, LEN, $3, ZN); } | LEN l_par varref r_par { $$ = nn($3, LEN, $3, ZN); }
| ENABLED '(' expr ')' { $$ = nn(ZN, ENABLED, $3, ZN); | ENABLED l_par expr r_par { $$ = nn(ZN, ENABLED, $3, ZN); has_enabled++; }
has_enabled++; | GET_P l_par expr r_par { $$ = nn(ZN, GET_P, $3, ZN); has_priority++; }
}
| varref RCV { Expand_Ok++; } | varref RCV { Expand_Ok++; }
'[' rargs ']' { Expand_Ok--; has_io++; '[' rargs ']' { Expand_Ok--; has_io++;
$$ = nn($1, 'R', $1, $5); $$ = nn($1, 'R', $1, $5);
@ -572,7 +822,7 @@ expr : '(' expr ')' { $$ = $2; }
$$ = nn($1, 'R', $1, $5); $$ = nn($1, 'R', $1, $5);
$$->val = has_random = 1; $$->val = has_random = 1;
} }
| varref { $$ = $1; trapwonly($1, "varref"); } | varref { $$ = $1; trapwonly($1 /*, "varref" */); }
| cexpr { $$ = $1; } | cexpr { $$ = $1; }
| CONST { $$ = nn(ZN,CONST,ZN,ZN); | CONST { $$ = nn(ZN,CONST,ZN,ZN);
$$->ismtyp = $1->ismtyp; $$->ismtyp = $1->ismtyp;
@ -582,7 +832,7 @@ expr : '(' expr ')' { $$ = $2; }
| NONPROGRESS { $$ = nn(ZN,NONPROGRESS, ZN, ZN); | NONPROGRESS { $$ = nn(ZN,NONPROGRESS, ZN, ZN);
has_np++; has_np++;
} }
| PC_VAL '(' expr ')' { $$ = nn(ZN, PC_VAL, $3, ZN); | PC_VAL l_par expr r_par { $$ = nn(ZN, PC_VAL, $3, ZN);
has_pcvalue++; has_pcvalue++;
} }
| PNAME '[' expr ']' '@' NAME | PNAME '[' expr ']' '@' NAME
@ -591,18 +841,51 @@ expr : '(' expr ')' { $$ = $2; }
{ $$ = rem_var($1->sym, $3, $6->sym, $6->lft); } { $$ = rem_var($1->sym, $3, $6->sym, $6->lft); }
| PNAME '@' NAME { $$ = rem_lab($1->sym, ZN, $3->sym); } | PNAME '@' NAME { $$ = rem_lab($1->sym, ZN, $3->sym); }
| PNAME ':' pfld { $$ = rem_var($1->sym, ZN, $3->sym, $3->lft); } | PNAME ':' pfld { $$ = rem_var($1->sym, ZN, $3->sym, $3->lft); }
| ltl_expr { $$ = $1; /* sanity_check($1); */ }
; ;
Opt_priority: /* none */ { $$ = ZN; } Opt_priority: /* none */ { $$ = ZN; }
| PRIORITY CONST { $$ = $2; } | PRIORITY CONST { $$ = $2; has_priority++; }
; ;
full_expr: expr { $$ = $1; } full_expr: expr { $$ = $1; }
| Expr { $$ = $1; } | Expr { $$ = $1; }
;
ltl_expr: expr UNTIL expr { $$ = nn(ZN, UNTIL, $1, $3); }
| expr RELEASE expr { $$ = nn(ZN, RELEASE, $1, $3); }
| expr WEAK_UNTIL expr { $$ = nn(ZN, ALWAYS, $1, ZN);
$$ = nn(ZN, OR, $$, nn(ZN, UNTIL, $1, $3));
}
| expr IMPLIES expr {
$$ = nn(ZN, '!', $1, ZN);
$$ = nn(ZN, OR, $$, $3);
}
| expr EQUIV expr { $$ = nn(ZN, EQUIV, $1, $3); }
| NEXT expr %prec NEG { $$ = nn(ZN, NEXT, $2, ZN); }
| ALWAYS expr %prec NEG { $$ = nn(ZN, ALWAYS,$2, ZN); }
| EVENTUALLY expr %prec NEG { $$ = nn(ZN, EVENTUALLY, $2, ZN); }
;
/* an Expr cannot be negated - to protect Probe expressions */
Expr : Probe { $$ = $1; }
| l_par Expr r_par { $$ = $2; }
| Expr AND Expr { $$ = nn(ZN, AND, $1, $3); }
| Expr AND expr { $$ = nn(ZN, AND, $1, $3); }
| expr AND Expr { $$ = nn(ZN, AND, $1, $3); }
| Expr OR Expr { $$ = nn(ZN, OR, $1, $3); }
| Expr OR expr { $$ = nn(ZN, OR, $1, $3); }
| expr OR Expr { $$ = nn(ZN, OR, $1, $3); }
;
Probe : FULL l_par varref r_par { $$ = nn($3, FULL, $3, ZN); }
| NFULL l_par varref r_par { $$ = nn($3, NFULL, $3, ZN); }
| EMPTY l_par varref r_par { $$ = nn($3, EMPTY, $3, ZN); }
| NEMPTY l_par varref r_par { $$ = nn($3,NEMPTY, $3, ZN); }
; ;
Opt_enabler: /* none */ { $$ = ZN; } Opt_enabler: /* none */ { $$ = ZN; }
| PROVIDED '(' full_expr ')' { if (!proper_enabler($3)) | PROVIDED l_par full_expr r_par { if (!proper_enabler($3))
{ non_fatal("invalid PROVIDED clause", { non_fatal("invalid PROVIDED clause",
(char *)0); (char *)0);
$$ = ZN; $$ = ZN;
@ -615,23 +898,6 @@ Opt_enabler: /* none */ { $$ = ZN; }
} }
; ;
/* an Expr cannot be negated - to protect Probe expressions */
Expr : Probe { $$ = $1; }
| '(' Expr ')' { $$ = $2; }
| Expr AND Expr { $$ = nn(ZN, AND, $1, $3); }
| Expr AND expr { $$ = nn(ZN, AND, $1, $3); }
| Expr OR Expr { $$ = nn(ZN, OR, $1, $3); }
| Expr OR expr { $$ = nn(ZN, OR, $1, $3); }
| expr AND Expr { $$ = nn(ZN, AND, $1, $3); }
| expr OR Expr { $$ = nn(ZN, OR, $1, $3); }
;
Probe : FULL '(' varref ')' { $$ = nn($3, FULL, $3, ZN); }
| NFULL '(' varref ')' { $$ = nn($3, NFULL, $3, ZN); }
| EMPTY '(' varref ')' { $$ = nn($3, EMPTY, $3, ZN); }
| NEMPTY '(' varref ')' { $$ = nn($3,NEMPTY, $3, ZN); }
;
basetype: TYPE { $$->sym = ZS; basetype: TYPE { $$->sym = ZS;
$$->val = $1->val; $$->val = $1->val;
if ($$->val == UNSIGNED) if ($$->val == UNSIGNED)
@ -647,6 +913,9 @@ typ_list: basetype { $$ = nn($1, $1->val, ZN, ZN); }
| basetype ',' typ_list { $$ = nn($1, $1->val, ZN, $3); } | basetype ',' typ_list { $$ = nn($1, $1->val, ZN, $3); }
; ;
two_args: expr ',' expr { $$ = nn(ZN, ',', $1, $3); }
;
args : /* empty */ { $$ = ZN; } args : /* empty */ { $$ = ZN; }
| arg { $$ = $1; } | arg { $$ = $1; }
; ;
@ -656,7 +925,7 @@ prargs : /* empty */ { $$ = ZN; }
; ;
margs : arg { $$ = $1; } margs : arg { $$ = $1; }
| expr '(' arg ')' { if ($1->ntyp == ',') | expr l_par arg r_par { if ($1->ntyp == ',')
$$ = tail_add($1, $3); $$ = tail_add($1, $3);
else else
$$ = nn(ZN, ',', $1, $3); $$ = nn(ZN, ',', $1, $3);
@ -676,9 +945,9 @@ arg : expr { if ($1->ntyp == ',')
; ;
rarg : varref { $$ = $1; trackvar($1, $1); rarg : varref { $$ = $1; trackvar($1, $1);
trapwonly($1, "rarg"); } trapwonly($1 /*, "rarg" */); }
| EVAL '(' expr ')' { $$ = nn(ZN,EVAL,$3,ZN); | EVAL l_par expr r_par { $$ = nn(ZN,EVAL,$3,ZN);
trapwonly($1, "eval rarg"); } trapwonly($1 /*, "eval rarg" */); }
| CONST { $$ = nn(ZN,CONST,ZN,ZN); | CONST { $$ = nn(ZN,CONST,ZN,ZN);
$$->ismtyp = $1->ismtyp; $$->ismtyp = $1->ismtyp;
$$->val = $1->val; $$->val = $1->val;
@ -698,12 +967,12 @@ rargs : rarg { if ($1->ntyp == ',')
else else
$$ = nn(ZN, ',', $1, $3); $$ = nn(ZN, ',', $1, $3);
} }
| rarg '(' rargs ')' { if ($1->ntyp == ',') | rarg l_par rargs r_par { if ($1->ntyp == ',')
$$ = tail_add($1, $3); $$ = tail_add($1, $3);
else else
$$ = nn(ZN, ',', $1, $3); $$ = nn(ZN, ',', $1, $3);
} }
| '(' rargs ')' { $$ = $2; } | l_par rargs r_par { $$ = $2; }
; ;
nlst : NAME { $$ = nn($1, NAME, ZN, ZN); nlst : NAME { $$ = nn($1, NAME, ZN, ZN);
@ -715,6 +984,138 @@ nlst : NAME { $$ = nn($1, NAME, ZN, ZN);
; ;
%% %%
#define binop(n, sop) fprintf(fd, "("); recursive(fd, n->lft); \
fprintf(fd, ") %s (", sop); recursive(fd, n->rgt); \
fprintf(fd, ")");
#define unop(n, sop) fprintf(fd, "%s (", sop); recursive(fd, n->lft); \
fprintf(fd, ")");
static void
recursive(FILE *fd, Lextok *n)
{
if (n)
switch (n->ntyp) {
case NEXT:
unop(n, "X");
break;
case ALWAYS:
unop(n, "[]");
break;
case EVENTUALLY:
unop(n, "<>");
break;
case '!':
unop(n, "!");
break;
case UNTIL:
binop(n, "U");
break;
case WEAK_UNTIL:
binop(n, "W");
break;
case RELEASE: /* see http://en.wikipedia.org/wiki/Linear_temporal_logic */
binop(n, "V");
break;
case OR:
binop(n, "||");
break;
case AND:
binop(n, "&&");
break;
case IMPLIES:
binop(n, "->");
break;
case EQUIV:
binop(n, "<->");
break;
case C_EXPR:
fprintf(fd, "c_expr { %s }", put_inline(fd, n->sym->name));
break;
default:
comment(fd, n, 0);
break;
}
}
static Lextok *
ltl_to_string(Lextok *n)
{ Lextok *m = nn(ZN, 0, ZN, ZN);
char *retval;
char ltl_formula[2048];
FILE *tf = fopen(TMP_FILE1, "w+"); /* tmpfile() fails on Windows 7 */
/* convert the parsed ltl to a string
by writing into a file, using existing functions,
and then passing it to the existing interface for
conversion into a never claim
(this means parsing everything twice, which is
a little redundant, but adds only miniscule overhead)
*/
if (!tf)
{ fatal("cannot create temporary file", (char *) 0);
}
dont_simplify = 1;
recursive(tf, n);
dont_simplify = 0;
(void) fseek(tf, 0L, SEEK_SET);
memset(ltl_formula, 0, sizeof(ltl_formula));
retval = fgets(ltl_formula, sizeof(ltl_formula), tf);
fclose(tf);
(void) unlink(TMP_FILE1);
if (!retval)
{ printf("%p\n", retval);
fatal("could not translate ltl ltl_formula", 0);
}
if (1) printf("ltl %s: %s\n", ltl_name, ltl_formula);
m->sym = lookup(ltl_formula);
return m;
}
int
is_temporal(int t)
{
return (t == EVENTUALLY || t == ALWAYS || t == UNTIL
|| t == WEAK_UNTIL || t == RELEASE);
}
int
is_boolean(int t)
{
return (t == AND || t == OR || t == IMPLIES || t == EQUIV);
}
#if 0
/* flags correct formula like: ltl { true U (true U true) } */
void
sanity_check(Lextok *t) /* check proper embedding of ltl_expr */
{
if (!t) return;
sanity_check(t->lft);
sanity_check(t->rgt);
if (t->lft && t->rgt)
{ if (!is_boolean(t->ntyp)
&& (is_temporal(t->lft->ntyp)
|| is_temporal(t->rgt->ntyp)))
{ printf("spin: attempt to apply '");
explain(t->ntyp);
printf("' to '");
explain(t->lft->ntyp);
printf("' and '");
explain(t->rgt->ntyp);
printf("'\n");
/* non_fatal("missing parentheses?", (char *)0); */
} }
}
#endif
void void
yyerror(char *fmt, ...) yyerror(char *fmt, ...)
{ {

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,10 @@
/***** spin: structs.c *****/ /***** spin: structs.c *****/
/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 "spin.h"
#include "y.tab.h" #include "y.tab.h"
@ -19,7 +16,7 @@ typedef struct UType {
} UType; } UType;
extern Symbol *Fname; extern Symbol *Fname;
extern int lineno, depth, Expand_Ok; extern int lineno, depth, Expand_Ok, has_hidden, in_for;
Symbol *owner; Symbol *owner;
@ -33,14 +30,16 @@ void
setuname(Lextok *n) setuname(Lextok *n)
{ UType *tmp; { UType *tmp;
if (!owner)
fatal("illegal reference inside typedef", (char *) 0);
for (tmp = Unames; tmp; tmp = tmp->nxt) for (tmp = Unames; tmp; tmp = tmp->nxt)
if (!strcmp(owner->name, tmp->nm->name)) if (!strcmp(owner->name, tmp->nm->name))
{ non_fatal("typename %s was defined before", { non_fatal("typename %s was defined before",
tmp->nm->name); tmp->nm->name);
return; return;
} }
if (!owner) fatal("illegal reference inside typedef",
(char *) 0);
tmp = (UType *) emalloc(sizeof(UType)); tmp = (UType *) emalloc(sizeof(UType));
tmp->nm = owner; tmp->nm = owner;
tmp->cn = n; tmp->cn = n;
@ -102,21 +101,22 @@ setutype(Lextok *p, Symbol *t, Lextok *vis) /* user-defined types */
{ lineno = n->ln; { lineno = n->ln;
Fname = n->fn; Fname = n->fn;
if (n->sym->type) if (n->sym->type)
non_fatal("redeclaration of '%s'", n->sym->name); fatal("redeclaration of '%s'", n->sym->name);
if (n->sym->nbits > 0) if (n->sym->nbits > 0)
non_fatal("(%s) only an unsigned can have width-field", non_fatal("(%s) only an unsigned can have width-field",
n->sym->name); n->sym->name);
if (Expand_Ok) if (Expand_Ok)
n->sym->hidden |= (4|8|16); /* formal par */ n->sym->hidden |= (4|8|16); /* formal par */
if (vis) if (vis)
{ if (strncmp(vis->sym->name, ":hide:", 6) == 0) { if (strncmp(vis->sym->name, ":hide:", (size_t) 6) == 0)
n->sym->hidden |= 1; { n->sym->hidden |= 1;
else if (strncmp(vis->sym->name, ":show:", 6) == 0) has_hidden++;
} else if (strncmp(vis->sym->name, ":show:", (size_t) 6) == 0)
n->sym->hidden |= 2; n->sym->hidden |= 2;
else if (strncmp(vis->sym->name, ":local:", 7) == 0) else if (strncmp(vis->sym->name, ":local:", (size_t) 7) == 0)
n->sym->hidden |= 64; n->sym->hidden |= 64;
} }
n->sym->type = STRUCT; /* classification */ n->sym->type = STRUCT; /* classification */
@ -196,6 +196,7 @@ Rval_struct(Lextok *n, Symbol *v, int xinit) /* n varref, v valref */
fatal("non-zero 'rgt' on non-structure", 0); fatal("non-zero 'rgt' on non-structure", 0);
ix = eval(tmp->lft); ix = eval(tmp->lft);
/* printf("%d: ix: %d (%d) %d\n", depth, ix, tl->nel, tl->val[ix]); */
if (ix >= tl->nel || ix < 0) if (ix >= tl->nel || ix < 0)
fatal("indexing error \'%s\'", tl->name); fatal("indexing error \'%s\'", tl->name);
@ -222,10 +223,12 @@ Lval_struct(Lextok *n, Symbol *v, int xinit, int a) /* a = assigned value */
fatal("indexing error \'%s\'", tl->name); fatal("indexing error \'%s\'", tl->name);
if (tl->nbits > 0) if (tl->nbits > 0)
a = (a & ((1<<tl->nbits)-1)); a = (a & ((1<<tl->nbits)-1));
tl->val[ix] = a;
tl->setat = depth;
if (a != tl->val[ix])
{ tl->val[ix] = a;
tl->setat = depth;
}
return 1; return 1;
} }
@ -246,7 +249,7 @@ is_lst:
for (fp = n; fp; fp = fp->rgt) for (fp = n; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt) for (tl = fp->lft; tl; tl = tl->rgt)
{ if (tl->sym->type == STRUCT) { if (tl->sym->type == STRUCT)
{ if (tl->sym->nel != 1) { if (tl->sym->nel > 1 || tl->sym->isarray)
fatal("array of structures in param list, %s", fatal("array of structures in param list, %s",
tl->sym->name); tl->sym->name);
cnt += Cnt_flds(tl->sym->Slst); cnt += Cnt_flds(tl->sym->Slst);
@ -266,9 +269,9 @@ Sym_typ(Lextok *t)
return s->type; return s->type;
if (!t->rgt if (!t->rgt
|| !t->rgt->ntyp == '.' || t->rgt->ntyp != '.' /* gh: had ! in wrong place */
|| !t->rgt->lft) || !t->rgt->lft)
return STRUCT; /* not a field reference */ return STRUCT; /* not a field reference */
return Sym_typ(t->rgt->lft); return Sym_typ(t->rgt->lft);
} }
@ -315,6 +318,7 @@ cpnn(Lextok *s, int L, int R, int S)
if (!s) return ZN; if (!s) return ZN;
d = (Lextok *) emalloc(sizeof(Lextok)); d = (Lextok *) emalloc(sizeof(Lextok));
d->uiid = s->uiid;
d->ntyp = s->ntyp; d->ntyp = s->ntyp;
d->val = s->val; d->val = s->val;
d->ln = s->ln; d->ln = s->ln;
@ -353,7 +357,7 @@ full_name(FILE *fd, Lextok *n, Symbol *v, int xinit)
goto out; goto out;
} }
fprintf(fd, ".%s", tl->name); fprintf(fd, ".%s", tl->name);
out: if (tmp->sym->nel > 1) out: if (tmp->sym->nel > 1 || tmp->sym->isarray == 1)
{ fprintf(fd, "[%d]", eval(tmp->lft)); { fprintf(fd, "[%d]", eval(tmp->lft));
hiddenarrays = 1; hiddenarrays = 1;
} }
@ -391,7 +395,7 @@ struct_name(Lextok *n, Symbol *v, int xinit, char *buf)
} }
sprintf(lbuf, ".%s", tl->name); sprintf(lbuf, ".%s", tl->name);
strcat(buf, lbuf); strcat(buf, lbuf);
if (tmp->sym->nel > 1) if (tmp->sym->nel > 1 || tmp->sym->isarray == 1)
{ sprintf(lbuf, "[%d]", eval(tmp->lft)); { sprintf(lbuf, "[%d]", eval(tmp->lft));
strcat(buf, lbuf); strcat(buf, lbuf);
} }
@ -405,10 +409,10 @@ walk2_struct(char *s, Symbol *z)
extern void Done_case(char *, Symbol *); extern void Done_case(char *, Symbol *);
ini_struct(z); ini_struct(z);
if (z->nel == 1) if (z->nel == 1 && z->isarray == 0)
sprintf(eprefix, "%s%s.", s, z->name); sprintf(eprefix, "%s%s.", s, z->name);
for (ix = 0; ix < z->nel; ix++) for (ix = 0; ix < z->nel; ix++)
{ if (z->nel > 1) { if (z->nel > 1 || z->isarray == 1)
sprintf(eprefix, "%s%s[%d].", s, z->name, ix); sprintf(eprefix, "%s%s[%d].", s, z->name, ix);
for (fp = z->Sval[ix]; fp; fp = fp->rgt) for (fp = z->Sval[ix]; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt) for (tl = fp->lft; tl; tl = tl->rgt)
@ -426,10 +430,10 @@ walk_struct(FILE *ofd, int dowhat, char *s, Symbol *z, char *a, char *b, char *c
int ix; int ix;
ini_struct(z); ini_struct(z);
if (z->nel == 1) if (z->nel == 1 && z->isarray == 0)
sprintf(eprefix, "%s%s.", s, z->name); sprintf(eprefix, "%s%s.", s, z->name);
for (ix = 0; ix < z->nel; ix++) for (ix = 0; ix < z->nel; ix++)
{ if (z->nel > 1) { if (z->nel > 1 || z->isarray == 1)
sprintf(eprefix, "%s%s[%d].", s, z->name, ix); sprintf(eprefix, "%s%s[%d].", s, z->name, ix);
for (fp = z->Sval[ix]; fp; fp = fp->rgt) for (fp = z->Sval[ix]; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt) for (tl = fp->lft; tl; tl = tl->rgt)
@ -443,7 +447,7 @@ walk_struct(FILE *ofd, int dowhat, char *s, Symbol *z, char *a, char *b, char *c
void void
c_struct(FILE *fd, char *ipref, Symbol *z) c_struct(FILE *fd, char *ipref, Symbol *z)
{ Lextok *fp, *tl; { Lextok *fp, *tl;
char pref[256], eprefix[256]; char pref[256], eprefix[300];
int ix; int ix;
ini_struct(z); ini_struct(z);
@ -452,7 +456,7 @@ c_struct(FILE *fd, char *ipref, Symbol *z)
for (fp = z->Sval[ix]; fp; fp = fp->rgt) for (fp = z->Sval[ix]; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt) for (tl = fp->lft; tl; tl = tl->rgt)
{ strcpy(eprefix, ipref); { strcpy(eprefix, ipref);
if (z->nel > 1) if (z->nel > 1 || z->isarray == 1)
{ /* insert index before last '.' */ { /* insert index before last '.' */
eprefix[strlen(eprefix)-1] = '\0'; eprefix[strlen(eprefix)-1] = '\0';
sprintf(pref, "[ %d ].", ix); sprintf(pref, "[ %d ].", ix);
@ -476,7 +480,7 @@ dump_struct(Symbol *z, char *prefix, RunList *r)
ini_struct(z); ini_struct(z);
for (ix = 0; ix < z->nel; ix++) for (ix = 0; ix < z->nel; ix++)
{ if (z->nel > 1) { if (z->nel > 1 || z->isarray == 1)
sprintf(eprefix, "%s[%d]", prefix, ix); sprintf(eprefix, "%s[%d]", prefix, ix);
else else
strcpy(eprefix, prefix); strcpy(eprefix, prefix);
@ -484,7 +488,7 @@ dump_struct(Symbol *z, char *prefix, RunList *r)
for (fp = z->Sval[ix]; fp; fp = fp->rgt) for (fp = z->Sval[ix]; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt) for (tl = fp->lft; tl; tl = tl->rgt)
{ if (tl->sym->type == STRUCT) { if (tl->sym->type == STRUCT)
{ char pref[256]; { char pref[300];
strcpy(pref, eprefix); strcpy(pref, eprefix);
strcat(pref, "."); strcat(pref, ".");
strcat(pref, tl->sym->name); strcat(pref, tl->sym->name);
@ -498,7 +502,7 @@ dump_struct(Symbol *z, char *prefix, RunList *r)
if (r) if (r)
printf("%s(%d):", r->n->name, r->pid); printf("%s(%d):", r->n->name, r->pid);
printf("%s.%s", eprefix, tl->sym->name); printf("%s.%s", eprefix, tl->sym->name);
if (tl->sym->nel > 1) if (tl->sym->nel > 1 || tl->sym->isarray == 1)
printf("[%d]", jx); printf("[%d]", jx);
printf(" = "); printf(" = ");
sr_mesg(stdout, tl->sym->val[jx], sr_mesg(stdout, tl->sym->val[jx],
@ -579,9 +583,11 @@ mk_explicit(Lextok *n, int Ok, int Ntyp)
int i, cnt; extern int IArgs; int i, cnt; extern int IArgs;
if (n->sym->type != STRUCT if (n->sym->type != STRUCT
|| in_for
|| is_explicit(n)) || is_explicit(n))
return n; return n;
if (n->rgt if (n->rgt
&& n->rgt->ntyp == '.' && n->rgt->ntyp == '.'
&& n->rgt->lft && n->rgt->lft

View file

@ -1,25 +1,27 @@
/***** spin: sym.c *****/ /***** spin: sym.c *****/
/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 "spin.h"
#include "y.tab.h" #include "y.tab.h"
extern Symbol *Fname, *owner; extern Symbol *Fname, *owner;
extern int lineno, depth, verbose, NamesNotAdded, deadvar; extern int lineno, depth, verbose, NamesNotAdded, deadvar;
extern int has_hidden, m_loss, old_scope_rules;
extern short has_xu; extern short has_xu;
extern char CurScope[MAXSCOPESZ];
Symbol *context = ZS; Symbol *context = ZS;
Ordered *all_names = (Ordered *)0; Ordered *all_names = (Ordered *)0;
int Nid = 0; int Nid = 0;
Lextok *Mtype = (Lextok *) 0;
Lextok *runstmnts = ZN;
static Ordered *last_name = (Ordered *)0; static Ordered *last_name = (Ordered *)0;
static Symbol *symtab[Nhash+1]; static Symbol *symtab[Nhash+1];
@ -31,12 +33,12 @@ samename(Symbol *a, Symbol *b)
return !strcmp(a->name, b->name); return !strcmp(a->name, b->name);
} }
int unsigned int
hash(char *s) hash(const char *s)
{ int h=0; { unsigned int h = 0;
while (*s) while (*s)
{ h += *s++; { h += (unsigned int) *s++;
h <<= 1; h <<= 1;
if (h&(Nhash+1)) if (h&(Nhash+1))
h |= 1; h |= 1;
@ -44,31 +46,89 @@ hash(char *s)
return h&Nhash; return h&Nhash;
} }
void
disambiguate(void)
{ Ordered *walk;
Symbol *sp;
char *n, *m;
if (old_scope_rules)
return;
/* prepend the scope_prefix to the names */
for (walk = all_names; walk; walk = walk->next)
{ sp = walk->entry;
if (sp->type != 0
&& sp->type != LABEL
&& strlen((const char *)sp->bscp) > 1)
{ if (sp->context)
{ m = (char *) emalloc(strlen((const char *)sp->bscp) + 1);
sprintf(m, "_%d_", sp->context->sc);
if (strcmp((const char *) m, (const char *) sp->bscp) == 0)
{ continue;
/* 6.2.0: only prepend scope for inner-blocks,
not for top-level locals within a proctype
this means that you can no longer use the same name
for a global and a (top-level) local variable
*/
} }
n = (char *) emalloc(strlen((const char *)sp->name)
+ strlen((const char *)sp->bscp) + 1);
sprintf(n, "%s%s", sp->bscp, sp->name);
sp->name = n; /* discard the old memory */
} }
}
Symbol * Symbol *
lookup(char *s) lookup(char *s)
{ Symbol *sp; Ordered *no; { Symbol *sp; Ordered *no;
int h = hash(s); unsigned int h = hash(s);
for (sp = symtab[h]; sp; sp = sp->next) if (old_scope_rules)
if (strcmp(sp->name, s) == 0 { /* same scope - global refering to global or local to local */
&& samename(sp->context, context) for (sp = symtab[h]; sp; sp = sp->next)
&& samename(sp->owner, owner)) { if (strcmp(sp->name, s) == 0
return sp; /* found */ && samename(sp->context, context)
&& samename(sp->owner, owner))
{ return sp; /* found */
} }
} else
{ /* added 6.0.0: more traditional, scope rule */
for (sp = symtab[h]; sp; sp = sp->next)
{ if (strcmp(sp->name, s) == 0
&& samename(sp->context, context)
&& (strcmp((const char *)sp->bscp, CurScope) == 0
|| strncmp((const char *)sp->bscp, CurScope, strlen((const char *)sp->bscp)) == 0)
&& samename(sp->owner, owner))
{
if (!samename(sp->owner, owner))
{ printf("spin: different container %s\n", sp->name);
printf(" old: %s\n", sp->owner?sp->owner->name:"--");
printf(" new: %s\n", owner?owner->name:"--");
/* alldone(1); */
}
return sp; /* found */
} } }
if (context) /* in proctype */ if (context) /* in proctype, refers to global */
for (sp = symtab[h]; sp; sp = sp->next) for (sp = symtab[h]; sp; sp = sp->next)
if (strcmp(sp->name, s) == 0 { if (strcmp(sp->name, s) == 0
&& !sp->context && !sp->context
&& samename(sp->owner, owner)) && samename(sp->owner, owner))
return sp; /* global */ { return sp; /* global */
} }
sp = (Symbol *) emalloc(sizeof(Symbol)); sp = (Symbol *) emalloc(sizeof(Symbol));
sp->name = (char *) emalloc((int) strlen(s) + 1); sp->name = (char *) emalloc(strlen(s) + 1);
strcpy(sp->name, s); strcpy(sp->name, s);
sp->nel = 1; sp->nel = 1;
sp->setat = depth; sp->setat = depth;
sp->context = context; sp->context = context;
sp->owner = owner; /* if fld in struct */ sp->owner = owner; /* if fld in struct */
sp->bscp = (unsigned char *) emalloc(strlen((const char *)CurScope)+1);
strcpy((char *)sp->bscp, CurScope);
if (NamesNotAdded == 0) if (NamesNotAdded == 0)
{ sp->next = symtab[h]; { sp->next = symtab[h];
@ -109,8 +169,6 @@ trackvar(Lextok *n, Lextok *m)
} }
} }
Lextok *runstmnts = ZN;
void void
trackrun(Lextok *n) trackrun(Lextok *n)
{ {
@ -151,11 +209,11 @@ checkrun(Symbol *parnm, int posno)
strcpy(buf2, (!(res&4))?"bit":"byte"); strcpy(buf2, (!(res&4))?"bit":"byte");
sputtype(buf, parnm->type); sputtype(buf, parnm->type);
i = (int) strlen(buf); i = (int) strlen(buf);
while (buf[--i] == ' ') buf[i] = '\0'; while (i > 0 && buf[--i] == ' ') buf[i] = '\0';
if (strcmp(buf, buf2) == 0) return; if (i == 0 || strcmp(buf, buf2) == 0) return;
prehint(parnm); prehint(parnm);
printf("proctype %s, '%s %s' could be declared", printf("proctype %s, '%s %s' could be declared",
parnm->context->name, buf, parnm->name); parnm->context?parnm->context->name:"", buf, parnm->name);
printf(" '%s %s'\n", buf2, parnm->name); printf(" '%s %s'\n", buf2, parnm->name);
} }
} }
@ -178,9 +236,9 @@ setptype(Lextok *n, int t, Lextok *vis) /* predefined types */
while (n) while (n)
{ if (n->sym->type && !(n->sym->hidden&32)) { if (n->sym->type && !(n->sym->hidden&32))
{ lineno = n->ln; Fname = n->fn; { lineno = n->ln; Fname = n->fn;
non_fatal("redeclaration of '%s'", n->sym->name); fatal("redeclaration of '%s'", n->sym->name);
lineno = oln; lineno = oln;
} }
n->sym->type = (short) t; n->sym->type = (short) t;
@ -201,14 +259,15 @@ setptype(Lextok *n, int t, Lextok *vis) /* predefined types */
n->sym->name); n->sym->name);
} }
if (vis) if (vis)
{ if (strncmp(vis->sym->name, ":hide:", 6) == 0) { if (strncmp(vis->sym->name, ":hide:", (size_t) 6) == 0)
{ n->sym->hidden |= 1; { n->sym->hidden |= 1;
has_hidden++;
if (t == BIT) if (t == BIT)
fatal("bit variable (%s) cannot be hidden", fatal("bit variable (%s) cannot be hidden",
n->sym->name); n->sym->name);
} else if (strncmp(vis->sym->name, ":show:", 6) == 0) } else if (strncmp(vis->sym->name, ":show:", (size_t) 6) == 0)
{ n->sym->hidden |= 2; { n->sym->hidden |= 2;
} else if (strncmp(vis->sym->name, ":local:", 7) == 0) } else if (strncmp(vis->sym->name, ":local:", (size_t) 7) == 0)
{ n->sym->hidden |= 64; { n->sym->hidden |= 64;
} }
} }
@ -268,7 +327,13 @@ void
setxus(Lextok *p, int t) setxus(Lextok *p, int t)
{ Lextok *m, *n; { Lextok *m, *n;
has_xu = 1; has_xu = 1;
if (m_loss && t == XS)
{ printf("spin: %s:%d, warning, xs tag not compatible with -m (message loss)\n",
(p->fn != NULL) ? p->fn->name : "stdin", p->ln);
}
if (!context) if (!context)
{ lineno = p->ln; { lineno = p->ln;
Fname = p->fn; Fname = p->fn;
@ -276,6 +341,7 @@ setxus(Lextok *p, int t)
} }
for (m = p; m; m = m->rgt) for (m = p; m; m = m->rgt)
{ Lextok *Xu_new = (Lextok *) emalloc(sizeof(Lextok)); { Lextok *Xu_new = (Lextok *) emalloc(sizeof(Lextok));
Xu_new->uiid = p->uiid;
Xu_new->val = t; Xu_new->val = t;
Xu_new->lft = m->lft; Xu_new->lft = m->lft;
Xu_new->sym = context; Xu_new->sym = context;
@ -297,8 +363,6 @@ setxus(Lextok *p, int t)
} }
} }
Lextok *Mtype = (Lextok *) 0;
void void
setmtype(Lextok *m) setmtype(Lextok *m)
{ Lextok *n; { Lextok *n;
@ -332,7 +396,7 @@ setmtype(Lextok *m)
} }
lineno = oln; lineno = oln;
if (cnt > 256) if (cnt > 256)
fatal("too many mtype elements (>255)", (char *)0); fatal("too many mtype elements (>255)", (char *)0);
} }
int int
@ -389,11 +453,11 @@ symvar(Symbol *sp)
printf("\t"); printf("\t");
if (sp->owner) printf("%s.", sp->owner->name); if (sp->owner) printf("%s.", sp->owner->name);
printf("%s", sp->name); printf("%s", sp->name);
if (sp->nel > 1) printf("[%d]", sp->nel); if (sp->nel > 1 || sp->isarray == 1) printf("[%d]", sp->nel);
if (sp->type == CHAN) if (sp->type == CHAN)
printf("\t%d", (sp->ini)?sp->ini->val:0); printf("\t%d", (sp->ini)?sp->ini->val:0);
else if (sp->type == STRUCT) /* Frank Weil, 2.9.8 */ else if (sp->type == STRUCT && sp->Snm != NULL) /* Frank Weil, 2.9.8 */
printf("\t%s", sp->Snm->name); printf("\t%s", sp->Snm->name);
else else
printf("\t%d", eval(sp->ini)); printf("\t%d", eval(sp->ini));
@ -408,8 +472,13 @@ symvar(Symbol *sp)
if (sp->Nid < 0) /* formal parameter */ if (sp->Nid < 0) /* formal parameter */
printf("\t<parameter %d>", -(sp->Nid)); printf("\t<parameter %d>", -(sp->Nid));
else if (sp->type == MTYPE)
printf("\t<constant>");
else if (sp->isarray)
printf("\t<array>");
else else
printf("\t<variable>"); printf("\t<variable>");
if (sp->type == CHAN && sp->ini) if (sp->type == CHAN && sp->ini)
{ int i; { int i;
for (m = sp->ini->rgt, i = 0; m; m = m->rgt) for (m = sp->ini->rgt, i = 0; m; m = m->rgt)
@ -423,6 +492,11 @@ symvar(Symbol *sp)
if (m->rgt) printf("\t"); if (m->rgt) printf("\t");
} }
} }
if (!old_scope_rules)
{ printf("\t{scope %s}", sp->bscp);
}
printf("\n"); printf("\n");
} }
@ -440,11 +514,10 @@ chname(Symbol *sp)
if (sp->context) printf("%s-", sp->context->name); if (sp->context) printf("%s-", sp->context->name);
if (sp->owner) printf("%s.", sp->owner->name); if (sp->owner) printf("%s.", sp->owner->name);
printf("%s", sp->name); printf("%s", sp->name);
if (sp->nel > 1) printf("[%d]", sp->nel); if (sp->nel > 1 || sp->isarray == 1) printf("[%d]", sp->nel);
printf("\t"); printf("\t");
} }
static struct X { static struct X {
int typ; char *nm; int typ; char *nm;
} xx[] = { } xx[] = {
@ -521,14 +594,14 @@ chanaccess(void)
if (!(verbose&32) || has_code) continue; if (!(verbose&32) || has_code) continue;
printf("spin: warning, %s, ", Fname->name); printf("spin: %s:0, warning, ", Fname->name);
sputtype(buf, walk->entry->type); sputtype(buf, walk->entry->type);
if (walk->entry->context) if (walk->entry->context)
printf("proctype %s", printf("proctype %s",
walk->entry->context->name); walk->entry->context->name);
else else
printf("global"); printf("global");
printf(", '%s%s' variable is never used\n", printf(", '%s%s' variable is never used (other than in print stmnts)\n",
buf, walk->entry->name); buf, walk->entry->name);
} } } }
} }

View file

@ -1,16 +1,13 @@
/***** tl_spin: tl.h *****/ /***** tl_spin: tl.h *****/
/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* this introductory message is not removed and no monies are exchanged. */ *
/* Software written by Gerard J. Holzmann. For tool documentation see: */ * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper,
/* http://spinroot.com/ */ * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.
/* Send all bug-reports and/or questions to: bugs@spinroot.com */ */
/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -66,6 +63,7 @@ enum {
#ifdef NXT #ifdef NXT
, NEXT /* 269 */ , NEXT /* 269 */
#endif #endif
, CEXPR /* 270 */
}; };
Node *Canonical(Node *); Node *Canonical(Node *);
@ -82,11 +80,12 @@ Symbol *tl_lookup(char *);
Symbol *getsym(Symbol *); Symbol *getsym(Symbol *);
Symbol *DoDump(Node *); Symbol *DoDump(Node *);
char *emalloc(int); /* in main.c */ extern char *emalloc(size_t); /* in main.c */
extern unsigned int hash(const char *); /* in sym.c */
int anywhere(int, Node *, Node *); int anywhere(int, Node *, Node *);
int dump_cond(Node *, Node *, int); int dump_cond(Node *, Node *, int);
int hash(char *); /* in sym.c */
int isalnum_(int); /* in spinlex.c */ int isalnum_(int); /* in spinlex.c */
int isequal(Node *, Node *); int isequal(Node *, Node *);
int tl_Getchar(void); int tl_Getchar(void);
@ -100,6 +99,10 @@ void exit(int);
void Fatal(char *, char *); void Fatal(char *, char *);
void fatal(char *, char *); void fatal(char *, char *);
void fsm_print(void); void fsm_print(void);
void ini_buchi(void);
void ini_cache(void);
void ini_rewrt(void);
void ini_trans(void);
void releasenode(int, Node *); void releasenode(int, Node *);
void tfree(void *); void tfree(void *);
void tl_explain(int); void tl_explain(int);

View file

@ -1,20 +1,18 @@
/***** tl_spin: tl_buchi.c *****/ /***** tl_spin: tl_buchi.c *****/
/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* this introductory message is not removed and no monies are exchanged. */ *
/* Software written by Gerard J. Holzmann. For tool documentation see: */ * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper,
/* http://spinroot.com/ */ * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.
/* Send all bug-reports and/or questions to: bugs@spinroot.com */ */
/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
#include "tl.h" #include "tl.h"
extern int tl_verbose, tl_clutter, Total, Max_Red; extern int tl_verbose, tl_clutter, Total, Max_Red;
extern char *claim_name;
FILE *tl_out; /* if standalone: = stdout; */ FILE *tl_out; /* if standalone: = stdout; */
@ -38,6 +36,13 @@ typedef struct State {
static State *never = (State *) 0; static State *never = (State *) 0;
static int hitsall; static int hitsall;
void
ini_buchi(void)
{
never = (State *) 0;
hitsall = 0;
}
static int static int
sametrans(Transition *s, Transition *t) sametrans(Transition *s, Transition *t)
{ {
@ -58,6 +63,7 @@ Prune(Node *p)
#ifdef NXT #ifdef NXT
case NEXT: case NEXT:
#endif #endif
case CEXPR:
return p; return p;
case OR: case OR:
p->lft = Prune(p->lft); p->lft = Prune(p->lft);
@ -545,10 +551,22 @@ rev_trans(Transition *t) /* print transitions in reverse order... */
rev_trans(t->nxt); rev_trans(t->nxt);
if (t->redundant && !tl_verbose) return; if (t->redundant && !tl_verbose) return;
fprintf(tl_out, "\t:: (");
if (dump_cond(t->cond, t->cond, 1)) if (strcmp(t->name->name, "accept_all") == 0) /* 6.2.4 */
fprintf(tl_out, "1"); { /* not d_step because there may be remote refs */
fprintf(tl_out, ") -> goto %s\n", t->name->name); fprintf(tl_out, "\t:: atomic { (");
if (dump_cond(t->cond, t->cond, 1))
fprintf(tl_out, "1");
fprintf(tl_out, ") -> assert(!(");
if (dump_cond(t->cond, t->cond, 1))
fprintf(tl_out, "1");
fprintf(tl_out, ")) }\n");
} else
{ fprintf(tl_out, "\t:: (");
if (dump_cond(t->cond, t->cond, 1))
fprintf(tl_out, "1");
fprintf(tl_out, ") -> goto %s\n", t->name->name);
}
tcnt++; tcnt++;
} }
@ -570,11 +588,11 @@ printstate(State *b)
&& Max_Red == 0) && Max_Red == 0)
fprintf(tl_out, "T0%s:\n", &(b->name->name[6])); fprintf(tl_out, "T0%s:\n", &(b->name->name[6]));
fprintf(tl_out, "\tif\n"); fprintf(tl_out, "\tdo\n");
tcnt = 0; tcnt = 0;
rev_trans(b->trans); rev_trans(b->trans);
if (!tcnt) fprintf(tl_out, "\t:: false\n"); if (!tcnt) fprintf(tl_out, "\t:: false\n");
fprintf(tl_out, "\tfi;\n"); fprintf(tl_out, "\tod;\n");
Total++; Total++;
} }
@ -626,13 +644,13 @@ fsm_print(void)
if (tl_clutter) clutter(); if (tl_clutter) clutter();
b = findstate("T0_init"); b = findstate("T0_init");
if (Max_Red == 0) if (b && (Max_Red == 0))
b->accepting = 1; b->accepting = 1;
mergestates(0); mergestates(0);
b = findstate("T0_init"); b = findstate("T0_init");
fprintf(tl_out, "never { /* "); fprintf(tl_out, "never %s { /* ", claim_name?claim_name:"");
put_uform(); put_uform();
fprintf(tl_out, " */\n"); fprintf(tl_out, " */\n");

View file

@ -1,16 +1,13 @@
/***** tl_spin: tl_cache.c *****/ /***** tl_spin: tl_cache.c *****/
/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* this introductory message is not removed and no monies are exchanged. */ *
/* Software written by Gerard J. Holzmann. For tool documentation see: */ * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper,
/* http://spinroot.com/ */ * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.
/* Send all bug-reports and/or questions to: bugs@spinroot.com */ */
/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
#include "tl.h" #include "tl.h"
@ -24,9 +21,18 @@ typedef struct Cache {
static Cache *stored = (Cache *) 0; static Cache *stored = (Cache *) 0;
static unsigned long Caches, CacheHits; static unsigned long Caches, CacheHits;
static int ismatch(Node *, Node *); static int ismatch(Node *, Node *);
static int sameform(Node *, Node *);
extern void fatal(char *, char *); extern void fatal(char *, char *);
int sameform(Node *, Node *);
void
ini_cache(void)
{
stored = (Cache *) 0;
Caches = 0;
CacheHits = 0;
}
#if 0 #if 0
void void
@ -182,7 +188,7 @@ sametrees(int ntyp, Node *a, Node *b)
return all_lfts(ntyp, b, a); return all_lfts(ntyp, b, a);
} }
int /* a better isequal() */ static int /* a better isequal() */
sameform(Node *a, Node *b) sameform(Node *a, Node *b)
{ {
if (!a && !b) return 1; if (!a && !b) return 1;
@ -206,6 +212,7 @@ sameform(Node *a, Node *b)
#ifdef NXT #ifdef NXT
case NEXT: case NEXT:
#endif #endif
case CEXPR:
return sameform(a->lft, b->lft); return sameform(a->lft, b->lft);
case U_OPER: case U_OPER:
case V_OPER: case V_OPER:

View file

@ -1,16 +1,13 @@
/***** tl_spin: tl_lex.c *****/ /***** tl_spin: tl_lex.c *****/
/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* this introductory message is not removed and no monies are exchanged. */ *
/* Software written by Gerard J. Holzmann. For tool documentation see: */ * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper,
/* http://spinroot.com/ */ * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.
/* Send all bug-reports and/or questions to: bugs@spinroot.com */ */
/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
@ -18,6 +15,7 @@
static Symbol *symtab[Nhash+1]; static Symbol *symtab[Nhash+1];
static int tl_lex(void); static int tl_lex(void);
extern int tl_peek(int);
extern YYSTYPE tl_yylval; extern YYSTYPE tl_yylval;
extern char yytext[]; extern char yytext[];
@ -26,11 +24,19 @@ extern char yytext[];
static void static void
tl_getword(int first, int (*tst)(int)) tl_getword(int first, int (*tst)(int))
{ int i=0; char c; { int i=0; int c;
yytext[i++] = (char ) first; yytext[i++] = (char ) first;
while (tst(c = tl_Getchar()))
yytext[i++] = c; c = tl_Getchar();
while (c != -1 && tst(c))
{ yytext[i++] = (char) c;
c = tl_Getchar();
}
/* while (tst(c = tl_Getchar()))
* yytext[i++] = c;
*/
yytext[i] = '\0'; yytext[i] = '\0';
tl_UnGetchar(); tl_UnGetchar();
} }
@ -54,11 +60,85 @@ int
tl_yylex(void) tl_yylex(void)
{ int c = tl_lex(); { int c = tl_lex();
#if 0 #if 0
printf("c = %d\n", c); printf("c = %c (%d)\n", c, c);
#endif #endif
return c; return c;
} }
static int
is_predicate(int z)
{ char c, c_prev = z;
char want = (z == '{') ? '}' : ')';
int i = 0, j, nesting = 0;
char peek_buf[512];
c = tl_peek(i++); /* look ahead without changing position */
while ((c != want || nesting > 0) && c != -1 && i < 2047)
{ if (islower((int) c) || c == '_')
{ peek_buf[0] = c;
j = 1;
while (j < (int) sizeof(peek_buf)
&& (isalnum((int)(c = tl_peek(i))) || c == '_'))
{ peek_buf[j++] = c;
i++;
}
c = 0; /* make sure we don't match on z or want on the peekahead */
if (j >= (int) sizeof(peek_buf))
{ peek_buf[j-1] = '\0';
fatal("name '%s' in ltl formula too long", peek_buf);
}
peek_buf[j] = '\0';
if (strcmp(peek_buf, "always") == 0
|| strcmp(peek_buf, "equivalent") == 0
|| strcmp(peek_buf, "eventually") == 0
|| strcmp(peek_buf, "until") == 0
|| strcmp(peek_buf, "next") == 0
|| strcmp(peek_buf, "c_expr") == 0)
{ return 0;
}
} else
{ int c_nxt = tl_peek(i);
if (((c == 'U' || c == 'V' || c == 'X')
&& !isalnum_(c_prev)
&& (c_nxt == -1 || !isalnum_(c_nxt)))
|| (c == '<' && c_nxt == '>')
|| (c == '<' && c_nxt == '-')
|| (c == '-' && c_nxt == '>')
|| (c == '[' && c_nxt == ']'))
{ return 0;
} }
if (c == z)
{ nesting++;
}
if (c == want)
{ nesting--;
}
c_prev = c;
c = tl_peek(i++);
}
return 1;
}
static void
read_upto_closing(int z)
{ char c, want = (z == '{') ? '}' : ')';
int i = 0, nesting = 0;
c = tl_Getchar();
while ((c != want || nesting > 0) && c != -1 && i < 2047) /* yytext is 2048 */
{ yytext[i++] = c;
if (c == z)
{ nesting++;
}
if (c == want)
{ nesting--;
}
c = tl_Getchar();
}
yytext[i] = '\0';
}
static int static int
tl_lex(void) tl_lex(void)
{ int c; { int c;
@ -74,6 +154,20 @@ tl_lex(void)
} while (c == ' '); /* '\t' is removed in tl_main.c */ } while (c == ' '); /* '\t' is removed in tl_main.c */
if (c == '{' || c == '(') /* new 6.0.0 */
{ if (is_predicate(c))
{ read_upto_closing(c);
tl_yylval = tl_nn(PREDICATE,ZN,ZN);
if (!tl_yylval)
{ fatal("unexpected error 4", (char *) 0);
}
tl_yylval->sym = tl_lookup(yytext);
return PREDICATE;
} }
if (c == '}')
{ tl_yyerror("unexpected '}'");
}
if (islower(c)) if (islower(c))
{ tl_getword(c, isalnum_); { tl_getword(c, isalnum_);
if (strcmp("true", yytext) == 0) if (strcmp("true", yytext) == 0)
@ -82,10 +176,34 @@ tl_lex(void)
if (strcmp("false", yytext) == 0) if (strcmp("false", yytext) == 0)
{ Token(FALSE); { Token(FALSE);
} }
if (strcmp("always", yytext) == 0)
{ Token(ALWAYS);
}
if (strcmp("eventually", yytext) == 0)
{ Token(EVENTUALLY);
}
if (strcmp("until", yytext) == 0)
{ Token(U_OPER);
}
#ifdef NXT
if (strcmp("next", yytext) == 0)
{ Token(NEXT);
}
#endif
if (strcmp("c_expr", yytext) == 0)
{ Token(CEXPR);
}
if (strcmp("not", yytext) == 0)
{ Token(NOT);
}
tl_yylval = tl_nn(PREDICATE,ZN,ZN); tl_yylval = tl_nn(PREDICATE,ZN,ZN);
if (!tl_yylval)
{ fatal("unexpected error 5", (char *) 0);
}
tl_yylval->sym = tl_lookup(yytext); tl_yylval->sym = tl_lookup(yytext);
return PREDICATE; return PREDICATE;
} }
if (c == '<') if (c == '<')
{ c = tl_Getchar(); { c = tl_Getchar();
if (c == '>') if (c == '>')
@ -124,7 +242,7 @@ tl_lex(void)
Symbol * Symbol *
tl_lookup(char *s) tl_lookup(char *s)
{ Symbol *sp; { Symbol *sp;
int h = hash(s); unsigned int h = hash(s);
for (sp = symtab[h]; sp; sp = sp->next) for (sp = symtab[h]; sp; sp = sp->next)
if (strcmp(sp->name, s) == 0) if (strcmp(sp->name, s) == 0)

View file

@ -1,16 +1,13 @@
/***** tl_spin: tl_main.c *****/ /***** tl_spin: tl_main.c *****/
/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* this introductory message is not removed and no monies are exchanged. */ *
/* Software written by Gerard J. Holzmann. For tool documentation see: */ * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper,
/* http://spinroot.com/ */ * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.
/* Send all bug-reports and/or questions to: bugs@spinroot.com */ */
/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
#include "tl.h" #include "tl.h"
@ -21,7 +18,10 @@ int tl_errs = 0;
int tl_verbose = 0; int tl_verbose = 0;
int tl_terse = 0; int tl_terse = 0;
int tl_clutter = 0; int tl_clutter = 0;
int state_cnt = 0;
unsigned long All_Mem = 0; unsigned long All_Mem = 0;
char *claim_name;
static char uform[4096]; static char uform[4096];
static int hasuform=0, cnt=0; static int hasuform=0, cnt=0;
@ -38,6 +38,15 @@ tl_Getchar(void)
return -1; return -1;
} }
int
tl_peek(int n)
{
if (cnt+n < hasuform)
{ return uform[cnt+n];
}
return -1;
}
void void
tl_balanced(void) tl_balanced(void)
{ int i; { int i;
@ -45,10 +54,21 @@ tl_balanced(void)
for (i = 0; i < hasuform; i++) for (i = 0; i < hasuform; i++)
{ if (uform[i] == '(') { if (uform[i] == '(')
{ k++; { if (i > 0
&& ((uform[i-1] == '"' && uform[i+1] == '"')
|| (uform[i-1] == '\'' && uform[i+1] == '\'')))
{ continue;
}
k++;
} else if (uform[i] == ')') } else if (uform[i] == ')')
{ k--; { if (i > 0
&& ((uform[i-1] == '"' && uform[i+1] == '"')
|| (uform[i-1] == '\'' && uform[i+1] == '\'')))
{ continue;
}
k--;
} } } }
if (k != 0) if (k != 0)
{ tl_errs++; { tl_errs++;
tl_yyerror("parentheses not balanced"); tl_yyerror("parentheses not balanced");
@ -79,18 +99,40 @@ tl_stats(void)
int int
tl_main(int argc, char *argv[]) tl_main(int argc, char *argv[])
{ int i; { int i;
extern int verbose, xspin; extern int xspin, s_trail;
tl_verbose = verbose;
tl_clutter = 1-xspin; /* use -X -f to turn off uncluttering */ tl_verbose = 0; /* was: tl_verbose = verbose; */
if (xspin && s_trail)
{ tl_clutter = 1;
/* generating claims for a replay should
be done the same as when generating the
pan.c that produced the error-trail */
} else
{ tl_clutter = 1-xspin; /* use -X -f to turn off uncluttering */
}
newstates = 0;
state_cnt = 0;
tl_errs = 0;
tl_terse = 0;
All_Mem = 0;
memset(uform, 0, sizeof(uform));
hasuform=0;
cnt=0;
claim_name = (char *) 0;
ini_buchi();
ini_cache();
ini_rewrt();
ini_trans();
while (argc > 1 && argv[1][0] == '-') while (argc > 1 && argv[1][0] == '-')
{ switch (argv[1][1]) { {
switch (argv[1][1]) {
case 'd': newstates = 1; /* debugging mode */ case 'd': newstates = 1; /* debugging mode */
break; break;
case 'f': argc--; argv++; case 'f': argc--; argv++;
for (i = 0; i < argv[1][i]; i++) for (i = 0; argv[1][i]; i++)
{ if (argv[1][i] == '\t' { if (argv[1][i] == '\t'
|| argv[1][i] == '\"'
|| argv[1][i] == '\n') || argv[1][i] == '\n')
argv[1][i] = ' '; argv[1][i] = ' ';
} }
@ -101,6 +143,10 @@ tl_main(int argc, char *argv[])
break; break;
case 'n': tl_terse = 1; case 'n': tl_terse = 1;
break; break;
case 'c': argc--; argv++;
claim_name = (char *) emalloc(strlen(argv[1])+1);
strcpy(claim_name, argv[1]);
break;
default : printf("spin -f: saw '-%c'\n", argv[1][1]); default : printf("spin -f: saw '-%c'\n", argv[1][1]);
goto nogood; goto nogood;
} }
@ -162,6 +208,12 @@ dump(Node *n)
case PREDICATE: case PREDICATE:
fprintf(tl_out, "(%s)", n->sym->name); fprintf(tl_out, "(%s)", n->sym->name);
break; break;
case CEXPR:
fprintf(tl_out, "c_expr");
fprintf(tl_out, " {");
dump(n->lft);
fprintf(tl_out, "}");
break;
case -1: case -1:
fprintf(tl_out, " D "); fprintf(tl_out, " D ");
break; break;
@ -189,6 +241,7 @@ tl_explain(int n)
#ifdef NXT #ifdef NXT
case NEXT: printf("X"); break; case NEXT: printf("X"); break;
#endif #endif
case CEXPR: printf("c_expr"); break;
case TRUE: printf("true"); break; case TRUE: printf("true"); break;
case FALSE: printf("false"); break; case FALSE: printf("false"); break;
case ';': printf("end of formula"); break; case ';': printf("end of formula"); break;
@ -202,10 +255,14 @@ tl_non_fatal(char *s1, char *s2)
int i; int i;
printf("tl_spin: "); printf("tl_spin: ");
#if 1
printf(s1, s2); /* prevent a compiler warning */
#else
if (s2) if (s2)
printf(s1, s2); printf(s1, s2);
else else
printf(s1); printf(s1);
#endif
if (tl_yychar != -1 && tl_yychar != 0) if (tl_yychar != -1 && tl_yychar != 0)
{ printf(", saw '"); { printf(", saw '");
tl_explain(tl_yychar); tl_explain(tl_yychar);

View file

@ -1,16 +1,13 @@
/***** tl_spin: tl_mem.c *****/ /***** tl_spin: tl_mem.c *****/
/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* this introductory message is not removed and no monies are exchanged. */ *
/* Software written by Gerard J. Holzmann. For tool documentation see: */ * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper,
/* http://spinroot.com/ */ * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.
/* Send all bug-reports and/or questions to: bugs@spinroot.com */ */
/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
#include "tl.h" #include "tl.h"

View file

@ -1,16 +1,13 @@
/***** tl_spin: tl_parse.c *****/ /***** tl_spin: tl_parse.c *****/
/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* this introductory message is not removed and no monies are exchanged. */ *
/* Software written by Gerard J. Holzmann. For tool documentation see: */ * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper,
/* http://spinroot.com/ */ * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.
/* Send all bug-reports and/or questions to: bugs@spinroot.com */ */
/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
#include "tl.h" #include "tl.h"
@ -44,11 +41,13 @@ tl_factor(void)
ptr = tl_yylval; ptr = tl_yylval;
tl_yychar = tl_yylex(); tl_yychar = tl_yylex();
ptr->lft = tl_factor(); ptr->lft = tl_factor();
if (!ptr->lft)
{ fatal("malformed expression", (char *) 0);
}
ptr = push_negation(ptr); ptr = push_negation(ptr);
break; break;
case ALWAYS: case ALWAYS:
tl_yychar = tl_yylex(); tl_yychar = tl_yylex();
ptr = tl_factor(); ptr = tl_factor();
#ifndef NO_OPT #ifndef NO_OPT
if (ptr->ntyp == FALSE if (ptr->ntyp == FALSE
@ -73,6 +72,14 @@ tl_factor(void)
ptr = tl_nn(NEXT, ptr, ZN); ptr = tl_nn(NEXT, ptr, ZN);
break; break;
#endif #endif
case CEXPR:
tl_yychar = tl_yylex();
ptr = tl_factor();
if (ptr->ntyp != PREDICATE)
{ tl_yyerror("expected {...} after c_expr");
}
ptr = tl_nn(CEXPR, ptr, ZN);
break;
case EVENTUALLY: case EVENTUALLY:
tl_yychar = tl_yylex(); tl_yychar = tl_yylex();
@ -385,7 +392,10 @@ tl_formula(void)
void void
tl_parse(void) tl_parse(void)
{ Node *n = tl_formula(); { Node *n;
/* tl_verbose = 1; */
n = tl_formula();
if (tl_verbose) if (tl_verbose)
{ printf("formula: "); { printf("formula: ");
dump(n); dump(n);

View file

@ -1,16 +1,13 @@
/***** tl_spin: tl_rewrt.c *****/ /***** tl_spin: tl_rewrt.c *****/
/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* this introductory message is not removed and no monies are exchanged. */ *
/* Software written by Gerard J. Holzmann. For tool documentation see: */ * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper,
/* http://spinroot.com/ */ * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.
/* Send all bug-reports and/or questions to: bugs@spinroot.com */ */
/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
#include "tl.h" #include "tl.h"
@ -18,6 +15,12 @@ extern int tl_verbose;
static Node *can = ZN; static Node *can = ZN;
void
ini_rewrt(void)
{
can = ZN;
}
Node * Node *
right_linked(Node *n) right_linked(Node *n)
{ {
@ -137,6 +140,9 @@ addcan(int tok, Node *n)
} }
s = DoDump(N); s = DoDump(N);
if (!s)
{ fatal("unexpected error 6", (char *) 0);
}
if (can->ntyp != tok) /* only one element in list so far */ if (can->ntyp != tok) /* only one element in list so far */
{ ptr = &can; { ptr = &can;
goto insert; goto insert;
@ -146,7 +152,10 @@ addcan(int tok, Node *n)
prev = ZN; prev = ZN;
for (m = can; m->ntyp == tok && m->rgt; prev = m, m = m->rgt) for (m = can; m->ntyp == tok && m->rgt; prev = m, m = m->rgt)
{ t = DoDump(m->lft); { t = DoDump(m->lft);
cmp = strcmp(s->name, t->name); if (t != ZS)
cmp = strcmp(s->name, t->name);
else
cmp = 0;
if (cmp == 0) /* duplicate */ if (cmp == 0) /* duplicate */
return; return;
if (cmp < 0) if (cmp < 0)

View file

@ -1,21 +1,18 @@
/***** tl_spin: tl_trans.c *****/ /***** tl_spin: tl_trans.c *****/
/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* this introductory message is not removed and no monies are exchanged. */ *
/* Software written by Gerard J. Holzmann. For tool documentation see: */ * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper,
/* http://spinroot.com/ */ * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.
/* Send all bug-reports and/or questions to: bugs@spinroot.com */ */
/* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
/* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. */
#include "tl.h" #include "tl.h"
extern FILE *tl_out; extern FILE *tl_out;
extern int tl_errs, tl_verbose, tl_terse, newstates; extern int tl_errs, tl_verbose, tl_terse, newstates, state_cnt;
int Stack_mx=0, Max_Red=0, Total=0; int Stack_mx=0, Max_Red=0, Total=0;
@ -23,7 +20,7 @@ static Mapping *Mapped = (Mapping *) 0;
static Graph *Nodes_Set = (Graph *) 0; static Graph *Nodes_Set = (Graph *) 0;
static Graph *Nodes_Stack = (Graph *) 0; static Graph *Nodes_Stack = (Graph *) 0;
static char dumpbuf[2048]; static char dumpbuf[4096];
static int Red_cnt = 0; static int Red_cnt = 0;
static int Lab_cnt = 0; static int Lab_cnt = 0;
static int Base = 0; static int Base = 0;
@ -51,6 +48,24 @@ static void ng(Symbol *, Symbol *, Node *, Node *, Node *);
static void push_stack(Graph *); static void push_stack(Graph *);
static void sdump(Node *); static void sdump(Node *);
void
ini_trans(void)
{
Stack_mx = 0;
Max_Red = 0;
Total = 0;
Mapped = (Mapping *) 0;
Nodes_Set = (Graph *) 0;
Nodes_Stack = (Graph *) 0;
memset(dumpbuf, 0, sizeof(dumpbuf));
Red_cnt = 0;
Lab_cnt = 0;
Base = 0;
Stack_sz = 0;
}
static void static void
dump_graph(Graph *g) dump_graph(Graph *g)
{ Node *n1; { Node *n1;
@ -101,9 +116,8 @@ pop_stack(void)
static char * static char *
newname(void) newname(void)
{ static int cnt = 0; { static char buf[32];
static char buf[32]; sprintf(buf, "S%d", state_cnt++);
sprintf(buf, "S%d", cnt++);
return buf; return buf;
} }
@ -132,6 +146,8 @@ static void
mk_grn(Node *n) mk_grn(Node *n)
{ Graph *p; { Graph *p;
if (!n) return;
n = right_linked(n); n = right_linked(n);
more: more:
for (p = Nodes_Set; p; p = p->nxt) for (p = Nodes_Set; p; p = p->nxt)
@ -152,6 +168,8 @@ static void
mk_red(Node *n) mk_red(Node *n)
{ Graph *p; { Graph *p;
if (!n) return;
n = right_linked(n); n = right_linked(n);
for (p = Nodes_Set; p; p = p->nxt) for (p = Nodes_Set; p; p = p->nxt)
{ if (p->outgoing { if (p->outgoing
@ -240,6 +258,15 @@ dump_cond(Node *pp, Node *r, int first)
q = dupnode(pp); q = dupnode(pp);
q = rewrite(q); q = rewrite(q);
if (q->ntyp == CEXPR)
{ if (!frst) fprintf(tl_out, " && ");
fprintf(tl_out, "c_expr { ");
dump_cond(q->lft, r, 1);
fprintf(tl_out, " } ");
frst = 0;
return frst;
}
if (q->ntyp == PREDICATE if (q->ntyp == PREDICATE
|| q->ntyp == NOT || q->ntyp == NOT
#ifndef NXT #ifndef NXT
@ -342,7 +369,7 @@ static void
fsm_trans(Graph *p, int count, char *curnm) fsm_trans(Graph *p, int count, char *curnm)
{ Graph *r; { Graph *r;
Symbol *s; Symbol *s;
char prefix[128], nwnm[128]; char prefix[128], nwnm[256];
if (!p->outgoing) if (!p->outgoing)
addtrans(p, curnm, False, "accept_all"); addtrans(p, curnm, False, "accept_all");
@ -452,9 +479,11 @@ fixinit(Node *orig)
ng(tl_lookup("init"), ZS, ZN, ZN, ZN); ng(tl_lookup("init"), ZS, ZN, ZN, ZN);
p1 = pop_stack(); p1 = pop_stack();
p1->nxt = Nodes_Set; if (p1)
p1->Other = p1->Old = orig; { p1->nxt = Nodes_Set;
Nodes_Set = p1; p1->Other = p1->Old = orig;
Nodes_Set = p1;
}
for (g = Nodes_Set; g; g = g->nxt) for (g = Nodes_Set; g; g = g->nxt)
{ for (q1 = g->incoming; q1; q1 = q2) { for (q1 = g->incoming; q1; q1 = q2)
@ -532,6 +561,10 @@ common1: sdump(n->lft);
case NEXT: strcat(dumpbuf, "X"); case NEXT: strcat(dumpbuf, "X");
goto common1; goto common1;
#endif #endif
case CEXPR: strcat(dumpbuf, "c_expr {");
sdump(n->lft);
strcat(dumpbuf, "}");
break;
case NOT: strcat(dumpbuf, "!"); case NOT: strcat(dumpbuf, "!");
goto common1; goto common1;
case TRUE: strcat(dumpbuf, "T"); case TRUE: strcat(dumpbuf, "T");
@ -718,10 +751,13 @@ out:
break; break;
case PREDICATE: case PREDICATE:
case NOT: case NOT:
case CEXPR:
if (can_release) releasenode(1, now); if (can_release) releasenode(1, now);
push_stack(g); push_stack(g);
break; break;
case V_OPER: case V_OPER:
Assert(now->rgt != ZN, now->ntyp);
Assert(now->lft != ZN, now->ntyp);
Assert(now->rgt->nxt == ZN, now->ntyp); Assert(now->rgt->nxt == ZN, now->ntyp);
Assert(now->lft->nxt == ZN, now->ntyp); Assert(now->lft->nxt == ZN, now->ntyp);
n1 = now->rgt; n1 = now->rgt;
@ -759,6 +795,7 @@ out:
#ifdef NXT #ifdef NXT
case NEXT: case NEXT:
Assert(now->lft != ZN, now->ntyp);
nx = dupnode(now->lft); nx = dupnode(now->lft);
nx->nxt = g->Next; nx->nxt = g->Next;
g->Next = nx; g->Next = nx;

View file

@ -1,13 +1,10 @@
/***** spin: vars.c *****/ /***** spin: vars.c *****/
/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /*
/* All Rights Reserved. This software is for educational purposes only. */ * This file is part of the public release of Spin. It is subject to the
/* No guarantee whatsoever is expressed or implied by the distribution of */ * terms in the LICENSE file that is included in this source directory.
/* this code. Permission is given to distribute this code provided that */ * Tool documentation is available at http://spinroot.com
/* 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 "spin.h"
#include "y.tab.h" #include "y.tab.h"
@ -17,7 +14,7 @@ extern RunList *X, *LastX;
extern Symbol *Fname; extern Symbol *Fname;
extern char Buf[]; extern char Buf[];
extern int lineno, depth, verbose, xspin, limited_vis; extern int lineno, depth, verbose, xspin, limited_vis;
extern int analyze, jumpsteps, nproc, nstop, columns; extern int analyze, jumpsteps, nproc, nstop, columns, old_priority_rules;
extern short no_arrays, Have_claim; extern short no_arrays, Have_claim;
extern void sr_mesg(FILE *, int, int); extern void sr_mesg(FILE *, int, int);
extern void sr_buf(int, int); extern void sr_buf(int, int);
@ -42,22 +39,54 @@ getval(Lextok *sn)
{ if (!X) return 0; { if (!X) return 0;
return X->pid - Have_claim; return X->pid - Have_claim;
} }
if (strcmp(s->name, "_priority") == 0)
{ if (!X) return 0;
if (old_priority_rules)
{ non_fatal("cannot refer to _priority with -o6", (char *) 0);
return 1;
}
return X->priority;
}
if (strcmp(s->name, "_nr_pr") == 0) if (strcmp(s->name, "_nr_pr") == 0)
return nproc-nstop; /* new 3.3.10 */ { return nproc-nstop; /* new 3.3.10 */
}
if (s->context && s->type) if (s->context && s->type)
return getlocal(sn); { return getlocal(sn);
}
if (!s->type) /* not declared locally */ if (!s->type) /* not declared locally */
{ s = lookup(s->name); /* try global */ { s = lookup(s->name); /* try global */
sn->sym = s; /* fix it */ sn->sym = s; /* fix it */
} }
return getglobal(sn); return getglobal(sn);
} }
int int
setval(Lextok *v, int n) setval(Lextok *v, int n)
{ {
if (strcmp(v->sym->name, "_last") == 0
|| strcmp(v->sym->name, "_p") == 0
|| strcmp(v->sym->name, "_pid") == 0
|| strcmp(v->sym->name, "_nr_qs") == 0
|| strcmp(v->sym->name, "_nr_pr") == 0)
{ non_fatal("illegal assignment to %s", v->sym->name);
}
if (strcmp(v->sym->name, "_priority") == 0)
{ if (old_priority_rules)
{ non_fatal("cannot refer to _priority with -o6", (char *) 0);
return 1;
}
if (!X)
{ non_fatal("no context for _priority", (char *) 0);
return 1;
}
X->priority = n;
}
if (v->sym->context && v->sym->type) if (v->sym->context && v->sym->type)
return setlocal(v, n); return setlocal(v, n);
if (!v->sym->type) if (!v->sym->type)
@ -90,6 +119,7 @@ int
checkvar(Symbol *s, int n) checkvar(Symbol *s, int n)
{ int i, oln = lineno; /* calls on eval() change it */ { int i, oln = lineno; /* calls on eval() change it */
Symbol *ofnm = Fname; Symbol *ofnm = Fname;
Lextok *z, *y;
if (!in_bound(s, n)) if (!in_bound(s, n))
return 0; return 0;
@ -101,15 +131,23 @@ checkvar(Symbol *s, int n)
/* not a STRUCT */ /* not a STRUCT */
if (s->val == (int *) 0) /* uninitialized */ if (s->val == (int *) 0) /* uninitialized */
{ s->val = (int *) emalloc(s->nel*sizeof(int)); { s->val = (int *) emalloc(s->nel*sizeof(int));
z = s->ini;
for (i = 0; i < s->nel; i++) for (i = 0; i < s->nel; i++)
{ if (s->type != CHAN) { if (z && z->ntyp == ',')
{ rm_selfrefs(s, s->ini); { y = z->lft;
s->val[i] = eval(s->ini); z = z->rgt;
} else
{ y = z;
}
if (s->type != CHAN)
{ rm_selfrefs(s, y);
s->val[i] = eval(y);
} else if (!analyze) } else if (!analyze)
s->val[i] = qmake(s); { s->val[i] = qmake(s);
} } } } }
lineno = oln; lineno = oln;
Fname = ofnm; Fname = ofnm;
return 1; return 1;
} }
@ -118,14 +156,16 @@ getglobal(Lextok *sn)
{ Symbol *s = sn->sym; { Symbol *s = sn->sym;
int i, n = eval(sn->lft); int i, n = eval(sn->lft);
if (s->type == 0 && X && (i = find_lab(s, X->n, 0))) if (s->type == 0 && X && (i = find_lab(s, X->n, 0))) /* getglobal */
{ printf("findlab through getglobal on %s\n", s->name); { printf("findlab through getglobal on %s\n", s->name);
return i; /* can this happen? */ return i; /* can this happen? */
} }
if (s->type == STRUCT) if (s->type == STRUCT)
return Rval_struct(sn, s, 1); /* 1 = check init */ { return Rval_struct(sn, s, 1); /* 1 = check init */
}
if (checkvar(s, n)) if (checkvar(s, n))
return cast_val(s->type, s->val[n], s->nbits); { return cast_val(s->type, s->val[n], s->nbits);
}
return 0; return 0;
} }
@ -145,23 +185,26 @@ cast_val(int t, int v, int w)
} }
if (v != i+s+ (int) u) if (v != i+s+ (int) u)
{ char buf[32]; sprintf(buf, "%d->%d (%d)", v, i+s+u, t); { char buf[64]; sprintf(buf, "%d->%d (%d)", v, i+s+(int)u, t);
non_fatal("value (%s) truncated in assignment", buf); non_fatal("value (%s) truncated in assignment", buf);
} }
return (int)(i+s+u); return (int)(i+s+(int)u);
} }
static int static int
setglobal(Lextok *v, int m) setglobal(Lextok *v, int m)
{ {
if (v->sym->type == STRUCT) if (v->sym->type == STRUCT)
(void) Lval_struct(v, v->sym, 1, m); { (void) Lval_struct(v, v->sym, 1, m);
else } else
{ int n = eval(v->lft); { int n = eval(v->lft);
if (checkvar(v->sym, n)) if (checkvar(v->sym, n))
{ v->sym->val[n] = cast_val(v->sym->type, m, v->sym->nbits); { int oval = v->sym->val[n];
v->sym->setat = depth; int nval = cast_val(v->sym->type, m, v->sym->nbits);
} } v->sym->val[n] = nval;
if (oval != nval)
{ v->sym->setat = depth;
} } }
return 1; return 1;
} }
@ -215,7 +258,12 @@ dumpglobals(void)
continue; continue;
if (sp->type == STRUCT) if (sp->type == STRUCT)
{ dump_struct(sp, sp->name, 0); { if ((verbose&4) && !(verbose&64)
&& (sp->setat < depth
&& jumpsteps != depth))
{ continue;
}
dump_struct(sp, sp->name, 0);
continue; continue;
} }
for (j = 0; j < sp->nel; j++) for (j = 0; j < sp->nel; j++)
@ -227,13 +275,15 @@ dumpglobals(void)
if ((verbose&4) && !(verbose&64) if ((verbose&4) && !(verbose&64)
&& (sp->setat < depth && (sp->setat < depth
&& jumpsteps != depth)) && jumpsteps != depth))
continue; { continue;
}
dummy->sym = sp; dummy->sym = sp;
dummy->lft->val = j; dummy->lft->val = j;
/* in case of cast_val warnings, do this first: */ /* in case of cast_val warnings, do this first: */
prefetch = getglobal(dummy); prefetch = getglobal(dummy);
printf("\t\t%s", sp->name); printf("\t\t%s", sp->name);
if (sp->nel > 1) printf("[%d]", j); if (sp->nel > 1 || sp->isarray) printf("[%d]", j);
printf(" = "); printf(" = ");
sr_mesg(stdout, prefetch, sr_mesg(stdout, prefetch,
sp->type == MTYPE); sp->type == MTYPE);
@ -249,7 +299,7 @@ dumpglobals(void)
} }
sr_buf(prefetch, sp->type == MTYPE); sr_buf(prefetch, sp->type == MTYPE);
if (sp->colnr == 0) if (sp->colnr == 0)
{ sp->colnr = maxcolnr; { sp->colnr = (unsigned char) maxcolnr;
maxcolnr = 1+(maxcolnr%10); maxcolnr = 1+(maxcolnr%10);
} }
colpos = nproc+sp->colnr-1; colpos = nproc+sp->colnr-1;
@ -266,7 +316,7 @@ dumpglobals(void)
depth, colpos); depth, colpos);
printf("(state 0)\t[printf('MSC: globvar\\\\n')]\n"); printf("(state 0)\t[printf('MSC: globvar\\\\n')]\n");
printf("\t\t%s", sp->name); printf("\t\t%s", sp->name);
if (sp->nel > 1) printf("[%d]", j); if (sp->nel > 1 || sp->isarray) printf("[%d]", j);
printf(" = %s\n", Buf); printf(" = %s\n", Buf);
} } } } } }
} }
@ -303,8 +353,8 @@ dumplocal(RunList *r)
dummy->lft->val = i; dummy->lft->val = i;
printf("\t\t%s(%d):%s", printf("\t\t%s(%d):%s",
r->n->name, r->pid, z->name); r->n->name, r->pid - Have_claim, z->name);
if (z->nel > 1) printf("[%d]", i); if (z->nel > 1 || z->isarray) printf("[%d]", i);
printf(" = "); printf(" = ");
sr_mesg(stdout, getval(dummy), z->type == MTYPE); sr_mesg(stdout, getval(dummy), z->type == MTYPE);
printf("\n"); printf("\n");
@ -321,7 +371,7 @@ dumplocal(RunList *r)
} }
sr_buf(getval(dummy), z->type==MTYPE); sr_buf(getval(dummy), z->type==MTYPE);
if (z->colnr == 0) if (z->colnr == 0)
{ z->colnr = maxcolnr; { z->colnr = (unsigned char) maxcolnr;
maxcolnr = 1+(maxcolnr%10); maxcolnr = 1+(maxcolnr%10);
} }
colpos = nproc+z->colnr-1; colpos = nproc+z->colnr-1;
@ -341,7 +391,7 @@ dumplocal(RunList *r)
printf("(state 0)\t[printf('MSC: locvar\\\\n')]\n"); printf("(state 0)\t[printf('MSC: locvar\\\\n')]\n");
printf("\t\t%s(%d):%s", printf("\t\t%s(%d):%s",
r->n->name, r->pid, z->name); r->n->name, r->pid, z->name);
if (z->nel > 1) printf("[%d]", i); if (z->nel > 1 || z->isarray) printf("[%d]", i);
printf(" = %s\n", Buf); printf(" = %s\n", Buf);
} } } } } }
} }

View file

@ -1 +1,9 @@
#define Version "Spin Version 4.3.0 -- 22 June 2007" /***** spin: version.h *****/
/*
* This file is part of the public release of Spin. It is subject to the
* terms in the LICENSE file that is included in this source directory.
* Tool documentation is available at http://spinroot.com
*/
#define SpinVersion "Spin Version 6.4.7 -- 19 August 2017"