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