spin.y 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947
  1. /***** spin: spin.y *****/
  2. /* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories. */
  3. /* All Rights Reserved. This software is for educational purposes only. */
  4. /* No guarantee whatsoever is expressed or implied by the distribution of */
  5. /* this code. Permission is given to distribute this code provided that */
  6. /* this introductory message is not removed and no monies are exchanged. */
  7. /* Software written by Gerard J. Holzmann. For tool documentation see: */
  8. /* http://spinroot.com/ */
  9. /* Send all bug-reports and/or questions to: bugs@spinroot.com */
  10. %{
  11. #include "spin.h"
  12. #include <sys/types.h>
  13. #ifndef PC
  14. #include <unistd.h>
  15. #endif
  16. #include <stdarg.h>
  17. #define YYDEBUG 0
  18. #define Stop nn(ZN,'@',ZN,ZN)
  19. #define PART0 "place initialized var decl of "
  20. #define PART1 "place initialized chan decl of "
  21. #define PART2 " at start of proctype "
  22. static Lextok *ltl_to_string(Lextok *);
  23. extern Symbol *context, *owner;
  24. extern Lextok *for_body(Lextok *, int);
  25. extern void for_setup(Lextok *, Lextok *, Lextok *);
  26. extern Lextok *for_index(Lextok *, Lextok *);
  27. extern Lextok *sel_index(Lextok *, Lextok *, Lextok *);
  28. extern int u_sync, u_async, dumptab, scope_level;
  29. extern int initialization_ok, split_decl;
  30. extern short has_sorted, has_random, has_enabled, has_pcvalue, has_np;
  31. extern short has_code, has_state, has_io;
  32. extern void count_runs(Lextok *);
  33. extern void no_internals(Lextok *);
  34. extern void any_runs(Lextok *);
  35. extern void ltl_list(char *, char *);
  36. extern void validref(Lextok *, Lextok *);
  37. extern char yytext[];
  38. int Mpars = 0; /* max nr of message parameters */
  39. int nclaims = 0; /* nr of never claims */
  40. int ltl_mode = 0; /* set when parsing an ltl formula */
  41. int Expand_Ok = 0, realread = 1, IArgs = 0, NamesNotAdded = 0;
  42. int in_for = 0;
  43. char *claimproc = (char *) 0;
  44. char *eventmap = (char *) 0;
  45. static char *ltl_name;
  46. static int Embedded = 0, inEventMap = 0, has_ini = 0;
  47. %}
  48. %token ASSERT PRINT PRINTM
  49. %token C_CODE C_DECL C_EXPR C_STATE C_TRACK
  50. %token RUN LEN ENABLED EVAL PC_VAL
  51. %token TYPEDEF MTYPE INLINE LABEL OF
  52. %token GOTO BREAK ELSE SEMI
  53. %token IF FI DO OD FOR SELECT IN SEP DOTDOT
  54. %token ATOMIC NON_ATOMIC D_STEP UNLESS
  55. %token TIMEOUT NONPROGRESS
  56. %token ACTIVE PROCTYPE D_PROCTYPE
  57. %token HIDDEN SHOW ISLOCAL
  58. %token PRIORITY PROVIDED
  59. %token FULL EMPTY NFULL NEMPTY
  60. %token CONST TYPE XU /* val */
  61. %token NAME UNAME PNAME INAME /* sym */
  62. %token STRING CLAIM TRACE INIT LTL /* sym */
  63. %right ASGN
  64. %left SND O_SND RCV R_RCV /* SND doubles as boolean negation */
  65. %left IMPLIES EQUIV /* ltl */
  66. %left OR
  67. %left AND
  68. %left ALWAYS EVENTUALLY /* ltl */
  69. %left UNTIL WEAK_UNTIL RELEASE /* ltl */
  70. %right NEXT /* ltl */
  71. %left '|'
  72. %left '^'
  73. %left '&'
  74. %left EQ NE
  75. %left GT LT GE LE
  76. %left LSHIFT RSHIFT
  77. %left '+' '-'
  78. %left '*' '/' '%'
  79. %left INCR DECR
  80. %right '~' UMIN NEG
  81. %left DOT
  82. %%
  83. /** PROMELA Grammar Rules **/
  84. program : units { yytext[0] = '\0'; }
  85. ;
  86. units : unit
  87. | units unit
  88. ;
  89. unit : proc /* proctype { } */
  90. | init /* init { } */
  91. | claim /* never claim */
  92. | ltl /* ltl formula */
  93. | events /* event assertions */
  94. | one_decl /* variables, chans */
  95. | utype /* user defined types */
  96. | c_fcts /* c functions etc. */
  97. | ns /* named sequence */
  98. | SEMI /* optional separator */
  99. | error
  100. ;
  101. proc : inst /* optional instantiator */
  102. proctype NAME {
  103. setptype($3, PROCTYPE, ZN);
  104. setpname($3);
  105. context = $3->sym;
  106. context->ini = $2; /* linenr and file */
  107. Expand_Ok++; /* expand struct names in decl */
  108. has_ini = 0;
  109. }
  110. '(' decl ')' { Expand_Ok--;
  111. if (has_ini)
  112. fatal("initializer in parameter list", (char *) 0);
  113. }
  114. Opt_priority
  115. Opt_enabler
  116. body { ProcList *rl;
  117. if ($1 != ZN && $1->val > 0)
  118. { int j;
  119. rl = ready($3->sym, $6, $11->sq, $2->val, $10, A_PROC);
  120. for (j = 0; j < $1->val; j++)
  121. { runnable(rl, $9?$9->val:1, 1);
  122. }
  123. announce(":root:");
  124. if (dumptab) $3->sym->ini = $1;
  125. } else
  126. { rl = ready($3->sym, $6, $11->sq, $2->val, $10, P_PROC);
  127. }
  128. if (rl && has_ini == 1) /* global initializations, unsafe */
  129. { /* printf("proctype %s has initialized data\n",
  130. $3->sym->name);
  131. */
  132. rl->unsafe = 1;
  133. }
  134. context = ZS;
  135. }
  136. ;
  137. proctype: PROCTYPE { $$ = nn(ZN,CONST,ZN,ZN); $$->val = 0; }
  138. | D_PROCTYPE { $$ = nn(ZN,CONST,ZN,ZN); $$->val = 1; }
  139. ;
  140. inst : /* empty */ { $$ = ZN; }
  141. | ACTIVE { $$ = nn(ZN,CONST,ZN,ZN); $$->val = 1; }
  142. | ACTIVE '[' CONST ']' {
  143. $$ = nn(ZN,CONST,ZN,ZN); $$->val = $3->val;
  144. if ($3->val > 255)
  145. non_fatal("max nr of processes is 255\n", "");
  146. }
  147. | ACTIVE '[' NAME ']' {
  148. $$ = nn(ZN,CONST,ZN,ZN);
  149. $$->val = 0;
  150. if (!$3->sym->type)
  151. fatal("undeclared variable %s",
  152. $3->sym->name);
  153. else if ($3->sym->ini->ntyp != CONST)
  154. fatal("need constant initializer for %s\n",
  155. $3->sym->name);
  156. else
  157. $$->val = $3->sym->ini->val;
  158. }
  159. ;
  160. init : INIT { context = $1->sym; }
  161. Opt_priority
  162. body { ProcList *rl;
  163. rl = ready(context, ZN, $4->sq, 0, ZN, I_PROC);
  164. runnable(rl, $3?$3->val:1, 1);
  165. announce(":root:");
  166. context = ZS;
  167. }
  168. ;
  169. ltl : LTL optname2 { ltl_mode = 1; ltl_name = $2->sym->name; }
  170. ltl_body { if ($4) ltl_list($2->sym->name, $4->sym->name);
  171. ltl_mode = 0;
  172. }
  173. ;
  174. ltl_body: '{' full_expr OS '}' { $$ = ltl_to_string($2); }
  175. | error { $$ = NULL; }
  176. ;
  177. claim : CLAIM optname { if ($2 != ZN)
  178. { $1->sym = $2->sym; /* new 5.3.0 */
  179. }
  180. nclaims++;
  181. context = $1->sym;
  182. if (claimproc && !strcmp(claimproc, $1->sym->name))
  183. { fatal("claim %s redefined", claimproc);
  184. }
  185. claimproc = $1->sym->name;
  186. }
  187. body { (void) ready($1->sym, ZN, $4->sq, 0, ZN, N_CLAIM);
  188. context = ZS;
  189. }
  190. ;
  191. optname : /* empty */ { char tb[32];
  192. memset(tb, 0, 32);
  193. sprintf(tb, "never_%d", nclaims);
  194. $$ = nn(ZN, NAME, ZN, ZN);
  195. $$->sym = lookup(tb);
  196. }
  197. | NAME { $$ = $1; }
  198. ;
  199. optname2 : /* empty */ { char tb[32]; static int nltl = 0;
  200. memset(tb, 0, 32);
  201. sprintf(tb, "ltl_%d", nltl++);
  202. $$ = nn(ZN, NAME, ZN, ZN);
  203. $$->sym = lookup(tb);
  204. }
  205. | NAME { $$ = $1; }
  206. ;
  207. events : TRACE { context = $1->sym;
  208. if (eventmap)
  209. non_fatal("trace %s redefined", eventmap);
  210. eventmap = $1->sym->name;
  211. inEventMap++;
  212. }
  213. body {
  214. if (strcmp($1->sym->name, ":trace:") == 0)
  215. { (void) ready($1->sym, ZN, $3->sq, 0, ZN, E_TRACE);
  216. } else
  217. { (void) ready($1->sym, ZN, $3->sq, 0, ZN, N_TRACE);
  218. }
  219. context = ZS;
  220. inEventMap--;
  221. }
  222. ;
  223. utype : TYPEDEF NAME { if (context)
  224. fatal("typedef %s must be global",
  225. $2->sym->name);
  226. owner = $2->sym;
  227. }
  228. '{' decl_lst '}' { setuname($5); owner = ZS; }
  229. ;
  230. nm : NAME { $$ = $1; }
  231. | INAME { $$ = $1;
  232. if (IArgs)
  233. fatal("invalid use of '%s'", $1->sym->name);
  234. }
  235. ;
  236. ns : INLINE nm '(' { NamesNotAdded++; }
  237. args ')' { prep_inline($2->sym, $5);
  238. NamesNotAdded--;
  239. }
  240. ;
  241. c_fcts : ccode { /* leaves pseudo-inlines with sym of
  242. * type CODE_FRAG or CODE_DECL in global context
  243. */
  244. }
  245. | cstate
  246. ;
  247. cstate : C_STATE STRING STRING {
  248. c_state($2->sym, $3->sym, ZS);
  249. has_code = has_state = 1;
  250. }
  251. | C_TRACK STRING STRING {
  252. c_track($2->sym, $3->sym, ZS);
  253. has_code = has_state = 1;
  254. }
  255. | C_STATE STRING STRING STRING {
  256. c_state($2->sym, $3->sym, $4->sym);
  257. has_code = has_state = 1;
  258. }
  259. | C_TRACK STRING STRING STRING {
  260. c_track($2->sym, $3->sym, $4->sym);
  261. has_code = has_state = 1;
  262. }
  263. ;
  264. ccode : C_CODE { Symbol *s;
  265. NamesNotAdded++;
  266. s = prep_inline(ZS, ZN);
  267. NamesNotAdded--;
  268. $$ = nn(ZN, C_CODE, ZN, ZN);
  269. $$->sym = s;
  270. has_code = 1;
  271. }
  272. | C_DECL { Symbol *s;
  273. NamesNotAdded++;
  274. s = prep_inline(ZS, ZN);
  275. NamesNotAdded--;
  276. s->type = CODE_DECL;
  277. $$ = nn(ZN, C_CODE, ZN, ZN);
  278. $$->sym = s;
  279. has_code = 1;
  280. }
  281. ;
  282. cexpr : C_EXPR { Symbol *s;
  283. NamesNotAdded++;
  284. s = prep_inline(ZS, ZN);
  285. NamesNotAdded--;
  286. $$ = nn(ZN, C_EXPR, ZN, ZN);
  287. $$->sym = s;
  288. no_side_effects(s->name);
  289. has_code = 1;
  290. }
  291. ;
  292. body : '{' { open_seq(1); }
  293. sequence OS { add_seq(Stop); }
  294. '}' { $$->sq = close_seq(0);
  295. if (scope_level != 0)
  296. { non_fatal("missing '}' ?", 0);
  297. scope_level = 0;
  298. }
  299. }
  300. ;
  301. sequence: step { if ($1) add_seq($1); }
  302. | sequence MS step { if ($3) add_seq($3); }
  303. ;
  304. step : one_decl { $$ = ZN; }
  305. | XU vref_lst { setxus($2, $1->val); $$ = ZN; }
  306. | NAME ':' one_decl { fatal("label preceding declaration,", (char *)0); }
  307. | NAME ':' XU { fatal("label predecing xr/xs claim,", 0); }
  308. | stmnt { $$ = $1; }
  309. | stmnt UNLESS stmnt { $$ = do_unless($1, $3); }
  310. ;
  311. vis : /* empty */ { $$ = ZN; }
  312. | HIDDEN { $$ = $1; }
  313. | SHOW { $$ = $1; }
  314. | ISLOCAL { $$ = $1; }
  315. ;
  316. asgn: /* empty */
  317. | ASGN
  318. ;
  319. one_decl: vis TYPE var_list { setptype($3, $2->val, $1);
  320. $$ = $3;
  321. }
  322. | vis UNAME var_list { setutype($3, $2->sym, $1);
  323. $$ = expand($3, Expand_Ok);
  324. }
  325. | vis TYPE asgn '{' nlst '}' {
  326. if ($2->val != MTYPE)
  327. fatal("malformed declaration", 0);
  328. setmtype($5);
  329. if ($1)
  330. non_fatal("cannot %s mtype (ignored)",
  331. $1->sym->name);
  332. if (context != ZS)
  333. fatal("mtype declaration must be global", 0);
  334. }
  335. ;
  336. decl_lst: one_decl { $$ = nn(ZN, ',', $1, ZN); }
  337. | one_decl SEMI
  338. decl_lst { $$ = nn(ZN, ',', $1, $3); }
  339. ;
  340. decl : /* empty */ { $$ = ZN; }
  341. | decl_lst { $$ = $1; }
  342. ;
  343. vref_lst: varref { $$ = nn($1, XU, $1, ZN); }
  344. | varref ',' vref_lst { $$ = nn($1, XU, $1, $3); }
  345. ;
  346. var_list: ivar { $$ = nn($1, TYPE, ZN, ZN); }
  347. | ivar ',' var_list { $$ = nn($1, TYPE, ZN, $3); }
  348. ;
  349. ivar : vardcl { $$ = $1;
  350. $1->sym->ini = nn(ZN,CONST,ZN,ZN);
  351. $1->sym->ini->val = 0;
  352. }
  353. | vardcl ASGN expr { $$ = $1;
  354. $1->sym->ini = $3;
  355. trackvar($1,$3);
  356. if ($3->ntyp == CONST
  357. || ($3->ntyp == NAME && $3->sym->context))
  358. { has_ini = 2; /* local init */
  359. } else
  360. { has_ini = 1; /* possibly global */
  361. }
  362. if (!initialization_ok && split_decl)
  363. { nochan_manip($1, $3, 0);
  364. no_internals($1);
  365. non_fatal(PART0 "'%s'" PART2, $1->sym->name);
  366. }
  367. }
  368. | vardcl ASGN ch_init { $1->sym->ini = $3;
  369. $$ = $1; has_ini = 1;
  370. if (!initialization_ok && split_decl)
  371. { non_fatal(PART1 "'%s'" PART2, $1->sym->name);
  372. }
  373. }
  374. ;
  375. ch_init : '[' CONST ']' OF
  376. '{' typ_list '}' { if ($2->val)
  377. u_async++;
  378. else
  379. u_sync++;
  380. { int i = cnt_mpars($6);
  381. Mpars = max(Mpars, i);
  382. }
  383. $$ = nn(ZN, CHAN, ZN, $6);
  384. $$->val = $2->val;
  385. }
  386. ;
  387. vardcl : NAME { $1->sym->nel = 1; $$ = $1; }
  388. | NAME ':' CONST { $1->sym->nbits = $3->val;
  389. if ($3->val >= 8*sizeof(long))
  390. { non_fatal("width-field %s too large",
  391. $1->sym->name);
  392. $3->val = 8*sizeof(long)-1;
  393. }
  394. $1->sym->nel = 1; $$ = $1;
  395. }
  396. | NAME '[' CONST ']' { $1->sym->nel = $3->val; $1->sym->isarray = 1; $$ = $1; }
  397. ;
  398. varref : cmpnd { $$ = mk_explicit($1, Expand_Ok, NAME); }
  399. ;
  400. pfld : NAME { $$ = nn($1, NAME, ZN, ZN);
  401. if ($1->sym->isarray && !in_for)
  402. { non_fatal("missing array index for '%s'",
  403. $1->sym->name);
  404. }
  405. }
  406. | NAME { owner = ZS; }
  407. '[' expr ']' { $$ = nn($1, NAME, $4, ZN); }
  408. ;
  409. cmpnd : pfld { Embedded++;
  410. if ($1->sym->type == STRUCT)
  411. owner = $1->sym->Snm;
  412. }
  413. sfld { $$ = $1; $$->rgt = $3;
  414. if ($3 && $1->sym->type != STRUCT)
  415. $1->sym->type = STRUCT;
  416. Embedded--;
  417. if (!Embedded && !NamesNotAdded
  418. && !$1->sym->type)
  419. fatal("undeclared variable: %s",
  420. $1->sym->name);
  421. if ($3) validref($1, $3->lft);
  422. owner = ZS;
  423. }
  424. ;
  425. sfld : /* empty */ { $$ = ZN; }
  426. | '.' cmpnd %prec DOT { $$ = nn(ZN, '.', $2, ZN); }
  427. ;
  428. stmnt : Special { $$ = $1; initialization_ok = 0; }
  429. | Stmnt { $$ = $1; initialization_ok = 0;
  430. if (inEventMap)
  431. non_fatal("not an event", (char *)0);
  432. }
  433. ;
  434. for_pre : FOR '(' { in_for = 1; }
  435. varref { $$ = $4; }
  436. ;
  437. for_post: '{' sequence OS '}' ;
  438. Special : varref RCV { Expand_Ok++; }
  439. rargs { Expand_Ok--; has_io++;
  440. $$ = nn($1, 'r', $1, $4);
  441. trackchanuse($4, ZN, 'R');
  442. }
  443. | varref SND { Expand_Ok++; }
  444. margs { Expand_Ok--; has_io++;
  445. $$ = nn($1, 's', $1, $4);
  446. $$->val=0; trackchanuse($4, ZN, 'S');
  447. any_runs($4);
  448. }
  449. | for_pre ':' expr DOTDOT expr ')' {
  450. for_setup($1, $3, $5); in_for = 0;
  451. }
  452. for_post { $$ = for_body($1, 1);
  453. }
  454. | for_pre IN varref ')' { $$ = for_index($1, $3); in_for = 0;
  455. }
  456. for_post { $$ = for_body($5, 1);
  457. }
  458. | SELECT '(' varref ':' expr DOTDOT expr ')' {
  459. $$ = sel_index($3, $5, $7);
  460. }
  461. | IF options FI { $$ = nn($1, IF, ZN, ZN);
  462. $$->sl = $2->sl;
  463. prune_opts($$);
  464. }
  465. | DO { pushbreak(); }
  466. options OD { $$ = nn($1, DO, ZN, ZN);
  467. $$->sl = $3->sl;
  468. prune_opts($$);
  469. }
  470. | BREAK { $$ = nn(ZN, GOTO, ZN, ZN);
  471. $$->sym = break_dest();
  472. }
  473. | GOTO NAME { $$ = nn($2, GOTO, ZN, ZN);
  474. if ($2->sym->type != 0
  475. && $2->sym->type != LABEL) {
  476. non_fatal("bad label-name %s",
  477. $2->sym->name);
  478. }
  479. $2->sym->type = LABEL;
  480. }
  481. | NAME ':' stmnt { $$ = nn($1, ':',$3, ZN);
  482. if ($1->sym->type != 0
  483. && $1->sym->type != LABEL) {
  484. non_fatal("bad label-name %s",
  485. $1->sym->name);
  486. }
  487. $1->sym->type = LABEL;
  488. }
  489. ;
  490. Stmnt : varref ASGN full_expr { $$ = nn($1, ASGN, $1, $3);
  491. trackvar($1, $3);
  492. nochan_manip($1, $3, 0);
  493. no_internals($1);
  494. }
  495. | varref INCR { $$ = nn(ZN,CONST, ZN, ZN); $$->val = 1;
  496. $$ = nn(ZN, '+', $1, $$);
  497. $$ = nn($1, ASGN, $1, $$);
  498. trackvar($1, $1);
  499. no_internals($1);
  500. if ($1->sym->type == CHAN)
  501. fatal("arithmetic on chan", (char *)0);
  502. }
  503. | varref DECR { $$ = nn(ZN,CONST, ZN, ZN); $$->val = 1;
  504. $$ = nn(ZN, '-', $1, $$);
  505. $$ = nn($1, ASGN, $1, $$);
  506. trackvar($1, $1);
  507. no_internals($1);
  508. if ($1->sym->type == CHAN)
  509. fatal("arithmetic on chan id's", (char *)0);
  510. }
  511. | PRINT '(' STRING { realread = 0; }
  512. prargs ')' { $$ = nn($3, PRINT, $5, ZN); realread = 1; }
  513. | PRINTM '(' varref ')' { $$ = nn(ZN, PRINTM, $3, ZN); }
  514. | PRINTM '(' CONST ')' { $$ = nn(ZN, PRINTM, $3, ZN); }
  515. | ASSERT full_expr { $$ = nn(ZN, ASSERT, $2, ZN); AST_track($2, 0); }
  516. | ccode { $$ = $1; }
  517. | varref R_RCV { Expand_Ok++; }
  518. rargs { Expand_Ok--; has_io++;
  519. $$ = nn($1, 'r', $1, $4);
  520. $$->val = has_random = 1;
  521. trackchanuse($4, ZN, 'R');
  522. }
  523. | varref RCV { Expand_Ok++; }
  524. LT rargs GT { Expand_Ok--; has_io++;
  525. $$ = nn($1, 'r', $1, $5);
  526. $$->val = 2; /* fifo poll */
  527. trackchanuse($5, ZN, 'R');
  528. }
  529. | varref R_RCV { Expand_Ok++; }
  530. LT rargs GT { Expand_Ok--; has_io++; /* rrcv poll */
  531. $$ = nn($1, 'r', $1, $5);
  532. $$->val = 3; has_random = 1;
  533. trackchanuse($5, ZN, 'R');
  534. }
  535. | varref O_SND { Expand_Ok++; }
  536. margs { Expand_Ok--; has_io++;
  537. $$ = nn($1, 's', $1, $4);
  538. $$->val = has_sorted = 1;
  539. trackchanuse($4, ZN, 'S');
  540. any_runs($4);
  541. }
  542. | full_expr { $$ = nn(ZN, 'c', $1, ZN); count_runs($$); }
  543. | ELSE { $$ = nn(ZN,ELSE,ZN,ZN);
  544. }
  545. | ATOMIC '{' { open_seq(0); }
  546. sequence OS '}' { $$ = nn($1, ATOMIC, ZN, ZN);
  547. $$->sl = seqlist(close_seq(3), 0);
  548. make_atomic($$->sl->this, 0);
  549. }
  550. | D_STEP '{' { open_seq(0);
  551. rem_Seq();
  552. }
  553. sequence OS '}' { $$ = nn($1, D_STEP, ZN, ZN);
  554. $$->sl = seqlist(close_seq(4), 0);
  555. make_atomic($$->sl->this, D_ATOM);
  556. unrem_Seq();
  557. }
  558. | '{' { open_seq(0); }
  559. sequence OS '}' { $$ = nn(ZN, NON_ATOMIC, ZN, ZN);
  560. $$->sl = seqlist(close_seq(5), 0);
  561. }
  562. | INAME { IArgs++; }
  563. '(' args ')' { pickup_inline($1->sym, $4); IArgs--; }
  564. Stmnt { $$ = $7; }
  565. ;
  566. options : option { $$->sl = seqlist($1->sq, 0); }
  567. | option options { $$->sl = seqlist($1->sq, $2->sl); }
  568. ;
  569. option : SEP { open_seq(0); }
  570. sequence OS { $$ = nn(ZN,0,ZN,ZN);
  571. $$->sq = close_seq(6); }
  572. ;
  573. OS : /* empty */
  574. | SEMI { /* redundant semi at end of sequence */ }
  575. ;
  576. MS : SEMI { /* at least one semi-colon */ }
  577. | MS SEMI { /* but more are okay too */ }
  578. ;
  579. aname : NAME { $$ = $1; }
  580. | PNAME { $$ = $1; }
  581. ;
  582. expr : '(' expr ')' { $$ = $2; }
  583. | expr '+' expr { $$ = nn(ZN, '+', $1, $3); }
  584. | expr '-' expr { $$ = nn(ZN, '-', $1, $3); }
  585. | expr '*' expr { $$ = nn(ZN, '*', $1, $3); }
  586. | expr '/' expr { $$ = nn(ZN, '/', $1, $3); }
  587. | expr '%' expr { $$ = nn(ZN, '%', $1, $3); }
  588. | expr '&' expr { $$ = nn(ZN, '&', $1, $3); }
  589. | expr '^' expr { $$ = nn(ZN, '^', $1, $3); }
  590. | expr '|' expr { $$ = nn(ZN, '|', $1, $3); }
  591. | expr GT expr { $$ = nn(ZN, GT, $1, $3); }
  592. | expr LT expr { $$ = nn(ZN, LT, $1, $3); }
  593. | expr GE expr { $$ = nn(ZN, GE, $1, $3); }
  594. | expr LE expr { $$ = nn(ZN, LE, $1, $3); }
  595. | expr EQ expr { $$ = nn(ZN, EQ, $1, $3); }
  596. | expr NE expr { $$ = nn(ZN, NE, $1, $3); }
  597. | expr AND expr { $$ = nn(ZN, AND, $1, $3); }
  598. | expr OR expr { $$ = nn(ZN, OR, $1, $3); }
  599. | expr LSHIFT expr { $$ = nn(ZN, LSHIFT,$1, $3); }
  600. | expr RSHIFT expr { $$ = nn(ZN, RSHIFT,$1, $3); }
  601. | '~' expr { $$ = nn(ZN, '~', $2, ZN); }
  602. | '-' expr %prec UMIN { $$ = nn(ZN, UMIN, $2, ZN); }
  603. | SND expr %prec NEG { $$ = nn(ZN, '!', $2, ZN); }
  604. | '(' expr SEMI expr ':' expr ')' {
  605. $$ = nn(ZN, OR, $4, $6);
  606. $$ = nn(ZN, '?', $2, $$);
  607. }
  608. | RUN aname { Expand_Ok++;
  609. if (!context)
  610. fatal("used 'run' outside proctype",
  611. (char *) 0);
  612. }
  613. '(' args ')'
  614. Opt_priority { Expand_Ok--;
  615. $$ = nn($2, RUN, $5, ZN);
  616. $$->val = ($7) ? $7->val : 1;
  617. trackchanuse($5, $2, 'A'); trackrun($$);
  618. }
  619. | LEN '(' varref ')' { $$ = nn($3, LEN, $3, ZN); }
  620. | ENABLED '(' expr ')' { $$ = nn(ZN, ENABLED, $3, ZN);
  621. has_enabled++;
  622. }
  623. | varref RCV { Expand_Ok++; }
  624. '[' rargs ']' { Expand_Ok--; has_io++;
  625. $$ = nn($1, 'R', $1, $5);
  626. }
  627. | varref R_RCV { Expand_Ok++; }
  628. '[' rargs ']' { Expand_Ok--; has_io++;
  629. $$ = nn($1, 'R', $1, $5);
  630. $$->val = has_random = 1;
  631. }
  632. | varref { $$ = $1; trapwonly($1 /*, "varref" */); }
  633. | cexpr { $$ = $1; }
  634. | CONST { $$ = nn(ZN,CONST,ZN,ZN);
  635. $$->ismtyp = $1->ismtyp;
  636. $$->val = $1->val;
  637. }
  638. | TIMEOUT { $$ = nn(ZN,TIMEOUT, ZN, ZN); }
  639. | NONPROGRESS { $$ = nn(ZN,NONPROGRESS, ZN, ZN);
  640. has_np++;
  641. }
  642. | PC_VAL '(' expr ')' { $$ = nn(ZN, PC_VAL, $3, ZN);
  643. has_pcvalue++;
  644. }
  645. | PNAME '[' expr ']' '@' NAME
  646. { $$ = rem_lab($1->sym, $3, $6->sym); }
  647. | PNAME '[' expr ']' ':' pfld
  648. { $$ = rem_var($1->sym, $3, $6->sym, $6->lft); }
  649. | PNAME '@' NAME { $$ = rem_lab($1->sym, ZN, $3->sym); }
  650. | PNAME ':' pfld { $$ = rem_var($1->sym, ZN, $3->sym, $3->lft); }
  651. | ltl_expr { $$ = $1; }
  652. ;
  653. Opt_priority: /* none */ { $$ = ZN; }
  654. | PRIORITY CONST { $$ = $2; }
  655. ;
  656. full_expr: expr { $$ = $1; }
  657. | Expr { $$ = $1; }
  658. ;
  659. ltl_expr: expr UNTIL expr { $$ = nn(ZN, UNTIL, $1, $3); }
  660. | expr RELEASE expr { $$ = nn(ZN, RELEASE, $1, $3); }
  661. | expr WEAK_UNTIL expr { $$ = nn(ZN, ALWAYS, $1, ZN);
  662. $$ = nn(ZN, OR, $$, nn(ZN, UNTIL, $1, $3));
  663. }
  664. | expr IMPLIES expr {
  665. $$ = nn(ZN, '!', $1, ZN);
  666. $$ = nn(ZN, OR, $$, $3);
  667. }
  668. | expr EQUIV expr { $$ = nn(ZN, EQUIV, $1, $3); }
  669. | NEXT expr %prec NEG { $$ = nn(ZN, NEXT, $2, ZN); }
  670. | ALWAYS expr %prec NEG { $$ = nn(ZN, ALWAYS,$2, ZN); }
  671. | EVENTUALLY expr %prec NEG { $$ = nn(ZN, EVENTUALLY, $2, ZN); }
  672. ;
  673. /* an Expr cannot be negated - to protect Probe expressions */
  674. Expr : Probe { $$ = $1; }
  675. | '(' Expr ')' { $$ = $2; }
  676. | Expr AND Expr { $$ = nn(ZN, AND, $1, $3); }
  677. | Expr AND expr { $$ = nn(ZN, AND, $1, $3); }
  678. | expr AND Expr { $$ = nn(ZN, AND, $1, $3); }
  679. | Expr OR Expr { $$ = nn(ZN, OR, $1, $3); }
  680. | Expr OR expr { $$ = nn(ZN, OR, $1, $3); }
  681. | expr OR Expr { $$ = nn(ZN, OR, $1, $3); }
  682. ;
  683. Probe : FULL '(' varref ')' { $$ = nn($3, FULL, $3, ZN); }
  684. | NFULL '(' varref ')' { $$ = nn($3, NFULL, $3, ZN); }
  685. | EMPTY '(' varref ')' { $$ = nn($3, EMPTY, $3, ZN); }
  686. | NEMPTY '(' varref ')' { $$ = nn($3,NEMPTY, $3, ZN); }
  687. ;
  688. Opt_enabler: /* none */ { $$ = ZN; }
  689. | PROVIDED '(' full_expr ')' { if (!proper_enabler($3))
  690. { non_fatal("invalid PROVIDED clause",
  691. (char *)0);
  692. $$ = ZN;
  693. } else
  694. $$ = $3;
  695. }
  696. | PROVIDED error { $$ = ZN;
  697. non_fatal("usage: provided ( ..expr.. )",
  698. (char *)0);
  699. }
  700. ;
  701. basetype: TYPE { $$->sym = ZS;
  702. $$->val = $1->val;
  703. if ($$->val == UNSIGNED)
  704. fatal("unsigned cannot be used as mesg type", 0);
  705. }
  706. | UNAME { $$->sym = $1->sym;
  707. $$->val = STRUCT;
  708. }
  709. | error /* e.g., unsigned ':' const */
  710. ;
  711. typ_list: basetype { $$ = nn($1, $1->val, ZN, ZN); }
  712. | basetype ',' typ_list { $$ = nn($1, $1->val, ZN, $3); }
  713. ;
  714. args : /* empty */ { $$ = ZN; }
  715. | arg { $$ = $1; }
  716. ;
  717. prargs : /* empty */ { $$ = ZN; }
  718. | ',' arg { $$ = $2; }
  719. ;
  720. margs : arg { $$ = $1; }
  721. | expr '(' arg ')' { if ($1->ntyp == ',')
  722. $$ = tail_add($1, $3);
  723. else
  724. $$ = nn(ZN, ',', $1, $3);
  725. }
  726. ;
  727. arg : expr { if ($1->ntyp == ',')
  728. $$ = $1;
  729. else
  730. $$ = nn(ZN, ',', $1, ZN);
  731. }
  732. | expr ',' arg { if ($1->ntyp == ',')
  733. $$ = tail_add($1, $3);
  734. else
  735. $$ = nn(ZN, ',', $1, $3);
  736. }
  737. ;
  738. rarg : varref { $$ = $1; trackvar($1, $1);
  739. trapwonly($1 /*, "rarg" */); }
  740. | EVAL '(' expr ')' { $$ = nn(ZN,EVAL,$3,ZN);
  741. trapwonly($1 /*, "eval rarg" */); }
  742. | CONST { $$ = nn(ZN,CONST,ZN,ZN);
  743. $$->ismtyp = $1->ismtyp;
  744. $$->val = $1->val;
  745. }
  746. | '-' CONST %prec UMIN { $$ = nn(ZN,CONST,ZN,ZN);
  747. $$->val = - ($2->val);
  748. }
  749. ;
  750. rargs : rarg { if ($1->ntyp == ',')
  751. $$ = $1;
  752. else
  753. $$ = nn(ZN, ',', $1, ZN);
  754. }
  755. | rarg ',' rargs { if ($1->ntyp == ',')
  756. $$ = tail_add($1, $3);
  757. else
  758. $$ = nn(ZN, ',', $1, $3);
  759. }
  760. | rarg '(' rargs ')' { if ($1->ntyp == ',')
  761. $$ = tail_add($1, $3);
  762. else
  763. $$ = nn(ZN, ',', $1, $3);
  764. }
  765. | '(' rargs ')' { $$ = $2; }
  766. ;
  767. nlst : NAME { $$ = nn($1, NAME, ZN, ZN);
  768. $$ = nn(ZN, ',', $$, ZN); }
  769. | nlst NAME { $$ = nn($2, NAME, ZN, ZN);
  770. $$ = nn(ZN, ',', $$, $1);
  771. }
  772. | nlst ',' { $$ = $1; /* commas optional */ }
  773. ;
  774. %%
  775. #define binop(n, sop) fprintf(fd, "("); recursive(fd, n->lft); \
  776. fprintf(fd, ") %s (", sop); recursive(fd, n->rgt); \
  777. fprintf(fd, ")");
  778. #define unop(n, sop) fprintf(fd, "%s (", sop); recursive(fd, n->lft); \
  779. fprintf(fd, ")");
  780. static void
  781. recursive(FILE *fd, Lextok *n)
  782. {
  783. if (n)
  784. switch (n->ntyp) {
  785. case NEXT:
  786. unop(n, "X");
  787. break;
  788. case ALWAYS:
  789. unop(n, "[]");
  790. break;
  791. case EVENTUALLY:
  792. unop(n, "<>");
  793. break;
  794. case '!':
  795. unop(n, "!");
  796. break;
  797. case UNTIL:
  798. binop(n, "U");
  799. break;
  800. case WEAK_UNTIL:
  801. binop(n, "W");
  802. break;
  803. case RELEASE: /* see http://en.wikipedia.org/wiki/Linear_temporal_logic */
  804. binop(n, "V");
  805. break;
  806. case OR:
  807. binop(n, "||");
  808. break;
  809. case AND:
  810. binop(n, "&&");
  811. break;
  812. case IMPLIES:
  813. binop(n, "->");
  814. break;
  815. case EQUIV:
  816. binop(n, "<->");
  817. break;
  818. default:
  819. comment(fd, n, 0);
  820. break;
  821. }
  822. }
  823. #define TMP_FILE "_S_p_I_n_.tmp"
  824. extern int unlink(const char *);
  825. static Lextok *
  826. ltl_to_string(Lextok *n)
  827. { Lextok *m = nn(ZN, 0, ZN, ZN);
  828. char *retval;
  829. char formula[1024];
  830. FILE *tf = fopen(TMP_FILE, "w+"); /* tmpfile() fails on Windows 7 */
  831. /* convert the parsed ltl to a string
  832. by writing into a file, using existing functions,
  833. and then passing it to the existing interface for
  834. conversion into a never claim
  835. (this means parsing everything twice, which is
  836. a little redundant, but adds only miniscule overhead)
  837. */
  838. if (!tf)
  839. { fatal("cannot create temporary file", (char *) 0);
  840. }
  841. recursive(tf, n);
  842. (void) fseek(tf, 0L, SEEK_SET);
  843. memset(formula, 0, sizeof(formula));
  844. retval = fgets(formula, sizeof(formula), tf);
  845. fclose(tf);
  846. (void) unlink(TMP_FILE);
  847. if (!retval)
  848. { printf("%p\n", retval);
  849. fatal("could not translate ltl formula", 0);
  850. }
  851. if (1) printf("ltl %s: %s\n", ltl_name, formula);
  852. m->sym = lookup(formula);
  853. return m;
  854. }
  855. void
  856. yyerror(char *fmt, ...)
  857. {
  858. non_fatal(fmt, (char *) 0);
  859. }