Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/***** spin: main.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 <stdlib.h>
13
#include "spin.h"
14
#include "version.h"
15
#include <sys/types.h>
16
#include <sys/stat.h>
17
#include <signal.h>
18
/* #include <malloc.h> */
19
#include <time.h>
20
#ifdef PC
21
#include <io.h>
22
extern int unlink(const char *);
23
#else
24
#include <unistd.h>
25
#endif
26
#include "y.tab.h"
27
 
28
extern int	DstepStart, lineno, tl_terse;
29
extern FILE	*yyin, *yyout, *tl_out;
30
extern Symbol	*context;
31
extern char	*claimproc;
32
extern void	repro_src(void);
33
extern void	qhide(int);
34
extern char	CurScope[MAXSCOPESZ];
35
 
36
Symbol	*Fname, *oFname;
37
 
38
int	Etimeouts;	/* nr timeouts in program */
39
int	Ntimeouts;	/* nr timeouts in never claim */
40
int	analyze, columns, dumptab, has_remote, has_remvar;
41
int	interactive, jumpsteps, m_loss, nr_errs, cutoff;
42
int	s_trail, ntrail, verbose, xspin, notabs, rvopt;
43
int	no_print, no_wrapup, Caccess, limited_vis, like_java;
44
int	separate;	/* separate compilation */
45
int	export_ast;	/* pangen5.c */
46
int	old_scope_rules;	/* use pre 5.3.0 rules */
47
int	split_decl = 1, product, Strict;
48
 
49
int	merger = 1, deadvar = 1;
50
int	ccache = 0; /* oyvind teig: 5.2.0 case caching off by default */
51
 
52
static int preprocessonly, SeedUsed;
53
static int seedy;	/* be verbose about chosen seed */
54
static int inlineonly;	/* show inlined code */
55
static int dataflow = 1;
56
 
57
#if 0
58
meaning of flags on verbose:
59
	1	-g global variable values
60
	2	-l local variable values
61
	4	-p all process actions
62
	8	-r receives
63
	16	-s sends
64
	32	-v verbose
65
	64	-w very verbose
66
#endif
67
 
68
static char	Operator[] = "operator: ";
69
static char	Keyword[]  = "keyword: ";
70
static char	Function[] = "function-name: ";
71
static char	**add_ltl  = (char **) 0;
72
static char	**ltl_file = (char **) 0;
73
static char	**nvr_file = (char **) 0;
74
static char	*ltl_claims = (char *) 0;
75
static FILE	*fd_ltl = (FILE *) 0;
76
static char	*PreArg[64];
77
static int	PreCnt = 0;
78
static char	out1[64];
79
 
80
char	**trailfilename;	/* new option 'k' */
81
 
82
void	explain(int);
83
 
84
	/* to use visual C++:
85
		#define CPP	"CL -E/E"
86
	   or call spin as:	"spin -PCL  -E/E"
87
 
88
	   on OS2:
89
		#define CPP	"icc -E/Pd+ -E/Q+"
90
	   or call spin as:	"spin -Picc -E/Pd+ -E/Q+"
91
	*/
92
#ifndef CPP
93
	#if defined(PC) || defined(MAC)
94
		#define CPP	"gcc -E -x c"	/* most systems have gcc or cpp */
95
		/* if gcc-4 is available, this setting is modified below */
96
	#else
97
		#ifdef SOLARIS
98
			#define CPP	"/usr/ccs/lib/cpp"
99
		#else
100
			#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
101
				#define CPP	"cpp"
102
			#else
103
				#define CPP	"/bin/cpp"	/* classic Unix systems */
104
			#endif
105
		#endif
106
	#endif
107
#endif
108
 
109
static char	*PreProc = CPP;
110
extern int	depth; /* at least some steps were made */
111
 
112
void
113
alldone(int estatus)
114
{
115
	if (preprocessonly == 0
116
	&&  strlen(out1) > 0)
117
		(void) unlink((const char *)out1);
118
 
119
	if (seedy && !analyze && !export_ast
120
	&& !s_trail && !preprocessonly && depth > 0)
121
		printf("seed used: %d\n", SeedUsed);
122
 
123
	if (xspin && (analyze || s_trail))
124
	{	if (estatus)
125
			printf("spin: %d error(s) - aborting\n",
126
			estatus);
127
		else
128
			printf("Exit-Status 0\n");
129
	}
130
	exit(estatus);
131
}
132
 
133
void
134
preprocess(char *a, char *b, int a_tmp)
135
{	char precmd[1024], cmd[2048]; int i;
136
#if defined(WIN32) || defined(WIN64)
137
	struct _stat x;
138
/*	struct stat x;	*/
139
#endif
140
#ifdef PC
141
	extern int try_zpp(char *, char *);
142
	if (PreCnt == 0 && try_zpp(a, b))
143
	{	goto out;
144
	}
145
#endif
146
#if defined(WIN32) || defined(WIN64)
147
	if (strncmp(PreProc, "gcc -E -x c", strlen("gcc -E -x c")) == 0)
148
	{	if (stat("/bin/gcc-4.exe", (struct stat *)&x) == 0	/* for PCs with cygwin */
149
		||  stat("c:/cygwin/bin/gcc-4.exe", (struct stat *)&x) == 0)
150
		{	PreProc = "gcc-4 -E -x c";
151
		} else if (stat("/bin/gcc-3.exe", (struct stat *)&x) == 0
152
		       ||  stat("c:/cygwin/bin/gcc-3.exe", (struct stat *)&x) == 0)
153
		{	PreProc = "gcc-3 -E -x c";
154
	}	}
155
#endif
156
	strcpy(precmd, PreProc);
157
	for (i = 1; i <= PreCnt; i++)
158
	{	strcat(precmd, " ");
159
		strcat(precmd, PreArg[i]);
160
	}
161
	if (strlen(precmd) > sizeof(precmd))
162
	{	fprintf(stdout, "spin: too many -D args, aborting\n");
163
		alldone(1);
164
	}
165
	sprintf(cmd, "%s %s > %s", precmd, a, b);
166
	if (system((const char *)cmd))
167
	{	(void) unlink((const char *) b);
168
		if (a_tmp) (void) unlink((const char *) a);
169
		fprintf(stdout, "spin: preprocessing failed\n");	/* 4.1.2 was stderr */
170
		alldone(1); /* no return, error exit */
171
	}
172
#ifdef PC
173
out:
174
#endif
175
	if (a_tmp) (void) unlink((const char *) a);
176
}
177
 
178
void
179
usage(void)
180
{
181
	printf("use: spin [-option] ... [-option] file\n");
182
	printf("\tNote: file must always be the last argument\n");
183
	printf("\t-A apply slicing algorithm\n");
184
	printf("\t-a generate a verifier in pan.c\n");
185
	printf("\t-B no final state details in simulations\n");
186
	printf("\t-b don't execute printfs in simulation\n");
187
	printf("\t-C print channel access info (combine with -g etc.)\n");
188
	printf("\t-c columnated -s -r simulation output\n");
189
	printf("\t-d produce symbol-table information\n");
190
	printf("\t-Dyyy pass -Dyyy to the preprocessor\n");
191
	printf("\t-Eyyy pass yyy to the preprocessor\n");
192
	printf("\t-e compute synchronous product of multiple never claims (modified by -L)\n");
193
	printf("\t-f \"..formula..\"  translate LTL ");
194
	printf("into never claim\n");
195
	printf("\t-F file  like -f, but with the LTL formula stored in a 1-line file\n");
196
	printf("\t-g print all global variables\n");
197
	printf("\t-h at end of run, print value of seed for random nr generator used\n");
198
	printf("\t-i interactive (random simulation)\n");
199
	printf("\t-I show result of inlining and preprocessing\n");
200
	printf("\t-J reverse eval order of nested unlesses\n");
201
	printf("\t-jN skip the first N steps ");
202
	printf("in simulation trail\n");
203
	printf("\t-k fname use the trailfile stored in file fname, see also -t\n");
204
	printf("\t-L when using -e, use strict language intersection\n");
205
	printf("\t-l print all local variables\n");
206
	printf("\t-M print msc-flow in Postscript\n");
207
	printf("\t-m lose msgs sent to full queues\n");
208
	printf("\t-N fname use never claim stored in file fname\n");
209
	printf("\t-nN seed for random nr generator\n");
210
	printf("\t-O use old scope rules (pre 5.3.0)\n");
211
	printf("\t-o1 turn off dataflow-optimizations in verifier\n");
212
	printf("\t-o2 don't hide write-only variables in verifier\n");
213
	printf("\t-o3 turn off statement merging in verifier\n");
214
	printf("\t-o4 turn on rendezvous optiomizations in verifier\n");
215
	printf("\t-o5 turn on case caching (reduces size of pan.m, but affects reachability reports)\n");
216
	printf("\t-Pxxx use xxx for preprocessing\n");
217
	printf("\t-p print all statements\n");
218
	printf("\t-qN suppress io for queue N in printouts\n");
219
	printf("\t-r print receive events\n");
220
	printf("\t-S1 and -S2 separate pan source for claim and model\n");
221
	printf("\t-s print send events\n");
222
	printf("\t-T do not indent printf output\n");
223
	printf("\t-t[N] follow [Nth] simulation trail, see also -k\n");
224
	printf("\t-Uyyy pass -Uyyy to the preprocessor\n");
225
	printf("\t-uN stop a simulation run after N steps\n");
226
	printf("\t-v verbose, more warnings\n");
227
	printf("\t-w very verbose (when combined with -l or -g)\n");
228
	printf("\t-[XYZ] reserved for use by xspin interface\n");
229
	printf("\t-V print version number and exit\n");
230
	alldone(1);
231
}
232
 
233
void
234
optimizations(int nr)
235
{
236
	switch (nr) {
237
	case '1':
238
		dataflow = 1 - dataflow; /* dataflow */
239
		if (verbose&32)
240
		printf("spin: dataflow optimizations turned %s\n",
241
			dataflow?"on":"off");
242
		break;
243
	case '2':
244
		/* dead variable elimination */
245
		deadvar = 1 - deadvar;
246
		if (verbose&32)
247
		printf("spin: dead variable elimination turned %s\n",
248
			deadvar?"on":"off");
249
		break;
250
	case '3':
251
		/* statement merging */
252
		merger = 1 - merger;
253
		if (verbose&32)
254
		printf("spin: statement merging turned %s\n",
255
			merger?"on":"off");
256
		break;
257
 
258
	case '4':
259
		/* rv optimization */
260
		rvopt = 1 - rvopt;
261
		if (verbose&32)
262
		printf("spin: rendezvous optimization turned %s\n",
263
			rvopt?"on":"off");
264
		break;
265
	case '5':
266
		/* case caching */
267
		ccache = 1 - ccache;
268
		if (verbose&32)
269
		printf("spin: case caching turned %s\n",
270
			ccache?"on":"off");
271
		break;
272
	default:
273
		printf("spin: bad or missing parameter on -o\n");
274
		usage();
275
		break;
276
	}
277
}
278
 
279
int
280
main(int argc, char *argv[])
281
{	Symbol *s;
282
	int T = (int) time((time_t *)0);
283
	int usedopts = 0;
284
	extern void ana_src(int, int);
285
 
286
	yyin  = stdin;
287
	yyout = stdout;
288
	tl_out = stdout;
289
	strcpy(CurScope, "_");
290
 
291
	/* unused flags: y, z, G, L, Q, R, W */
292
	while (argc > 1 && argv[1][0] == '-')
293
	{	switch (argv[1][1]) {
294
		/* generate code for separate compilation: S1 or S2 */
295
		case 'S': separate = atoi(&argv[1][2]);
296
			  /* fall through */
297
		case 'a': analyze  = 1; break;
298
		case 'A': export_ast = 1; break;
299
		case 'B': no_wrapup = 1; break;
300
		case 'b': no_print = 1; break;
301
		case 'C': Caccess = 1; break;
302
		case 'c': columns = 1; break;
303
		case 'D': PreArg[++PreCnt] = (char *) &argv[1][0];
304
			  break;	/* define */
305
		case 'd': dumptab =  1; break;
306
		case 'E': PreArg[++PreCnt] = (char *) &argv[1][2];
307
			  break;
308
		case 'e': product++; break; /* see also 'L' */
309
		case 'F': ltl_file = (char **) (argv+2);
310
			  argc--; argv++; break;
311
		case 'f': add_ltl = (char **) argv;
312
			  argc--; argv++; break;
313
		case 'g': verbose +=  1; break;
314
		case 'h': seedy = 1; break;
315
		case 'i': interactive = 1; break;
316
		case 'I': inlineonly = 1; break;
317
		case 'J': like_java = 1; break;
318
		case 'j': jumpsteps = atoi(&argv[1][2]); break;
319
		case 'k': s_trail = 1;
320
			  trailfilename = (char **) (argv+2);
321
			  argc--; argv++; break;
322
		case 'L': Strict++; break; /* modified -e */
323
		case 'l': verbose +=  2; break;
324
		case 'M': columns = 2; break;
325
		case 'm': m_loss   =  1; break;
326
		case 'N': nvr_file = (char **) (argv+2);
327
			  argc--; argv++; break;
328
		case 'n': T = atoi(&argv[1][2]); tl_terse = 1; break;
329
		case 'O': old_scope_rules = 1; break;
330
		case 'o': optimizations(argv[1][2]);
331
			  usedopts = 1; break;
332
		case 'P': PreProc = (char *) &argv[1][2]; break;
333
		case 'p': verbose +=  4; break;
334
		case 'q': if (isdigit((int) argv[1][2]))
335
				qhide(atoi(&argv[1][2]));
336
			  break;
337
		case 'r': verbose +=  8; break;
338
		case 's': verbose += 16; break;
339
		case 'T': notabs = 1; break;
340
		case 't': s_trail  =  1;
341
			  if (isdigit((int)argv[1][2]))
342
				ntrail = atoi(&argv[1][2]);
343
			  break;
344
		case 'U': PreArg[++PreCnt] = (char *) &argv[1][0];
345
			  break;	/* undefine */
346
		case 'u': cutoff = atoi(&argv[1][2]); break;	/* new 3.4.14 */
347
		case 'v': verbose += 32; break;
348
		case 'V': printf("%s\n", SpinVersion);
349
			  alldone(0);
350
			  break;
351
		case 'w': verbose += 64; break;
352
#if 0
353
		case 'x': split_decl = 0; break;	/* experimental */
354
#endif
355
		case 'X': xspin = notabs = 1;
356
#ifndef PC
357
			  signal(SIGPIPE, alldone); /* not posix... */
358
#endif
359
			  break;
360
		case 'Y': limited_vis = 1; break;	/* used by xspin */
361
		case 'Z': preprocessonly = 1; break;	/* used by xspin */
362
 
363
		default : usage(); break;
364
		}
365
		argc--; argv++;
366
	}
367
 
368
	if (usedopts && !analyze)
369
		printf("spin: warning -o[123] option ignored in simulations\n");
370
 
371
	if (ltl_file)
372
	{	char formula[4096];
373
		add_ltl = ltl_file-2; add_ltl[1][1] = 'f';
374
		if (!(tl_out = fopen(*ltl_file, "r")))
375
		{	printf("spin: cannot open %s\n", *ltl_file);
376
			alldone(1);
377
		}
378
		if (!fgets(formula, 4096, tl_out))
379
		{	printf("spin: cannot read %s\n", *ltl_file);
380
		}
381
		fclose(tl_out);
382
		tl_out = stdout;
383
		*ltl_file = (char *) formula;
384
	}
385
	if (argc > 1)
386
	{	FILE *fd = stdout;
387
		char cmd[512], out2[512];
388
 
389
		/* must remain in current dir */
390
		strcpy(out1, "pan.pre");
391
 
392
		if (add_ltl || nvr_file)
393
		{	sprintf(out2, "%s.nvr", argv[1]);
394
			if ((fd = fopen(out2, MFLAGS)) == NULL)
395
			{	printf("spin: cannot create tmp file %s\n",
396
					out2);
397
				alldone(1);
398
			}
399
			fprintf(fd, "#include \"%s\"\n", argv[1]);
400
		}
401
 
402
		if (add_ltl)
403
		{	tl_out = fd;
404
			nr_errs = tl_main(2, add_ltl);
405
			fclose(fd);
406
			preprocess(out2, out1, 1);
407
		} else if (nvr_file)
408
		{	fprintf(fd, "#include \"%s\"\n", *nvr_file);
409
			fclose(fd);
410
			preprocess(out2, out1, 1);
411
		} else
412
		{	preprocess(argv[1], out1, 0);
413
		}
414
 
415
		if (preprocessonly)
416
			alldone(0);
417
 
418
		if (!(yyin = fopen(out1, "r")))
419
		{	printf("spin: cannot open %s\n", out1);
420
			alldone(1);
421
		}
422
 
423
		if (strncmp(argv[1], "progress", (size_t) 8) == 0
424
		||  strncmp(argv[1], "accept", (size_t) 6) == 0)
425
			sprintf(cmd, "_%s", argv[1]);
426
		else
427
			strcpy(cmd, argv[1]);
428
		oFname = Fname = lookup(cmd);
429
		if (oFname->name[0] == '\"')
430
		{	int i = (int) strlen(oFname->name);
431
			oFname->name[i-1] = '\0';
432
			oFname = lookup(&oFname->name[1]);
433
		}
434
	} else
435
	{	oFname = Fname = lookup("<stdin>");
436
		if (add_ltl)
437
		{	if (argc > 0)
438
				exit(tl_main(2, add_ltl));
439
			printf("spin: missing argument to -f\n");
440
			alldone(1);
441
		}
442
		printf("%s\n", SpinVersion);
443
		fprintf(stderr, "spin: error, no filename specified");
444
		fflush(stdout);
445
		alldone(1);
446
	}
447
	if (columns == 2)
448
	{	extern void putprelude(void);
449
		if (xspin || verbose&(1|4|8|16|32))
450
		{	printf("spin: -c precludes all flags except -t\n");
451
			alldone(1);
452
		}
453
		putprelude();
454
	}
455
	if (columns && !(verbose&8) && !(verbose&16))
456
		verbose += (8+16);
457
	if (columns == 2 && limited_vis)
458
		verbose += (1+4);
459
	Srand((unsigned int) T);	/* defined in run.c */
460
	SeedUsed = T;
461
	s = lookup("_");	s->type = PREDEF; /* write-only global var */
462
	s = lookup("_p");	s->type = PREDEF;
463
	s = lookup("_pid");	s->type = PREDEF;
464
	s = lookup("_last");	s->type = PREDEF;
465
	s = lookup("_nr_pr");	s->type = PREDEF; /* new 3.3.10 */
466
 
467
	yyparse();
468
	fclose(yyin);
469
 
470
	if (ltl_claims)
471
	{	Symbol *r;
472
		fclose(fd_ltl);
473
		if (!(yyin = fopen(ltl_claims, "r")))
474
		{	fatal("cannot open %s", ltl_claims);
475
		}
476
		r = oFname;
477
		oFname = Fname = lookup(ltl_claims);
478
		lineno = 0;
479
		yyparse();
480
		fclose(yyin);
481
		oFname = Fname = r;
482
		if (0)
483
		{	(void) unlink(ltl_claims);
484
	}	}
485
 
486
	loose_ends();
487
 
488
	if (inlineonly)
489
	{	repro_src();
490
		return 0;
491
	}
492
 
493
	chanaccess();
494
	if (!Caccess)
495
	{	if (!s_trail && (dataflow || merger))
496
			ana_src(dataflow, merger);
497
		sched();
498
		alldone(nr_errs);
499
	}
500
	return 0;
501
}
502
 
503
void
504
ltl_list(char *nm, char *fm)
505
{
506
	if (analyze || dumptab)	/* when generating pan.c only */
507
	{	if (!ltl_claims)
508
		{	ltl_claims = "_spin_nvr.tmp";
509
			if ((fd_ltl = fopen(ltl_claims, MFLAGS)) == NULL)
510
			{	fatal("cannot open tmp file %s", ltl_claims);
511
			}
512
			tl_out = fd_ltl;
513
		}
514
 
515
		add_ltl = (char **) emalloc(5 * sizeof(char *));
516
		add_ltl[1] = "-c";
517
		add_ltl[2] = nm;
518
		add_ltl[3] = "-f";
519
		add_ltl[4] = (char *) emalloc(strlen(fm)+4);
520
		strcpy(add_ltl[4], "!(");
521
		strcat(add_ltl[4], fm);
522
		strcat(add_ltl[4], ")");
523
		/* add_ltl[4] = fm; */
524
 
525
		nr_errs += tl_main(4, add_ltl);
526
 
527
		fflush(tl_out);
528
		/* should read this file after the main file is read */
529
	}
530
}
531
 
532
int
533
yywrap(void)	/* dummy routine */
534
{
535
	return 1;
536
}
537
 
538
void
539
non_fatal(char *s1, char *s2)
540
{	extern char yytext[];
541
 
542
	printf("spin: %s:%d, Error: ",
543
		oFname?oFname->name:"nofilename", lineno);
544
	if (s2)
545
		printf(s1, s2);
546
	else
547
		printf(s1);
548
	if (strlen(yytext)>1)
549
		printf(" near '%s'", yytext);
550
	printf("\n");
551
	nr_errs++;
552
}
553
 
554
void
555
fatal(char *s1, char *s2)
556
{
557
	non_fatal(s1, s2);
558
	(void) unlink("pan.b");
559
	(void) unlink("pan.c");
560
	(void) unlink("pan.h");
561
	(void) unlink("pan.m");
562
	(void) unlink("pan.t");
563
	(void) unlink("pan.pre");
564
	alldone(1);
565
}
566
 
567
char *
568
emalloc(size_t n)
569
{	char *tmp;
570
	static unsigned long cnt = 0;
571
 
572
	if (n == 0)
573
		return NULL;	/* robert shelton 10/20/06 */
574
 
575
	if (!(tmp = (char *) malloc(n)))
576
	{	printf("spin: allocated %ld Gb, wanted %d bytes more\n",
577
			cnt/(1024*1024*1024), (int) n);
578
		fatal("not enough memory", (char *)0);
579
	}
580
	cnt += (unsigned long) n;
581
	memset(tmp, 0, n);
582
	return tmp;
583
}
584
 
585
void
586
trapwonly(Lextok *n /* , char *unused */)
587
{	extern int realread;
588
	short i = (n->sym)?n->sym->type:0;
589
 
590
	if (i != MTYPE
591
	&&  i != BIT
592
	&&  i != BYTE
593
	&&  i != SHORT
594
	&&  i != INT
595
	&&  i != UNSIGNED)
596
		return;
597
 
598
	if (realread)
599
	n->sym->hidden |= 128;	/* var is read at least once */
600
}
601
 
602
void
603
setaccess(Symbol *sp, Symbol *what, int cnt, int t)
604
{	Access *a;
605
 
606
	for (a = sp->access; a; a = a->lnk)
607
		if (a->who == context
608
		&&  a->what == what
609
		&&  a->cnt == cnt
610
		&&  a->typ == t)
611
			return;
612
 
613
	a = (Access *) emalloc(sizeof(Access));
614
	a->who = context;
615
	a->what = what;
616
	a->cnt = cnt;
617
	a->typ = t;
618
	a->lnk = sp->access;
619
	sp->access = a;
620
}
621
 
622
Lextok *
623
nn(Lextok *s, int t, Lextok *ll, Lextok *rl)
624
{	Lextok *n = (Lextok *) emalloc(sizeof(Lextok));
625
	static int warn_nn = 0;
626
 
627
	n->uiid = is_inline();	/* record origin of the statement */
628
	n->ntyp = (short) t;
629
	if (s && s->fn)
630
	{	n->ln = s->ln;
631
		n->fn = s->fn;
632
	} else if (rl && rl->fn)
633
	{	n->ln = rl->ln;
634
		n->fn = rl->fn;
635
	} else if (ll && ll->fn)
636
	{	n->ln = ll->ln;
637
		n->fn = ll->fn;
638
	} else
639
	{	n->ln = lineno;
640
		n->fn = Fname;
641
	}
642
	if (s) n->sym  = s->sym;
643
	n->lft  = ll;
644
	n->rgt  = rl;
645
	n->indstep = DstepStart;
646
 
647
	if (t == TIMEOUT) Etimeouts++;
648
 
649
	if (!context) return n;
650
 
651
	if (t == 'r' || t == 's')
652
		setaccess(n->sym, ZS, 0, t);
653
	if (t == 'R')
654
		setaccess(n->sym, ZS, 0, 'P');
655
 
656
	if (context->name == claimproc)
657
	{	int forbidden = separate;
658
		switch (t) {
659
		case ASGN:
660
			printf("spin: Warning, never claim has side-effect\n");
661
			break;
662
		case 'r': case 's':
663
			non_fatal("never claim contains i/o stmnts",(char *)0);
664
			break;
665
		case TIMEOUT:
666
			/* never claim polls timeout */
667
			if (Ntimeouts && Etimeouts)
668
				forbidden = 0;
669
			Ntimeouts++; Etimeouts--;
670
			break;
671
		case LEN: case EMPTY: case FULL:
672
		case 'R': case NFULL: case NEMPTY:
673
			/* status becomes non-exclusive */
674
			if (n->sym && !(n->sym->xu&XX))
675
			{	n->sym->xu |= XX;
676
				if (separate == 2) {
677
				printf("spin: warning, make sure that the S1 model\n");
678
				printf("      also polls channel '%s' in its claim\n",
679
				n->sym->name); 
680
			}	}
681
			forbidden = 0;
682
			break;
683
		case 'c':
684
			AST_track(n, 0);	/* register as a slice criterion */
685
			/* fall thru */
686
		default:
687
			forbidden = 0;
688
			break;
689
		}
690
		if (forbidden)
691
		{	printf("spin: never, saw "); explain(t); printf("\n");
692
			fatal("incompatible with separate compilation",(char *)0);
693
		}
694
	} else if ((t == ENABLED || t == PC_VAL) && !(warn_nn&t))
695
	{	printf("spin: Warning, using %s outside never claim\n",
696
			(t == ENABLED)?"enabled()":"pc_value()");
697
		warn_nn |= t;
698
	} else if (t == NONPROGRESS)
699
	{	fatal("spin: Error, using np_ outside never claim\n", (char *)0);
700
	}
701
	return n;
702
}
703
 
704
Lextok *
705
rem_lab(Symbol *a, Lextok *b, Symbol *c)	/* proctype name, pid, label name */
706
{	Lextok *tmp1, *tmp2, *tmp3;
707
 
708
	has_remote++;
709
	c->type = LABEL;	/* refered to in global context here */
710
	fix_dest(c, a);		/* in case target of rem_lab is jump */
711
	tmp1 = nn(ZN, '?',   b, ZN); tmp1->sym = a;
712
	tmp1 = nn(ZN, 'p', tmp1, ZN);
713
	tmp1->sym = lookup("_p");
714
	tmp2 = nn(ZN, NAME,  ZN, ZN); tmp2->sym = a;
715
	tmp3 = nn(ZN, 'q', tmp2, ZN); tmp3->sym = c;
716
	return nn(ZN, EQ, tmp1, tmp3);
717
#if 0
718
	      .---------------EQ-------.
719
	     /                          \
720
	   'p' -sym-> _p               'q' -sym-> c (label name)
721
	   /                           /
722
	 '?' -sym-> a (proctype)     NAME -sym-> a (proctype name)
723
	 / 
724
	b (pid expr)
725
#endif
726
}
727
 
728
Lextok *
729
rem_var(Symbol *a, Lextok *b, Symbol *c, Lextok *ndx)
730
{	Lextok *tmp1;
731
 
732
	has_remote++;
733
	has_remvar++;
734
	dataflow = 0;	/* turn off dead variable resets 4.2.5 */
735
	tmp1 = nn(ZN, '?', b, ZN); tmp1->sym = a;
736
	tmp1 = nn(ZN, 'p', tmp1, ndx);
737
	tmp1->sym = c;
738
	return tmp1;
739
#if 0
740
	cannot refer to struct elements
741
	only to scalars and arrays
742
 
743
	    'p' -sym-> c (variable name)
744
	    / \______  possible arrayindex on c
745
	   /
746
	 '?' -sym-> a (proctype)
747
	 / 
748
	b (pid expr)
749
#endif
750
}
751
 
752
void
753
explain(int n)
754
{	FILE *fd = stdout;
755
	switch (n) {
756
	default:	if (n > 0 && n < 256)
757
				fprintf(fd, "'%c' = ", n);
758
			fprintf(fd, "%d", n);
759
			break;
760
	case '\b':	fprintf(fd, "\\b"); break;
761
	case '\t':	fprintf(fd, "\\t"); break;
762
	case '\f':	fprintf(fd, "\\f"); break;
763
	case '\n':	fprintf(fd, "\\n"); break;
764
	case '\r':	fprintf(fd, "\\r"); break;
765
	case 'c':	fprintf(fd, "condition"); break;
766
	case 's':	fprintf(fd, "send"); break;
767
	case 'r':	fprintf(fd, "recv"); break;
768
	case 'R':	fprintf(fd, "recv poll %s", Operator); break;
769
	case '@':	fprintf(fd, "@"); break;
770
	case '?':	fprintf(fd, "(x->y:z)"); break;
771
#if 1
772
	case NEXT:	fprintf(fd, "X"); break;
773
	case ALWAYS:	fprintf(fd, "[]"); break;
774
	case EVENTUALLY: fprintf(fd, "<>"); break;
775
	case IMPLIES:	fprintf(fd, "->"); break;
776
	case EQUIV:	fprintf(fd, "<->"); break;
777
	case UNTIL:	fprintf(fd, "U"); break;
778
	case WEAK_UNTIL: fprintf(fd, "W"); break;
779
	case IN: fprintf(fd, "%sin", Keyword); break;
780
#endif
781
	case ACTIVE:	fprintf(fd, "%sactive",	Keyword); break;
782
	case AND:	fprintf(fd, "%s&&",	Operator); break;
783
	case ASGN:	fprintf(fd, "%s=",	Operator); break;
784
	case ASSERT:	fprintf(fd, "%sassert",	Function); break;
785
	case ATOMIC:	fprintf(fd, "%satomic",	Keyword); break;
786
	case BREAK:	fprintf(fd, "%sbreak",	Keyword); break;
787
	case C_CODE:	fprintf(fd, "%sc_code",	Keyword); break;
788
	case C_DECL:	fprintf(fd, "%sc_decl",	Keyword); break;
789
	case C_EXPR:	fprintf(fd, "%sc_expr",	Keyword); break;
790
	case C_STATE:	fprintf(fd, "%sc_state",Keyword); break;
791
	case C_TRACK:	fprintf(fd, "%sc_track",Keyword); break;
792
	case CLAIM:	fprintf(fd, "%snever",	Keyword); break;
793
	case CONST:	fprintf(fd, "a constant"); break;
794
	case DECR:	fprintf(fd, "%s--",	Operator); break;
795
	case D_STEP:	fprintf(fd, "%sd_step",	Keyword); break;
796
	case D_PROCTYPE: fprintf(fd, "%sd_proctype", Keyword); break;
797
	case DO:	fprintf(fd, "%sdo",	Keyword); break;
798
	case DOT:	fprintf(fd, "."); break;
799
	case ELSE:	fprintf(fd, "%selse",	Keyword); break;
800
	case EMPTY:	fprintf(fd, "%sempty",	Function); break;
801
	case ENABLED:	fprintf(fd, "%senabled",Function); break;
802
	case EQ:	fprintf(fd, "%s==",	Operator); break;
803
	case EVAL:	fprintf(fd, "%seval",	Function); break;
804
	case FI:	fprintf(fd, "%sfi",	Keyword); break;
805
	case FULL:	fprintf(fd, "%sfull",	Function); break;
806
	case GE:	fprintf(fd, "%s>=",	Operator); break;
807
	case GOTO:	fprintf(fd, "%sgoto",	Keyword); break;
808
	case GT:	fprintf(fd, "%s>",	Operator); break;
809
	case HIDDEN:	fprintf(fd, "%shidden",	Keyword); break;
810
	case IF:	fprintf(fd, "%sif",	Keyword); break;
811
	case INCR:	fprintf(fd, "%s++",	Operator); break;
812
	case INAME:	fprintf(fd, "inline name"); break;
813
	case INLINE:	fprintf(fd, "%sinline",	Keyword); break;
814
	case INIT:	fprintf(fd, "%sinit",	Keyword); break;
815
	case ISLOCAL:	fprintf(fd, "%slocal",  Keyword); break;
816
	case LABEL:	fprintf(fd, "a label-name"); break;
817
	case LE:	fprintf(fd, "%s<=",	Operator); break;
818
	case LEN:	fprintf(fd, "%slen",	Function); break;
819
	case LSHIFT:	fprintf(fd, "%s<<",	Operator); break;
820
	case LT:	fprintf(fd, "%s<",	Operator); break;
821
	case MTYPE:	fprintf(fd, "%smtype",	Keyword); break;
822
	case NAME:	fprintf(fd, "an identifier"); break;
823
	case NE:	fprintf(fd, "%s!=",	Operator); break;
824
	case NEG:	fprintf(fd, "%s! (not)",Operator); break;
825
	case NEMPTY:	fprintf(fd, "%snempty",	Function); break;
826
	case NFULL:	fprintf(fd, "%snfull",	Function); break;
827
	case NON_ATOMIC: fprintf(fd, "sub-sequence"); break;
828
	case NONPROGRESS: fprintf(fd, "%snp_",	Function); break;
829
	case OD:	fprintf(fd, "%sod",	Keyword); break;
830
	case OF:	fprintf(fd, "%sof",	Keyword); break;
831
	case OR:	fprintf(fd, "%s||",	Operator); break;
832
	case O_SND:	fprintf(fd, "%s!!",	Operator); break;
833
	case PC_VAL:	fprintf(fd, "%spc_value",Function); break;
834
	case PNAME:	fprintf(fd, "process name"); break;
835
	case PRINT:	fprintf(fd, "%sprintf",	Function); break;
836
	case PRINTM:	fprintf(fd, "%sprintm",	Function); break;
837
	case PRIORITY:	fprintf(fd, "%spriority", Keyword); break;
838
	case PROCTYPE:	fprintf(fd, "%sproctype",Keyword); break;
839
	case PROVIDED:	fprintf(fd, "%sprovided",Keyword); break;
840
	case RCV:	fprintf(fd, "%s?",	Operator); break;
841
	case R_RCV:	fprintf(fd, "%s??",	Operator); break;
842
	case RSHIFT:	fprintf(fd, "%s>>",	Operator); break;
843
	case RUN:	fprintf(fd, "%srun",	Operator); break;
844
	case SEP:	fprintf(fd, "token: ::"); break;
845
	case SEMI:	fprintf(fd, ";"); break;
846
	case SHOW:	fprintf(fd, "%sshow", Keyword); break;
847
	case SND:	fprintf(fd, "%s!",	Operator); break;
848
	case STRING:	fprintf(fd, "a string"); break;
849
	case TRACE:	fprintf(fd, "%strace", Keyword); break;
850
	case TIMEOUT:	fprintf(fd, "%stimeout",Keyword); break;
851
	case TYPE:	fprintf(fd, "data typename"); break;
852
	case TYPEDEF:	fprintf(fd, "%stypedef",Keyword); break;
853
	case XU:	fprintf(fd, "%sx[rs]",	Keyword); break;
854
	case UMIN:	fprintf(fd, "%s- (unary minus)", Operator); break;
855
	case UNAME:	fprintf(fd, "a typename"); break;
856
	case UNLESS:	fprintf(fd, "%sunless",	Keyword); break;
857
	}
858
}
859
 
860