xref: /plan9/sys/src/cmd/spin/main.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier /***** spin: main.c *****/
2*219b2ee8SDavid du Colombier 
3*219b2ee8SDavid du Colombier /* Copyright (c) 1991,1995 by AT&T Corporation.  All Rights Reserved.     */
4*219b2ee8SDavid du Colombier /* This software is for educational purposes only.                        */
5*219b2ee8SDavid du Colombier /* Permission is given to distribute this code provided that this intro-  */
6*219b2ee8SDavid du Colombier /* ductory message is not removed and no monies are exchanged.            */
7*219b2ee8SDavid du Colombier /* No guarantee is expressed or implied by the distribution of this code. */
8*219b2ee8SDavid du Colombier /* Software written by Gerard J. Holzmann as part of the book:            */
9*219b2ee8SDavid du Colombier /* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
10*219b2ee8SDavid du Colombier /* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
11*219b2ee8SDavid du Colombier /* Send bug-reports and/or questions to: gerard@research.att.com          */
12*219b2ee8SDavid du Colombier 
13*219b2ee8SDavid du Colombier #include "spin.h"
14*219b2ee8SDavid du Colombier #include <signal.h>
15*219b2ee8SDavid du Colombier #include <stdlib.h>
16*219b2ee8SDavid du Colombier #include <unistd.h>
17*219b2ee8SDavid du Colombier #include "y.tab.h"
18*219b2ee8SDavid du Colombier 
19*219b2ee8SDavid du Colombier extern int	DstepStart, lineno;
20*219b2ee8SDavid du Colombier extern FILE	*yyin;
21*219b2ee8SDavid du Colombier 
22*219b2ee8SDavid du Colombier Symbol	*Fname, *oFname;
23*219b2ee8SDavid du Colombier 
24*219b2ee8SDavid du Colombier int	verbose = 0;
25*219b2ee8SDavid du Colombier int	analyze = 0;
26*219b2ee8SDavid du Colombier int	s_trail = 0;
27*219b2ee8SDavid du Colombier int	m_loss  = 0;
28*219b2ee8SDavid du Colombier int	dumptab	= 0;
29*219b2ee8SDavid du Colombier int	nr_errs	= 0;
30*219b2ee8SDavid du Colombier int	dataflow = 0;
31*219b2ee8SDavid du Colombier int	has_remote = 0;
32*219b2ee8SDavid du Colombier int	Interactive = 0;
33*219b2ee8SDavid du Colombier int	Ntimeouts = 0;	/* counts those used in never claim */
34*219b2ee8SDavid du Colombier int	Etimeouts = 0;	/* counts those used in program */
35*219b2ee8SDavid du Colombier int	xspin = 0;	/* set when used with xspin interface */
36*219b2ee8SDavid du Colombier 
37*219b2ee8SDavid du Colombier void
38*219b2ee8SDavid du Colombier main(int argc, char *argv[])
39*219b2ee8SDavid du Colombier {	Symbol *s;
40*219b2ee8SDavid du Colombier 	int T = (int) time((long *)0);
41*219b2ee8SDavid du Colombier 
42*219b2ee8SDavid du Colombier 	while (argc > 1 && argv[1][0] == '-')
43*219b2ee8SDavid du Colombier 	{	switch (argv[1][1]) {
44*219b2ee8SDavid du Colombier 		case 'a': analyze  =  1; break;
45*219b2ee8SDavid du Colombier 		case 'd': dumptab  =  1; break;
46*219b2ee8SDavid du Colombier 		case 'D': dataflow++; break;
47*219b2ee8SDavid du Colombier 		case 'g': verbose +=  1; break;
48*219b2ee8SDavid du Colombier 		case 'i': Interactive = 1; break;
49*219b2ee8SDavid du Colombier 		case 'l': verbose +=  2; break;
50*219b2ee8SDavid du Colombier 		case 'm': m_loss   =  1; break;
51*219b2ee8SDavid du Colombier 		case 'n': T = atoi(&argv[1][2]); break;
52*219b2ee8SDavid du Colombier 		case 'p': verbose +=  4; break;
53*219b2ee8SDavid du Colombier 		case 'r': verbose +=  8; break;
54*219b2ee8SDavid du Colombier 		case 's': verbose += 16; break;
55*219b2ee8SDavid du Colombier 		case 't': s_trail  =  1; break;
56*219b2ee8SDavid du Colombier 		case 'v': verbose += 32; break;
57*219b2ee8SDavid du Colombier 		case 'V': printf("%s\n", Version); exit(0);
58*219b2ee8SDavid du Colombier 		case 'X': xspin    =  1;
59*219b2ee8SDavid du Colombier 			  signal(SIGPIPE, exit); /* not posix compliant... */
60*219b2ee8SDavid du Colombier 			  break;
61*219b2ee8SDavid du Colombier 		default : printf("use: spin [-option] ... [-option] file\n");
62*219b2ee8SDavid du Colombier 			  printf("\t-a produce an analyzer\n");
63*219b2ee8SDavid du Colombier 			  printf("\t-d produce symbol-table information\n");
64*219b2ee8SDavid du Colombier 			  printf("\t-D write/write dataflow\n");
65*219b2ee8SDavid du Colombier 			  printf("\t-D -D read/write dataflow\n");
66*219b2ee8SDavid du Colombier 			  printf("\t-g print all global variables\n");
67*219b2ee8SDavid du Colombier 			  printf("\t-i interactive (random simulation)\n");
68*219b2ee8SDavid du Colombier 			  printf("\t-l print all local variables\n");
69*219b2ee8SDavid du Colombier 			  printf("\t-m lose msgs sent to full queues\n");
70*219b2ee8SDavid du Colombier 			  printf("\t-nN seed for random nr generator\n");
71*219b2ee8SDavid du Colombier 			  printf("\t-p print all statements\n");
72*219b2ee8SDavid du Colombier 			  printf("\t-r print receive events\n");
73*219b2ee8SDavid du Colombier 			  printf("\t-s print send events\n");
74*219b2ee8SDavid du Colombier 			  printf("\t-v verbose, more warnings\n");
75*219b2ee8SDavid du Colombier 			  printf("\t-t follow a simulation trail\n");
76*219b2ee8SDavid du Colombier 			  printf("\t-V print version number and exit\n");
77*219b2ee8SDavid du Colombier 			  exit(1);
78*219b2ee8SDavid du Colombier 		}
79*219b2ee8SDavid du Colombier 		argc--, argv++;
80*219b2ee8SDavid du Colombier 	}
81*219b2ee8SDavid du Colombier 	if (argc > 1)
82*219b2ee8SDavid du Colombier 	{	char outfile[32], cmd[128];
83*219b2ee8SDavid du Colombier 		extern char *tmpnam(char *);
84*219b2ee8SDavid du Colombier 		(void) tmpnam(outfile);
85*219b2ee8SDavid du Colombier 
86*219b2ee8SDavid du Colombier 		/* on some systems: "/usr/ccs/lib/cpp" */
87*219b2ee8SDavid du Colombier 		sprintf(cmd, "/bin/cpp %s > %s", argv[1], outfile);
88*219b2ee8SDavid du Colombier 		if (system((const char *)cmd))
89*219b2ee8SDavid du Colombier 		{	(void) unlink((const char *)outfile);
90*219b2ee8SDavid du Colombier 			exit(1);
91*219b2ee8SDavid du Colombier 		} else if (!(yyin = fopen(outfile, "r")))
92*219b2ee8SDavid du Colombier 		{	printf("cannot open %s\n", outfile);
93*219b2ee8SDavid du Colombier 			exit(1);
94*219b2ee8SDavid du Colombier 		}
95*219b2ee8SDavid du Colombier 		(void) unlink((const char *)outfile);
96*219b2ee8SDavid du Colombier 		oFname = Fname = lookup(argv[1]);
97*219b2ee8SDavid du Colombier 		if (oFname->name[0] == '\"')
98*219b2ee8SDavid du Colombier 		{	int i = strlen(oFname->name);
99*219b2ee8SDavid du Colombier 			oFname->name[i-1] = '\0';
100*219b2ee8SDavid du Colombier 			oFname = lookup(&oFname->name[1]);
101*219b2ee8SDavid du Colombier 		}
102*219b2ee8SDavid du Colombier 	} else
103*219b2ee8SDavid du Colombier 		Fname = lookup("<stdin>");
104*219b2ee8SDavid du Colombier 	Srand(T);	/* defined in run.c */
105*219b2ee8SDavid du Colombier 	s = lookup("_p");	s->type = PREDEF;
106*219b2ee8SDavid du Colombier 	s = lookup("_pid");	s->type = PREDEF;
107*219b2ee8SDavid du Colombier 	s = lookup("_last");	s->type = PREDEF;
108*219b2ee8SDavid du Colombier 	yyparse();
109*219b2ee8SDavid du Colombier 	exit(nr_errs);
110*219b2ee8SDavid du Colombier }
111*219b2ee8SDavid du Colombier 
112*219b2ee8SDavid du Colombier int
113*219b2ee8SDavid du Colombier yywrap(void)	/* dummy routine */
114*219b2ee8SDavid du Colombier {
115*219b2ee8SDavid du Colombier 	return 1;
116*219b2ee8SDavid du Colombier }
117*219b2ee8SDavid du Colombier 
118*219b2ee8SDavid du Colombier void
119*219b2ee8SDavid du Colombier non_fatal(char *s1, char *s2)
120*219b2ee8SDavid du Colombier {	extern int yychar; extern char yytext[];
121*219b2ee8SDavid du Colombier 
122*219b2ee8SDavid du Colombier 	printf("spin: line %3d %s: ", lineno, Fname->name);
123*219b2ee8SDavid du Colombier 	if (s2)
124*219b2ee8SDavid du Colombier 		printf(s1, s2);
125*219b2ee8SDavid du Colombier 	else
126*219b2ee8SDavid du Colombier 		printf(s1);
127*219b2ee8SDavid du Colombier 	if (yychar != -1 && yychar != 0)
128*219b2ee8SDavid du Colombier 	{	printf("	saw '");
129*219b2ee8SDavid du Colombier 		explain(yychar);
130*219b2ee8SDavid du Colombier 		printf("'");
131*219b2ee8SDavid du Colombier 	}
132*219b2ee8SDavid du Colombier 	if (yytext && strlen(yytext)>1)
133*219b2ee8SDavid du Colombier 		printf(" near '%s'", yytext);
134*219b2ee8SDavid du Colombier 	printf("\n"); fflush(stdout);
135*219b2ee8SDavid du Colombier 	nr_errs++;
136*219b2ee8SDavid du Colombier }
137*219b2ee8SDavid du Colombier 
138*219b2ee8SDavid du Colombier void
139*219b2ee8SDavid du Colombier fatal(char *s1, char *s2)
140*219b2ee8SDavid du Colombier {
141*219b2ee8SDavid du Colombier 	non_fatal(s1, s2);
142*219b2ee8SDavid du Colombier 	exit(1);
143*219b2ee8SDavid du Colombier }
144*219b2ee8SDavid du Colombier 
145*219b2ee8SDavid du Colombier char *
146*219b2ee8SDavid du Colombier emalloc(int n)
147*219b2ee8SDavid du Colombier {	char *tmp;
148*219b2ee8SDavid du Colombier 
149*219b2ee8SDavid du Colombier 	if (!(tmp = (char *) malloc(n)))
150*219b2ee8SDavid du Colombier 		fatal("not enough memory", (char *)0);
151*219b2ee8SDavid du Colombier 	memset(tmp, 0, n);
152*219b2ee8SDavid du Colombier 	return tmp;
153*219b2ee8SDavid du Colombier }
154*219b2ee8SDavid du Colombier 
155*219b2ee8SDavid du Colombier Lextok *
156*219b2ee8SDavid du Colombier nn(Lextok *s, int t, Lextok *ll, Lextok *rl)
157*219b2ee8SDavid du Colombier {	Lextok *n = (Lextok *) emalloc(sizeof(Lextok));
158*219b2ee8SDavid du Colombier 	extern char *claimproc;
159*219b2ee8SDavid du Colombier 	extern Symbol *context;
160*219b2ee8SDavid du Colombier 
161*219b2ee8SDavid du Colombier 	n->ntyp = t;
162*219b2ee8SDavid du Colombier 	if (s && s->fn)
163*219b2ee8SDavid du Colombier 	{	n->ln = s->ln;
164*219b2ee8SDavid du Colombier 		n->fn = s->fn;
165*219b2ee8SDavid du Colombier 	} else if (rl && rl->fn)
166*219b2ee8SDavid du Colombier 	{	n->ln = rl->ln;
167*219b2ee8SDavid du Colombier 		n->fn = rl->fn;
168*219b2ee8SDavid du Colombier 	} else if (ll && ll->fn)
169*219b2ee8SDavid du Colombier 	{	n->ln = ll->ln;
170*219b2ee8SDavid du Colombier 		n->fn = ll->fn;
171*219b2ee8SDavid du Colombier 	} else
172*219b2ee8SDavid du Colombier 	{	n->ln = lineno;
173*219b2ee8SDavid du Colombier 		n->fn = Fname;
174*219b2ee8SDavid du Colombier 	}
175*219b2ee8SDavid du Colombier 	if (s) n->sym  = s->sym;
176*219b2ee8SDavid du Colombier 	n->lft  = ll;
177*219b2ee8SDavid du Colombier 	n->rgt  = rl;
178*219b2ee8SDavid du Colombier 	n->indstep = DstepStart;
179*219b2ee8SDavid du Colombier 
180*219b2ee8SDavid du Colombier 	if (t == TIMEOUT) Etimeouts++;
181*219b2ee8SDavid du Colombier 
182*219b2ee8SDavid du Colombier 	if (!context)
183*219b2ee8SDavid du Colombier 		return n;
184*219b2ee8SDavid du Colombier 	if (context->name == claimproc)
185*219b2ee8SDavid du Colombier 	{	switch (t) {
186*219b2ee8SDavid du Colombier 		case ASGN: case 'r': case 's':
187*219b2ee8SDavid du Colombier 			non_fatal("never claim has side-effect",(char *)0);
188*219b2ee8SDavid du Colombier 			break;
189*219b2ee8SDavid du Colombier 		case TIMEOUT:
190*219b2ee8SDavid du Colombier 			/* never claim polls timeout */
191*219b2ee8SDavid du Colombier 			Ntimeouts++; Etimeouts--;
192*219b2ee8SDavid du Colombier 			break;
193*219b2ee8SDavid du Colombier 		case LEN: case EMPTY: case FULL:
194*219b2ee8SDavid du Colombier 		case 'R': case NFULL: case NEMPTY:
195*219b2ee8SDavid du Colombier 			/* status bumped to non-exclusive */
196*219b2ee8SDavid du Colombier 			if (n->sym) n->sym->xu |= XX;
197*219b2ee8SDavid du Colombier 			break;
198*219b2ee8SDavid du Colombier 		default:
199*219b2ee8SDavid du Colombier 			break;
200*219b2ee8SDavid du Colombier 		}
201*219b2ee8SDavid du Colombier 	} else if (t == ENABLED)
202*219b2ee8SDavid du Colombier 		fatal("using enabled() outside never-claim",(char *)0);
203*219b2ee8SDavid du Colombier 		/* this affects how enabled is implemented in run.c */
204*219b2ee8SDavid du Colombier 
205*219b2ee8SDavid du Colombier 	return n;
206*219b2ee8SDavid du Colombier }
207*219b2ee8SDavid du Colombier 
208*219b2ee8SDavid du Colombier Lextok *
209*219b2ee8SDavid du Colombier rem_lab(Symbol *a, Lextok *b, Symbol *c)
210*219b2ee8SDavid du Colombier {	Lextok *tmp1, *tmp2, *tmp3;
211*219b2ee8SDavid du Colombier 
212*219b2ee8SDavid du Colombier 	has_remote++;
213*219b2ee8SDavid du Colombier 	fix_dest(c, a);	/* in case target is jump */
214*219b2ee8SDavid du Colombier 	tmp1 = nn(ZN, '?',   b, ZN); tmp1->sym = a;
215*219b2ee8SDavid du Colombier 	tmp1 = nn(ZN, 'p', tmp1, ZN);
216*219b2ee8SDavid du Colombier 	tmp1->sym = lookup("_p");
217*219b2ee8SDavid du Colombier 	tmp2 = nn(ZN, NAME,  ZN, ZN); tmp2->sym = a;
218*219b2ee8SDavid du Colombier 	tmp3 = nn(ZN, 'q', tmp2, ZN); tmp3->sym = c;
219*219b2ee8SDavid du Colombier 	return nn(ZN, EQ, tmp1, tmp3);
220*219b2ee8SDavid du Colombier }
221*219b2ee8SDavid du Colombier 
222*219b2ee8SDavid du Colombier char Operator[] = "operator: ";
223*219b2ee8SDavid du Colombier char Keyword[]  = "keyword: ";
224*219b2ee8SDavid du Colombier char Function[] = "function-name: ";
225*219b2ee8SDavid du Colombier 
226*219b2ee8SDavid du Colombier void
227*219b2ee8SDavid du Colombier explain(int n)
228*219b2ee8SDavid du Colombier {
229*219b2ee8SDavid du Colombier 	switch (n) {
230*219b2ee8SDavid du Colombier 	default:	if (n > 0 && n < 256)
231*219b2ee8SDavid du Colombier 				printf("%c' = '", n);
232*219b2ee8SDavid du Colombier 			printf("%d", n);
233*219b2ee8SDavid du Colombier 			break;
234*219b2ee8SDavid du Colombier 	case '\b':	printf("\\b"); break;
235*219b2ee8SDavid du Colombier 	case '\t':	printf("\\t"); break;
236*219b2ee8SDavid du Colombier 	case '\f':	printf("\\f"); break;
237*219b2ee8SDavid du Colombier 	case '\n':	printf("\\n"); break;
238*219b2ee8SDavid du Colombier 	case '\r':	printf("\\r"); break;
239*219b2ee8SDavid du Colombier 	case 'c':	printf("condition"); break;
240*219b2ee8SDavid du Colombier 	case 's':	printf("send"); break;
241*219b2ee8SDavid du Colombier 	case 'r':	printf("recv"); break;
242*219b2ee8SDavid du Colombier 	case '@':	printf("delproc"); break;
243*219b2ee8SDavid du Colombier 	case '?':	printf("(x->y:z)"); break;
244*219b2ee8SDavid du Colombier 	case ACTIVE:	printf("%sactive",	Keyword); break;
245*219b2ee8SDavid du Colombier 	case AND:	printf("%s&&",		Operator); break;
246*219b2ee8SDavid du Colombier 	case ASGN:	printf("%s=",		Operator); break;
247*219b2ee8SDavid du Colombier 	case ASSERT:	printf("%sassert",	Function); break;
248*219b2ee8SDavid du Colombier 	case ATOMIC:	printf("%satomic",	Keyword); break;
249*219b2ee8SDavid du Colombier 	case BREAK:	printf("%sbreak",	Keyword); break;
250*219b2ee8SDavid du Colombier 	case CLAIM:	printf("%snever",	Keyword); break;
251*219b2ee8SDavid du Colombier 	case CONST:	printf("a constant"); break;
252*219b2ee8SDavid du Colombier 	case DECR:	printf("%s--",		Operator); break;
253*219b2ee8SDavid du Colombier 	case D_STEP:	printf("%sd_step",	Keyword); break;
254*219b2ee8SDavid du Colombier 	case DO:	printf("%sdo",		Keyword); break;
255*219b2ee8SDavid du Colombier 	case DOT:	printf("."); break;
256*219b2ee8SDavid du Colombier 	case ELSE:	printf("%selse",	Keyword); break;
257*219b2ee8SDavid du Colombier 	case EMPTY:	printf("%sempty",	Function); break;
258*219b2ee8SDavid du Colombier 	case ENABLED:	printf("%senabled",	Function); break;
259*219b2ee8SDavid du Colombier 	case EQ:	printf("%s==",		Operator); break;
260*219b2ee8SDavid du Colombier 	case FI:	printf("%sfi",		Keyword); break;
261*219b2ee8SDavid du Colombier 	case FULL:	printf("%sfull",	Function); break;
262*219b2ee8SDavid du Colombier 	case GE:	printf("%s>=",		Operator); break;
263*219b2ee8SDavid du Colombier 	case GOTO:	printf("%sgoto",	Keyword); break;
264*219b2ee8SDavid du Colombier 	case GT:	printf("%s>",		Operator); break;
265*219b2ee8SDavid du Colombier 	case IF:	printf("%sif",		Keyword); break;
266*219b2ee8SDavid du Colombier 	case INCR:	printf("%s++",		Operator); break;
267*219b2ee8SDavid du Colombier 	case INIT:	printf("%sinit",	Keyword); break;
268*219b2ee8SDavid du Colombier 	case LABEL:	printf("a label-name"); break;
269*219b2ee8SDavid du Colombier 	case LE:	printf("%s<=",		Operator); break;
270*219b2ee8SDavid du Colombier 	case LEN:	printf("%slen",		Function); break;
271*219b2ee8SDavid du Colombier 	case LSHIFT:	printf("%s<<",		Operator); break;
272*219b2ee8SDavid du Colombier 	case LT:	printf("%s<",		Operator); break;
273*219b2ee8SDavid du Colombier 	case MTYPE:	printf("%smtype",	Keyword); break;
274*219b2ee8SDavid du Colombier 	case NAME:	printf("an identifier"); break;
275*219b2ee8SDavid du Colombier 	case NE:	printf("%s!=",		Operator); break;
276*219b2ee8SDavid du Colombier 	case NEG:	printf("%s! (not)",	Operator); break;
277*219b2ee8SDavid du Colombier 	case NEMPTY:	printf("%snempty",	Function); break;
278*219b2ee8SDavid du Colombier 	case NFULL:	printf("%snfull",	Function); break;
279*219b2ee8SDavid du Colombier 	case NON_ATOMIC: printf("sub-sequence"); break;
280*219b2ee8SDavid du Colombier 	case OD:	printf("%sod",		Keyword); break;
281*219b2ee8SDavid du Colombier 	case OF:	printf("%sof",		Keyword); break;
282*219b2ee8SDavid du Colombier 	case OR:	printf("%s||",		Operator); break;
283*219b2ee8SDavid du Colombier 	case O_SND:	printf("%s!!",		Operator); break;
284*219b2ee8SDavid du Colombier 	case PC_VAL:	printf("%spc_value",	Function); break;
285*219b2ee8SDavid du Colombier 	case PNAME:	printf("process name"); break;
286*219b2ee8SDavid du Colombier 	case PRINT:	printf("%sprintf",	Function); break;
287*219b2ee8SDavid du Colombier 	case PROCTYPE:	printf("%sproctype",	Keyword); break;
288*219b2ee8SDavid du Colombier 	case RCV:	printf("%s?",		Operator); break;
289*219b2ee8SDavid du Colombier 	case R_RCV:	printf("%s??",		Operator); break;
290*219b2ee8SDavid du Colombier 	case RSHIFT:	printf("%s>>",		Operator); break;
291*219b2ee8SDavid du Colombier 	case RUN:	printf("%srun",		Operator); break;
292*219b2ee8SDavid du Colombier 	case SEP:	printf("token: ::"); break;
293*219b2ee8SDavid du Colombier 	case SEMI:	printf(";"); break;
294*219b2ee8SDavid du Colombier 	case SND:	printf("%s!",		Operator); break;
295*219b2ee8SDavid du Colombier 	case STRING:	printf("a string"); break;
296*219b2ee8SDavid du Colombier 	case TIMEOUT:	printf("%stimeout",	Keyword); break;
297*219b2ee8SDavid du Colombier 	case TYPE:	printf("data typename"); break;
298*219b2ee8SDavid du Colombier 	case TYPEDEF:	printf("%stypedef",	Keyword); break;
299*219b2ee8SDavid du Colombier 	case XU:	printf("%sx[rs]",	Keyword); break;
300*219b2ee8SDavid du Colombier 	case UMIN:	printf("%s- (unary minus)", Operator); break;
301*219b2ee8SDavid du Colombier 	case UNAME:	printf("a typename"); break;
302*219b2ee8SDavid du Colombier 	case UNLESS:	printf("%sunless",	Keyword); break;
303*219b2ee8SDavid du Colombier 	}
304*219b2ee8SDavid du Colombier }
305*219b2ee8SDavid du Colombier 
306*219b2ee8SDavid du Colombier static int IsAsgn = 0, OrIsAsgn = 0;
307*219b2ee8SDavid du Colombier static Element *Same;
308*219b2ee8SDavid du Colombier 
309*219b2ee8SDavid du Colombier int
310*219b2ee8SDavid du Colombier used_here(Symbol *s, Lextok *n)
311*219b2ee8SDavid du Colombier {	extern Symbol *context;
312*219b2ee8SDavid du Colombier 	int res = 0;
313*219b2ee8SDavid du Colombier 
314*219b2ee8SDavid du Colombier 	if (!n) return 0;
315*219b2ee8SDavid du Colombier #ifdef DEBUG
316*219b2ee8SDavid du Colombier 	{	int oln; Symbol *ofn;
317*219b2ee8SDavid du Colombier 		printf("	used_here %s -- ", context->name);
318*219b2ee8SDavid du Colombier 		oln = lineno; ofn = Fname;
319*219b2ee8SDavid du Colombier 		comment(stdout, n, 0);
320*219b2ee8SDavid du Colombier 		lineno = oln; Fname = ofn;
321*219b2ee8SDavid du Colombier 		printf(" -- %d:%s\n", n->ln,n->fn->name);
322*219b2ee8SDavid du Colombier 	}
323*219b2ee8SDavid du Colombier #endif
324*219b2ee8SDavid du Colombier 	if (n->sym == s) res = (IsAsgn || n->ntyp == ASGN)?2:1;
325*219b2ee8SDavid du Colombier 	if (n->ntyp == ASGN)
326*219b2ee8SDavid du Colombier 		res |= used_here(s, n->lft->lft);
327*219b2ee8SDavid du Colombier 	else
328*219b2ee8SDavid du Colombier 		res |= used_here(s, n->lft);
329*219b2ee8SDavid du Colombier 	if (n->ntyp == 'r')
330*219b2ee8SDavid du Colombier 		IsAsgn = 1;
331*219b2ee8SDavid du Colombier 	res |= used_here(s, n->rgt);
332*219b2ee8SDavid du Colombier 	if (n->ntyp == 'r')
333*219b2ee8SDavid du Colombier 		IsAsgn = 0;
334*219b2ee8SDavid du Colombier 	return res;
335*219b2ee8SDavid du Colombier }
336*219b2ee8SDavid du Colombier 
337*219b2ee8SDavid du Colombier int
338*219b2ee8SDavid du Colombier used_later(Symbol *s, Element *t)
339*219b2ee8SDavid du Colombier {	extern Symbol *context;
340*219b2ee8SDavid du Colombier 	int res = 0;
341*219b2ee8SDavid du Colombier 
342*219b2ee8SDavid du Colombier 	if (!t || !s)
343*219b2ee8SDavid du Colombier 		return 0;
344*219b2ee8SDavid du Colombier 	if (t->status&CHECK2)
345*219b2ee8SDavid du Colombier 	{
346*219b2ee8SDavid du Colombier #ifdef DEBUG
347*219b2ee8SDavid du Colombier 		printf("\t%d used_later: done before\n", t->Seqno);
348*219b2ee8SDavid du Colombier #endif
349*219b2ee8SDavid du Colombier 		return (t->Seqno == Same->Seqno) ? 4 : 0;
350*219b2ee8SDavid du Colombier 	}
351*219b2ee8SDavid du Colombier 
352*219b2ee8SDavid du Colombier 	t->status |= CHECK2;
353*219b2ee8SDavid du Colombier 
354*219b2ee8SDavid du Colombier #ifdef DEBUG
355*219b2ee8SDavid du Colombier 	{	int oln; Symbol *ofn;
356*219b2ee8SDavid du Colombier 		printf("\t%d %u ->%d %u used_later %s -- ",
357*219b2ee8SDavid du Colombier 			t->seqno,
358*219b2ee8SDavid du Colombier 			t, (t->nxt)?t->nxt->seqno:-1,
359*219b2ee8SDavid du Colombier 			t->nxt, context->name);
360*219b2ee8SDavid du Colombier 		oln = lineno; ofn = Fname;
361*219b2ee8SDavid du Colombier 		comment(stdout, t->n, 0);
362*219b2ee8SDavid du Colombier 		lineno = oln; Fname = ofn;
363*219b2ee8SDavid du Colombier 		printf(" -- %d:%s\n", t->n->ln, t->n->fn->name);
364*219b2ee8SDavid du Colombier 	}
365*219b2ee8SDavid du Colombier #endif
366*219b2ee8SDavid du Colombier 	if (t->n->ntyp == GOTO)
367*219b2ee8SDavid du Colombier 	{	Element *j = target(t);
368*219b2ee8SDavid du Colombier #ifdef DEBUG
369*219b2ee8SDavid du Colombier 		printf("\t\tjump to %d\n", j?j->Seqno:-1);
370*219b2ee8SDavid du Colombier #endif
371*219b2ee8SDavid du Colombier 		res |= used_later(s, j);
372*219b2ee8SDavid du Colombier 		goto done;
373*219b2ee8SDavid du Colombier 	}
374*219b2ee8SDavid du Colombier 
375*219b2ee8SDavid du Colombier 	if (t->n->sl && ! t->sub)	/* d_step or (non-) atomic */
376*219b2ee8SDavid du Colombier 	{	SeqList *f;
377*219b2ee8SDavid du Colombier 		for (f = t->n->sl; f; f = f->nxt)
378*219b2ee8SDavid du Colombier 		{	f->this->last->nxt = t->nxt;
379*219b2ee8SDavid du Colombier #ifdef DEBUG
380*219b2ee8SDavid du Colombier 	printf("\tPatch2 %d->%d (%d)\n",
381*219b2ee8SDavid du Colombier 	f->this->last->seqno, t->nxt?t->nxt->seqno:-1, t->n->ntyp);
382*219b2ee8SDavid du Colombier #endif
383*219b2ee8SDavid du Colombier 			res |= used_later(s, f->this->frst);
384*219b2ee8SDavid du Colombier 		}
385*219b2ee8SDavid du Colombier 	} else if (t->sub)	/* IF or DO */
386*219b2ee8SDavid du Colombier 	{	SeqList *f;
387*219b2ee8SDavid du Colombier 		for (f = t->sub; f; f = f->nxt)
388*219b2ee8SDavid du Colombier 			res |= used_later(s, f->this->frst);
389*219b2ee8SDavid du Colombier 	} else
390*219b2ee8SDavid du Colombier 	{	res |= used_here(s, t->n);
391*219b2ee8SDavid du Colombier 	}
392*219b2ee8SDavid du Colombier 	if (!(res&3)) res |= used_later(s, t->nxt);
393*219b2ee8SDavid du Colombier done:
394*219b2ee8SDavid du Colombier 	t->status &= ~CHECK2;
395*219b2ee8SDavid du Colombier 	return res;
396*219b2ee8SDavid du Colombier }
397*219b2ee8SDavid du Colombier 
398*219b2ee8SDavid du Colombier void
399*219b2ee8SDavid du Colombier varused(Lextok *t, Element *u, int isread)
400*219b2ee8SDavid du Colombier {	int res = 0;
401*219b2ee8SDavid du Colombier 
402*219b2ee8SDavid du Colombier 	if (!t || !t->sym)		return;
403*219b2ee8SDavid du Colombier 	if (dataflow == 1 && isread)	return;
404*219b2ee8SDavid du Colombier 
405*219b2ee8SDavid du Colombier 	res = used_later(t->sym, u);
406*219b2ee8SDavid du Colombier 
407*219b2ee8SDavid du Colombier 	if ((res&1)
408*219b2ee8SDavid du Colombier 	||  (isread && res&4))
409*219b2ee8SDavid du Colombier 		 return;	/* followed by at least one read */
410*219b2ee8SDavid du Colombier 
411*219b2ee8SDavid du Colombier 	printf("%s:%3d: ",
412*219b2ee8SDavid du Colombier 		Same->n->fn->name,
413*219b2ee8SDavid du Colombier 		Same->n->ln);
414*219b2ee8SDavid du Colombier 	if (t->sym->owner) printf("%s.", t->sym->owner->name);
415*219b2ee8SDavid du Colombier 	printf("%s -- (%s)",
416*219b2ee8SDavid du Colombier 		t->sym->name,
417*219b2ee8SDavid du Colombier 		(isread)?"read":"write");
418*219b2ee8SDavid du Colombier 
419*219b2ee8SDavid du Colombier 	if (!res)	{ printf(" none"); printf("\n");exit(0); }
420*219b2ee8SDavid du Colombier 	if (res&2)	printf(" write");
421*219b2ee8SDavid du Colombier 	if (res&4)	printf(" same");
422*219b2ee8SDavid du Colombier 	printf("\n");
423*219b2ee8SDavid du Colombier 
424*219b2ee8SDavid du Colombier }
425*219b2ee8SDavid du Colombier 
426*219b2ee8SDavid du Colombier void
427*219b2ee8SDavid du Colombier varprobe(Element *parent, Lextok *n, Element *q)
428*219b2ee8SDavid du Colombier {
429*219b2ee8SDavid du Colombier 	if (!n) return;
430*219b2ee8SDavid du Colombier 
431*219b2ee8SDavid du Colombier 	Same = parent;
432*219b2ee8SDavid du Colombier 
433*219b2ee8SDavid du Colombier 	/* can't deal with globals, structs, or arrays */
434*219b2ee8SDavid du Colombier 	if (n->sym
435*219b2ee8SDavid du Colombier 	&&  n->sym->context
436*219b2ee8SDavid du Colombier 	&&  n->sym->nel == 1
437*219b2ee8SDavid du Colombier 	&&  n->sym->type != STRUCT
438*219b2ee8SDavid du Colombier 	&&  n->ntyp != PRINT)
439*219b2ee8SDavid du Colombier 		varused(n, q, (!OrIsAsgn && n->ntyp != ASGN));
440*219b2ee8SDavid du Colombier 
441*219b2ee8SDavid du Colombier 	if (n->ntyp == ASGN)
442*219b2ee8SDavid du Colombier 		varprobe(parent, n->lft->lft, q);
443*219b2ee8SDavid du Colombier 	else
444*219b2ee8SDavid du Colombier 		varprobe(parent, n->lft, q);
445*219b2ee8SDavid du Colombier 
446*219b2ee8SDavid du Colombier 	if (n->ntyp == 'r')
447*219b2ee8SDavid du Colombier 		OrIsAsgn = 1;
448*219b2ee8SDavid du Colombier 
449*219b2ee8SDavid du Colombier 	varprobe(parent, n->rgt, q);
450*219b2ee8SDavid du Colombier 
451*219b2ee8SDavid du Colombier 	if (n->ntyp == 'r')
452*219b2ee8SDavid du Colombier 		OrIsAsgn = 0;
453*219b2ee8SDavid du Colombier }
454*219b2ee8SDavid du Colombier 
455*219b2ee8SDavid du Colombier #if 0
456*219b2ee8SDavid du Colombier #define walkprog	varcheck
457*219b2ee8SDavid du Colombier #else
458*219b2ee8SDavid du Colombier #define Varcheck	varcheck
459*219b2ee8SDavid du Colombier #endif
460*219b2ee8SDavid du Colombier 
461*219b2ee8SDavid du Colombier void
462*219b2ee8SDavid du Colombier Varcheck(Element *e, Element *nx)
463*219b2ee8SDavid du Colombier {	SeqList *f; extern Symbol *context;
464*219b2ee8SDavid du Colombier 
465*219b2ee8SDavid du Colombier 	if (!dataflow || !e || e->status&CHECK1)
466*219b2ee8SDavid du Colombier 		return;
467*219b2ee8SDavid du Colombier #ifdef DEBUG
468*219b2ee8SDavid du Colombier 	{	int oln; Symbol *ofn;
469*219b2ee8SDavid du Colombier 		printf("%s:%d -- ", context->name, e->Seqno);
470*219b2ee8SDavid du Colombier 		oln = lineno; ofn = Fname;
471*219b2ee8SDavid du Colombier 		comment(stdout, e->n, 0);
472*219b2ee8SDavid du Colombier 		lineno = oln; Fname = ofn;
473*219b2ee8SDavid du Colombier 		printf(" -- %d:%s\n", e->n->ln, e->n->fn->name);
474*219b2ee8SDavid du Colombier 	}
475*219b2ee8SDavid du Colombier #endif
476*219b2ee8SDavid du Colombier 	e->status |= CHECK1;
477*219b2ee8SDavid du Colombier 
478*219b2ee8SDavid du Colombier 	if (e->n->ntyp == GOTO)
479*219b2ee8SDavid du Colombier 	{	Element *ef = target(e);
480*219b2ee8SDavid du Colombier 		if (ef) varcheck(ef, ef->nxt);
481*219b2ee8SDavid du Colombier 		goto done;
482*219b2ee8SDavid du Colombier 	} else if (e->n->sl && !e->sub)	/* d_step or (non)-atomic */
483*219b2ee8SDavid du Colombier 	{	for (f = e->n->sl; f; f = f->nxt)
484*219b2ee8SDavid du Colombier 		{	f->this->last->nxt = nx;
485*219b2ee8SDavid du Colombier #ifdef DEBUG
486*219b2ee8SDavid du Colombier 			printf("\tPatch1 %d->%d\n",
487*219b2ee8SDavid du Colombier 			f->this->last->seqno, nx?nx->seqno:-1);
488*219b2ee8SDavid du Colombier 			varcheck(f->this->frst, nx);
489*219b2ee8SDavid du Colombier #endif
490*219b2ee8SDavid du Colombier 			f->this->last->nxt = 0;
491*219b2ee8SDavid du Colombier 		}
492*219b2ee8SDavid du Colombier 	} else if (e->sub && e->n->ntyp == IF)	/* if */
493*219b2ee8SDavid du Colombier 	{	for (f = e->sub; f; f = f->nxt)
494*219b2ee8SDavid du Colombier 			varcheck(f->this->frst, nx);
495*219b2ee8SDavid du Colombier 	} else if (e->sub && e->n->ntyp == DO)	/* do */
496*219b2ee8SDavid du Colombier 	{	for (f = e->sub; f; f = f->nxt)
497*219b2ee8SDavid du Colombier 			varcheck(f->this->frst, e);
498*219b2ee8SDavid du Colombier 	} else
499*219b2ee8SDavid du Colombier 	{	varprobe(e, e->n, e->nxt);
500*219b2ee8SDavid du Colombier 	}
501*219b2ee8SDavid du Colombier 	{	Element *ef = huntele(e->nxt, e->status);
502*219b2ee8SDavid du Colombier 		if (ef) varcheck(ef, ef->nxt);
503*219b2ee8SDavid du Colombier 	}
504*219b2ee8SDavid du Colombier done:
505*219b2ee8SDavid du Colombier 	/* e->status &= ~CHECK1 */ ;
506*219b2ee8SDavid du Colombier }
507*219b2ee8SDavid du Colombier 
508*219b2ee8SDavid du Colombier void
509*219b2ee8SDavid du Colombier nested(int n)
510*219b2ee8SDavid du Colombier {	int i;
511*219b2ee8SDavid du Colombier 	for (i = 0; i < n; i++)
512*219b2ee8SDavid du Colombier 		printf("\t");
513*219b2ee8SDavid du Colombier }
514*219b2ee8SDavid du Colombier 
515*219b2ee8SDavid du Colombier void
516*219b2ee8SDavid du Colombier walkprog(Element *e, Element *nx)
517*219b2ee8SDavid du Colombier {	SeqList *f; extern Symbol *context;
518*219b2ee8SDavid du Colombier 	static int Nest=0; int oln;
519*219b2ee8SDavid du Colombier 
520*219b2ee8SDavid du Colombier 	if (!dataflow) return;
521*219b2ee8SDavid du Colombier 	if (!e)
522*219b2ee8SDavid du Colombier 	{	nested(Nest);
523*219b2ee8SDavid du Colombier 		printf("nil\n");
524*219b2ee8SDavid du Colombier 		return;
525*219b2ee8SDavid du Colombier 	}
526*219b2ee8SDavid du Colombier 
527*219b2ee8SDavid du Colombier 	nested(Nest);
528*219b2ee8SDavid du Colombier 	printf("%4d,%4d, %s:%d(%u) -- ",
529*219b2ee8SDavid du Colombier 		e->status, lineno,
530*219b2ee8SDavid du Colombier 		context->name, e->Seqno, e);
531*219b2ee8SDavid du Colombier 	oln = lineno;
532*219b2ee8SDavid du Colombier 	comment(stdout, e->n, 0);
533*219b2ee8SDavid du Colombier 	lineno = oln;
534*219b2ee8SDavid du Colombier 	printf(" -- %d:%s\n", e->n->ln, e->n->fn->name);
535*219b2ee8SDavid du Colombier 
536*219b2ee8SDavid du Colombier 	if (e->status&CHECK1)
537*219b2ee8SDavid du Colombier 	{	nested(Nest);
538*219b2ee8SDavid du Colombier 		printf("seenbefore\n");
539*219b2ee8SDavid du Colombier 		return;
540*219b2ee8SDavid du Colombier 	}
541*219b2ee8SDavid du Colombier 
542*219b2ee8SDavid du Colombier 	e->status |= CHECK1;
543*219b2ee8SDavid du Colombier 
544*219b2ee8SDavid du Colombier 	if (e->n->ntyp == GOTO)
545*219b2ee8SDavid du Colombier 	{	Element *ef = target(e);
546*219b2ee8SDavid du Colombier 		if (ef) walkprog(ef, ef->nxt);
547*219b2ee8SDavid du Colombier 	} else if (e->n->sl && !e->sub)	/* ATOMIC, NON_ATOMIC, D_STEP */
548*219b2ee8SDavid du Colombier 	{	int cnt;
549*219b2ee8SDavid du Colombier 
550*219b2ee8SDavid du Colombier 		for (f = e->n->sl, cnt=1; f; f = f->nxt, cnt++)
551*219b2ee8SDavid du Colombier 		{	Nest++;
552*219b2ee8SDavid du Colombier 			nested(Nest);
553*219b2ee8SDavid du Colombier 			printf("---a>%d:\n", cnt);
554*219b2ee8SDavid du Colombier #ifdef DEBUG
555*219b2ee8SDavid du Colombier 			printf("\tPatch0 %d->%d\n",
556*219b2ee8SDavid du Colombier 			f->this->last->seqno, nx?nx->seqno:-1);
557*219b2ee8SDavid du Colombier 			f->this->last->nxt = nx;
558*219b2ee8SDavid du Colombier 			walkprog(f->this->frst, nx);
559*219b2ee8SDavid du Colombier #endif
560*219b2ee8SDavid du Colombier 		/*	f->this->last->nxt = 0;		*/
561*219b2ee8SDavid du Colombier 			Nest--;
562*219b2ee8SDavid du Colombier 		}
563*219b2ee8SDavid du Colombier 	} else if (e->sub && e->n->ntyp == IF)
564*219b2ee8SDavid du Colombier 	{	int cnt;
565*219b2ee8SDavid du Colombier 		for (f = e->sub, cnt=1; f; f = f->nxt, cnt++)
566*219b2ee8SDavid du Colombier 		{	Nest++;
567*219b2ee8SDavid du Colombier 			nested(Nest);
568*219b2ee8SDavid du Colombier 			printf("---s>%d:\n", cnt);
569*219b2ee8SDavid du Colombier 			walkprog(f->this->frst, nx);
570*219b2ee8SDavid du Colombier 			Nest--;
571*219b2ee8SDavid du Colombier 		}
572*219b2ee8SDavid du Colombier 	} else if (e->sub && e->n->ntyp == DO)
573*219b2ee8SDavid du Colombier 	{	int cnt;
574*219b2ee8SDavid du Colombier 		for (f = e->sub, cnt=1; f; f = f->nxt, cnt++)
575*219b2ee8SDavid du Colombier 		{	Nest++;
576*219b2ee8SDavid du Colombier 			nested(Nest);
577*219b2ee8SDavid du Colombier 			printf("---s>%d:\n", cnt);
578*219b2ee8SDavid du Colombier 			walkprog(f->this->frst, e);
579*219b2ee8SDavid du Colombier 			Nest--;
580*219b2ee8SDavid du Colombier 		}
581*219b2ee8SDavid du Colombier 	}
582*219b2ee8SDavid du Colombier 	{	Element *ef = huntele(e->nxt, e->status);
583*219b2ee8SDavid du Colombier 		if (ef) walkprog(ef, ef->nxt);
584*219b2ee8SDavid du Colombier 	}
585*219b2ee8SDavid du Colombier 	e->status &= ~CHECK1;
586*219b2ee8SDavid du Colombier }
587