1 /***** spin: structs.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 typedef struct UType {
16 Symbol *nm; /* name of the type */
17 Lextok *cn; /* contents */
18 struct UType *nxt; /* linked list */
19 } UType;
20
21 extern Symbol *Fname;
22 extern int lineno, depth, Expand_Ok, has_hidden, in_for;
23
24 Symbol *owner;
25
26 static UType *Unames = 0;
27 static UType *Pnames = 0;
28
29 static Lextok *cpnn(Lextok *, int, int, int);
30 extern void sr_mesg(FILE *, int, int);
31
32 void
setuname(Lextok * n)33 setuname(Lextok *n)
34 { UType *tmp;
35
36 if (!owner)
37 fatal("illegal reference inside typedef", (char *) 0);
38
39 for (tmp = Unames; tmp; tmp = tmp->nxt)
40 if (!strcmp(owner->name, tmp->nm->name))
41 { non_fatal("typename %s was defined before",
42 tmp->nm->name);
43 return;
44 }
45
46 tmp = (UType *) emalloc(sizeof(UType));
47 tmp->nm = owner;
48 tmp->cn = n;
49 tmp->nxt = Unames;
50 Unames = tmp;
51 }
52
53 static void
putUname(FILE * fd,UType * tmp)54 putUname(FILE *fd, UType *tmp)
55 { Lextok *fp, *tl;
56
57 if (!tmp) return;
58 putUname(fd, tmp->nxt); /* postorder */
59 fprintf(fd, "struct %s { /* user defined type */\n",
60 tmp->nm->name);
61 for (fp = tmp->cn; fp; fp = fp->rgt)
62 for (tl = fp->lft; tl; tl = tl->rgt)
63 typ2c(tl->sym);
64 fprintf(fd, "};\n");
65 }
66
67 void
putunames(FILE * fd)68 putunames(FILE *fd)
69 {
70 putUname(fd, Unames);
71 }
72
73 int
isutype(char * t)74 isutype(char *t)
75 { UType *tmp;
76
77 for (tmp = Unames; tmp; tmp = tmp->nxt)
78 { if (!strcmp(t, tmp->nm->name))
79 return 1;
80 }
81 return 0;
82 }
83
84 Lextok *
getuname(Symbol * t)85 getuname(Symbol *t)
86 { UType *tmp;
87
88 for (tmp = Unames; tmp; tmp = tmp->nxt)
89 { if (!strcmp(t->name, tmp->nm->name))
90 return tmp->cn;
91 }
92 fatal("%s is not a typename", t->name);
93 return (Lextok *)0;
94 }
95
96 void
setutype(Lextok * p,Symbol * t,Lextok * vis)97 setutype(Lextok *p, Symbol *t, Lextok *vis) /* user-defined types */
98 { int oln = lineno;
99 Symbol *ofn = Fname;
100 Lextok *m, *n;
101
102 m = getuname(t);
103 for (n = p; n; n = n->rgt)
104 { lineno = n->ln;
105 Fname = n->fn;
106 if (n->sym->type)
107 fatal("redeclaration of '%s'", n->sym->name);
108
109 if (n->sym->nbits > 0)
110 non_fatal("(%s) only an unsigned can have width-field",
111 n->sym->name);
112
113 if (Expand_Ok)
114 n->sym->hidden |= (4|8|16); /* formal par */
115
116 if (vis)
117 { if (strncmp(vis->sym->name, ":hide:", (size_t) 6) == 0)
118 { n->sym->hidden |= 1;
119 has_hidden++;
120 } else if (strncmp(vis->sym->name, ":show:", (size_t) 6) == 0)
121 n->sym->hidden |= 2;
122 else if (strncmp(vis->sym->name, ":local:", (size_t) 7) == 0)
123 n->sym->hidden |= 64;
124 }
125 n->sym->type = STRUCT; /* classification */
126 n->sym->Slst = m; /* structure itself */
127 n->sym->Snm = t; /* name of typedef */
128 n->sym->Nid = 0; /* this is no chan */
129 n->sym->hidden |= 4;
130 if (n->sym->nel <= 0)
131 non_fatal("bad array size for '%s'", n->sym->name);
132 }
133 lineno = oln;
134 Fname = ofn;
135 }
136
137 static Symbol *
do_same(Lextok * n,Symbol * v,int xinit)138 do_same(Lextok *n, Symbol *v, int xinit)
139 { Lextok *tmp, *fp, *tl;
140 int ix = eval(n->lft);
141 int oln = lineno;
142 Symbol *ofn = Fname;
143
144 lineno = n->ln;
145 Fname = n->fn;
146
147 /* n->sym->type == STRUCT
148 * index: n->lft
149 * subfields: n->rgt
150 * structure template: n->sym->Slst
151 * runtime values: n->sym->Sval
152 */
153 if (xinit) ini_struct(v); /* once, at top level */
154
155 if (ix >= v->nel || ix < 0)
156 { printf("spin: indexing %s[%d] - size is %d\n",
157 v->name, ix, v->nel);
158 fatal("indexing error \'%s\'", v->name);
159 }
160 if (!n->rgt || !n->rgt->lft)
161 { non_fatal("no subfields %s", v->name); /* i.e., wants all */
162 lineno = oln; Fname = ofn;
163 return ZS;
164 }
165
166 if (n->rgt->ntyp != '.')
167 { printf("bad subfield type %d\n", n->rgt->ntyp);
168 alldone(1);
169 }
170
171 tmp = n->rgt->lft;
172 if (tmp->ntyp != NAME && tmp->ntyp != TYPE)
173 { printf("bad subfield entry %d\n", tmp->ntyp);
174 alldone(1);
175 }
176 for (fp = v->Sval[ix]; fp; fp = fp->rgt)
177 for (tl = fp->lft; tl; tl = tl->rgt)
178 if (!strcmp(tl->sym->name, tmp->sym->name))
179 { lineno = oln; Fname = ofn;
180 return tl->sym;
181 }
182 fatal("cannot locate subfield %s", tmp->sym->name);
183 return ZS;
184 }
185
186 int
Rval_struct(Lextok * n,Symbol * v,int xinit)187 Rval_struct(Lextok *n, Symbol *v, int xinit) /* n varref, v valref */
188 { Symbol *tl;
189 Lextok *tmp;
190 int ix;
191
192 if (!n || !(tl = do_same(n, v, xinit)))
193 return 0;
194
195 tmp = n->rgt->lft;
196 if (tmp->sym->type == STRUCT)
197 { return Rval_struct(tmp, tl, 0);
198 } else if (tmp->rgt)
199 fatal("non-zero 'rgt' on non-structure", 0);
200
201 ix = eval(tmp->lft);
202 /* printf("%d: ix: %d (%d) %d\n", depth, ix, tl->nel, tl->val[ix]); */
203 if (ix >= tl->nel || ix < 0)
204 fatal("indexing error \'%s\'", tl->name);
205
206 return cast_val(tl->type, tl->val[ix], tl->nbits);
207 }
208
209 int
Lval_struct(Lextok * n,Symbol * v,int xinit,int a)210 Lval_struct(Lextok *n, Symbol *v, int xinit, int a) /* a = assigned value */
211 { Symbol *tl;
212 Lextok *tmp;
213 int ix;
214
215 if (!(tl = do_same(n, v, xinit)))
216 return 1;
217
218 tmp = n->rgt->lft;
219 if (tmp->sym->type == STRUCT)
220 return Lval_struct(tmp, tl, 0, a);
221 else if (tmp->rgt)
222 fatal("non-zero 'rgt' on non-structure", 0);
223
224 ix = eval(tmp->lft);
225 if (ix >= tl->nel || ix < 0)
226 fatal("indexing error \'%s\'", tl->name);
227
228 if (tl->nbits > 0)
229 a = (a & ((1<<tl->nbits)-1));
230
231 if (a != tl->val[ix])
232 { tl->val[ix] = a;
233 tl->setat = depth;
234 }
235 return 1;
236 }
237
238 int
Cnt_flds(Lextok * m)239 Cnt_flds(Lextok *m)
240 { Lextok *fp, *tl, *n;
241 int cnt = 0;
242
243 if (m->ntyp == ',')
244 { n = m;
245 goto is_lst;
246 }
247 if (!m->sym || m->ntyp != STRUCT)
248 return 1;
249
250 n = getuname(m->sym);
251 is_lst:
252 for (fp = n; fp; fp = fp->rgt)
253 for (tl = fp->lft; tl; tl = tl->rgt)
254 { if (tl->sym->type == STRUCT)
255 { if (tl->sym->nel > 1 || tl->sym->isarray)
256 fatal("array of structures in param list, %s",
257 tl->sym->name);
258 cnt += Cnt_flds(tl->sym->Slst);
259 } else
260 cnt += tl->sym->nel;
261 }
262 return cnt;
263 }
264
265 int
Sym_typ(Lextok * t)266 Sym_typ(Lextok *t)
267 { Symbol *s = t->sym;
268
269 if (!s) return 0;
270
271 if (s->type != STRUCT)
272 return s->type;
273
274 if (!t->rgt
275 || t->rgt->ntyp != '.' /* gh: had ! in wrong place */
276 || !t->rgt->lft)
277 return STRUCT; /* not a field reference */
278
279 return Sym_typ(t->rgt->lft);
280 }
281
282 int
Width_set(int * wdth,int i,Lextok * n)283 Width_set(int *wdth, int i, Lextok *n)
284 { Lextok *fp, *tl;
285 int j = i, k;
286
287 for (fp = n; fp; fp = fp->rgt)
288 for (tl = fp->lft; tl; tl = tl->rgt)
289 { if (tl->sym->type == STRUCT)
290 j = Width_set(wdth, j, tl->sym->Slst);
291 else
292 { for (k = 0; k < tl->sym->nel; k++, j++)
293 wdth[j] = tl->sym->type;
294 } }
295 return j;
296 }
297
298 void
ini_struct(Symbol * s)299 ini_struct(Symbol *s)
300 { int i; Lextok *fp, *tl;
301
302 if (s->type != STRUCT) /* last step */
303 { (void) checkvar(s, 0);
304 return;
305 }
306 if (s->Sval == (Lextok **) 0)
307 { s->Sval = (Lextok **) emalloc(s->nel * sizeof(Lextok *));
308 for (i = 0; i < s->nel; i++)
309 { s->Sval[i] = cpnn(s->Slst, 1, 1, 1);
310
311 for (fp = s->Sval[i]; fp; fp = fp->rgt)
312 for (tl = fp->lft; tl; tl = tl->rgt)
313 ini_struct(tl->sym);
314 } }
315 }
316
317 static Lextok *
cpnn(Lextok * s,int L,int R,int S)318 cpnn(Lextok *s, int L, int R, int S)
319 { Lextok *d; extern int Nid;
320
321 if (!s) return ZN;
322
323 d = (Lextok *) emalloc(sizeof(Lextok));
324 d->uiid = s->uiid;
325 d->ntyp = s->ntyp;
326 d->val = s->val;
327 d->ln = s->ln;
328 d->fn = s->fn;
329 d->sym = s->sym;
330 if (L) d->lft = cpnn(s->lft, 1, 1, S);
331 if (R) d->rgt = cpnn(s->rgt, 1, 1, S);
332
333 if (S && s->sym)
334 { d->sym = (Symbol *) emalloc(sizeof(Symbol));
335 memcpy(d->sym, s->sym, sizeof(Symbol));
336 if (d->sym->type == CHAN)
337 d->sym->Nid = ++Nid;
338 }
339 if (s->sq || s->sl)
340 fatal("cannot happen cpnn", (char *) 0);
341
342 return d;
343 }
344
345 int
full_name(FILE * fd,Lextok * n,Symbol * v,int xinit)346 full_name(FILE *fd, Lextok *n, Symbol *v, int xinit)
347 { Symbol *tl;
348 Lextok *tmp;
349 int hiddenarrays = 0;
350
351 fprintf(fd, "%s", v->name);
352
353 if (!n || !(tl = do_same(n, v, xinit)))
354 return 0;
355 tmp = n->rgt->lft;
356
357 if (tmp->sym->type == STRUCT)
358 { fprintf(fd, ".");
359 hiddenarrays = full_name(fd, tmp, tl, 0);
360 goto out;
361 }
362 fprintf(fd, ".%s", tl->name);
363 out: if (tmp->sym->nel > 1 || tmp->sym->isarray == 1)
364 { fprintf(fd, "[%d]", eval(tmp->lft));
365 hiddenarrays = 1;
366 }
367 return hiddenarrays;
368 }
369
370 void
validref(Lextok * p,Lextok * c)371 validref(Lextok *p, Lextok *c)
372 { Lextok *fp, *tl;
373 char lbuf[512];
374
375 for (fp = p->sym->Slst; fp; fp = fp->rgt)
376 for (tl = fp->lft; tl; tl = tl->rgt)
377 if (strcmp(tl->sym->name, c->sym->name) == 0)
378 return;
379
380 sprintf(lbuf, "no field '%s' defined in structure '%s'\n",
381 c->sym->name, p->sym->name);
382 non_fatal(lbuf, (char *) 0);
383 }
384
385 void
struct_name(Lextok * n,Symbol * v,int xinit,char * buf)386 struct_name(Lextok *n, Symbol *v, int xinit, char *buf)
387 { Symbol *tl;
388 Lextok *tmp;
389 char lbuf[512];
390
391 if (!n || !(tl = do_same(n, v, xinit)))
392 return;
393 tmp = n->rgt->lft;
394 if (tmp->sym->type == STRUCT)
395 { strcat(buf, ".");
396 struct_name(tmp, tl, 0, buf);
397 return;
398 }
399 sprintf(lbuf, ".%s", tl->name);
400 strcat(buf, lbuf);
401 if (tmp->sym->nel > 1 || tmp->sym->isarray == 1)
402 { sprintf(lbuf, "[%d]", eval(tmp->lft));
403 strcat(buf, lbuf);
404 }
405 }
406
407 void
walk2_struct(char * s,Symbol * z)408 walk2_struct(char *s, Symbol *z)
409 { Lextok *fp, *tl;
410 char eprefix[128];
411 int ix;
412 extern void Done_case(char *, Symbol *);
413
414 ini_struct(z);
415 if (z->nel == 1 && z->isarray == 0)
416 sprintf(eprefix, "%s%s.", s, z->name);
417 for (ix = 0; ix < z->nel; ix++)
418 { if (z->nel > 1 || z->isarray == 1)
419 sprintf(eprefix, "%s%s[%d].", s, z->name, ix);
420 for (fp = z->Sval[ix]; fp; fp = fp->rgt)
421 for (tl = fp->lft; tl; tl = tl->rgt)
422 { if (tl->sym->type == STRUCT)
423 walk2_struct(eprefix, tl->sym);
424 else if (tl->sym->type == CHAN)
425 Done_case(eprefix, tl->sym);
426 } }
427 }
428
429 void
walk_struct(FILE * ofd,int dowhat,char * s,Symbol * z,char * a,char * b,char * c)430 walk_struct(FILE *ofd, int dowhat, char *s, Symbol *z, char *a, char *b, char *c)
431 { Lextok *fp, *tl;
432 char eprefix[128];
433 int ix;
434
435 ini_struct(z);
436 if (z->nel == 1 && z->isarray == 0)
437 sprintf(eprefix, "%s%s.", s, z->name);
438 for (ix = 0; ix < z->nel; ix++)
439 { if (z->nel > 1 || z->isarray == 1)
440 sprintf(eprefix, "%s%s[%d].", s, z->name, ix);
441 for (fp = z->Sval[ix]; fp; fp = fp->rgt)
442 for (tl = fp->lft; tl; tl = tl->rgt)
443 { if (tl->sym->type == STRUCT)
444 walk_struct(ofd, dowhat, eprefix, tl->sym, a,b,c);
445 else
446 do_var(ofd, dowhat, eprefix, tl->sym, a,b,c);
447 } }
448 }
449
450 void
c_struct(FILE * fd,char * ipref,Symbol * z)451 c_struct(FILE *fd, char *ipref, Symbol *z)
452 { Lextok *fp, *tl;
453 char pref[256], eprefix[300];
454 int ix;
455
456 ini_struct(z);
457
458 for (ix = 0; ix < z->nel; ix++)
459 for (fp = z->Sval[ix]; fp; fp = fp->rgt)
460 for (tl = fp->lft; tl; tl = tl->rgt)
461 { strcpy(eprefix, ipref);
462 if (z->nel > 1 || z->isarray == 1)
463 { /* insert index before last '.' */
464 eprefix[strlen(eprefix)-1] = '\0';
465 sprintf(pref, "[ %d ].", ix);
466 strcat(eprefix, pref);
467 }
468 if (tl->sym->type == STRUCT)
469 { strcat(eprefix, tl->sym->name);
470 strcat(eprefix, ".");
471 c_struct(fd, eprefix, tl->sym);
472 } else
473 c_var(fd, eprefix, tl->sym);
474 }
475 }
476
477 void
dump_struct(Symbol * z,char * prefix,RunList * r)478 dump_struct(Symbol *z, char *prefix, RunList *r)
479 { Lextok *fp, *tl;
480 char eprefix[256];
481 int ix, jx;
482
483 ini_struct(z);
484
485 for (ix = 0; ix < z->nel; ix++)
486 { if (z->nel > 1 || z->isarray == 1)
487 sprintf(eprefix, "%s[%d]", prefix, ix);
488 else
489 strcpy(eprefix, prefix);
490
491 for (fp = z->Sval[ix]; fp; fp = fp->rgt)
492 for (tl = fp->lft; tl; tl = tl->rgt)
493 { if (tl->sym->type == STRUCT)
494 { char pref[300];
495 strcpy(pref, eprefix);
496 strcat(pref, ".");
497 strcat(pref, tl->sym->name);
498 dump_struct(tl->sym, pref, r);
499 } else
500 for (jx = 0; jx < tl->sym->nel; jx++)
501 { if (tl->sym->type == CHAN)
502 doq(tl->sym, jx, r);
503 else
504 { printf("\t\t");
505 if (r)
506 printf("%s(%d):", r->n->name, r->pid);
507 printf("%s.%s", eprefix, tl->sym->name);
508 if (tl->sym->nel > 1 || tl->sym->isarray == 1)
509 printf("[%d]", jx);
510 printf(" = ");
511 sr_mesg(stdout, tl->sym->val[jx],
512 tl->sym->type == MTYPE);
513 printf("\n");
514 } } }
515 }
516 }
517
518 static int
retrieve(Lextok ** targ,int i,int want,Lextok * n,int Ntyp)519 retrieve(Lextok **targ, int i, int want, Lextok *n, int Ntyp)
520 { Lextok *fp, *tl;
521 int j = i, k;
522
523 for (fp = n; fp; fp = fp->rgt)
524 for (tl = fp->lft; tl; tl = tl->rgt)
525 { if (tl->sym->type == STRUCT)
526 { j = retrieve(targ, j, want, tl->sym->Slst, Ntyp);
527 if (j < 0)
528 { Lextok *x = cpnn(tl, 1, 0, 0);
529 x->rgt = nn(ZN, '.', (*targ), ZN);
530 (*targ) = x;
531 return -1;
532 }
533 } else
534 { for (k = 0; k < tl->sym->nel; k++, j++)
535 { if (j == want)
536 { *targ = cpnn(tl, 1, 0, 0);
537 (*targ)->lft = nn(ZN, CONST, ZN, ZN);
538 (*targ)->lft->val = k;
539 if (Ntyp)
540 (*targ)->ntyp = (short) Ntyp;
541 return -1;
542 }
543 } } }
544 return j;
545 }
546
547 static int
is_explicit(Lextok * n)548 is_explicit(Lextok *n)
549 {
550 if (!n) return 0;
551 if (!n->sym) fatal("unexpected - no symbol", 0);
552 if (n->sym->type != STRUCT) return 1;
553 if (!n->rgt) return 0;
554 if (n->rgt->ntyp != '.')
555 { lineno = n->ln;
556 Fname = n->fn;
557 printf("ntyp %d\n", n->rgt->ntyp);
558 fatal("unexpected %s, no '.'", n->sym->name);
559 }
560 return is_explicit(n->rgt->lft);
561 }
562
563 Lextok *
expand(Lextok * n,int Ok)564 expand(Lextok *n, int Ok)
565 /* turn rgt-lnked list of struct nms, into ',' list of flds */
566 { Lextok *x = ZN, *y;
567
568 if (!Ok) return n;
569
570 while (n)
571 { y = mk_explicit(n, 1, 0);
572 if (x)
573 (void) tail_add(x, y);
574 else
575 x = y;
576
577 n = n->rgt;
578 }
579 return x;
580 }
581
582 Lextok *
mk_explicit(Lextok * n,int Ok,int Ntyp)583 mk_explicit(Lextok *n, int Ok, int Ntyp)
584 /* produce a single ',' list of fields */
585 { Lextok *bld = ZN, *x;
586 int i, cnt; extern int IArgs;
587
588 if (n->sym->type != STRUCT
589 || in_for
590 || is_explicit(n))
591 return n;
592
593
594 if (n->rgt
595 && n->rgt->ntyp == '.'
596 && n->rgt->lft
597 && n->rgt->lft->sym
598 && n->rgt->lft->sym->type == STRUCT)
599 { Lextok *y;
600 bld = mk_explicit(n->rgt->lft, Ok, Ntyp);
601 for (x = bld; x; x = x->rgt)
602 { y = cpnn(n, 1, 0, 0);
603 y->rgt = nn(ZN, '.', x->lft, ZN);
604 x->lft = y;
605 }
606
607 return bld;
608 }
609
610 if (!Ok || !n->sym->Slst)
611 { if (IArgs) return n;
612 printf("spin: saw '");
613 comment(stdout, n, 0);
614 printf("'\n");
615 fatal("incomplete structure ref '%s'", n->sym->name);
616 }
617
618 cnt = Cnt_flds(n->sym->Slst);
619 for (i = cnt-1; i >= 0; i--)
620 { bld = nn(ZN, ',', ZN, bld);
621 if (retrieve(&(bld->lft), 0, i, n->sym->Slst, Ntyp) >= 0)
622 { printf("cannot retrieve field %d\n", i);
623 fatal("bad structure %s", n->sym->name);
624 }
625 x = cpnn(n, 1, 0, 0);
626 x->rgt = nn(ZN, '.', bld->lft, ZN);
627 bld->lft = x;
628 }
629 return bld;
630 }
631
632 Lextok *
tail_add(Lextok * a,Lextok * b)633 tail_add(Lextok *a, Lextok *b)
634 { Lextok *t;
635
636 for (t = a; t->rgt; t = t->rgt)
637 if (t->ntyp != ',')
638 fatal("unexpected type - tail_add", 0);
639 t->rgt = b;
640 return a;
641 }
642
643 void
setpname(Lextok * n)644 setpname(Lextok *n)
645 { UType *tmp;
646
647 for (tmp = Pnames; tmp; tmp = tmp->nxt)
648 if (!strcmp(n->sym->name, tmp->nm->name))
649 { non_fatal("proctype %s redefined",
650 n->sym->name);
651 return;
652 }
653 tmp = (UType *) emalloc(sizeof(UType));
654 tmp->nm = n->sym;
655 tmp->nxt = Pnames;
656 Pnames = tmp;
657 }
658
659 int
isproctype(char * t)660 isproctype(char *t)
661 { UType *tmp;
662
663 for (tmp = Pnames; tmp; tmp = tmp->nxt)
664 { if (!strcmp(t, tmp->nm->name))
665 return 1;
666 }
667 return 0;
668 }
669