1 /***** spin: spinlex.c *****/
2 
3 /*
4  * This file is part of the public release of Spin. It is subject to the
5  * terms in the LICENSE file that is included in this source directory.
6  * Tool documentation is available at http://spinroot.com
7  */
8 
9 #include <stdlib.h>
10 #include <assert.h>
11 #include <errno.h>
12 #include <ctype.h>
13 #include "spin.h"
14 #include "y.tab.h"
15 
16 #define MAXINL	16	/* max recursion depth inline fcts */
17 #define MAXPAR	32	/* max params to an inline call */
18 #define MAXLEN	512	/* max len of an actual parameter text */
19 
20 typedef struct IType {
21 	Symbol *nm;		/* name of the type */
22 	Lextok *cn;		/* contents */
23 	Lextok *params;		/* formal pars if any */
24 	Lextok *rval;		/* variable to assign return value, if any */
25 	char   **anms;		/* literal text for actual pars */
26 	char   *prec;		/* precondition for c_code or c_expr */
27 	int    uiid;		/* unique inline id */
28 	int    is_expr;		/* c_expr in an ltl formula */
29 	int    dln, cln;	/* def and call linenr */
30 	Symbol *dfn, *cfn;	/* def and call filename */
31 	struct IType *nxt;	/* linked list */
32 } IType;
33 
34 typedef struct C_Added {
35 	Symbol *s;
36 	Symbol *t;
37 	Symbol *ival;
38 	Symbol *fnm;
39 	int	lno;
40 	struct C_Added *nxt;
41 } C_Added;
42 
43 extern RunList	*X_lst;
44 extern ProcList	*ready;
45 extern Symbol	*Fname, *oFname;
46 extern Symbol	*context, *owner;
47 extern YYSTYPE	yylval;
48 extern short	has_last, has_code, has_priority;
49 extern int	verbose, IArgs, hastrack, separate, in_for;
50 extern int	implied_semis, ltl_mode, in_seq, par_cnt;
51 
52 short	has_stack = 0;
53 int	lineno  = 1;
54 int	scope_seq[128], scope_level = 0;
55 char	CurScope[MAXSCOPESZ];
56 char	yytext[2048];
57 FILE	*yyin, *yyout;
58 
59 static C_Added	*c_added, *c_tracked;
60 static IType	*Inline_stub[MAXINL];
61 static char	*ReDiRect;
62 static char	*Inliner[MAXINL], IArg_cont[MAXPAR][MAXLEN];
63 static unsigned char	in_comment=0;
64 static int	IArgno = 0, Inlining = -1;
65 static int	check_name(char *);
66 static int	last_token = 0;
67 
68 #define ValToken(x, y)	{ if (in_comment) goto again; \
69 			yylval = nn(ZN,0,ZN,ZN); \
70 			yylval->val = x; \
71 			last_token = y; \
72 			return y; \
73 			}
74 
75 #define SymToken(x, y)	{ if (in_comment) goto again; \
76 			yylval = nn(ZN,0,ZN,ZN); \
77 			yylval->sym = x; \
78 			last_token = y; \
79 			return y; \
80 			}
81 
82 static int  getinline(void);
83 static void uninline(void);
84 
85 static int PushBack;
86 static int PushedBack;
87 static char pushedback[4096];
88 
89 static void
push_back(char * s)90 push_back(char *s)
91 {
92 	if (PushedBack + strlen(s) > 4094)
93 	{	fatal("select statement too large", 0);
94 	}
95 	strcat(pushedback, s);
96 	PushedBack += strlen(s);
97 }
98 
99 static int
Getchar(void)100 Getchar(void)
101 {	int c;
102 
103 	if (PushedBack > 0 && PushBack < PushedBack)
104 	{	c = pushedback[PushBack++];
105 		if (PushBack == PushedBack)
106 		{	pushedback[0] = '\0';
107 			PushBack = PushedBack = 0;
108 		}
109 		return c;	/* expanded select statement */
110 	}
111 	if (Inlining<0)
112 	{	c = getc(yyin);
113 	} else
114 	{	c = getinline();
115 	}
116 #if 0
117 	if (0)
118 	{	printf("<%c:%d>[%d] ", c, c, Inlining);
119 	} else
120 	{	printf("%c", c);
121 	}
122 #endif
123 	return c;
124 }
125 
126 static void
Ungetch(int c)127 Ungetch(int c)
128 {
129 	if (PushedBack > 0 && PushBack > 0)
130 	{	PushBack--;
131 		return;
132 	}
133 
134 	if (Inlining<0)
135 	{	ungetc(c,yyin);
136 	} else
137 	{	uninline();
138 	}
139 	if (0)
140 	{	printf("\n<bs{%d}bs>\n", c);
141 	}
142 }
143 
144 static int
notdollar(int c)145 notdollar(int c)
146 {	return (c != '$' && c != '\n');
147 }
148 
149 static int
notquote(int c)150 notquote(int c)
151 {	return (c != '\"' && c != '\n');
152 }
153 
154 int
isalnum_(int c)155 isalnum_(int c)
156 {	return (isalnum(c) || c == '_');
157 }
158 
159 static int
isalpha_(int c)160 isalpha_(int c)
161 {	return isalpha(c);	/* could be macro */
162 }
163 
164 static int
isdigit_(int c)165 isdigit_(int c)
166 {	return isdigit(c);	/* could be macro */
167 }
168 
169 static void
getword(int first,int (* tst)(int))170 getword(int first, int (*tst)(int))
171 {	int i=0, c;
172 
173 	yytext[i++]= (char) first;
174 	while (tst(c = Getchar()))
175 	{	yytext[i++] = (char) c;
176 		if (c == '\\')
177 		{	c = Getchar();
178 			yytext[i++] = (char) c;	/* no tst */
179 	}	}
180 	yytext[i] = '\0';
181 
182 	Ungetch(c);
183 }
184 
185 static int
follow(int tok,int ifyes,int ifno)186 follow(int tok, int ifyes, int ifno)
187 {	int c;
188 
189 	if ((c = Getchar()) == tok)
190 	{	return ifyes;
191 	}
192 	Ungetch(c);
193 
194 	return ifno;
195 }
196 
197 static IType *seqnames;
198 
199 static void
def_inline(Symbol * s,int ln,char * ptr,char * prc,Lextok * nms)200 def_inline(Symbol *s, int ln, char *ptr, char *prc, Lextok *nms)
201 {	IType *tmp;
202 	int  cnt = 0;
203 	char *nw = (char *) emalloc(strlen(ptr)+1);
204 	strcpy(nw, ptr);
205 
206 	for (tmp = seqnames; tmp; cnt++, tmp = tmp->nxt)
207 		if (!strcmp(s->name, tmp->nm->name))
208 		{	non_fatal("procedure name %s redefined",
209 				tmp->nm->name);
210 			tmp->cn = (Lextok *) nw;
211 			tmp->params = nms;
212 			tmp->dln = ln;
213 			tmp->dfn = Fname;
214 			return;
215 		}
216 	tmp = (IType *) emalloc(sizeof(IType));
217 	tmp->nm = s;
218 	tmp->cn = (Lextok *) nw;
219 	tmp->params = nms;
220 	if (strlen(prc) > 0)
221 	{	tmp->prec = (char *) emalloc(strlen(prc)+1);
222 		strcpy(tmp->prec, prc);
223 	}
224 	tmp->dln = ln;
225 	tmp->dfn = Fname;
226 	tmp->uiid = cnt+1;	/* so that 0 means: not an inline */
227 	tmp->nxt = seqnames;
228 	seqnames = tmp;
229 }
230 
231 void
gencodetable(FILE * fd)232 gencodetable(FILE *fd)
233 {	IType *tmp;
234 	char *q;
235 	int cnt;
236 
237 	if (separate == 2) return;
238 
239 	fprintf(fd, "struct {\n");
240 	fprintf(fd, "	char *c; char *t;\n");
241 	fprintf(fd, "} code_lookup[] = {\n");
242 
243 	if (has_code)
244 	for (tmp = seqnames; tmp; tmp = tmp->nxt)
245 		if (tmp->nm->type == CODE_FRAG
246 		||  tmp->nm->type == CODE_DECL)
247 		{	fprintf(fd, "\t{ \"%s\", ",
248 				tmp->nm->name);
249 			q = (char *) tmp->cn;
250 
251 			while (*q == '\n' || *q == '\r' || *q == '\\')
252 				q++;
253 
254 			fprintf(fd, "\"");
255 			cnt = 0;
256 			while (*q && cnt < 1024) /* pangen1.h allows 2048 */
257 			{	switch (*q) {
258 				case '"':
259 					fprintf(fd, "\\\"");
260 					break;
261 				case '%':
262 					fprintf(fd, "%%");
263 					break;
264 				case '\n':
265 					fprintf(fd, "\\n");
266 					break;
267 				default:
268 					putc(*q, fd);
269 					break;
270 				}
271 				q++; cnt++;
272 			}
273 			if (*q) fprintf(fd, "...");
274 			fprintf(fd, "\"");
275 			fprintf(fd, " },\n");
276 		}
277 
278 	fprintf(fd, "	{ (char *) 0, \"\" }\n");
279 	fprintf(fd, "};\n");
280 }
281 
282 static int
iseqname(char * t)283 iseqname(char *t)
284 {	IType *tmp;
285 
286 	for (tmp = seqnames; tmp; tmp = tmp->nxt)
287 	{	if (!strcmp(t, tmp->nm->name))
288 			return 1;
289 	}
290 	return 0;
291 }
292 
293 Lextok *
return_statement(Lextok * n)294 return_statement(Lextok *n)
295 {
296 	if (Inline_stub[Inlining]->rval)
297 	{	Lextok *g = nn(ZN, NAME, ZN, ZN);
298 		Lextok *h = Inline_stub[Inlining]->rval;
299 		g->sym = lookup("rv_");
300 		return nn(h, ASGN, h, n);
301 	} else
302 	{	fatal("return statement outside inline", (char *) 0);
303 	}
304 	return ZN;
305 }
306 
307 static int
getinline(void)308 getinline(void)
309 {	int c;
310 
311 	if (ReDiRect)
312 	{	c = *ReDiRect++;
313 		if (c == '\0')
314 		{	ReDiRect = (char *) 0;
315 			c = *Inliner[Inlining]++;
316 		}
317 	} else
318 	{
319 		c = *Inliner[Inlining]++;
320 	}
321 
322 	if (c == '\0')
323 	{
324 		lineno = Inline_stub[Inlining]->cln;
325 		Fname  = Inline_stub[Inlining]->cfn;
326 		Inlining--;
327 
328 #if 0
329 		if (verbose&32)
330 		printf("spin: %s:%d, done inlining %s\n",
331 			Fname, lineno, Inline_stub[Inlining+1]->nm->name);
332 #endif
333 		return Getchar();
334 	}
335 	return c;
336 }
337 
338 static void
uninline(void)339 uninline(void)
340 {
341 	if (ReDiRect)
342 		ReDiRect--;
343 	else
344 		Inliner[Inlining]--;
345 }
346 
347 int
is_inline(void)348 is_inline(void)
349 {
350 	if (Inlining < 0)
351 		return 0;	/* i.e., not an inline */
352 	if (Inline_stub[Inlining] == NULL)
353 		fatal("unexpected, inline_stub not set", 0);
354 	return Inline_stub[Inlining]->uiid;
355 }
356 
357 IType *
find_inline(char * s)358 find_inline(char *s)
359 {	IType *tmp;
360 
361 	for (tmp = seqnames; tmp; tmp = tmp->nxt)
362 		if (!strcmp(s, tmp->nm->name))
363 			break;
364 	if (!tmp)
365 		fatal("cannot happen, missing inline def %s", s);
366 
367 	return tmp;
368 }
369 
370 void
c_state(Symbol * s,Symbol * t,Symbol * ival)371 c_state(Symbol *s, Symbol *t, Symbol *ival)	/* name, scope, ival */
372 {	C_Added *r;
373 
374 	r = (C_Added *) emalloc(sizeof(C_Added));
375 	r->s = s;	/* pointer to a data object */
376 	r->t = t;	/* size of object, or "global", or "local proctype_name"  */
377 	r->ival = ival;
378 	r->lno = lineno;
379 	r->fnm = Fname;
380 	r->nxt = c_added;
381 
382 	if(strncmp(r->s->name, "\"unsigned unsigned", 18) == 0)
383 	{	int i;
384 		for (i = 10; i < 18; i++)
385 		{	r->s->name[i] = ' ';
386 		}
387 	/*	printf("corrected <%s>\n", r->s->name);	*/
388 	}
389 	c_added = r;
390 }
391 
392 void
c_track(Symbol * s,Symbol * t,Symbol * stackonly)393 c_track(Symbol *s, Symbol *t, Symbol *stackonly)	/* name, size */
394 {	C_Added *r;
395 
396 	r = (C_Added *) emalloc(sizeof(C_Added));
397 	r->s = s;
398 	r->t = t;
399 	r->ival = stackonly;	/* abuse of name */
400 	r->nxt = c_tracked;
401 	r->fnm = Fname;
402 	r->lno = lineno;
403 	c_tracked = r;
404 
405 	if (stackonly != ZS)
406 	{	if (strcmp(stackonly->name, "\"Matched\"") == 0)
407 			r->ival = ZS;	/* the default */
408 		else if (strcmp(stackonly->name, "\"UnMatched\"") != 0
409 		     &&  strcmp(stackonly->name, "\"unMatched\"") != 0
410 		     &&  strcmp(stackonly->name, "\"StackOnly\"") != 0)
411 			non_fatal("expecting '[Un]Matched', saw %s", stackonly->name);
412 		else
413 			has_stack = 1;	/* unmatched stack */
414 	}
415 }
416 
417 char *
skip_white(char * p)418 skip_white(char *p)
419 {
420 	if (p != NULL)
421 	{	while (*p == ' ' || *p == '\t')
422 			p++;
423 	} else
424 	{	fatal("bad format - 1", (char *) 0);
425 	}
426 	return p;
427 }
428 
429 char *
skip_nonwhite(char * p)430 skip_nonwhite(char *p)
431 {
432 	if (p != NULL)
433 	{	while (*p != ' ' && *p != '\t')
434 			p++;
435 	} else
436 	{	fatal("bad format - 2", (char *) 0);
437 	}
438 	return p;
439 }
440 
441 static char *
jump_etc(C_Added * r)442 jump_etc(C_Added *r)
443 {	char *op = r->s->name;
444 	char *p = op;
445 	char *q = (char *) 0;
446 	int oln = lineno;
447 	Symbol *ofnm = Fname;
448 
449 	/* try to get the type separated from the name */
450 	lineno = r->lno;
451 	Fname  = r->fnm;
452 
453 	p = skip_white(p);	/* initial white space */
454 
455 	if (strncmp(p, "enum", strlen("enum")) == 0) /* special case: a two-part typename */
456 	{	p += strlen("enum")+1;
457 		p = skip_white(p);
458 	}
459 	if (strncmp(p, "unsigned", strlen("unsigned")) == 0) /* possibly a two-part typename */
460 	{	p += strlen("unsigned")+1;
461 		q = p = skip_white(p);
462 	}
463 	p = skip_nonwhite(p);	/* type name */
464 	p = skip_white(p);	/* white space */
465 	while (*p == '*') p++;	/* decorations */
466 	p = skip_white(p);	/* white space */
467 
468 	if (*p == '\0')
469 	{	if (q)
470 		{	p = q;	/* unsigned with implied 'int' */
471 		} else
472 		{	fatal("c_state format (%s)", op);
473 	}	}
474 
475 	if (strchr(p, '[')
476 	&& (!r->ival
477 	||  !r->ival->name
478 	||  !strchr(r->ival->name, '{')))	// was !strchr(p, '{'))
479 	{	non_fatal("array initialization error, c_state (%s)", p);
480 		p = (char *) 0;
481 	}
482 
483 	lineno = oln;
484 	Fname = ofnm;
485 
486 	return p;
487 }
488 
489 void
c_add_globinit(FILE * fd)490 c_add_globinit(FILE *fd)
491 {	C_Added *r;
492 	char *p, *q;
493 
494 	fprintf(fd, "void\nglobinit(void)\n{\n");
495 	for (r = c_added; r; r = r->nxt)
496 	{	if (r->ival == ZS)
497 			continue;
498 
499 		if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0)
500 		{	for (q = r->ival->name; *q; q++)
501 			{	if (*q == '\"')
502 					*q = ' ';
503 				if (*q == '\\')
504 					*q++ = ' '; /* skip over the next */
505 			}
506 			p = jump_etc(r);	/* e.g., "int **q" */
507 			if (p)
508 			fprintf(fd, "	now.%s = %s;\n", p, r->ival->name);
509 
510 		} else
511 		if (strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0)
512 		{	for (q = r->ival->name; *q; q++)
513 			{	if (*q == '\"')
514 					*q = ' ';
515 				if (*q == '\\')
516 					*q++ = ' '; /* skip over the next */
517 			}
518 			p = jump_etc(r);	/* e.g., "int **q" */
519 			if (p)
520 			fprintf(fd, "	%s = %s;\n", p, r->ival->name);	/* no now. prefix */
521 
522 	}	}
523 	fprintf(fd, "}\n");
524 }
525 
526 void
c_add_locinit(FILE * fd,int tpnr,char * pnm)527 c_add_locinit(FILE *fd, int tpnr, char *pnm)
528 {	C_Added *r;
529 	char *p, *q, *s;
530 	int frst = 1;
531 
532 	fprintf(fd, "void\nlocinit%d(int h)\n{\n", tpnr);
533 	for (r = c_added; r; r = r->nxt)
534 		if (r->ival != ZS
535 		&&  strncmp(r->t->name, " Local", strlen(" Local")) == 0)
536 		{	for (q = r->ival->name; *q; q++)
537 				if (*q == '\"')
538 					*q = ' ';
539 			p = jump_etc(r);	/* e.g., "int **q" */
540 
541 			q = r->t->name + strlen(" Local");
542 			while (*q == ' ' || *q == '\t')
543 				q++;			/* process name */
544 
545 			s = (char *) emalloc(strlen(q)+1);
546 			strcpy(s, q);
547 
548 			q = &s[strlen(s)-1];
549 			while (*q == ' ' || *q == '\t')
550 				*q-- = '\0';
551 
552 			if (strcmp(pnm, s) != 0)
553 				continue;
554 
555 			if (frst)
556 			{	fprintf(fd, "\tuchar *_this = pptr(h);\n");
557 				frst = 0;
558 			}
559 
560 			if (p)
561 			{	fprintf(fd, "\t\t((P%d *)_this)->%s = %s;\n",
562 					tpnr, p, r->ival->name);
563 			}
564 		}
565 	fprintf(fd, "}\n");
566 }
567 
568 /* tracking:
569 	1. for non-global and non-local c_state decls: add up all the sizes in c_added
570 	2. add a global char array of that size into now
571 	3. generate a routine that memcpy's the required values into that array
572 	4. generate a call to that routine
573  */
574 
575 void
c_preview(void)576 c_preview(void)
577 {	C_Added *r;
578 
579 	hastrack = 0;
580 	if (c_tracked)
581 		hastrack = 1;
582 	else
583 	for (r = c_added; r; r = r->nxt)
584 		if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0
585 		&&  strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0
586 		&&  strncmp(r->t->name, " Local",  strlen(" Local"))  != 0)
587 		{	hastrack = 1;	/* c_state variant now obsolete */
588 			break;
589 		}
590 }
591 
592 int
c_add_sv(FILE * fd)593 c_add_sv(FILE *fd)	/* 1+2 -- called in pangen1.c */
594 {	C_Added *r;
595 	int cnt = 0;
596 
597 	if (!c_added && !c_tracked) return 0;
598 
599 	for (r = c_added; r; r = r->nxt)	/* pickup global decls */
600 		if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0)
601 			fprintf(fd, "	%s;\n", r->s->name);
602 
603 	for (r = c_added; r; r = r->nxt)
604 		if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0
605 		&&  strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0
606 		&&  strncmp(r->t->name, " Local",  strlen(" Local"))  != 0)
607 		{	cnt++;	/* obsolete use */
608 		}
609 
610 	for (r = c_tracked; r; r = r->nxt)
611 		cnt++;		/* preferred use */
612 
613 	if (cnt == 0) return 0;
614 
615 	cnt = 0;
616 	fprintf(fd, "	uchar c_state[");
617 	for (r = c_added; r; r = r->nxt)
618 		if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0
619 		&&  strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0
620 		&&  strncmp(r->t->name, " Local",  strlen(" Local"))  != 0)
621 		{	fprintf(fd, "%ssizeof(%s)",
622 				(cnt==0)?"":"+", r->t->name);
623 			cnt++;
624 		}
625 
626 	for (r = c_tracked; r; r = r->nxt)
627 	{	if (r->ival != ZS) continue;
628 
629 		fprintf(fd, "%s%s",
630 			(cnt==0)?"":"+", r->t->name);
631 		cnt++;
632 	}
633 
634 	if (cnt == 0) fprintf(fd, "4");	/* now redundant */
635 	fprintf(fd, "];\n");
636 	return 1;
637 }
638 
639 void
c_stack_size(FILE * fd)640 c_stack_size(FILE *fd)
641 {	C_Added *r;
642 	int cnt = 0;
643 
644 	for (r = c_tracked; r; r = r->nxt)
645 		if (r->ival != ZS)
646 		{	fprintf(fd, "%s%s",
647 				(cnt==0)?"":"+", r->t->name);
648 			cnt++;
649 		}
650 	if (cnt == 0)
651 	{	fprintf(fd, "WS");
652 	}
653 }
654 
655 void
c_add_stack(FILE * fd)656 c_add_stack(FILE *fd)
657 {	C_Added *r;
658 	int cnt = 0;
659 
660 	if ((!c_added && !c_tracked) || !has_stack)
661 	{	return;
662 	}
663 
664 	for (r = c_tracked; r; r = r->nxt)
665 		if (r->ival != ZS)
666 		{	cnt++;
667 		}
668 
669 	if (cnt > 0)
670 	{	fprintf(fd, "	uchar c_stack[StackSize];\n");
671 	}
672 }
673 
674 void
c_add_hidden(FILE * fd)675 c_add_hidden(FILE *fd)
676 {	C_Added *r;
677 
678 	for (r = c_added; r; r = r->nxt)	/* pickup hidden decls */
679 		if (strncmp(r->t->name, "\"Hidden\"", strlen("\"Hidden\"")) == 0)
680 		{	r->s->name[strlen(r->s->name)-1] = ' ';
681 			fprintf(fd, "%s;	/* Hidden */\n", &r->s->name[1]);
682 			r->s->name[strlen(r->s->name)-1] = '"';
683 		}
684 	/* called before c_add_def - quotes are still there */
685 }
686 
687 void
c_add_loc(FILE * fd,char * s)688 c_add_loc(FILE *fd, char *s)	/* state vector entries for proctype s */
689 {	C_Added *r;
690 	static char buf[1024];
691 	char *p;
692 
693 	if (!c_added) return;
694 
695 	strcpy(buf, s);
696 	strcat(buf, " ");
697 	for (r = c_added; r; r = r->nxt)	/* pickup local decls */
698 	{	if (strncmp(r->t->name, " Local", strlen(" Local")) == 0)
699 		{	p = r->t->name + strlen(" Local");
700 fprintf(fd, "/* XXX p=<%s>, s=<%s>, buf=<%s> r->s->name=<%s>XXX */\n", p, s, buf, r->s->name);
701 			while (*p == ' ' || *p == '\t')
702 			{	p++;
703 			}
704 			if (strcmp(p, buf) == 0
705 			||  (strncmp(p, "init", 4) == 0 && strncmp(buf, ":init:", 6) == 0))
706 			{	fprintf(fd, "	%s;\n", r->s->name);
707 	}	}	}
708 }
709 void
c_add_def(FILE * fd)710 c_add_def(FILE *fd)	/* 3 - called in plunk_c_fcts() */
711 {	C_Added *r;
712 
713 	fprintf(fd, "#if defined(C_States) && (HAS_TRACK==1)\n");
714 	for (r = c_added; r; r = r->nxt)
715 	{	r->s->name[strlen(r->s->name)-1] = ' ';
716 		r->s->name[0] = ' '; /* remove the "s */
717 
718 		r->t->name[strlen(r->t->name)-1] = ' ';
719 		r->t->name[0] = ' ';
720 
721 		if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0
722 		||  strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0
723 		||  strncmp(r->t->name, " Local",  strlen(" Local"))  == 0)
724 			continue;
725 
726 		if (strchr(r->s->name, '&'))
727 			fatal("dereferencing state object: %s", r->s->name);
728 
729 		fprintf(fd, "extern %s %s;\n", r->t->name, r->s->name);
730 	}
731 	for (r = c_tracked; r; r = r->nxt)
732 	{	r->s->name[strlen(r->s->name)-1] = ' ';
733 		r->s->name[0] = ' '; /* remove " */
734 
735 		r->t->name[strlen(r->t->name)-1] = ' ';
736 		r->t->name[0] = ' ';
737 	}
738 
739 	if (separate == 2)
740 	{	fprintf(fd, "#endif\n");
741 		return;
742 	}
743 
744 	if (has_stack)
745 	{	fprintf(fd, "int cpu_printf(const char *, ...);\n");
746 		fprintf(fd, "void\nc_stack(uchar *p_t_r)\n{\n");
747 		fprintf(fd, "#ifdef VERBOSE\n");
748 		fprintf(fd, "	cpu_printf(\"c_stack %%u\\n\", p_t_r);\n");
749 		fprintf(fd, "#endif\n");
750 		for (r = c_tracked; r; r = r->nxt)
751 		{	if (r->ival == ZS) continue;
752 
753 			fprintf(fd, "\tif(%s)\n", r->s->name);
754 			fprintf(fd, "\t\tmemcpy(p_t_r, %s, %s);\n",
755 				r->s->name, r->t->name);
756 			fprintf(fd, "\telse\n");
757 			fprintf(fd, "\t\tmemset(p_t_r, 0, %s);\n",
758 				r->t->name);
759 			fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
760 		}
761 		fprintf(fd, "}\n\n");
762 	}
763 
764 	fprintf(fd, "void\nc_update(uchar *p_t_r)\n{\n");
765 	fprintf(fd, "#ifdef VERBOSE\n");
766 	fprintf(fd, "	printf(\"c_update %%p\\n\", p_t_r);\n");
767 	fprintf(fd, "#endif\n");
768 	for (r = c_added; r; r = r->nxt)
769 	{	if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0
770 		||  strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0
771 		||  strncmp(r->t->name, " Local",  strlen(" Local"))  == 0)
772 			continue;
773 
774 		fprintf(fd, "\tmemcpy(p_t_r, &%s, sizeof(%s));\n",
775 			r->s->name, r->t->name);
776 		fprintf(fd, "\tp_t_r += sizeof(%s);\n", r->t->name);
777 	}
778 
779 	for (r = c_tracked; r; r = r->nxt)
780 	{	if (r->ival) continue;
781 
782 		fprintf(fd, "\tif(%s)\n", r->s->name);
783 		fprintf(fd, "\t\tmemcpy(p_t_r, %s, %s);\n",
784 			r->s->name, r->t->name);
785 		fprintf(fd, "\telse\n");
786 		fprintf(fd, "\t\tmemset(p_t_r, 0, %s);\n",
787 			r->t->name);
788 		fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
789 	}
790 
791 	fprintf(fd, "}\n");
792 
793 	if (has_stack)
794 	{	fprintf(fd, "void\nc_unstack(uchar *p_t_r)\n{\n");
795 		fprintf(fd, "#ifdef VERBOSE\n");
796 		fprintf(fd, "	cpu_printf(\"c_unstack %%u\\n\", p_t_r);\n");
797 		fprintf(fd, "#endif\n");
798 		for (r = c_tracked; r; r = r->nxt)
799 		{	if (r->ival == ZS) continue;
800 
801 			fprintf(fd, "\tif(%s)\n", r->s->name);
802 			fprintf(fd, "\t\tmemcpy(%s, p_t_r, %s);\n",
803 				r->s->name, r->t->name);
804 			fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
805 		}
806 		fprintf(fd, "}\n");
807 	}
808 
809 	fprintf(fd, "void\nc_revert(uchar *p_t_r)\n{\n");
810 	fprintf(fd, "#ifdef VERBOSE\n");
811 	fprintf(fd, "	printf(\"c_revert %%p\\n\", p_t_r);\n");
812 	fprintf(fd, "#endif\n");
813 	for (r = c_added; r; r = r->nxt)
814 	{	if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0
815 		||  strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0
816 		||  strncmp(r->t->name, " Local",  strlen(" Local"))  == 0)
817 			continue;
818 
819 		fprintf(fd, "\tmemcpy(&%s, p_t_r, sizeof(%s));\n",
820 			r->s->name, r->t->name);
821 		fprintf(fd, "\tp_t_r += sizeof(%s);\n", r->t->name);
822 	}
823 	for (r = c_tracked; r; r = r->nxt)
824 	{	if (r->ival != ZS) continue;
825 
826 		fprintf(fd, "\tif(%s)\n", r->s->name);
827 		fprintf(fd, "\t\tmemcpy(%s, p_t_r, %s);\n",
828 			r->s->name, r->t->name);
829 		fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
830 	}
831 
832 	fprintf(fd, "}\n");
833 	fprintf(fd, "#endif\n");
834 }
835 
836 void
plunk_reverse(FILE * fd,IType * p,int matchthis)837 plunk_reverse(FILE *fd, IType *p, int matchthis)
838 {	char *y, *z;
839 
840 	if (!p) return;
841 	plunk_reverse(fd, p->nxt, matchthis);
842 
843 	if (!p->nm->context
844 	&&   p->nm->type == matchthis
845 	&&   p->is_expr == 0)
846 	{	fprintf(fd, "\n/* start of %s */\n", p->nm->name);
847 		z = (char *) p->cn;
848 		while (*z == '\n' || *z == '\r' || *z == '\\')
849 		{	z++;
850 		}
851 		/* e.g.: \#include "..." */
852 
853 		y = z;
854 		while ((y = strstr(y, "\\#")) != NULL)
855 		{	*y = '\n'; y++;
856 		}
857 
858 		fprintf(fd, "%s\n", z);
859 		fprintf(fd, "\n/* end of %s */\n", p->nm->name);
860 	}
861 }
862 
863 void
plunk_c_decls(FILE * fd)864 plunk_c_decls(FILE *fd)
865 {
866 	plunk_reverse(fd, seqnames, CODE_DECL);
867 }
868 
869 void
plunk_c_fcts(FILE * fd)870 plunk_c_fcts(FILE *fd)
871 {
872 	if (separate == 2 && hastrack)
873 	{	c_add_def(fd);
874 		return;
875 	}
876 
877 	c_add_hidden(fd);
878 	plunk_reverse(fd, seqnames, CODE_FRAG);
879 
880 	if (c_added || c_tracked)	/* enables calls to c_revert and c_update */
881 		fprintf(fd, "#define C_States	1\n");
882 	else
883 		fprintf(fd, "#undef C_States\n");
884 
885 	if (hastrack)
886 		c_add_def(fd);
887 
888 	c_add_globinit(fd);
889 	do_locinits(fd);
890 }
891 
892 static void
check_inline(IType * tmp)893 check_inline(IType *tmp)
894 {	char buf[128];
895 	ProcList *p;
896 
897 	if (!X_lst) return;
898 
899 	for (p = ready; p; p = p->nxt)
900 	{	if (strcmp(p->n->name, X_lst->n->name) == 0)
901 			continue;
902 		sprintf(buf, "P%s->", p->n->name);
903 		if (strstr((char *)tmp->cn, buf))
904 		{	printf("spin: in proctype %s, ref to object in proctype %s\n",
905 				X_lst->n->name, p->n->name);
906 			fatal("invalid variable ref in '%s'", tmp->nm->name);
907 	}	}
908 }
909 
910 extern short terse;
911 extern short nocast;
912 
913 void
plunk_expr(FILE * fd,char * s)914 plunk_expr(FILE *fd, char *s)
915 {	IType *tmp;
916 	char *q;
917 
918 	tmp = find_inline(s);
919 	check_inline(tmp);
920 
921 	if (terse && nocast)
922 	{	for (q = (char *) tmp->cn; q && *q != '\0'; q++)
923 		{	fflush(fd);
924 			if (*q == '"')
925 			{	fprintf(fd, "\\");
926 			}
927 			fprintf(fd, "%c", *q);
928 		}
929 	} else
930 	{	fprintf(fd, "%s", (char *) tmp->cn);
931 	}
932 }
933 
934 void
preruse(FILE * fd,Lextok * n)935 preruse(FILE *fd, Lextok *n)	/* check a condition for c_expr with preconditions */
936 {	IType *tmp;
937 
938 	if (!n) return;
939 	if (n->ntyp == C_EXPR)
940 	{	tmp = find_inline(n->sym->name);
941 		if (tmp->prec)
942 		{	fprintf(fd, "if (!(%s)) { if (!readtrail) { depth++; ", tmp->prec);
943 			fprintf(fd, "trpt++; trpt->pr = II; trpt->o_t = t; trpt->st = tt; ");
944 			fprintf(fd, "uerror(\"c_expr line %d precondition false: %s\"); continue;",
945 				tmp->dln, tmp->prec);
946 			fprintf(fd, " } else { printf(\"pan: precondition false: %s\\n\"); ",
947 				tmp->prec);
948 			fprintf(fd, "_m = 3; goto P999; } } \n\t\t");
949 		}
950 	} else
951 	{	preruse(fd, n->rgt);
952 		preruse(fd, n->lft);
953 	}
954 }
955 
956 int
glob_inline(char * s)957 glob_inline(char *s)
958 {	IType *tmp;
959 	char *bdy;
960 
961 	tmp = find_inline(s);
962 	bdy = (char *) tmp->cn;
963 	return (strstr(bdy, "now.")		/* global ref or   */
964 	||      strchr(bdy, '(') > bdy);	/* possible C-function call */
965 }
966 
967 char *
put_inline(FILE * fd,char * s)968 put_inline(FILE *fd, char *s)
969 {	IType *tmp;
970 
971 	tmp = find_inline(s);
972 	check_inline(tmp);
973 	return (char *) tmp->cn;
974 }
975 
976 void
mark_last(void)977 mark_last(void)
978 {
979 	if (seqnames)
980 	{	seqnames->is_expr = 1;
981 	}
982 }
983 
984 void
plunk_inline(FILE * fd,char * s,int how,int gencode)985 plunk_inline(FILE *fd, char *s, int how, int gencode)	/* c_code with precondition */
986 {	IType *tmp;
987 
988 	tmp = find_inline(s);
989 	check_inline(tmp);
990 
991 	fprintf(fd, "{ ");
992 	if (how && tmp->prec)
993 	{	fprintf(fd, "if (!(%s)) { if (!readtrail) {",
994 			tmp->prec);
995 		fprintf(fd, " uerror(\"c_code line %d precondition false: %s\"); continue; ",
996 			tmp->dln,
997 			tmp->prec);
998 		fprintf(fd, "} else { ");
999 		fprintf(fd, "printf(\"pan: precondition false: %s\\n\"); _m = 3; goto P999; } } ",
1000 			tmp->prec);
1001 	}
1002 
1003 	if (!gencode)	/* not in d_step */
1004 	{	fprintf(fd, "\n\t\tsv_save();");
1005 	}
1006 
1007 	fprintf(fd, "%s", (char *) tmp->cn);
1008 	fprintf(fd, " }\n");
1009 }
1010 
1011 int
side_scan(char * t,char * pat)1012 side_scan(char *t, char *pat)
1013 {	char *r = strstr(t, pat);
1014 	return (r
1015 		&& *(r-1) != '"'
1016 		&& *(r-1) != '\'');
1017 }
1018 
1019 void
no_side_effects(char * s)1020 no_side_effects(char *s)
1021 {	IType *tmp;
1022 	char *t;
1023 	char *z;
1024 
1025 	/* could still defeat this check via hidden
1026 	 * side effects in function calls,
1027 	 * but this will catch at least some cases
1028 	 */
1029 
1030 	tmp = find_inline(s);
1031 	t = (char *) tmp->cn;
1032 	while (t && *t == ' ')
1033 	{	t++;
1034 	}
1035 
1036 	z = strchr(t, '(');
1037 	if (z
1038 	&&  z > t
1039 	&&  isalnum((int) *(z-1))
1040 	&&  strncmp(t, "spin_mutex_free(", strlen("spin_mutex_free(")) != 0)
1041 	{	goto bad;	/* fct call */
1042 	}
1043 
1044 	if (side_scan(t, ";")
1045 	||  side_scan(t, "++")
1046 	||  side_scan(t, "--"))
1047 	{
1048 bad:		lineno = tmp->dln;
1049 		Fname = tmp->dfn;
1050 		non_fatal("c_expr %s has side-effects", s);
1051 		return;
1052 	}
1053 	while ((t = strchr(t, '=')) != NULL)
1054 	{	if (*(t-1) == '!'
1055 		||  *(t-1) == '>'
1056 		||  *(t-1) == '<'
1057 		||  *(t-1) == '"'
1058 		||  *(t-1) == '\'')
1059 		{	t += 2;
1060 			continue;
1061 		}
1062 		t++;
1063 		if (*t != '=')
1064 			goto bad;
1065 		t++;
1066 	}
1067 }
1068 
1069 void
pickup_inline(Symbol * t,Lextok * apars,Lextok * rval)1070 pickup_inline(Symbol *t, Lextok *apars, Lextok *rval)
1071 {	IType *tmp; Lextok *p, *q; int j;
1072 
1073 	tmp = find_inline(t->name);
1074 
1075 	if (++Inlining >= MAXINL)
1076 		fatal("inlines nested too deeply", 0);
1077 	tmp->cln = lineno;	/* remember calling point */
1078 	tmp->cfn = Fname;	/* and filename */
1079 	tmp->rval = rval;
1080 
1081 	for (p = apars, q = tmp->params, j = 0; p && q; p = p->rgt, q = q->rgt)
1082 		j++; /* count them */
1083 	if (p || q)
1084 		fatal("wrong nr of params on call of '%s'", t->name);
1085 
1086 	tmp->anms  = (char **) emalloc(j * sizeof(char *));
1087 	for (p = apars, j = 0; p; p = p->rgt, j++)
1088 	{	tmp->anms[j] = (char *) emalloc(strlen(IArg_cont[j])+1);
1089 		strcpy(tmp->anms[j], IArg_cont[j]);
1090 	}
1091 
1092 	lineno = tmp->dln;	/* linenr of def */
1093 	Fname = tmp->dfn;	/* filename of same */
1094 	Inliner[Inlining] = (char *)tmp->cn;
1095 	Inline_stub[Inlining] = tmp;
1096 #if 0
1097 	if (verbose&32)
1098 	printf("spin: %s:%d, inlining '%s' (from %s:%d)\n",
1099 		tmp->cfn->name, tmp->cln, t->name, tmp->dfn->name, tmp->dln);
1100 #endif
1101 	for (j = 0; j < Inlining; j++)
1102 	{	if (Inline_stub[j] == Inline_stub[Inlining])
1103 		{	fatal("cyclic inline attempt on: %s", t->name);
1104 	}	}
1105 	last_token = SEMI;	/* avoid insertion of extra semi */
1106 }
1107 
1108 extern int pp_mode;
1109 
1110 static void
do_directive(int first)1111 do_directive(int first)
1112 {	int c = first;	/* handles lines starting with pound */
1113 
1114 	getword(c, isalpha_);
1115 
1116 	if (strcmp(yytext, "#ident") == 0)
1117 		goto done;
1118 
1119 	if ((c = Getchar()) != ' ')
1120 		fatal("malformed preprocessor directive - # .", 0);
1121 
1122 	if (!isdigit_(c = Getchar()))
1123 		fatal("malformed preprocessor directive - # .lineno", 0);
1124 
1125 	getword(c, isdigit_);
1126 	lineno = atoi(yytext);	/* pickup the line number */
1127 
1128 	if ((c = Getchar()) == '\n')
1129 		return;	/* no filename */
1130 
1131 	if (c != ' ')
1132 		fatal("malformed preprocessor directive - .fname", 0);
1133 
1134 	if ((c = Getchar()) != '\"')
1135 	{	printf("got %c, expected \" -- lineno %d\n", c, lineno);
1136 		fatal("malformed preprocessor directive - .fname (%s)", yytext);
1137 	}
1138 
1139 	getword(Getchar(), notquote);	/* was getword(c, notquote); */
1140 	if (Getchar() != '\"')
1141 		fatal("malformed preprocessor directive - fname.", 0);
1142 
1143 	/* strcat(yytext, "\""); */
1144 	Fname = lookup(yytext);
1145 done:
1146 	while (Getchar() != '\n')
1147 		;
1148 }
1149 
1150 void
precondition(char * q)1151 precondition(char *q)
1152 {	int c, nest = 1;
1153 
1154 	for (;;)
1155 	{	c = Getchar();
1156 		*q++ = c;
1157 		switch (c) {
1158 		case '\n':
1159 			lineno++;
1160 			break;
1161 		case '[':
1162 			nest++;
1163 			break;
1164 		case ']':
1165 			if (--nest <= 0)
1166 			{	*--q = '\0';
1167 				return;
1168 			}
1169 			break;
1170 		}
1171 	}
1172 	fatal("cannot happen", (char *) 0); /* unreachable */
1173 }
1174 
1175 
1176 Symbol *
prep_inline(Symbol * s,Lextok * nms)1177 prep_inline(Symbol *s, Lextok *nms)
1178 {	int c, nest = 1, dln, firstchar, cnr;
1179 	char *p;
1180 	Lextok *t;
1181 	static char Buf1[SOMETHINGBIG], Buf2[RATHERSMALL];
1182 	static int c_code = 1;
1183 
1184 	for (t = nms; t; t = t->rgt)
1185 		if (t->lft)
1186 		{	if (t->lft->ntyp != NAME)
1187 			fatal("bad param to inline %s", s?s->name:"--");
1188 			t->lft->sym->hidden |= 32;
1189 		}
1190 
1191 	if (!s)	/* C_Code fragment */
1192 	{	s = (Symbol *) emalloc(sizeof(Symbol));
1193 		s->name = (char *) emalloc(strlen("c_code")+26);
1194 		sprintf(s->name, "c_code%d", c_code++);
1195 		s->context = context;
1196 		s->type = CODE_FRAG;
1197 	} else
1198 	{	s->type = PREDEF;
1199 	}
1200 
1201 	p = &Buf1[0];
1202 	Buf2[0] = '\0';
1203 	for (;;)
1204 	{	c = Getchar();
1205 		switch (c) {
1206 		case '[':
1207 			if (s->type != CODE_FRAG)
1208 				goto bad;
1209 			precondition(&Buf2[0]);	/* e.g., c_code [p] { r = p-r; } */
1210 			continue;
1211 		case '{':
1212 			break;
1213 		case '\n':
1214 			lineno++;
1215 			/* fall through */
1216 		case ' ': case '\t': case '\f': case '\r':
1217 			continue;
1218 		default :
1219 			 printf("spin: saw char '%c'\n", c);
1220 bad:			 fatal("bad inline: %s", s->name);
1221 		}
1222 		break;
1223 	}
1224 	dln = lineno;
1225 	if (s->type == CODE_FRAG)
1226 	{	if (verbose&32)
1227 		{	sprintf(Buf1, "\t/* line %d %s */\n\t\t",
1228 				lineno, Fname->name);
1229 		} else
1230 		{	strcpy(Buf1, "");
1231 		}
1232 	} else
1233 	{	sprintf(Buf1, "\n#line %d \"%s\"\n{", lineno, Fname->name);
1234 	}
1235 	p += strlen(Buf1);
1236 	firstchar = 1;
1237 
1238 	cnr = 1; /* not zero */
1239 more:
1240 	c = Getchar();
1241 	*p++ = (char) c;
1242 	if (p - Buf1 >= SOMETHINGBIG)
1243 		fatal("inline text too long", 0);
1244 	switch (c) {
1245 	case '\n':
1246 		lineno++;
1247 		cnr = 0;
1248 		break;
1249 	case '{':
1250 		cnr++;
1251 		nest++;
1252 		break;
1253 	case '}':
1254 		cnr++;
1255 		if (--nest <= 0)
1256 		{	*p = '\0';
1257 			if (s->type == CODE_FRAG)
1258 			{	*--p = '\0';	/* remove trailing '}' */
1259 			}
1260 			def_inline(s, dln, &Buf1[0], &Buf2[0], nms);
1261 			if (firstchar)
1262 			{	printf("%3d: %s, warning: empty inline definition (%s)\n",
1263 					dln, Fname->name, s->name);
1264 			}
1265 			return s;	/* normal return */
1266 		}
1267 		break;
1268 	case '#':
1269 		if (cnr == 0)
1270 		{	p--;
1271 			do_directive(c); /* reads to newline */
1272 		} else
1273 		{	firstchar = 0;
1274 			cnr++;
1275 		}
1276 		break;
1277 	case '\t':
1278 	case ' ':
1279 	case '\f':
1280 		cnr++;
1281 		break;
1282 	case '"':
1283 		do {
1284 			c = Getchar();
1285 			*p++ = (char) c;
1286 			if (c == '\\')
1287 			{	*p++ = (char) Getchar();
1288 			}
1289 			if (p - Buf1 >= SOMETHINGBIG)
1290 			{	fatal("inline text too long", 0);
1291 			}
1292 		} while (c != '"');	/* end of string */
1293 		/* *p = '\0'; */
1294 		break;
1295 	case '\'':
1296 		c = Getchar();
1297 		*p++ = (char) c;
1298 		if (c == '\\')
1299 		{	*p++ = (char) Getchar();
1300 		}
1301 		c = Getchar();
1302 		*p++ = (char) c;
1303 		assert(c == '\'');
1304 		break;
1305 	default:
1306 		firstchar = 0;
1307 		cnr++;
1308 		break;
1309 	}
1310 	goto more;
1311 }
1312 
1313 static void
set_cur_scope(void)1314 set_cur_scope(void)
1315 {	int i;
1316 	char tmpbuf[256];
1317 
1318 	strcpy(CurScope, "_");
1319 
1320 	if (context)
1321 	for (i = 0; i < scope_level; i++)
1322 	{	sprintf(tmpbuf, "%d_", scope_seq[i]);
1323 		strcat(CurScope, tmpbuf);
1324 	}
1325 }
1326 
1327 static int
pre_proc(void)1328 pre_proc(void)
1329 {	char b[512];
1330 	int c, i = 0;
1331 
1332 	b[i++] = '#';
1333 	while ((c = Getchar()) != '\n' && c != EOF)
1334 	{	b[i++] = (char) c;
1335 	}
1336 	b[i] = '\0';
1337 	yylval = nn(ZN, 0, ZN, ZN);
1338 	yylval->sym = lookup(b);
1339 	return PREPROC;
1340 }
1341 
1342 static int specials[] = {
1343 	'}', ')', ']',
1344 	OD, FI, ELSE, BREAK,
1345 	C_CODE, C_EXPR, C_DECL,
1346 	NAME, CONST, INCR, DECR, 0
1347 };
1348 
1349 int
follows_token(int c)1350 follows_token(int c)
1351 {	int i;
1352 
1353 	for (i = 0; specials[i]; i++)
1354 	{	if (c == specials[i])
1355 		{	return 1;
1356 	}	}
1357 	return 0;
1358 }
1359 #define DEFER_LTL
1360 #ifdef DEFER_LTL
1361 /* defer ltl formula to the end of the spec
1362  * no matter where they appear in the original
1363  */
1364 
1365 static int deferred = 0;
1366 static FILE *defer_fd;
1367 
1368 int
get_deferred(void)1369 get_deferred(void)
1370 {
1371 	if (!defer_fd)
1372 	{	return 0;	/* nothing was deferred */
1373 	}
1374 	fclose(defer_fd);
1375 
1376 	defer_fd = fopen(TMP_FILE2, "r");
1377 	if (!defer_fd)
1378 	{	non_fatal("cannot retrieve deferred ltl formula", (char *) 0);
1379 		return 0;
1380 	}
1381 	fclose(yyin);
1382 	yyin = defer_fd;
1383 	return 1;
1384 }
1385 
1386 void
zap_deferred(void)1387 zap_deferred(void)
1388 {
1389 	(void) unlink(TMP_FILE2);
1390 }
1391 
1392 int
put_deferred(void)1393 put_deferred(void)
1394 {	int c, cnt;
1395 	if (!defer_fd)
1396 	{	defer_fd = fopen(TMP_FILE2, "w+");
1397 		if (!defer_fd)
1398 		{	non_fatal("cannot defer ltl expansion", (char *) 0);
1399 			return 0;
1400 	}	}
1401 	fprintf(defer_fd, "ltl ");
1402 	cnt = 0;
1403 	while ((c = getc(yyin)) != EOF)
1404 	{	if (c == '{')
1405 		{	cnt++;
1406 		}
1407 		if (c == '}')
1408 		{	cnt--;
1409 			if (cnt == 0)
1410 			{	break;
1411 		}	}
1412 		fprintf(defer_fd, "%c", c);
1413 	}
1414 	fprintf(defer_fd, "}\n");
1415 	fflush(defer_fd);
1416 	return 1;
1417 }
1418 #endif
1419 
1420 #define EXPAND_SELECT
1421 #ifdef EXPAND_SELECT
1422 static char tmp_hold[256];
1423 static int  tmp_has;
1424 
1425 void
new_select(void)1426 new_select(void)
1427 {	tmp_hold[0] = '\0';
1428 	tmp_has = 0;
1429 }
1430 
1431 int
scan_to(int stop,int (* tst)(int),char * buf)1432 scan_to(int stop, int (*tst)(int), char *buf)
1433 {	int c, i = 0;
1434 
1435 	do {	c = Getchar();
1436 		if (tmp_has < sizeof(tmp_hold))
1437 		{	tmp_hold[tmp_has++] = c;
1438 		}
1439 		if (c == '\n')
1440 		{	lineno++;
1441 		} else if (buf)
1442 		{	buf[i++] = c;
1443 		}
1444 		if (tst && !tst(c) && c != ' ' && c != '\t')
1445 		{	break;
1446 		}
1447 	} while (c != stop && c != EOF);
1448 
1449 	if (buf)
1450 	{	buf[i-1] = '\0';
1451 	}
1452 
1453 	if (c != stop)
1454 	{	if (0)
1455 		{	printf("saw: '%c', expected '%c'\n", c, stop);
1456 		}
1457 		if (tmp_has < sizeof(tmp_hold))
1458 		{	tmp_hold[tmp_has] = '\0';
1459 			push_back(tmp_hold);
1460 			if (0)
1461 			{	printf("pushed back: <'%s'>\n", tmp_hold);
1462 			}
1463 			return 0; /* internal expansion fails */
1464 		} else
1465 		{	fatal("expecting select ( name : constant .. constant )", 0);
1466 	}	}
1467 	return 1;		/* success */
1468 }
1469 #endif
1470 
1471 int
lex(void)1472 lex(void)
1473 {	int c;
1474 again:
1475 	c = Getchar();
1476 // more:
1477 	yytext[0] = (char) c;
1478 	yytext[1] = '\0';
1479 	switch (c) {
1480 	case EOF:
1481 #ifdef DEFER_LTL
1482 		if (!deferred)
1483 		{	deferred = 1;
1484 			if (get_deferred())
1485 			{	goto again;
1486 			}
1487 		} else
1488 		{	zap_deferred();
1489 		}
1490 #endif
1491 		return c;
1492 	case '\n':		/* newline */
1493 		lineno++;
1494 		/* make most semi-colons optional */
1495 		if (implied_semis
1496 	/*	&&  context	*/
1497 		&&  in_seq
1498 		&&  par_cnt == 0
1499 		&&  follows_token(last_token))
1500 		{	if (last_token == '}')
1501 			{	do {	c = Getchar();
1502 					if (c == '\n')
1503 					{	lineno++;
1504 					}
1505 				} while (c == ' ' || c == '\t' ||
1506 					 c == '\f' || c == '\n' ||
1507 					 c == '\r');
1508 				Ungetch(c);
1509 				if (0) printf("%d: saw %d\n", lineno, c);
1510 				if (c == 'u') /* first letter of UNLESS */
1511 				{	goto again;
1512 			}	}
1513 			if (0)
1514 			{	printf("insert ; line %d, last_token %d in_seq %d\n",
1515 				 lineno-1, last_token, in_seq);
1516 			}
1517 			ValToken(1, SEMI);
1518 		}
1519 		/* else fall thru */
1520 	case '\r':		/* carriage return */
1521 		goto again;
1522 
1523 	case  ' ': case '\t': case '\f':	/* white space */
1524 		goto again;
1525 
1526 	case '#':		/* preprocessor directive */
1527 		if (in_comment) goto again;
1528 		if (pp_mode)
1529 		{	last_token = PREPROC;
1530 			return pre_proc();
1531 		}
1532 		do_directive(c);
1533 		goto again;
1534 
1535 	case '\"':
1536 		getword(c, notquote);
1537 		if (Getchar() != '\"')
1538 			fatal("string not terminated", yytext);
1539 		strcat(yytext, "\"");
1540 		SymToken(lookup(yytext), STRING)
1541 
1542 	case '$':
1543 		getword('\"', notdollar);
1544 		if (Getchar() != '$')
1545 			fatal("ltl definition not terminated", yytext);
1546 		strcat(yytext, "\"");
1547 		SymToken(lookup(yytext), STRING)
1548 
1549 	case '\'':	/* new 3.0.9 */
1550 		c = Getchar();
1551 		if (c == '\\')
1552 		{	c = Getchar();
1553 			if (c == 'n') c = '\n';
1554 			else if (c == 'r') c = '\r';
1555 			else if (c == 't') c = '\t';
1556 			else if (c == 'f') c = '\f';
1557 		}
1558 		if (Getchar() != '\'' && !in_comment)
1559 			fatal("character quote missing: %s", yytext);
1560 		ValToken(c, CONST)
1561 
1562 	default:
1563 		break;
1564 	}
1565 
1566 	if (isdigit_(c))
1567 	{	long int nr;
1568 		getword(c, isdigit_);
1569 		errno = 0;
1570 		nr = strtol(yytext, NULL, 10);
1571 		if (errno != 0)
1572 		{	fprintf(stderr, "spin: value out of range: '%s' read as '%d'\n",
1573 				yytext, (int) nr);
1574 		}
1575 		ValToken((int)nr, CONST)
1576 	}
1577 
1578 	if (isalpha_(c) || c == '_')
1579 	{	getword(c, isalnum_);
1580 		if (!in_comment)
1581 		{	c = check_name(yytext);
1582 
1583 // replace timeout with (timeout)
1584 			if (c == TIMEOUT
1585 			&&  Inlining < 0
1586 			&&  last_token != '(')
1587 			{	push_back("timeout)");
1588 				last_token = '(';
1589 				return '(';
1590 			}
1591 // end
1592 
1593 #ifdef EXPAND_SELECT
1594 			if (c == SELECT && Inlining < 0)
1595 			{	char name[64], from[32], upto[32];
1596 				int i, a, b;
1597 				new_select();
1598 				if (!scan_to('(', 0, 0)
1599 				||  !scan_to(':', isalnum, name)
1600 				||  !scan_to('.', isdigit, from)
1601 				||  !scan_to('.', 0, 0)
1602 				||  !scan_to(')', isdigit, upto))
1603 				{	goto not_expanded;
1604 				}
1605 				a = atoi(from);
1606 				b = atoi(upto);
1607 				if (0)
1608 				{	printf("Select %s from %d to %d\n",
1609 						name, a, b);
1610 				}
1611 				if (a > b)
1612 				{	non_fatal("bad range in select statement", 0);
1613 					goto again;
1614 				}
1615 				if (b - a <= 32)
1616 				{	push_back("if ");
1617 					for (i = a; i <= b; i++)
1618 					{	char buf[256];
1619 						push_back(":: ");
1620 						sprintf(buf, "%s = %d ",
1621 							name, i);
1622 						push_back(buf);
1623 					}
1624 					push_back("fi ");
1625 				} else
1626 				{	char buf[256];
1627 					sprintf(buf, "%s = %d; do ",
1628 						name, a);
1629 					push_back(buf);
1630 					sprintf(buf, ":: (%s < %d) -> %s++ ",
1631 						name, b, name);
1632 					push_back(buf);
1633 					push_back(":: break od; ");
1634 				}
1635 				goto again;
1636 			}
1637 not_expanded:
1638 #endif
1639 
1640 #ifdef DEFER_LTL
1641 			if (c == LTL && !deferred)
1642 			{	if (put_deferred())
1643 				{	goto again;
1644 			}	}
1645 #endif
1646 			if (c)
1647 			{	last_token = c;
1648 				return c;
1649 			}
1650 			/* else fall through */
1651 		}
1652 		goto again;
1653 	}
1654 
1655 	if (ltl_mode)
1656 	{	switch (c) {
1657 		case '-': c = follow('>', IMPLIES,    '-'); break;
1658 		case '[': c = follow(']', ALWAYS,     '['); break;
1659 		case '<': c = follow('>', EVENTUALLY, '<');
1660 			  if (c == '<')
1661 			  {	c = Getchar();
1662 				if (c == '-')
1663 				{	c = follow('>', EQUIV, '-');
1664 					if (c == '-')
1665 					{	Ungetch(c);
1666 						c = '<';
1667 					}
1668 				} else
1669 				{	Ungetch(c);
1670 					c = '<';
1671 			  }	}
1672 		default:  break;
1673 	}	}
1674 
1675 	switch (c) {
1676 	case '/': c = follow('*', 0, '/');
1677 		  if (!c) { in_comment = 1; goto again; }
1678 		  break;
1679 	case '*': c = follow('/', 0, '*');
1680 		  if (!c) { in_comment = 0; goto again; }
1681 		  break;
1682 	case ':': c = follow(':', SEP, ':'); break;
1683 	case '-': c = follow('>', ARROW, follow('-', DECR, '-')); break;
1684 	case '+': c = follow('+', INCR, '+'); break;
1685 	case '<': c = follow('<', LSHIFT, follow('=', LE, LT)); break;
1686 	case '>': c = follow('>', RSHIFT, follow('=', GE, GT)); break;
1687 	case '=': c = follow('=', EQ, ASGN); break;
1688 	case '!': c = follow('=', NE, follow('!', O_SND, SND)); break;
1689 	case '?': c = follow('?', R_RCV, RCV); break;
1690 	case '&': c = follow('&', AND, '&'); break;
1691 	case '|': c = follow('|', OR, '|'); break;
1692 	case ';': c = SEMI; break;
1693 	case '.': c = follow('.', DOTDOT, '.'); break;
1694 	case '{': scope_seq[scope_level++]++; set_cur_scope(); break;
1695 	case '}': scope_level--; set_cur_scope(); break;
1696 	default : break;
1697 	}
1698 	ValToken(0, c)
1699 }
1700 
1701 static struct {
1702 	char *s;	int tok;
1703 } LTL_syms[] = {
1704 	/* [], <>, ->, and <-> are intercepted in lex() */
1705 	{ "U",		UNTIL   },
1706 	{ "V",		RELEASE },
1707 	{ "W",		WEAK_UNTIL },
1708 	{ "X",		NEXT    },
1709 	{ "always",	ALWAYS  },
1710 	{ "eventually",	EVENTUALLY },
1711 	{ "until",	UNTIL   },
1712 	{ "stronguntil",UNTIL   },
1713 	{ "weakuntil",	WEAK_UNTIL   },
1714 	{ "release",	RELEASE },
1715 	{ "next",	NEXT    },
1716 	{ "implies",	IMPLIES },
1717 	{ "equivalent",	EQUIV   },
1718 	{ 0, 		0       },
1719 };
1720 
1721 static struct {
1722 	char *s;	int tok;	int val;	char *sym;
1723 } Names[] = {
1724 	{"active",	ACTIVE,		0,		0},
1725 	{"assert",	ASSERT,		0,		0},
1726 	{"atomic",	ATOMIC,		0,		0},
1727 	{"bit",		TYPE,		BIT,		0},
1728 	{"bool",	TYPE,		BIT,		0},
1729 	{"break",	BREAK,		0,		0},
1730 	{"byte",	TYPE,		BYTE,		0},
1731 	{"c_code",	C_CODE,		0,		0},
1732 	{"c_decl",	C_DECL,		0,		0},
1733 	{"c_expr",	C_EXPR,		0,		0},
1734 	{"c_state",	C_STATE,	0,		0},
1735 	{"c_track",	C_TRACK,	0,		0},
1736 	{"D_proctype",	D_PROCTYPE,	0,		0},
1737 	{"do",		DO,		0,		0},
1738 	{"chan",	TYPE,		CHAN,		0},
1739 	{"else", 	ELSE,		0,		0},
1740 	{"empty",	EMPTY,		0,		0},
1741 	{"enabled",	ENABLED,	0,		0},
1742 	{"eval",	EVAL,		0,		0},
1743 	{"false",	CONST,		0,		0},
1744 	{"fi",		FI,		0,		0},
1745 	{"for",		FOR,		0,		0},
1746 	{"full",	FULL,		0,		0},
1747 	{"get_priority", GET_P,		0,		0},
1748 	{"goto",	GOTO,		0,		0},
1749 	{"hidden",	HIDDEN,		0,		":hide:"},
1750 	{"if",		IF,		0,		0},
1751 	{"in",		IN,		0,		0},
1752 	{"init",	INIT,		0,		":init:"},
1753 	{"inline",	INLINE,		0,		0},
1754 	{"int",		TYPE,		INT,		0},
1755 	{"len",		LEN,		0,		0},
1756 	{"local",	ISLOCAL,	0,		":local:"},
1757 	{"ltl",		LTL,		0,		":ltl:"},
1758 	{"mtype",	TYPE,		MTYPE,		0},
1759 	{"nempty",	NEMPTY,		0,		0},
1760 	{"never",	CLAIM,		0,		":never:"},
1761 	{"nfull",	NFULL,		0,		0},
1762 	{"notrace",	TRACE,		0,		":notrace:"},
1763 	{"np_",		NONPROGRESS,	0,		0},
1764 	{"od",		OD,		0,		0},
1765 	{"of",		OF,		0,		0},
1766 	{"pc_value",	PC_VAL,		0,		0},
1767 	{"pid",		TYPE,		BYTE,		0},
1768 	{"printf",	PRINT,		0,		0},
1769 	{"printm",	PRINTM,		0,		0},
1770 	{"priority",	PRIORITY,	0,		0},
1771 	{"proctype",	PROCTYPE,	0,		0},
1772 	{"provided",	PROVIDED,	0,		0},
1773 	{"return",	RETURN,		0,		0},
1774 	{"run",		RUN,		0,		0},
1775 	{"d_step",	D_STEP,		0,		0},
1776 	{"select",	SELECT,		0,		0},
1777 	{"set_priority", SET_P,		0,		0},
1778 	{"short",	TYPE,		SHORT,		0},
1779 	{"skip",	CONST,		1,		0},
1780 	{"timeout",	TIMEOUT,	0,		0},
1781 	{"trace",	TRACE,		0,		":trace:"},
1782 	{"true",	CONST,		1,		0},
1783 	{"show",	SHOW,		0,		":show:"},
1784 	{"typedef",	TYPEDEF,	0,		0},
1785 	{"unless",	UNLESS,		0,		0},
1786 	{"unsigned",	TYPE,		UNSIGNED,	0},
1787 	{"xr",		XU,		XR,		0},
1788 	{"xs",		XU,		XS,		0},
1789 	{0, 		0,		0,		0},
1790 };
1791 
1792 static int
check_name(char * s)1793 check_name(char *s)
1794 {	int i;
1795 
1796 	yylval = nn(ZN, 0, ZN, ZN);
1797 
1798 	if (ltl_mode)
1799 	{	for (i = 0; LTL_syms[i].s; i++)
1800 		{	if (strcmp(s, LTL_syms[i].s) == 0)
1801 			{	return LTL_syms[i].tok;
1802 	}	}	}
1803 
1804 	for (i = 0; Names[i].s; i++)
1805 	{	if (strcmp(s, Names[i].s) == 0)
1806 		{	yylval->val = Names[i].val;
1807 			if (Names[i].sym)
1808 				yylval->sym = lookup(Names[i].sym);
1809 			if (Names[i].tok == IN && !in_for)
1810 			{	continue;
1811 			}
1812 			return Names[i].tok;
1813 	}	}
1814 
1815 	if ((yylval->val = ismtype(s)) != 0)
1816 	{	yylval->ismtyp = 1;
1817 		yylval->sym = (Symbol *) emalloc(sizeof(Symbol));
1818 		yylval->sym->name = (char *) emalloc(strlen(s)+1);
1819 		strcpy(yylval->sym->name, s);
1820 		return CONST;
1821 	}
1822 
1823 	if (strcmp(s, "_last") == 0)
1824 		has_last++;
1825 
1826 	if (strcmp(s, "_priority") == 0)
1827 		has_priority++;
1828 
1829 	if (Inlining >= 0 && !ReDiRect)
1830 	{	Lextok *tt, *t = Inline_stub[Inlining]->params;
1831 
1832 		for (i = 0; t; t = t->rgt, i++)				/* formal pars */
1833 		 if (!strcmp(s, t->lft->sym->name)			/* varname matches formal */
1834 		 &&   strcmp(s, Inline_stub[Inlining]->anms[i]) != 0)	/* actual pars */
1835 		 {
1836 #if 0
1837 			if (verbose&32)
1838 			printf("\tline %d, replace %s in call of '%s' with %s\n",
1839 				lineno, s,
1840 				Inline_stub[Inlining]->nm->name,
1841 				Inline_stub[Inlining]->anms[i]);
1842 #endif
1843 			for (tt = Inline_stub[Inlining]->params; tt; tt = tt->rgt)
1844 				if (!strcmp(Inline_stub[Inlining]->anms[i],
1845 					tt->lft->sym->name))
1846 				{	/* would be cyclic if not caught */
1847 					printf("spin: %s:%d replacement value: %s\n",
1848 						oFname->name?oFname->name:"--", lineno, tt->lft->sym->name);
1849 					fatal("formal par of %s contains replacement value",
1850 						Inline_stub[Inlining]->nm->name);
1851 					yylval->ntyp = tt->lft->ntyp;
1852 					yylval->sym = lookup(tt->lft->sym->name);
1853 					return NAME;
1854 				}
1855 
1856 			/* check for occurrence of param as field of struct */
1857 			{ char *ptr = Inline_stub[Inlining]->anms[i];
1858 				while ((ptr = strstr(ptr, s)) != NULL)
1859 				{	if (*(ptr-1) == '.'
1860 					||  *(ptr+strlen(s)) == '.')
1861 					{	fatal("formal par of %s used in structure name",
1862 						Inline_stub[Inlining]->nm->name);
1863 					}
1864 					ptr++;
1865 			}	}
1866 			ReDiRect = Inline_stub[Inlining]->anms[i];
1867 			return 0;
1868 	}	 }
1869 
1870 	yylval->sym = lookup(s);	/* symbol table */
1871 	if (isutype(s))
1872 		return UNAME;
1873 	if (isproctype(s))
1874 		return PNAME;
1875 	if (iseqname(s))
1876 		return INAME;
1877 
1878 	return NAME;
1879 }
1880 
1881 int
yylex(void)1882 yylex(void)
1883 {	static int last = 0;
1884 	static int hold = 0;
1885 	int c;
1886 	/*
1887 	 * repair two common syntax mistakes with
1888 	 * semi-colons before or after a '}'
1889 	 */
1890 	if (hold)
1891 	{	c = hold;
1892 		hold = 0;
1893 		last_token = c;
1894 	} else
1895 	{	c = lex();
1896 		if (last == ELSE
1897 		&&  c != SEMI
1898 		&&  c != ARROW
1899 		&&  c != FI)
1900 		{	hold = c;
1901 			last = 0;
1902 			last_token = SEMI;
1903 			return SEMI;
1904 		}
1905 		if (last == '}'
1906 		&&  c != PROCTYPE
1907 		&&  c != INIT
1908 		&&  c != CLAIM
1909 		&&  c != SEP
1910 		&&  c != FI
1911 		&&  c != OD
1912 		&&  c != '}'
1913 		&&  c != UNLESS
1914 		&&  c != SEMI
1915 		&&  c != ARROW
1916 		&&  c != EOF)
1917 		{	hold = c;
1918 			last = 0;
1919 			last_token = SEMI;
1920 			return SEMI;	/* insert ';' */
1921 		}
1922 		if (c == SEMI || c == ARROW)
1923 		{	/* if context, we're not in a typedef
1924 			 * because they're global.
1925 			 * if owner, we're at the end of a ref
1926 			 * to a struct field -- prevent that the
1927 			 * lookahead is interpreted as a field of
1928 			 * the same struct...
1929 			 */
1930 			if (context) owner = ZS;
1931 			hold = lex();	/* look ahead */
1932 			if (hold == '}'
1933 			||  hold == ARROW
1934 			||  hold == SEMI)
1935 			{	c = hold; /* omit ';' */
1936 				hold = 0;
1937 			}
1938 		}
1939 	}
1940 	last = c;
1941 
1942 	if (IArgs)
1943 	{	static int IArg_nst = 0;
1944 
1945 		if (strcmp(yytext, ",") == 0)
1946 		{	IArg_cont[++IArgno][0] = '\0';
1947 		} else if (strcmp(yytext, "(") == 0)
1948 		{	if (IArg_nst++ == 0)
1949 			{	IArgno = 0;
1950 				IArg_cont[0][0] = '\0';
1951 			} else
1952 			{	assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont));
1953 				strcat(IArg_cont[IArgno], yytext);
1954 			}
1955 		} else if (strcmp(yytext, ")") == 0)
1956 		{	if (--IArg_nst > 0)
1957 			{	assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont));
1958 				strcat(IArg_cont[IArgno], yytext);
1959 			}
1960 		} else if (c == CONST && yytext[0] == '\'')
1961 		{	sprintf(yytext, "'%c'", yylval->val);
1962 			assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont));
1963 			strcat(IArg_cont[IArgno], yytext);
1964 		} else if (c == CONST)
1965 		{	sprintf(yytext, "%d", yylval->val);
1966 			assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont));
1967 			strcat(IArg_cont[IArgno], yytext);
1968 		} else
1969 		{
1970 			switch (c) {
1971 			case ARROW:	strcpy(yytext, "->"); break; /* NEW */
1972 			case SEP:	strcpy(yytext, "::"); break;
1973 			case SEMI:	strcpy(yytext, ";"); break;
1974 			case DECR:	strcpy(yytext, "--"); break;
1975 			case INCR: 	strcpy(yytext, "++"); break;
1976 			case LSHIFT:	strcpy(yytext, "<<"); break;
1977 			case RSHIFT:	strcpy(yytext, ">>"); break;
1978 			case LE:	strcpy(yytext, "<="); break;
1979 			case LT:	strcpy(yytext, "<"); break;
1980 			case GE:	strcpy(yytext, ">="); break;
1981 			case GT:	strcpy(yytext, ">"); break;
1982 			case EQ:	strcpy(yytext, "=="); break;
1983 			case ASGN:	strcpy(yytext, "="); break;
1984 			case NE:	strcpy(yytext, "!="); break;
1985 			case R_RCV:	strcpy(yytext, "??"); break;
1986 			case RCV:	strcpy(yytext, "?"); break;
1987 			case O_SND:	strcpy(yytext, "!!"); break;
1988 			case SND:	strcpy(yytext, "!"); break;
1989 			case AND: 	strcpy(yytext, "&&"); break;
1990 			case OR:	strcpy(yytext, "||"); break;
1991 			}
1992 			assert(strlen(IArg_cont[IArgno])+strlen(yytext) < sizeof(IArg_cont));
1993 			strcat(IArg_cont[IArgno], yytext);
1994 		}
1995 	}
1996 	return c;
1997 }
1998