/***** spin: sym.c *****/ /* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ /* No guarantee whatsoever is expressed or implied by the distribution of */ /* this code. Permission is given to distribute this code provided that */ /* this introductory message is not removed and no monies are exchanged. */ /* Software written by Gerard J. Holzmann. For tool documentation see: */ /* http://spinroot.com/ */ /* Send all bug-reports and/or questions to: bugs@spinroot.com */ #include "spin.h" #include "y.tab.h" extern Symbol *Fname, *owner; extern int lineno, depth, verbose, NamesNotAdded, deadvar; extern int has_hidden, m_loss, old_scope_rules; extern short has_xu; extern char CurScope[MAXSCOPESZ]; Symbol *context = ZS; Ordered *all_names = (Ordered *)0; int Nid = 0; Lextok *Mtype = (Lextok *) 0; static Ordered *last_name = (Ordered *)0; static Symbol *symtab[Nhash+1]; static Lextok *runstmnts = ZN; static int samename(Symbol *a, Symbol *b) { if (!a && !b) return 1; if (!a || !b) return 0; return !strcmp(a->name, b->name); } int hash(char *s) { int h=0; while (*s) { h += *s++; h <<= 1; if (h&(Nhash+1)) h |= 1; } return h&Nhash; } void disambiguate(void) { Ordered *walk; Symbol *sp; if (old_scope_rules) return; /* if the same name appears in two different scopes, 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) { char *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; /* discord the old memory */ } } } Symbol * lookup(char *s) { Symbol *sp; Ordered *no; int h = hash(s); if (old_scope_rules) { /* same scope - global refering to global or local to local */ for (sp = symtab[h]; sp; sp = sp->next) { if (strcmp(sp->name, s) == 0 && 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, refers to global */ for (sp = symtab[h]; sp; sp = sp->next) { if (strcmp(sp->name, s) == 0 && !sp->context && samename(sp->owner, owner)) { return sp; /* global */ } } sp = (Symbol *) emalloc(sizeof(Symbol)); sp->name = (char *) emalloc(strlen(s) + 1); strcpy(sp->name, s); sp->nel = 1; sp->setat = depth; sp->context = context; 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) { sp->next = symtab[h]; symtab[h] = sp; no = (Ordered *) emalloc(sizeof(Ordered)); no->entry = sp; if (!last_name) last_name = all_names = no; else { last_name->next = no; last_name = no; } } return sp; } void trackvar(Lextok *n, Lextok *m) { Symbol *sp = n->sym; if (!sp) return; /* a structure list */ switch (m->ntyp) { case NAME: if (m->sym->type != BIT) { sp->hidden |= 4; if (m->sym->type != BYTE) sp->hidden |= 8; } break; case CONST: if (m->val != 0 && m->val != 1) sp->hidden |= 4; if (m->val < 0 || m->val > 256) sp->hidden |= 8; /* ditto byte-equiv */ break; default: /* unknown */ sp->hidden |= (4|8); /* not known bit-equiv */ } } void trackrun(Lextok *n) { runstmnts = nn(ZN, 0, n, runstmnts); } void checkrun(Symbol *parnm, int posno) { Lextok *n, *now, *v; int i, m; int res = 0; char buf[16], buf2[16]; for (n = runstmnts; n; n = n->rgt) { now = n->lft; if (now->sym != parnm->context) continue; for (v = now->lft, i = 0; v; v = v->rgt, i++) if (i == posno) { m = v->lft->ntyp; if (m == CONST) { m = v->lft->val; if (m != 0 && m != 1) res |= 4; if (m < 0 || m > 256) res |= 8; } else if (m == NAME) { m = v->lft->sym->type; if (m != BIT) { res |= 4; if (m != BYTE) res |= 8; } } else res |= (4|8); /* unknown */ break; } } if (!(res&4) || !(res&8)) { if (!(verbose&32)) return; strcpy(buf2, (!(res&4))?"bit":"byte"); sputtype(buf, parnm->type); i = (int) strlen(buf); while (i > 0 && buf[--i] == ' ') buf[i] = '\0'; if (i == 0 || strcmp(buf, buf2) == 0) return; prehint(parnm); printf("proctype %s, '%s %s' could be declared", parnm->context?parnm->context->name:"", buf, parnm->name); printf(" '%s %s'\n", buf2, parnm->name); } } void trackchanuse(Lextok *m, Lextok *w, int t) { Lextok *n = m; int cnt = 1; while (n) { if (n->lft && n->lft->sym && n->lft->sym->type == CHAN) setaccess(n->lft->sym, w?w->sym:ZS, cnt, t); n = n->rgt; cnt++; } } void setptype(Lextok *n, int t, Lextok *vis) /* predefined types */ { int oln = lineno, cnt = 1; extern int Expand_Ok; while (n) { if (n->sym->type && !(n->sym->hidden&32)) { lineno = n->ln; Fname = n->fn; fatal("redeclaration of '%s'", n->sym->name); lineno = oln; } n->sym->type = (short) t; if (Expand_Ok) { n->sym->hidden |= (4|8|16); /* formal par */ if (t == CHAN) setaccess(n->sym, ZS, cnt, 'F'); } if (t == UNSIGNED) { if (n->sym->nbits < 0 || n->sym->nbits >= 32) fatal("(%s) has invalid width-field", n->sym->name); if (n->sym->nbits == 0) { n->sym->nbits = 16; non_fatal("unsigned without width-field", 0); } } else if (n->sym->nbits > 0) { non_fatal("(%s) only an unsigned can have width-field", n->sym->name); } if (vis) { if (strncmp(vis->sym->name, ":hide:", (size_t) 6) == 0) { n->sym->hidden |= 1; has_hidden++; if (t == BIT) fatal("bit variable (%s) cannot be hidden", n->sym->name); } else if (strncmp(vis->sym->name, ":show:", (size_t) 6) == 0) { n->sym->hidden |= 2; } else if (strncmp(vis->sym->name, ":local:", (size_t) 7) == 0) { n->sym->hidden |= 64; } } if (t == CHAN) n->sym->Nid = ++Nid; else { n->sym->Nid = 0; if (n->sym->ini && n->sym->ini->ntyp == CHAN) { Fname = n->fn; lineno = n->ln; fatal("chan initializer for non-channel %s", n->sym->name); } } if (n->sym->nel <= 0) { lineno = n->ln; Fname = n->fn; non_fatal("bad array size for '%s'", n->sym->name); lineno = oln; } n = n->rgt; cnt++; } } static void setonexu(Symbol *sp, int t) { sp->xu |= t; if (t == XR || t == XS) { if (sp->xup[t-1] && strcmp(sp->xup[t-1]->name, context->name)) { printf("error: x[rs] claims from %s and %s\n", sp->xup[t-1]->name, context->name); non_fatal("conflicting claims on chan '%s'", sp->name); } sp->xup[t-1] = context; } } static void setallxu(Lextok *n, int t) { Lextok *fp, *tl; for (fp = n; fp; fp = fp->rgt) for (tl = fp->lft; tl; tl = tl->rgt) { if (tl->sym->type == STRUCT) setallxu(tl->sym->Slst, t); else if (tl->sym->type == CHAN) setonexu(tl->sym, t); } } Lextok *Xu_List = (Lextok *) 0; void setxus(Lextok *p, int t) { Lextok *m, *n; has_xu = 1; if (m_loss && t == XS) { printf("spin: warning, %s:%d, xs tag not compatible with -m (message loss)\n", (p->fn != NULL) ? p->fn->name : "stdin", p->ln); } if (!context) { lineno = p->ln; Fname = p->fn; fatal("non-local x[rs] assertion", (char *)0); } for (m = p; m; m = m->rgt) { Lextok *Xu_new = (Lextok *) emalloc(sizeof(Lextok)); Xu_new->uiid = p->uiid; Xu_new->val = t; Xu_new->lft = m->lft; Xu_new->sym = context; Xu_new->rgt = Xu_List; Xu_List = Xu_new; n = m->lft; if (n->sym->type == STRUCT) setallxu(n->sym->Slst, t); else if (n->sym->type == CHAN) setonexu(n->sym, t); else { int oln = lineno; lineno = n->ln; Fname = n->fn; non_fatal("xr or xs of non-chan '%s'", n->sym->name); lineno = oln; } } } void setmtype(Lextok *m) { Lextok *n; int cnt, oln = lineno; if (m) { lineno = m->ln; Fname = m->fn; } if (!Mtype) Mtype = m; else { for (n = Mtype; n->rgt; n = n->rgt) ; n->rgt = m; /* concatenate */ } for (n = Mtype, cnt = 1; n; n = n->rgt, cnt++) /* syntax check */ { if (!n->lft || !n->lft->sym || n->lft->ntyp != NAME || n->lft->lft) /* indexed variable */ fatal("bad mtype definition", (char *)0); /* label the name */ if (n->lft->sym->type != MTYPE) { n->lft->sym->hidden |= 128; /* is used */ n->lft->sym->type = MTYPE; n->lft->sym->ini = nn(ZN,CONST,ZN,ZN); n->lft->sym->ini->val = cnt; } else if (n->lft->sym->ini->val != cnt) non_fatal("name %s appears twice in mtype declaration", n->lft->sym->name); } lineno = oln; if (cnt > 256) fatal("too many mtype elements (>255)", (char *)0); } int ismtype(char *str) /* name to number */ { Lextok *n; int cnt = 1; for (n = Mtype; n; n = n->rgt) { if (strcmp(str, n->lft->sym->name) == 0) return cnt; cnt++; } return 0; } int sputtype(char *foo, int m) { switch (m) { case UNSIGNED: strcpy(foo, "unsigned "); break; case BIT: strcpy(foo, "bit "); break; case BYTE: strcpy(foo, "byte "); break; case CHAN: strcpy(foo, "chan "); break; case SHORT: strcpy(foo, "short "); break; case INT: strcpy(foo, "int "); break; case MTYPE: strcpy(foo, "mtype "); break; case STRUCT: strcpy(foo, "struct"); break; case PROCTYPE: strcpy(foo, "proctype"); break; case LABEL: strcpy(foo, "label "); return 0; default: strcpy(foo, "value "); return 0; } return 1; } static int puttype(int m) { char buf[128]; if (sputtype(buf, m)) { printf("%s", buf); return 1; } return 0; } void symvar(Symbol *sp) { Lextok *m; if (!puttype(sp->type)) return; printf("\t"); if (sp->owner) printf("%s.", sp->owner->name); printf("%s", sp->name); if (sp->nel > 1 || sp->isarray == 1) printf("[%d]", sp->nel); if (sp->type == CHAN) printf("\t%d", (sp->ini)?sp->ini->val:0); else if (sp->type == STRUCT && sp->Snm != NULL) /* Frank Weil, 2.9.8 */ printf("\t%s", sp->Snm->name); else printf("\t%d", eval(sp->ini)); if (sp->owner) printf("\t<:struct-field:>"); else if (!sp->context) printf("\t<:global:>"); else printf("\t<%s>", sp->context->name); if (sp->Nid < 0) /* formal parameter */ printf("\t", -(sp->Nid)); else if (sp->type == MTYPE) printf("\t"); else if (sp->isarray) printf("\t"); else printf("\t"); if (sp->type == CHAN && sp->ini) { int i; for (m = sp->ini->rgt, i = 0; m; m = m->rgt) i++; printf("\t%d\t", i); for (m = sp->ini->rgt; m; m = m->rgt) { if (m->ntyp == STRUCT) printf("struct %s", m->sym->name); else (void) puttype(m->ntyp); if (m->rgt) printf("\t"); } } if (1) printf("\t{scope %s}", sp->bscp); printf("\n"); } void symdump(void) { Ordered *walk; for (walk = all_names; walk; walk = walk->next) symvar(walk->entry); } void chname(Symbol *sp) { printf("chan "); if (sp->context) printf("%s-", sp->context->name); if (sp->owner) printf("%s.", sp->owner->name); printf("%s", sp->name); if (sp->nel > 1 || sp->isarray == 1) printf("[%d]", sp->nel); printf("\t"); } static struct X { int typ; char *nm; } xx[] = { { 'A', "exported as run parameter" }, { 'F', "imported as proctype parameter" }, { 'L', "used as l-value in asgnmnt" }, { 'V', "used as r-value in asgnmnt" }, { 'P', "polled in receive stmnt" }, { 'R', "used as parameter in receive stmnt" }, { 'S', "used as parameter in send stmnt" }, { 'r', "received from" }, { 's', "sent to" }, }; static void chan_check(Symbol *sp) { Access *a; int i, b=0, d; if (verbose&1) goto report; /* -C -g */ for (a = sp->access; a; a = a->lnk) if (a->typ == 'r') b |= 1; else if (a->typ == 's') b |= 2; if (b == 3 || (sp->hidden&16)) /* balanced or formal par */ return; report: chname(sp); for (i = d = 0; i < (int) (sizeof(xx)/sizeof(struct X)); i++) { b = 0; for (a = sp->access; a; a = a->lnk) if (a->typ == xx[i].typ) b++; if (b == 0) continue; d++; printf("\n\t%s by: ", xx[i].nm); for (a = sp->access; a; a = a->lnk) if (a->typ == xx[i].typ) { printf("%s", a->who->name); if (a->what) printf(" to %s", a->what->name); if (a->cnt) printf(" par %d", a->cnt); if (--b > 0) printf(", "); } } printf("%s\n", (!d)?"\n\tnever used under this name":""); } void chanaccess(void) { Ordered *walk; char buf[128]; extern int Caccess, separate; extern short has_code; for (walk = all_names; walk; walk = walk->next) { if (!walk->entry->owner) switch (walk->entry->type) { case CHAN: if (Caccess) chan_check(walk->entry); break; case MTYPE: case BIT: case BYTE: case SHORT: case INT: case UNSIGNED: if ((walk->entry->hidden&128)) /* was: 32 */ continue; if (!separate && !walk->entry->context && !has_code && deadvar) walk->entry->hidden |= 1; /* auto-hide */ if (!(verbose&32) || has_code) continue; printf("spin: warning, %s, ", Fname->name); sputtype(buf, walk->entry->type); if (walk->entry->context) printf("proctype %s", walk->entry->context->name); else printf("global"); printf(", '%s%s' variable is never used\n", buf, walk->entry->name); } } }