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