1 /***** spin: sym.c *****/ 2 3 /* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ 4 /* All Rights Reserved. This software is for educational purposes only. */ 5 /* No guarantee whatsoever is expressed or implied by the distribution of */ 6 /* this code. Permission is given to distribute this code provided that */ 7 /* this introductory message is not removed and no monies are exchanged. */ 8 /* Software written by Gerard J. Holzmann. For tool documentation see: */ 9 /* http://spinroot.com/ */ 10 /* Send all bug-reports and/or questions to: bugs@spinroot.com */ 11 12 #include "spin.h" 13 #include "y.tab.h" 14 15 extern Symbol *Fname, *owner; 16 extern int lineno, depth, verbose, NamesNotAdded, deadvar; 17 extern short has_xu; 18 19 Symbol *context = ZS; 20 Ordered *all_names = (Ordered *)0; 21 int Nid = 0; 22 23 static Ordered *last_name = (Ordered *)0; 24 static Symbol *symtab[Nhash+1]; 25 26 static int 27 samename(Symbol *a, Symbol *b) 28 { 29 if (!a && !b) return 1; 30 if (!a || !b) return 0; 31 return !strcmp(a->name, b->name); 32 } 33 34 int 35 hash(char *s) 36 { int h=0; 37 38 while (*s) 39 { h += *s++; 40 h <<= 1; 41 if (h&(Nhash+1)) 42 h |= 1; 43 } 44 return h&Nhash; 45 } 46 47 Symbol * 48 lookup(char *s) 49 { Symbol *sp; Ordered *no; 50 int h = hash(s); 51 52 for (sp = symtab[h]; sp; sp = sp->next) 53 if (strcmp(sp->name, s) == 0 54 && samename(sp->context, context) 55 && samename(sp->owner, owner)) 56 return sp; /* found */ 57 58 if (context) /* in proctype */ 59 for (sp = symtab[h]; sp; sp = sp->next) 60 if (strcmp(sp->name, s) == 0 61 && !sp->context 62 && samename(sp->owner, owner)) 63 return sp; /* global */ 64 65 sp = (Symbol *) emalloc(sizeof(Symbol)); 66 sp->name = (char *) emalloc((int) strlen(s) + 1); 67 strcpy(sp->name, s); 68 sp->nel = 1; 69 sp->setat = depth; 70 sp->context = context; 71 sp->owner = owner; /* if fld in struct */ 72 73 if (NamesNotAdded == 0) 74 { sp->next = symtab[h]; 75 symtab[h] = sp; 76 no = (Ordered *) emalloc(sizeof(Ordered)); 77 no->entry = sp; 78 if (!last_name) 79 last_name = all_names = no; 80 else 81 { last_name->next = no; 82 last_name = no; 83 } } 84 85 return sp; 86 } 87 88 void 89 trackvar(Lextok *n, Lextok *m) 90 { Symbol *sp = n->sym; 91 92 if (!sp) return; /* a structure list */ 93 switch (m->ntyp) { 94 case NAME: 95 if (m->sym->type != BIT) 96 { sp->hidden |= 4; 97 if (m->sym->type != BYTE) 98 sp->hidden |= 8; 99 } 100 break; 101 case CONST: 102 if (m->val != 0 && m->val != 1) 103 sp->hidden |= 4; 104 if (m->val < 0 || m->val > 256) 105 sp->hidden |= 8; /* ditto byte-equiv */ 106 break; 107 default: /* unknown */ 108 sp->hidden |= (4|8); /* not known bit-equiv */ 109 } 110 } 111 112 Lextok *runstmnts = ZN; 113 114 void 115 trackrun(Lextok *n) 116 { 117 runstmnts = nn(ZN, 0, n, runstmnts); 118 } 119 120 void 121 checkrun(Symbol *parnm, int posno) 122 { Lextok *n, *now, *v; int i, m; 123 int res = 0; char buf[16], buf2[16]; 124 125 for (n = runstmnts; n; n = n->rgt) 126 { now = n->lft; 127 if (now->sym != parnm->context) 128 continue; 129 for (v = now->lft, i = 0; v; v = v->rgt, i++) 130 if (i == posno) 131 { m = v->lft->ntyp; 132 if (m == CONST) 133 { m = v->lft->val; 134 if (m != 0 && m != 1) 135 res |= 4; 136 if (m < 0 || m > 256) 137 res |= 8; 138 } else if (m == NAME) 139 { m = v->lft->sym->type; 140 if (m != BIT) 141 { res |= 4; 142 if (m != BYTE) 143 res |= 8; 144 } 145 } else 146 res |= (4|8); /* unknown */ 147 break; 148 } } 149 if (!(res&4) || !(res&8)) 150 { if (!(verbose&32)) return; 151 strcpy(buf2, (!(res&4))?"bit":"byte"); 152 sputtype(buf, parnm->type); 153 i = (int) strlen(buf); 154 while (buf[--i] == ' ') buf[i] = '\0'; 155 if (strcmp(buf, buf2) == 0) return; 156 prehint(parnm); 157 printf("proctype %s, '%s %s' could be declared", 158 parnm->context->name, buf, parnm->name); 159 printf(" '%s %s'\n", buf2, parnm->name); 160 } 161 } 162 163 void 164 trackchanuse(Lextok *m, Lextok *w, int t) 165 { Lextok *n = m; int cnt = 1; 166 while (n) 167 { if (n->lft 168 && n->lft->sym 169 && n->lft->sym->type == CHAN) 170 setaccess(n->lft->sym, w?w->sym:ZS, cnt, t); 171 n = n->rgt; cnt++; 172 } 173 } 174 175 void 176 setptype(Lextok *n, int t, Lextok *vis) /* predefined types */ 177 { int oln = lineno, cnt = 1; extern int Expand_Ok; 178 179 while (n) 180 { if (n->sym->type && !(n->sym->hidden&32)) 181 { lineno = n->ln; Fname = n->fn; 182 non_fatal("redeclaration of '%s'", n->sym->name); 183 lineno = oln; 184 } 185 n->sym->type = (short) t; 186 187 if (Expand_Ok) 188 { n->sym->hidden |= (4|8|16); /* formal par */ 189 if (t == CHAN) 190 setaccess(n->sym, ZS, cnt, 'F'); 191 } 192 if (t == UNSIGNED) 193 { if (n->sym->nbits < 0 || n->sym->nbits >= 32) 194 fatal("(%s) has invalid width-field", n->sym->name); 195 if (n->sym->nbits == 0) 196 { n->sym->nbits = 16; 197 non_fatal("unsigned without width-field", 0); 198 } 199 } else if (n->sym->nbits > 0) 200 { non_fatal("(%s) only an unsigned can have width-field", 201 n->sym->name); 202 } 203 if (vis) 204 { if (strncmp(vis->sym->name, ":hide:", 6) == 0) 205 { n->sym->hidden |= 1; 206 if (t == BIT) 207 fatal("bit variable (%s) cannot be hidden", 208 n->sym->name); 209 } else if (strncmp(vis->sym->name, ":show:", 6) == 0) 210 { n->sym->hidden |= 2; 211 } else if (strncmp(vis->sym->name, ":local:", 7) == 0) 212 { n->sym->hidden |= 64; 213 } 214 } 215 if (t == CHAN) 216 n->sym->Nid = ++Nid; 217 else 218 { n->sym->Nid = 0; 219 if (n->sym->ini 220 && n->sym->ini->ntyp == CHAN) 221 { Fname = n->fn; 222 lineno = n->ln; 223 fatal("chan initializer for non-channel %s", 224 n->sym->name); 225 } 226 } 227 if (n->sym->nel <= 0) 228 { lineno = n->ln; Fname = n->fn; 229 non_fatal("bad array size for '%s'", n->sym->name); 230 lineno = oln; 231 } 232 n = n->rgt; cnt++; 233 } 234 } 235 236 static void 237 setonexu(Symbol *sp, int t) 238 { 239 sp->xu |= t; 240 if (t == XR || t == XS) 241 { if (sp->xup[t-1] 242 && strcmp(sp->xup[t-1]->name, context->name)) 243 { printf("error: x[rs] claims from %s and %s\n", 244 sp->xup[t-1]->name, context->name); 245 non_fatal("conflicting claims on chan '%s'", 246 sp->name); 247 } 248 sp->xup[t-1] = context; 249 } 250 } 251 252 static void 253 setallxu(Lextok *n, int t) 254 { Lextok *fp, *tl; 255 256 for (fp = n; fp; fp = fp->rgt) 257 for (tl = fp->lft; tl; tl = tl->rgt) 258 { if (tl->sym->type == STRUCT) 259 setallxu(tl->sym->Slst, t); 260 else if (tl->sym->type == CHAN) 261 setonexu(tl->sym, t); 262 } 263 } 264 265 Lextok *Xu_List = (Lextok *) 0; 266 267 void 268 setxus(Lextok *p, int t) 269 { Lextok *m, *n; 270 271 has_xu = 1; 272 if (!context) 273 { lineno = p->ln; 274 Fname = p->fn; 275 fatal("non-local x[rs] assertion", (char *)0); 276 } 277 for (m = p; m; m = m->rgt) 278 { Lextok *Xu_new = (Lextok *) emalloc(sizeof(Lextok)); 279 Xu_new->val = t; 280 Xu_new->lft = m->lft; 281 Xu_new->sym = context; 282 Xu_new->rgt = Xu_List; 283 Xu_List = Xu_new; 284 285 n = m->lft; 286 if (n->sym->type == STRUCT) 287 setallxu(n->sym->Slst, t); 288 else if (n->sym->type == CHAN) 289 setonexu(n->sym, t); 290 else 291 { int oln = lineno; 292 lineno = n->ln; Fname = n->fn; 293 non_fatal("xr or xs of non-chan '%s'", 294 n->sym->name); 295 lineno = oln; 296 } 297 } 298 } 299 300 Lextok *Mtype = (Lextok *) 0; 301 302 void 303 setmtype(Lextok *m) 304 { Lextok *n; 305 int cnt, oln = lineno; 306 307 if (m) { lineno = m->ln; Fname = m->fn; } 308 309 if (!Mtype) 310 Mtype = m; 311 else 312 { for (n = Mtype; n->rgt; n = n->rgt) 313 ; 314 n->rgt = m; /* concatenate */ 315 } 316 317 for (n = Mtype, cnt = 1; n; n = n->rgt, cnt++) /* syntax check */ 318 { if (!n->lft || !n->lft->sym 319 || n->lft->ntyp != NAME 320 || n->lft->lft) /* indexed variable */ 321 fatal("bad mtype definition", (char *)0); 322 323 /* label the name */ 324 if (n->lft->sym->type != MTYPE) 325 { n->lft->sym->hidden |= 128; /* is used */ 326 n->lft->sym->type = MTYPE; 327 n->lft->sym->ini = nn(ZN,CONST,ZN,ZN); 328 n->lft->sym->ini->val = cnt; 329 } else if (n->lft->sym->ini->val != cnt) 330 non_fatal("name %s appears twice in mtype declaration", 331 n->lft->sym->name); 332 } 333 lineno = oln; 334 if (cnt > 256) 335 fatal("too many mtype elements (>255)", (char *)0); 336 } 337 338 int 339 ismtype(char *str) /* name to number */ 340 { Lextok *n; 341 int cnt = 1; 342 343 for (n = Mtype; n; n = n->rgt) 344 { if (strcmp(str, n->lft->sym->name) == 0) 345 return cnt; 346 cnt++; 347 } 348 return 0; 349 } 350 351 int 352 sputtype(char *foo, int m) 353 { 354 switch (m) { 355 case UNSIGNED: strcpy(foo, "unsigned "); break; 356 case BIT: strcpy(foo, "bit "); break; 357 case BYTE: strcpy(foo, "byte "); break; 358 case CHAN: strcpy(foo, "chan "); break; 359 case SHORT: strcpy(foo, "short "); break; 360 case INT: strcpy(foo, "int "); break; 361 case MTYPE: strcpy(foo, "mtype "); break; 362 case STRUCT: strcpy(foo, "struct"); break; 363 case PROCTYPE: strcpy(foo, "proctype"); break; 364 case LABEL: strcpy(foo, "label "); return 0; 365 default: strcpy(foo, "value "); return 0; 366 } 367 return 1; 368 } 369 370 371 static int 372 puttype(int m) 373 { char buf[128]; 374 375 if (sputtype(buf, m)) 376 { printf("%s", buf); 377 return 1; 378 } 379 return 0; 380 } 381 382 void 383 symvar(Symbol *sp) 384 { Lextok *m; 385 386 if (!puttype(sp->type)) 387 return; 388 389 printf("\t"); 390 if (sp->owner) printf("%s.", sp->owner->name); 391 printf("%s", sp->name); 392 if (sp->nel > 1) printf("[%d]", sp->nel); 393 394 if (sp->type == CHAN) 395 printf("\t%d", (sp->ini)?sp->ini->val:0); 396 else if (sp->type == STRUCT) /* Frank Weil, 2.9.8 */ 397 printf("\t%s", sp->Snm->name); 398 else 399 printf("\t%d", eval(sp->ini)); 400 401 if (sp->owner) 402 printf("\t<:struct-field:>"); 403 else 404 if (!sp->context) 405 printf("\t<:global:>"); 406 else 407 printf("\t<%s>", sp->context->name); 408 409 if (sp->Nid < 0) /* formal parameter */ 410 printf("\t<parameter %d>", -(sp->Nid)); 411 else 412 printf("\t<variable>"); 413 if (sp->type == CHAN && sp->ini) 414 { int i; 415 for (m = sp->ini->rgt, i = 0; m; m = m->rgt) 416 i++; 417 printf("\t%d\t", i); 418 for (m = sp->ini->rgt; m; m = m->rgt) 419 { if (m->ntyp == STRUCT) 420 printf("struct %s", m->sym->name); 421 else 422 (void) puttype(m->ntyp); 423 if (m->rgt) printf("\t"); 424 } 425 } 426 printf("\n"); 427 } 428 429 void 430 symdump(void) 431 { Ordered *walk; 432 433 for (walk = all_names; walk; walk = walk->next) 434 symvar(walk->entry); 435 } 436 437 void 438 chname(Symbol *sp) 439 { printf("chan "); 440 if (sp->context) printf("%s-", sp->context->name); 441 if (sp->owner) printf("%s.", sp->owner->name); 442 printf("%s", sp->name); 443 if (sp->nel > 1) printf("[%d]", sp->nel); 444 printf("\t"); 445 } 446 447 448 static struct X { 449 int typ; char *nm; 450 } xx[] = { 451 { 'A', "exported as run parameter" }, 452 { 'F', "imported as proctype parameter" }, 453 { 'L', "used as l-value in asgnmnt" }, 454 { 'V', "used as r-value in asgnmnt" }, 455 { 'P', "polled in receive stmnt" }, 456 { 'R', "used as parameter in receive stmnt" }, 457 { 'S', "used as parameter in send stmnt" }, 458 { 'r', "received from" }, 459 { 's', "sent to" }, 460 }; 461 462 static void 463 chan_check(Symbol *sp) 464 { Access *a; int i, b=0, d; 465 466 if (verbose&1) goto report; /* -C -g */ 467 468 for (a = sp->access; a; a = a->lnk) 469 if (a->typ == 'r') 470 b |= 1; 471 else if (a->typ == 's') 472 b |= 2; 473 if (b == 3 || (sp->hidden&16)) /* balanced or formal par */ 474 return; 475 report: 476 chname(sp); 477 for (i = d = 0; i < (int) (sizeof(xx)/sizeof(struct X)); i++) 478 { b = 0; 479 for (a = sp->access; a; a = a->lnk) 480 if (a->typ == xx[i].typ) b++; 481 if (b == 0) continue; d++; 482 printf("\n\t%s by: ", xx[i].nm); 483 for (a = sp->access; a; a = a->lnk) 484 if (a->typ == xx[i].typ) 485 { printf("%s", a->who->name); 486 if (a->what) printf(" to %s", a->what->name); 487 if (a->cnt) printf(" par %d", a->cnt); 488 if (--b > 0) printf(", "); 489 } 490 } 491 printf("%s\n", (!d)?"\n\tnever used under this name":""); 492 } 493 494 void 495 chanaccess(void) 496 { Ordered *walk; 497 char buf[128]; 498 extern int Caccess, separate; 499 extern short has_code; 500 501 for (walk = all_names; walk; walk = walk->next) 502 { if (!walk->entry->owner) 503 switch (walk->entry->type) { 504 case CHAN: 505 if (Caccess) chan_check(walk->entry); 506 break; 507 case MTYPE: 508 case BIT: 509 case BYTE: 510 case SHORT: 511 case INT: 512 case UNSIGNED: 513 if ((walk->entry->hidden&128)) /* was: 32 */ 514 continue; 515 516 if (!separate 517 && !walk->entry->context 518 && !has_code 519 && deadvar) 520 walk->entry->hidden |= 1; /* auto-hide */ 521 522 if (!(verbose&32) || has_code) continue; 523 524 printf("spin: warning, %s, ", Fname->name); 525 sputtype(buf, walk->entry->type); 526 if (walk->entry->context) 527 printf("proctype %s", 528 walk->entry->context->name); 529 else 530 printf("global"); 531 printf(", '%s%s' variable is never used\n", 532 buf, walk->entry->name); 533 } } 534 } 535