spinlex.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. /***** spin: spinlex.c *****/
  2. /* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories */
  3. /* All Rights Reserved. This software is for educational purposes only. */
  4. /* Permission is given to distribute this code provided that this intro- */
  5. /* ductory message is not removed and no monies are exchanged. */
  6. /* No guarantee is expressed or implied by the distribution of this code. */
  7. /* Software written by Gerard J. Holzmann as part of the book: */
  8. /* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4, */
  9. /* Prentice Hall, Englewood Cliffs, NJ, 07632. */
  10. /* Send bug-reports and/or questions to: gerard@research.bell-labs.com */
  11. #include <stdlib.h>
  12. #include "spin.h"
  13. #ifdef PC
  14. #include "y_tab.h"
  15. #else
  16. #include "y.tab.h"
  17. #endif
  18. #define MAXINL 16 /* max recursion depth inline fcts */
  19. #define MAXPAR 32 /* max params to an inline call */
  20. #define MAXLEN 512 /* max len of an actual parameter text */
  21. typedef struct IType {
  22. Symbol *nm; /* name of the type */
  23. Lextok *cn; /* contents */
  24. Lextok *params; /* formal pars if any */
  25. char **anms; /* literal text for actual pars */
  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. extern Symbol *Fname;
  31. extern YYSTYPE yylval;
  32. extern short has_last, terse;
  33. extern int verbose, IArgs;
  34. int lineno = 1, IArgno = 0;
  35. int Inlining = -1;
  36. char *Inliner[MAXINL], IArg_cont[MAXPAR][MAXLEN];
  37. IType *Inline_stub[MAXINL];
  38. char yytext[2048];
  39. FILE *yyin, *yyout;
  40. static unsigned char in_comment=0;
  41. static char *ReDiRect;
  42. static int check_name(char *);
  43. #if 1
  44. #define Token(y) { if (in_comment) goto again; \
  45. yylval = nn(ZN,0,ZN,ZN); return y; }
  46. #define ValToken(x, y) { if (in_comment) goto again; \
  47. yylval = nn(ZN,0,ZN,ZN); yylval->val = x; return y; }
  48. #define SymToken(x, y) { if (in_comment) goto again; \
  49. yylval = nn(ZN,0,ZN,ZN); yylval->sym = x; return y; }
  50. #else
  51. #define Token(y) { yylval = nn(ZN,0,ZN,ZN); \
  52. if (!in_comment) return y; else goto again; }
  53. #define ValToken(x, y) { yylval = nn(ZN,0,ZN,ZN); yylval->val = x; \
  54. if (!in_comment) return y; else goto again; }
  55. #define SymToken(x, y) { yylval = nn(ZN,0,ZN,ZN); yylval->sym = x; \
  56. if (!in_comment) return y; else goto again; }
  57. #endif
  58. #define Getchar() ((Inlining<0)?getc(yyin):getinline())
  59. #define Ungetch(c) {if (Inlining<0) ungetc(c,yyin); else uninline(); }
  60. static int getinline(void);
  61. static void uninline(void);
  62. static int
  63. notquote(int c)
  64. { return (c != '\"' && c != '\n');
  65. }
  66. int
  67. isalnum_(int c)
  68. { return (isalnum(c) || c == '_');
  69. }
  70. static int
  71. isalpha_(int c)
  72. { return isalpha(c); /* could be macro */
  73. }
  74. static int
  75. isdigit_(int c)
  76. { return isdigit(c); /* could be macro */
  77. }
  78. static void
  79. getword(int first, int (*tst)(int))
  80. { int i=0; char c;
  81. yytext[i++]= (char) first;
  82. while (tst(c = Getchar()))
  83. yytext[i++] = c;
  84. yytext[i] = '\0';
  85. Ungetch(c);
  86. }
  87. static int
  88. follow(int tok, int ifyes, int ifno)
  89. { int c;
  90. if ((c = Getchar()) == tok)
  91. return ifyes;
  92. Ungetch(c);
  93. return ifno;
  94. }
  95. static IType *seqnames;
  96. static void
  97. def_inline(Symbol *s, int ln, char *ptr, Lextok *nms)
  98. { IType *tmp;
  99. char *nw = (char *) emalloc(strlen(ptr)+1);
  100. strcpy(nw, ptr);
  101. for (tmp = seqnames; tmp; tmp = tmp->nxt)
  102. if (!strcmp(s->name, tmp->nm->name))
  103. { non_fatal("procedure name %s redefined",
  104. tmp->nm->name);
  105. tmp->cn = (Lextok *) nw;
  106. tmp->params = nms;
  107. tmp->dln = ln;
  108. tmp->dfn = Fname;
  109. return;
  110. }
  111. tmp = (IType *) emalloc(sizeof(IType));
  112. tmp->nm = s;
  113. tmp->cn = (Lextok *) nw;
  114. tmp->params = nms;
  115. tmp->dln = ln;
  116. tmp->dfn = Fname;
  117. tmp->nxt = seqnames;
  118. seqnames = tmp;
  119. }
  120. static int
  121. iseqname(char *t)
  122. { IType *tmp;
  123. for (tmp = seqnames; tmp; tmp = tmp->nxt)
  124. { if (!strcmp(t, tmp->nm->name))
  125. return 1;
  126. }
  127. return 0;
  128. }
  129. static int
  130. getinline(void)
  131. { int c;
  132. if (ReDiRect)
  133. { c = *ReDiRect++;
  134. if (c == '\0')
  135. { ReDiRect = (char *) 0;
  136. c = *Inliner[Inlining]++;
  137. }
  138. } else
  139. c = *Inliner[Inlining]++;
  140. if (c == '\0')
  141. { lineno = Inline_stub[Inlining]->cln;
  142. Fname = Inline_stub[Inlining]->cfn;
  143. Inlining--;
  144. #if 0
  145. if (verbose&32)
  146. printf("spin: line %d, done inlining %s\n",
  147. lineno, Inline_stub[Inlining+1]->nm->name);
  148. #endif
  149. return Getchar();
  150. }
  151. return c;
  152. }
  153. static void
  154. uninline(void)
  155. {
  156. if (ReDiRect)
  157. ReDiRect--;
  158. else
  159. Inliner[Inlining]--;
  160. }
  161. void
  162. pickup_inline(Symbol *t, Lextok *apars)
  163. { IType *tmp; Lextok *p, *q; int j;
  164. for (tmp = seqnames; tmp; tmp = tmp->nxt)
  165. if (!strcmp(t->name, tmp->nm->name))
  166. break;
  167. if (!tmp)
  168. fatal("cannot happen, ns %s", t->name);
  169. if (++Inlining >= MAXINL)
  170. fatal("inline fcts too deeply nested", 0);
  171. tmp->cln = lineno; /* remember calling point */
  172. tmp->cfn = Fname; /* and filename */
  173. for (p = apars, q = tmp->params, j = 0; p && q; p = p->rgt, q = q->rgt)
  174. j++; /* count them */
  175. if (p || q)
  176. fatal("wrong nr of params on call of '%s'", t->name);
  177. tmp->anms = (char **) emalloc(j * sizeof(char *));
  178. for (p = apars, j = 0; p; p = p->rgt, j++)
  179. { tmp->anms[j] = (char *) emalloc(strlen(IArg_cont[j])+1);
  180. strcpy(tmp->anms[j], IArg_cont[j]);
  181. }
  182. lineno = tmp->dln; /* linenr of def */
  183. Fname = tmp->dfn; /* filename of same */
  184. Inliner[Inlining] = (char *)tmp->cn;
  185. Inline_stub[Inlining] = tmp;
  186. #if 0
  187. if (verbose&32)
  188. printf("spin: line %d, file %s, inlining '%s' (from line %d, file %s)\n",
  189. tmp->cln, tmp->cfn->name, t->name, tmp->dln, tmp->dfn->name);
  190. #endif
  191. for (j = 0; j < Inlining; j++)
  192. if (Inline_stub[j] == Inline_stub[Inlining])
  193. fatal("cyclic inline attempt on: %s", t->name);
  194. }
  195. static void
  196. do_directive(int first, int fromwhere)
  197. { int c = first; /* handles lines starting with pound */
  198. getword(c, isalpha_);
  199. if ((c = Getchar()) != ' ')
  200. fatal("malformed preprocessor directive - # .", 0);
  201. if (!isdigit_(c = Getchar()))
  202. fatal("malformed preprocessor directive - # .lineno", 0);
  203. getword(c, isdigit_);
  204. lineno = atoi(yytext); /* pickup the line number */
  205. if ((c = Getchar()) == '\n')
  206. return; /* no filename */
  207. if (c != ' ')
  208. fatal("malformed preprocessor directive - .fname", 0);
  209. if ((c = Getchar()) != '\"')
  210. fatal("malformed preprocessor directive - .fname", 0);
  211. getword(c, notquote);
  212. if (Getchar() != '\"')
  213. fatal("malformed preprocessor directive - fname.", 0);
  214. strcat(yytext, "\"");
  215. Fname = lookup(yytext);
  216. while (Getchar() != '\n')
  217. ;
  218. }
  219. #define SOMETHINGBIG 65536
  220. void
  221. prep_inline(Symbol *s, Lextok *nms)
  222. { int c, nest = 1, dln, firstchar, cnr;
  223. char *p, buf[SOMETHINGBIG];
  224. Lextok *t;
  225. for (t = nms; t; t = t->rgt)
  226. if (t->lft)
  227. { if (t->lft->ntyp != NAME)
  228. fatal("bad param to inline %s", s->name);
  229. t->lft->sym->hidden |= 32;
  230. }
  231. s->type = PREDEF;
  232. p = &buf[0];
  233. for (;;)
  234. { c = Getchar();
  235. switch (c) {
  236. case '{':
  237. break;
  238. case '\n':
  239. lineno++;
  240. /* fall through */
  241. case ' ': case '\t': case '\f': case '\r':
  242. continue;
  243. default : fatal("bad inline: %s", s->name);
  244. }
  245. break;
  246. }
  247. dln = lineno;
  248. sprintf(buf, "\n#line %d %s\n{", lineno, Fname->name);
  249. p += strlen(buf);
  250. firstchar = 1;
  251. cnr = 1; /* not zero */
  252. more:
  253. *p++ = c = Getchar();
  254. if (p - buf >= SOMETHINGBIG)
  255. fatal("inline text too long", 0);
  256. switch (c) {
  257. case '\n':
  258. lineno++;
  259. cnr = 0;
  260. break;
  261. case '{':
  262. cnr++;
  263. nest++;
  264. break;
  265. case '}':
  266. cnr++;
  267. if (--nest <= 0)
  268. { *p = '\0';
  269. def_inline(s, dln, &buf[0], nms);
  270. if (firstchar)
  271. fatal("empty inline definition '%s'", s->name);
  272. return;
  273. }
  274. break;
  275. case '#':
  276. if (cnr == 0)
  277. { p--;
  278. do_directive(c, 4); /* reads to newline */
  279. break;
  280. } /* else fall through */
  281. default:
  282. firstchar = 0;
  283. case '\t':
  284. case ' ':
  285. case '\f':
  286. cnr++;
  287. break;
  288. }
  289. goto more;
  290. }
  291. static int
  292. lex(void)
  293. { int c;
  294. again:
  295. c = Getchar();
  296. yytext[0] = (char) c;
  297. yytext[1] = '\0';
  298. switch (c) {
  299. case '\n': /* newline */
  300. lineno++;
  301. case '\r': /* carriage return */
  302. goto again;
  303. case ' ': case '\t': case '\f': /* white space */
  304. goto again;
  305. case '#': /* preprocessor directive */
  306. if (in_comment) goto again;
  307. do_directive(c, 5);
  308. goto again;
  309. case '\"':
  310. getword(c, notquote);
  311. if (Getchar() != '\"')
  312. fatal("string not terminated", yytext);
  313. strcat(yytext, "\"");
  314. SymToken(lookup(yytext), STRING)
  315. case '\'': /* new 3.0.9 */
  316. c = Getchar();
  317. if (c == '\\')
  318. { c = Getchar();
  319. if (c == 'n') c = '\n';
  320. else if (c == 'r') c = '\r';
  321. else if (c == 't') c = '\t';
  322. else if (c == 'f') c = '\f';
  323. }
  324. if (Getchar() != '\'')
  325. fatal("character quote missing", yytext);
  326. ValToken(c, CONST)
  327. default:
  328. break;
  329. }
  330. if (isdigit_(c))
  331. { getword(c, isdigit_);
  332. ValToken(atoi(yytext), CONST)
  333. }
  334. if (isalpha_(c) || c == '_')
  335. { getword(c, isalnum_);
  336. if (!in_comment)
  337. { c = check_name(yytext);
  338. if (c) return c;
  339. /* else fall through */
  340. }
  341. goto again;
  342. }
  343. switch (c) {
  344. case '/': c = follow('*', 0, '/');
  345. if (!c) { in_comment = 1; goto again; }
  346. break;
  347. case '*': c = follow('/', 0, '*');
  348. if (!c) { in_comment = 0; goto again; }
  349. break;
  350. case ':': c = follow(':', SEP, ':'); break;
  351. case '-': c = follow('>', SEMI, follow('-', DECR, '-')); break;
  352. case '+': c = follow('+', INCR, '+'); break;
  353. case '<': c = follow('<', LSHIFT, follow('=', LE, LT)); break;
  354. case '>': c = follow('>', RSHIFT, follow('=', GE, GT)); break;
  355. case '=': c = follow('=', EQ, ASGN); break;
  356. case '!': c = follow('=', NE, follow('!', O_SND, SND)); break;
  357. case '?': c = follow('?', R_RCV, RCV); break;
  358. case '&': c = follow('&', AND, '&'); break;
  359. case '|': c = follow('|', OR, '|'); break;
  360. case ';': c = SEMI; break;
  361. default : break;
  362. }
  363. Token(c)
  364. }
  365. static struct {
  366. char *s; int tok; int val; char *sym;
  367. } Names[] = {
  368. {"active", ACTIVE, 0, 0},
  369. {"assert", ASSERT, 0, 0},
  370. {"atomic", ATOMIC, 0, 0},
  371. {"bit", TYPE, BIT, 0},
  372. {"bool", TYPE, BIT, 0},
  373. {"break", BREAK, 0, 0},
  374. {"byte", TYPE, BYTE, 0},
  375. {"D_proctype", D_PROCTYPE, 0, 0},
  376. {"do", DO, 0, 0},
  377. {"chan", TYPE, CHAN, 0},
  378. {"else", ELSE, 0, 0},
  379. {"empty", EMPTY, 0, 0},
  380. {"enabled", ENABLED, 0, 0},
  381. {"eval", EVAL, 0, 0},
  382. {"false", CONST, 0, 0},
  383. {"fi", FI, 0, 0},
  384. {"full", FULL, 0, 0},
  385. {"goto", GOTO, 0, 0},
  386. {"hidden", HIDDEN, 0, ":hide:"},
  387. {"if", IF, 0, 0},
  388. {"init", INIT, 0, ":init:"},
  389. {"int", TYPE, INT, 0},
  390. {"local", ISLOCAL, 0, ":local:"},
  391. {"len", LEN, 0, 0},
  392. {"mtype", TYPE, MTYPE, 0},
  393. {"nempty", NEMPTY, 0, 0},
  394. {"never", CLAIM, 0, ":never:"},
  395. {"nfull", NFULL, 0, 0},
  396. {"notrace", TRACE, 0, ":notrace:"},
  397. {"np_", NONPROGRESS, 0, 0},
  398. {"od", OD, 0, 0},
  399. {"of", OF, 0, 0},
  400. {"pc_value", PC_VAL, 0, 0},
  401. {"printf", PRINT, 0, 0},
  402. {"priority", PRIORITY, 0, 0},
  403. {"proctype", PROCTYPE, 0, 0},
  404. {"provided", PROVIDED, 0, 0},
  405. {"run", RUN, 0, 0},
  406. {"d_step", D_STEP, 0, 0},
  407. {"inline", INLINE, 0, 0},
  408. {"short", TYPE, SHORT, 0},
  409. {"skip", CONST, 1, 0},
  410. {"timeout", TIMEOUT, 0, 0},
  411. {"trace", TRACE, 0, ":trace:"},
  412. {"true", CONST, 1, 0},
  413. {"show", SHOW, 0, ":show:"},
  414. {"typedef", TYPEDEF, 0, 0},
  415. {"unless", UNLESS, 0, 0},
  416. {"unsigned", TYPE, UNSIGNED, 0},
  417. {"xr", XU, XR, 0},
  418. {"xs", XU, XS, 0},
  419. {0, 0, 0, 0},
  420. };
  421. static int
  422. check_name(char *s)
  423. { register int i;
  424. yylval = nn(ZN, 0, ZN, ZN);
  425. for (i = 0; Names[i].s; i++)
  426. if (strcmp(s, Names[i].s) == 0)
  427. { yylval->val = Names[i].val;
  428. if (Names[i].sym)
  429. yylval->sym = lookup(Names[i].sym);
  430. return Names[i].tok;
  431. }
  432. if (yylval->val = ismtype(s))
  433. { yylval->ismtyp = 1;
  434. return CONST;
  435. }
  436. if (strcmp(s, "_last") == 0)
  437. has_last++;
  438. if (Inlining >= 0 && !ReDiRect)
  439. { Lextok *tt, *t = Inline_stub[Inlining]->params;
  440. for (i = 0; t; t = t->rgt, i++)
  441. if (!strcmp(s, t->lft->sym->name)
  442. && strcmp(s, Inline_stub[Inlining]->anms[i]) != 0)
  443. {
  444. #if 0
  445. if (verbose&32)
  446. printf("\tline %d, replace %s in call of '%s' with %s\n",
  447. lineno, s,
  448. Inline_stub[Inlining]->nm->name,
  449. Inline_stub[Inlining]->anms[i]);
  450. #endif
  451. tt = Inline_stub[Inlining]->params;
  452. for ( ; tt; tt = tt->rgt)
  453. if (!strcmp(Inline_stub[Inlining]->anms[i],
  454. tt->lft->sym->name))
  455. { /* would be cyclic if not caught */
  456. yylval->ntyp = tt->lft->ntyp;
  457. yylval->sym = lookup(tt->lft->sym->name);
  458. return NAME;
  459. }
  460. ReDiRect = Inline_stub[Inlining]->anms[i];
  461. return 0;
  462. } }
  463. yylval->sym = lookup(s); /* symbol table */
  464. if (isutype(s))
  465. return UNAME;
  466. if (isproctype(s))
  467. return PNAME;
  468. if (iseqname(s))
  469. return INAME;
  470. return NAME;
  471. }
  472. int
  473. yylex(void)
  474. { static int last = 0;
  475. static int hold = 0;
  476. int c;
  477. /*
  478. * repair two common syntax mistakes with
  479. * semi-colons before or after a '}'
  480. */
  481. if (hold)
  482. { c = hold;
  483. hold = 0;
  484. } else
  485. { c = lex();
  486. if (last == ELSE
  487. && c != SEMI
  488. && c != FI)
  489. { hold = c;
  490. last = 0;
  491. return SEMI;
  492. }
  493. if (last == '}'
  494. && c != PROCTYPE
  495. && c != INIT
  496. && c != CLAIM
  497. && c != SEP
  498. && c != FI
  499. && c != OD
  500. && c != '}'
  501. && c != UNLESS
  502. && c != SEMI
  503. && c != EOF)
  504. { hold = c;
  505. last = 0;
  506. return SEMI; /* insert ';' */
  507. }
  508. if (c == SEMI)
  509. { extern Symbol *context, *owner;
  510. /* if context, we're not in a typedef
  511. * because they're global.
  512. * if owner, we're at the end of a ref
  513. * to a struct field -- prevent that the
  514. * lookahead is interpreted as a field of
  515. * the same struct...
  516. */
  517. if (context) owner = ZS;
  518. hold = lex(); /* look ahead */
  519. if (hold == '}'
  520. || hold == SEMI)
  521. { c = hold; /* omit ';' */
  522. hold = 0;
  523. }
  524. }
  525. }
  526. last = c;
  527. if (IArgs)
  528. { static int IArg_nst = 0;
  529. if (strcmp(yytext, ",") == 0)
  530. { IArg_cont[++IArgno][0] = '\0';
  531. } else if (strcmp(yytext, "(") == 0)
  532. { if (IArg_nst++ == 0)
  533. { IArgno = 0;
  534. IArg_cont[0][0] = '\0';
  535. }
  536. } else if (strcmp(yytext, ")") == 0)
  537. { IArg_nst--;
  538. } else
  539. strcat(IArg_cont[IArgno], yytext);
  540. }
  541. return c;
  542. }