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