/***** spin: structs.c *****/
/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */
/* All Rights Reserved. This software is for educational purposes only. */
/* No guarantee whatsoever is expressed or implied by the distribution of */
/* this code. Permission is given to distribute this code provided that */
/* this introductory message is not removed and no monies are exchanged. */
/* Software written by Gerard J. Holzmann. For tool documentation see: */
/* http://spinroot.com/ */
/* Send all bug-reports and/or questions to: bugs@spinroot.com */
#include "spin.h"
#include "y.tab.h"
typedef struct UType {
Symbol *nm; /* name of the type */
Lextok *cn; /* contents */
struct UType *nxt; /* linked list */
} UType;
extern Symbol *Fname;
extern int lineno, depth, Expand_Ok;
Symbol *owner;
static UType *Unames = 0;
static UType *Pnames = 0;
static Lextok *cpnn(Lextok *, int, int, int);
extern void sr_mesg(FILE *, int, int);
void
setuname(Lextok *n)
{ UType *tmp;
for (tmp = Unames; tmp; tmp = tmp->nxt)
if (!strcmp(owner->name, tmp->nm->name))
{ non_fatal("typename %s was defined before",
tmp->nm->name);
return;
}
if (!owner) fatal("illegal reference inside typedef",
(char *) 0);
tmp = (UType *) emalloc(sizeof(UType));
tmp->nm = owner;
tmp->cn = n;
tmp->nxt = Unames;
Unames = tmp;
}
static void
putUname(FILE *fd, UType *tmp)
{ Lextok *fp, *tl;
if (!tmp) return;
putUname(fd, tmp->nxt); /* postorder */
fprintf(fd, "struct %s { /* user defined type */\n",
tmp->nm->name);
for (fp = tmp->cn; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt)
typ2c(tl->sym);
fprintf(fd, "};\n");
}
void
putunames(FILE *fd)
{
putUname(fd, Unames);
}
int
isutype(char *t)
{ UType *tmp;
for (tmp = Unames; tmp; tmp = tmp->nxt)
{ if (!strcmp(t, tmp->nm->name))
return 1;
}
return 0;
}
Lextok *
getuname(Symbol *t)
{ UType *tmp;
for (tmp = Unames; tmp; tmp = tmp->nxt)
{ if (!strcmp(t->name, tmp->nm->name))
return tmp->cn;
}
fatal("%s is not a typename", t->name);
return (Lextok *)0;
}
void
setutype(Lextok *p, Symbol *t, Lextok *vis) /* user-defined types */
{ int oln = lineno;
Symbol *ofn = Fname;
Lextok *m, *n;
m = getuname(t);
for (n = p; n; n = n->rgt)
{ lineno = n->ln;
Fname = n->fn;
if (n->sym->type)
non_fatal("redeclaration of '%s'", n->sym->name);
if (n->sym->nbits > 0)
non_fatal("(%s) only an unsigned can have width-field",
n->sym->name);
if (Expand_Ok)
n->sym->hidden |= (4|8|16); /* formal par */
if (vis)
{ if (strncmp(vis->sym->name, ":hide:", 6) == 0)
n->sym->hidden |= 1;
else if (strncmp(vis->sym->name, ":show:", 6) == 0)
n->sym->hidden |= 2;
else if (strncmp(vis->sym->name, ":local:", 7) == 0)
n->sym->hidden |= 64;
}
n->sym->type = STRUCT; /* classification */
n->sym->Slst = m; /* structure itself */
n->sym->Snm = t; /* name of typedef */
n->sym->Nid = 0; /* this is no chan */
n->sym->hidden |= 4;
if (n->sym->nel <= 0)
non_fatal("bad array size for '%s'", n->sym->name);
}
lineno = oln;
Fname = ofn;
}
static Symbol *
do_same(Lextok *n, Symbol *v, int xinit)
{ Lextok *tmp, *fp, *tl;
int ix = eval(n->lft);
int oln = lineno;
Symbol *ofn = Fname;
lineno = n->ln;
Fname = n->fn;
/* n->sym->type == STRUCT
* index: n->lft
* subfields: n->rgt
* structure template: n->sym->Slst
* runtime values: n->sym->Sval
*/
if (xinit) ini_struct(v); /* once, at top level */
if (ix >= v->nel || ix < 0)
{ printf("spin: indexing %s[%d] - size is %d\n",
v->name, ix, v->nel);
fatal("indexing error \'%s\'", v->name);
}
if (!n->rgt || !n->rgt->lft)
{ non_fatal("no subfields %s", v->name); /* i.e., wants all */
lineno = oln; Fname = ofn;
return ZS;
}
if (n->rgt->ntyp != '.')
{ printf("bad subfield type %d\n", n->rgt->ntyp);
alldone(1);
}
tmp = n->rgt->lft;
if (tmp->ntyp != NAME && tmp->ntyp != TYPE)
{ printf("bad subfield entry %d\n", tmp->ntyp);
alldone(1);
}
for (fp = v->Sval[ix]; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt)
if (!strcmp(tl->sym->name, tmp->sym->name))
{ lineno = oln; Fname = ofn;
return tl->sym;
}
fatal("cannot locate subfield %s", tmp->sym->name);
return ZS;
}
int
Rval_struct(Lextok *n, Symbol *v, int xinit) /* n varref, v valref */
{ Symbol *tl;
Lextok *tmp;
int ix;
if (!n || !(tl = do_same(n, v, xinit)))
return 0;
tmp = n->rgt->lft;
if (tmp->sym->type == STRUCT)
{ return Rval_struct(tmp, tl, 0);
} else if (tmp->rgt)
fatal("non-zero 'rgt' on non-structure", 0);
ix = eval(tmp->lft);
if (ix >= tl->nel || ix < 0)
fatal("indexing error \'%s\'", tl->name);
return cast_val(tl->type, tl->val[ix], tl->nbits);
}
int
Lval_struct(Lextok *n, Symbol *v, int xinit, int a) /* a = assigned value */
{ Symbol *tl;
Lextok *tmp;
int ix;
if (!(tl = do_same(n, v, xinit)))
return 1;
tmp = n->rgt->lft;
if (tmp->sym->type == STRUCT)
return Lval_struct(tmp, tl, 0, a);
else if (tmp->rgt)
fatal("non-zero 'rgt' on non-structure", 0);
ix = eval(tmp->lft);
if (ix >= tl->nel || ix < 0)
fatal("indexing error \'%s\'", tl->name);
if (tl->nbits > 0)
a = (a & ((1<<tl->nbits)-1));
tl->val[ix] = a;
tl->setat = depth;
return 1;
}
int
Cnt_flds(Lextok *m)
{ Lextok *fp, *tl, *n;
int cnt = 0;
if (m->ntyp == ',')
{ n = m;
goto is_lst;
}
if (!m->sym || m->ntyp != STRUCT)
return 1;
n = getuname(m->sym);
is_lst:
for (fp = n; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt)
{ if (tl->sym->type == STRUCT)
{ if (tl->sym->nel != 1)
fatal("array of structures in param list, %s",
tl->sym->name);
cnt += Cnt_flds(tl->sym->Slst);
} else
cnt += tl->sym->nel;
}
return cnt;
}
int
Sym_typ(Lextok *t)
{ Symbol *s = t->sym;
if (!s) return 0;
if (s->type != STRUCT)
return s->type;
if (!t->rgt
|| !t->rgt->ntyp == '.'
|| !t->rgt->lft)
return STRUCT; /* not a field reference */
return Sym_typ(t->rgt->lft);
}
int
Width_set(int *wdth, int i, Lextok *n)
{ Lextok *fp, *tl;
int j = i, k;
for (fp = n; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt)
{ if (tl->sym->type == STRUCT)
j = Width_set(wdth, j, tl->sym->Slst);
else
{ for (k = 0; k < tl->sym->nel; k++, j++)
wdth[j] = tl->sym->type;
} }
return j;
}
void
ini_struct(Symbol *s)
{ int i; Lextok *fp, *tl;
if (s->type != STRUCT) /* last step */
{ (void) checkvar(s, 0);
return;
}
if (s->Sval == (Lextok **) 0)
{ s->Sval = (Lextok **) emalloc(s->nel * sizeof(Lextok *));
for (i = 0; i < s->nel; i++)
{ s->Sval[i] = cpnn(s->Slst, 1, 1, 1);
for (fp = s->Sval[i]; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt)
ini_struct(tl->sym);
} }
}
static Lextok *
cpnn(Lextok *s, int L, int R, int S)
{ Lextok *d; extern int Nid;
if (!s) return ZN;
d = (Lextok *) emalloc(sizeof(Lextok));
d->ntyp = s->ntyp;
d->val = s->val;
d->ln = s->ln;
d->fn = s->fn;
d->sym = s->sym;
if (L) d->lft = cpnn(s->lft, 1, 1, S);
if (R) d->rgt = cpnn(s->rgt, 1, 1, S);
if (S && s->sym)
{ d->sym = (Symbol *) emalloc(sizeof(Symbol));
memcpy(d->sym, s->sym, sizeof(Symbol));
if (d->sym->type == CHAN)
d->sym->Nid = ++Nid;
}
if (s->sq || s->sl)
fatal("cannot happen cpnn", (char *) 0);
return d;
}
int
full_name(FILE *fd, Lextok *n, Symbol *v, int xinit)
{ Symbol *tl;
Lextok *tmp;
int hiddenarrays = 0;
fprintf(fd, "%s", v->name);
if (!n || !(tl = do_same(n, v, xinit)))
return 0;
tmp = n->rgt->lft;
if (tmp->sym->type == STRUCT)
{ fprintf(fd, ".");
hiddenarrays = full_name(fd, tmp, tl, 0);
goto out;
}
fprintf(fd, ".%s", tl->name);
out: if (tmp->sym->nel > 1)
{ fprintf(fd, "[%d]", eval(tmp->lft));
hiddenarrays = 1;
}
return hiddenarrays;
}
void
validref(Lextok *p, Lextok *c)
{ Lextok *fp, *tl;
char lbuf[512];
for (fp = p->sym->Slst; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt)
if (strcmp(tl->sym->name, c->sym->name) == 0)
return;
sprintf(lbuf, "no field '%s' defined in structure '%s'\n",
c->sym->name, p->sym->name);
non_fatal(lbuf, (char *) 0);
}
void
struct_name(Lextok *n, Symbol *v, int xinit, char *buf)
{ Symbol *tl;
Lextok *tmp;
char lbuf[512];
if (!n || !(tl = do_same(n, v, xinit)))
return;
tmp = n->rgt->lft;
if (tmp->sym->type == STRUCT)
{ strcat(buf, ".");
struct_name(tmp, tl, 0, buf);
return;
}
sprintf(lbuf, ".%s", tl->name);
strcat(buf, lbuf);
if (tmp->sym->nel > 1)
{ sprintf(lbuf, "[%d]", eval(tmp->lft));
strcat(buf, lbuf);
}
}
void
walk2_struct(char *s, Symbol *z)
{ Lextok *fp, *tl;
char eprefix[128];
int ix;
extern void Done_case(char *, Symbol *);
ini_struct(z);
if (z->nel == 1)
sprintf(eprefix, "%s%s.", s, z->name);
for (ix = 0; ix < z->nel; ix++)
{ if (z->nel > 1)
sprintf(eprefix, "%s%s[%d].", s, z->name, ix);
for (fp = z->Sval[ix]; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt)
{ if (tl->sym->type == STRUCT)
walk2_struct(eprefix, tl->sym);
else if (tl->sym->type == CHAN)
Done_case(eprefix, tl->sym);
} }
}
void
walk_struct(FILE *ofd, int dowhat, char *s, Symbol *z, char *a, char *b, char *c)
{ Lextok *fp, *tl;
char eprefix[128];
int ix;
ini_struct(z);
if (z->nel == 1)
sprintf(eprefix, "%s%s.", s, z->name);
for (ix = 0; ix < z->nel; ix++)
{ if (z->nel > 1)
sprintf(eprefix, "%s%s[%d].", s, z->name, ix);
for (fp = z->Sval[ix]; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt)
{ if (tl->sym->type == STRUCT)
walk_struct(ofd, dowhat, eprefix, tl->sym, a,b,c);
else
do_var(ofd, dowhat, eprefix, tl->sym, a,b,c);
} }
}
void
c_struct(FILE *fd, char *ipref, Symbol *z)
{ Lextok *fp, *tl;
char pref[256], eprefix[256];
int ix;
ini_struct(z);
for (ix = 0; ix < z->nel; ix++)
for (fp = z->Sval[ix]; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt)
{ strcpy(eprefix, ipref);
if (z->nel > 1)
{ /* insert index before last '.' */
eprefix[strlen(eprefix)-1] = '\0';
sprintf(pref, "[ %d ].", ix);
strcat(eprefix, pref);
}
if (tl->sym->type == STRUCT)
{ strcat(eprefix, tl->sym->name);
strcat(eprefix, ".");
c_struct(fd, eprefix, tl->sym);
} else
c_var(fd, eprefix, tl->sym);
}
}
void
dump_struct(Symbol *z, char *prefix, RunList *r)
{ Lextok *fp, *tl;
char eprefix[256];
int ix, jx;
ini_struct(z);
for (ix = 0; ix < z->nel; ix++)
{ if (z->nel > 1)
sprintf(eprefix, "%s[%d]", prefix, ix);
else
strcpy(eprefix, prefix);
for (fp = z->Sval[ix]; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt)
{ if (tl->sym->type == STRUCT)
{ char pref[256];
strcpy(pref, eprefix);
strcat(pref, ".");
strcat(pref, tl->sym->name);
dump_struct(tl->sym, pref, r);
} else
for (jx = 0; jx < tl->sym->nel; jx++)
{ if (tl->sym->type == CHAN)
doq(tl->sym, jx, r);
else
{ printf("\t\t");
if (r)
printf("%s(%d):", r->n->name, r->pid);
printf("%s.%s", eprefix, tl->sym->name);
if (tl->sym->nel > 1)
printf("[%d]", jx);
printf(" = ");
sr_mesg(stdout, tl->sym->val[jx],
tl->sym->type == MTYPE);
printf("\n");
} } }
}
}
static int
retrieve(Lextok **targ, int i, int want, Lextok *n, int Ntyp)
{ Lextok *fp, *tl;
int j = i, k;
for (fp = n; fp; fp = fp->rgt)
for (tl = fp->lft; tl; tl = tl->rgt)
{ if (tl->sym->type == STRUCT)
{ j = retrieve(targ, j, want, tl->sym->Slst, Ntyp);
if (j < 0)
{ Lextok *x = cpnn(tl, 1, 0, 0);
x->rgt = nn(ZN, '.', (*targ), ZN);
(*targ) = x;
return -1;
}
} else
{ for (k = 0; k < tl->sym->nel; k++, j++)
{ if (j == want)
{ *targ = cpnn(tl, 1, 0, 0);
(*targ)->lft = nn(ZN, CONST, ZN, ZN);
(*targ)->lft->val = k;
if (Ntyp)
(*targ)->ntyp = (short) Ntyp;
return -1;
}
} } }
return j;
}
static int
is_explicit(Lextok *n)
{
if (!n) return 0;
if (!n->sym) fatal("unexpected - no symbol", 0);
if (n->sym->type != STRUCT) return 1;
if (!n->rgt) return 0;
if (n->rgt->ntyp != '.')
{ lineno = n->ln;
Fname = n->fn;
printf("ntyp %d\n", n->rgt->ntyp);
fatal("unexpected %s, no '.'", n->sym->name);
}
return is_explicit(n->rgt->lft);
}
Lextok *
expand(Lextok *n, int Ok)
/* turn rgt-lnked list of struct nms, into ',' list of flds */
{ Lextok *x = ZN, *y;
if (!Ok) return n;
while (n)
{ y = mk_explicit(n, 1, 0);
if (x)
(void) tail_add(x, y);
else
x = y;
n = n->rgt;
}
return x;
}
Lextok *
mk_explicit(Lextok *n, int Ok, int Ntyp)
/* produce a single ',' list of fields */
{ Lextok *bld = ZN, *x;
int i, cnt; extern int IArgs;
if (n->sym->type != STRUCT
|| is_explicit(n))
return n;
if (n->rgt
&& n->rgt->ntyp == '.'
&& n->rgt->lft
&& n->rgt->lft->sym
&& n->rgt->lft->sym->type == STRUCT)
{ Lextok *y;
bld = mk_explicit(n->rgt->lft, Ok, Ntyp);
for (x = bld; x; x = x->rgt)
{ y = cpnn(n, 1, 0, 0);
y->rgt = nn(ZN, '.', x->lft, ZN);
x->lft = y;
}
return bld;
}
if (!Ok || !n->sym->Slst)
{ if (IArgs) return n;
printf("spin: saw '");
comment(stdout, n, 0);
printf("'\n");
fatal("incomplete structure ref '%s'", n->sym->name);
}
cnt = Cnt_flds(n->sym->Slst);
for (i = cnt-1; i >= 0; i--)
{ bld = nn(ZN, ',', ZN, bld);
if (retrieve(&(bld->lft), 0, i, n->sym->Slst, Ntyp) >= 0)
{ printf("cannot retrieve field %d\n", i);
fatal("bad structure %s", n->sym->name);
}
x = cpnn(n, 1, 0, 0);
x->rgt = nn(ZN, '.', bld->lft, ZN);
bld->lft = x;
}
return bld;
}
Lextok *
tail_add(Lextok *a, Lextok *b)
{ Lextok *t;
for (t = a; t->rgt; t = t->rgt)
if (t->ntyp != ',')
fatal("unexpected type - tail_add", 0);
t->rgt = b;
return a;
}
void
setpname(Lextok *n)
{ UType *tmp;
for (tmp = Pnames; tmp; tmp = tmp->nxt)
if (!strcmp(n->sym->name, tmp->nm->name))
{ non_fatal("proctype %s redefined",
n->sym->name);
return;
}
tmp = (UType *) emalloc(sizeof(UType));
tmp->nm = n->sym;
tmp->nxt = Pnames;
Pnames = tmp;
}
int
isproctype(char *t)
{ UType *tmp;
for (tmp = Pnames; tmp; tmp = tmp->nxt)
{ if (!strcmp(t, tmp->nm->name))
return 1;
}
return 0;
}
|