xref: /plan9/sys/src/cmd/spin/sym.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
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