]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/spin/sym.c
Import sources from 2011-03-30 iso image
[plan9front.git] / sys / src / cmd / spin / sym.c
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 }