1 /***** spin: spinlex.c *****/
3 /* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */
4 /* All Rights Reserved. This software is for educational purposes only. */
5 /* No guarantee whatsoever is expressed or implied by the distribution of */
6 /* this code. Permission is given to distribute this code provided that */
7 /* this introductory message is not removed and no monies are exchanged. */
8 /* Software written by Gerard J. Holzmann. For tool documentation see: */
9 /* http://spinroot.com/ */
10 /* Send all bug-reports and/or questions to: bugs@spinroot.com */
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 */
20 typedef struct IType {
21 Symbol *nm; /* name of the type */
22 Lextok *cn; /* contents */
23 Lextok *params; /* formal pars if any */
24 char **anms; /* literal text for actual pars */
25 char *prec; /* precondition for c_code or c_expr */
26 int dln, cln; /* def and call linenr */
27 Symbol *dfn, *cfn; /* def and call filename */
28 struct IType *nxt; /* linked list */
31 typedef struct C_Added {
41 extern Symbol *context, *owner;
42 extern YYSTYPE yylval;
43 extern short has_last, has_code;
44 extern int verbose, IArgs, hastrack, separate;
51 static C_Added *c_added, *c_tracked;
52 static IType *Inline_stub[MAXINL];
53 static char *ReDiRect;
54 static char *Inliner[MAXINL], IArg_cont[MAXPAR][MAXLEN];
55 static unsigned char in_comment=0;
56 static int IArgno = 0, Inlining = -1;
57 static int check_name(char *);
60 #define Token(y) { if (in_comment) goto again; \
61 yylval = nn(ZN,0,ZN,ZN); return y; }
63 #define ValToken(x, y) { if (in_comment) goto again; \
64 yylval = nn(ZN,0,ZN,ZN); yylval->val = x; return y; }
66 #define SymToken(x, y) { if (in_comment) goto again; \
67 yylval = nn(ZN,0,ZN,ZN); yylval->sym = x; return y; }
69 #define Token(y) { yylval = nn(ZN,0,ZN,ZN); \
70 if (!in_comment) return y; else goto again; }
72 #define ValToken(x, y) { yylval = nn(ZN,0,ZN,ZN); yylval->val = x; \
73 if (!in_comment) return y; else goto again; }
75 #define SymToken(x, y) { yylval = nn(ZN,0,ZN,ZN); yylval->sym = x; \
76 if (!in_comment) return y; else goto again; }
79 static int getinline(void);
80 static void uninline(void);
83 #define Getchar() ((Inlining<0)?getc(yyin):getinline())
84 #define Ungetch(c) {if (Inlining<0) ungetc(c,yyin); else uninline(); }
116 { return (c != '\"' && c != '\n');
121 { return (isalnum(c) || c == '_');
126 { return isalpha(c); /* could be macro */
131 { return isdigit(c); /* could be macro */
135 getword(int first, int (*tst)(int))
138 yytext[i++]= (char) first;
139 while (tst(c = Getchar()))
142 yytext[i++] = Getchar(); /* no tst */
149 follow(int tok, int ifyes, int ifno)
152 if ((c = Getchar()) == tok)
159 static IType *seqnames;
162 def_inline(Symbol *s, int ln, char *ptr, char *prc, Lextok *nms)
164 char *nw = (char *) emalloc((int) strlen(ptr)+1);
167 for (tmp = seqnames; tmp; tmp = tmp->nxt)
168 if (!strcmp(s->name, tmp->nm->name))
169 { non_fatal("procedure name %s redefined",
171 tmp->cn = (Lextok *) nw;
177 tmp = (IType *) emalloc(sizeof(IType));
179 tmp->cn = (Lextok *) nw;
182 { tmp->prec = (char *) emalloc((int) strlen(prc)+1);
183 strcpy(tmp->prec, prc);
192 gencodetable(FILE *fd)
197 if (separate == 2) return;
199 fprintf(fd, "struct {\n");
200 fprintf(fd, " char *c; char *t;\n");
201 fprintf(fd, "} code_lookup[] = {\n");
204 for (tmp = seqnames; tmp; tmp = tmp->nxt)
205 if (tmp->nm->type == CODE_FRAG
206 || tmp->nm->type == CODE_DECL)
207 { fprintf(fd, "\t{ \"%s\", ",
209 q = (char *) tmp->cn;
211 while (*q == '\n' || *q == '\r' || *q == '\\')
216 while (*q && cnt < 1024) /* pangen1.h allows 2048 */
233 if (*q) fprintf(fd, "...");
235 fprintf(fd, " },\n");
238 fprintf(fd, " { (char *) 0, \"\" }\n");
246 for (tmp = seqnames; tmp; tmp = tmp->nxt)
247 { if (!strcmp(t, tmp->nm->name))
260 { ReDiRect = (char *) 0;
261 c = *Inliner[Inlining]++;
264 c = *Inliner[Inlining]++;
267 { lineno = Inline_stub[Inlining]->cln;
268 Fname = Inline_stub[Inlining]->cfn;
272 printf("spin: line %d, done inlining %s\n",
273 lineno, Inline_stub[Inlining+1]->nm->name);
293 for (tmp = seqnames; tmp; tmp = tmp->nxt)
294 if (!strcmp(s, tmp->nm->name))
297 fatal("cannot happen, missing inline def %s", s);
302 c_state(Symbol *s, Symbol *t, Symbol *ival) /* name, scope, ival */
305 r = (C_Added *) emalloc(sizeof(C_Added));
306 r->s = s; /* pointer to a data object */
307 r->t = t; /* size of object, or "global", or "local proctype_name" */
314 c_track(Symbol *s, Symbol *t, Symbol *stackonly) /* name, size */
317 r = (C_Added *) emalloc(sizeof(C_Added));
320 r->ival = stackonly; /* abuse of name */
325 { if (strcmp(stackonly->name, "\"Matched\"") == 0)
326 r->ival = ZS; /* the default */
327 else if (strcmp(stackonly->name, "\"UnMatched\"") != 0
328 && strcmp(stackonly->name, "\"unMatched\"") != 0
329 && strcmp(stackonly->name, "\"StackOnly\"") != 0)
330 non_fatal("expecting '[Un]Matched', saw %s", stackonly->name);
340 /* kludgy - try to get the type separated from the name */
342 while (*p == ' ' || *p == '\t')
343 p++; /* initial white space */
344 while (*p != ' ' && *p != '\t')
346 while (*p == ' ' || *p == '\t')
347 p++; /* white space */
349 p++; /* decorations */
350 while (*p == ' ' || *p == '\t')
351 p++; /* white space */
354 fatal("c_state format (%s)", op);
358 { non_fatal("array initialization error, c_state (%s)", p);
366 c_add_globinit(FILE *fd)
370 fprintf(fd, "void\nglobinit(void)\n{\n");
371 for (r = c_added; r; r = r->nxt)
375 if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0)
376 { for (q = r->ival->name; *q; q++)
380 *q++ = ' '; /* skip over the next */
382 p = jump_etc(r->s->name); /* e.g., "int **q" */
384 fprintf(fd, " now.%s = %s;\n", p, r->ival->name);
387 if (strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0)
388 { for (q = r->ival->name; *q; q++)
392 *q++ = ' '; /* skip over the next */
394 p = jump_etc(r->s->name); /* e.g., "int **q" */
396 fprintf(fd, " %s = %s;\n", p, r->ival->name); /* no now. prefix */
403 c_add_locinit(FILE *fd, int tpnr, char *pnm)
408 fprintf(fd, "void\nlocinit%d(int h)\n{\n", tpnr);
409 for (r = c_added; r; r = r->nxt)
411 && strncmp(r->t->name, " Local", strlen(" Local")) == 0)
412 { for (q = r->ival->name; *q; q++)
416 p = jump_etc(r->s->name); /* e.g., "int **q" */
418 q = r->t->name + strlen(" Local");
419 while (*q == ' ' || *q == '\t')
420 q++; /* process name */
422 s = (char *) emalloc(strlen(q)+1);
426 while (*q == ' ' || *q == '\t')
429 if (strcmp(pnm, s) != 0)
433 { fprintf(fd, "\tuchar *this = pptr(h);\n");
438 fprintf(fd, " ((P%d *)this)->%s = %s;\n",
439 tpnr, p, r->ival->name);
446 1. for non-global and non-local c_state decls: add up all the sizes in c_added
447 2. add a global char array of that size into now
448 3. generate a routine that memcpy's the required values into that array
449 4. generate a call to that routine
460 for (r = c_added; r; r = r->nxt)
461 if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0
462 && strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0
463 && strncmp(r->t->name, " Local", strlen(" Local")) != 0)
464 { hastrack = 1; /* c_state variant now obsolete */
470 c_add_sv(FILE *fd) /* 1+2 -- called in pangen1.c */
474 if (!c_added && !c_tracked) return 0;
476 for (r = c_added; r; r = r->nxt) /* pickup global decls */
477 if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0)
478 fprintf(fd, " %s;\n", r->s->name);
480 for (r = c_added; r; r = r->nxt)
481 if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0
482 && strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0
483 && strncmp(r->t->name, " Local", strlen(" Local")) != 0)
484 { cnt++; /* obsolete use */
487 for (r = c_tracked; r; r = r->nxt)
488 cnt++; /* preferred use */
490 if (cnt == 0) return 0;
493 fprintf(fd, " uchar c_state[");
494 for (r = c_added; r; r = r->nxt)
495 if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0
496 && strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0
497 && strncmp(r->t->name, " Local", strlen(" Local")) != 0)
498 { fprintf(fd, "%ssizeof(%s)",
499 (cnt==0)?"":"+", r->t->name);
503 for (r = c_tracked; r; r = r->nxt)
504 { if (r->ival != ZS) continue;
507 (cnt==0)?"":"+", r->t->name);
511 if (cnt == 0) fprintf(fd, "4"); /* now redundant */
517 c_add_stack(FILE *fd)
521 if ((!c_added && !c_tracked) || !has_stack) return;
524 for (r = c_tracked; r; r = r->nxt)
528 if (cnt == 0) return;
530 fprintf(fd, " uchar c_stack[");
533 for (r = c_tracked; r; r = r->nxt)
534 { if (r->ival == ZS) continue;
537 (cnt==0)?"":"+", r->t->name);
541 if (cnt == 0) fprintf(fd, "WS"); /* can't happen */
546 c_add_hidden(FILE *fd)
549 for (r = c_added; r; r = r->nxt) /* pickup hidden decls */
550 if (strncmp(r->t->name, "\"Hidden\"", strlen("\"Hidden\"")) == 0)
551 { r->s->name[strlen(r->s->name)-1] = ' ';
552 fprintf(fd, "%s; /* Hidden */\n", &r->s->name[1]);
553 r->s->name[strlen(r->s->name)-1] = '"';
555 /* called before c_add_def - quotes are still there */
559 c_add_loc(FILE *fd, char *s) /* state vector entries for proctype s */
561 static char buf[1024];
564 if (!c_added) return;
568 for (r = c_added; r; r = r->nxt) /* pickup local decls */
569 if (strncmp(r->t->name, " Local", strlen(" Local")) == 0)
570 { p = r->t->name + strlen(" Local");
571 while (*p == ' ' || *p == '\t')
573 if (strcmp(p, buf) == 0)
574 fprintf(fd, " %s;\n", r->s->name);
578 c_add_def(FILE *fd) /* 3 - called in plunk_c_fcts() */
581 fprintf(fd, "#if defined(C_States) && defined(HAS_TRACK)\n");
582 for (r = c_added; r; r = r->nxt)
583 { r->s->name[strlen(r->s->name)-1] = ' ';
584 r->s->name[0] = ' '; /* remove the "s */
586 r->t->name[strlen(r->t->name)-1] = ' ';
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)
594 if (strchr(r->s->name, '&'))
595 fatal("dereferencing state object: %s", r->s->name);
597 fprintf(fd, "extern %s %s;\n", r->t->name, r->s->name);
599 for (r = c_tracked; r; r = r->nxt)
600 { r->s->name[strlen(r->s->name)-1] = ' ';
601 r->s->name[0] = ' '; /* remove " */
603 r->t->name[strlen(r->t->name)-1] = ' ';
608 { fprintf(fd, "#endif\n");
613 { fprintf(fd, "void\nc_stack(uchar *p_t_r)\n{\n");
614 fprintf(fd, "#ifdef VERBOSE\n");
615 fprintf(fd, " printf(\"c_stack %%u\\n\", p_t_r);\n");
616 fprintf(fd, "#endif\n");
617 for (r = c_tracked; r; r = r->nxt)
618 { if (r->ival == ZS) continue;
620 fprintf(fd, "\tif(%s)\n", r->s->name);
621 fprintf(fd, "\t\tmemcpy(p_t_r, %s, %s);\n",
622 r->s->name, r->t->name);
623 fprintf(fd, "\telse\n");
624 fprintf(fd, "\t\tmemset(p_t_r, 0, %s);\n",
626 fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
628 fprintf(fd, "}\n\n");
631 fprintf(fd, "void\nc_update(uchar *p_t_r)\n{\n");
632 fprintf(fd, "#ifdef VERBOSE\n");
633 fprintf(fd, " printf(\"c_update %%u\\n\", p_t_r);\n");
634 fprintf(fd, "#endif\n");
635 for (r = c_added; r; r = r->nxt)
636 { if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0
637 || strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0
638 || strncmp(r->t->name, " Local", strlen(" Local")) == 0)
641 fprintf(fd, "\tmemcpy(p_t_r, &%s, sizeof(%s));\n",
642 r->s->name, r->t->name);
643 fprintf(fd, "\tp_t_r += sizeof(%s);\n", r->t->name);
646 for (r = c_tracked; r; r = r->nxt)
647 { if (r->ival) continue;
649 fprintf(fd, "\tif(%s)\n", r->s->name);
650 fprintf(fd, "\t\tmemcpy(p_t_r, %s, %s);\n",
651 r->s->name, r->t->name);
652 fprintf(fd, "\telse\n");
653 fprintf(fd, "\t\tmemset(p_t_r, 0, %s);\n",
655 fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
661 { fprintf(fd, "void\nc_unstack(uchar *p_t_r)\n{\n");
662 fprintf(fd, "#ifdef VERBOSE\n");
663 fprintf(fd, " printf(\"c_unstack %%u\\n\", p_t_r);\n");
664 fprintf(fd, "#endif\n");
665 for (r = c_tracked; r; r = r->nxt)
666 { if (r->ival == ZS) continue;
668 fprintf(fd, "\tif(%s)\n", r->s->name);
669 fprintf(fd, "\t\tmemcpy(%s, p_t_r, %s);\n",
670 r->s->name, r->t->name);
671 fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
676 fprintf(fd, "void\nc_revert(uchar *p_t_r)\n{\n");
677 fprintf(fd, "#ifdef VERBOSE\n");
678 fprintf(fd, " printf(\"c_revert %%u\\n\", p_t_r);\n");
679 fprintf(fd, "#endif\n");
680 for (r = c_added; r; r = r->nxt)
681 { if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0
682 || strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0
683 || strncmp(r->t->name, " Local", strlen(" Local")) == 0)
686 fprintf(fd, "\tmemcpy(&%s, p_t_r, sizeof(%s));\n",
687 r->s->name, r->t->name);
688 fprintf(fd, "\tp_t_r += sizeof(%s);\n", r->t->name);
690 for (r = c_tracked; r; r = r->nxt)
691 { if (r->ival != ZS) continue;
693 fprintf(fd, "\tif(%s)\n", r->s->name);
694 fprintf(fd, "\t\tmemcpy(%s, p_t_r, %s);\n",
695 r->s->name, r->t->name);
696 fprintf(fd, "\tp_t_r += %s;\n", r->t->name);
700 fprintf(fd, "#endif\n");
704 plunk_reverse(FILE *fd, IType *p, int matchthis)
708 plunk_reverse(fd, p->nxt, matchthis);
711 && p->nm->type == matchthis)
712 { fprintf(fd, "\n/* start of %s */\n", p->nm->name);
714 while (*z == '\n' || *z == '\r' || *z == '\\')
716 /* e.g.: \#include "..." */
719 while ((y = strstr(y, "\\#")) != NULL)
723 fprintf(fd, "%s\n", z);
724 fprintf(fd, "\n/* end of %s */\n", p->nm->name);
729 plunk_c_decls(FILE *fd)
731 plunk_reverse(fd, seqnames, CODE_DECL);
735 plunk_c_fcts(FILE *fd)
737 if (separate == 2 && hastrack)
743 plunk_reverse(fd, seqnames, CODE_FRAG);
745 if (c_added || c_tracked) /* enables calls to c_revert and c_update */
746 fprintf(fd, "#define C_States 1\n");
748 fprintf(fd, "#undef C_States\n");
758 check_inline(IType *tmp)
764 for (p = rdy; p; p = p->nxt)
765 { if (strcmp(p->n->name, X->n->name) == 0)
767 sprintf(buf, "P%s->", p->n->name);
768 if (strstr((char *)tmp->cn, buf))
769 { printf("spin: in proctype %s, ref to object in proctype %s\n",
770 X->n->name, p->n->name);
771 fatal("invalid variable ref in '%s'", tmp->nm->name);
776 plunk_expr(FILE *fd, char *s)
779 tmp = find_inline(s);
782 fprintf(fd, "%s", (char *) tmp->cn);
786 preruse(FILE *fd, Lextok *n) /* check a condition for c_expr with preconditions */
790 if (n->ntyp == C_EXPR)
791 { tmp = find_inline(n->sym->name);
793 { fprintf(fd, "if (!(%s)) { if (!readtrail) { depth++; ", tmp->prec);
794 fprintf(fd, "trpt++; trpt->pr = II; trpt->o_t = t;");
795 fprintf(fd, "trpt->st = tt; Uerror(\"%s\"); } ", tmp->prec);
796 fprintf(fd, "else { printf(\"pan: precondition false: %s\\n\"); ", tmp->prec);
797 fprintf(fd, "_m = 3; goto P999; } } \n\t\t");
800 { preruse(fd, n->rgt);
810 tmp = find_inline(s);
811 bdy = (char *) tmp->cn;
812 return (strstr(bdy, "now.") /* global ref or */
813 || strchr(bdy, '(') > bdy); /* possible C-function call */
817 plunk_inline(FILE *fd, char *s, int how) /* c_code with precondition */
820 tmp = find_inline(s);
824 if (how && tmp->prec)
825 { fprintf(fd, "if (!(%s)) { if (!readtrail) { depth++; ", tmp->prec);
826 fprintf(fd, "trpt++; trpt->pr = II; trpt->o_t = t;");
827 fprintf(fd, "trpt->st = tt; Uerror(\"%s\"); } ", tmp->prec);
828 fprintf(fd, "else { printf(\"pan: precondition false: %s\\n\"); ", tmp->prec);
829 fprintf(fd, "_m = 3; goto P999; } } ");
831 fprintf(fd, "%s", (char *) tmp->cn);
836 no_side_effects(char *s)
840 /* could still defeat this check via hidden
841 * side effects in function calls,
842 * but this will catch at least some cases
845 tmp = find_inline(s);
846 t = (char *) tmp->cn;
852 bad: lineno = tmp->dln;
854 non_fatal("c_expr %s has side-effects", s);
857 while ((t = strchr(t, '=')) != NULL)
872 pickup_inline(Symbol *t, Lextok *apars)
873 { IType *tmp; Lextok *p, *q; int j;
875 tmp = find_inline(t->name);
877 if (++Inlining >= MAXINL)
878 fatal("inline fcts too deeply nested", 0);
880 tmp->cln = lineno; /* remember calling point */
881 tmp->cfn = Fname; /* and filename */
883 for (p = apars, q = tmp->params, j = 0; p && q; p = p->rgt, q = q->rgt)
884 j++; /* count them */
886 fatal("wrong nr of params on call of '%s'", t->name);
888 tmp->anms = (char **) emalloc(j * sizeof(char *));
889 for (p = apars, j = 0; p; p = p->rgt, j++)
890 { tmp->anms[j] = (char *) emalloc((int) strlen(IArg_cont[j])+1);
891 strcpy(tmp->anms[j], IArg_cont[j]);
894 lineno = tmp->dln; /* linenr of def */
895 Fname = tmp->dfn; /* filename of same */
896 Inliner[Inlining] = (char *)tmp->cn;
897 Inline_stub[Inlining] = tmp;
900 printf("spin: line %d, file %s, inlining '%s' (from line %d, file %s)\n",
901 tmp->cln, tmp->cfn->name, t->name, tmp->dln, tmp->dfn->name);
903 for (j = 0; j < Inlining; j++)
904 if (Inline_stub[j] == Inline_stub[Inlining])
905 fatal("cyclic inline attempt on: %s", t->name);
909 do_directive(int first)
910 { int c = first; /* handles lines starting with pound */
912 getword(c, isalpha_);
914 if (strcmp(yytext, "#ident") == 0)
917 if ((c = Getchar()) != ' ')
918 fatal("malformed preprocessor directive - # .", 0);
920 if (!isdigit_(c = Getchar()))
921 fatal("malformed preprocessor directive - # .lineno", 0);
923 getword(c, isdigit_);
924 lineno = atoi(yytext); /* pickup the line number */
926 if ((c = Getchar()) == '\n')
927 return; /* no filename */
930 fatal("malformed preprocessor directive - .fname", 0);
932 if ((c = Getchar()) != '\"')
933 fatal("malformed preprocessor directive - .fname", 0);
935 getword(c, notquote);
936 if (Getchar() != '\"')
937 fatal("malformed preprocessor directive - fname.", 0);
939 strcat(yytext, "\"");
940 Fname = lookup(yytext);
942 while (Getchar() != '\n')
947 precondition(char *q)
968 fatal("cannot happen", (char *) 0);
972 prep_inline(Symbol *s, Lextok *nms)
973 { int c, nest = 1, dln, firstchar, cnr;
974 char *p, buf[SOMETHINGBIG], buf2[RATHERSMALL];
976 static int c_code = 1;
978 for (t = nms; t; t = t->rgt)
980 { if (t->lft->ntyp != NAME)
981 fatal("bad param to inline %s", s->name);
982 t->lft->sym->hidden |= 32;
985 if (!s) /* C_Code fragment */
986 { s = (Symbol *) emalloc(sizeof(Symbol));
987 s->name = (char *) emalloc((int) strlen("c_code")+26);
988 sprintf(s->name, "c_code%d", c_code++);
989 s->context = context;
1000 if (s->type != CODE_FRAG)
1002 precondition(&buf2[0]); /* e.g., c_code [p] { r = p-r; } */
1009 case ' ': case '\t': case '\f': case '\r':
1012 printf("spin: saw char '%c'\n", c);
1013 bad: fatal("bad inline: %s", s->name);
1018 if (s->type == CODE_FRAG)
1020 sprintf(buf, "\t/* line %d %s */\n\t\t",
1021 lineno, Fname->name);
1025 sprintf(buf, "\n#line %d %s\n{", lineno, Fname->name);
1029 cnr = 1; /* not zero */
1031 *p++ = c = Getchar();
1032 if (p - buf >= SOMETHINGBIG)
1033 fatal("inline text too long", 0);
1047 if (s->type == CODE_FRAG)
1048 *--p = '\0'; /* remove trailing '}' */
1049 def_inline(s, dln, &buf[0], &buf2[0], nms);
1051 printf("%3d: %s, warning: empty inline definition (%s)\n",
1052 dln, Fname->name, s->name);
1053 return s; /* normal return */
1059 do_directive(c); /* reads to newline */
1061 } /* else fall through */
1079 yytext[0] = (char) c;
1082 case '\n': /* newline */
1084 case '\r': /* carriage return */
1087 case ' ': case '\t': case '\f': /* white space */
1090 case '#': /* preprocessor directive */
1091 if (in_comment) goto again;
1096 getword(c, notquote);
1097 if (Getchar() != '\"')
1098 fatal("string not terminated", yytext);
1099 strcat(yytext, "\"");
1100 SymToken(lookup(yytext), STRING)
1102 case '\'': /* new 3.0.9 */
1106 if (c == 'n') c = '\n';
1107 else if (c == 'r') c = '\r';
1108 else if (c == 't') c = '\t';
1109 else if (c == 'f') c = '\f';
1111 if (Getchar() != '\'' && !in_comment)
1112 fatal("character quote missing: %s", yytext);
1120 { getword(c, isdigit_);
1121 ValToken(atoi(yytext), CONST)
1124 if (isalpha_(c) || c == '_')
1125 { getword(c, isalnum_);
1127 { c = check_name(yytext);
1129 /* else fall through */
1135 case '/': c = follow('*', 0, '/');
1136 if (!c) { in_comment = 1; goto again; }
1138 case '*': c = follow('/', 0, '*');
1139 if (!c) { in_comment = 0; goto again; }
1141 case ':': c = follow(':', SEP, ':'); break;
1142 case '-': c = follow('>', SEMI, follow('-', DECR, '-')); break;
1143 case '+': c = follow('+', INCR, '+'); break;
1144 case '<': c = follow('<', LSHIFT, follow('=', LE, LT)); break;
1145 case '>': c = follow('>', RSHIFT, follow('=', GE, GT)); break;
1146 case '=': c = follow('=', EQ, ASGN); break;
1147 case '!': c = follow('=', NE, follow('!', O_SND, SND)); break;
1148 case '?': c = follow('?', R_RCV, RCV); break;
1149 case '&': c = follow('&', AND, '&'); break;
1150 case '|': c = follow('|', OR, '|'); break;
1151 case ';': c = SEMI; break;
1158 char *s; int tok; int val; char *sym;
1160 {"active", ACTIVE, 0, 0},
1161 {"assert", ASSERT, 0, 0},
1162 {"atomic", ATOMIC, 0, 0},
1163 {"bit", TYPE, BIT, 0},
1164 {"bool", TYPE, BIT, 0},
1165 {"break", BREAK, 0, 0},
1166 {"byte", TYPE, BYTE, 0},
1167 {"c_code", C_CODE, 0, 0},
1168 {"c_decl", C_DECL, 0, 0},
1169 {"c_expr", C_EXPR, 0, 0},
1170 {"c_state", C_STATE, 0, 0},
1171 {"c_track", C_TRACK, 0, 0},
1172 {"D_proctype", D_PROCTYPE, 0, 0},
1174 {"chan", TYPE, CHAN, 0},
1175 {"else", ELSE, 0, 0},
1176 {"empty", EMPTY, 0, 0},
1177 {"enabled", ENABLED, 0, 0},
1178 {"eval", EVAL, 0, 0},
1179 {"false", CONST, 0, 0},
1181 {"full", FULL, 0, 0},
1182 {"goto", GOTO, 0, 0},
1183 {"hidden", HIDDEN, 0, ":hide:"},
1185 {"init", INIT, 0, ":init:"},
1186 {"int", TYPE, INT, 0},
1188 {"local", ISLOCAL, 0, ":local:"},
1189 {"mtype", TYPE, MTYPE, 0},
1190 {"nempty", NEMPTY, 0, 0},
1191 {"never", CLAIM, 0, ":never:"},
1192 {"nfull", NFULL, 0, 0},
1193 {"notrace", TRACE, 0, ":notrace:"},
1194 {"np_", NONPROGRESS, 0, 0},
1197 {"pc_value", PC_VAL, 0, 0},
1198 {"pid", TYPE, BYTE, 0},
1199 {"printf", PRINT, 0, 0},
1200 {"printm", PRINTM, 0, 0},
1201 {"priority", PRIORITY, 0, 0},
1202 {"proctype", PROCTYPE, 0, 0},
1203 {"provided", PROVIDED, 0, 0},
1205 {"d_step", D_STEP, 0, 0},
1206 {"inline", INLINE, 0, 0},
1207 {"short", TYPE, SHORT, 0},
1208 {"skip", CONST, 1, 0},
1209 {"timeout", TIMEOUT, 0, 0},
1210 {"trace", TRACE, 0, ":trace:"},
1211 {"true", CONST, 1, 0},
1212 {"show", SHOW, 0, ":show:"},
1213 {"typedef", TYPEDEF, 0, 0},
1214 {"unless", UNLESS, 0, 0},
1215 {"unsigned", TYPE, UNSIGNED, 0},
1225 yylval = nn(ZN, 0, ZN, ZN);
1226 for (i = 0; Names[i].s; i++)
1227 if (strcmp(s, Names[i].s) == 0)
1228 { yylval->val = Names[i].val;
1230 yylval->sym = lookup(Names[i].sym);
1231 return Names[i].tok;
1234 if ((yylval->val = ismtype(s)) != 0)
1235 { yylval->ismtyp = 1;
1239 if (strcmp(s, "_last") == 0)
1242 if (Inlining >= 0 && !ReDiRect)
1243 { Lextok *tt, *t = Inline_stub[Inlining]->params;
1245 for (i = 0; t; t = t->rgt, i++) /* formal pars */
1246 if (!strcmp(s, t->lft->sym->name) /* varname matches formal */
1247 && strcmp(s, Inline_stub[Inlining]->anms[i]) != 0) /* actual pars */
1251 printf("\tline %d, replace %s in call of '%s' with %s\n",
1253 Inline_stub[Inlining]->nm->name,
1254 Inline_stub[Inlining]->anms[i]);
1257 for (tt = Inline_stub[Inlining]->params; tt; tt = tt->rgt)
1258 if (!strcmp(Inline_stub[Inlining]->anms[i],
1259 tt->lft->sym->name))
1260 { /* would be cyclic if not caught */
1261 printf("spin: line %d replacement value: %s\n",
1262 lineno, tt->lft->sym->name);
1263 fatal("formal par of %s matches replacement value",
1264 Inline_stub[Inlining]->nm->name);
1265 yylval->ntyp = tt->lft->ntyp;
1266 yylval->sym = lookup(tt->lft->sym->name);
1269 ReDiRect = Inline_stub[Inlining]->anms[i];
1273 yylval->sym = lookup(s); /* symbol table */
1286 { static int last = 0;
1287 static int hold = 0;
1290 * repair two common syntax mistakes with
1291 * semi-colons before or after a '}'
1318 return SEMI; /* insert ';' */
1321 { /* if context, we're not in a typedef
1322 * because they're global.
1323 * if owner, we're at the end of a ref
1324 * to a struct field -- prevent that the
1325 * lookahead is interpreted as a field of
1326 * the same struct...
1328 if (context) owner = ZS;
1329 hold = lex(); /* look ahead */
1332 { c = hold; /* omit ';' */
1340 { static int IArg_nst = 0;
1342 if (strcmp(yytext, ",") == 0)
1343 { IArg_cont[++IArgno][0] = '\0';
1344 } else if (strcmp(yytext, "(") == 0)
1345 { if (IArg_nst++ == 0)
1347 IArg_cont[0][0] = '\0';
1349 strcat(IArg_cont[IArgno], yytext);
1350 } else if (strcmp(yytext, ")") == 0)
1351 { if (--IArg_nst > 0)
1352 strcat(IArg_cont[IArgno], yytext);
1353 } else if (c == CONST && yytext[0] == '\'')
1354 { sprintf(yytext, "'%c'", yylval->val);
1355 strcat(IArg_cont[IArgno], yytext);
1359 case SEP: strcpy(yytext, "::"); break;
1360 case SEMI: strcpy(yytext, ";"); break;
1361 case DECR: strcpy(yytext, "--"); break;
1362 case INCR: strcpy(yytext, "++"); break;
1363 case LSHIFT: strcpy(yytext, "<<"); break;
1364 case RSHIFT: strcpy(yytext, ">>"); break;
1365 case LE: strcpy(yytext, "<="); break;
1366 case LT: strcpy(yytext, "<"); break;
1367 case GE: strcpy(yytext, ">="); break;
1368 case GT: strcpy(yytext, ">"); break;
1369 case EQ: strcpy(yytext, "=="); break;
1370 case ASGN: strcpy(yytext, "="); break;
1371 case NE: strcpy(yytext, "!="); break;
1372 case R_RCV: strcpy(yytext, "??"); break;
1373 case RCV: strcpy(yytext, "?"); break;
1374 case O_SND: strcpy(yytext, "!!"); break;
1375 case SND: strcpy(yytext, "!"); break;
1376 case AND: strcpy(yytext, "&&"); break;
1377 case OR: strcpy(yytext, "||"); break;
1379 strcat(IArg_cont[IArgno], yytext);