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