xref: /plan9/sys/src/cmd/spin/mesg.c (revision 00d970127b9d44d2b22f4f656717a212dec1f1d2)
1 /***** spin: mesg.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 #ifndef MAXQ
16 #define MAXQ	2500		/* default max # queues  */
17 #endif
18 
19 extern RunList	*X;
20 extern Symbol	*Fname;
21 extern Lextok	*Mtype;
22 extern int	verbose, TstOnly, s_trail, analyze, columns;
23 extern int	lineno, depth, xspin, m_loss, jumpsteps;
24 extern int	nproc, nstop;
25 extern short	Have_claim;
26 
27 Queue	*qtab = (Queue *) 0;	/* linked list of queues */
28 Queue	*ltab[MAXQ];		/* linear list of queues */
29 int	nqs = 0, firstrow = 1;
30 char	Buf[4096];
31 
32 static Lextok	*n_rem = (Lextok *) 0;
33 static Queue	*q_rem = (Queue  *) 0;
34 
35 static int	a_rcv(Queue *, Lextok *, int);
36 static int	a_snd(Queue *, Lextok *);
37 static int	sa_snd(Queue *, Lextok *);
38 static int	s_snd(Queue *, Lextok *);
39 extern void	sr_buf(int, int);
40 extern void	sr_mesg(FILE *, int, int);
41 extern void	putarrow(int, int);
42 static void	sr_talk(Lextok *, int, char *, char *, int, Queue *);
43 
44 int
cnt_mpars(Lextok * n)45 cnt_mpars(Lextok *n)
46 {	Lextok *m;
47 	int i=0;
48 
49 	for (m = n; m; m = m->rgt)
50 		i += Cnt_flds(m);
51 	return i;
52 }
53 
54 int
qmake(Symbol * s)55 qmake(Symbol *s)
56 {	Lextok *m;
57 	Queue *q;
58 	int i;
59 
60 	if (!s->ini)
61 		return 0;
62 
63 	if (nqs >= MAXQ)
64 	{	lineno = s->ini->ln;
65 		Fname  = s->ini->fn;
66 		fatal("too many queues (%s)", s->name);
67 	}
68 	if (analyze && nqs >= 255)
69 	{	fatal("too many channel types", (char *)0);
70 	}
71 
72 	if (s->ini->ntyp != CHAN)
73 		return eval(s->ini);
74 
75 	q = (Queue *) emalloc(sizeof(Queue));
76 	q->qid    = ++nqs;
77 	q->nslots = s->ini->val;
78 	q->nflds  = cnt_mpars(s->ini->rgt);
79 	q->setat  = depth;
80 
81 	i = max(1, q->nslots);	/* 0-slot qs get 1 slot minimum */
82 
83 	q->contents  = (int *) emalloc(q->nflds*i*sizeof(int));
84 	q->fld_width = (int *) emalloc(q->nflds*sizeof(int));
85 	q->stepnr = (int *)   emalloc(i*sizeof(int));
86 
87 	for (m = s->ini->rgt, i = 0; m; m = m->rgt)
88 	{	if (m->sym && m->ntyp == STRUCT)
89 			i = Width_set(q->fld_width, i, getuname(m->sym));
90 		else
91 			q->fld_width[i++] = m->ntyp;
92 	}
93 	q->nxt = qtab;
94 	qtab = q;
95 	ltab[q->qid-1] = q;
96 
97 	return q->qid;
98 }
99 
100 int
qfull(Lextok * n)101 qfull(Lextok *n)
102 {	int whichq = eval(n->lft)-1;
103 
104 	if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
105 		return (ltab[whichq]->qlen >= ltab[whichq]->nslots);
106 	return 0;
107 }
108 
109 int
qlen(Lextok * n)110 qlen(Lextok *n)
111 {	int whichq = eval(n->lft)-1;
112 
113 	if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
114 		return ltab[whichq]->qlen;
115 	return 0;
116 }
117 
118 int
q_is_sync(Lextok * n)119 q_is_sync(Lextok *n)
120 {	int whichq = eval(n->lft)-1;
121 
122 	if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
123 		return (ltab[whichq]->nslots == 0);
124 	return 0;
125 }
126 
127 int
qsend(Lextok * n)128 qsend(Lextok *n)
129 {	int whichq = eval(n->lft)-1;
130 
131 	if (whichq == -1)
132 	{	printf("Error: sending to an uninitialized chan\n");
133 		whichq = 0;
134 		return 0;
135 	}
136 	if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
137 	{	ltab[whichq]->setat = depth;
138 		if (ltab[whichq]->nslots > 0)
139 			return a_snd(ltab[whichq], n);
140 		else
141 			return s_snd(ltab[whichq], n);
142 	}
143 	return 0;
144 }
145 
146 int
qrecv(Lextok * n,int full)147 qrecv(Lextok *n, int full)
148 {	int whichq = eval(n->lft)-1;
149 
150 	if (whichq == -1)
151 	{	if (n->sym && !strcmp(n->sym->name, "STDIN"))
152 		{	Lextok *m;
153 
154 			if (TstOnly) return 1;
155 
156 			for (m = n->rgt; m; m = m->rgt)
157 			if (m->lft->ntyp != CONST && m->lft->ntyp != EVAL)
158 			{	int c = getchar();
159 				(void) setval(m->lft, c);
160 			} else
161 				fatal("invalid use of STDIN", (char *)0);
162 
163 			whichq = 0;
164 			return 1;
165 		}
166 		printf("Error: receiving from an uninitialized chan %s\n",
167 			n->sym?n->sym->name:"");
168 		whichq = 0;
169 		return 0;
170 	}
171 	if (whichq < MAXQ && whichq >= 0 && ltab[whichq])
172 	{	ltab[whichq]->setat = depth;
173 		return a_rcv(ltab[whichq], n, full);
174 	}
175 	return 0;
176 }
177 
178 static int
sa_snd(Queue * q,Lextok * n)179 sa_snd(Queue *q, Lextok *n)	/* sorted asynchronous */
180 {	Lextok *m;
181 	int i, j, k;
182 	int New, Old;
183 
184 	for (i = 0; i < q->qlen; i++)
185 	for (j = 0, m = n->rgt; m && j < q->nflds; m = m->rgt, j++)
186 	{	New = cast_val(q->fld_width[j], eval(m->lft), 0);
187 		Old = q->contents[i*q->nflds+j];
188 		if (New == Old)
189 			continue;
190 		if (New >  Old)
191 			break;	/* inner loop */
192 		goto found;	/* New < Old */
193 	}
194 found:
195 	for (j = q->qlen-1; j >= i; j--)
196 	for (k = 0; k < q->nflds; k++)
197 	{	q->contents[(j+1)*q->nflds+k] =
198 			q->contents[j*q->nflds+k];	/* shift up */
199 		if (k == 0)
200 			q->stepnr[j+1] = q->stepnr[j];
201 	}
202 	return i*q->nflds;				/* new q offset */
203 }
204 
205 void
typ_ck(int ft,int at,char * s)206 typ_ck(int ft, int at, char *s)
207 {
208 	if ((verbose&32) && ft != at
209 	&& (ft == CHAN || at == CHAN))
210 	{	char buf[128], tag1[64], tag2[64];
211 		(void) sputtype(tag1, ft);
212 		(void) sputtype(tag2, at);
213 		sprintf(buf, "type-clash in %s, (%s<-> %s)", s, tag1, tag2);
214 		non_fatal("%s", buf);
215 	}
216 }
217 
218 static int
a_snd(Queue * q,Lextok * n)219 a_snd(Queue *q, Lextok *n)
220 {	Lextok *m;
221 	int i = q->qlen*q->nflds;	/* q offset */
222 	int j = 0;			/* q field# */
223 
224 	if (q->nslots > 0 && q->qlen >= q->nslots)
225 		return m_loss;	/* q is full */
226 
227 	if (TstOnly) return 1;
228 
229 	if (n->val) i = sa_snd(q, n);	/* sorted insert */
230 
231 	q->stepnr[i/q->nflds] = depth;
232 
233 	for (m = n->rgt; m && j < q->nflds; m = m->rgt, j++)
234 	{	int New = eval(m->lft);
235 		q->contents[i+j] = cast_val(q->fld_width[j], New, 0);
236 		if ((verbose&16) && depth >= jumpsteps)
237 			sr_talk(n, New, "Send ", "->", j, q);
238 		typ_ck(q->fld_width[j], Sym_typ(m->lft), "send");
239 	}
240 	if ((verbose&16) && depth >= jumpsteps)
241 	{	for (i = j; i < q->nflds; i++)
242 			sr_talk(n, 0, "Send ", "->", i, q);
243 		if (j < q->nflds)
244 			printf("%3d: warning: missing params in send\n",
245 				depth);
246 		if (m)
247 			printf("%3d: warning: too many params in send\n",
248 				depth);
249 	}
250 	q->qlen++;
251 	return 1;
252 }
253 
254 static int
a_rcv(Queue * q,Lextok * n,int full)255 a_rcv(Queue *q, Lextok *n, int full)
256 {	Lextok *m;
257 	int i=0, oi, j, k;
258 	extern int Rvous;
259 
260 	if (q->qlen == 0)
261 		return 0;	/* q is empty */
262 try_slot:
263 	/* test executability */
264 	for (m = n->rgt, j=0; m && j < q->nflds; m = m->rgt, j++)
265 		if ((m->lft->ntyp == CONST
266 		   && q->contents[i*q->nflds+j] != m->lft->val)
267 		||  (m->lft->ntyp == EVAL
268 		   && q->contents[i*q->nflds+j] != eval(m->lft->lft)))
269 		{	if (n->val == 0		/* fifo recv */
270 			||  n->val == 2		/* fifo poll */
271 			|| ++i >= q->qlen)	/* last slot */
272 				return 0;	/* no match  */
273 			goto try_slot;
274 		}
275 	if (TstOnly) return 1;
276 
277 	if (verbose&8)
278 	{	if (j < q->nflds)
279 			printf("%3d: warning: missing params in next recv\n",
280 				depth);
281 		else if (m)
282 			printf("%3d: warning: too many params in next recv\n",
283 				depth);
284 	}
285 
286 	/* set the fields */
287 	if (Rvous)
288 	{	n_rem = n;
289 		q_rem = q;
290 	}
291 
292 	oi = q->stepnr[i];
293 	for (m = n->rgt, j = 0; m && j < q->nflds; m = m->rgt, j++)
294 	{	if (columns && !full)	/* was columns == 1 */
295 			continue;
296 		if ((verbose&8) && !Rvous && depth >= jumpsteps)
297 		{	sr_talk(n, q->contents[i*q->nflds+j],
298 			(full && n->val < 2)?"Recv ":"[Recv] ", "<-", j, q);
299 		}
300 		if (!full)
301 			continue;	/* test */
302 		if (m && m->lft->ntyp != CONST && m->lft->ntyp != EVAL)
303 		{	(void) setval(m->lft, q->contents[i*q->nflds+j]);
304 			typ_ck(q->fld_width[j], Sym_typ(m->lft), "recv");
305 		}
306 		if (n->val < 2)		/* not a poll */
307 		for (k = i; k < q->qlen-1; k++)
308 		{	q->contents[k*q->nflds+j] =
309 			  q->contents[(k+1)*q->nflds+j];
310 			if (j == 0)
311 			  q->stepnr[k] = q->stepnr[k+1];
312 		}
313 	}
314 
315 	if ((!columns || full)
316 	&& (verbose&8) && !Rvous && depth >= jumpsteps)
317 	for (i = j; i < q->nflds; i++)
318 	{	sr_talk(n, 0,
319 		(full && n->val < 2)?"Recv ":"[Recv] ", "<-", i, q);
320 	}
321 	if (columns == 2 && full && !Rvous && depth >= jumpsteps)
322 		putarrow(oi, depth);
323 
324 	if (full && n->val < 2)
325 		q->qlen--;
326 	return 1;
327 }
328 
329 static int
s_snd(Queue * q,Lextok * n)330 s_snd(Queue *q, Lextok *n)
331 {	Lextok *m;
332 	RunList *rX, *sX = X;	/* rX=recvr, sX=sendr */
333 	int i, j = 0;	/* q field# */
334 
335 	for (m = n->rgt; m && j < q->nflds; m = m->rgt, j++)
336 	{	q->contents[j] = cast_val(q->fld_width[j], eval(m->lft), 0);
337 		typ_ck(q->fld_width[j], Sym_typ(m->lft), "rv-send");
338 	}
339 	q->qlen = 1;
340 	if (!complete_rendez())
341 	{	q->qlen = 0;
342 		return 0;
343 	}
344 	if (TstOnly)
345 	{	q->qlen = 0;
346 		return 1;
347 	}
348 	q->stepnr[0] = depth;
349 	if ((verbose&16) && depth >= jumpsteps)
350 	{	m = n->rgt;
351 		rX = X; X = sX;
352 		for (j = 0; m && j < q->nflds; m = m->rgt, j++)
353 			sr_talk(n, eval(m->lft), "Sent ", "->", j, q);
354 		for (i = j; i < q->nflds; i++)
355 			sr_talk(n, 0, "Sent ", "->", i, q);
356 		if (j < q->nflds)
357 			  printf("%3d: warning: missing params in rv-send\n",
358 				depth);
359 		else if (m)
360 			  printf("%3d: warning: too many params in rv-send\n",
361 				depth);
362 		X = rX;	/* restore receiver's context */
363 		if (!s_trail)
364 		{	if (!n_rem || !q_rem)
365 				fatal("cannot happen, s_snd", (char *) 0);
366 			m = n_rem->rgt;
367 			for (j = 0; m && j < q->nflds; m = m->rgt, j++)
368 			{	if (m->lft->ntyp != NAME
369 				||  strcmp(m->lft->sym->name, "_") != 0)
370 					i = eval(m->lft);
371 				else	i = 0;
372 
373 				if (verbose&8)
374 				sr_talk(n_rem,i,"Recv ","<-",j,q_rem);
375 			}
376 			if (verbose&8)
377 			for (i = j; i < q->nflds; i++)
378 				sr_talk(n_rem, 0, "Recv ", "<-", j, q_rem);
379 			if (columns == 2)
380 				putarrow(depth, depth);
381 		}
382 		n_rem = (Lextok *) 0;
383 		q_rem = (Queue *) 0;
384 	}
385 	return 1;
386 }
387 
388 static void
channm(Lextok * n)389 channm(Lextok *n)
390 {	char lbuf[512];
391 
392 	if (n->sym->type == CHAN)
393 		strcat(Buf, n->sym->name);
394 	else if (n->sym->type == NAME)
395 		strcat(Buf, lookup(n->sym->name)->name);
396 	else if (n->sym->type == STRUCT)
397 	{	Symbol *r = n->sym;
398 		if (r->context)
399 		{	r = findloc(r);
400 			if (!r)
401 			{	strcat(Buf, "*?*");
402 				return;
403 		}	}
404 		ini_struct(r);
405 		printf("%s", r->name);
406 		strcpy(lbuf, "");
407 		struct_name(n->lft, r, 1, lbuf);
408 		strcat(Buf, lbuf);
409 	} else
410 		strcat(Buf, "-");
411 	if (n->lft->lft)
412 	{	sprintf(lbuf, "[%d]", eval(n->lft->lft));
413 		strcat(Buf, lbuf);
414 	}
415 }
416 
417 static void
difcolumns(Lextok * n,char * tr,int v,int j,Queue * q)418 difcolumns(Lextok *n, char *tr, int v, int j, Queue *q)
419 {	extern int pno;
420 
421 	if (j == 0)
422 	{	Buf[0] = '\0';
423 		channm(n);
424 		strcat(Buf, (strncmp(tr, "Sen", 3))?"?":"!");
425 	} else
426 		strcat(Buf, ",");
427 	if (tr[0] == '[') strcat(Buf, "[");
428 	sr_buf(v, q->fld_width[j] == MTYPE);
429 	if (j == q->nflds - 1)
430 	{	int cnr;
431 		if (s_trail) cnr = pno; else cnr = X?X->pid - Have_claim:0;
432 		if (tr[0] == '[') strcat(Buf, "]");
433 		pstext(cnr, Buf);
434 	}
435 }
436 
437 static void
docolumns(Lextok * n,char * tr,int v,int j,Queue * q)438 docolumns(Lextok *n, char *tr, int v, int j, Queue *q)
439 {	int i;
440 
441 	if (firstrow)
442 	{	printf("q\\p");
443 		for (i = 0; i < nproc-nstop - Have_claim; i++)
444 			printf(" %3d", i);
445 		printf("\n");
446 		firstrow = 0;
447 	}
448 	if (j == 0)
449 	{	printf("%3d", q->qid);
450 		if (X)
451 		for (i = 0; i < X->pid - Have_claim; i++)
452 			printf("   .");
453 		printf("   ");
454 		Buf[0] = '\0';
455 		channm(n);
456 		printf("%s%c", Buf, (strncmp(tr, "Sen", 3))?'?':'!');
457 	} else
458 		printf(",");
459 	if (tr[0] == '[') printf("[");
460 	sr_mesg(stdout, v, q->fld_width[j] == MTYPE);
461 	if (j == q->nflds - 1)
462 	{	if (tr[0] == '[') printf("]");
463 		printf("\n");
464 	}
465 }
466 
467 typedef struct QH {
468 	int	n;
469 	struct	QH *nxt;
470 } QH;
471 static QH *qh;
472 
473 void
qhide(int q)474 qhide(int q)
475 {	QH *p = (QH *) emalloc(sizeof(QH));
476 	p->n = q;
477 	p->nxt = qh;
478 	qh = p;
479 }
480 
481 int
qishidden(int q)482 qishidden(int q)
483 {	QH *p;
484 	for (p = qh; p; p = p->nxt)
485 		if (p->n == q)
486 			return 1;
487 	return 0;
488 }
489 
490 static void
sr_talk(Lextok * n,int v,char * tr,char * a,int j,Queue * q)491 sr_talk(Lextok *n, int v, char *tr, char *a, int j, Queue *q)
492 {	char s[128];
493 
494 	if (qishidden(eval(n->lft)))
495 		return;
496 
497 	if (columns)
498 	{	if (columns == 2)
499 			difcolumns(n, tr, v, j, q);
500 		else
501 			docolumns(n, tr, v, j, q);
502 		return;
503 	}
504 	if (xspin)
505 	{	if ((verbose&4) && tr[0] != '[')
506 		sprintf(s, "(state -)\t[values: %d",
507 			eval(n->lft));
508 		else
509 		sprintf(s, "(state -)\t[%d", eval(n->lft));
510 		if (strncmp(tr, "Sen", 3) == 0)
511 			strcat(s, "!");
512 		else
513 			strcat(s, "?");
514 	} else
515 	{	strcpy(s, tr);
516 	}
517 
518 	if (j == 0)
519 	{	char snm[128];
520 		whoruns(1);
521 		{	char *ptr = n->fn->name;
522 			char *qtr = snm;
523 			while (*ptr != '\0')
524 			{	if (*ptr != '\"')
525 				{	*qtr++ = *ptr;
526 				}
527 				ptr++;
528 			}
529 			*qtr = '\0';
530 			printf("%s:%d %s",
531 				snm, n->ln, s);
532 		}
533 	} else
534 		printf(",");
535 	sr_mesg(stdout, v, q->fld_width[j] == MTYPE);
536 
537 	if (j == q->nflds - 1)
538 	{	if (xspin)
539 		{	printf("]\n");
540 			if (!(verbose&4)) printf("\n");
541 			return;
542 		}
543 		printf("\t%s queue %d (", a, eval(n->lft));
544 		Buf[0] = '\0';
545 		channm(n);
546 		printf("%s)\n", Buf);
547 	}
548 	fflush(stdout);
549 }
550 
551 void
sr_buf(int v,int j)552 sr_buf(int v, int j)
553 {	int cnt = 1; Lextok *n;
554 	char lbuf[512];
555 
556 	for (n = Mtype; n && j; n = n->rgt, cnt++)
557 		if (cnt == v)
558 		{	if(strlen(n->lft->sym->name) >= sizeof(lbuf))
559 			{	non_fatal("mtype name %s too long", n->lft->sym->name);
560 				break;
561 			}
562 			sprintf(lbuf, "%s", n->lft->sym->name);
563 			strcat(Buf, lbuf);
564 			return;
565 		}
566 	sprintf(lbuf, "%d", v);
567 	strcat(Buf, lbuf);
568 }
569 
570 void
sr_mesg(FILE * fd,int v,int j)571 sr_mesg(FILE *fd, int v, int j)
572 {	Buf[0] ='\0';
573 	sr_buf(v, j);
574 	fprintf(fd, Buf);
575 }
576 
577 void
doq(Symbol * s,int n,RunList * r)578 doq(Symbol *s, int n, RunList *r)
579 {	Queue *q;
580 	int j, k;
581 
582 	if (!s->val)	/* uninitialized queue */
583 		return;
584 	for (q = qtab; q; q = q->nxt)
585 	if (q->qid == s->val[n])
586 	{	if (xspin > 0
587 		&& (verbose&4)
588 		&& q->setat < depth)
589 			continue;
590 		if (q->nslots == 0)
591 			continue; /* rv q always empty */
592 #if 0
593 		if (q->qlen == 0)	/* new 7/10 -- dont show if queue is empty */
594 		{	continue;
595 		}
596 #endif
597 		printf("\t\tqueue %d (", q->qid);
598 		if (r)
599 		printf("%s(%d):", r->n->name, r->pid - Have_claim);
600 		if (s->nel > 1 || s->isarray)
601 		  printf("%s[%d]): ", s->name, n);
602 		else
603 		  printf("%s): ", s->name);
604 		for (k = 0; k < q->qlen; k++)
605 		{	printf("[");
606 			for (j = 0; j < q->nflds; j++)
607 			{	if (j > 0) printf(",");
608 				sr_mesg(stdout, q->contents[k*q->nflds+j],
609 					q->fld_width[j] == MTYPE);
610 			}
611 			printf("]");
612 		}
613 		printf("\n");
614 		break;
615 	}
616 }
617 
618 void
nochan_manip(Lextok * p,Lextok * n,int d)619 nochan_manip(Lextok *p, Lextok *n, int d)
620 {	int e = 1;
621 
622 	if (d == 0 && p->sym && p->sym->type == CHAN)
623 	{	setaccess(p->sym, ZS, 0, 'L');
624 
625 		if (n && n->ntyp == CONST)
626 			fatal("invalid asgn to chan", (char *) 0);
627 
628 		if (n && n->sym && n->sym->type == CHAN)
629 		{	setaccess(n->sym, ZS, 0, 'V');
630 			return;
631 		}
632 	}
633 
634 	/* ok on the rhs of an assignment: */
635 	if (!n || n->ntyp == LEN || n->ntyp == RUN
636 	||  n->ntyp == FULL  || n->ntyp == NFULL
637 	||  n->ntyp == EMPTY || n->ntyp == NEMPTY)
638 		return;
639 
640 	if (n->sym && n->sym->type == CHAN)
641 	{	if (d == 1)
642 			fatal("invalid use of chan name", (char *) 0);
643 		else
644 			setaccess(n->sym, ZS, 0, 'V');
645 	}
646 
647 	if (n->ntyp == NAME
648 	||  n->ntyp == '.')
649 		e = 0;	/* array index or struct element */
650 
651 	nochan_manip(p, n->lft, e);
652 	nochan_manip(p, n->rgt, 1);
653 }
654 
655 typedef struct BaseName {
656 	char *str;
657 	int cnt;
658 	struct BaseName *nxt;
659 } BaseName;
660 BaseName *bsn;
661 
662 void
newbasename(char * s)663 newbasename(char *s)
664 {	BaseName *b;
665 
666 /*	printf("+++++++++%s\n", s);	*/
667 	for (b = bsn; b; b = b->nxt)
668 		if (strcmp(b->str, s) == 0)
669 		{	b->cnt++;
670 			return;
671 		}
672 	b = (BaseName *) emalloc(sizeof(BaseName));
673 	b->str = emalloc(strlen(s)+1);
674 	b->cnt = 1;
675 	strcpy(b->str, s);
676 	b->nxt = bsn;
677 	bsn = b;
678 }
679 
680 void
delbasename(char * s)681 delbasename(char *s)
682 {	BaseName *b, *prv = (BaseName *) 0;
683 
684 	for (b = bsn; b; prv = b, b = b->nxt)
685 	{	if (strcmp(b->str, s) == 0)
686 		{	b->cnt--;
687 			if (b->cnt == 0)
688 			{	if (prv)
689 				{	prv->nxt = b->nxt;
690 				} else
691 				{	bsn = b->nxt;
692 			}	}
693 /*	printf("---------%s\n", s);	*/
694 			break;
695 	}	}
696 }
697 
698 void
checkindex(char * s,char * t)699 checkindex(char *s, char *t)
700 {	BaseName *b;
701 
702 /*	printf("xxx Check %s (%s)\n", s, t);	*/
703 	for (b = bsn; b; b = b->nxt)
704 	{
705 /*		printf("	%s\n", b->str);	*/
706 		if (strcmp(b->str, s) == 0)
707 		{	non_fatal("do not index an array with itself (%s)", t);
708 			break;
709 	}	}
710 }
711 
712 void
scan_tree(Lextok * t,char * mn,char * mx)713 scan_tree(Lextok *t, char *mn, char *mx)
714 {	char sv[512];
715 	char tmp[32];
716 	int oln = lineno;
717 
718 	if (!t) return;
719 
720 	lineno = t->ln;
721 
722 	if (t->ntyp == NAME)
723 	{	strcat(mn, t->sym->name);
724 		strcat(mx, t->sym->name);
725 		if (t->lft)		/* array index */
726 		{	strcat(mn, "[]");
727 			newbasename(mn);
728 				strcpy(sv, mn);		/* save */
729 				strcpy(mn, "");		/* clear */
730 				strcat(mx, "[");
731 				scan_tree(t->lft, mn, mx);	/* index */
732 				strcat(mx, "]");
733 				checkindex(mn, mx);	/* match against basenames */
734 				strcpy(mn, sv);		/* restore */
735 			delbasename(mn);
736 		}
737 		if (t->rgt)	/* structure element */
738 		{	scan_tree(t->rgt, mn, mx);
739 		}
740 	} else if (t->ntyp == CONST)
741 	{	strcat(mn, "1"); /* really: t->val */
742 		sprintf(tmp, "%d", t->val);
743 		strcat(mx, tmp);
744 	} else if (t->ntyp == '.')
745 	{	strcat(mn, ".");
746 		strcat(mx, ".");
747 		scan_tree(t->lft, mn, mx);
748 	} else
749 	{	strcat(mn, "??");
750 		strcat(mx, "??");
751 	}
752 	lineno = oln;
753 }
754 
755 void
no_nested_array_refs(Lextok * n)756 no_nested_array_refs(Lextok *n)	/* a [ a[1] ] with a[1] = 1, causes trouble in pan.b */
757 {	char mn[512];
758 	char mx[512];
759 
760 /*	printf("==================================ZAP\n");	*/
761 	bsn = (BaseName *) 0;	/* start new list */
762 	strcpy(mn, "");
763 	strcpy(mx, "");
764 
765 	scan_tree(n, mn, mx);
766 /*	printf("==> %s\n", mn);	*/
767 }
768 
769 void
no_internals(Lextok * n)770 no_internals(Lextok *n)
771 {	char *sp;
772 
773 	if (!n->sym
774 	||  !n->sym->name)
775 		return;
776 
777 	sp = n->sym->name;
778 
779 	if ((strlen(sp) == strlen("_nr_pr") && strcmp(sp, "_nr_pr") == 0)
780 	||  (strlen(sp) == strlen("_p") && strcmp(sp, "_p") == 0))
781 	{	fatal("attempt to assign value to system variable %s", sp);
782 	}
783 
784 	no_nested_array_refs(n);
785 }
786