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