| 1 | /***** spin: spinlex.c *****/ |
| 2 | |
| 3 | /* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */ |
| 4 | /* All Rights Reserved. This software is for educational purposes only. */ |
| 5 | /* No guarantee whatsoever is expressed or implied by the distribution of */ |
| 6 | /* this code. Permission is given to distribute this code provided that */ |
| 7 | /* this introductory message is not removed and no monies are exchanged. */ |
| 8 | /* Software written by Gerard J. Holzmann. For tool documentation see: */ |
| 9 | /* http://spinroot.com/ */ |
| 10 | /* Send all bug-reports and/or questions to: bugs@spinroot.com */ |
| 11 | |
| 12 | #include <stdlib.h> |
| 13 | #include "spin.h" |
| 14 | #include "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 | 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 */ |
| 29 | } IType; |
| 30 | |
| 31 | typedef struct C_Added { |
| 32 | Symbol *s; |
| 33 | Symbol *t; |
| 34 | Symbol *ival; |
| 35 | struct C_Added *nxt; |
| 36 | } C_Added; |
| 37 | |
| 38 | extern RunList *X; |
| 39 | extern ProcList *rdy; |
| 40 | extern Symbol *Fname; |
| 41 | extern Symbol *context, *owner; |
| 42 | extern YYSTYPE yylval; |
| 43 | extern short has_last, has_code; |
| 44 | extern int verbose, IArgs, hastrack, separate; |
| 45 | |
| 46 | short has_stack = 0; |
| 47 | int lineno = 1; |
| 48 | char yytext[2048]; |
| 49 | FILE *yyin, *yyout; |
| 50 | |
| 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 *); |
| 58 | |
| 59 | #if 1 |
| 60 | #define Token(y) { if (in_comment) goto again; \ |
| 61 | yylval = nn(ZN,0,ZN,ZN); return y; } |
| 62 | |
| 63 | #define ValToken(x, y) { if (in_comment) goto again; \ |
| 64 | yylval = nn(ZN,0,ZN,ZN); yylval->val = x; return y; } |
| 65 | |
| 66 | #define SymToken(x, y) { if (in_comment) goto again; \ |
| 67 | yylval = nn(ZN,0,ZN,ZN); yylval->sym = x; return y; } |
| 68 | #else |
| 69 | #define Token(y) { yylval = nn(ZN,0,ZN,ZN); \ |
| 70 | if (!in_comment) return y; else goto again; } |
| 71 | |
| 72 | #define ValToken(x, y) { yylval = nn(ZN,0,ZN,ZN); yylval->val = x; \ |
| 73 | if (!in_comment) return y; else goto again; } |
| 74 | |
| 75 | #define SymToken(x, y) { yylval = nn(ZN,0,ZN,ZN); yylval->sym = x; \ |
| 76 | if (!in_comment) return y; else goto again; } |
| 77 | #endif |
| 78 | |
| 79 | static int getinline(void); |
| 80 | static void uninline(void); |
| 81 | |
| 82 | #if 1 |
| 83 | #define Getchar() ((Inlining<0)?getc(yyin):getinline()) |
| 84 | #define Ungetch(c) {if (Inlining<0) ungetc(c,yyin); else uninline(); } |
| 85 | |
| 86 | #else |
| 87 | |
| 88 | static int |
| 89 | Getchar(void) |
| 90 | { int c; |
| 91 | if (Inlining<0) |
| 92 | c = getc(yyin); |
| 93 | else |
| 94 | c = getinline(); |
| 95 | if (0) |
| 96 | { printf("<%c:%d>[%d] ", c, c, Inlining); |
| 97 | } |
| 98 | return c; |
| 99 | } |
| 100 | |
| 101 | static void |
| 102 | Ungetch(int c) |
| 103 | { |
| 104 | if (Inlining<0) |
| 105 | ungetc(c,yyin); |
| 106 | else |
| 107 | uninline(); |
| 108 | #if 1 |
| 109 | printf("<bs>"); |
| 110 | #endif |
| 111 | } |
| 112 | #endif |
| 113 | |
| 114 | static int |
| 115 | notquote(int c) |
| 116 | { return (c != '\"' && c != '\n'); |
| 117 | } |
| 118 | |
| 119 | int |
| 120 | isalnum_(int c) |
| 121 | { return (isalnum(c) || c == '_'); |
| 122 | } |
| 123 | |
| 124 | static int |
| 125 | isalpha_(int c) |
| 126 | { return isalpha(c); /* could be macro */ |
| 127 | } |
| 128 | |
| 129 | static int |
| 130 | isdigit_(int c) |
| 131 | { return isdigit(c); /* could be macro */ |
| 132 | } |
| 133 | |
| 134 | static void |
| 135 | getword(int first, int (*tst)(int)) |
| 136 | { int i=0, c; |
| 137 | |
| 138 | yytext[i++]= (char) first; |
| 139 | while (tst(c = Getchar())) |
| 140 | { yytext[i++] = (char) c; |
| 141 | if (c == '\\') |
| 142 | { c = Getchar(); |
| 143 | yytext[i++] = (char) c; /* no tst */ |
| 144 | } } |
| 145 | yytext[i] = '\0'; |
| 146 | Ungetch(c); |
| 147 | } |
| 148 | |
| 149 | static int |
| 150 | follow(int tok, int ifyes, int ifno) |
| 151 | { int c; |
| 152 | |
| 153 | if ((c = Getchar()) == tok) |
| 154 | return ifyes; |
| 155 | Ungetch(c); |
| 156 | |
| 157 | return ifno; |
| 158 | } |
| 159 | |
| 160 | static IType *seqnames; |
| 161 | |
| 162 | static void |
| 163 | def_inline(Symbol *s, int ln, char *ptr, char *prc, Lextok *nms) |
| 164 | { IType *tmp; |
| 165 | char *nw = (char *) emalloc(strlen(ptr)+1); |
| 166 | strcpy(nw, ptr); |
| 167 | |
| 168 | for (tmp = seqnames; tmp; tmp = tmp->nxt) |
| 169 | if (!strcmp(s->name, tmp->nm->name)) |
| 170 | { non_fatal("procedure name %s redefined", |
| 171 | tmp->nm->name); |
| 172 | tmp->cn = (Lextok *) nw; |
| 173 | tmp->params = nms; |
| 174 | tmp->dln = ln; |
| 175 | tmp->dfn = Fname; |
| 176 | return; |
| 177 | } |
| 178 | tmp = (IType *) emalloc(sizeof(IType)); |
| 179 | tmp->nm = s; |
| 180 | tmp->cn = (Lextok *) nw; |
| 181 | tmp->params = nms; |
| 182 | if (strlen(prc) > 0) |
| 183 | { tmp->prec = (char *) emalloc(strlen(prc)+1); |
| 184 | strcpy(tmp->prec, prc); |
| 185 | } |
| 186 | tmp->dln = ln; |
| 187 | tmp->dfn = Fname; |
| 188 | tmp->nxt = seqnames; |
| 189 | seqnames = tmp; |
| 190 | } |
| 191 | |
| 192 | void |
| 193 | gencodetable(FILE *fd) |
| 194 | { IType *tmp; |
| 195 | char *q; |
| 196 | int cnt; |
| 197 | |
| 198 | if (separate == 2) return; |
| 199 | |
| 200 | fprintf(fd, "struct {\n"); |
| 201 | fprintf(fd, " char *c; char *t;\n"); |
| 202 | fprintf(fd, "} code_lookup[] = {\n"); |
| 203 | |
| 204 | if (has_code) |
| 205 | for (tmp = seqnames; tmp; tmp = tmp->nxt) |
| 206 | if (tmp->nm->type == CODE_FRAG |
| 207 | || tmp->nm->type == CODE_DECL) |
| 208 | { fprintf(fd, "\t{ \"%s\", ", |
| 209 | tmp->nm->name); |
| 210 | q = (char *) tmp->cn; |
| 211 | |
| 212 | while (*q == '\n' || *q == '\r' || *q == '\\') |
| 213 | q++; |
| 214 | |
| 215 | fprintf(fd, "\""); |
| 216 | cnt = 0; |
| 217 | while (*q && cnt < 1024) /* pangen1.h allows 2048 */ |
| 218 | { switch (*q) { |
| 219 | case '"': |
| 220 | fprintf(fd, "\\\""); |
| 221 | break; |
| 222 | case '%': |
| 223 | fprintf(fd, "%%"); |
| 224 | break; |
| 225 | case '\n': |
| 226 | fprintf(fd, "\\n"); |
| 227 | break; |
| 228 | default: |
| 229 | putc(*q, fd); |
| 230 | break; |
| 231 | } |
| 232 | q++; cnt++; |
| 233 | } |
| 234 | if (*q) fprintf(fd, "..."); |
| 235 | fprintf(fd, "\""); |
| 236 | fprintf(fd, " },\n"); |
| 237 | } |
| 238 | |
| 239 | fprintf(fd, " { (char *) 0, \"\" }\n"); |
| 240 | fprintf(fd, "};\n"); |
| 241 | } |
| 242 | |
| 243 | static int |
| 244 | iseqname(char *t) |
| 245 | { IType *tmp; |
| 246 | |
| 247 | for (tmp = seqnames; tmp; tmp = tmp->nxt) |
| 248 | { if (!strcmp(t, tmp->nm->name)) |
| 249 | return 1; |
| 250 | } |
| 251 | return 0; |
| 252 | } |
| 253 | |
| 254 | static int |
| 255 | getinline(void) |
| 256 | { int c; |
| 257 | |
| 258 | if (ReDiRect) |
| 259 | { c = *ReDiRect++; |
| 260 | if (c == '\0') |
| 261 | { ReDiRect = (char *) 0; |
| 262 | c = *Inliner[Inlining]++; |
| 263 | } |
| 264 | } else |
| 265 | c = *Inliner[Inlining]++; |
| 266 | |
| 267 | if (c == '\0') |
| 268 | { lineno = Inline_stub[Inlining]->cln; |
| 269 | Fname = Inline_stub[Inlining]->cfn; |
| 270 | Inlining--; |
| 271 | #if 0 |
| 272 | if (verbose&32) |
| 273 | printf("spin: line %d, done inlining %s\n", |
| 274 | lineno, Inline_stub[Inlining+1]->nm->name); |
| 275 | #endif |
| 276 | return Getchar(); |
| 277 | } |
| 278 | return c; |
| 279 | } |
| 280 | |
| 281 | static void |
| 282 | uninline(void) |
| 283 | { |
| 284 | if (ReDiRect) |
| 285 | ReDiRect--; |
| 286 | else |
| 287 | Inliner[Inlining]--; |
| 288 | } |
| 289 | |
| 290 | IType * |
| 291 | find_inline(char *s) |
| 292 | { IType *tmp; |
| 293 | |
| 294 | for (tmp = seqnames; tmp; tmp = tmp->nxt) |
| 295 | if (!strcmp(s, tmp->nm->name)) |
| 296 | break; |
| 297 | if (!tmp) |
| 298 | fatal("cannot happen, missing inline def %s", s); |
| 299 | |
| 300 | return tmp; |
| 301 | } |
| 302 | |
| 303 | void |
| 304 | c_state(Symbol *s, Symbol *t, Symbol *ival) /* name, scope, ival */ |
| 305 | { C_Added *r; |
| 306 | |
| 307 | r = (C_Added *) emalloc(sizeof(C_Added)); |
| 308 | r->s = s; /* pointer to a data object */ |
| 309 | r->t = t; /* size of object, or "global", or "local proctype_name" */ |
| 310 | r->ival = ival; |
| 311 | r->nxt = c_added; |
| 312 | c_added = r; |
| 313 | } |
| 314 | |
| 315 | void |
| 316 | c_track(Symbol *s, Symbol *t, Symbol *stackonly) /* name, size */ |
| 317 | { C_Added *r; |
| 318 | |
| 319 | r = (C_Added *) emalloc(sizeof(C_Added)); |
| 320 | r->s = s; |
| 321 | r->t = t; |
| 322 | r->ival = stackonly; /* abuse of name */ |
| 323 | r->nxt = c_tracked; |
| 324 | c_tracked = r; |
| 325 | |
| 326 | if (stackonly != ZS) |
| 327 | { if (strcmp(stackonly->name, "\"Matched\"") == 0) |
| 328 | r->ival = ZS; /* the default */ |
| 329 | else if (strcmp(stackonly->name, "\"UnMatched\"") != 0 |
| 330 | && strcmp(stackonly->name, "\"unMatched\"") != 0 |
| 331 | && strcmp(stackonly->name, "\"StackOnly\"") != 0) |
| 332 | non_fatal("expecting '[Un]Matched', saw %s", stackonly->name); |
| 333 | else |
| 334 | has_stack = 1; /* unmatched stack */ |
| 335 | } |
| 336 | } |
| 337 | |
| 338 | char * |
| 339 | jump_etc(char *op) |
| 340 | { char *p = op; |
| 341 | |
| 342 | /* kludgy - try to get the type separated from the name */ |
| 343 | |
| 344 | while (*p == ' ' || *p == '\t') |
| 345 | p++; /* initial white space */ |
| 346 | while (*p != ' ' && *p != '\t') |
| 347 | p++; /* type name */ |
| 348 | while (*p == ' ' || *p == '\t') |
| 349 | p++; /* white space */ |
| 350 | while (*p == '*') |
| 351 | p++; /* decorations */ |
| 352 | while (*p == ' ' || *p == '\t') |
| 353 | p++; /* white space */ |
| 354 | |
| 355 | if (*p == '\0') |
| 356 | fatal("c_state format (%s)", op); |
| 357 | |
| 358 | if (strchr(p, '[') |
| 359 | && !strchr(p, '{')) |
| 360 | { non_fatal("array initialization error, c_state (%s)", p); |
| 361 | return (char *) 0; |
| 362 | } |
| 363 | |
| 364 | return p; |
| 365 | } |
| 366 | |
| 367 | void |
| 368 | c_add_globinit(FILE *fd) |
| 369 | { C_Added *r; |
| 370 | char *p, *q; |
| 371 | |
| 372 | fprintf(fd, "void\nglobinit(void)\n{\n"); |
| 373 | for (r = c_added; r; r = r->nxt) |
| 374 | { if (r->ival == ZS) |
| 375 | continue; |
| 376 | |
| 377 | if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0) |
| 378 | { for (q = r->ival->name; *q; q++) |
| 379 | { if (*q == '\"') |
| 380 | *q = ' '; |
| 381 | if (*q == '\\') |
| 382 | *q++ = ' '; /* skip over the next */ |
| 383 | } |
| 384 | p = jump_etc(r->s->name); /* e.g., "int **q" */ |
| 385 | if (p) |
| 386 | fprintf(fd, " now.%s = %s;\n", p, r->ival->name); |
| 387 | |
| 388 | } else |
| 389 | if (strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0) |
| 390 | { for (q = r->ival->name; *q; q++) |
| 391 | { if (*q == '\"') |
| 392 | *q = ' '; |
| 393 | if (*q == '\\') |
| 394 | *q++ = ' '; /* skip over the next */ |
| 395 | } |
| 396 | p = jump_etc(r->s->name); /* e.g., "int **q" */ |
| 397 | if (p) |
| 398 | fprintf(fd, " %s = %s;\n", p, r->ival->name); /* no now. prefix */ |
| 399 | |
| 400 | } } |
| 401 | fprintf(fd, "}\n"); |
| 402 | } |
| 403 | |
| 404 | void |
| 405 | c_add_locinit(FILE *fd, int tpnr, char *pnm) |
| 406 | { C_Added *r; |
| 407 | char *p, *q, *s; |
| 408 | int frst = 1; |
| 409 | |
| 410 | fprintf(fd, "void\nlocinit%d(int h)\n{\n", tpnr); |
| 411 | for (r = c_added; r; r = r->nxt) |
| 412 | if (r->ival != ZS |
| 413 | && strncmp(r->t->name, " Local", strlen(" Local")) == 0) |
| 414 | { for (q = r->ival->name; *q; q++) |
| 415 | if (*q == '\"') |
| 416 | *q = ' '; |
| 417 | |
| 418 | p = jump_etc(r->s->name); /* e.g., "int **q" */ |
| 419 | |
| 420 | q = r->t->name + strlen(" Local"); |
| 421 | while (*q == ' ' || *q == '\t') |
| 422 | q++; /* process name */ |
| 423 | |
| 424 | s = (char *) emalloc(strlen(q)+1); |
| 425 | strcpy(s, q); |
| 426 | |
| 427 | q = &s[strlen(s)-1]; |
| 428 | while (*q == ' ' || *q == '\t') |
| 429 | *q-- = '\0'; |
| 430 | |
| 431 | if (strcmp(pnm, s) != 0) |
| 432 | continue; |
| 433 | |
| 434 | if (frst) |
| 435 | { fprintf(fd, "\tuchar *this = pptr(h);\n"); |
| 436 | frst = 0; |
| 437 | } |
| 438 | |
| 439 | if (p) |
| 440 | fprintf(fd, " ((P%d *)this)->%s = %s;\n", |
| 441 | tpnr, p, r->ival->name); |
| 442 | |
| 443 | } |
| 444 | fprintf(fd, "}\n"); |
| 445 | } |
| 446 | |
| 447 | /* tracking: |
| 448 | 1. for non-global and non-local c_state decls: add up all the sizes in c_added |
| 449 | 2. add a global char array of that size into now |
| 450 | 3. generate a routine that memcpy's the required values into that array |
| 451 | 4. generate a call to that routine |
| 452 | */ |
| 453 | |
| 454 | void |
| 455 | c_preview(void) |
| 456 | { C_Added *r; |
| 457 | |
| 458 | hastrack = 0; |
| 459 | if (c_tracked) |
| 460 | hastrack = 1; |
| 461 | else |
| 462 | for (r = c_added; r; r = r->nxt) |
| 463 | if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0 |
| 464 | && strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0 |
| 465 | && strncmp(r->t->name, " Local", strlen(" Local")) != 0) |
| 466 | { hastrack = 1; /* c_state variant now obsolete */ |
| 467 | break; |
| 468 | } |
| 469 | } |
| 470 | |
| 471 | int |
| 472 | c_add_sv(FILE *fd) /* 1+2 -- called in pangen1.c */ |
| 473 | { C_Added *r; |
| 474 | int cnt = 0; |
| 475 | |
| 476 | if (!c_added && !c_tracked) return 0; |
| 477 | |
| 478 | for (r = c_added; r; r = r->nxt) /* pickup global decls */ |
| 479 | if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0) |
| 480 | fprintf(fd, " %s;\n", r->s->name); |
| 481 | |
| 482 | for (r = c_added; r; r = r->nxt) |
| 483 | if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0 |
| 484 | && strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0 |
| 485 | && strncmp(r->t->name, " Local", strlen(" Local")) != 0) |
| 486 | { cnt++; /* obsolete use */ |
| 487 | } |
| 488 | |
| 489 | for (r = c_tracked; r; r = r->nxt) |
| 490 | cnt++; /* preferred use */ |
| 491 | |
| 492 | if (cnt == 0) return 0; |
| 493 | |
| 494 | cnt = 0; |
| 495 | fprintf(fd, " uchar c_state["); |
| 496 | for (r = c_added; r; r = r->nxt) |
| 497 | if (strncmp(r->t->name, " Global ", strlen(" Global ")) != 0 |
| 498 | && strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) != 0 |
| 499 | && strncmp(r->t->name, " Local", strlen(" Local")) != 0) |
| 500 | { fprintf(fd, "%ssizeof(%s)", |
| 501 | (cnt==0)?"":"+", r->t->name); |
| 502 | cnt++; |
| 503 | } |
| 504 | |
| 505 | for (r = c_tracked; r; r = r->nxt) |
| 506 | { if (r->ival != ZS) continue; |
| 507 | |
| 508 | fprintf(fd, "%s%s", |
| 509 | (cnt==0)?"":"+", r->t->name); |
| 510 | cnt++; |
| 511 | } |
| 512 | |
| 513 | if (cnt == 0) fprintf(fd, "4"); /* now redundant */ |
| 514 | fprintf(fd, "];\n"); |
| 515 | return 1; |
| 516 | } |
| 517 | |
| 518 | void |
| 519 | c_stack_size(FILE *fd) |
| 520 | { C_Added *r; |
| 521 | int cnt = 0; |
| 522 | |
| 523 | for (r = c_tracked; r; r = r->nxt) |
| 524 | if (r->ival != ZS) |
| 525 | { fprintf(fd, "%s%s", |
| 526 | (cnt==0)?"":"+", r->t->name); |
| 527 | cnt++; |
| 528 | } |
| 529 | if (cnt == 0) |
| 530 | { fprintf(fd, "WS"); |
| 531 | } |
| 532 | } |
| 533 | |
| 534 | void |
| 535 | c_add_stack(FILE *fd) |
| 536 | { C_Added *r; |
| 537 | int cnt = 0; |
| 538 | |
| 539 | if ((!c_added && !c_tracked) || !has_stack) |
| 540 | { return; |
| 541 | } |
| 542 | |
| 543 | for (r = c_tracked; r; r = r->nxt) |
| 544 | if (r->ival != ZS) |
| 545 | { cnt++; |
| 546 | } |
| 547 | |
| 548 | if (cnt > 0) |
| 549 | { fprintf(fd, " uchar c_stack[StackSize];\n"); |
| 550 | } |
| 551 | } |
| 552 | |
| 553 | void |
| 554 | c_add_hidden(FILE *fd) |
| 555 | { C_Added *r; |
| 556 | |
| 557 | for (r = c_added; r; r = r->nxt) /* pickup hidden decls */ |
| 558 | if (strncmp(r->t->name, "\"Hidden\"", strlen("\"Hidden\"")) == 0) |
| 559 | { r->s->name[strlen(r->s->name)-1] = ' '; |
| 560 | fprintf(fd, "%s; /* Hidden */\n", &r->s->name[1]); |
| 561 | r->s->name[strlen(r->s->name)-1] = '"'; |
| 562 | } |
| 563 | /* called before c_add_def - quotes are still there */ |
| 564 | } |
| 565 | |
| 566 | void |
| 567 | c_add_loc(FILE *fd, char *s) /* state vector entries for proctype s */ |
| 568 | { C_Added *r; |
| 569 | static char buf[1024]; |
| 570 | char *p; |
| 571 | |
| 572 | if (!c_added) return; |
| 573 | |
| 574 | strcpy(buf, s); |
| 575 | strcat(buf, " "); |
| 576 | for (r = c_added; r; r = r->nxt) /* pickup local decls */ |
| 577 | if (strncmp(r->t->name, " Local", strlen(" Local")) == 0) |
| 578 | { p = r->t->name + strlen(" Local"); |
| 579 | while (*p == ' ' || *p == '\t') |
| 580 | p++; |
| 581 | if (strcmp(p, buf) == 0) |
| 582 | fprintf(fd, " %s;\n", r->s->name); |
| 583 | } |
| 584 | } |
| 585 | void |
| 586 | c_add_def(FILE *fd) /* 3 - called in plunk_c_fcts() */ |
| 587 | { C_Added *r; |
| 588 | |
| 589 | fprintf(fd, "#if defined(C_States) && defined(HAS_TRACK)\n"); |
| 590 | for (r = c_added; r; r = r->nxt) |
| 591 | { r->s->name[strlen(r->s->name)-1] = ' '; |
| 592 | r->s->name[0] = ' '; /* remove the "s */ |
| 593 | |
| 594 | r->t->name[strlen(r->t->name)-1] = ' '; |
| 595 | r->t->name[0] = ' '; |
| 596 | |
| 597 | if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0 |
| 598 | || strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0 |
| 599 | || strncmp(r->t->name, " Local", strlen(" Local")) == 0) |
| 600 | continue; |
| 601 | |
| 602 | if (strchr(r->s->name, '&')) |
| 603 | fatal("dereferencing state object: %s", r->s->name); |
| 604 | |
| 605 | fprintf(fd, "extern %s %s;\n", r->t->name, r->s->name); |
| 606 | } |
| 607 | for (r = c_tracked; r; r = r->nxt) |
| 608 | { r->s->name[strlen(r->s->name)-1] = ' '; |
| 609 | r->s->name[0] = ' '; /* remove " */ |
| 610 | |
| 611 | r->t->name[strlen(r->t->name)-1] = ' '; |
| 612 | r->t->name[0] = ' '; |
| 613 | } |
| 614 | |
| 615 | if (separate == 2) |
| 616 | { fprintf(fd, "#endif\n"); |
| 617 | return; |
| 618 | } |
| 619 | |
| 620 | if (has_stack) |
| 621 | { fprintf(fd, "int cpu_printf(const char *, ...);\n"); |
| 622 | fprintf(fd, "void\nc_stack(uchar *p_t_r)\n{\n"); |
| 623 | fprintf(fd, "#ifdef VERBOSE\n"); |
| 624 | fprintf(fd, " cpu_printf(\"c_stack %%u\\n\", p_t_r);\n"); |
| 625 | fprintf(fd, "#endif\n"); |
| 626 | for (r = c_tracked; r; r = r->nxt) |
| 627 | { if (r->ival == ZS) continue; |
| 628 | |
| 629 | fprintf(fd, "\tif(%s)\n", r->s->name); |
| 630 | fprintf(fd, "\t\tmemcpy(p_t_r, %s, %s);\n", |
| 631 | r->s->name, r->t->name); |
| 632 | fprintf(fd, "\telse\n"); |
| 633 | fprintf(fd, "\t\tmemset(p_t_r, 0, %s);\n", |
| 634 | r->t->name); |
| 635 | fprintf(fd, "\tp_t_r += %s;\n", r->t->name); |
| 636 | } |
| 637 | fprintf(fd, "}\n\n"); |
| 638 | } |
| 639 | |
| 640 | fprintf(fd, "void\nc_update(uchar *p_t_r)\n{\n"); |
| 641 | fprintf(fd, "#ifdef VERBOSE\n"); |
| 642 | fprintf(fd, " printf(\"c_update %%u\\n\", p_t_r);\n"); |
| 643 | fprintf(fd, "#endif\n"); |
| 644 | for (r = c_added; r; r = r->nxt) |
| 645 | { if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0 |
| 646 | || strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0 |
| 647 | || strncmp(r->t->name, " Local", strlen(" Local")) == 0) |
| 648 | continue; |
| 649 | |
| 650 | fprintf(fd, "\tmemcpy(p_t_r, &%s, sizeof(%s));\n", |
| 651 | r->s->name, r->t->name); |
| 652 | fprintf(fd, "\tp_t_r += sizeof(%s);\n", r->t->name); |
| 653 | } |
| 654 | |
| 655 | for (r = c_tracked; r; r = r->nxt) |
| 656 | { if (r->ival) continue; |
| 657 | |
| 658 | fprintf(fd, "\tif(%s)\n", r->s->name); |
| 659 | fprintf(fd, "\t\tmemcpy(p_t_r, %s, %s);\n", |
| 660 | r->s->name, r->t->name); |
| 661 | fprintf(fd, "\telse\n"); |
| 662 | fprintf(fd, "\t\tmemset(p_t_r, 0, %s);\n", |
| 663 | r->t->name); |
| 664 | fprintf(fd, "\tp_t_r += %s;\n", r->t->name); |
| 665 | } |
| 666 | |
| 667 | fprintf(fd, "}\n"); |
| 668 | |
| 669 | if (has_stack) |
| 670 | { fprintf(fd, "void\nc_unstack(uchar *p_t_r)\n{\n"); |
| 671 | fprintf(fd, "#ifdef VERBOSE\n"); |
| 672 | fprintf(fd, " cpu_printf(\"c_unstack %%u\\n\", p_t_r);\n"); |
| 673 | fprintf(fd, "#endif\n"); |
| 674 | for (r = c_tracked; r; r = r->nxt) |
| 675 | { if (r->ival == ZS) continue; |
| 676 | |
| 677 | fprintf(fd, "\tif(%s)\n", r->s->name); |
| 678 | fprintf(fd, "\t\tmemcpy(%s, p_t_r, %s);\n", |
| 679 | r->s->name, r->t->name); |
| 680 | fprintf(fd, "\tp_t_r += %s;\n", r->t->name); |
| 681 | } |
| 682 | fprintf(fd, "}\n"); |
| 683 | } |
| 684 | |
| 685 | fprintf(fd, "void\nc_revert(uchar *p_t_r)\n{\n"); |
| 686 | fprintf(fd, "#ifdef VERBOSE\n"); |
| 687 | fprintf(fd, " printf(\"c_revert %%u\\n\", p_t_r);\n"); |
| 688 | fprintf(fd, "#endif\n"); |
| 689 | for (r = c_added; r; r = r->nxt) |
| 690 | { if (strncmp(r->t->name, " Global ", strlen(" Global ")) == 0 |
| 691 | || strncmp(r->t->name, " Hidden ", strlen(" Hidden ")) == 0 |
| 692 | || strncmp(r->t->name, " Local", strlen(" Local")) == 0) |
| 693 | continue; |
| 694 | |
| 695 | fprintf(fd, "\tmemcpy(&%s, p_t_r, sizeof(%s));\n", |
| 696 | r->s->name, r->t->name); |
| 697 | fprintf(fd, "\tp_t_r += sizeof(%s);\n", r->t->name); |
| 698 | } |
| 699 | for (r = c_tracked; r; r = r->nxt) |
| 700 | { if (r->ival != ZS) continue; |
| 701 | |
| 702 | fprintf(fd, "\tif(%s)\n", r->s->name); |
| 703 | fprintf(fd, "\t\tmemcpy(%s, p_t_r, %s);\n", |
| 704 | r->s->name, r->t->name); |
| 705 | fprintf(fd, "\tp_t_r += %s;\n", r->t->name); |
| 706 | } |
| 707 | |
| 708 | fprintf(fd, "}\n"); |
| 709 | fprintf(fd, "#endif\n"); |
| 710 | } |
| 711 | |
| 712 | void |
| 713 | plunk_reverse(FILE *fd, IType *p, int matchthis) |
| 714 | { char *y, *z; |
| 715 | |
| 716 | if (!p) return; |
| 717 | plunk_reverse(fd, p->nxt, matchthis); |
| 718 | |
| 719 | if (!p->nm->context |
| 720 | && p->nm->type == matchthis) |
| 721 | { fprintf(fd, "\n/* start of %s */\n", p->nm->name); |
| 722 | z = (char *) p->cn; |
| 723 | while (*z == '\n' || *z == '\r' || *z == '\\') |
| 724 | z++; |
| 725 | /* e.g.: \#include "..." */ |
| 726 | |
| 727 | y = z; |
| 728 | while ((y = strstr(y, "\\#")) != NULL) |
| 729 | { *y = '\n'; y++; |
| 730 | } |
| 731 | |
| 732 | fprintf(fd, "%s\n", z); |
| 733 | fprintf(fd, "\n/* end of %s */\n", p->nm->name); |
| 734 | } |
| 735 | } |
| 736 | |
| 737 | void |
| 738 | plunk_c_decls(FILE *fd) |
| 739 | { |
| 740 | plunk_reverse(fd, seqnames, CODE_DECL); |
| 741 | } |
| 742 | |
| 743 | void |
| 744 | plunk_c_fcts(FILE *fd) |
| 745 | { |
| 746 | if (separate == 2 && hastrack) |
| 747 | { c_add_def(fd); |
| 748 | return; |
| 749 | } |
| 750 | |
| 751 | c_add_hidden(fd); |
| 752 | plunk_reverse(fd, seqnames, CODE_FRAG); |
| 753 | |
| 754 | if (c_added || c_tracked) /* enables calls to c_revert and c_update */ |
| 755 | fprintf(fd, "#define C_States 1\n"); |
| 756 | else |
| 757 | fprintf(fd, "#undef C_States\n"); |
| 758 | |
| 759 | if (hastrack) |
| 760 | c_add_def(fd); |
| 761 | |
| 762 | c_add_globinit(fd); |
| 763 | do_locinits(fd); |
| 764 | } |
| 765 | |
| 766 | static void |
| 767 | check_inline(IType *tmp) |
| 768 | { char buf[128]; |
| 769 | ProcList *p; |
| 770 | |
| 771 | if (!X) return; |
| 772 | |
| 773 | for (p = rdy; p; p = p->nxt) |
| 774 | { if (strcmp(p->n->name, X->n->name) == 0) |
| 775 | continue; |
| 776 | sprintf(buf, "P%s->", p->n->name); |
| 777 | if (strstr((char *)tmp->cn, buf)) |
| 778 | { printf("spin: in proctype %s, ref to object in proctype %s\n", |
| 779 | X->n->name, p->n->name); |
| 780 | fatal("invalid variable ref in '%s'", tmp->nm->name); |
| 781 | } } |
| 782 | } |
| 783 | |
| 784 | void |
| 785 | plunk_expr(FILE *fd, char *s) |
| 786 | { IType *tmp; |
| 787 | |
| 788 | tmp = find_inline(s); |
| 789 | check_inline(tmp); |
| 790 | |
| 791 | fprintf(fd, "%s", (char *) tmp->cn); |
| 792 | } |
| 793 | |
| 794 | void |
| 795 | preruse(FILE *fd, Lextok *n) /* check a condition for c_expr with preconditions */ |
| 796 | { IType *tmp; |
| 797 | |
| 798 | if (!n) return; |
| 799 | if (n->ntyp == C_EXPR) |
| 800 | { tmp = find_inline(n->sym->name); |
| 801 | if (tmp->prec) |
| 802 | { fprintf(fd, "if (!(%s)) { if (!readtrail) { depth++; ", tmp->prec); |
| 803 | fprintf(fd, "trpt++; trpt->pr = II; trpt->o_t = t;"); |
| 804 | fprintf(fd, "trpt->st = tt; Uerror(\"%s\"); } ", tmp->prec); |
| 805 | fprintf(fd, "else { printf(\"pan: precondition false: %s\\n\"); ", tmp->prec); |
| 806 | fprintf(fd, "_m = 3; goto P999; } } \n\t\t"); |
| 807 | } |
| 808 | } else |
| 809 | { preruse(fd, n->rgt); |
| 810 | preruse(fd, n->lft); |
| 811 | } |
| 812 | } |
| 813 | |
| 814 | int |
| 815 | glob_inline(char *s) |
| 816 | { IType *tmp; |
| 817 | char *bdy; |
| 818 | |
| 819 | tmp = find_inline(s); |
| 820 | bdy = (char *) tmp->cn; |
| 821 | return (strstr(bdy, "now.") /* global ref or */ |
| 822 | || strchr(bdy, '(') > bdy); /* possible C-function call */ |
| 823 | } |
| 824 | |
| 825 | void |
| 826 | plunk_inline(FILE *fd, char *s, int how) /* c_code with precondition */ |
| 827 | { IType *tmp; |
| 828 | |
| 829 | tmp = find_inline(s); |
| 830 | check_inline(tmp); |
| 831 | |
| 832 | fprintf(fd, "{ "); |
| 833 | if (how && tmp->prec) |
| 834 | { fprintf(fd, "if (!(%s)) { if (!readtrail) { depth++; ", tmp->prec); |
| 835 | fprintf(fd, "trpt++; trpt->pr = II; trpt->o_t = t;"); |
| 836 | fprintf(fd, "trpt->st = tt; Uerror(\"%s\"); } ", tmp->prec); |
| 837 | fprintf(fd, "else { printf(\"pan: precondition false: %s\\n\"); ", tmp->prec); |
| 838 | fprintf(fd, "_m = 3; goto P999; } } "); |
| 839 | } |
| 840 | fprintf(fd, "%s", (char *) tmp->cn); |
| 841 | fprintf(fd, " }\n"); |
| 842 | } |
| 843 | |
| 844 | void |
| 845 | no_side_effects(char *s) |
| 846 | { IType *tmp; |
| 847 | char *t; |
| 848 | |
| 849 | /* could still defeat this check via hidden |
| 850 | * side effects in function calls, |
| 851 | * but this will catch at least some cases |
| 852 | */ |
| 853 | |
| 854 | tmp = find_inline(s); |
| 855 | t = (char *) tmp->cn; |
| 856 | |
| 857 | if (strchr(t, ';') |
| 858 | || strstr(t, "++") |
| 859 | || strstr(t, "--")) |
| 860 | { |
| 861 | bad: lineno = tmp->dln; |
| 862 | Fname = tmp->dfn; |
| 863 | non_fatal("c_expr %s has side-effects", s); |
| 864 | return; |
| 865 | } |
| 866 | while ((t = strchr(t, '=')) != NULL) |
| 867 | { if (*(t-1) == '!' |
| 868 | || *(t-1) == '>' |
| 869 | || *(t-1) == '<') |
| 870 | { t++; |
| 871 | continue; |
| 872 | } |
| 873 | t++; |
| 874 | if (*t != '=') |
| 875 | goto bad; |
| 876 | t++; |
| 877 | } |
| 878 | } |
| 879 | |
| 880 | void |
| 881 | pickup_inline(Symbol *t, Lextok *apars) |
| 882 | { IType *tmp; Lextok *p, *q; int j; |
| 883 | |
| 884 | tmp = find_inline(t->name); |
| 885 | |
| 886 | if (++Inlining >= MAXINL) |
| 887 | fatal("inline fcts too deeply nested", 0); |
| 888 | tmp->cln = lineno; /* remember calling point */ |
| 889 | tmp->cfn = Fname; /* and filename */ |
| 890 | |
| 891 | for (p = apars, q = tmp->params, j = 0; p && q; p = p->rgt, q = q->rgt) |
| 892 | j++; /* count them */ |
| 893 | if (p || q) |
| 894 | fatal("wrong nr of params on call of '%s'", t->name); |
| 895 | |
| 896 | tmp->anms = (char **) emalloc(j * sizeof(char *)); |
| 897 | for (p = apars, j = 0; p; p = p->rgt, j++) |
| 898 | { tmp->anms[j] = (char *) emalloc(strlen(IArg_cont[j])+1); |
| 899 | strcpy(tmp->anms[j], IArg_cont[j]); |
| 900 | } |
| 901 | |
| 902 | lineno = tmp->dln; /* linenr of def */ |
| 903 | Fname = tmp->dfn; /* filename of same */ |
| 904 | Inliner[Inlining] = (char *)tmp->cn; |
| 905 | Inline_stub[Inlining] = tmp; |
| 906 | #if 0 |
| 907 | if (verbose&32) |
| 908 | printf("spin: line %d, file %s, inlining '%s' (from line %d, file %s)\n", |
| 909 | tmp->cln, tmp->cfn->name, t->name, tmp->dln, tmp->dfn->name); |
| 910 | #endif |
| 911 | for (j = 0; j < Inlining; j++) |
| 912 | if (Inline_stub[j] == Inline_stub[Inlining]) |
| 913 | fatal("cyclic inline attempt on: %s", t->name); |
| 914 | } |
| 915 | |
| 916 | static void |
| 917 | do_directive(int first) |
| 918 | { int c = first; /* handles lines starting with pound */ |
| 919 | |
| 920 | getword(c, isalpha_); |
| 921 | |
| 922 | if (strcmp(yytext, "#ident") == 0) |
| 923 | goto done; |
| 924 | |
| 925 | if ((c = Getchar()) != ' ') |
| 926 | fatal("malformed preprocessor directive - # .", 0); |
| 927 | |
| 928 | if (!isdigit_(c = Getchar())) |
| 929 | fatal("malformed preprocessor directive - # .lineno", 0); |
| 930 | |
| 931 | getword(c, isdigit_); |
| 932 | lineno = atoi(yytext); /* pickup the line number */ |
| 933 | |
| 934 | if ((c = Getchar()) == '\n') |
| 935 | return; /* no filename */ |
| 936 | |
| 937 | if (c != ' ') |
| 938 | fatal("malformed preprocessor directive - .fname", 0); |
| 939 | |
| 940 | if ((c = Getchar()) != '\"') |
| 941 | fatal("malformed preprocessor directive - .fname", 0); |
| 942 | |
| 943 | getword(c, notquote); |
| 944 | if (Getchar() != '\"') |
| 945 | fatal("malformed preprocessor directive - fname.", 0); |
| 946 | |
| 947 | strcat(yytext, "\""); |
| 948 | Fname = lookup(yytext); |
| 949 | done: |
| 950 | while (Getchar() != '\n') |
| 951 | ; |
| 952 | } |
| 953 | |
| 954 | void |
| 955 | precondition(char *q) |
| 956 | { int c, nest = 1; |
| 957 | |
| 958 | for (;;) |
| 959 | { c = Getchar(); |
| 960 | *q++ = c; |
| 961 | switch (c) { |
| 962 | case '\n': |
| 963 | lineno++; |
| 964 | break; |
| 965 | case '[': |
| 966 | nest++; |
| 967 | break; |
| 968 | case ']': |
| 969 | if (--nest <= 0) |
| 970 | { *--q = '\0'; |
| 971 | return; |
| 972 | } |
| 973 | break; |
| 974 | } |
| 975 | } |
| 976 | fatal("cannot happen", (char *) 0); /* unreachable */ |
| 977 | } |
| 978 | |
| 979 | |
| 980 | Symbol * |
| 981 | prep_inline(Symbol *s, Lextok *nms) |
| 982 | { int c, nest = 1, dln, firstchar, cnr; |
| 983 | char *p; |
| 984 | Lextok *t; |
| 985 | static char Buf1[SOMETHINGBIG], Buf2[RATHERSMALL]; |
| 986 | static int c_code = 1; |
| 987 | |
| 988 | for (t = nms; t; t = t->rgt) |
| 989 | if (t->lft) |
| 990 | { if (t->lft->ntyp != NAME) |
| 991 | fatal("bad param to inline %s", s?s->name:"--"); |
| 992 | t->lft->sym->hidden |= 32; |
| 993 | } |
| 994 | |
| 995 | if (!s) /* C_Code fragment */ |
| 996 | { s = (Symbol *) emalloc(sizeof(Symbol)); |
| 997 | s->name = (char *) emalloc(strlen("c_code")+26); |
| 998 | sprintf(s->name, "c_code%d", c_code++); |
| 999 | s->context = context; |
| 1000 | s->type = CODE_FRAG; |
| 1001 | } else |
| 1002 | s->type = PREDEF; |
| 1003 | |
| 1004 | p = &Buf1[0]; |
| 1005 | Buf2[0] = '\0'; |
| 1006 | for (;;) |
| 1007 | { c = Getchar(); |
| 1008 | switch (c) { |
| 1009 | case '[': |
| 1010 | if (s->type != CODE_FRAG) |
| 1011 | goto bad; |
| 1012 | precondition(&Buf2[0]); /* e.g., c_code [p] { r = p-r; } */ |
| 1013 | continue; |
| 1014 | case '{': |
| 1015 | break; |
| 1016 | case '\n': |
| 1017 | lineno++; |
| 1018 | /* fall through */ |
| 1019 | case ' ': case '\t': case '\f': case '\r': |
| 1020 | continue; |
| 1021 | default : |
| 1022 | printf("spin: saw char '%c'\n", c); |
| 1023 | bad: fatal("bad inline: %s", s->name); |
| 1024 | } |
| 1025 | break; |
| 1026 | } |
| 1027 | dln = lineno; |
| 1028 | if (s->type == CODE_FRAG) |
| 1029 | { if (verbose&32) |
| 1030 | sprintf(Buf1, "\t/* line %d %s */\n\t\t", |
| 1031 | lineno, Fname->name); |
| 1032 | else |
| 1033 | strcpy(Buf1, ""); |
| 1034 | } else |
| 1035 | sprintf(Buf1, "\n#line %d %s\n{", lineno, Fname->name); |
| 1036 | p += strlen(Buf1); |
| 1037 | firstchar = 1; |
| 1038 | |
| 1039 | cnr = 1; /* not zero */ |
| 1040 | more: |
| 1041 | *p++ = c = Getchar(); |
| 1042 | if (p - Buf1 >= SOMETHINGBIG) |
| 1043 | fatal("inline text too long", 0); |
| 1044 | switch (c) { |
| 1045 | case '\n': |
| 1046 | lineno++; |
| 1047 | cnr = 0; |
| 1048 | break; |
| 1049 | case '{': |
| 1050 | cnr++; |
| 1051 | nest++; |
| 1052 | break; |
| 1053 | case '}': |
| 1054 | cnr++; |
| 1055 | if (--nest <= 0) |
| 1056 | { *p = '\0'; |
| 1057 | if (s->type == CODE_FRAG) |
| 1058 | *--p = '\0'; /* remove trailing '}' */ |
| 1059 | def_inline(s, dln, &Buf1[0], &Buf2[0], nms); |
| 1060 | if (firstchar) |
| 1061 | printf("%3d: %s, warning: empty inline definition (%s)\n", |
| 1062 | dln, Fname->name, s->name); |
| 1063 | return s; /* normal return */ |
| 1064 | } |
| 1065 | break; |
| 1066 | case '#': |
| 1067 | if (cnr == 0) |
| 1068 | { p--; |
| 1069 | do_directive(c); /* reads to newline */ |
| 1070 | break; |
| 1071 | } /* else fall through */ |
| 1072 | default: |
| 1073 | firstchar = 0; |
| 1074 | case '\t': |
| 1075 | case ' ': |
| 1076 | case '\f': |
| 1077 | cnr++; |
| 1078 | break; |
| 1079 | } |
| 1080 | goto more; |
| 1081 | } |
| 1082 | |
| 1083 | static int |
| 1084 | lex(void) |
| 1085 | { int c; |
| 1086 | |
| 1087 | again: |
| 1088 | c = Getchar(); |
| 1089 | yytext[0] = (char) c; |
| 1090 | yytext[1] = '\0'; |
| 1091 | switch (c) { |
| 1092 | case '\n': /* newline */ |
| 1093 | lineno++; |
| 1094 | case '\r': /* carriage return */ |
| 1095 | goto again; |
| 1096 | |
| 1097 | case ' ': case '\t': case '\f': /* white space */ |
| 1098 | goto again; |
| 1099 | |
| 1100 | case '#': /* preprocessor directive */ |
| 1101 | if (in_comment) goto again; |
| 1102 | do_directive(c); |
| 1103 | goto again; |
| 1104 | |
| 1105 | case '\"': |
| 1106 | getword(c, notquote); |
| 1107 | if (Getchar() != '\"') |
| 1108 | fatal("string not terminated", yytext); |
| 1109 | strcat(yytext, "\""); |
| 1110 | SymToken(lookup(yytext), STRING) |
| 1111 | |
| 1112 | case '\'': /* new 3.0.9 */ |
| 1113 | c = Getchar(); |
| 1114 | if (c == '\\') |
| 1115 | { c = Getchar(); |
| 1116 | if (c == 'n') c = '\n'; |
| 1117 | else if (c == 'r') c = '\r'; |
| 1118 | else if (c == 't') c = '\t'; |
| 1119 | else if (c == 'f') c = '\f'; |
| 1120 | } |
| 1121 | if (Getchar() != '\'' && !in_comment) |
| 1122 | fatal("character quote missing: %s", yytext); |
| 1123 | ValToken(c, CONST) |
| 1124 | |
| 1125 | default: |
| 1126 | break; |
| 1127 | } |
| 1128 | |
| 1129 | if (isdigit_(c)) |
| 1130 | { getword(c, isdigit_); |
| 1131 | ValToken(atoi(yytext), CONST) |
| 1132 | } |
| 1133 | |
| 1134 | if (isalpha_(c) || c == '_') |
| 1135 | { getword(c, isalnum_); |
| 1136 | if (!in_comment) |
| 1137 | { c = check_name(yytext); |
| 1138 | if (c) return c; |
| 1139 | /* else fall through */ |
| 1140 | } |
| 1141 | goto again; |
| 1142 | } |
| 1143 | |
| 1144 | switch (c) { |
| 1145 | case '/': c = follow('*', 0, '/'); |
| 1146 | if (!c) { in_comment = 1; goto again; } |
| 1147 | break; |
| 1148 | case '*': c = follow('/', 0, '*'); |
| 1149 | if (!c) { in_comment = 0; goto again; } |
| 1150 | break; |
| 1151 | case ':': c = follow(':', SEP, ':'); break; |
| 1152 | case '-': c = follow('>', SEMI, follow('-', DECR, '-')); break; |
| 1153 | case '+': c = follow('+', INCR, '+'); break; |
| 1154 | case '<': c = follow('<', LSHIFT, follow('=', LE, LT)); break; |
| 1155 | case '>': c = follow('>', RSHIFT, follow('=', GE, GT)); break; |
| 1156 | case '=': c = follow('=', EQ, ASGN); break; |
| 1157 | case '!': c = follow('=', NE, follow('!', O_SND, SND)); break; |
| 1158 | case '?': c = follow('?', R_RCV, RCV); break; |
| 1159 | case '&': c = follow('&', AND, '&'); break; |
| 1160 | case '|': c = follow('|', OR, '|'); break; |
| 1161 | case ';': c = SEMI; break; |
| 1162 | default : break; |
| 1163 | } |
| 1164 | Token(c) |
| 1165 | } |
| 1166 | |
| 1167 | static struct { |
| 1168 | char *s; int tok; int val; char *sym; |
| 1169 | } Names[] = { |
| 1170 | {"active", ACTIVE, 0, 0}, |
| 1171 | {"assert", ASSERT, 0, 0}, |
| 1172 | {"atomic", ATOMIC, 0, 0}, |
| 1173 | {"bit", TYPE, BIT, 0}, |
| 1174 | {"bool", TYPE, BIT, 0}, |
| 1175 | {"break", BREAK, 0, 0}, |
| 1176 | {"byte", TYPE, BYTE, 0}, |
| 1177 | {"c_code", C_CODE, 0, 0}, |
| 1178 | {"c_decl", C_DECL, 0, 0}, |
| 1179 | {"c_expr", C_EXPR, 0, 0}, |
| 1180 | {"c_state", C_STATE, 0, 0}, |
| 1181 | {"c_track", C_TRACK, 0, 0}, |
| 1182 | {"D_proctype", D_PROCTYPE, 0, 0}, |
| 1183 | {"do", DO, 0, 0}, |
| 1184 | {"chan", TYPE, CHAN, 0}, |
| 1185 | {"else", ELSE, 0, 0}, |
| 1186 | {"empty", EMPTY, 0, 0}, |
| 1187 | {"enabled", ENABLED, 0, 0}, |
| 1188 | {"eval", EVAL, 0, 0}, |
| 1189 | {"false", CONST, 0, 0}, |
| 1190 | {"fi", FI, 0, 0}, |
| 1191 | {"full", FULL, 0, 0}, |
| 1192 | {"goto", GOTO, 0, 0}, |
| 1193 | {"hidden", HIDDEN, 0, ":hide:"}, |
| 1194 | {"if", IF, 0, 0}, |
| 1195 | {"init", INIT, 0, ":init:"}, |
| 1196 | {"int", TYPE, INT, 0}, |
| 1197 | {"len", LEN, 0, 0}, |
| 1198 | {"local", ISLOCAL, 0, ":local:"}, |
| 1199 | {"mtype", TYPE, MTYPE, 0}, |
| 1200 | {"nempty", NEMPTY, 0, 0}, |
| 1201 | {"never", CLAIM, 0, ":never:"}, |
| 1202 | {"nfull", NFULL, 0, 0}, |
| 1203 | {"notrace", TRACE, 0, ":notrace:"}, |
| 1204 | {"np_", NONPROGRESS, 0, 0}, |
| 1205 | {"od", OD, 0, 0}, |
| 1206 | {"of", OF, 0, 0}, |
| 1207 | {"pc_value", PC_VAL, 0, 0}, |
| 1208 | {"pid", TYPE, BYTE, 0}, |
| 1209 | {"printf", PRINT, 0, 0}, |
| 1210 | {"printm", PRINTM, 0, 0}, |
| 1211 | {"priority", PRIORITY, 0, 0}, |
| 1212 | {"proctype", PROCTYPE, 0, 0}, |
| 1213 | {"provided", PROVIDED, 0, 0}, |
| 1214 | {"run", RUN, 0, 0}, |
| 1215 | {"d_step", D_STEP, 0, 0}, |
| 1216 | {"inline", INLINE, 0, 0}, |
| 1217 | {"short", TYPE, SHORT, 0}, |
| 1218 | {"skip", CONST, 1, 0}, |
| 1219 | {"timeout", TIMEOUT, 0, 0}, |
| 1220 | {"trace", TRACE, 0, ":trace:"}, |
| 1221 | {"true", CONST, 1, 0}, |
| 1222 | {"show", SHOW, 0, ":show:"}, |
| 1223 | {"typedef", TYPEDEF, 0, 0}, |
| 1224 | {"unless", UNLESS, 0, 0}, |
| 1225 | {"unsigned", TYPE, UNSIGNED, 0}, |
| 1226 | {"xr", XU, XR, 0}, |
| 1227 | {"xs", XU, XS, 0}, |
| 1228 | {0, 0, 0, 0}, |
| 1229 | }; |
| 1230 | |
| 1231 | static int |
| 1232 | check_name(char *s) |
| 1233 | { int i; |
| 1234 | |
| 1235 | yylval = nn(ZN, 0, ZN, ZN); |
| 1236 | for (i = 0; Names[i].s; i++) |
| 1237 | if (strcmp(s, Names[i].s) == 0) |
| 1238 | { yylval->val = Names[i].val; |
| 1239 | if (Names[i].sym) |
| 1240 | yylval->sym = lookup(Names[i].sym); |
| 1241 | return Names[i].tok; |
| 1242 | } |
| 1243 | |
| 1244 | if ((yylval->val = ismtype(s)) != 0) |
| 1245 | { yylval->ismtyp = 1; |
| 1246 | return CONST; |
| 1247 | } |
| 1248 | |
| 1249 | if (strcmp(s, "_last") == 0) |
| 1250 | has_last++; |
| 1251 | |
| 1252 | if (Inlining >= 0 && !ReDiRect) |
| 1253 | { Lextok *tt, *t = Inline_stub[Inlining]->params; |
| 1254 | |
| 1255 | for (i = 0; t; t = t->rgt, i++) /* formal pars */ |
| 1256 | if (!strcmp(s, t->lft->sym->name) /* varname matches formal */ |
| 1257 | && strcmp(s, Inline_stub[Inlining]->anms[i]) != 0) /* actual pars */ |
| 1258 | { |
| 1259 | #if 0 |
| 1260 | if (verbose&32) |
| 1261 | printf("\tline %d, replace %s in call of '%s' with %s\n", |
| 1262 | lineno, s, |
| 1263 | Inline_stub[Inlining]->nm->name, |
| 1264 | Inline_stub[Inlining]->anms[i]); |
| 1265 | #endif |
| 1266 | for (tt = Inline_stub[Inlining]->params; tt; tt = tt->rgt) |
| 1267 | if (!strcmp(Inline_stub[Inlining]->anms[i], |
| 1268 | tt->lft->sym->name)) |
| 1269 | { /* would be cyclic if not caught */ |
| 1270 | printf("spin: line %d replacement value: %s\n", |
| 1271 | lineno, tt->lft->sym->name); |
| 1272 | wrong: fatal("formal par of %s contains replacement value", |
| 1273 | Inline_stub[Inlining]->nm->name); |
| 1274 | yylval->ntyp = tt->lft->ntyp; |
| 1275 | yylval->sym = lookup(tt->lft->sym->name); |
| 1276 | return NAME; |
| 1277 | } |
| 1278 | |
| 1279 | /* check for occurrence of param as field of struct */ |
| 1280 | { char *ptr = Inline_stub[Inlining]->anms[i]; |
| 1281 | while ((ptr = strstr(ptr, s)) != NULL) |
| 1282 | { if (*(ptr-1) == '.' |
| 1283 | || *(ptr+strlen(s)) == '.') |
| 1284 | { goto wrong; |
| 1285 | } |
| 1286 | ptr++; |
| 1287 | } } |
| 1288 | ReDiRect = Inline_stub[Inlining]->anms[i]; |
| 1289 | return 0; |
| 1290 | } } |
| 1291 | |
| 1292 | yylval->sym = lookup(s); /* symbol table */ |
| 1293 | if (isutype(s)) |
| 1294 | return UNAME; |
| 1295 | if (isproctype(s)) |
| 1296 | return PNAME; |
| 1297 | if (iseqname(s)) |
| 1298 | return INAME; |
| 1299 | |
| 1300 | return NAME; |
| 1301 | } |
| 1302 | |
| 1303 | int |
| 1304 | yylex(void) |
| 1305 | { static int last = 0; |
| 1306 | static int hold = 0; |
| 1307 | int c; |
| 1308 | /* |
| 1309 | * repair two common syntax mistakes with |
| 1310 | * semi-colons before or after a '}' |
| 1311 | */ |
| 1312 | if (hold) |
| 1313 | { c = hold; |
| 1314 | hold = 0; |
| 1315 | } else |
| 1316 | { c = lex(); |
| 1317 | if (last == ELSE |
| 1318 | && c != SEMI |
| 1319 | && c != FI) |
| 1320 | { hold = c; |
| 1321 | last = 0; |
| 1322 | return SEMI; |
| 1323 | } |
| 1324 | if (last == '}' |
| 1325 | && c != PROCTYPE |
| 1326 | && c != INIT |
| 1327 | && c != CLAIM |
| 1328 | && c != SEP |
| 1329 | && c != FI |
| 1330 | && c != OD |
| 1331 | && c != '}' |
| 1332 | && c != UNLESS |
| 1333 | && c != SEMI |
| 1334 | && c != EOF) |
| 1335 | { hold = c; |
| 1336 | last = 0; |
| 1337 | return SEMI; /* insert ';' */ |
| 1338 | } |
| 1339 | if (c == SEMI) |
| 1340 | { /* if context, we're not in a typedef |
| 1341 | * because they're global. |
| 1342 | * if owner, we're at the end of a ref |
| 1343 | * to a struct field -- prevent that the |
| 1344 | * lookahead is interpreted as a field of |
| 1345 | * the same struct... |
| 1346 | */ |
| 1347 | if (context) owner = ZS; |
| 1348 | hold = lex(); /* look ahead */ |
| 1349 | if (hold == '}' |
| 1350 | || hold == SEMI) |
| 1351 | { c = hold; /* omit ';' */ |
| 1352 | hold = 0; |
| 1353 | } |
| 1354 | } |
| 1355 | } |
| 1356 | last = c; |
| 1357 | |
| 1358 | if (IArgs) |
| 1359 | { static int IArg_nst = 0; |
| 1360 | |
| 1361 | if (strcmp(yytext, ",") == 0) |
| 1362 | { IArg_cont[++IArgno][0] = '\0'; |
| 1363 | } else if (strcmp(yytext, "(") == 0) |
| 1364 | { if (IArg_nst++ == 0) |
| 1365 | { IArgno = 0; |
| 1366 | IArg_cont[0][0] = '\0'; |
| 1367 | } else |
| 1368 | strcat(IArg_cont[IArgno], yytext); |
| 1369 | } else if (strcmp(yytext, ")") == 0) |
| 1370 | { if (--IArg_nst > 0) |
| 1371 | strcat(IArg_cont[IArgno], yytext); |
| 1372 | } else if (c == CONST && yytext[0] == '\'') |
| 1373 | { sprintf(yytext, "'%c'", yylval->val); |
| 1374 | strcat(IArg_cont[IArgno], yytext); |
| 1375 | } else if (c == CONST) |
| 1376 | { sprintf(yytext, "%d", yylval->val); |
| 1377 | strcat(IArg_cont[IArgno], yytext); |
| 1378 | } else |
| 1379 | { |
| 1380 | switch (c) { |
| 1381 | case SEP: strcpy(yytext, "::"); break; |
| 1382 | case SEMI: strcpy(yytext, ";"); break; |
| 1383 | case DECR: strcpy(yytext, "--"); break; |
| 1384 | case INCR: strcpy(yytext, "++"); break; |
| 1385 | case LSHIFT: strcpy(yytext, "<<"); break; |
| 1386 | case RSHIFT: strcpy(yytext, ">>"); break; |
| 1387 | case LE: strcpy(yytext, "<="); break; |
| 1388 | case LT: strcpy(yytext, "<"); break; |
| 1389 | case GE: strcpy(yytext, ">="); break; |
| 1390 | case GT: strcpy(yytext, ">"); break; |
| 1391 | case EQ: strcpy(yytext, "=="); break; |
| 1392 | case ASGN: strcpy(yytext, "="); break; |
| 1393 | case NE: strcpy(yytext, "!="); break; |
| 1394 | case R_RCV: strcpy(yytext, "??"); break; |
| 1395 | case RCV: strcpy(yytext, "?"); break; |
| 1396 | case O_SND: strcpy(yytext, "!!"); break; |
| 1397 | case SND: strcpy(yytext, "!"); break; |
| 1398 | case AND: strcpy(yytext, "&&"); break; |
| 1399 | case OR: strcpy(yytext, "||"); break; |
| 1400 | } |
| 1401 | strcat(IArg_cont[IArgno], yytext); |
| 1402 | } |
| 1403 | } |
| 1404 | return c; |
| 1405 | } |