├── version.h ├── README.txt ├── makefile ├── LICENSE ├── tl_mem.c ├── tl.h ├── tl_lex.c ├── tl_main.c ├── tl_cache.c ├── tl_rewrt.c ├── pangen4.c ├── tl_parse.c ├── vars.c ├── guided.c ├── msc_tcl.c ├── reprosrc.c ├── dstep.c ├── pangen5.h ├── pangen3.c ├── spin.h ├── tl_buchi.c ├── sym.c ├── structs.c └── run.c /version.h: -------------------------------------------------------------------------------- 1 | /***** spin: version.h *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | */ 8 | 9 | #define SpinVersion "Spin Version 6.4.7 -- 19 August 2017" 10 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | This is Spin version 6.4.7 with some additional patches from the developer Gerard Holzmann. He said that they will be included in version 6.4.8, but until then they will live here. 2 | 3 | You may need to install YACC: 4 | sudo apt-get install bison 5 | 6 | To compile: 7 | make 8 | 9 | To install (it will be installed to /usr/local/bin): 10 | sudo make install 11 | 12 | To clean: 13 | make clean 14 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # SPIN - Verification Software - Version 6.4 - August 2017 2 | # 3 | # This file is part of the public release of Spin. It is subject to the 4 | # terms in the LICENSE file that is included in this source directory. 5 | # Tool documentation is available at http://spinroot.com 6 | 7 | CC=gcc 8 | CFLAGS?=-O2 -DNXT # on some systems add: -I/usr/include 9 | # on a PC: make CFLAGS=-O2 -DNXT -DPC 10 | # on Solaris: make CFLAGS=-O2 -DNXT -DSOLARIS 11 | # on a Mac: make CFLAGS=-O2 -DNXT -DMAC 12 | # on HP-UX: make CFLAGS=-O2 -DNXT -Aa 13 | 14 | # debugging: make CFLAGS=-pg -g -DNXT 15 | 16 | # for a more picky compilation use gcc-4 and add: 17 | PICKY=-std=c99 -Wstrict-prototypes -pedantic -fno-strength-reduce \ 18 | -fno-builtin -W -Wshadow -Wpointer-arith \ 19 | -Wcast-qual -Winline -Wall 20 | 21 | # when running spin with a different compiler: 22 | # on OS2: spin -Picc -E/Pd+ -E/Q+ 23 | # for Visual C++: spin -PCL -E/E 24 | 25 | YACC=yacc # on Solaris: /usr/ccs/bin/yacc 26 | YFLAGS=-v -d # creates y.output and y.tab.h 27 | DESTDIR?=/usr/local/bin 28 | INSTALL?=cp 29 | 30 | SPIN_OS= spinlex.o sym.o vars.o main.o msc_tcl.o \ 31 | mesg.o flow.o sched.o run.o pangen1.o pangen2.o \ 32 | pangen3.o pangen4.o pangen5.o guided.o dstep.o \ 33 | structs.o pangen6.o pangen7.o reprosrc.o 34 | 35 | TL_OS= tl_parse.o tl_lex.o tl_main.o tl_trans.o tl_buchi.o \ 36 | tl_mem.o tl_rewrt.o tl_cache.o 37 | 38 | spin: $(SPIN_OS) $(TL_OS) spin.o 39 | $(CC) $(CFLAGS) -o spin spin.o $(SPIN_OS) $(TL_OS) 40 | 41 | install: spin 42 | $(INSTALL) spin $(DESTDIR) 43 | 44 | spin.o: spin.y 45 | $(YACC) $(YFLAGS) spin.y 46 | $(CC) $(CFLAGS) -c y?tab.c 47 | rm -f y?tab.c 48 | mv y?tab.o spin.o 49 | 50 | $(SPIN_OS): spin.h spin.o 51 | 52 | $(TL_OS): tl.h spin.o 53 | 54 | main.o pangen2.o msc_tcl.o: version.h 55 | pangen1.o: pangen1.h pangen3.h pangen6.h 56 | pangen2.o: pangen2.h pangen4.h pangen5.h pangen7.h 57 | 58 | clean: 59 | rm -f spin *.o y?tab.[ch] y.output y.debug 60 | rm -f pan.[chmotb] a.out core *stackdump 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Spin open source distribution 2 | ============================= 3 | 4 | Copyright (c) 1989-2016 Gerard J. Holzmann. All rights reserved. 5 | 6 | This software was originally authored by employees of Bell Laboratories, 7 | a unit of Lucent Technologies, Inc. All Alcatel-Lucent copyrights in the 8 | software were assigned to Gerard J. Holzmann on 30 December 2015, and 9 | thus no rights are herein granted by Lucent Technologies itself, or by 10 | its successor Alcatel-Lucent. 11 | 12 | This and subsequent versions of the Spin source code are made available 13 | as open source code under the terms of the BSD 3-Clause License: 14 | 15 | Redistribution and use in source and binary forms, with or without 16 | modification, are permitted provided that the following conditions 17 | are met: 18 | 19 | 1. Redistributions of source code must retain the above copyright notice, 20 | this list of conditions and the following disclaimer. 21 | 22 | 2. Redistributions in binary form must reproduce the above copyright notice, 23 | this list of conditions and the following disclaimer in the documentation 24 | and/or other materials provided with the distribution. 25 | 26 | 3. Neither the name of the copyright holder nor the names of its contributors 27 | may be used to endorse or promote products derived from this software 28 | without specific prior written permission. 29 | 30 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 31 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 34 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 35 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 36 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 37 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 38 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 39 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 40 | POSSIBILITY OF SUCH DAMAGE. 41 | -------------------------------------------------------------------------------- /tl_mem.c: -------------------------------------------------------------------------------- 1 | /***** tl_spin: tl_mem.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | * 8 | * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, 9 | * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. 10 | */ 11 | 12 | #include "tl.h" 13 | 14 | #if 1 15 | #define log(e, u, d) event[e][(int) u] += (long) d; 16 | #else 17 | #define log(e, u, d) 18 | #endif 19 | 20 | #define A_LARGE 80 21 | #define A_USER 0x55000000 22 | #define NOTOOBIG 32768 23 | 24 | #define POOL 0 25 | #define ALLOC 1 26 | #define FREE 2 27 | #define NREVENT 3 28 | 29 | extern unsigned long All_Mem; 30 | extern int tl_verbose; 31 | 32 | union M { 33 | long size; 34 | union M *link; 35 | }; 36 | 37 | static union M *freelist[A_LARGE]; 38 | static long req[A_LARGE]; 39 | static long event[NREVENT][A_LARGE]; 40 | 41 | void * 42 | tl_emalloc(int U) 43 | { union M *m; 44 | long r, u; 45 | void *rp; 46 | 47 | u = (long) ((U-1)/sizeof(union M) + 2); 48 | 49 | if (u >= A_LARGE) 50 | { log(ALLOC, 0, 1); 51 | if (tl_verbose) 52 | printf("tl_spin: memalloc %ld bytes\n", u); 53 | m = (union M *) emalloc((int) u*sizeof(union M)); 54 | All_Mem += (unsigned long) u*sizeof(union M); 55 | } else 56 | { if (!freelist[u]) 57 | { r = req[u] += req[u] ? req[u] : 1; 58 | if (r >= NOTOOBIG) 59 | r = req[u] = NOTOOBIG; 60 | log(POOL, u, r); 61 | freelist[u] = (union M *) 62 | emalloc((int) r*u*sizeof(union M)); 63 | All_Mem += (unsigned long) r*u*sizeof(union M); 64 | m = freelist[u] + (r-2)*u; 65 | for ( ; m >= freelist[u]; m -= u) 66 | m->link = m+u; 67 | } 68 | log(ALLOC, u, 1); 69 | m = freelist[u]; 70 | freelist[u] = m->link; 71 | } 72 | m->size = (u|A_USER); 73 | 74 | for (r = 1; r < u; ) 75 | (&m->size)[r++] = 0; 76 | 77 | rp = (void *) (m+1); 78 | memset(rp, 0, U); 79 | return rp; 80 | } 81 | 82 | void 83 | tfree(void *v) 84 | { union M *m = (union M *) v; 85 | long u; 86 | 87 | --m; 88 | if ((m->size&0xFF000000) != A_USER) 89 | Fatal("releasing a free block", (char *)0); 90 | 91 | u = (m->size &= 0xFFFFFF); 92 | if (u >= A_LARGE) 93 | { log(FREE, 0, 1); 94 | /* free(m); */ 95 | } else 96 | { log(FREE, u, 1); 97 | m->link = freelist[u]; 98 | freelist[u] = m; 99 | } 100 | } 101 | 102 | void 103 | a_stats(void) 104 | { long p, a, f; 105 | int i; 106 | 107 | printf(" size\t pool\tallocs\t frees\n"); 108 | for (i = 0; i < A_LARGE; i++) 109 | { p = event[POOL][i]; 110 | a = event[ALLOC][i]; 111 | f = event[FREE][i]; 112 | 113 | if(p|a|f) 114 | printf("%5d\t%6ld\t%6ld\t%6ld\n", 115 | i, p, a, f); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /tl.h: -------------------------------------------------------------------------------- 1 | /***** tl_spin: tl.h *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | * 8 | * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, 9 | * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. 10 | */ 11 | 12 | #include 13 | #include 14 | 15 | typedef struct Symbol { 16 | char *name; 17 | struct Symbol *next; /* linked list, symbol table */ 18 | } Symbol; 19 | 20 | typedef struct Node { 21 | short ntyp; /* node type */ 22 | struct Symbol *sym; 23 | struct Node *lft; /* tree */ 24 | struct Node *rgt; /* tree */ 25 | struct Node *nxt; /* if linked list */ 26 | } Node; 27 | 28 | typedef struct Graph { 29 | Symbol *name; 30 | Symbol *incoming; 31 | Symbol *outgoing; 32 | Symbol *oldstring; 33 | Symbol *nxtstring; 34 | Node *New; 35 | Node *Old; 36 | Node *Other; 37 | Node *Next; 38 | unsigned char isred[64], isgrn[64]; 39 | unsigned char redcnt, grncnt; 40 | unsigned char reachable; 41 | struct Graph *nxt; 42 | } Graph; 43 | 44 | typedef struct Mapping { 45 | char *from; 46 | Graph *to; 47 | struct Mapping *nxt; 48 | } Mapping; 49 | 50 | enum { 51 | ALWAYS=257, 52 | AND, /* 258 */ 53 | EQUIV, /* 259 */ 54 | EVENTUALLY, /* 260 */ 55 | FALSE, /* 261 */ 56 | IMPLIES, /* 262 */ 57 | NOT, /* 263 */ 58 | OR, /* 264 */ 59 | PREDICATE, /* 265 */ 60 | TRUE, /* 266 */ 61 | U_OPER, /* 267 */ 62 | V_OPER /* 268 */ 63 | #ifdef NXT 64 | , NEXT /* 269 */ 65 | #endif 66 | , CEXPR /* 270 */ 67 | }; 68 | 69 | Node *Canonical(Node *); 70 | Node *canonical(Node *); 71 | Node *cached(Node *); 72 | Node *dupnode(Node *); 73 | Node *getnode(Node *); 74 | Node *in_cache(Node *); 75 | Node *push_negation(Node *); 76 | Node *right_linked(Node *); 77 | Node *tl_nn(int, Node *, Node *); 78 | 79 | Symbol *tl_lookup(char *); 80 | Symbol *getsym(Symbol *); 81 | Symbol *DoDump(Node *); 82 | 83 | extern char *emalloc(size_t); /* in main.c */ 84 | 85 | extern unsigned int hash(const char *); /* in sym.c */ 86 | 87 | int anywhere(int, Node *, Node *); 88 | int dump_cond(Node *, Node *, int); 89 | int isalnum_(int); /* in spinlex.c */ 90 | int isequal(Node *, Node *); 91 | int tl_Getchar(void); 92 | 93 | void *tl_emalloc(int); 94 | void a_stats(void); 95 | void addtrans(Graph *, char *, Node *, char *); 96 | void cache_stats(void); 97 | void dump(Node *); 98 | void exit(int); 99 | void Fatal(char *, char *); 100 | void fatal(char *, char *); 101 | void fsm_print(void); 102 | void ini_buchi(void); 103 | void ini_cache(void); 104 | void ini_rewrt(void); 105 | void ini_trans(void); 106 | void releasenode(int, Node *); 107 | void tfree(void *); 108 | void tl_explain(int); 109 | void tl_UnGetchar(void); 110 | void tl_parse(void); 111 | void tl_yyerror(char *); 112 | void trans(Node *); 113 | 114 | #define ZN (Node *)0 115 | #define ZS (Symbol *)0 116 | #define Nhash 255 /* must match size in spin.h */ 117 | #define True tl_nn(TRUE, ZN, ZN) 118 | #define False tl_nn(FALSE, ZN, ZN) 119 | #define Not(a) push_negation(tl_nn(NOT, a, ZN)) 120 | #define rewrite(n) canonical(right_linked(n)) 121 | 122 | typedef Node *Nodeptr; 123 | #define YYSTYPE Nodeptr 124 | 125 | #define Debug(x) { if (tl_verbose) printf(x); } 126 | #define Debug2(x,y) { if (tl_verbose) printf(x,y); } 127 | #define Dump(x) { if (tl_verbose) dump(x); } 128 | #define Explain(x) { if (tl_verbose) tl_explain(x); } 129 | 130 | #define Assert(x, y) { if (!(x)) { tl_explain(y); \ 131 | Fatal(": assertion failed\n",(char *)0); } } 132 | -------------------------------------------------------------------------------- /tl_lex.c: -------------------------------------------------------------------------------- 1 | /***** tl_spin: tl_lex.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | * 8 | * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, 9 | * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. 10 | */ 11 | 12 | #include 13 | #include 14 | #include "tl.h" 15 | 16 | static Symbol *symtab[Nhash+1]; 17 | static int tl_lex(void); 18 | extern int tl_peek(int); 19 | 20 | extern YYSTYPE tl_yylval; 21 | extern char yytext[]; 22 | 23 | #define Token(y) tl_yylval = tl_nn(y,ZN,ZN); return y 24 | 25 | static void 26 | tl_getword(int first, int (*tst)(int)) 27 | { int i=0; int c; 28 | 29 | yytext[i++] = (char ) first; 30 | 31 | c = tl_Getchar(); 32 | while (c != -1 && tst(c)) 33 | { yytext[i++] = (char) c; 34 | c = tl_Getchar(); 35 | } 36 | 37 | /* while (tst(c = tl_Getchar())) 38 | * yytext[i++] = c; 39 | */ 40 | yytext[i] = '\0'; 41 | tl_UnGetchar(); 42 | } 43 | 44 | static int 45 | tl_follow(int tok, int ifyes, int ifno) 46 | { int c; 47 | char buf[32]; 48 | extern int tl_yychar; 49 | 50 | if ((c = tl_Getchar()) == tok) 51 | return ifyes; 52 | tl_UnGetchar(); 53 | tl_yychar = c; 54 | sprintf(buf, "expected '%c'", tok); 55 | tl_yyerror(buf); /* no return from here */ 56 | return ifno; 57 | } 58 | 59 | int 60 | tl_yylex(void) 61 | { int c = tl_lex(); 62 | #if 0 63 | printf("c = %c (%d)\n", c, c); 64 | #endif 65 | return c; 66 | } 67 | 68 | static int 69 | is_predicate(int z) 70 | { char c, c_prev = z; 71 | char want = (z == '{') ? '}' : ')'; 72 | int i = 0, j, nesting = 0; 73 | char peek_buf[512]; 74 | 75 | c = tl_peek(i++); /* look ahead without changing position */ 76 | while ((c != want || nesting > 0) && c != -1 && i < 2047) 77 | { if (islower((int) c) || c == '_') 78 | { peek_buf[0] = c; 79 | j = 1; 80 | while (j < (int) sizeof(peek_buf) 81 | && (isalnum((int)(c = tl_peek(i))) || c == '_')) 82 | { peek_buf[j++] = c; 83 | i++; 84 | } 85 | c = 0; /* make sure we don't match on z or want on the peekahead */ 86 | if (j >= (int) sizeof(peek_buf)) 87 | { peek_buf[j-1] = '\0'; 88 | fatal("name '%s' in ltl formula too long", peek_buf); 89 | } 90 | peek_buf[j] = '\0'; 91 | if (strcmp(peek_buf, "always") == 0 92 | || strcmp(peek_buf, "equivalent") == 0 93 | || strcmp(peek_buf, "eventually") == 0 94 | || strcmp(peek_buf, "until") == 0 95 | || strcmp(peek_buf, "next") == 0 96 | || strcmp(peek_buf, "c_expr") == 0) 97 | { return 0; 98 | } 99 | } else 100 | { int c_nxt = tl_peek(i); 101 | if (((c == 'U' || c == 'V' || c == 'X') 102 | && !isalnum_(c_prev) 103 | && (c_nxt == -1 || !isalnum_(c_nxt))) 104 | || (c == '<' && c_nxt == '>') 105 | || (c == '<' && c_nxt == '-') 106 | || (c == '-' && c_nxt == '>') 107 | || (c == '[' && c_nxt == ']')) 108 | { return 0; 109 | } } 110 | 111 | if (c == z) 112 | { nesting++; 113 | } 114 | if (c == want) 115 | { nesting--; 116 | } 117 | c_prev = c; 118 | c = tl_peek(i++); 119 | } 120 | return 1; 121 | } 122 | 123 | static void 124 | read_upto_closing(int z) 125 | { char c, want = (z == '{') ? '}' : ')'; 126 | int i = 0, nesting = 0; 127 | 128 | c = tl_Getchar(); 129 | while ((c != want || nesting > 0) && c != -1 && i < 2047) /* yytext is 2048 */ 130 | { yytext[i++] = c; 131 | if (c == z) 132 | { nesting++; 133 | } 134 | if (c == want) 135 | { nesting--; 136 | } 137 | c = tl_Getchar(); 138 | } 139 | yytext[i] = '\0'; 140 | } 141 | 142 | static int 143 | tl_lex(void) 144 | { int c; 145 | 146 | do { 147 | c = tl_Getchar(); 148 | yytext[0] = (char ) c; 149 | yytext[1] = '\0'; 150 | 151 | if (c <= 0) 152 | { Token(';'); 153 | } 154 | 155 | } while (c == ' '); /* '\t' is removed in tl_main.c */ 156 | 157 | if (c == '{' || c == '(') /* new 6.0.0 */ 158 | { if (is_predicate(c)) 159 | { read_upto_closing(c); 160 | tl_yylval = tl_nn(PREDICATE,ZN,ZN); 161 | if (!tl_yylval) 162 | { fatal("unexpected error 4", (char *) 0); 163 | } 164 | tl_yylval->sym = tl_lookup(yytext); 165 | return PREDICATE; 166 | } } 167 | 168 | if (c == '}') 169 | { tl_yyerror("unexpected '}'"); 170 | } 171 | if (islower(c)) 172 | { tl_getword(c, isalnum_); 173 | if (strcmp("true", yytext) == 0) 174 | { Token(TRUE); 175 | } 176 | if (strcmp("false", yytext) == 0) 177 | { Token(FALSE); 178 | } 179 | if (strcmp("always", yytext) == 0) 180 | { Token(ALWAYS); 181 | } 182 | if (strcmp("eventually", yytext) == 0) 183 | { Token(EVENTUALLY); 184 | } 185 | if (strcmp("until", yytext) == 0) 186 | { Token(U_OPER); 187 | } 188 | #ifdef NXT 189 | if (strcmp("next", yytext) == 0) 190 | { Token(NEXT); 191 | } 192 | #endif 193 | if (strcmp("c_expr", yytext) == 0) 194 | { Token(CEXPR); 195 | } 196 | if (strcmp("not", yytext) == 0) 197 | { Token(NOT); 198 | } 199 | tl_yylval = tl_nn(PREDICATE,ZN,ZN); 200 | if (!tl_yylval) 201 | { fatal("unexpected error 5", (char *) 0); 202 | } 203 | tl_yylval->sym = tl_lookup(yytext); 204 | return PREDICATE; 205 | } 206 | 207 | if (c == '<') 208 | { c = tl_Getchar(); 209 | if (c == '>') 210 | { Token(EVENTUALLY); 211 | } 212 | if (c != '-') 213 | { tl_UnGetchar(); 214 | tl_yyerror("expected '<>' or '<->'"); 215 | } 216 | c = tl_Getchar(); 217 | if (c == '>') 218 | { Token(EQUIV); 219 | } 220 | tl_UnGetchar(); 221 | tl_yyerror("expected '<->'"); 222 | } 223 | 224 | switch (c) { 225 | case '/' : c = tl_follow('\\', AND, '/'); break; 226 | case '\\': c = tl_follow('/', OR, '\\'); break; 227 | case '&' : c = tl_follow('&', AND, '&'); break; 228 | case '|' : c = tl_follow('|', OR, '|'); break; 229 | case '[' : c = tl_follow(']', ALWAYS, '['); break; 230 | case '-' : c = tl_follow('>', IMPLIES, '-'); break; 231 | case '!' : c = NOT; break; 232 | case 'U' : c = U_OPER; break; 233 | case 'V' : c = V_OPER; break; 234 | #ifdef NXT 235 | case 'X' : c = NEXT; break; 236 | #endif 237 | default : break; 238 | } 239 | Token(c); 240 | } 241 | 242 | Symbol * 243 | tl_lookup(char *s) 244 | { Symbol *sp; 245 | unsigned int h = hash(s); 246 | 247 | for (sp = symtab[h]; sp; sp = sp->next) 248 | if (strcmp(sp->name, s) == 0) 249 | return sp; 250 | 251 | sp = (Symbol *) tl_emalloc(sizeof(Symbol)); 252 | sp->name = (char *) tl_emalloc((int) strlen(s) + 1); 253 | strcpy(sp->name, s); 254 | sp->next = symtab[h]; 255 | symtab[h] = sp; 256 | 257 | return sp; 258 | } 259 | 260 | Symbol * 261 | getsym(Symbol *s) 262 | { Symbol *n = (Symbol *) tl_emalloc(sizeof(Symbol)); 263 | 264 | n->name = s->name; 265 | return n; 266 | } 267 | -------------------------------------------------------------------------------- /tl_main.c: -------------------------------------------------------------------------------- 1 | /***** tl_spin: tl_main.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | * 8 | * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, 9 | * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. 10 | */ 11 | 12 | #include "tl.h" 13 | 14 | extern FILE *tl_out; 15 | 16 | int newstates = 0; /* debugging only */ 17 | int tl_errs = 0; 18 | int tl_verbose = 0; 19 | int tl_terse = 0; 20 | int tl_clutter = 0; 21 | int state_cnt = 0; 22 | 23 | unsigned long All_Mem = 0; 24 | char *claim_name; 25 | 26 | static char uform[4096]; 27 | static int hasuform=0, cnt=0; 28 | 29 | extern void cache_stats(void); 30 | extern void a_stats(void); 31 | 32 | int 33 | tl_Getchar(void) 34 | { 35 | if (cnt < hasuform) 36 | return uform[cnt++]; 37 | cnt++; 38 | return -1; 39 | } 40 | 41 | int 42 | tl_peek(int n) 43 | { 44 | if (cnt+n < hasuform) 45 | { return uform[cnt+n]; 46 | } 47 | return -1; 48 | } 49 | 50 | void 51 | tl_balanced(void) 52 | { int i; 53 | int k = 0; 54 | 55 | for (i = 0; i < hasuform; i++) 56 | { if (uform[i] == '(') 57 | { if (i > 0 58 | && ((uform[i-1] == '"' && uform[i+1] == '"') 59 | || (uform[i-1] == '\'' && uform[i+1] == '\''))) 60 | { continue; 61 | } 62 | k++; 63 | } else if (uform[i] == ')') 64 | { if (i > 0 65 | && ((uform[i-1] == '"' && uform[i+1] == '"') 66 | || (uform[i-1] == '\'' && uform[i+1] == '\''))) 67 | { continue; 68 | } 69 | k--; 70 | } } 71 | 72 | if (k != 0) 73 | { tl_errs++; 74 | tl_yyerror("parentheses not balanced"); 75 | } 76 | } 77 | 78 | void 79 | put_uform(void) 80 | { 81 | fprintf(tl_out, "%s", uform); 82 | } 83 | 84 | void 85 | tl_UnGetchar(void) 86 | { 87 | if (cnt > 0) cnt--; 88 | } 89 | 90 | static void 91 | tl_stats(void) 92 | { extern int Stack_mx; 93 | printf("total memory used: %9ld\n", All_Mem); 94 | printf("largest stack sze: %9d\n", Stack_mx); 95 | cache_stats(); 96 | a_stats(); 97 | } 98 | 99 | int 100 | tl_main(int argc, char *argv[]) 101 | { int i; 102 | extern int xspin, s_trail; 103 | 104 | tl_verbose = 0; /* was: tl_verbose = verbose; */ 105 | if (xspin && s_trail) 106 | { tl_clutter = 1; 107 | /* generating claims for a replay should 108 | be done the same as when generating the 109 | pan.c that produced the error-trail */ 110 | } else 111 | { tl_clutter = 1-xspin; /* use -X -f to turn off uncluttering */ 112 | } 113 | newstates = 0; 114 | state_cnt = 0; 115 | tl_errs = 0; 116 | tl_terse = 0; 117 | All_Mem = 0; 118 | memset(uform, 0, sizeof(uform)); 119 | hasuform=0; 120 | cnt=0; 121 | claim_name = (char *) 0; 122 | 123 | ini_buchi(); 124 | ini_cache(); 125 | ini_rewrt(); 126 | ini_trans(); 127 | 128 | while (argc > 1 && argv[1][0] == '-') 129 | { 130 | switch (argv[1][1]) { 131 | case 'd': newstates = 1; /* debugging mode */ 132 | break; 133 | case 'f': argc--; argv++; 134 | for (i = 0; argv[1][i]; i++) 135 | { if (argv[1][i] == '\t' 136 | || argv[1][i] == '\n') 137 | argv[1][i] = ' '; 138 | } 139 | strcpy(uform, argv[1]); 140 | hasuform = (int) strlen(uform); 141 | break; 142 | case 'v': tl_verbose++; 143 | break; 144 | case 'n': tl_terse = 1; 145 | break; 146 | case 'c': argc--; argv++; 147 | claim_name = (char *) emalloc(strlen(argv[1])+1); 148 | strcpy(claim_name, argv[1]); 149 | break; 150 | default : printf("spin -f: saw '-%c'\n", argv[1][1]); 151 | goto nogood; 152 | } 153 | argc--; argv++; 154 | } 155 | if (hasuform == 0) 156 | { 157 | nogood: printf("usage:\tspin [-v] [-n] -f formula\n"); 158 | printf(" -v verbose translation\n"); 159 | printf(" -n normalize tl formula and exit\n"); 160 | exit(1); 161 | } 162 | tl_balanced(); 163 | 164 | if (tl_errs == 0) 165 | tl_parse(); 166 | 167 | if (tl_verbose) tl_stats(); 168 | return tl_errs; 169 | } 170 | 171 | #define Binop(a) \ 172 | fprintf(tl_out, "("); \ 173 | dump(n->lft); \ 174 | fprintf(tl_out, a); \ 175 | dump(n->rgt); \ 176 | fprintf(tl_out, ")") 177 | 178 | void 179 | dump(Node *n) 180 | { 181 | if (!n) return; 182 | 183 | switch(n->ntyp) { 184 | case OR: Binop(" || "); break; 185 | case AND: Binop(" && "); break; 186 | case U_OPER: Binop(" U "); break; 187 | case V_OPER: Binop(" V "); break; 188 | #ifdef NXT 189 | case NEXT: 190 | fprintf(tl_out, "X"); 191 | fprintf(tl_out, " ("); 192 | dump(n->lft); 193 | fprintf(tl_out, ")"); 194 | break; 195 | #endif 196 | case NOT: 197 | fprintf(tl_out, "!"); 198 | fprintf(tl_out, " ("); 199 | dump(n->lft); 200 | fprintf(tl_out, ")"); 201 | break; 202 | case FALSE: 203 | fprintf(tl_out, "false"); 204 | break; 205 | case TRUE: 206 | fprintf(tl_out, "true"); 207 | break; 208 | case PREDICATE: 209 | fprintf(tl_out, "(%s)", n->sym->name); 210 | break; 211 | case CEXPR: 212 | fprintf(tl_out, "c_expr"); 213 | fprintf(tl_out, " {"); 214 | dump(n->lft); 215 | fprintf(tl_out, "}"); 216 | break; 217 | case -1: 218 | fprintf(tl_out, " D "); 219 | break; 220 | default: 221 | printf("Unknown token: "); 222 | tl_explain(n->ntyp); 223 | break; 224 | } 225 | } 226 | 227 | void 228 | tl_explain(int n) 229 | { 230 | switch (n) { 231 | case ALWAYS: printf("[]"); break; 232 | case EVENTUALLY: printf("<>"); break; 233 | case IMPLIES: printf("->"); break; 234 | case EQUIV: printf("<->"); break; 235 | case PREDICATE: printf("predicate"); break; 236 | case OR: printf("||"); break; 237 | case AND: printf("&&"); break; 238 | case NOT: printf("!"); break; 239 | case U_OPER: printf("U"); break; 240 | case V_OPER: printf("V"); break; 241 | #ifdef NXT 242 | case NEXT: printf("X"); break; 243 | #endif 244 | case CEXPR: printf("c_expr"); break; 245 | case TRUE: printf("true"); break; 246 | case FALSE: printf("false"); break; 247 | case ';': printf("end of formula"); break; 248 | default: printf("%c", n); break; 249 | } 250 | } 251 | 252 | static void 253 | tl_non_fatal(char *s1, char *s2) 254 | { extern int tl_yychar; 255 | int i; 256 | 257 | printf("tl_spin: "); 258 | #if 1 259 | printf(s1, s2); /* prevent a compiler warning */ 260 | #else 261 | if (s2) 262 | printf(s1, s2); 263 | else 264 | printf(s1); 265 | #endif 266 | if (tl_yychar != -1 && tl_yychar != 0) 267 | { printf(", saw '"); 268 | tl_explain(tl_yychar); 269 | printf("'"); 270 | } 271 | printf("\ntl_spin: %s\n---------", uform); 272 | for (i = 0; i < cnt; i++) 273 | printf("-"); 274 | printf("^\n"); 275 | fflush(stdout); 276 | tl_errs++; 277 | } 278 | 279 | void 280 | tl_yyerror(char *s1) 281 | { 282 | Fatal(s1, (char *) 0); 283 | } 284 | 285 | void 286 | Fatal(char *s1, char *s2) 287 | { 288 | tl_non_fatal(s1, s2); 289 | /* tl_stats(); */ 290 | exit(1); 291 | } 292 | -------------------------------------------------------------------------------- /tl_cache.c: -------------------------------------------------------------------------------- 1 | /***** tl_spin: tl_cache.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | * 8 | * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, 9 | * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. 10 | */ 11 | 12 | #include "tl.h" 13 | 14 | typedef struct Cache { 15 | Node *before; 16 | Node *after; 17 | int same; 18 | struct Cache *nxt; 19 | } Cache; 20 | 21 | static Cache *stored = (Cache *) 0; 22 | static unsigned long Caches, CacheHits; 23 | 24 | static int ismatch(Node *, Node *); 25 | static int sameform(Node *, Node *); 26 | 27 | extern void fatal(char *, char *); 28 | 29 | void 30 | ini_cache(void) 31 | { 32 | stored = (Cache *) 0; 33 | Caches = 0; 34 | CacheHits = 0; 35 | } 36 | 37 | #if 0 38 | void 39 | cache_dump(void) 40 | { Cache *d; int nr=0; 41 | 42 | printf("\nCACHE DUMP:\n"); 43 | for (d = stored; d; d = d->nxt, nr++) 44 | { if (d->same) continue; 45 | printf("B%3d: ", nr); dump(d->before); printf("\n"); 46 | printf("A%3d: ", nr); dump(d->after); printf("\n"); 47 | } 48 | printf("============\n"); 49 | } 50 | #endif 51 | 52 | Node * 53 | in_cache(Node *n) 54 | { Cache *d; int nr=0; 55 | 56 | for (d = stored; d; d = d->nxt, nr++) 57 | if (isequal(d->before, n)) 58 | { CacheHits++; 59 | if (d->same && ismatch(n, d->before)) return n; 60 | return dupnode(d->after); 61 | } 62 | return ZN; 63 | } 64 | 65 | Node * 66 | cached(Node *n) 67 | { Cache *d; 68 | Node *m; 69 | 70 | if (!n) return n; 71 | if ((m = in_cache(n)) != ZN) 72 | return m; 73 | 74 | Caches++; 75 | d = (Cache *) tl_emalloc(sizeof(Cache)); 76 | d->before = dupnode(n); 77 | d->after = Canonical(n); /* n is released */ 78 | 79 | if (ismatch(d->before, d->after)) 80 | { d->same = 1; 81 | releasenode(1, d->after); 82 | d->after = d->before; 83 | } 84 | d->nxt = stored; 85 | stored = d; 86 | return dupnode(d->after); 87 | } 88 | 89 | void 90 | cache_stats(void) 91 | { 92 | printf("cache stores : %9ld\n", Caches); 93 | printf("cache hits : %9ld\n", CacheHits); 94 | } 95 | 96 | void 97 | releasenode(int all_levels, Node *n) 98 | { 99 | if (!n) return; 100 | 101 | if (all_levels) 102 | { releasenode(1, n->lft); 103 | n->lft = ZN; 104 | releasenode(1, n->rgt); 105 | n->rgt = ZN; 106 | } 107 | tfree((void *) n); 108 | } 109 | 110 | Node * 111 | tl_nn(int t, Node *ll, Node *rl) 112 | { Node *n = (Node *) tl_emalloc(sizeof(Node)); 113 | 114 | n->ntyp = (short) t; 115 | n->lft = ll; 116 | n->rgt = rl; 117 | 118 | return n; 119 | } 120 | 121 | Node * 122 | getnode(Node *p) 123 | { Node *n; 124 | 125 | if (!p) return p; 126 | 127 | n = (Node *) tl_emalloc(sizeof(Node)); 128 | n->ntyp = p->ntyp; 129 | n->sym = p->sym; /* same name */ 130 | n->lft = p->lft; 131 | n->rgt = p->rgt; 132 | 133 | return n; 134 | } 135 | 136 | Node * 137 | dupnode(Node *n) 138 | { Node *d; 139 | 140 | if (!n) return n; 141 | d = getnode(n); 142 | d->lft = dupnode(n->lft); 143 | d->rgt = dupnode(n->rgt); 144 | return d; 145 | } 146 | 147 | int 148 | one_lft(int ntyp, Node *x, Node *in) 149 | { 150 | if (!x) return 1; 151 | if (!in) return 0; 152 | 153 | if (sameform(x, in)) 154 | return 1; 155 | 156 | if (in->ntyp != ntyp) 157 | return 0; 158 | 159 | if (one_lft(ntyp, x, in->lft)) 160 | return 1; 161 | 162 | return one_lft(ntyp, x, in->rgt); 163 | } 164 | 165 | int 166 | all_lfts(int ntyp, Node *from, Node *in) 167 | { 168 | if (!from) return 1; 169 | 170 | if (from->ntyp != ntyp) 171 | return one_lft(ntyp, from, in); 172 | 173 | if (!one_lft(ntyp, from->lft, in)) 174 | return 0; 175 | 176 | return all_lfts(ntyp, from->rgt, in); 177 | } 178 | 179 | int 180 | sametrees(int ntyp, Node *a, Node *b) 181 | { /* toplevel is an AND or OR */ 182 | /* both trees are right-linked, but the leafs */ 183 | /* can be in different places in the two trees */ 184 | 185 | if (!all_lfts(ntyp, a, b)) 186 | return 0; 187 | 188 | return all_lfts(ntyp, b, a); 189 | } 190 | 191 | static int /* a better isequal() */ 192 | sameform(Node *a, Node *b) 193 | { 194 | if (!a && !b) return 1; 195 | if (!a || !b) return 0; 196 | if (a->ntyp != b->ntyp) return 0; 197 | 198 | if (a->sym 199 | && b->sym 200 | && strcmp(a->sym->name, b->sym->name) != 0) 201 | return 0; 202 | 203 | switch (a->ntyp) { 204 | case TRUE: 205 | case FALSE: 206 | return 1; 207 | case PREDICATE: 208 | if (!a->sym || !b->sym) fatal("sameform...", (char *) 0); 209 | return !strcmp(a->sym->name, b->sym->name); 210 | 211 | case NOT: 212 | #ifdef NXT 213 | case NEXT: 214 | #endif 215 | case CEXPR: 216 | return sameform(a->lft, b->lft); 217 | case U_OPER: 218 | case V_OPER: 219 | if (!sameform(a->lft, b->lft)) 220 | return 0; 221 | if (!sameform(a->rgt, b->rgt)) 222 | return 0; 223 | return 1; 224 | 225 | case AND: 226 | case OR: /* the hard case */ 227 | return sametrees(a->ntyp, a, b); 228 | 229 | default: 230 | printf("type: %d\n", a->ntyp); 231 | fatal("cannot happen, sameform", (char *) 0); 232 | } 233 | 234 | return 0; 235 | } 236 | 237 | int 238 | isequal(Node *a, Node *b) 239 | { 240 | if (!a && !b) 241 | return 1; 242 | 243 | if (!a || !b) 244 | { if (!a) 245 | { if (b->ntyp == TRUE) 246 | return 1; 247 | } else 248 | { if (a->ntyp == TRUE) 249 | return 1; 250 | } 251 | return 0; 252 | } 253 | if (a->ntyp != b->ntyp) 254 | return 0; 255 | 256 | if (a->sym 257 | && b->sym 258 | && strcmp(a->sym->name, b->sym->name) != 0) 259 | return 0; 260 | 261 | if (isequal(a->lft, b->lft) 262 | && isequal(a->rgt, b->rgt)) 263 | return 1; 264 | 265 | return sameform(a, b); 266 | } 267 | 268 | static int 269 | ismatch(Node *a, Node *b) 270 | { 271 | if (!a && !b) return 1; 272 | if (!a || !b) return 0; 273 | if (a->ntyp != b->ntyp) return 0; 274 | 275 | if (a->sym 276 | && b->sym 277 | && strcmp(a->sym->name, b->sym->name) != 0) 278 | return 0; 279 | 280 | if (ismatch(a->lft, b->lft) 281 | && ismatch(a->rgt, b->rgt)) 282 | return 1; 283 | 284 | return 0; 285 | } 286 | 287 | int 288 | any_term(Node *srch, Node *in) 289 | { 290 | if (!in) return 0; 291 | 292 | if (in->ntyp == AND) 293 | return any_term(srch, in->lft) || 294 | any_term(srch, in->rgt); 295 | 296 | return isequal(in, srch); 297 | } 298 | 299 | int 300 | any_and(Node *srch, Node *in) 301 | { 302 | if (!in) return 0; 303 | 304 | if (srch->ntyp == AND) 305 | return any_and(srch->lft, in) && 306 | any_and(srch->rgt, in); 307 | 308 | return any_term(srch, in); 309 | } 310 | 311 | int 312 | any_lor(Node *srch, Node *in) 313 | { 314 | if (!in) return 0; 315 | 316 | if (in->ntyp == OR) 317 | return any_lor(srch, in->lft) || 318 | any_lor(srch, in->rgt); 319 | 320 | return isequal(in, srch); 321 | } 322 | 323 | int 324 | anywhere(int tok, Node *srch, Node *in) 325 | { 326 | if (!in) return 0; 327 | 328 | switch (tok) { 329 | case AND: return any_and(srch, in); 330 | case OR: return any_lor(srch, in); 331 | case 0: return any_term(srch, in); 332 | } 333 | fatal("cannot happen, anywhere", (char *) 0); 334 | return 0; 335 | } 336 | -------------------------------------------------------------------------------- /tl_rewrt.c: -------------------------------------------------------------------------------- 1 | /***** tl_spin: tl_rewrt.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | * 8 | * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, 9 | * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. 10 | */ 11 | 12 | #include "tl.h" 13 | 14 | extern int tl_verbose; 15 | 16 | static Node *can = ZN; 17 | 18 | void 19 | ini_rewrt(void) 20 | { 21 | can = ZN; 22 | } 23 | 24 | Node * 25 | right_linked(Node *n) 26 | { 27 | if (!n) return n; 28 | 29 | if (n->ntyp == AND || n->ntyp == OR) 30 | while (n->lft && n->lft->ntyp == n->ntyp) 31 | { Node *tmp = n->lft; 32 | n->lft = tmp->rgt; 33 | tmp->rgt = n; 34 | n = tmp; 35 | } 36 | 37 | n->lft = right_linked(n->lft); 38 | n->rgt = right_linked(n->rgt); 39 | 40 | return n; 41 | } 42 | 43 | Node * 44 | canonical(Node *n) 45 | { Node *m; /* assumes input is right_linked */ 46 | 47 | if (!n) return n; 48 | if ((m = in_cache(n)) != ZN) 49 | return m; 50 | 51 | n->rgt = canonical(n->rgt); 52 | n->lft = canonical(n->lft); 53 | 54 | return cached(n); 55 | } 56 | 57 | Node * 58 | push_negation(Node *n) 59 | { Node *m; 60 | 61 | Assert(n->ntyp == NOT, n->ntyp); 62 | 63 | switch (n->lft->ntyp) { 64 | case TRUE: 65 | Debug("!true => false\n"); 66 | releasenode(0, n->lft); 67 | n->lft = ZN; 68 | n->ntyp = FALSE; 69 | break; 70 | case FALSE: 71 | Debug("!false => true\n"); 72 | releasenode(0, n->lft); 73 | n->lft = ZN; 74 | n->ntyp = TRUE; 75 | break; 76 | case NOT: 77 | Debug("!!p => p\n"); 78 | m = n->lft->lft; 79 | releasenode(0, n->lft); 80 | n->lft = ZN; 81 | releasenode(0, n); 82 | n = m; 83 | break; 84 | case V_OPER: 85 | Debug("!(p V q) => (!p U !q)\n"); 86 | n->ntyp = U_OPER; 87 | goto same; 88 | case U_OPER: 89 | Debug("!(p U q) => (!p V !q)\n"); 90 | n->ntyp = V_OPER; 91 | goto same; 92 | #ifdef NXT 93 | case NEXT: 94 | Debug("!X -> X!\n"); 95 | n->ntyp = NEXT; 96 | n->lft->ntyp = NOT; 97 | n->lft = push_negation(n->lft); 98 | break; 99 | #endif 100 | case AND: 101 | Debug("!(p && q) => !p || !q\n"); 102 | n->ntyp = OR; 103 | goto same; 104 | case OR: 105 | Debug("!(p || q) => !p && !q\n"); 106 | n->ntyp = AND; 107 | 108 | same: m = n->lft->rgt; 109 | n->lft->rgt = ZN; 110 | 111 | n->rgt = Not(m); 112 | n->lft->ntyp = NOT; 113 | m = n->lft; 114 | n->lft = push_negation(m); 115 | break; 116 | } 117 | 118 | return rewrite(n); 119 | } 120 | 121 | static void 122 | addcan(int tok, Node *n) 123 | { Node *m, *prev = ZN; 124 | Node **ptr; 125 | Node *N; 126 | Symbol *s, *t; int cmp; 127 | 128 | if (!n) return; 129 | 130 | if (n->ntyp == tok) 131 | { addcan(tok, n->rgt); 132 | addcan(tok, n->lft); 133 | return; 134 | } 135 | 136 | N = dupnode(n); 137 | if (!can) 138 | { can = N; 139 | return; 140 | } 141 | 142 | s = DoDump(N); 143 | if (!s) 144 | { fatal("unexpected error 6", (char *) 0); 145 | } 146 | if (can->ntyp != tok) /* only one element in list so far */ 147 | { ptr = &can; 148 | goto insert; 149 | } 150 | 151 | /* there are at least 2 elements in list */ 152 | prev = ZN; 153 | for (m = can; m->ntyp == tok && m->rgt; prev = m, m = m->rgt) 154 | { t = DoDump(m->lft); 155 | if (t != ZS) 156 | cmp = strcmp(s->name, t->name); 157 | else 158 | cmp = 0; 159 | if (cmp == 0) /* duplicate */ 160 | return; 161 | if (cmp < 0) 162 | { if (!prev) 163 | { can = tl_nn(tok, N, can); 164 | return; 165 | } else 166 | { ptr = &(prev->rgt); 167 | goto insert; 168 | } } } 169 | 170 | /* new entry goes at the end of the list */ 171 | ptr = &(prev->rgt); 172 | insert: 173 | t = DoDump(*ptr); 174 | cmp = strcmp(s->name, t->name); 175 | if (cmp == 0) /* duplicate */ 176 | return; 177 | if (cmp < 0) 178 | *ptr = tl_nn(tok, N, *ptr); 179 | else 180 | *ptr = tl_nn(tok, *ptr, N); 181 | } 182 | 183 | static void 184 | marknode(int tok, Node *m) 185 | { 186 | if (m->ntyp != tok) 187 | { releasenode(0, m->rgt); 188 | m->rgt = ZN; 189 | } 190 | m->ntyp = -1; 191 | } 192 | 193 | Node * 194 | Canonical(Node *n) 195 | { Node *m, *p, *k1, *k2, *prev, *dflt = ZN; 196 | int tok; 197 | 198 | if (!n) return n; 199 | 200 | tok = n->ntyp; 201 | if (tok != AND && tok != OR) 202 | return n; 203 | 204 | can = ZN; 205 | addcan(tok, n); 206 | #if 0 207 | Debug("\nA0: "); Dump(can); 208 | Debug("\nA1: "); Dump(n); Debug("\n"); 209 | #endif 210 | releasenode(1, n); 211 | 212 | /* mark redundant nodes */ 213 | if (tok == AND) 214 | { for (m = can; m; m = (m->ntyp == AND) ? m->rgt : ZN) 215 | { k1 = (m->ntyp == AND) ? m->lft : m; 216 | if (k1->ntyp == TRUE) 217 | { marknode(AND, m); 218 | dflt = True; 219 | continue; 220 | } 221 | if (k1->ntyp == FALSE) 222 | { releasenode(1, can); 223 | can = False; 224 | goto out; 225 | } } 226 | for (m = can; m; m = (m->ntyp == AND) ? m->rgt : ZN) 227 | for (p = can; p; p = (p->ntyp == AND) ? p->rgt : ZN) 228 | { if (p == m 229 | || p->ntyp == -1 230 | || m->ntyp == -1) 231 | continue; 232 | k1 = (m->ntyp == AND) ? m->lft : m; 233 | k2 = (p->ntyp == AND) ? p->lft : p; 234 | 235 | if (isequal(k1, k2)) 236 | { marknode(AND, p); 237 | continue; 238 | } 239 | if (anywhere(OR, k1, k2)) 240 | { marknode(AND, p); 241 | continue; 242 | } 243 | } } 244 | if (tok == OR) 245 | { for (m = can; m; m = (m->ntyp == OR) ? m->rgt : ZN) 246 | { k1 = (m->ntyp == OR) ? m->lft : m; 247 | if (k1->ntyp == FALSE) 248 | { marknode(OR, m); 249 | dflt = False; 250 | continue; 251 | } 252 | if (k1->ntyp == TRUE) 253 | { releasenode(1, can); 254 | can = True; 255 | goto out; 256 | } } 257 | for (m = can; m; m = (m->ntyp == OR) ? m->rgt : ZN) 258 | for (p = can; p; p = (p->ntyp == OR) ? p->rgt : ZN) 259 | { if (p == m 260 | || p->ntyp == -1 261 | || m->ntyp == -1) 262 | continue; 263 | k1 = (m->ntyp == OR) ? m->lft : m; 264 | k2 = (p->ntyp == OR) ? p->lft : p; 265 | 266 | if (isequal(k1, k2)) 267 | { marknode(OR, p); 268 | continue; 269 | } 270 | if (anywhere(AND, k1, k2)) 271 | { marknode(OR, p); 272 | continue; 273 | } 274 | } } 275 | for (m = can, prev = ZN; m; ) /* remove marked nodes */ 276 | { if (m->ntyp == -1) 277 | { k2 = m->rgt; 278 | releasenode(0, m); 279 | if (!prev) 280 | { m = can = can->rgt; 281 | } else 282 | { m = prev->rgt = k2; 283 | /* if deleted the last node in a chain */ 284 | if (!prev->rgt && prev->lft 285 | && (prev->ntyp == AND || prev->ntyp == OR)) 286 | { k1 = prev->lft; 287 | prev->ntyp = prev->lft->ntyp; 288 | prev->sym = prev->lft->sym; 289 | prev->rgt = prev->lft->rgt; 290 | prev->lft = prev->lft->lft; 291 | releasenode(0, k1); 292 | } 293 | } 294 | continue; 295 | } 296 | prev = m; 297 | m = m->rgt; 298 | } 299 | out: 300 | #if 0 301 | Debug("A2: "); Dump(can); Debug("\n"); 302 | #endif 303 | if (!can) 304 | { if (!dflt) 305 | fatal("cannot happen, Canonical", (char *) 0); 306 | return dflt; 307 | } 308 | 309 | return can; 310 | } 311 | -------------------------------------------------------------------------------- /pangen4.c: -------------------------------------------------------------------------------- 1 | /***** spin: pangen4.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | */ 8 | 9 | #include "spin.h" 10 | #include "y.tab.h" 11 | 12 | extern FILE *tc, *tb; 13 | extern Queue *qtab; 14 | extern Symbol *Fname; 15 | extern int lineno, m_loss, Pid, eventmapnr, multi_oval; 16 | extern short nocast, has_provided, has_sorted; 17 | extern const char *R13[], *R14[], *R15[]; 18 | 19 | static void check_proc(Lextok *, int); 20 | 21 | void 22 | undostmnt(Lextok *now, int m) 23 | { Lextok *v; 24 | int i, j; 25 | 26 | if (!now) 27 | { fprintf(tb, "0"); 28 | return; 29 | } 30 | lineno = now->ln; 31 | Fname = now->fn; 32 | switch (now->ntyp) { 33 | case CONST: case '!': case UMIN: 34 | case '~': case '/': case '*': 35 | case '-': case '+': case '%': 36 | case LT: case GT: case '&': 37 | case '|': case LE: case GE: 38 | case NE: case EQ: case OR: 39 | case AND: case LSHIFT: case RSHIFT: 40 | case TIMEOUT: case LEN: case NAME: 41 | case FULL: case EMPTY: case 'R': 42 | case NFULL: case NEMPTY: case ENABLED: 43 | case '?': case PC_VAL: case '^': 44 | case C_EXPR: case GET_P: 45 | case NONPROGRESS: 46 | putstmnt(tb, now, m); 47 | break; 48 | 49 | case RUN: 50 | fprintf(tb, "delproc(0, now._nr_pr-1)"); 51 | break; 52 | 53 | case 's': 54 | if (Pid == eventmapnr) break; 55 | 56 | if (m_loss) 57 | fprintf(tb, "if (_m == 2) "); 58 | putname(tb, "_m = unsend(", now->lft, m, ")"); 59 | break; 60 | 61 | case 'r': 62 | if (Pid == eventmapnr) break; 63 | 64 | for (v = now->rgt, i=j=0; v; v = v->rgt, i++) 65 | if (v->lft->ntyp != CONST 66 | && v->lft->ntyp != EVAL) 67 | j++; 68 | if (j == 0 && now->val >= 2) 69 | break; /* poll without side-effect */ 70 | 71 | { int ii = 0, jj; 72 | 73 | for (v = now->rgt; v; v = v->rgt) 74 | if ((v->lft->ntyp != CONST 75 | && v->lft->ntyp != EVAL)) 76 | ii++; /* nr of things bupped */ 77 | if (now->val == 1) 78 | { ii++; 79 | jj = multi_oval - ii - 1; 80 | fprintf(tb, "XX = trpt->bup.oval"); 81 | if (multi_oval > 0) 82 | { fprintf(tb, "s[%d]", jj); 83 | jj++; 84 | } 85 | fprintf(tb, ";\n\t\t"); 86 | } else 87 | { fprintf(tb, "XX = 1;\n\t\t"); 88 | jj = multi_oval - ii - 1; 89 | } 90 | 91 | if (now->val < 2) /* not for channel poll */ 92 | for (v = now->rgt, i = 0; v; v = v->rgt, i++) 93 | { switch(v->lft->ntyp) { 94 | case CONST: 95 | case EVAL: 96 | fprintf(tb, "unrecv"); 97 | putname(tb, "(", now->lft, m, ", XX-1, "); 98 | fprintf(tb, "%d, ", i); 99 | if (v->lft->ntyp == EVAL) 100 | undostmnt(v->lft->lft, m); 101 | else 102 | undostmnt(v->lft, m); 103 | fprintf(tb, ", %d);\n\t\t", (i==0)?1:0); 104 | break; 105 | default: 106 | fprintf(tb, "unrecv"); 107 | putname(tb, "(", now->lft, m, ", XX-1, "); 108 | fprintf(tb, "%d, ", i); 109 | if (v->lft->sym 110 | && !strcmp(v->lft->sym->name, "_")) 111 | { fprintf(tb, "trpt->bup.oval"); 112 | if (multi_oval > 0) 113 | fprintf(tb, "s[%d]", jj); 114 | } else 115 | putstmnt(tb, v->lft, m); 116 | 117 | fprintf(tb, ", %d);\n\t\t", (i==0)?1:0); 118 | if (multi_oval > 0) 119 | jj++; 120 | break; 121 | } } 122 | jj = multi_oval - ii - 1; 123 | 124 | if (now->val == 1 && multi_oval > 0) 125 | jj++; /* new 3.4.0 */ 126 | 127 | for (v = now->rgt, i = 0; v; v = v->rgt, i++) 128 | { switch(v->lft->ntyp) { 129 | case CONST: 130 | case EVAL: 131 | break; 132 | default: 133 | if (!v->lft->sym 134 | || strcmp(v->lft->sym->name, "_") != 0) 135 | { nocast=1; putstmnt(tb,v->lft,m); 136 | nocast=0; fprintf(tb, " = trpt->bup.oval"); 137 | if (multi_oval > 0) 138 | fprintf(tb, "s[%d]", jj); 139 | fprintf(tb, ";\n\t\t"); 140 | } 141 | if (multi_oval > 0) 142 | jj++; 143 | break; 144 | } } 145 | multi_oval -= ii; 146 | } 147 | break; 148 | 149 | case '@': 150 | fprintf(tb, "p_restor(II);\n\t\t"); 151 | break; 152 | 153 | case SET_P: 154 | fprintf(tb, "((P0 *)pptr((trpt->o_priority >> 8)))"); 155 | fprintf(tb, "->_priority = trpt->o_priority & 255"); 156 | break; 157 | 158 | case ASGN: 159 | if (check_track(now) == STRUCT) { break; } 160 | 161 | nocast=1; putstmnt(tb,now->lft,m); 162 | nocast=0; fprintf(tb, " = trpt->bup.oval"); 163 | if (multi_oval > 0) 164 | { multi_oval--; 165 | fprintf(tb, "s[%d]", multi_oval-1); 166 | } 167 | check_proc(now->rgt, m); 168 | break; 169 | 170 | case 'c': 171 | check_proc(now->lft, m); 172 | break; 173 | 174 | case '.': 175 | case GOTO: 176 | case ELSE: 177 | case BREAK: 178 | break; 179 | 180 | case C_CODE: 181 | fprintf(tb, "sv_restor();\n"); 182 | break; 183 | 184 | case ASSERT: 185 | case PRINT: 186 | check_proc(now, m); 187 | break; 188 | case PRINTM: 189 | break; 190 | 191 | default: 192 | printf("spin: bad node type %d (.b)\n", now->ntyp); 193 | alldone(1); 194 | } 195 | } 196 | 197 | int 198 | any_undo(Lextok *now) 199 | { /* is there anything to undo on a return move? */ 200 | if (!now) return 1; 201 | switch (now->ntyp) { 202 | case 'c': return any_oper(now->lft, RUN); 203 | case ASSERT: 204 | case PRINT: return any_oper(now, RUN); 205 | 206 | case PRINTM: 207 | case '.': 208 | case GOTO: 209 | case ELSE: 210 | case BREAK: return 0; 211 | default: return 1; 212 | } 213 | } 214 | 215 | int 216 | any_oper(Lextok *now, int oper) 217 | { /* check if an expression contains oper operator */ 218 | if (!now) return 0; 219 | if (now->ntyp == oper) 220 | return 1; 221 | return (any_oper(now->lft, oper) || any_oper(now->rgt, oper)); 222 | } 223 | 224 | static void 225 | check_proc(Lextok *now, int m) 226 | { 227 | if (!now) 228 | return; 229 | if (now->ntyp == '@' || now->ntyp == RUN) 230 | { fprintf(tb, ";\n\t\t"); 231 | undostmnt(now, m); 232 | } 233 | check_proc(now->lft, m); 234 | check_proc(now->rgt, m); 235 | } 236 | 237 | void 238 | genunio(void) 239 | { char buf1[256]; 240 | Queue *q; int i; 241 | 242 | ntimes(tc, 0, 1, R13); 243 | for (q = qtab; q; q = q->nxt) 244 | { fprintf(tc, "\tcase %d:\n", q->qid); 245 | 246 | if (has_sorted) 247 | { sprintf(buf1, "((Q%d *)z)->contents", q->qid); 248 | fprintf(tc, "#ifdef HAS_SORTED\n"); 249 | fprintf(tc, "\t\tj = trpt->ipt;\n"); /* ipt was bup.oval */ 250 | fprintf(tc, "#endif\n"); 251 | fprintf(tc, "\t\tfor (k = j; k < ((Q%d *)z)->Qlen; k++)\n", 252 | q->qid); 253 | fprintf(tc, "\t\t{\n"); 254 | for (i = 0; i < q->nflds; i++) 255 | fprintf(tc, "\t\t\t%s[k].fld%d = %s[k+1].fld%d;\n", 256 | buf1, i, buf1, i); 257 | fprintf(tc, "\t\t}\n"); 258 | fprintf(tc, "\t\tj = ((Q0 *)z)->Qlen;\n"); 259 | } 260 | 261 | sprintf(buf1, "((Q%d *)z)->contents[j].fld", q->qid); 262 | for (i = 0; i < q->nflds; i++) 263 | fprintf(tc, "\t\t%s%d = 0;\n", buf1, i); 264 | if (q->nslots==0) 265 | { /* check if rendezvous succeeded, 1 level down */ 266 | fprintf(tc, "\t\t_m = (trpt+1)->o_m;\n"); 267 | fprintf(tc, "\t\tif (_m) (trpt-1)->o_pm |= 1;\n"); 268 | fprintf(tc, "\t\tUnBlock;\n"); 269 | } else 270 | fprintf(tc, "\t\t_m = trpt->o_m;\n"); 271 | 272 | fprintf(tc, "\t\tbreak;\n"); 273 | } 274 | ntimes(tc, 0, 1, R14); 275 | for (q = qtab; q; q = q->nxt) 276 | { sprintf(buf1, "((Q%d *)z)->contents", q->qid); 277 | fprintf(tc, " case %d:\n", q->qid); 278 | if (q->nslots == 0) 279 | fprintf(tc, "\t\tif (strt) boq = from+1;\n"); 280 | else if (q->nslots > 1) /* shift */ 281 | { fprintf(tc, "\t\tif (strt && slot<%d)\n", 282 | q->nslots-1); 283 | fprintf(tc, "\t\t{\tfor (j--; j>=slot; j--)\n"); 284 | fprintf(tc, "\t\t\t{"); 285 | for (i = 0; i < q->nflds; i++) 286 | { fprintf(tc, "\t%s[j+1].fld%d =\n\t\t\t", 287 | buf1, i); 288 | fprintf(tc, "\t%s[j].fld%d;\n\t\t\t", 289 | buf1, i); 290 | } 291 | fprintf(tc, "}\n\t\t}\n"); 292 | } 293 | strcat(buf1, "[slot].fld"); 294 | fprintf(tc, "\t\tif (strt) {\n"); 295 | for (i = 0; i < q->nflds; i++) 296 | fprintf(tc, "\t\t\t%s%d = 0;\n", buf1, i); 297 | fprintf(tc, "\t\t}\n"); 298 | if (q->nflds == 1) /* set */ 299 | fprintf(tc, "\t\tif (fld == 0) %s0 = fldvar;\n", 300 | buf1); 301 | else 302 | { fprintf(tc, "\t\tswitch (fld) {\n"); 303 | for (i = 0; i < q->nflds; i++) 304 | { fprintf(tc, "\t\tcase %d:\t%s", i, buf1); 305 | fprintf(tc, "%d = fldvar; break;\n", i); 306 | } 307 | fprintf(tc, "\t\t}\n"); 308 | } 309 | fprintf(tc, "\t\tbreak;\n"); 310 | } 311 | ntimes(tc, 0, 1, R15); 312 | } 313 | 314 | extern void explain(int); 315 | 316 | int 317 | proper_enabler(Lextok *n) 318 | { 319 | if (!n) return 1; 320 | switch (n->ntyp) { 321 | case NEMPTY: case FULL: 322 | case NFULL: case EMPTY: 323 | case LEN: case 'R': 324 | case NAME: 325 | has_provided = 1; 326 | if (strcmp(n->sym->name, "_pid") == 0 327 | || strcmp(n->sym->name, "_priority") == 0) 328 | return 1; 329 | return (!(n->sym->context)); 330 | 331 | case C_EXPR: 332 | case CONST: 333 | case TIMEOUT: 334 | has_provided = 1; 335 | return 1; 336 | 337 | case ENABLED: case PC_VAL: 338 | case GET_P: /* not SET_P */ 339 | return proper_enabler(n->lft); 340 | 341 | case '!': case UMIN: case '~': 342 | return proper_enabler(n->lft); 343 | 344 | case '/': case '*': case '-': case '+': 345 | case '%': case LT: case GT: case '&': case '^': 346 | case '|': case LE: case GE: case NE: case '?': 347 | case EQ: case OR: case AND: case LSHIFT: 348 | case RSHIFT: case 'c': /* case ',': */ 349 | return proper_enabler(n->lft) && proper_enabler(n->rgt); 350 | 351 | default: 352 | break; 353 | } 354 | printf("spin: saw "); 355 | explain(n->ntyp); 356 | printf("\n"); 357 | return 0; 358 | } 359 | -------------------------------------------------------------------------------- /tl_parse.c: -------------------------------------------------------------------------------- 1 | /***** tl_spin: tl_parse.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | * 8 | * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, 9 | * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. 10 | */ 11 | 12 | #include "tl.h" 13 | 14 | extern int tl_yylex(void); 15 | extern int tl_verbose, tl_errs; 16 | 17 | int tl_yychar = 0; 18 | YYSTYPE tl_yylval; 19 | 20 | static Node *tl_formula(void); 21 | static Node *tl_factor(void); 22 | static Node *tl_level(int); 23 | 24 | static int prec[2][4] = { 25 | { U_OPER, V_OPER, 0, 0 }, /* left associative */ 26 | { OR, AND, IMPLIES, EQUIV, }, /* left associative */ 27 | }; 28 | 29 | static Node * 30 | tl_factor(void) 31 | { Node *ptr = ZN; 32 | 33 | switch (tl_yychar) { 34 | case '(': 35 | ptr = tl_formula(); 36 | if (tl_yychar != ')') 37 | tl_yyerror("expected ')'"); 38 | tl_yychar = tl_yylex(); 39 | break; 40 | case NOT: 41 | ptr = tl_yylval; 42 | tl_yychar = tl_yylex(); 43 | ptr->lft = tl_factor(); 44 | if (!ptr->lft) 45 | { fatal("malformed expression", (char *) 0); 46 | } 47 | ptr = push_negation(ptr); 48 | break; 49 | case ALWAYS: 50 | tl_yychar = tl_yylex(); 51 | ptr = tl_factor(); 52 | #ifndef NO_OPT 53 | if (ptr->ntyp == FALSE 54 | || ptr->ntyp == TRUE) 55 | break; /* [] false == false */ 56 | 57 | if (ptr->ntyp == V_OPER) 58 | { if (ptr->lft->ntyp == FALSE) 59 | break; /* [][]p = []p */ 60 | 61 | ptr = ptr->rgt; /* [] (p V q) = [] q */ 62 | } 63 | #endif 64 | ptr = tl_nn(V_OPER, False, ptr); 65 | break; 66 | #ifdef NXT 67 | case NEXT: 68 | tl_yychar = tl_yylex(); 69 | ptr = tl_factor(); 70 | if (ptr->ntyp == TRUE) 71 | break; /* X true = true */ 72 | ptr = tl_nn(NEXT, ptr, ZN); 73 | break; 74 | #endif 75 | case CEXPR: 76 | tl_yychar = tl_yylex(); 77 | ptr = tl_factor(); 78 | if (ptr->ntyp != PREDICATE) 79 | { tl_yyerror("expected {...} after c_expr"); 80 | } 81 | ptr = tl_nn(CEXPR, ptr, ZN); 82 | break; 83 | case EVENTUALLY: 84 | tl_yychar = tl_yylex(); 85 | 86 | ptr = tl_factor(); 87 | #ifndef NO_OPT 88 | if (ptr->ntyp == TRUE 89 | || ptr->ntyp == FALSE) 90 | break; /* <> true == true */ 91 | 92 | if (ptr->ntyp == U_OPER 93 | && ptr->lft->ntyp == TRUE) 94 | break; /* <><>p = <>p */ 95 | 96 | if (ptr->ntyp == U_OPER) 97 | { /* <> (p U q) = <> q */ 98 | ptr = ptr->rgt; 99 | /* fall thru */ 100 | } 101 | #endif 102 | ptr = tl_nn(U_OPER, True, ptr); 103 | 104 | break; 105 | case PREDICATE: 106 | ptr = tl_yylval; 107 | tl_yychar = tl_yylex(); 108 | break; 109 | case TRUE: 110 | case FALSE: 111 | ptr = tl_yylval; 112 | tl_yychar = tl_yylex(); 113 | break; 114 | } 115 | if (!ptr) tl_yyerror("expected predicate"); 116 | #if 0 117 | printf("factor: "); 118 | tl_explain(ptr->ntyp); 119 | printf("\n"); 120 | #endif 121 | return ptr; 122 | } 123 | 124 | static Node * 125 | bin_simpler(Node *ptr) 126 | { Node *a, *b; 127 | 128 | if (ptr) 129 | switch (ptr->ntyp) { 130 | case U_OPER: 131 | #ifndef NO_OPT 132 | if (ptr->rgt->ntyp == TRUE 133 | || ptr->rgt->ntyp == FALSE 134 | || ptr->lft->ntyp == FALSE) 135 | { ptr = ptr->rgt; 136 | break; 137 | } 138 | if (isequal(ptr->lft, ptr->rgt)) 139 | { /* p U p = p */ 140 | ptr = ptr->rgt; 141 | break; 142 | } 143 | if (ptr->lft->ntyp == U_OPER 144 | && isequal(ptr->lft->lft, ptr->rgt)) 145 | { /* (p U q) U p = (q U p) */ 146 | ptr->lft = ptr->lft->rgt; 147 | break; 148 | } 149 | if (ptr->rgt->ntyp == U_OPER 150 | && ptr->rgt->lft->ntyp == TRUE) 151 | { /* p U (T U q) = (T U q) */ 152 | ptr = ptr->rgt; 153 | break; 154 | } 155 | #ifdef NXT 156 | /* X p U X q == X (p U q) */ 157 | if (ptr->rgt->ntyp == NEXT 158 | && ptr->lft->ntyp == NEXT) 159 | { ptr = tl_nn(NEXT, 160 | tl_nn(U_OPER, 161 | ptr->lft->lft, 162 | ptr->rgt->lft), ZN); 163 | } 164 | #endif 165 | #endif 166 | break; 167 | case V_OPER: 168 | #ifndef NO_OPT 169 | if (ptr->rgt->ntyp == FALSE 170 | || ptr->rgt->ntyp == TRUE 171 | || ptr->lft->ntyp == TRUE) 172 | { ptr = ptr->rgt; 173 | break; 174 | } 175 | if (isequal(ptr->lft, ptr->rgt)) 176 | { /* p V p = p */ 177 | ptr = ptr->rgt; 178 | break; 179 | } 180 | /* F V (p V q) == F V q */ 181 | if (ptr->lft->ntyp == FALSE 182 | && ptr->rgt->ntyp == V_OPER) 183 | { ptr->rgt = ptr->rgt->rgt; 184 | break; 185 | } 186 | /* p V (F V q) == F V q */ 187 | if (ptr->rgt->ntyp == V_OPER 188 | && ptr->rgt->lft->ntyp == FALSE) 189 | { ptr->lft = False; 190 | ptr->rgt = ptr->rgt->rgt; 191 | break; 192 | } 193 | #endif 194 | break; 195 | case IMPLIES: 196 | #ifndef NO_OPT 197 | if (isequal(ptr->lft, ptr->rgt)) 198 | { ptr = True; 199 | break; 200 | } 201 | #endif 202 | ptr = tl_nn(OR, Not(ptr->lft), ptr->rgt); 203 | ptr = rewrite(ptr); 204 | break; 205 | case EQUIV: 206 | #ifndef NO_OPT 207 | if (isequal(ptr->lft, ptr->rgt)) 208 | { ptr = True; 209 | break; 210 | } 211 | #endif 212 | a = rewrite(tl_nn(AND, 213 | dupnode(ptr->lft), 214 | dupnode(ptr->rgt))); 215 | b = rewrite(tl_nn(AND, 216 | Not(ptr->lft), 217 | Not(ptr->rgt))); 218 | ptr = tl_nn(OR, a, b); 219 | ptr = rewrite(ptr); 220 | break; 221 | case AND: 222 | #ifndef NO_OPT 223 | /* p && (q U p) = p */ 224 | if (ptr->rgt->ntyp == U_OPER 225 | && isequal(ptr->rgt->rgt, ptr->lft)) 226 | { ptr = ptr->lft; 227 | break; 228 | } 229 | if (ptr->lft->ntyp == U_OPER 230 | && isequal(ptr->lft->rgt, ptr->rgt)) 231 | { ptr = ptr->rgt; 232 | break; 233 | } 234 | 235 | /* p && (q V p) == q V p */ 236 | if (ptr->rgt->ntyp == V_OPER 237 | && isequal(ptr->rgt->rgt, ptr->lft)) 238 | { ptr = ptr->rgt; 239 | break; 240 | } 241 | if (ptr->lft->ntyp == V_OPER 242 | && isequal(ptr->lft->rgt, ptr->rgt)) 243 | { ptr = ptr->lft; 244 | break; 245 | } 246 | 247 | /* (p U q) && (r U q) = (p && r) U q*/ 248 | if (ptr->rgt->ntyp == U_OPER 249 | && ptr->lft->ntyp == U_OPER 250 | && isequal(ptr->rgt->rgt, ptr->lft->rgt)) 251 | { ptr = tl_nn(U_OPER, 252 | tl_nn(AND, ptr->lft->lft, ptr->rgt->lft), 253 | ptr->lft->rgt); 254 | break; 255 | } 256 | 257 | /* (p V q) && (p V r) = p V (q && r) */ 258 | if (ptr->rgt->ntyp == V_OPER 259 | && ptr->lft->ntyp == V_OPER 260 | && isequal(ptr->rgt->lft, ptr->lft->lft)) 261 | { ptr = tl_nn(V_OPER, 262 | ptr->rgt->lft, 263 | tl_nn(AND, ptr->lft->rgt, ptr->rgt->rgt)); 264 | break; 265 | } 266 | #ifdef NXT 267 | /* X p && X q == X (p && q) */ 268 | if (ptr->rgt->ntyp == NEXT 269 | && ptr->lft->ntyp == NEXT) 270 | { ptr = tl_nn(NEXT, 271 | tl_nn(AND, 272 | ptr->rgt->lft, 273 | ptr->lft->lft), ZN); 274 | break; 275 | } 276 | #endif 277 | 278 | if (isequal(ptr->lft, ptr->rgt) /* (p && p) == p */ 279 | || ptr->rgt->ntyp == FALSE /* (p && F) == F */ 280 | || ptr->lft->ntyp == TRUE) /* (T && p) == p */ 281 | { ptr = ptr->rgt; 282 | break; 283 | } 284 | if (ptr->rgt->ntyp == TRUE /* (p && T) == p */ 285 | || ptr->lft->ntyp == FALSE) /* (F && p) == F */ 286 | { ptr = ptr->lft; 287 | break; 288 | } 289 | 290 | /* (p V q) && (r U q) == p V q */ 291 | if (ptr->rgt->ntyp == U_OPER 292 | && ptr->lft->ntyp == V_OPER 293 | && isequal(ptr->lft->rgt, ptr->rgt->rgt)) 294 | { ptr = ptr->lft; 295 | break; 296 | } 297 | #endif 298 | break; 299 | 300 | case OR: 301 | #ifndef NO_OPT 302 | /* p || (q U p) == q U p */ 303 | if (ptr->rgt->ntyp == U_OPER 304 | && isequal(ptr->rgt->rgt, ptr->lft)) 305 | { ptr = ptr->rgt; 306 | break; 307 | } 308 | 309 | /* p || (q V p) == p */ 310 | if (ptr->rgt->ntyp == V_OPER 311 | && isequal(ptr->rgt->rgt, ptr->lft)) 312 | { ptr = ptr->lft; 313 | break; 314 | } 315 | 316 | /* (p U q) || (p U r) = p U (q || r) */ 317 | if (ptr->rgt->ntyp == U_OPER 318 | && ptr->lft->ntyp == U_OPER 319 | && isequal(ptr->rgt->lft, ptr->lft->lft)) 320 | { ptr = tl_nn(U_OPER, 321 | ptr->rgt->lft, 322 | tl_nn(OR, ptr->lft->rgt, ptr->rgt->rgt)); 323 | break; 324 | } 325 | 326 | if (isequal(ptr->lft, ptr->rgt) /* (p || p) == p */ 327 | || ptr->rgt->ntyp == FALSE /* (p || F) == p */ 328 | || ptr->lft->ntyp == TRUE) /* (T || p) == T */ 329 | { ptr = ptr->lft; 330 | break; 331 | } 332 | if (ptr->rgt->ntyp == TRUE /* (p || T) == T */ 333 | || ptr->lft->ntyp == FALSE) /* (F || p) == p */ 334 | { ptr = ptr->rgt; 335 | break; 336 | } 337 | 338 | /* (p V q) || (r V q) = (p || r) V q */ 339 | if (ptr->rgt->ntyp == V_OPER 340 | && ptr->lft->ntyp == V_OPER 341 | && isequal(ptr->lft->rgt, ptr->rgt->rgt)) 342 | { ptr = tl_nn(V_OPER, 343 | tl_nn(OR, ptr->lft->lft, ptr->rgt->lft), 344 | ptr->rgt->rgt); 345 | break; 346 | } 347 | 348 | /* (p V q) || (r U q) == r U q */ 349 | if (ptr->rgt->ntyp == U_OPER 350 | && ptr->lft->ntyp == V_OPER 351 | && isequal(ptr->lft->rgt, ptr->rgt->rgt)) 352 | { ptr = ptr->rgt; 353 | break; 354 | } 355 | #endif 356 | break; 357 | } 358 | return ptr; 359 | } 360 | 361 | static Node * 362 | tl_level(int nr) 363 | { int i; Node *ptr = ZN; 364 | 365 | if (nr < 0) 366 | return tl_factor(); 367 | 368 | ptr = tl_level(nr-1); 369 | again: 370 | for (i = 0; i < 4; i++) 371 | if (tl_yychar == prec[nr][i]) 372 | { tl_yychar = tl_yylex(); 373 | ptr = tl_nn(prec[nr][i], 374 | ptr, tl_level(nr-1)); 375 | ptr = bin_simpler(ptr); 376 | goto again; 377 | } 378 | if (!ptr) tl_yyerror("syntax error"); 379 | #if 0 380 | printf("level %d: ", nr); 381 | tl_explain(ptr->ntyp); 382 | printf("\n"); 383 | #endif 384 | return ptr; 385 | } 386 | 387 | static Node * 388 | tl_formula(void) 389 | { tl_yychar = tl_yylex(); 390 | return tl_level(1); /* 2 precedence levels, 1 and 0 */ 391 | } 392 | 393 | void 394 | tl_parse(void) 395 | { Node *n; 396 | 397 | /* tl_verbose = 1; */ 398 | n = tl_formula(); 399 | if (tl_verbose) 400 | { printf("formula: "); 401 | dump(n); 402 | printf("\n"); 403 | } 404 | if (tl_Getchar() != -1) 405 | { tl_yyerror("syntax error"); 406 | tl_errs++; 407 | return; 408 | } 409 | trans(n); 410 | } 411 | -------------------------------------------------------------------------------- /vars.c: -------------------------------------------------------------------------------- 1 | /***** spin: vars.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | */ 8 | 9 | #include "spin.h" 10 | #include "y.tab.h" 11 | 12 | extern Ordered *all_names; 13 | extern RunList *X, *LastX; 14 | extern Symbol *Fname; 15 | extern char Buf[]; 16 | extern int lineno, depth, verbose, xspin, limited_vis; 17 | extern int analyze, jumpsteps, nproc, nstop, columns, old_priority_rules; 18 | extern short no_arrays, Have_claim; 19 | extern void sr_mesg(FILE *, int, int); 20 | extern void sr_buf(int, int); 21 | 22 | static int getglobal(Lextok *); 23 | static int setglobal(Lextok *, int); 24 | static int maxcolnr = 1; 25 | 26 | int 27 | getval(Lextok *sn) 28 | { Symbol *s = sn->sym; 29 | 30 | if (strcmp(s->name, "_") == 0) 31 | { non_fatal("attempt to read value of '_'", 0); 32 | return 0; 33 | } 34 | if (strcmp(s->name, "_last") == 0) 35 | return (LastX)?LastX->pid:0; 36 | if (strcmp(s->name, "_p") == 0) 37 | return (X && X->pc)?X->pc->seqno:0; 38 | if (strcmp(s->name, "_pid") == 0) 39 | { if (!X) return 0; 40 | return X->pid - Have_claim; 41 | } 42 | if (strcmp(s->name, "_priority") == 0) 43 | { if (!X) return 0; 44 | 45 | if (old_priority_rules) 46 | { non_fatal("cannot refer to _priority with -o6", (char *) 0); 47 | return 1; 48 | } 49 | return X->priority; 50 | } 51 | 52 | if (strcmp(s->name, "_nr_pr") == 0) 53 | { return nproc-nstop; /* new 3.3.10 */ 54 | } 55 | 56 | if (s->context && s->type) 57 | { return getlocal(sn); 58 | } 59 | 60 | if (!s->type) /* not declared locally */ 61 | { s = lookup(s->name); /* try global */ 62 | sn->sym = s; /* fix it */ 63 | } 64 | 65 | return getglobal(sn); 66 | } 67 | 68 | int 69 | setval(Lextok *v, int n) 70 | { 71 | if (strcmp(v->sym->name, "_last") == 0 72 | || strcmp(v->sym->name, "_p") == 0 73 | || strcmp(v->sym->name, "_pid") == 0 74 | || strcmp(v->sym->name, "_nr_qs") == 0 75 | || strcmp(v->sym->name, "_nr_pr") == 0) 76 | { non_fatal("illegal assignment to %s", v->sym->name); 77 | } 78 | if (strcmp(v->sym->name, "_priority") == 0) 79 | { if (old_priority_rules) 80 | { non_fatal("cannot refer to _priority with -o6", (char *) 0); 81 | return 1; 82 | } 83 | if (!X) 84 | { non_fatal("no context for _priority", (char *) 0); 85 | return 1; 86 | } 87 | X->priority = n; 88 | } 89 | 90 | if (v->sym->context && v->sym->type) 91 | return setlocal(v, n); 92 | if (!v->sym->type) 93 | v->sym = lookup(v->sym->name); 94 | return setglobal(v, n); 95 | } 96 | 97 | void 98 | rm_selfrefs(Symbol *s, Lextok *i) 99 | { 100 | if (!i) return; 101 | 102 | if (i->ntyp == NAME 103 | && strcmp(i->sym->name, s->name) == 0 104 | && ( (!i->sym->context && !s->context) 105 | || ( i->sym->context && s->context 106 | && strcmp(i->sym->context->name, s->context->name) == 0))) 107 | { lineno = i->ln; 108 | Fname = i->fn; 109 | non_fatal("self-reference initializing '%s'", s->name); 110 | i->ntyp = CONST; 111 | i->val = 0; 112 | } else 113 | { rm_selfrefs(s, i->lft); 114 | rm_selfrefs(s, i->rgt); 115 | } 116 | } 117 | 118 | int 119 | checkvar(Symbol *s, int n) 120 | { int i, oln = lineno; /* calls on eval() change it */ 121 | Symbol *ofnm = Fname; 122 | Lextok *z, *y; 123 | 124 | if (!in_bound(s, n)) 125 | return 0; 126 | 127 | if (s->type == 0) 128 | { non_fatal("undecl var %s (assuming int)", s->name); 129 | s->type = INT; 130 | } 131 | /* not a STRUCT */ 132 | if (s->val == (int *) 0) /* uninitialized */ 133 | { s->val = (int *) emalloc(s->nel*sizeof(int)); 134 | z = s->ini; 135 | for (i = 0; i < s->nel; i++) 136 | { if (z && z->ntyp == ',') 137 | { y = z->lft; 138 | z = z->rgt; 139 | } else 140 | { y = z; 141 | } 142 | if (s->type != CHAN) 143 | { rm_selfrefs(s, y); 144 | s->val[i] = eval(y); 145 | } else if (!analyze) 146 | { s->val[i] = qmake(s); 147 | } } } 148 | lineno = oln; 149 | Fname = ofnm; 150 | 151 | return 1; 152 | } 153 | 154 | static int 155 | getglobal(Lextok *sn) 156 | { Symbol *s = sn->sym; 157 | int i, n = eval(sn->lft); 158 | 159 | if (s->type == 0 && X && (i = find_lab(s, X->n, 0))) /* getglobal */ 160 | { printf("findlab through getglobal on %s\n", s->name); 161 | return i; /* can this happen? */ 162 | } 163 | if (s->type == STRUCT) 164 | { return Rval_struct(sn, s, 1); /* 1 = check init */ 165 | } 166 | if (checkvar(s, n)) 167 | { return cast_val(s->type, s->val[n], s->nbits); 168 | } 169 | return 0; 170 | } 171 | 172 | int 173 | cast_val(int t, int v, int w) 174 | { int i=0; short s=0; unsigned int u=0; 175 | 176 | if (t == PREDEF || t == INT || t == CHAN) i = v; /* predef means _ */ 177 | else if (t == SHORT) s = (short) v; 178 | else if (t == BYTE || t == MTYPE) u = (unsigned char)v; 179 | else if (t == BIT) u = (unsigned char)(v&1); 180 | else if (t == UNSIGNED) 181 | { if (w == 0) 182 | fatal("cannot happen, cast_val", (char *)0); 183 | /* u = (unsigned)(v& ((1<>(8*sizeof(unsigned)-w))); /* doug */ 185 | } 186 | 187 | if (v != i+s+ (int) u) 188 | { char buf[64]; sprintf(buf, "%d->%d (%d)", v, i+s+(int)u, t); 189 | non_fatal("value (%s) truncated in assignment", buf); 190 | } 191 | return (int)(i+s+(int)u); 192 | } 193 | 194 | static int 195 | setglobal(Lextok *v, int m) 196 | { 197 | if (v->sym->type == STRUCT) 198 | { (void) Lval_struct(v, v->sym, 1, m); 199 | } else 200 | { int n = eval(v->lft); 201 | if (checkvar(v->sym, n)) 202 | { int oval = v->sym->val[n]; 203 | int nval = cast_val(v->sym->type, m, v->sym->nbits); 204 | v->sym->val[n] = nval; 205 | if (oval != nval) 206 | { v->sym->setat = depth; 207 | } } } 208 | return 1; 209 | } 210 | 211 | void 212 | dumpclaims(FILE *fd, int pid, char *s) 213 | { extern Lextok *Xu_List; extern int Pid; 214 | extern short terse; 215 | Lextok *m; int cnt = 0; int oPid = Pid; 216 | 217 | for (m = Xu_List; m; m = m->rgt) 218 | if (strcmp(m->sym->name, s) == 0) 219 | { cnt=1; 220 | break; 221 | } 222 | if (cnt == 0) return; 223 | 224 | Pid = pid; 225 | fprintf(fd, "#ifndef XUSAFE\n"); 226 | for (m = Xu_List; m; m = m->rgt) 227 | { if (strcmp(m->sym->name, s) != 0) 228 | continue; 229 | no_arrays = 1; 230 | putname(fd, "\t\tsetq_claim(", m->lft, 0, ""); 231 | no_arrays = 0; 232 | fprintf(fd, ", %d, ", m->val); 233 | terse = 1; 234 | putname(fd, "\"", m->lft, 0, "\", h, "); 235 | terse = 0; 236 | fprintf(fd, "\"%s\");\n", s); 237 | } 238 | fprintf(fd, "#endif\n"); 239 | Pid = oPid; 240 | } 241 | 242 | void 243 | dumpglobals(void) 244 | { Ordered *walk; 245 | static Lextok *dummy = ZN; 246 | Symbol *sp; 247 | int j; 248 | 249 | if (!dummy) 250 | dummy = nn(ZN, NAME, nn(ZN,CONST,ZN,ZN), ZN); 251 | 252 | for (walk = all_names; walk; walk = walk->next) 253 | { sp = walk->entry; 254 | if (!sp->type || sp->context || sp->owner 255 | || sp->type == PROCTYPE || sp->type == PREDEF 256 | || sp->type == CODE_FRAG || sp->type == CODE_DECL 257 | || (sp->type == MTYPE && ismtype(sp->name))) 258 | continue; 259 | 260 | if (sp->type == STRUCT) 261 | { if ((verbose&4) && !(verbose&64) 262 | && (sp->setat < depth 263 | && jumpsteps != depth)) 264 | { continue; 265 | } 266 | dump_struct(sp, sp->name, 0); 267 | continue; 268 | } 269 | for (j = 0; j < sp->nel; j++) 270 | { int prefetch; 271 | if (sp->type == CHAN) 272 | { doq(sp, j, 0); 273 | continue; 274 | } 275 | if ((verbose&4) && !(verbose&64) 276 | && (sp->setat < depth 277 | && jumpsteps != depth)) 278 | { continue; 279 | } 280 | 281 | dummy->sym = sp; 282 | dummy->lft->val = j; 283 | /* in case of cast_val warnings, do this first: */ 284 | prefetch = getglobal(dummy); 285 | printf("\t\t%s", sp->name); 286 | if (sp->nel > 1 || sp->isarray) printf("[%d]", j); 287 | printf(" = "); 288 | sr_mesg(stdout, prefetch, 289 | sp->type == MTYPE); 290 | printf("\n"); 291 | if (limited_vis && (sp->hidden&2)) 292 | { int colpos; 293 | Buf[0] = '\0'; 294 | if (!xspin) 295 | { if (columns == 2) 296 | sprintf(Buf, "~G%s = ", sp->name); 297 | else 298 | sprintf(Buf, "%s = ", sp->name); 299 | } 300 | sr_buf(prefetch, sp->type == MTYPE); 301 | if (sp->colnr == 0) 302 | { sp->colnr = (unsigned char) maxcolnr; 303 | maxcolnr = 1+(maxcolnr%10); 304 | } 305 | colpos = nproc+sp->colnr-1; 306 | if (columns == 2) 307 | { pstext(colpos, Buf); 308 | continue; 309 | } 310 | if (!xspin) 311 | { printf("\t\t%s\n", Buf); 312 | continue; 313 | } 314 | printf("MSC: ~G %s %s\n", sp->name, Buf); 315 | printf("%3d:\tproc %3d (TRACK) line 1 \"var\" ", 316 | depth, colpos); 317 | printf("(state 0)\t[printf('MSC: globvar\\\\n')]\n"); 318 | printf("\t\t%s", sp->name); 319 | if (sp->nel > 1 || sp->isarray) printf("[%d]", j); 320 | printf(" = %s\n", Buf); 321 | } } } 322 | } 323 | 324 | void 325 | dumplocal(RunList *r) 326 | { static Lextok *dummy = ZN; 327 | Symbol *z, *s; 328 | int i; 329 | 330 | if (!r) return; 331 | 332 | s = r->symtab; 333 | 334 | if (!dummy) 335 | dummy = nn(ZN, NAME, nn(ZN,CONST,ZN,ZN), ZN); 336 | 337 | for (z = s; z; z = z->next) 338 | { if (z->type == STRUCT) 339 | { dump_struct(z, z->name, r); 340 | continue; 341 | } 342 | for (i = 0; i < z->nel; i++) 343 | { if (z->type == CHAN) 344 | { doq(z, i, r); 345 | continue; 346 | } 347 | if ((verbose&4) && !(verbose&64) 348 | && (z->setat < depth 349 | && jumpsteps != depth)) 350 | continue; 351 | 352 | dummy->sym = z; 353 | dummy->lft->val = i; 354 | 355 | printf("\t\t%s(%d):%s", 356 | r->n->name, r->pid - Have_claim, z->name); 357 | if (z->nel > 1 || z->isarray) printf("[%d]", i); 358 | printf(" = "); 359 | sr_mesg(stdout, getval(dummy), z->type == MTYPE); 360 | printf("\n"); 361 | if (limited_vis && (z->hidden&2)) 362 | { int colpos; 363 | Buf[0] = '\0'; 364 | if (!xspin) 365 | { if (columns == 2) 366 | sprintf(Buf, "~G%s(%d):%s = ", 367 | r->n->name, r->pid, z->name); 368 | else 369 | sprintf(Buf, "%s(%d):%s = ", 370 | r->n->name, r->pid, z->name); 371 | } 372 | sr_buf(getval(dummy), z->type==MTYPE); 373 | if (z->colnr == 0) 374 | { z->colnr = (unsigned char) maxcolnr; 375 | maxcolnr = 1+(maxcolnr%10); 376 | } 377 | colpos = nproc+z->colnr-1; 378 | if (columns == 2) 379 | { pstext(colpos, Buf); 380 | continue; 381 | } 382 | if (!xspin) 383 | { printf("\t\t%s\n", Buf); 384 | continue; 385 | } 386 | printf("MSC: ~G %s(%d):%s %s\n", 387 | r->n->name, r->pid, z->name, Buf); 388 | 389 | printf("%3d:\tproc %3d (TRACK) line 1 \"var\" ", 390 | depth, colpos); 391 | printf("(state 0)\t[printf('MSC: locvar\\\\n')]\n"); 392 | printf("\t\t%s(%d):%s", 393 | r->n->name, r->pid, z->name); 394 | if (z->nel > 1 || z->isarray) printf("[%d]", i); 395 | printf(" = %s\n", Buf); 396 | } } } 397 | } 398 | -------------------------------------------------------------------------------- /guided.c: -------------------------------------------------------------------------------- 1 | /***** spin: guided.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | */ 8 | 9 | #include "spin.h" 10 | #include 11 | #include 12 | #include 13 | #include "y.tab.h" 14 | 15 | extern RunList *run, *X; 16 | extern Element *Al_El; 17 | extern Symbol *Fname, *oFname; 18 | extern int verbose, lineno, xspin, jumpsteps, depth, merger, cutoff; 19 | extern int nproc, nstop, Tval, ntrail, columns; 20 | extern short Have_claim, Skip_claim, has_code; 21 | extern void ana_src(int, int); 22 | extern char **trailfilename; 23 | 24 | int TstOnly = 0, pno; 25 | 26 | static int lastclaim = -1; 27 | static FILE *fd; 28 | static void lost_trail(void); 29 | 30 | static void 31 | whichproc(int p) 32 | { RunList *oX; 33 | 34 | for (oX = run; oX; oX = oX->nxt) 35 | if (oX->pid == p) 36 | { printf("(%s) ", oX->n->name); 37 | break; 38 | } 39 | } 40 | 41 | static int 42 | newer(char *f1, char *f2) 43 | { 44 | #if defined(WIN32) || defined(WIN64) 45 | struct _stat x, y; 46 | #else 47 | struct stat x, y; 48 | #endif 49 | 50 | if (stat(f1, (struct stat *)&x) < 0) return 0; 51 | if (stat(f2, (struct stat *)&y) < 0) return 1; 52 | if (x.st_mtime < y.st_mtime) return 0; 53 | 54 | return 1; 55 | } 56 | 57 | void 58 | hookup(void) 59 | { Element *e; 60 | 61 | for (e = Al_El; e; e = e->Nxt) 62 | if (e->n 63 | && (e->n->ntyp == ATOMIC 64 | || e->n->ntyp == NON_ATOMIC 65 | || e->n->ntyp == D_STEP)) 66 | (void) huntstart(e); 67 | } 68 | 69 | int 70 | not_claim(void) 71 | { 72 | return (!Have_claim || !X || X->pid != 0); 73 | } 74 | 75 | int globmin = INT_MAX; 76 | int globmax = 0; 77 | 78 | int 79 | find_min(Sequence *s) 80 | { SeqList *l; 81 | Element *e; 82 | 83 | if (s->minel < 0) 84 | { s->minel = INT_MAX; 85 | for (e = s->frst; e; e = e->nxt) 86 | { if (e->status & 512) 87 | { continue; 88 | } 89 | e->status |= 512; 90 | 91 | if (e->n->ntyp == ATOMIC 92 | || e->n->ntyp == NON_ATOMIC 93 | || e->n->ntyp == D_STEP) 94 | { int n = find_min(e->n->sl->this); 95 | if (n < s->minel) 96 | { s->minel = n; 97 | } 98 | } else if (e->Seqno < s->minel) 99 | { s->minel = e->Seqno; 100 | } 101 | for (l = e->sub; l; l = l->nxt) 102 | { int n = find_min(l->this); 103 | if (n < s->minel) 104 | { s->minel = n; 105 | } } } 106 | } 107 | if (s->minel < globmin) 108 | { globmin = s->minel; 109 | } 110 | return s->minel; 111 | } 112 | 113 | int 114 | find_max(Sequence *s) 115 | { 116 | if (s->last->Seqno > globmax) 117 | { globmax = s->last->Seqno; 118 | } 119 | return s->last->Seqno; 120 | } 121 | 122 | void 123 | match_trail(void) 124 | { int i, a, nst; 125 | Element *dothis; 126 | char snap[512], *q; 127 | 128 | if (has_code) 129 | { printf("spin: important:\n"); 130 | printf(" =======================================warning====\n"); 131 | printf(" this model contains embedded c code statements\n"); 132 | printf(" these statements will not be executed when the trail\n"); 133 | printf(" is replayed in this way -- they are just printed,\n"); 134 | printf(" which will likely lead to inaccurate variable values.\n"); 135 | printf(" for an accurate replay use: ./pan -r\n"); 136 | printf(" =======================================warning====\n\n"); 137 | } 138 | 139 | /* 140 | * if source model name is leader.pml 141 | * look for the trail file under these names: 142 | * leader.pml.trail 143 | * leader.pml.tra 144 | * leader.trail 145 | * leader.tra 146 | */ 147 | 148 | if (trailfilename) 149 | { if (strlen(*trailfilename) < sizeof(snap)) 150 | { strcpy(snap, (const char *) *trailfilename); 151 | } else 152 | { fatal("filename %s too long", *trailfilename); 153 | } 154 | } else 155 | { if (ntrail) 156 | sprintf(snap, "%s%d.trail", oFname->name, ntrail); 157 | else 158 | sprintf(snap, "%s.trail", oFname->name); 159 | } 160 | 161 | if ((fd = fopen(snap, "r")) == NULL) 162 | { snap[strlen(snap)-2] = '\0'; /* .tra */ 163 | if ((fd = fopen(snap, "r")) == NULL) 164 | { if ((q = strchr(oFname->name, '.')) != NULL) 165 | { *q = '\0'; 166 | if (ntrail) 167 | sprintf(snap, "%s%d.trail", 168 | oFname->name, ntrail); 169 | else 170 | sprintf(snap, "%s.trail", 171 | oFname->name); 172 | *q = '.'; 173 | 174 | if ((fd = fopen(snap, "r")) != NULL) 175 | goto okay; 176 | 177 | snap[strlen(snap)-2] = '\0'; /* last try */ 178 | if ((fd = fopen(snap, "r")) != NULL) 179 | goto okay; 180 | } 181 | printf("spin: cannot find trail file\n"); 182 | alldone(1); 183 | } } 184 | okay: 185 | if (xspin == 0 && newer(oFname->name, snap)) 186 | { printf("spin: warning, \"%s\" is newer than %s\n", 187 | oFname->name, snap); 188 | } 189 | Tval = 1; 190 | 191 | /* 192 | * sets Tval because timeouts may be part of trail 193 | * this used to also set m_loss to 1, but that is 194 | * better handled with the runtime -m flag 195 | */ 196 | 197 | hookup(); 198 | 199 | while (fscanf(fd, "%d:%d:%d\n", &depth, &pno, &nst) == 3) 200 | { if (depth == -2) 201 | { if (verbose) 202 | { printf("starting claim %d\n", pno); 203 | } 204 | start_claim(pno); 205 | continue; 206 | } 207 | if (depth == -4) 208 | { if (verbose) 209 | { printf("using statement merging\n"); 210 | } 211 | merger = 1; 212 | ana_src(0, 1); 213 | continue; 214 | } 215 | if (depth == -1) 216 | { if (1 || verbose) 217 | { if (columns == 2) 218 | dotag(stdout, " CYCLE>\n"); 219 | else 220 | dotag(stdout, "<<<<>>>>\n"); 221 | } 222 | continue; 223 | } 224 | 225 | if (cutoff > 0 && depth >= cutoff) 226 | { printf("-------------\n"); 227 | printf("depth-limit (-u%d steps) reached\n", cutoff); 228 | break; 229 | } 230 | 231 | if (Skip_claim && pno == 0) continue; 232 | 233 | for (dothis = Al_El; dothis; dothis = dothis->Nxt) 234 | { if (dothis->Seqno == nst) 235 | break; 236 | } 237 | if (!dothis) 238 | { printf("%3d: proc %d, no matching stmnt %d\n", 239 | depth, pno - Have_claim, nst); 240 | lost_trail(); 241 | } 242 | 243 | i = nproc - nstop + Skip_claim; 244 | 245 | if (dothis->n->ntyp == '@') 246 | { if (pno == i-1) 247 | { run = run->nxt; 248 | nstop++; 249 | if (verbose&4) 250 | { if (columns == 2) 251 | { dotag(stdout, "\n"); 252 | continue; 253 | } 254 | if (Have_claim && pno == 0) 255 | printf("%3d: claim terminates\n", 256 | depth); 257 | else 258 | printf("%3d: proc %d terminates\n", 259 | depth, pno - Have_claim); 260 | } 261 | continue; 262 | } 263 | if (pno <= 1) continue; /* init dies before never */ 264 | printf("%3d: stop error, ", depth); 265 | printf("proc %d (i=%d) trans %d, %c\n", 266 | pno - Have_claim, i, nst, dothis->n->ntyp); 267 | lost_trail(); 268 | } 269 | 270 | if (0 && !xspin && (verbose&32)) 271 | { printf("step %d i=%d pno %d stmnt %d\n", depth, i, pno, nst); 272 | } 273 | 274 | for (X = run; X; X = X->nxt) 275 | { if (--i == pno) 276 | break; 277 | } 278 | 279 | if (!X) 280 | { if (verbose&32) 281 | { printf("%3d: no process %d (stmnt %d)\n", depth, pno - Have_claim, nst); 282 | printf(" max %d (%d - %d + %d) claim %d ", 283 | nproc - nstop + Skip_claim, 284 | nproc, nstop, Skip_claim, Have_claim); 285 | printf("active processes:\n"); 286 | for (X = run; X; X = X->nxt) 287 | { printf("\tpid %d\tproctype %s\n", X->pid, X->n->name); 288 | } 289 | printf("\n"); 290 | continue; 291 | } else 292 | { printf("%3d:\tproc %d (?) ", depth, pno); 293 | lost_trail(); 294 | } 295 | } else 296 | { int min_seq = find_min(X->ps); 297 | int max_seq = find_max(X->ps); 298 | 299 | 300 | if (nst < min_seq || nst > max_seq) 301 | { printf("%3d: error: invalid statement", depth); 302 | if (verbose&32) 303 | { printf(": pid %d:%d (%s:%d:%d) stmnt %d (valid range %d .. %d)", 304 | pno, X->pid, X->n->name, X->tn, X->b, nst, min_seq, max_seq); 305 | } 306 | printf("\n"); 307 | continue; 308 | /* lost_trail(); */ 309 | } 310 | X->pc = dothis; 311 | } 312 | 313 | lineno = dothis->n->ln; 314 | Fname = dothis->n->fn; 315 | 316 | if (dothis->n->ntyp == D_STEP) 317 | { Element *g, *og = dothis; 318 | do { 319 | g = eval_sub(og); 320 | if (g && depth >= jumpsteps 321 | && ((verbose&32) || ((verbose&4) && not_claim()))) 322 | { if (columns != 2) 323 | { p_talk(og, 1); 324 | 325 | if (og->n->ntyp == D_STEP) 326 | og = og->n->sl->this->frst; 327 | 328 | printf("\t["); 329 | comment(stdout, og->n, 0); 330 | printf("]\n"); 331 | } 332 | if (verbose&1) dumpglobals(); 333 | if (verbose&2) dumplocal(X); 334 | if (xspin) printf("\n"); 335 | } 336 | og = g; 337 | } while (g && g != dothis->nxt); 338 | if (X != NULL) 339 | { X->pc = g?huntele(g, 0, -1):g; 340 | } 341 | } else 342 | { 343 | keepgoing: if (dothis->merge_start) 344 | a = dothis->merge_start; 345 | else 346 | a = dothis->merge; 347 | 348 | if (X != NULL) 349 | { X->pc = eval_sub(dothis); 350 | if (X->pc) X->pc = huntele(X->pc, 0, a); 351 | } 352 | 353 | if (depth >= jumpsteps 354 | && ((verbose&32) || ((verbose&4) && not_claim()))) /* -v or -p */ 355 | { if (columns != 2) 356 | { p_talk(dothis, 1); 357 | 358 | if (dothis->n->ntyp == D_STEP) 359 | dothis = dothis->n->sl->this->frst; 360 | 361 | printf("\t["); 362 | comment(stdout, dothis->n, 0); 363 | printf("]"); 364 | if (a && (verbose&32)) 365 | printf("\t", 366 | dothis->merge, 367 | (X && X->pc)?X->pc->seqno:-1); 368 | printf("\n"); 369 | } 370 | if (verbose&1) dumpglobals(); 371 | if (verbose&2) dumplocal(X); 372 | if (xspin) printf("\n"); 373 | 374 | if (X && !X->pc) 375 | { X->pc = dothis; 376 | printf("\ttransition failed\n"); 377 | a = 0; /* avoid inf loop */ 378 | } 379 | } 380 | if (a && X && X->pc && X->pc->seqno != a) 381 | { dothis = X->pc; 382 | goto keepgoing; 383 | } } 384 | 385 | if (Have_claim && X && X->pid == 0 386 | && dothis->n 387 | && lastclaim != dothis->n->ln) 388 | { lastclaim = dothis->n->ln; 389 | if (columns == 2) 390 | { char t[128]; 391 | sprintf(t, "#%d", lastclaim); 392 | pstext(0, t); 393 | } else 394 | { 395 | printf("Never claim moves to line %d\t[", lastclaim); 396 | comment(stdout, dothis->n, 0); 397 | printf("]\n"); 398 | } } } 399 | printf("spin: trail ends after %d steps\n", depth); 400 | wrapup(0); 401 | } 402 | 403 | static void 404 | lost_trail(void) 405 | { int d, p, n, l; 406 | 407 | while (fscanf(fd, "%d:%d:%d:%d\n", &d, &p, &n, &l) == 4) 408 | { printf("step %d: proc %d ", d, p); whichproc(p); 409 | printf("(state %d) - d %d\n", n, l); 410 | } 411 | wrapup(1); /* no return */ 412 | } 413 | 414 | int 415 | pc_value(Lextok *n) 416 | { int i = nproc - nstop; 417 | int pid = eval(n); 418 | RunList *Y; 419 | 420 | for (Y = run; Y; Y = Y->nxt) 421 | { if (--i == pid) 422 | return Y->pc->seqno; 423 | } 424 | return 0; 425 | } 426 | -------------------------------------------------------------------------------- /msc_tcl.c: -------------------------------------------------------------------------------- 1 | /***** spin: msc_tcl.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | */ 8 | 9 | #include 10 | #include "spin.h" 11 | #include "version.h" 12 | 13 | #define MW 500 /* page width */ 14 | #define RH 100 /* right margin */ 15 | #define WW 80 /* distance between process lines */ 16 | #define HH 12 /* vertical distance between steps */ 17 | #define LW 2 /* line width of message arrows */ 18 | 19 | #define RVC "darkred" /* rendezvous arrows */ 20 | #define MPC "darkblue" /* asynchronous message passing arrow */ 21 | #define GRC "lightgrey" /* grid lines */ 22 | 23 | static int MH = 600; /* anticipated page-length */ 24 | static FILE *pfd; 25 | static char **I; /* initial procs */ 26 | static int *D,*R; /* maps between depth (stepnr) and ldepth (msc-step) */ 27 | static short *M; /* x location of each box at index y */ 28 | static short *T; /* y index of match for each box at index y */ 29 | static char **L; /* text labels */ 30 | static int ProcLine[256]; /* active processes */ 31 | static int UsedLine[256]; /* process line has at least one entry */ 32 | static int ldepth = 1; 33 | static int maxx, TotSteps = 2*4096; /* max nr of steps for simulation output */ 34 | static float Scaler = (float) 1.0; 35 | 36 | static int xscale = 2; 37 | static int yscale = 1; 38 | static int no_box; 39 | 40 | extern int ntrail, s_trail, pno, depth; 41 | extern Symbol *oFname; 42 | 43 | extern void exit(int); 44 | extern void putpostlude(void); 45 | 46 | static void putpages(void); 47 | 48 | static void 49 | psline(int x0, int y0, int x1, int y1, char *color) 50 | { char *side = "last"; 51 | 52 | if (x0 == x1) /* gridline */ 53 | { fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags grid -width 1 \n", 54 | xscale*(x0+1)*WW-20, yscale*y0+20, 55 | xscale*(x1+1)*WW-20, yscale*y1+20, color); 56 | fprintf(pfd, ".c lower grid\n"); 57 | } else 58 | { int xm = xscale*(x0+1)*WW + (xscale*(x1 - x0)*WW)/2 - 20; /* mid x */ 59 | 60 | if (y1 - y0 <= HH+20) 61 | { y1 = y0+20; /* close enough to horizontal - looks better */ 62 | } 63 | 64 | fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags mesg -width %d\n", 65 | xscale*(x0+1)*WW-20, yscale*y0+20+10, 66 | xm, yscale*y0+20+10, color, LW); 67 | 68 | if (y1 != y0+20) 69 | { fprintf(pfd, ".c create line %d %d %d %d -fill %s -tags mesg -width %d\n", 70 | xm, yscale*y0+20+10, 71 | xm, yscale*y1+20-10, color, LW); 72 | } 73 | 74 | fprintf(pfd, ".c create line %d %d %d %d -fill %s -width %d ", 75 | xm, yscale*y1+20-10, 76 | xscale*(x1+1)*WW-20, yscale*y1+20-10, color, LW); 77 | 78 | if (strcmp(color, RVC) == 0) 79 | { side = "both"; 80 | } 81 | fprintf(pfd, "-arrow %s -arrowshape {5 5 5} -tags mesg\n", side); 82 | fprintf(pfd, ".c raise mesg\n"); 83 | } 84 | } 85 | 86 | static void 87 | colbox(int ix, int iy, int w, int h_unused, char *color) 88 | { int x = ix*WW; 89 | int y = iy*HH; 90 | 91 | if (ix < 0 || ix > 255) 92 | { fatal("msc_tcl: unexpected\n", (char *) 0); 93 | } 94 | 95 | if (ProcLine[ix] < iy) 96 | { /* if (ProcLine[ix] > 0) */ 97 | { psline(ix-1, ProcLine[ix]*HH+HH+4, 98 | ix-1, iy*HH-HH, GRC); 99 | } 100 | fprintf(pfd, "# ProcLine[%d] from %d to %d (Used %d nobox %d)\n", 101 | ix, ProcLine[ix], iy, UsedLine[ix], no_box); 102 | ProcLine[ix] = iy; 103 | } else 104 | { fprintf(pfd, "# ProcLine[%d] stays at %d (Used %d nobox %d)\n", 105 | ix, ProcLine[ix], UsedLine[ix], no_box); 106 | } 107 | 108 | if (UsedLine[ix]) 109 | { no_box = 2; 110 | } 111 | 112 | if (strcmp(color, "black") == 0) 113 | { if (no_box == 0) /* shadow */ 114 | { fprintf(pfd, ".c create rectangle %d %d %d %d -fill black\n", 115 | xscale*x-(xscale*4*w/3)-20+4, (yscale*y-10)+20+2, 116 | xscale*x+(xscale*4*w/3)-20, (yscale*y+10)+20+2); 117 | } 118 | } else 119 | { if (no_box == 0) /* box with outline */ 120 | { fprintf(pfd, ".c create rectangle %d %d %d %d -fill ivory\n", 121 | xscale*x-(xscale*4*w/3)-20, (yscale*y-10)+20, 122 | xscale*x+(xscale*4*w/3)-20, (yscale*y+10)+20); 123 | UsedLine[ix]++; 124 | } else /* no outline */ 125 | { fprintf(pfd, ".c create rectangle %d %d %d %d -fill white -width 0\n", 126 | xscale*x-(xscale*4*w/3)-20, (yscale*y-10)+20, 127 | xscale*x+(xscale*4*w/3)-20, (yscale*y+10)+20); 128 | } } 129 | if (no_box > 0) 130 | { no_box--; 131 | } 132 | } 133 | 134 | static void 135 | stepnumber(int i) 136 | { int y = (yscale*i*HH) + 20; 137 | 138 | fprintf(pfd, ".c create text %d %d -fill #eef -text \"%d\"\n", 139 | -10+(xscale*WW)/2, y, i); 140 | 141 | /* horizontal dashed grid line */ 142 | fprintf(pfd, ".c create line %d %d %d %d -fill #eef -dash {6 4}\n", 143 | -20+WW*xscale, y, (maxx+1)*WW*xscale-20, y); 144 | } 145 | 146 | static void 147 | spitbox(int ix, int y, char *s) 148 | { float bw; /* box width */ 149 | char d[256], *t, *z; 150 | int a, i, x = ix+1; 151 | char *color = "black"; 152 | 153 | if (y > 0) 154 | { stepnumber(y); 155 | } 156 | 157 | bw = (float)1.8*(float)strlen(s); /* guess at default font width */ 158 | colbox(x, y, (int) (bw+1.0), 5, "black"); 159 | if (s[0] == '~') 160 | { switch (s[1]) { 161 | default : 162 | case 'R': color = "red"; break; 163 | case 'B': color = "blue"; break; 164 | case 'G': color = "green"; break; 165 | } 166 | s += 2; 167 | } else if (strchr(s, '!')) 168 | { color = "ivory"; 169 | } else if (strchr(s, '?')) 170 | { color = "azure"; 171 | } else 172 | { color = "pink"; 173 | if (sscanf(s, "%d:%250s", &a, d) == 2 174 | && a >= 0 && a < TotSteps) 175 | { if (!I[a] || strlen(I[a]) <= strlen(s)) 176 | { I[a] = (char *) emalloc((int) strlen(s)+1); 177 | } 178 | strcpy(I[a], s); 179 | } } 180 | 181 | colbox(x, y, (int) bw, 4, color); 182 | 183 | z = t = (char *) emalloc(2*strlen(s)+1); 184 | 185 | for (i = 0; i < (int) strlen(s); i++) 186 | { if (s[i] == '\n') 187 | { continue; 188 | } 189 | if (s[i] == '[' || s[i] == ']') 190 | { *t++ = '\\'; 191 | } 192 | *t++ = s[i]; 193 | } 194 | 195 | fprintf(pfd, ".c create text %d %d -text \"%s\"\n", 196 | xscale*x*WW-20, yscale*y*HH+20, z); 197 | } 198 | 199 | static void 200 | putpages(void) 201 | { int i, lasti=0; float nmh; 202 | 203 | if (maxx*xscale*WW > MW-RH/2) 204 | { Scaler = (float) (MW-RH/2) / (float) (maxx*xscale*WW); 205 | nmh = (float) MH; nmh /= Scaler; MH = (int) nmh; 206 | fprintf(pfd, "# Scaler %f, MH %d\n", Scaler, MH); 207 | } 208 | if (ldepth >= TotSteps) 209 | { ldepth = TotSteps-1; 210 | } 211 | 212 | /* W: (maxx+2)*xscale*WW */ 213 | /* H: ldepth*HH*yscale+50 */ 214 | fprintf(pfd, "wm title . \"scenario\"\n"); 215 | fprintf(pfd, "wm geometry . %dx600+650+100\n", (maxx+2)*xscale*WW); 216 | 217 | fprintf(pfd, "canvas .c -width 800 -height 800 \\\n"); 218 | fprintf(pfd, " -scrollregion {0c -1c 30c 100c} \\\n"); 219 | fprintf(pfd, " -xscrollcommand \".hscroll set\" \\\n"); 220 | fprintf(pfd, " -yscrollcommand \".vscroll set\" \\\n"); 221 | fprintf(pfd, " -bg white -relief raised -bd 2\n"); 222 | 223 | fprintf(pfd, "scrollbar .vscroll -relief sunken "); 224 | fprintf(pfd, " -command \".c yview\"\n"); 225 | fprintf(pfd, "scrollbar .hscroll -relief sunken -orient horiz "); 226 | fprintf(pfd, " -command \".c xview\"\n"); 227 | 228 | fprintf(pfd, "pack append . \\\n"); 229 | fprintf(pfd, " .vscroll {right filly} \\\n"); 230 | fprintf(pfd, " .hscroll {bottom fillx} \\\n"); 231 | fprintf(pfd, " .c {top expand fill}\n"); 232 | 233 | fprintf(pfd, ".c yview moveto 0\n"); 234 | 235 | for (i = TotSteps-1; i >= 0; i--) 236 | { if (I[i]) 237 | { spitbox(i, -1, I[i]); 238 | } } 239 | 240 | for (i = 0; i <= ldepth; i++) 241 | { if (!M[i] && !L[i]) 242 | { continue; /* no box */ 243 | } 244 | if (T[i] > 0) /* arrow */ 245 | { if (T[i] == i) /* rv handshake */ 246 | { psline( M[lasti], lasti*HH, 247 | M[i], i*HH, RVC); 248 | } else 249 | { psline( M[i], i*HH, 250 | M[T[i]], T[i]*HH, MPC); 251 | } } 252 | if (L[i]) 253 | { spitbox(M[i], i, L[i]); 254 | lasti = i; 255 | } } 256 | } 257 | 258 | static void 259 | putbox(int x) 260 | { 261 | if (ldepth >= TotSteps) 262 | { fprintf(stderr, "max length of %d steps exceeded - ps file truncated\n", 263 | TotSteps); 264 | putpostlude(); 265 | } 266 | M[ldepth] = x; 267 | if (x > maxx) 268 | { maxx = x; 269 | fprintf(pfd, "# maxx %d\n", x); 270 | } 271 | } 272 | 273 | /* functions called externally: */ 274 | 275 | extern int WhatSeed(void); 276 | 277 | void 278 | putpostlude(void) 279 | { char cmd[512]; 280 | 281 | putpages(); 282 | fprintf(pfd, ".c lower grid\n"); 283 | fprintf(pfd, ".c raise mesg\n"); 284 | fclose(pfd); 285 | 286 | fprintf(stderr, "seed used: -n%d\n", WhatSeed()); 287 | sprintf(cmd, "wish -f %s.tcl &", oFname?oFname->name:"msc"); 288 | fprintf(stderr, "%s\n", cmd); 289 | (void) unlink("pan.pre"); 290 | exit (system(cmd)); 291 | } 292 | 293 | void 294 | putprelude(void) 295 | { char snap[256]; FILE *fd; 296 | 297 | sprintf(snap, "%s.tcl", oFname?oFname->name:"msc"); 298 | if (!(pfd = fopen(snap, MFLAGS))) 299 | { fatal("cannot create file '%s'", snap); 300 | } 301 | if (s_trail) 302 | { if (ntrail) 303 | sprintf(snap, "%s%d.trail", oFname?oFname->name:"msc", ntrail); 304 | else 305 | sprintf(snap, "%s.trail", oFname?oFname->name:"msc"); 306 | if (!(fd = fopen(snap, "r"))) 307 | { snap[strlen(snap)-2] = '\0'; 308 | if (!(fd = fopen(snap, "r"))) 309 | fatal("cannot open trail file", (char *) 0); 310 | } 311 | TotSteps = 1; 312 | while (fgets(snap, 256, fd)) TotSteps++; 313 | fclose(fd); 314 | } 315 | TotSteps *= 2; 316 | R = (int *) emalloc(TotSteps * sizeof(int)); 317 | D = (int *) emalloc(TotSteps * sizeof(int)); 318 | M = (short *) emalloc(TotSteps * sizeof(short)); 319 | T = (short *) emalloc(TotSteps * sizeof(short)); 320 | L = (char **) emalloc(TotSteps * sizeof(char *)); 321 | I = (char **) emalloc(TotSteps * sizeof(char *)); 322 | } 323 | 324 | void 325 | putarrow(int from, int to) 326 | { 327 | /* from rv if from == to */ 328 | /* which means that D[from] == D[to] */ 329 | /* which means that T[x] == x */ 330 | 331 | if (from < TotSteps 332 | && to < TotSteps 333 | && D[from] < TotSteps) 334 | { T[D[from]] = D[to]; 335 | } 336 | } 337 | 338 | void 339 | pstext(int x, char *s) 340 | { char *tmp = emalloc((int) strlen(s)+1); 341 | 342 | strcpy(tmp, s); 343 | if (depth == 0) 344 | { I[x] = tmp; 345 | } else 346 | { if (depth >= TotSteps || ldepth >= TotSteps) 347 | { fprintf(stderr, "spin: error: max nr of %d steps exceeded\n", 348 | TotSteps); 349 | fatal("use -uN to limit steps", (char *) 0); 350 | } 351 | putbox(x); 352 | D[depth] = ldepth; 353 | R[ldepth] = depth; 354 | L[ldepth] = tmp; 355 | ldepth += 2; 356 | } 357 | } 358 | 359 | void 360 | dotag(FILE *fd, char *s) 361 | { extern int columns, notabs; extern RunList *X; 362 | int i = (!strncmp(s, "MSC: ", 5))?5:0; 363 | int pid = s_trail ? pno : (X?X->pid:0); 364 | 365 | if (columns == 2) 366 | { pstext(pid, &s[i]); 367 | } else 368 | { if (!notabs) 369 | { printf(" "); 370 | for (i = 0; i <= pid; i++) 371 | { printf(" "); 372 | } } 373 | fprintf(fd, "%s", s); 374 | fflush(fd); 375 | } 376 | } 377 | -------------------------------------------------------------------------------- /reprosrc.c: -------------------------------------------------------------------------------- 1 | /***** spin: reprosrc.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | */ 8 | 9 | #include 10 | #include 11 | #include "spin.h" 12 | #include "y.tab.h" 13 | 14 | static int indent = 1; 15 | 16 | extern YYSTYPE yylval; 17 | extern ProcList *rdy; 18 | static void repro_seq(Sequence *); 19 | 20 | void 21 | doindent(void) 22 | { int i; 23 | for (i = 0; i < indent; i++) 24 | printf(" "); 25 | } 26 | 27 | void 28 | repro_sub(Element *e) 29 | { 30 | doindent(); 31 | switch (e->n->ntyp) { 32 | case D_STEP: 33 | printf("d_step {\n"); 34 | break; 35 | case ATOMIC: 36 | printf("atomic {\n"); 37 | break; 38 | case NON_ATOMIC: 39 | printf(" {\n"); 40 | break; 41 | } 42 | indent++; 43 | repro_seq(e->n->sl->this); 44 | indent--; 45 | 46 | doindent(); 47 | printf(" };\n"); 48 | } 49 | 50 | static void 51 | repro_seq(Sequence *s) 52 | { Element *e; 53 | Symbol *v; 54 | SeqList *h; 55 | 56 | for (e = s->frst; e; e = e->nxt) 57 | { 58 | v = has_lab(e, 0); 59 | if (v) printf("%s:\n", v->name); 60 | 61 | if (e->n->ntyp == UNLESS) 62 | { printf("/* normal */ {\n"); 63 | repro_seq(e->n->sl->this); 64 | doindent(); 65 | printf("} unless {\n"); 66 | repro_seq(e->n->sl->nxt->this); 67 | doindent(); 68 | printf("}; /* end unless */\n"); 69 | } else if (e->sub) 70 | { 71 | switch (e->n->ntyp) { 72 | case DO: doindent(); printf("do\n"); indent++; break; 73 | case IF: doindent(); printf("if\n"); indent++; break; 74 | } 75 | 76 | for (h = e->sub; h; h = h->nxt) 77 | { indent--; doindent(); indent++; printf("::\n"); 78 | repro_seq(h->this); 79 | printf("\n"); 80 | } 81 | 82 | switch (e->n->ntyp) { 83 | case DO: indent--; doindent(); printf("od;\n"); break; 84 | case IF: indent--; doindent(); printf("fi;\n"); break; 85 | } 86 | } else 87 | { if (e->n->ntyp == ATOMIC 88 | || e->n->ntyp == D_STEP 89 | || e->n->ntyp == NON_ATOMIC) 90 | repro_sub(e); 91 | else if (e->n->ntyp != '.' 92 | && e->n->ntyp != '@' 93 | && e->n->ntyp != BREAK) 94 | { 95 | doindent(); 96 | if (e->n->ntyp == C_CODE) 97 | { printf("c_code "); 98 | plunk_inline(stdout, e->n->sym->name, 1, 1); 99 | } else if (e->n->ntyp == 'c' 100 | && e->n->lft->ntyp == C_EXPR) 101 | { printf("c_expr { "); 102 | plunk_expr(stdout, e->n->lft->sym->name); 103 | printf("} ->\n"); 104 | } else 105 | { comment(stdout, e->n, 0); 106 | printf(";\n"); 107 | } } 108 | } 109 | if (e == s->last) 110 | break; 111 | } 112 | } 113 | 114 | void 115 | repro_proc(ProcList *p) 116 | { 117 | if (!p) return; 118 | if (p->nxt) repro_proc(p->nxt); 119 | 120 | if (p->det) printf("D"); /* deterministic */ 121 | printf("proctype %s()", p->n->name); 122 | if (p->prov) 123 | { printf(" provided "); 124 | comment(stdout, p->prov, 0); 125 | } 126 | printf("\n{\n"); 127 | repro_seq(p->s); 128 | printf("}\n"); 129 | } 130 | 131 | void 132 | repro_src(void) 133 | { 134 | repro_proc(rdy); 135 | } 136 | 137 | static int in_decl; 138 | static int in_c_decl; 139 | static int in_c_code; 140 | 141 | void 142 | blip(int n, char *b) 143 | { char mtxt[1024]; 144 | 145 | strcpy(mtxt, ""); 146 | 147 | switch (n) { 148 | default: if (n > 0 && n < 256) 149 | sprintf(mtxt, "%c", n); 150 | else 151 | sprintf(mtxt, "<%d?>", n); 152 | 153 | break; 154 | case '(': strcpy(mtxt, "("); in_decl++; break; 155 | case ')': strcpy(mtxt, ")"); in_decl--; break; 156 | case '{': strcpy(mtxt, "{"); break; 157 | case '}': strcpy(mtxt, "}"); break; 158 | case '\t': sprintf(mtxt, "\\t"); break; 159 | case '\f': sprintf(mtxt, "\\f"); break; 160 | case '\n': sprintf(mtxt, "\\n"); break; 161 | case '\r': sprintf(mtxt, "\\r"); break; 162 | case 'c': sprintf(mtxt, "condition"); break; 163 | case 's': sprintf(mtxt, "send"); break; 164 | case 'r': sprintf(mtxt, "recv"); break; 165 | case 'R': sprintf(mtxt, "recv poll"); break; 166 | case '@': sprintf(mtxt, "@"); break; 167 | case '?': sprintf(mtxt, "(x->y:z)"); break; 168 | case NEXT: sprintf(mtxt, "X"); break; 169 | case ALWAYS: sprintf(mtxt, "[]"); break; 170 | case EVENTUALLY: sprintf(mtxt, "<>"); break; 171 | case IMPLIES: sprintf(mtxt, "->"); break; 172 | case EQUIV: sprintf(mtxt, "<->"); break; 173 | case UNTIL: sprintf(mtxt, "U"); break; 174 | case WEAK_UNTIL: sprintf(mtxt, "W"); break; 175 | case IN: sprintf(mtxt, "in"); break; 176 | case ACTIVE: sprintf(mtxt, "active"); break; 177 | case AND: sprintf(mtxt, "&&"); break; 178 | case ARROW: sprintf(mtxt, "->"); break; 179 | case ASGN: sprintf(mtxt, "="); break; 180 | case ASSERT: sprintf(mtxt, "assert"); break; 181 | case ATOMIC: sprintf(mtxt, "atomic"); break; 182 | case BREAK: sprintf(mtxt, "break"); break; 183 | case C_CODE: sprintf(mtxt, "c_code"); in_c_code++; break; 184 | case C_DECL: sprintf(mtxt, "c_decl"); in_c_decl++; break; 185 | case C_EXPR: sprintf(mtxt, "c_expr"); break; 186 | case C_STATE: sprintf(mtxt, "c_state"); break; 187 | case C_TRACK: sprintf(mtxt, "c_track"); break; 188 | case CLAIM: sprintf(mtxt, "never"); break; 189 | case CONST: sprintf(mtxt, "%d", yylval->val); break; 190 | case DECR: sprintf(mtxt, "--"); break; 191 | case D_STEP: sprintf(mtxt, "d_step"); break; 192 | case D_PROCTYPE: sprintf(mtxt, "d_proctype"); break; 193 | case DO: sprintf(mtxt, "do"); break; 194 | case DOT: sprintf(mtxt, "."); break; 195 | case ELSE: sprintf(mtxt, "else"); break; 196 | case EMPTY: sprintf(mtxt, "empty"); break; 197 | case ENABLED: sprintf(mtxt, "enabled"); break; 198 | case EQ: sprintf(mtxt, "=="); break; 199 | case EVAL: sprintf(mtxt, "eval"); break; 200 | case FI: sprintf(mtxt, "fi"); break; 201 | case FULL: sprintf(mtxt, "full"); break; 202 | case GE: sprintf(mtxt, ">="); break; 203 | case GET_P: sprintf(mtxt, "get_priority"); break; 204 | case GOTO: sprintf(mtxt, "goto"); break; 205 | case GT: sprintf(mtxt, ">"); break; 206 | case HIDDEN: sprintf(mtxt, "hidden"); break; 207 | case IF: sprintf(mtxt, "if"); break; 208 | case INCR: sprintf(mtxt, "++"); break; 209 | 210 | case INLINE: sprintf(mtxt, "inline"); break; 211 | case INIT: sprintf(mtxt, "init"); break; 212 | case ISLOCAL: sprintf(mtxt, "local"); break; 213 | 214 | case LABEL: sprintf(mtxt, ""); break; 215 | 216 | case LE: sprintf(mtxt, "<="); break; 217 | case LEN: sprintf(mtxt, "len"); break; 218 | case LSHIFT: sprintf(mtxt, "<<"); break; 219 | case LT: sprintf(mtxt, "<"); break; 220 | case LTL: sprintf(mtxt, "ltl"); break; 221 | 222 | case NAME: sprintf(mtxt, "%s", yylval->sym->name); break; 223 | 224 | case XU: switch (yylval->val) { 225 | case XR: sprintf(mtxt, "xr"); break; 226 | case XS: sprintf(mtxt, "xs"); break; 227 | default: sprintf(mtxt, ""); break; 228 | } 229 | break; 230 | 231 | case TYPE: switch (yylval->val) { 232 | case BIT: sprintf(mtxt, "bit"); break; 233 | case BYTE: sprintf(mtxt, "byte"); break; 234 | case CHAN: sprintf(mtxt, "chan"); in_decl++; break; 235 | case INT: sprintf(mtxt, "int"); break; 236 | case MTYPE: sprintf(mtxt, "mtype"); break; 237 | case SHORT: sprintf(mtxt, "short"); break; 238 | case UNSIGNED: sprintf(mtxt, "unsigned"); break; 239 | default: sprintf(mtxt, ""); break; 240 | } 241 | break; 242 | 243 | case NE: sprintf(mtxt, "!="); break; 244 | case NEG: sprintf(mtxt, "!"); break; 245 | case NEMPTY: sprintf(mtxt, "nempty"); break; 246 | case NFULL: sprintf(mtxt, "nfull"); break; 247 | 248 | case NON_ATOMIC: sprintf(mtxt, ""); break; 249 | 250 | case NONPROGRESS: sprintf(mtxt, "np_"); break; 251 | case OD: sprintf(mtxt, "od"); break; 252 | case OF: sprintf(mtxt, "of"); break; 253 | case OR: sprintf(mtxt, "||"); break; 254 | case O_SND: sprintf(mtxt, "!!"); break; 255 | case PC_VAL: sprintf(mtxt, "pc_value"); break; 256 | case PRINT: sprintf(mtxt, "printf"); break; 257 | case PRINTM: sprintf(mtxt, "printm"); break; 258 | case PRIORITY: sprintf(mtxt, "priority"); break; 259 | case PROCTYPE: sprintf(mtxt, "proctype"); break; 260 | case PROVIDED: sprintf(mtxt, "provided"); break; 261 | case RCV: sprintf(mtxt, "?"); break; 262 | case R_RCV: sprintf(mtxt, "??"); break; 263 | case RSHIFT: sprintf(mtxt, ">>"); break; 264 | case RUN: sprintf(mtxt, "run"); break; 265 | case SEP: sprintf(mtxt, "::"); break; 266 | case SEMI: sprintf(mtxt, ";"); break; 267 | case SET_P: sprintf(mtxt, "set_priority"); break; 268 | case SHOW: sprintf(mtxt, "show"); break; 269 | case SND: sprintf(mtxt, "!"); break; 270 | 271 | case INAME: 272 | case UNAME: 273 | case PNAME: 274 | case STRING: sprintf(mtxt, "%s", yylval->sym->name); break; 275 | 276 | case TRACE: sprintf(mtxt, "trace"); break; 277 | case TIMEOUT: sprintf(mtxt, "timeout"); break; 278 | case TYPEDEF: sprintf(mtxt, "typedef"); break; 279 | case UMIN: sprintf(mtxt, "-"); break; 280 | case UNLESS: sprintf(mtxt, "unless"); break; 281 | } 282 | strcat(b, mtxt); 283 | } 284 | 285 | void 286 | purge(char *b) 287 | { 288 | if (strlen(b) == 0) return; 289 | 290 | if (b[strlen(b)-1] != ':') /* label? */ 291 | { if (b[0] == ':' && b[1] == ':') 292 | { indent--; 293 | doindent(); 294 | indent++; 295 | } else 296 | { doindent(); 297 | } 298 | } 299 | printf("%s\n", b); 300 | strcpy(b, ""); 301 | 302 | in_decl = 0; 303 | in_c_code = 0; 304 | in_c_decl = 0; 305 | } 306 | 307 | int pp_mode; 308 | extern int lex(void); 309 | 310 | void 311 | pretty_print(void) 312 | { int c, lastc = 0; 313 | char buf[1024]; 314 | 315 | pp_mode = 1; 316 | indent = 0; 317 | strcpy(buf, ""); 318 | while ((c = lex()) != EOF) 319 | { 320 | if ((lastc == IF || lastc == DO) && c != SEP) 321 | { indent--; /* c_code if */ 322 | } 323 | if (c == C_DECL || c == C_STATE 324 | || c == C_TRACK || c == SEP 325 | || c == DO || c == IF 326 | || (c == TYPE && !in_decl)) 327 | { purge(buf); /* start on new line */ 328 | } 329 | 330 | if (c == '{' 331 | && lastc != OF && lastc != IN 332 | && lastc != ATOMIC && lastc != D_STEP 333 | && lastc != C_CODE && lastc != C_DECL && lastc != C_EXPR) 334 | { purge(buf); 335 | } 336 | 337 | if (c == PREPROC) 338 | { int oi = indent; 339 | purge(buf); 340 | assert(strlen(yylval->sym->name) < sizeof(buf)); 341 | strcpy(buf, yylval->sym->name); 342 | indent = 0; 343 | purge(buf); 344 | indent = oi; 345 | continue; 346 | } 347 | 348 | if (c != ':' && c != SEMI 349 | && c != ',' && c != '(' 350 | && c != '#' && lastc != '#' 351 | && c != ARROW && lastc != ARROW 352 | && c != '.' && lastc != '.' 353 | && c != '!' && lastc != '!' 354 | && c != SND && lastc != SND 355 | && c != RCV && lastc != RCV 356 | && c != O_SND && lastc != O_SND 357 | && c != R_RCV && lastc != R_RCV 358 | && (c != ']' || lastc != '[') 359 | && (c != '>' || lastc != '<') 360 | && (c != GT || lastc != LT) 361 | && c != '@' && lastc != '@' 362 | && c != DO && c != OD && c != IF && c != FI 363 | && c != SEP && strlen(buf) > 0) 364 | strcat(buf, " "); 365 | 366 | if (c == '}' || c == OD || c == FI) 367 | { purge(buf); 368 | indent--; 369 | } 370 | blip(c, buf); 371 | 372 | if (c == '{' || c == DO || c == IF) 373 | { purge(buf); 374 | indent++; 375 | } 376 | 377 | if (c == '}' || c == BREAK || c == SEMI 378 | || (c == ':' && lastc == NAME)) 379 | { purge(buf); 380 | } 381 | lastc = c; 382 | } 383 | purge(buf); 384 | } 385 | -------------------------------------------------------------------------------- /dstep.c: -------------------------------------------------------------------------------- 1 | /***** spin: dstep.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | */ 8 | 9 | #include 10 | #include "spin.h" 11 | #include "y.tab.h" 12 | 13 | #define MAXDSTEP 2048 /* was 512 */ 14 | 15 | char *NextLab[64]; /* must match value in pangen2.c:41 */ 16 | int Level=0, GenCode=0, IsGuard=0, TestOnly=0; 17 | 18 | static int Tj=0, Jt=0, LastGoto=0; 19 | static int Tojump[MAXDSTEP], Jumpto[MAXDSTEP], Special[MAXDSTEP]; 20 | static void putCode(FILE *, Element *, Element *, Element *, int); 21 | 22 | extern int Pid, separate, OkBreak; 23 | 24 | static void 25 | Sourced(int n, int special) 26 | { int i; 27 | for (i = 0; i < Tj; i++) 28 | if (Tojump[i] == n) 29 | return; 30 | if (Tj >= MAXDSTEP) 31 | fatal("d_step sequence too long", (char *)0); 32 | Special[Tj] = special; 33 | Tojump[Tj++] = n; 34 | } 35 | 36 | static void 37 | Dested(int n) 38 | { int i; 39 | for (i = 0; i < Tj; i++) 40 | if (Tojump[i] == n) 41 | return; 42 | for (i = 0; i < Jt; i++) 43 | if (Jumpto[i] == n) 44 | return; 45 | if (Jt >= MAXDSTEP) 46 | fatal("d_step sequence too long", (char *)0); 47 | Jumpto[Jt++] = n; 48 | LastGoto = 1; 49 | } 50 | 51 | static void 52 | Mopup(FILE *fd) 53 | { int i, j; 54 | 55 | for (i = 0; i < Jt; i++) 56 | { for (j = 0; j < Tj; j++) 57 | if (Tojump[j] == Jumpto[i]) 58 | break; 59 | if (j == Tj) 60 | { char buf[16]; 61 | if (Jumpto[i] == OkBreak) 62 | { if (!LastGoto) 63 | fprintf(fd, "S_%.3d_0: /* break-dest */\n", 64 | OkBreak); 65 | } else { 66 | sprintf(buf, "S_%.3d_0", Jumpto[i]); 67 | non_fatal("goto %s breaks from d_step seq", buf); 68 | } } } 69 | for (j = 0; j < Tj; j++) 70 | { for (i = 0; i < Jt; i++) 71 | if (Tojump[j] == Jumpto[i]) 72 | break; 73 | #ifdef DEBUG 74 | if (i == Jt && !Special[i]) 75 | fprintf(fd, "\t\t/* no goto's to S_%.3d_0 */\n", 76 | Tojump[j]); 77 | #endif 78 | } 79 | for (j = i = 0; j < Tj; j++) 80 | if (Special[j]) 81 | { if (i >= MAXDSTEP) 82 | { fatal("cannot happen (dstep.c)", (char *)0); 83 | } 84 | Tojump[i] = Tojump[j]; 85 | Special[i] = 2; 86 | i++; 87 | } 88 | Tj = i; /* keep only the global exit-labels */ 89 | Jt = 0; 90 | } 91 | 92 | static int 93 | FirstTime(int n) 94 | { int i; 95 | for (i = 0; i < Tj; i++) 96 | if (Tojump[i] == n) 97 | return (Special[i] <= 1); 98 | return 1; 99 | } 100 | 101 | static void 102 | illegal(Element *e, char *str) 103 | { 104 | printf("illegal operator in 'd_step:' '"); 105 | comment(stdout, e->n, 0); 106 | printf("'\n"); 107 | fatal("'%s'", str); 108 | } 109 | 110 | static void 111 | filterbad(Element *e) 112 | { 113 | switch (e->n->ntyp) { 114 | case ASSERT: 115 | case PRINT: 116 | case 'c': 117 | /* run cannot be completely undone 118 | * with sv_save-sv_restor 119 | */ 120 | if (any_oper(e->n->lft, RUN)) 121 | illegal(e, "run operator in d_step"); 122 | 123 | /* remote refs inside d_step sequences 124 | * would be okay, but they cannot always 125 | * be interpreted by the simulator the 126 | * same as by the verifier (e.g., for an 127 | * error trail) 128 | */ 129 | if (any_oper(e->n->lft, 'p')) 130 | illegal(e, "remote reference in d_step"); 131 | break; 132 | case '@': 133 | illegal(e, "process termination"); 134 | break; 135 | case D_STEP: 136 | illegal(e, "nested d_step sequence"); 137 | break; 138 | case ATOMIC: 139 | illegal(e, "nested atomic sequence"); 140 | break; 141 | default: 142 | break; 143 | } 144 | } 145 | 146 | static int 147 | CollectGuards(FILE *fd, Element *e, int inh) 148 | { SeqList *h; Element *ee; 149 | 150 | for (h = e->sub; h; h = h->nxt) 151 | { ee = huntstart(h->this->frst); 152 | filterbad(ee); 153 | switch (ee->n->ntyp) { 154 | case NON_ATOMIC: 155 | inh += CollectGuards(fd, ee->n->sl->this->frst, inh); 156 | break; 157 | case IF: 158 | inh += CollectGuards(fd, ee, inh); 159 | break; 160 | case '.': 161 | if (ee->nxt->n->ntyp == DO) 162 | inh += CollectGuards(fd, ee->nxt, inh); 163 | break; 164 | case ELSE: 165 | if (inh++ > 0) fprintf(fd, " || "); 166 | /* 4.2.5 */ if (!pid_is_claim(Pid)) 167 | fprintf(fd, "(boq == -1 /* else */)"); 168 | else 169 | fprintf(fd, "(1 /* else */)"); 170 | break; 171 | case 'R': 172 | if (inh++ > 0) fprintf(fd, " || "); 173 | fprintf(fd, "("); TestOnly=1; 174 | putstmnt(fd, ee->n, ee->seqno); 175 | fprintf(fd, ")"); TestOnly=0; 176 | break; 177 | case 'r': 178 | if (inh++ > 0) fprintf(fd, " || "); 179 | fprintf(fd, "("); TestOnly=1; 180 | putstmnt(fd, ee->n, ee->seqno); 181 | fprintf(fd, ")"); TestOnly=0; 182 | break; 183 | case 's': 184 | if (inh++ > 0) fprintf(fd, " || "); 185 | fprintf(fd, "("); TestOnly=1; 186 | /* 4.2.1 */ if (!pid_is_claim(Pid)) fprintf(fd, "(boq == -1) && "); 187 | putstmnt(fd, ee->n, ee->seqno); 188 | fprintf(fd, ")"); TestOnly=0; 189 | break; 190 | case 'c': 191 | if (inh++ > 0) fprintf(fd, " || "); 192 | fprintf(fd, "("); TestOnly=1; 193 | if (!pid_is_claim(Pid)) 194 | fprintf(fd, "(boq == -1 && "); 195 | putstmnt(fd, ee->n->lft, e->seqno); 196 | if (!pid_is_claim(Pid)) 197 | fprintf(fd, ")"); 198 | fprintf(fd, ")"); TestOnly=0; 199 | break; 200 | } } 201 | return inh; 202 | } 203 | 204 | int 205 | putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno) 206 | { int isg=0; 207 | static char buf[64]; 208 | 209 | NextLab[0] = "continue"; 210 | filterbad(s->frst); 211 | 212 | switch (s->frst->n->ntyp) { 213 | case UNLESS: 214 | non_fatal("'unless' inside d_step - ignored", (char *) 0); 215 | return putcode(fd, s->frst->n->sl->this, nxt, 0, ln, seqno); 216 | case NON_ATOMIC: 217 | (void) putcode(fd, s->frst->n->sl->this, ZE, 1, ln, seqno); 218 | if (justguards) return 0; /* 6.2.5 */ 219 | break; 220 | case IF: 221 | fprintf(fd, "if (!("); 222 | if (!CollectGuards(fd, s->frst, 0)) /* what about boq? */ 223 | fprintf(fd, "1"); 224 | fprintf(fd, "))\n\t\t\tcontinue;"); 225 | isg = 1; 226 | break; 227 | case '.': 228 | if (s->frst->nxt->n->ntyp == DO) 229 | { fprintf(fd, "if (!("); 230 | if (!CollectGuards(fd, s->frst->nxt, 0)) 231 | fprintf(fd, "1"); 232 | fprintf(fd, "))\n\t\t\tcontinue;"); 233 | isg = 1; 234 | } 235 | break; 236 | case 'R': /* <- can't really happen (it's part of a 'c') */ 237 | fprintf(fd, "if (!("); TestOnly=1; 238 | putstmnt(fd, s->frst->n, s->frst->seqno); 239 | fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0; 240 | break; 241 | case 'r': 242 | fprintf(fd, "if (!("); TestOnly=1; 243 | putstmnt(fd, s->frst->n, s->frst->seqno); 244 | fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0; 245 | break; 246 | case 's': 247 | fprintf(fd, "if ("); 248 | #if 1 249 | /* 4.2.1 */ if (!pid_is_claim(Pid)) fprintf(fd, "(boq != -1) || "); 250 | #endif 251 | fprintf(fd, "!("); TestOnly=1; 252 | putstmnt(fd, s->frst->n, s->frst->seqno); 253 | fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0; 254 | break; 255 | case 'c': 256 | fprintf(fd, "if (!("); 257 | if (!pid_is_claim(Pid)) fprintf(fd, "boq == -1 && "); 258 | TestOnly=1; 259 | putstmnt(fd, s->frst->n->lft, s->frst->seqno); 260 | fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0; 261 | break; 262 | case ELSE: 263 | fprintf(fd, "if (boq != -1 || ("); 264 | if (separate != 2) fprintf(fd, "trpt->"); 265 | fprintf(fd, "o_pm&1))\n\t\t\tcontinue;"); 266 | { extern FILE *th; 267 | fprintf(th, "#ifndef ELSE_IN_GUARD\n"); 268 | fprintf(th, " #define ELSE_IN_GUARD\n"); 269 | fprintf(th, "#endif\n"); 270 | } 271 | break; 272 | case ASGN: /* new 3.0.8 */ 273 | fprintf(fd, "IfNotBlocked"); 274 | break; 275 | default: 276 | fprintf(fd, "/* default %d */\n\t\t", s->frst->n->ntyp); 277 | } 278 | 279 | /* 6.2.5 : before TstOnly */ 280 | fprintf(fd, "\n\n\t\treached[%d][%d] = 1;\n\t\t", Pid, seqno); 281 | fprintf(fd, "reached[%d][t->st] = 1;\n\t\t", Pid); /* next state */ 282 | fprintf(fd, "reached[%d][tt] = 1;\n", Pid); /* current state */ 283 | 284 | /* 6.2.5 : before sv_save() */ 285 | if (s->frst->n->ntyp != NON_ATOMIC) 286 | fprintf(fd, "\n\t\tif (TstOnly) return 1;\n"); /* if called from enabled() */ 287 | 288 | if (justguards) return 0; 289 | 290 | fprintf(fd, "\n\t\tsv_save();\n\t\t"); 291 | sprintf(buf, "Uerror(\"block in d_step seq, line %d\")", ln); 292 | NextLab[0] = buf; 293 | putCode(fd, s->frst, s->extent, nxt, isg); 294 | 295 | if (nxt) 296 | { extern Symbol *Fname; 297 | extern int lineno; 298 | 299 | if (FirstTime(nxt->Seqno) 300 | && (!(nxt->status & DONE2) || !(nxt->status & D_ATOM))) 301 | { fprintf(fd, "S_%.3d_0: /* 1 */\n", nxt->Seqno); 302 | nxt->status |= DONE2; 303 | LastGoto = 0; 304 | } 305 | Sourced(nxt->Seqno, 1); 306 | lineno = ln; 307 | Fname = nxt->n->fn; 308 | Mopup(fd); 309 | } 310 | unskip(s->frst->seqno); 311 | return LastGoto; 312 | } 313 | 314 | static void 315 | putCode(FILE *fd, Element *f, Element *last, Element *next, int isguard) 316 | { Element *e, *N; 317 | SeqList *h; int i; 318 | char NextOpt[64]; 319 | static int bno = 0; 320 | 321 | for (e = f; e; e = e->nxt) 322 | { if (e->status & DONE2) 323 | continue; 324 | e->status |= DONE2; 325 | 326 | if (!(e->status & D_ATOM)) 327 | { if (!LastGoto) 328 | { fprintf(fd, "\t\tgoto S_%.3d_0;\n", 329 | e->Seqno); 330 | Dested(e->Seqno); 331 | } 332 | break; 333 | } 334 | fprintf(fd, "S_%.3d_0: /* 2 */\n", e->Seqno); 335 | LastGoto = 0; 336 | Sourced(e->Seqno, 0); 337 | 338 | if (!e->sub) 339 | { filterbad(e); 340 | switch (e->n->ntyp) { 341 | case NON_ATOMIC: 342 | h = e->n->sl; 343 | putCode(fd, h->this->frst, 344 | h->this->extent, e->nxt, 0); 345 | break; 346 | case BREAK: 347 | if (LastGoto) break; 348 | if (e->nxt) 349 | { i = target( huntele(e->nxt, 350 | e->status, -1))->Seqno; 351 | fprintf(fd, "\t\tgoto S_%.3d_0; ", i); 352 | fprintf(fd, "/* 'break' */\n"); 353 | Dested(i); 354 | } else 355 | { if (next) 356 | { fprintf(fd, "\t\tgoto S_%.3d_0;", 357 | next->Seqno); 358 | fprintf(fd, " /* NEXT */\n"); 359 | Dested(next->Seqno); 360 | } else 361 | fatal("cannot interpret d_step", 0); 362 | } 363 | break; 364 | case GOTO: 365 | if (LastGoto) break; 366 | i = huntele( get_lab(e->n,1), 367 | e->status, -1)->Seqno; 368 | fprintf(fd, "\t\tgoto S_%.3d_0; ", i); 369 | fprintf(fd, "/* 'goto' */\n"); 370 | Dested(i); 371 | break; 372 | case '.': 373 | if (LastGoto) break; 374 | if (e->nxt && (e->nxt->status & DONE2)) 375 | { i = e->nxt->Seqno; 376 | fprintf(fd, "\t\tgoto S_%.3d_0;", i); 377 | fprintf(fd, " /* '.' */\n"); 378 | Dested(i); 379 | } 380 | break; 381 | default: 382 | putskip(e->seqno); 383 | GenCode = 1; IsGuard = isguard; 384 | fprintf(fd, "\t\t"); 385 | putstmnt(fd, e->n, e->seqno); 386 | fprintf(fd, ";\n"); 387 | GenCode = IsGuard = isguard = LastGoto = 0; 388 | break; 389 | } 390 | i = e->nxt?e->nxt->Seqno:0; 391 | if (e->nxt && (e->nxt->status & DONE2) && !LastGoto) 392 | { fprintf(fd, "\t\tgoto S_%.3d_0; ", i); 393 | fprintf(fd, "/* ';' */\n"); 394 | Dested(i); 395 | break; 396 | } 397 | } else 398 | { for (h = e->sub, i=1; h; h = h->nxt, i++) 399 | { sprintf(NextOpt, "goto S_%.3d_%d", 400 | e->Seqno, i); 401 | NextLab[++Level] = NextOpt; 402 | N = (e->n && e->n->ntyp == DO) ? e : e->nxt; 403 | putCode(fd, h->this->frst, 404 | h->this->extent, N, 1); 405 | Level--; 406 | fprintf(fd, "%s: /* 3 */\n", &NextOpt[5]); 407 | LastGoto = 0; 408 | } 409 | if (!LastGoto) 410 | { fprintf(fd, "\t\tUerror(\"blocking sel "); 411 | fprintf(fd, "in d_step (nr.%d, near line %d)\");\n", 412 | bno++, (e->n)?e->n->ln:0); 413 | LastGoto = 0; 414 | } 415 | } 416 | if (e == last) 417 | { if (!LastGoto && next) 418 | { fprintf(fd, "\t\tgoto S_%.3d_0;\n", 419 | next->Seqno); 420 | Dested(next->Seqno); 421 | } 422 | break; 423 | } } 424 | } 425 | -------------------------------------------------------------------------------- /pangen5.h: -------------------------------------------------------------------------------- 1 | /***** spin: pangen5.h *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | */ 8 | 9 | static const char *Xpt[] = { 10 | "#if defined(MA) && (defined(W_XPT) || defined(R_XPT))", 11 | "static Vertex **temptree;", 12 | "static char wbuf[4096];", 13 | "static int WCNT = 4096, wcnt=0;", 14 | "static uchar stacker[MA+1];", 15 | "static ulong stackcnt = 0;", 16 | "extern double nstates, nlinks, truncs, truncs2;", 17 | "", 18 | "static void", 19 | "xwrite(int fd, char *b, int n)", 20 | "{", 21 | " if (wcnt+n >= 4096)", 22 | " { write(fd, wbuf, wcnt);", 23 | " wcnt = 0;", 24 | " }", 25 | " memcpy(&wbuf[wcnt], b, n);", 26 | " wcnt += n;", 27 | "}", 28 | "", 29 | "static void", 30 | "wclose(fd)", 31 | "{", 32 | " if (wcnt > 0)", 33 | " write(fd, wbuf, wcnt);", 34 | " wcnt = 0;", 35 | " close(fd);", 36 | "}", 37 | "", 38 | "static void", 39 | "w_vertex(int fd, Vertex *v)", 40 | "{ char t[3]; int i; Edge *e;", 41 | "", 42 | " xwrite(fd, (char *) &v, sizeof(Vertex *));", 43 | " t[0] = 0;", 44 | " for (i = 0; i < 2; i++)", 45 | " if (v->dst[i])", 46 | " { t[1] = v->from[i], t[2] = v->to[i];", 47 | " xwrite(fd, t, 3);", 48 | " xwrite(fd, (char *) &(v->dst[i]), sizeof(Vertex *));", 49 | " }", 50 | " for (e = v->Succ; e; e = e->Nxt)", 51 | " { t[1] = e->From, t[2] = e->To;", 52 | " xwrite(fd, t, 3);", 53 | " xwrite(fd, (char *) &(e->Dst), sizeof(Vertex *));", 54 | "", 55 | " if (e->s)", 56 | " { t[1] = t[2] = e->S;", 57 | " xwrite(fd, t, 3);", 58 | " xwrite(fd, (char *) &(e->Dst), sizeof(Vertex *));", 59 | " } }", 60 | "}", 61 | "", 62 | "static void", 63 | "w_layer(int fd, Vertex *v)", 64 | "{ uchar c=1;", 65 | "", 66 | " if (!v) return;", 67 | " xwrite(fd, (char *) &c, 1);", 68 | " w_vertex(fd, v);", 69 | " w_layer(fd, v->lnk);", 70 | " w_layer(fd, v->left);", 71 | " w_layer(fd, v->right);", 72 | "}", 73 | "", 74 | "void", 75 | "w_xpoint(void)", 76 | "{ int fd; char nm[64];", 77 | " int i, j; uchar c;", 78 | " static uchar xwarned = 0;", 79 | "", 80 | " sprintf(nm, \"%%s.xpt\", PanSource);", 81 | " if ((fd = creat(nm, 0666)) <= 0)", 82 | " if (!xwarned)", 83 | " { xwarned = 1;", 84 | " printf(\"cannot creat checkpoint file\\n\");", 85 | " return;", 86 | " }", 87 | " xwrite(fd, (char *) &nstates, sizeof(double));", 88 | " xwrite(fd, (char *) &truncs, sizeof(double));", 89 | " xwrite(fd, (char *) &truncs2, sizeof(double));", 90 | " xwrite(fd, (char *) &nlinks, sizeof(double));", 91 | " xwrite(fd, (char *) &dfa_depth, sizeof(int));", 92 | " xwrite(fd, (char *) &R, sizeof(Vertex *));", 93 | " xwrite(fd, (char *) &F, sizeof(Vertex *));", 94 | " xwrite(fd, (char *) &NF, sizeof(Vertex *));", 95 | "", 96 | " for (j = 0; j < TWIDTH; j++)", 97 | " for (i = 0; i < dfa_depth+1; i++)", 98 | " { w_layer(fd, layers[i*TWIDTH+j]);", 99 | " c = 2; xwrite(fd, (char *) &c, 1);", 100 | " }", 101 | " wclose(fd);", 102 | "}", 103 | "", 104 | "static void", 105 | "xread(int fd, char *b, int n)", 106 | "{ int m = wcnt; int delta = 0;", 107 | " if (m < n)", 108 | " { if (m > 0) memcpy(b, &wbuf[WCNT-m], m);", 109 | " delta = m;", 110 | " WCNT = wcnt = read(fd, wbuf, 4096);", 111 | " if (wcnt < n-m)", 112 | " Uerror(\"xread failed -- insufficient data\");", 113 | " n -= m;", 114 | " }", 115 | " memcpy(&b[delta], &wbuf[WCNT-wcnt], n);", 116 | " wcnt -= n;", 117 | "}", 118 | "", 119 | "static void", 120 | "x_cleanup(Vertex *c)", 121 | "{ Edge *e; /* remove the tree and edges from c */", 122 | " if (!c) return;", 123 | " for (e = c->Succ; e; e = e->Nxt)", 124 | " x_cleanup(e->Dst);", 125 | " recyc_vertex(c);", 126 | "}", 127 | "", 128 | "static void", 129 | "x_remove(void)", 130 | "{ Vertex *tmp; int i, s;", 131 | " int r, j;", 132 | " /* double-check: */", 133 | " stacker[dfa_depth-1] = 0; r = dfa_store(stacker);", 134 | " stacker[dfa_depth-1] = 4; j = dfa_member(dfa_depth-1);", 135 | " if (r != 1 || j != 0)", 136 | " { printf(\"%%lu: \", stackcnt);", 137 | " for (i = 0; i < dfa_depth; i++)", 138 | " printf(\"%%d,\", stacker[i]);", 139 | " printf(\" -- not a stackstate \\n\", r, j);", 140 | " return;", 141 | " }", 142 | " stacker[dfa_depth-1] = 1;", 143 | " s = dfa_member(dfa_depth-1);", 144 | "", 145 | " { tmp = F; F = NF; NF = tmp; } /* complement */", 146 | " if (s) dfa_store(stacker);", 147 | " stacker[dfa_depth-1] = 0;", 148 | " dfa_store(stacker);", 149 | " stackcnt++;", 150 | " { tmp = F; F = NF; NF = tmp; }", 151 | "}", 152 | "", 153 | "static void", 154 | "x_rm_stack(Vertex *t, int k)", 155 | "{ int j; Edge *e;", 156 | "", 157 | " if (k == 0)", 158 | " { x_remove();", 159 | " return;", 160 | " }", 161 | " if (t)", 162 | " for (e = t->Succ; e; e = e->Nxt)", 163 | " { for (j = e->From; j <= (int) e->To; j++)", 164 | " { stacker[k] = (uchar) j;", 165 | " x_rm_stack(e->Dst, k-1);", 166 | " }", 167 | " if (e->s)", 168 | " { stacker[k] = e->S;", 169 | " x_rm_stack(e->Dst, k-1);", 170 | " } }", 171 | "}", 172 | "", 173 | "static Vertex *", 174 | "insert_withkey(Vertex *v, int L)", 175 | "{ Vertex *new, *t = temptree[L];", 176 | "", 177 | " if (!t) { temptree[L] = v; return v; }", 178 | " t = splay(v->key, t);", 179 | " if (v->key < t->key)", 180 | " { new = v;", 181 | " new->left = t->left;", 182 | " new->right = t;", 183 | " t->left = (Vertex *) 0;", 184 | " } else if (v->key > t->key)", 185 | " { new = v;", 186 | " new->right = t->right;", 187 | " new->left = t;", 188 | " t->right = (Vertex *) 0;", 189 | " } else", 190 | " { if (t != R && t != F && t != NF)", 191 | " Uerror(\"double insert, bad checkpoint data\");", 192 | " else", 193 | " { recyc_vertex(v);", 194 | " new = t;", 195 | " } }", 196 | " temptree[L] = new;", 197 | "", 198 | " return new;", 199 | "}", 200 | "", 201 | "static Vertex *", 202 | "find_withkey(Vertex *v, int L)", 203 | "{ Vertex *t = temptree[L];", 204 | " if (t)", 205 | " { temptree[L] = t = splay((ulong) v, t);", 206 | " if (t->key == (ulong) v)", 207 | " return t;", 208 | " }", 209 | " Uerror(\"not found error, bad checkpoint data\");", 210 | " return (Vertex *) 0;", 211 | "}", 212 | "", 213 | "void", 214 | "r_layer(int fd, int n)", 215 | "{ Vertex *v;", 216 | " Edge *e;", 217 | " char c, t[2];", 218 | "", 219 | " for (;;)", 220 | " { xread(fd, &c, 1);", 221 | " if (c == 2) break;", 222 | " if (c == 1)", 223 | " { v = new_vertex();", 224 | " xread(fd, (char *) &(v->key), sizeof(Vertex *));", 225 | " v = insert_withkey(v, n);", 226 | " } else /* c == 0 */", 227 | " { e = new_edge((Vertex *) 0);", 228 | " xread(fd, t, 2);", 229 | " e->From = t[0];", 230 | " e->To = t[1];", 231 | " xread(fd, (char *) &(e->Dst), sizeof(Vertex *));", 232 | " insert_edge(v, e);", 233 | " } }", 234 | "}", 235 | "", 236 | "static void", 237 | "v_fix(Vertex *t, int nr)", 238 | "{ int i; Edge *e;", 239 | "", 240 | " if (!t) return;", 241 | "", 242 | " for (i = 0; i < 2; i++)", 243 | " if (t->dst[i])", 244 | " t->dst[i] = find_withkey(t->dst[i], nr);", 245 | "", 246 | " for (e = t->Succ; e; e = e->Nxt)", 247 | " e->Dst = find_withkey(e->Dst, nr);", 248 | " ", 249 | " v_fix(t->left, nr);", 250 | " v_fix(t->right, nr);", 251 | "}", 252 | "", 253 | "static void", 254 | "v_insert(Vertex *t, int nr)", 255 | "{ Edge *e; int i;", 256 | "", 257 | " if (!t) return;", 258 | " v_insert(t->left, nr);", 259 | " v_insert(t->right, nr);", 260 | "", 261 | " /* remove only leafs from temptree */", 262 | " t->left = t->right = t->lnk = (Vertex *) 0;", 263 | " insert_it(t, nr); /* into layers */", 264 | " for (i = 0; i < 2; i++)", 265 | " if (t->dst[i])", 266 | " t->dst[i]->num += (t->to[i] - t->from[i] + 1);", 267 | " for (e = t->Succ; e; e = e->Nxt)", 268 | " e->Dst->num += (e->To - e->From + 1 + e->s);", 269 | "}", 270 | "", 271 | "static void", 272 | "x_fixup(void)", 273 | "{ int i;", 274 | "", 275 | " for (i = 0; i < dfa_depth; i++)", 276 | " v_fix(temptree[i], (i+1));", 277 | "", 278 | " for (i = dfa_depth; i >= 0; i--)", 279 | " v_insert(temptree[i], i);", 280 | "}", 281 | "", 282 | "static Vertex *", 283 | "x_tail(Vertex *t, ulong want)", 284 | "{ int i, yes, no; Edge *e; Vertex *v = (Vertex *) 0;", 285 | "", 286 | " if (!t) return v;", 287 | "", 288 | " yes = no = 0;", 289 | " for (i = 0; i < 2; i++)", 290 | " if ((ulong) t->dst[i] == want)", 291 | " { /* was t->from[i] <= 0 && t->to[i] >= 0 */", 292 | " /* but from and to are uchar */", 293 | " if (t->from[i] == 0)", 294 | " yes = 1;", 295 | " else", 296 | " if (t->from[i] <= 4 && t->to[i] >= 4)", 297 | " no = 1;", 298 | " }", 299 | "", 300 | " for (e = t->Succ; e; e = e->Nxt)", 301 | " if ((ulong) e->Dst == want)", 302 | " { /* was INRANGE(e,0) but From and To are uchar */", 303 | " if ((e->From == 0) || (e->s==1 && e->S==0))", 304 | " yes = 1;", 305 | " else if (INRANGE(e, 4))", 306 | " no = 1;", 307 | " }", 308 | " if (yes && !no) return t;", 309 | " v = x_tail(t->left, want); if (v) return v;", 310 | " v = x_tail(t->right, want); if (v) return v;", 311 | " return (Vertex *) 0;", 312 | "}", 313 | "", 314 | "static void", 315 | "x_anytail(Vertex *t, Vertex *c, int nr)", 316 | "{ int i; Edge *e, *f; Vertex *v;", 317 | "", 318 | " if (!t) return;", 319 | "", 320 | " for (i = 0; i < 2; i++)", 321 | " if ((ulong) t->dst[i] == c->key)", 322 | " { v = new_vertex(); v->key = t->key;", 323 | " f = new_edge(v);", 324 | " f->From = t->from[i];", 325 | " f->To = t->to[i];", 326 | " f->Nxt = c->Succ;", 327 | " c->Succ = f;", 328 | " if (nr > 0)", 329 | " x_anytail(temptree[nr-1], v, nr-1);", 330 | " }", 331 | "", 332 | " for (e = t->Succ; e; e = e->Nxt)", 333 | " if ((ulong) e->Dst == c->key)", 334 | " { v = new_vertex(); v->key = t->key;", 335 | " f = new_edge(v);", 336 | " f->From = e->From;", 337 | " f->To = e->To;", 338 | " f->s = e->s;", 339 | " f->S = e->S;", 340 | " f->Nxt = c->Succ;", 341 | " c->Succ = f;", 342 | " x_anytail(temptree[nr-1], v, nr-1);", 343 | " }", 344 | "", 345 | " x_anytail(t->left, c, nr);", 346 | " x_anytail(t->right, c, nr);", 347 | "}", 348 | "", 349 | "static Vertex *", 350 | "x_cpy_rev(void)", 351 | "{ Vertex *c, *v; /* find 0 and !4 predecessor of F */", 352 | "", 353 | " v = x_tail(temptree[dfa_depth-1], F->key);", 354 | " if (!v) return (Vertex *) 0;", 355 | "", 356 | " c = new_vertex(); c->key = v->key;", 357 | "", 358 | " /* every node on dfa_depth-2 that has v->key as succ */", 359 | " /* make copy and let c point to these (reversing ptrs) */", 360 | "", 361 | " x_anytail(temptree[dfa_depth-2], c, dfa_depth-2);", 362 | " ", 363 | " return c;", 364 | "}", 365 | "", 366 | "void", 367 | "r_xpoint(void)", 368 | "{ int fd; char nm[64]; Vertex *d;", 369 | " int i, j;", 370 | "", 371 | " wcnt = 0;", 372 | " sprintf(nm, \"%%s.xpt\", PanSource);", 373 | " if ((fd = open(nm, 0)) < 0) /* O_RDONLY */", 374 | " Uerror(\"cannot open checkpoint file\");", 375 | "", 376 | " xread(fd, (char *) &nstates, sizeof(double));", 377 | " xread(fd, (char *) &truncs, sizeof(double));", 378 | " xread(fd, (char *) &truncs2, sizeof(double));", 379 | " xread(fd, (char *) &nlinks, sizeof(double));", 380 | " xread(fd, (char *) &dfa_depth, sizeof(int));", 381 | "", 382 | " if (dfa_depth != MA+a_cycles)", 383 | " Uerror(\"bad dfa_depth in checkpoint file\");", 384 | "", 385 | " path = (Vertex **) emalloc((dfa_depth+1)*sizeof(Vertex *));", 386 | " layers = (Vertex **) emalloc(TWIDTH*(dfa_depth+1)*sizeof(Vertex *));", 387 | " temptree = (Vertex **) emalloc((dfa_depth+2)*sizeof(Vertex *));", 388 | " lastword = (uchar *) emalloc((dfa_depth+1)*sizeof(uchar));", 389 | " lastword[dfa_depth] = lastword[0] = 255; ", 390 | "", 391 | " path[0] = R = new_vertex();", 392 | " xread(fd, (char *) &R->key, sizeof(Vertex *));", 393 | " R = insert_withkey(R, 0);", 394 | "", 395 | " F = new_vertex();", 396 | " xread(fd, (char *) &F->key, sizeof(Vertex *));", 397 | " F = insert_withkey(F, dfa_depth);", 398 | "", 399 | " NF = new_vertex();", 400 | " xread(fd, (char *) &NF->key, sizeof(Vertex *));", 401 | " NF = insert_withkey(NF, dfa_depth);", 402 | "", 403 | " for (j = 0; j < TWIDTH; j++)", 404 | " for (i = 0; i < dfa_depth+1; i++)", 405 | " r_layer(fd, i);", 406 | "", 407 | " if (wcnt != 0) Uerror(\"bad count in checkpoint file\");", 408 | "", 409 | " d = x_cpy_rev();", 410 | " x_fixup();", 411 | " stacker[dfa_depth-1] = 0;", 412 | " x_rm_stack(d, dfa_depth-2);", 413 | " x_cleanup(d);", 414 | " close(fd);", 415 | "", 416 | " printf(\"pan: removed %%lu stackstates\\n\", stackcnt);", 417 | " nstates -= (double) stackcnt;", 418 | "}", 419 | "#endif", 420 | 0, 421 | }; 422 | -------------------------------------------------------------------------------- /pangen3.c: -------------------------------------------------------------------------------- 1 | /***** spin: pangen3.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | */ 8 | 9 | #include "spin.h" 10 | #include "y.tab.h" 11 | #include 12 | 13 | extern FILE *th, *tc; 14 | extern int eventmapnr, old_priority_rules; 15 | 16 | typedef struct SRC { 17 | int ln, st; /* linenr, statenr */ 18 | Symbol *fn; /* filename */ 19 | struct SRC *nxt; 20 | } SRC; 21 | 22 | static int col; 23 | static Symbol *lastfnm; 24 | static Symbol lastdef; 25 | static int lastfrom; 26 | static SRC *frst = (SRC *) 0; 27 | static SRC *skip = (SRC *) 0; 28 | 29 | extern int ltl_mode; 30 | 31 | extern void sr_mesg(FILE *, int, int); 32 | 33 | static void 34 | putnr(int n) 35 | { 36 | if (col++ == 8) 37 | { fprintf(tc, "\n\t"); /* was th */ 38 | col = 1; 39 | } 40 | fprintf(tc, "%3d, ", n); /* was th */ 41 | } 42 | 43 | static void 44 | putfnm(int j, Symbol *s) 45 | { 46 | if (lastfnm && lastfnm == s && j != -1) 47 | return; 48 | 49 | if (lastfnm) 50 | fprintf(tc, "{ \"%s\", %d, %d },\n\t", /* was th */ 51 | lastfnm->name, 52 | lastfrom, 53 | j-1); 54 | lastfnm = s; 55 | lastfrom = j; 56 | } 57 | 58 | static void 59 | putfnm_flush(int j) 60 | { 61 | if (lastfnm) 62 | fprintf(tc, "{ \"%s\", %d, %d }\n", /* was th */ 63 | lastfnm->name, 64 | lastfrom, j); 65 | } 66 | 67 | static SRC * 68 | newsrc(int m, SRC *n) 69 | { SRC *tmp; 70 | tmp = (SRC *) emalloc(sizeof(SRC)); 71 | tmp->st = m; 72 | tmp->nxt = n; 73 | return tmp; 74 | } 75 | 76 | void 77 | putskip(int m) /* states that need not be reached */ 78 | { SRC *tmp, *lst = (SRC *)0; 79 | /* 6.4.0: now an ordered list */ 80 | for (tmp = skip; tmp; lst = tmp, tmp = tmp->nxt) 81 | { if (tmp->st == m) 82 | { return; 83 | } 84 | if (tmp->st > m) /* insert before */ 85 | { if (tmp == skip) 86 | { tmp = newsrc(m, skip); 87 | skip = tmp; 88 | } else 89 | { assert(lst); 90 | tmp = newsrc(m, lst->nxt); 91 | lst->nxt = tmp; 92 | } 93 | return; 94 | } } 95 | /* insert at the end */ 96 | if (lst) 97 | { lst->nxt = newsrc(m, 0); 98 | } else /* empty list */ 99 | { skip = newsrc(m, 0); 100 | } 101 | } 102 | 103 | void 104 | unskip(int m) /* a state that needs to be reached after all */ 105 | { SRC *tmp, *lst = (SRC *)0; 106 | 107 | for (tmp = skip; tmp; lst = tmp, tmp = tmp->nxt) 108 | { if (tmp->st == m) 109 | { if (tmp == skip) 110 | skip = skip->nxt; 111 | else if (lst) /* always true, but helps coverity */ 112 | lst->nxt = tmp->nxt; 113 | break; 114 | } 115 | if (tmp->st > m) 116 | { break; /* m is not in list */ 117 | } } 118 | } 119 | 120 | void 121 | putsrc(Element *e) /* match states to source lines */ 122 | { SRC *tmp, *lst = (SRC *)0; 123 | int n, m; 124 | 125 | if (!e || !e->n) return; 126 | 127 | n = e->n->ln; 128 | m = e->seqno; 129 | /* 6.4.0: now an ordered list */ 130 | for (tmp = frst; tmp; lst = tmp, tmp = tmp->nxt) 131 | { if (tmp->st == m) 132 | { if (tmp->ln != n || tmp->fn != e->n->fn) 133 | printf("putsrc mismatch seqno %d, line %d - %d, file %s\n", m, n, 134 | tmp->ln, tmp->fn->name); 135 | return; 136 | } 137 | if (tmp->st > m) /* insert before */ 138 | { if (tmp == frst) 139 | { tmp = newsrc(m, frst); 140 | frst = tmp; 141 | } else 142 | { assert(lst); 143 | tmp = newsrc(m, lst->nxt); 144 | lst->nxt = tmp; 145 | } 146 | tmp->ln = n; 147 | tmp->fn = e->n->fn; 148 | return; 149 | } } 150 | /* insert at the end */ 151 | tmp = newsrc(m, lst?lst->nxt:0); 152 | tmp->ln = n; 153 | tmp->fn = e->n->fn; 154 | if (lst) 155 | { lst->nxt = tmp; 156 | } else 157 | { frst = tmp; 158 | } 159 | } 160 | 161 | static void 162 | dumpskip(int n, int m) 163 | { SRC *tmp, *lst; 164 | FILE *tz = tc; /* was th */ 165 | int j; 166 | 167 | fprintf(tz, "uchar reached%d [] = {\n\t", m); 168 | tmp = skip; 169 | lst = (SRC *) 0; 170 | for (j = 0, col = 0; j <= n; j++) 171 | { /* find j in the sorted list */ 172 | for ( ; tmp; lst = tmp, tmp = tmp->nxt) 173 | { if (tmp->st == j) 174 | { putnr(1); 175 | if (lst) 176 | lst->nxt = tmp->nxt; 177 | else 178 | skip = tmp->nxt; 179 | break; 180 | } 181 | if (tmp->st > j) 182 | { putnr(0); 183 | break; /* j is not in the list */ 184 | } } 185 | 186 | if (!tmp) 187 | { putnr(0); 188 | } } 189 | fprintf(tz, "};\n"); 190 | fprintf(tz, "uchar *loopstate%d;\n", m); 191 | 192 | if (m == eventmapnr) 193 | fprintf(th, "#define reached_event reached%d\n", m); 194 | 195 | skip = (SRC *) 0; 196 | } 197 | 198 | void 199 | dumpsrc(int n, int m) 200 | { SRC *tmp, *lst; 201 | int j; 202 | static int did_claim = 0; 203 | FILE *tz = tc; /* was th */ 204 | 205 | fprintf(tz, "\nshort src_ln%d [] = {\n\t", m); 206 | tmp = frst; 207 | for (j = 0, col = 0; j <= n; j++) 208 | { for ( ; tmp; tmp = tmp->nxt) 209 | { if (tmp->st == j) 210 | { putnr(tmp->ln); 211 | break; 212 | } 213 | if (tmp->st > j) 214 | { putnr(0); 215 | break; 216 | } } 217 | if (!tmp) 218 | { putnr(0); 219 | } } 220 | fprintf(tz, "};\n"); 221 | 222 | lastfnm = (Symbol *) 0; 223 | lastdef.name = "-"; 224 | fprintf(tz, "S_F_MAP src_file%d [] = {\n\t", m); 225 | tmp = frst; 226 | lst = (SRC *) 0; 227 | for (j = 0, col = 0; j <= n; j++) 228 | { for ( ; tmp; lst = tmp, tmp = tmp->nxt) 229 | { if (tmp->st == j) 230 | { putfnm(j, tmp->fn); 231 | if (lst) 232 | lst->nxt = tmp->nxt; 233 | else 234 | frst = tmp->nxt; 235 | break; 236 | } 237 | if (tmp->st > j) 238 | { putfnm(j, &lastdef); 239 | break; 240 | } } 241 | if (!tmp) 242 | { putfnm(j, &lastdef); 243 | } } 244 | putfnm_flush(j); 245 | fprintf(tz, "};\n"); 246 | 247 | if (pid_is_claim(m) && !did_claim) 248 | { fprintf(tz, "short *src_claim;\n"); 249 | did_claim++; 250 | } 251 | if (m == eventmapnr) 252 | fprintf(th, "#define src_event src_ln%d\n", m); 253 | 254 | frst = (SRC *) 0; 255 | dumpskip(n, m); 256 | } 257 | 258 | #define Cat0(x) comwork(fd,now->lft,m); fprintf(fd, x); \ 259 | comwork(fd,now->rgt,m) 260 | #define Cat1(x) fprintf(fd,"("); Cat0(x); fprintf(fd,")") 261 | #define Cat2(x,y) fprintf(fd,x); comwork(fd,y,m) 262 | #define Cat3(x,y,z) fprintf(fd,x); comwork(fd,y,m); fprintf(fd,z) 263 | 264 | static int 265 | symbolic(FILE *fd, Lextok *tv) 266 | { Lextok *n; extern Lextok *Mtype; 267 | int cnt = 1; 268 | 269 | if (tv->ismtyp) 270 | for (n = Mtype; n; n = n->rgt, cnt++) 271 | if (cnt == tv->val) 272 | { fprintf(fd, "%s", n->lft->sym->name); 273 | return 1; 274 | } 275 | return 0; 276 | } 277 | 278 | static void 279 | comwork(FILE *fd, Lextok *now, int m) 280 | { Lextok *v; 281 | int i, j; 282 | 283 | if (!now) { fprintf(fd, "0"); return; } 284 | switch (now->ntyp) { 285 | case CONST: sr_mesg(fd, now->val, now->ismtyp); break; 286 | case '!': Cat3("!(", now->lft, ")"); break; 287 | case UMIN: Cat3("-(", now->lft, ")"); break; 288 | case '~': Cat3("~(", now->lft, ")"); break; 289 | 290 | case '/': Cat1("/"); break; 291 | case '*': Cat1("*"); break; 292 | case '-': Cat1("-"); break; 293 | case '+': Cat1("+"); break; 294 | case '%': Cat1("%%"); break; 295 | case '&': Cat1("&"); break; 296 | case '^': Cat1("^"); break; 297 | case '|': Cat1("|"); break; 298 | case LE: Cat1("<="); break; 299 | case GE: Cat1(">="); break; 300 | case GT: Cat1(">"); break; 301 | case LT: Cat1("<"); break; 302 | case NE: Cat1("!="); break; 303 | case EQ: 304 | if (ltl_mode 305 | && now->lft->ntyp == 'p' 306 | && now->rgt->ntyp == 'q') /* remote ref */ 307 | { Lextok *p = now->lft->lft; 308 | 309 | fprintf(fd, "("); 310 | fprintf(fd, "%s", p->sym->name); 311 | if (p->lft) 312 | { fprintf(fd, "["); 313 | putstmnt(fd, p->lft, 0); /* pid */ 314 | fprintf(fd, "]"); 315 | } 316 | fprintf(fd, "@"); 317 | fprintf(fd, "%s", now->rgt->sym->name); 318 | fprintf(fd, ")"); 319 | break; 320 | } 321 | Cat1("=="); 322 | break; 323 | 324 | case OR: Cat1("||"); break; 325 | case AND: Cat1("&&"); break; 326 | case LSHIFT: Cat1("<<"); break; 327 | case RSHIFT: Cat1(">>"); break; 328 | 329 | case RUN: fprintf(fd, "run %s(", now->sym->name); 330 | for (v = now->lft; v; v = v->rgt) 331 | if (v == now->lft) 332 | { comwork(fd, v->lft, m); 333 | } else 334 | { Cat2(",", v->lft); 335 | } 336 | fprintf(fd, ")"); 337 | break; 338 | 339 | case LEN: putname(fd, "len(", now->lft, m, ")"); 340 | break; 341 | case FULL: putname(fd, "full(", now->lft, m, ")"); 342 | break; 343 | case EMPTY: putname(fd, "empty(", now->lft, m, ")"); 344 | break; 345 | case NFULL: putname(fd, "nfull(", now->lft, m, ")"); 346 | break; 347 | case NEMPTY: putname(fd, "nempty(", now->lft, m, ")"); 348 | break; 349 | 350 | case 's': putname(fd, "", now->lft, m, now->val?"!!":"!"); 351 | for (v = now->rgt, i=0; v; v = v->rgt, i++) 352 | { if (v != now->rgt) fprintf(fd,","); 353 | if (!symbolic(fd, v->lft)) 354 | comwork(fd,v->lft,m); 355 | } 356 | break; 357 | case 'r': putname(fd, "", now->lft, m, "?"); 358 | switch (now->val) { 359 | case 0: break; 360 | case 1: fprintf(fd, "?"); break; 361 | case 2: fprintf(fd, "<"); break; 362 | case 3: fprintf(fd, "?<"); break; 363 | } 364 | for (v = now->rgt, i=0; v; v = v->rgt, i++) 365 | { if (v != now->rgt) fprintf(fd,","); 366 | if (!symbolic(fd, v->lft)) 367 | comwork(fd,v->lft,m); 368 | } 369 | if (now->val >= 2) 370 | fprintf(fd, ">"); 371 | break; 372 | case 'R': putname(fd, "", now->lft, m, now->val?"??[":"?["); 373 | for (v = now->rgt, i=0; v; v = v->rgt, i++) 374 | { if (v != now->rgt) fprintf(fd,","); 375 | if (!symbolic(fd, v->lft)) 376 | comwork(fd,v->lft,m); 377 | } 378 | fprintf(fd, "]"); 379 | break; 380 | 381 | case ENABLED: Cat3("enabled(", now->lft, ")"); 382 | break; 383 | 384 | case GET_P: if (old_priority_rules) 385 | { fprintf(fd, "1"); 386 | } else 387 | { Cat3("get_priority(", now->lft, ")"); 388 | } 389 | break; 390 | 391 | case SET_P: if (!old_priority_rules) 392 | { fprintf(fd, "set_priority("); 393 | comwork(fd, now->lft->lft, m); 394 | fprintf(fd, ", "); 395 | comwork(fd, now->lft->rgt, m); 396 | fprintf(fd, ")"); 397 | } 398 | break; 399 | 400 | case EVAL: Cat3("eval(", now->lft, ")"); 401 | break; 402 | 403 | case NONPROGRESS: 404 | fprintf(fd, "np_"); 405 | break; 406 | 407 | case PC_VAL: Cat3("pc_value(", now->lft, ")"); 408 | break; 409 | 410 | case 'c': Cat3("(", now->lft, ")"); 411 | break; 412 | 413 | case '?': if (now->lft) 414 | { Cat3("( (", now->lft, ") -> "); 415 | } 416 | if (now->rgt) 417 | { Cat3("(", now->rgt->lft, ") : "); 418 | Cat3("(", now->rgt->rgt, ") )"); 419 | } 420 | break; 421 | 422 | case ASGN: 423 | if (check_track(now) == STRUCT) { break; } 424 | comwork(fd,now->lft,m); 425 | fprintf(fd," = "); 426 | comwork(fd,now->rgt,m); 427 | break; 428 | 429 | case PRINT: { char c, buf[1024]; 430 | strncpy(buf, now->sym->name, 510); 431 | for (i = j = 0; i < 510; i++, j++) 432 | { c = now->sym->name[i]; 433 | buf[j] = c; 434 | if (c == '\\') buf[++j] = c; 435 | if (c == '\"') buf[j] = '\''; 436 | if (c == '\0') break; 437 | } 438 | if (now->ntyp == PRINT) 439 | fprintf(fd, "printf"); 440 | else 441 | fprintf(fd, "annotate"); 442 | fprintf(fd, "(%s", buf); 443 | } 444 | for (v = now->lft; v; v = v->rgt) 445 | { Cat2(",", v->lft); 446 | } 447 | fprintf(fd, ")"); 448 | break; 449 | case PRINTM: fprintf(fd, "printm("); 450 | comwork(fd, now->lft, m); 451 | fprintf(fd, ")"); 452 | break; 453 | case NAME: 454 | putname(fd, "", now, m, ""); 455 | break; 456 | 457 | case 'p': 458 | if (ltl_mode) 459 | { fprintf(fd, "%s", now->lft->sym->name); /* proctype */ 460 | if (now->lft->lft) 461 | { fprintf(fd, "["); 462 | putstmnt(fd, now->lft->lft, 0); /* pid */ 463 | fprintf(fd, "]"); 464 | } 465 | fprintf(fd, ":"); /* remote varref */ 466 | fprintf(fd, "%s", now->sym->name); /* varname */ 467 | break; 468 | } 469 | putremote(fd, now, m); 470 | break; 471 | case 'q': fprintf(fd, "%s", now->sym->name); 472 | break; 473 | case C_EXPR: 474 | case C_CODE: fprintf(fd, "{%s}", now->sym->name); 475 | break; 476 | case ASSERT: Cat3("assert(", now->lft, ")"); 477 | break; 478 | case '.': fprintf(fd, ".(goto)"); break; 479 | case GOTO: fprintf(fd, "goto %s", now->sym->name); break; 480 | case BREAK: fprintf(fd, "break"); break; 481 | case ELSE: fprintf(fd, "else"); break; 482 | case '@': fprintf(fd, "-end-"); break; 483 | 484 | case D_STEP: fprintf(fd, "D_STEP%d", now->ln); break; 485 | case ATOMIC: fprintf(fd, "ATOMIC"); break; 486 | case NON_ATOMIC: fprintf(fd, "sub-sequence"); break; 487 | case IF: fprintf(fd, "IF"); break; 488 | case DO: fprintf(fd, "DO"); break; 489 | case UNLESS: fprintf(fd, "unless"); break; 490 | case TIMEOUT: fprintf(fd, "timeout"); break; 491 | default: if (isprint(now->ntyp)) 492 | fprintf(fd, "'%c'", now->ntyp); 493 | else 494 | fprintf(fd, "%d", now->ntyp); 495 | break; 496 | } 497 | } 498 | 499 | void 500 | comment(FILE *fd, Lextok *now, int m) 501 | { extern short terse, nocast; 502 | 503 | terse=nocast=1; 504 | comwork(fd, now, m); 505 | terse=nocast=0; 506 | } 507 | -------------------------------------------------------------------------------- /spin.h: -------------------------------------------------------------------------------- 1 | /***** spin: spin.h *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | */ 8 | 9 | #ifndef SEEN_SPIN_H 10 | #define SEEN_SPIN_H 11 | 12 | #include 13 | #include 14 | #include 15 | #if !defined(WIN32) && !defined(WIN64) 16 | #include 17 | #endif 18 | #ifndef PC 19 | #include 20 | #endif 21 | 22 | enum { INIV, PUTV, LOGV }; /* used in pangen1.c */ 23 | enum btypes { NONE, N_CLAIM, I_PROC, A_PROC, P_PROC, E_TRACE, N_TRACE }; 24 | 25 | typedef struct Lextok { 26 | unsigned short ntyp; /* node type */ 27 | short ismtyp; /* CONST derived from MTYP */ 28 | int val; /* value attribute */ 29 | int ln; /* line number */ 30 | int indstep; /* part of d_step sequence */ 31 | int uiid; /* inline id, if non-zero */ 32 | struct Symbol *fn; /* file name */ 33 | struct Symbol *sym; /* symbol reference */ 34 | struct Sequence *sq; /* sequence */ 35 | struct SeqList *sl; /* sequence list */ 36 | struct Lextok *lft, *rgt; /* children in parse tree */ 37 | } Lextok; 38 | 39 | typedef struct Slicer { 40 | Lextok *n; /* global var, usable as slice criterion */ 41 | short code; /* type of use: DEREF_USE or normal USE */ 42 | short used; /* set when handled */ 43 | struct Slicer *nxt; /* linked list */ 44 | } Slicer; 45 | 46 | typedef struct Access { 47 | struct Symbol *who; /* proctype name of accessor */ 48 | struct Symbol *what; /* proctype name of accessed */ 49 | int cnt, typ; /* parameter nr and, e.g., 's' or 'r' */ 50 | struct Access *lnk; /* linked list */ 51 | } Access; 52 | 53 | typedef struct Symbol { 54 | char *name; 55 | int Nid; /* unique number for the name */ 56 | unsigned short type; /* bit,short,.., chan,struct */ 57 | unsigned char hidden; /* bit-flags: 58 | 1=hide, 2=show, 59 | 4=bit-equiv, 8=byte-equiv, 60 | 16=formal par, 32=inline par, 61 | 64=treat as if local; 128=read at least once 62 | */ 63 | unsigned char colnr; /* for use with xspin during simulation */ 64 | unsigned char isarray; /* set if decl specifies array bound */ 65 | unsigned char *bscp; /* block scope */ 66 | int sc; /* scope seq no -- set only for proctypes */ 67 | int nbits; /* optional width specifier */ 68 | int nel; /* 1 if scalar, >1 if array */ 69 | int setat; /* last depth value changed */ 70 | int *val; /* runtime value(s), initl 0 */ 71 | Lextok **Sval; /* values for structures */ 72 | 73 | int xu; /* exclusive r or w by 1 pid */ 74 | struct Symbol *xup[2]; /* xr or xs proctype */ 75 | struct Access *access;/* e.g., senders and receives of chan */ 76 | Lextok *ini; /* initial value, or chan-def */ 77 | Lextok *Slst; /* template for structure if struct */ 78 | struct Symbol *Snm; /* name of the defining struct */ 79 | struct Symbol *owner; /* set for names of subfields in typedefs */ 80 | struct Symbol *context; /* 0 if global, or procname */ 81 | struct Symbol *next; /* linked list */ 82 | } Symbol; 83 | 84 | typedef struct Ordered { /* links all names in Symbol table */ 85 | struct Symbol *entry; 86 | struct Ordered *next; 87 | } Ordered; 88 | 89 | typedef struct Queue { 90 | short qid; /* runtime q index */ 91 | int qlen; /* nr messages stored */ 92 | int nslots, nflds; /* capacity, flds/slot */ 93 | int setat; /* last depth value changed */ 94 | int *fld_width; /* type of each field */ 95 | int *contents; /* the values stored */ 96 | int *stepnr; /* depth when each msg was sent */ 97 | struct Queue *nxt; /* linked list */ 98 | } Queue; 99 | 100 | typedef struct FSM_state { /* used in pangen5.c - dataflow */ 101 | int from; /* state number */ 102 | int seen; /* used for dfs */ 103 | int in; /* nr of incoming edges */ 104 | int cr; /* has reachable 1-relevant successor */ 105 | int scratch; 106 | unsigned long *dom, *mod; /* to mark dominant nodes */ 107 | struct FSM_trans *t; /* outgoing edges */ 108 | struct FSM_trans *p; /* incoming edges, predecessors */ 109 | struct FSM_state *nxt; /* linked list of all states */ 110 | } FSM_state; 111 | 112 | typedef struct FSM_trans { /* used in pangen5.c - dataflow */ 113 | int to; 114 | short relevant; /* when sliced */ 115 | short round; /* ditto: iteration when marked */ 116 | struct FSM_use *Val[2]; /* 0=reads, 1=writes */ 117 | struct Element *step; 118 | struct FSM_trans *nxt; 119 | } FSM_trans; 120 | 121 | typedef struct FSM_use { /* used in pangen5.c - dataflow */ 122 | Lextok *n; 123 | Symbol *var; 124 | int special; 125 | struct FSM_use *nxt; 126 | } FSM_use; 127 | 128 | typedef struct Element { 129 | Lextok *n; /* defines the type & contents */ 130 | int Seqno; /* identifies this el within system */ 131 | int seqno; /* identifies this el within a proc */ 132 | int merge; /* set by -O if step can be merged */ 133 | int merge_start; 134 | int merge_single; 135 | short merge_in; /* nr of incoming edges */ 136 | short merge_mark; /* state was generated in merge sequence */ 137 | unsigned int status; /* used by analyzer generator */ 138 | struct FSM_use *dead; /* optional dead variable list */ 139 | struct SeqList *sub; /* subsequences, for compounds */ 140 | struct SeqList *esc; /* zero or more escape sequences */ 141 | struct Element *Nxt; /* linked list - for global lookup */ 142 | struct Element *nxt; /* linked list - program structure */ 143 | } Element; 144 | 145 | typedef struct Sequence { 146 | Element *frst; 147 | Element *last; /* links onto continuations */ 148 | Element *extent; /* last element in original */ 149 | int minel; /* minimum Seqno, set and used only in guided.c */ 150 | int maxel; /* 1+largest id in sequence */ 151 | } Sequence; 152 | 153 | typedef struct SeqList { 154 | Sequence *this; /* one sequence */ 155 | struct SeqList *nxt; /* linked list */ 156 | } SeqList; 157 | 158 | typedef struct Label { 159 | Symbol *s; 160 | Symbol *c; 161 | Element *e; 162 | int uiid; /* non-zero if label appears in an inline */ 163 | int visible; /* label referenced in claim (slice relevant) */ 164 | struct Label *nxt; 165 | } Label; 166 | 167 | typedef struct Lbreak { 168 | Symbol *l; 169 | struct Lbreak *nxt; 170 | } Lbreak; 171 | 172 | typedef struct L_List { 173 | Lextok *n; 174 | struct L_List *nxt; 175 | } L_List; 176 | 177 | typedef struct RunList { 178 | Symbol *n; /* name */ 179 | int tn; /* ordinal of type */ 180 | int pid; /* process id */ 181 | int priority; /* for simulations only */ 182 | enum btypes b; /* the type of process */ 183 | Element *pc; /* current stmnt */ 184 | Sequence *ps; /* used by analyzer generator */ 185 | Lextok *prov; /* provided clause */ 186 | Symbol *symtab; /* local variables */ 187 | struct RunList *nxt; /* linked list */ 188 | } RunList; 189 | 190 | typedef struct ProcList { 191 | Symbol *n; /* name */ 192 | Lextok *p; /* parameters */ 193 | Sequence *s; /* body */ 194 | Lextok *prov; /* provided clause */ 195 | enum btypes b; /* e.g., claim, trace, proc */ 196 | short tn; /* ordinal number */ 197 | unsigned char det; /* deterministic */ 198 | unsigned char unsafe; /* contains global var inits */ 199 | unsigned char priority; /* process priority, if any */ 200 | struct ProcList *nxt; /* linked list */ 201 | } ProcList; 202 | 203 | typedef struct QH { 204 | int n; 205 | struct QH *nxt; 206 | } QH; 207 | 208 | typedef Lextok *Lexptr; 209 | 210 | #define YYSTYPE Lexptr 211 | 212 | #define ZN (Lextok *)0 213 | #define ZS (Symbol *)0 214 | #define ZE (Element *)0 215 | 216 | #define DONE 1 /* status bits of elements */ 217 | #define ATOM 2 /* part of an atomic chain */ 218 | #define L_ATOM 4 /* last element in a chain */ 219 | #define I_GLOB 8 /* inherited global ref */ 220 | #define DONE2 16 /* used in putcode and main*/ 221 | #define D_ATOM 32 /* deterministic atomic */ 222 | #define ENDSTATE 64 /* normal endstate */ 223 | #define CHECK2 128 /* status bits for remote ref check */ 224 | #define CHECK3 256 /* status bits for atomic jump check */ 225 | 226 | #define Nhash 255 /* slots in symbol hash-table */ 227 | 228 | #define XR 1 /* non-shared receive-only */ 229 | #define XS 2 /* non-shared send-only */ 230 | #define XX 4 /* overrides XR or XS tag */ 231 | 232 | #define CODE_FRAG 2 /* auto-numbered code-fragment */ 233 | #define CODE_DECL 4 /* auto-numbered c_decl */ 234 | #define PREDEF 3 /* predefined name: _p, _last */ 235 | 236 | #define UNSIGNED 5 /* val defines width in bits */ 237 | #define BIT 1 /* also equal to width in bits */ 238 | #define BYTE 8 /* ditto */ 239 | #define SHORT 16 /* ditto */ 240 | #define INT 32 /* ditto */ 241 | #define CHAN 64 /* not */ 242 | #define STRUCT 128 /* user defined structure name */ 243 | 244 | #define SOMETHINGBIG 65536 245 | #define RATHERSMALL 512 246 | #define MAXSCOPESZ 1024 247 | 248 | #ifndef max 249 | #define max(a,b) (((a)<(b)) ? (b) : (a)) 250 | #endif 251 | 252 | #ifdef PC 253 | #define MFLAGS "wb" 254 | #else 255 | #define MFLAGS "w" 256 | #endif 257 | 258 | /***** prototype definitions *****/ 259 | Element *eval_sub(Element *); 260 | Element *get_lab(Lextok *, int); 261 | Element *huntele(Element *, unsigned int, int); 262 | Element *huntstart(Element *); 263 | Element *mk_skip(void); 264 | Element *target(Element *); 265 | 266 | Lextok *do_unless(Lextok *, Lextok *); 267 | Lextok *expand(Lextok *, int); 268 | Lextok *getuname(Symbol *); 269 | Lextok *mk_explicit(Lextok *, int, int); 270 | Lextok *nn(Lextok *, int, Lextok *, Lextok *); 271 | Lextok *rem_lab(Symbol *, Lextok *, Symbol *); 272 | Lextok *rem_var(Symbol *, Lextok *, Symbol *, Lextok *); 273 | Lextok *tail_add(Lextok *, Lextok *); 274 | Lextok *return_statement(Lextok *); 275 | 276 | ProcList *ready(Symbol *, Lextok *, Sequence *, int, Lextok *, enum btypes); 277 | 278 | SeqList *seqlist(Sequence *, SeqList *); 279 | Sequence *close_seq(int); 280 | 281 | Symbol *break_dest(void); 282 | Symbol *findloc(Symbol *); 283 | Symbol *has_lab(Element *, int); 284 | Symbol *lookup(char *); 285 | Symbol *prep_inline(Symbol *, Lextok *); 286 | 287 | char *put_inline(FILE *, char *); 288 | char *emalloc(size_t); 289 | long Rand(void); 290 | 291 | int any_oper(Lextok *, int); 292 | int any_undo(Lextok *); 293 | int c_add_sv(FILE *); 294 | int cast_val(int, int, int); 295 | int checkvar(Symbol *, int); 296 | int check_track(Lextok *); 297 | int Cnt_flds(Lextok *); 298 | int cnt_mpars(Lextok *); 299 | int complete_rendez(void); 300 | int enable(Lextok *); 301 | int Enabled0(Element *); 302 | int eval(Lextok *); 303 | int find_lab(Symbol *, Symbol *, int); 304 | int find_maxel(Symbol *); 305 | int full_name(FILE *, Lextok *, Symbol *, int); 306 | int getlocal(Lextok *); 307 | int getval(Lextok *); 308 | int glob_inline(char *); 309 | int has_typ(Lextok *, int); 310 | int in_bound(Symbol *, int); 311 | int interprint(FILE *, Lextok *); 312 | int printm(FILE *, Lextok *); 313 | int is_inline(void); 314 | int ismtype(char *); 315 | int isproctype(char *); 316 | int isutype(char *); 317 | int Lval_struct(Lextok *, Symbol *, int, int); 318 | int main(int, char **); 319 | int pc_value(Lextok *); 320 | int pid_is_claim(int); 321 | int proper_enabler(Lextok *); 322 | int putcode(FILE *, Sequence *, Element *, int, int, int); 323 | int q_is_sync(Lextok *); 324 | int qlen(Lextok *); 325 | int qfull(Lextok *); 326 | int qmake(Symbol *); 327 | int qrecv(Lextok *, int); 328 | int qsend(Lextok *); 329 | int remotelab(Lextok *); 330 | int remotevar(Lextok *); 331 | int Rval_struct(Lextok *, Symbol *, int); 332 | int setlocal(Lextok *, int); 333 | int setval(Lextok *, int); 334 | int sputtype(char *, int); 335 | int Sym_typ(Lextok *); 336 | int tl_main(int, char *[]); 337 | int Width_set(int *, int, Lextok *); 338 | int yyparse(void); 339 | int yylex(void); 340 | 341 | void AST_track(Lextok *, int); 342 | void add_seq(Lextok *); 343 | void alldone(int); 344 | void announce(char *); 345 | void c_state(Symbol *, Symbol *, Symbol *); 346 | void c_add_def(FILE *); 347 | void c_add_loc(FILE *, char *); 348 | void c_add_locinit(FILE *, int, char *); 349 | void c_chandump(FILE *); 350 | void c_preview(void); 351 | void c_struct(FILE *, char *, Symbol *); 352 | void c_track(Symbol *, Symbol *, Symbol *); 353 | void c_var(FILE *, char *, Symbol *); 354 | void c_wrapper(FILE *); 355 | void chanaccess(void); 356 | void check_param_count(int, Lextok *); 357 | void checkrun(Symbol *, int); 358 | void comment(FILE *, Lextok *, int); 359 | void cross_dsteps(Lextok *, Lextok *); 360 | void disambiguate(void); 361 | void doq(Symbol *, int, RunList *); 362 | void dotag(FILE *, char *); 363 | void do_locinits(FILE *); 364 | void do_var(FILE *, int, char *, Symbol *, char *, char *, char *); 365 | void dump_struct(Symbol *, char *, RunList *); 366 | void dumpclaims(FILE *, int, char *); 367 | void dumpglobals(void); 368 | void dumplabels(void); 369 | void dumplocal(RunList *); 370 | void dumpsrc(int, int); 371 | void fatal(char *, char *); 372 | void fix_dest(Symbol *, Symbol *); 373 | void genaddproc(void); 374 | void genaddqueue(void); 375 | void gencodetable(FILE *); 376 | void genheader(void); 377 | void genother(void); 378 | void gensrc(void); 379 | void gensvmap(void); 380 | void genunio(void); 381 | void ini_struct(Symbol *); 382 | void loose_ends(void); 383 | void make_atomic(Sequence *, int); 384 | void mark_last(void); 385 | void match_trail(void); 386 | void no_side_effects(char *); 387 | void nochan_manip(Lextok *, Lextok *, int); 388 | void non_fatal(char *, char *); 389 | void ntimes(FILE *, int, int, const char *c[]); 390 | void open_seq(int); 391 | void p_talk(Element *, int); 392 | void pickup_inline(Symbol *, Lextok *, Lextok *); 393 | void plunk_c_decls(FILE *); 394 | void plunk_c_fcts(FILE *); 395 | void plunk_expr(FILE *, char *); 396 | void plunk_inline(FILE *, char *, int, int); 397 | void prehint(Symbol *); 398 | void preruse(FILE *, Lextok *); 399 | void pretty_print(void); 400 | void prune_opts(Lextok *); 401 | void pstext(int, char *); 402 | void pushbreak(void); 403 | void putname(FILE *, char *, Lextok *, int, char *); 404 | void putremote(FILE *, Lextok *, int); 405 | void putskip(int); 406 | void putsrc(Element *); 407 | void putstmnt(FILE *, Lextok *, int); 408 | void putunames(FILE *); 409 | void rem_Seq(void); 410 | void runnable(ProcList *, int, int); 411 | void sched(void); 412 | void setaccess(Symbol *, Symbol *, int, int); 413 | void set_lab(Symbol *, Element *); 414 | void setmtype(Lextok *); 415 | void setpname(Lextok *); 416 | void setptype(Lextok *, int, Lextok *); 417 | void setuname(Lextok *); 418 | void setutype(Lextok *, Symbol *, Lextok *); 419 | void setxus(Lextok *, int); 420 | void Srand(unsigned); 421 | void start_claim(int); 422 | void struct_name(Lextok *, Symbol *, int, char *); 423 | void symdump(void); 424 | void symvar(Symbol *); 425 | void sync_product(void); 426 | void trackchanuse(Lextok *, Lextok *, int); 427 | void trackvar(Lextok *, Lextok *); 428 | void trackrun(Lextok *); 429 | void trapwonly(Lextok * /* , char * */); /* spin.y and main.c */ 430 | void typ2c(Symbol *); 431 | void typ_ck(int, int, char *); 432 | void undostmnt(Lextok *, int); 433 | void unrem_Seq(void); 434 | void unskip(int); 435 | void whoruns(int); 436 | void wrapup(int); 437 | void yyerror(char *, ...); 438 | 439 | extern int unlink(const char *); 440 | 441 | #define TMP_FILE1 "._s_p_i_n_" 442 | #define TMP_FILE2 "._n_i_p_s_" 443 | 444 | #endif 445 | -------------------------------------------------------------------------------- /tl_buchi.c: -------------------------------------------------------------------------------- 1 | /***** tl_spin: tl_buchi.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | * 8 | * Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, 9 | * presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995. 10 | */ 11 | 12 | #include "tl.h" 13 | 14 | extern int tl_verbose, tl_clutter, Total, Max_Red; 15 | extern char *claim_name; 16 | 17 | FILE *tl_out; /* if standalone: = stdout; */ 18 | 19 | typedef struct Transition { 20 | Symbol *name; 21 | Node *cond; 22 | int redundant, merged, marked; 23 | struct Transition *nxt; 24 | } Transition; 25 | 26 | typedef struct State { 27 | Symbol *name; 28 | Transition *trans; 29 | Graph *colors; 30 | unsigned char redundant; 31 | unsigned char accepting; 32 | unsigned char reachable; 33 | struct State *nxt; 34 | } State; 35 | 36 | static State *never = (State *) 0; 37 | static int hitsall; 38 | 39 | void 40 | ini_buchi(void) 41 | { 42 | never = (State *) 0; 43 | hitsall = 0; 44 | } 45 | 46 | static int 47 | sametrans(Transition *s, Transition *t) 48 | { 49 | if (strcmp(s->name->name, t->name->name) != 0) 50 | return 0; 51 | return isequal(s->cond, t->cond); 52 | } 53 | 54 | static Node * 55 | Prune(Node *p) 56 | { 57 | if (p) 58 | switch (p->ntyp) { 59 | case PREDICATE: 60 | case NOT: 61 | case FALSE: 62 | case TRUE: 63 | #ifdef NXT 64 | case NEXT: 65 | #endif 66 | case CEXPR: 67 | return p; 68 | case OR: 69 | p->lft = Prune(p->lft); 70 | if (!p->lft) 71 | { releasenode(1, p->rgt); 72 | return ZN; 73 | } 74 | p->rgt = Prune(p->rgt); 75 | if (!p->rgt) 76 | { releasenode(1, p->lft); 77 | return ZN; 78 | } 79 | return p; 80 | case AND: 81 | p->lft = Prune(p->lft); 82 | if (!p->lft) 83 | return Prune(p->rgt); 84 | p->rgt = Prune(p->rgt); 85 | if (!p->rgt) 86 | return p->lft; 87 | return p; 88 | } 89 | releasenode(1, p); 90 | return ZN; 91 | } 92 | 93 | static State * 94 | findstate(char *nm) 95 | { State *b; 96 | for (b = never; b; b = b->nxt) 97 | if (!strcmp(b->name->name, nm)) 98 | return b; 99 | if (strcmp(nm, "accept_all")) 100 | { if (strncmp(nm, "accept", 6)) 101 | { int i; char altnm[64]; 102 | for (i = 0; i < 64; i++) 103 | if (nm[i] == '_') 104 | break; 105 | if (i >= 64) 106 | Fatal("name too long %s", nm); 107 | sprintf(altnm, "accept%s", &nm[i]); 108 | return findstate(altnm); 109 | } 110 | /* Fatal("buchi: no state %s", nm); */ 111 | } 112 | return (State *) 0; 113 | } 114 | 115 | static void 116 | Dfs(State *b) 117 | { Transition *t; 118 | 119 | if (!b || b->reachable) return; 120 | b->reachable = 1; 121 | 122 | if (b->redundant) 123 | printf("/* redundant state %s */\n", 124 | b->name->name); 125 | for (t = b->trans; t; t = t->nxt) 126 | { if (!t->redundant) 127 | { Dfs(findstate(t->name->name)); 128 | if (!hitsall 129 | && strcmp(t->name->name, "accept_all") == 0) 130 | hitsall = 1; 131 | } 132 | } 133 | } 134 | 135 | void 136 | retarget(char *from, char *to) 137 | { State *b; 138 | Transition *t; 139 | Symbol *To = tl_lookup(to); 140 | 141 | if (tl_verbose) printf("replace %s with %s\n", from, to); 142 | 143 | for (b = never; b; b = b->nxt) 144 | { if (!strcmp(b->name->name, from)) 145 | b->redundant = 1; 146 | else 147 | for (t = b->trans; t; t = t->nxt) 148 | { if (!strcmp(t->name->name, from)) 149 | t->name = To; 150 | } } 151 | } 152 | 153 | #ifdef NXT 154 | static Node * 155 | nonxt(Node *n) 156 | { 157 | switch (n->ntyp) { 158 | case U_OPER: 159 | case V_OPER: 160 | case NEXT: 161 | return ZN; 162 | case OR: 163 | n->lft = nonxt(n->lft); 164 | n->rgt = nonxt(n->rgt); 165 | if (!n->lft || !n->rgt) 166 | return True; 167 | return n; 168 | case AND: 169 | n->lft = nonxt(n->lft); 170 | n->rgt = nonxt(n->rgt); 171 | if (!n->lft) 172 | { if (!n->rgt) 173 | n = ZN; 174 | else 175 | n = n->rgt; 176 | } else if (!n->rgt) 177 | n = n->lft; 178 | return n; 179 | } 180 | return n; 181 | } 182 | #endif 183 | 184 | static Node * 185 | combination(Node *s, Node *t) 186 | { Node *nc; 187 | #ifdef NXT 188 | Node *a = nonxt(s); 189 | Node *b = nonxt(t); 190 | 191 | if (tl_verbose) 192 | { printf("\tnonxtA: "); dump(a); 193 | printf("\n\tnonxtB: "); dump(b); 194 | printf("\n"); 195 | } 196 | /* if there's only a X(f), its equivalent to true */ 197 | if (!a || !b) 198 | nc = True; 199 | else 200 | nc = tl_nn(OR, a, b); 201 | #else 202 | nc = tl_nn(OR, s, t); 203 | #endif 204 | if (tl_verbose) 205 | { printf("\tcombo: "); dump(nc); 206 | printf("\n"); 207 | } 208 | return nc; 209 | } 210 | 211 | Node * 212 | unclutter(Node *n, char *snm) 213 | { Node *t, *s, *v, *u; 214 | Symbol *w; 215 | 216 | /* check only simple cases like !q && q */ 217 | for (t = n; t; t = t->rgt) 218 | { if (t->rgt) 219 | { if (t->ntyp != AND || !t->lft) 220 | return n; 221 | if (t->lft->ntyp != PREDICATE 222 | #ifdef NXT 223 | && t->lft->ntyp != NEXT 224 | #endif 225 | && t->lft->ntyp != NOT) 226 | return n; 227 | } else 228 | { if (t->ntyp != PREDICATE 229 | #ifdef NXT 230 | && t->ntyp != NEXT 231 | #endif 232 | && t->ntyp != NOT) 233 | return n; 234 | } 235 | } 236 | 237 | for (t = n; t; t = t->rgt) 238 | { if (t->rgt) 239 | v = t->lft; 240 | else 241 | v = t; 242 | if (v->ntyp == NOT 243 | && v->lft->ntyp == PREDICATE) 244 | { w = v->lft->sym; 245 | for (s = n; s; s = s->rgt) 246 | { if (s == t) continue; 247 | if (s->rgt) 248 | u = s->lft; 249 | else 250 | u = s; 251 | if (u->ntyp == PREDICATE 252 | && strcmp(u->sym->name, w->name) == 0) 253 | { if (tl_verbose) 254 | { printf("BINGO %s:\t", snm); 255 | dump(n); 256 | printf("\n"); 257 | } 258 | return False; 259 | } 260 | } 261 | } } 262 | return n; 263 | } 264 | 265 | static void 266 | clutter(void) 267 | { State *p; 268 | Transition *s; 269 | 270 | for (p = never; p; p = p->nxt) 271 | for (s = p->trans; s; s = s->nxt) 272 | { s->cond = unclutter(s->cond, p->name->name); 273 | if (s->cond 274 | && s->cond->ntyp == FALSE) 275 | { if (s != p->trans 276 | || s->nxt) 277 | s->redundant = 1; 278 | } 279 | } 280 | } 281 | 282 | static void 283 | showtrans(State *a) 284 | { Transition *s; 285 | 286 | for (s = a->trans; s; s = s->nxt) 287 | { printf("%s ", s->name?s->name->name:"-"); 288 | dump(s->cond); 289 | printf(" %d %d %d\n", s->redundant, s->merged, s->marked); 290 | } 291 | } 292 | 293 | static int 294 | mergetrans(void) 295 | { State *b; 296 | Transition *s, *t; 297 | Node *nc; int cnt = 0; 298 | 299 | for (b = never; b; b = b->nxt) 300 | { if (!b->reachable) continue; 301 | 302 | for (s = b->trans; s; s = s->nxt) 303 | { if (s->redundant) continue; 304 | 305 | for (t = s->nxt; t; t = t->nxt) 306 | if (!t->redundant 307 | && !strcmp(s->name->name, t->name->name)) 308 | { if (tl_verbose) 309 | { printf("===\nstate %s, trans to %s redundant\n", 310 | b->name->name, s->name->name); 311 | showtrans(b); 312 | printf(" conditions "); 313 | dump(s->cond); printf(" <-> "); 314 | dump(t->cond); printf("\n"); 315 | } 316 | 317 | if (!s->cond) /* same as T */ 318 | { releasenode(1, t->cond); /* T or t */ 319 | nc = True; 320 | } else if (!t->cond) 321 | { releasenode(1, s->cond); 322 | nc = True; 323 | } else 324 | { nc = combination(s->cond, t->cond); 325 | } 326 | t->cond = rewrite(nc); 327 | t->merged = 1; 328 | s->redundant = 1; 329 | cnt++; 330 | break; 331 | } } } 332 | return cnt; 333 | } 334 | 335 | static int 336 | all_trans_match(State *a, State *b) 337 | { Transition *s, *t; 338 | int found, result = 0; 339 | 340 | if (a->accepting != b->accepting) 341 | goto done; 342 | 343 | for (s = a->trans; s; s = s->nxt) 344 | { if (s->redundant) continue; 345 | found = 0; 346 | for (t = b->trans; t; t = t->nxt) 347 | { if (t->redundant) continue; 348 | if (sametrans(s, t)) 349 | { found = 1; 350 | t->marked = 1; 351 | break; 352 | } } 353 | if (!found) 354 | goto done; 355 | } 356 | for (s = b->trans; s; s = s->nxt) 357 | { if (s->redundant || s->marked) continue; 358 | found = 0; 359 | for (t = a->trans; t; t = t->nxt) 360 | { if (t->redundant) continue; 361 | if (sametrans(s, t)) 362 | { found = 1; 363 | break; 364 | } } 365 | if (!found) 366 | goto done; 367 | } 368 | result = 1; 369 | done: 370 | for (s = b->trans; s; s = s->nxt) 371 | s->marked = 0; 372 | return result; 373 | } 374 | 375 | #ifndef NO_OPT 376 | #define BUCKY 377 | #endif 378 | 379 | #ifdef BUCKY 380 | static int 381 | all_bucky(State *a, State *b) 382 | { Transition *s, *t; 383 | int found, result = 0; 384 | 385 | for (s = a->trans; s; s = s->nxt) 386 | { if (s->redundant) continue; 387 | found = 0; 388 | for (t = b->trans; t; t = t->nxt) 389 | { if (t->redundant) continue; 390 | 391 | if (isequal(s->cond, t->cond)) 392 | { if (strcmp(s->name->name, b->name->name) == 0 393 | && strcmp(t->name->name, a->name->name) == 0) 394 | { found = 1; /* they point to each other */ 395 | t->marked = 1; 396 | break; 397 | } 398 | if (strcmp(s->name->name, t->name->name) == 0 399 | && strcmp(s->name->name, "accept_all") == 0) 400 | { found = 1; 401 | t->marked = 1; 402 | break; 403 | /* same exit from which there is no return */ 404 | } 405 | } 406 | } 407 | if (!found) 408 | goto done; 409 | } 410 | for (s = b->trans; s; s = s->nxt) 411 | { if (s->redundant || s->marked) continue; 412 | found = 0; 413 | for (t = a->trans; t; t = t->nxt) 414 | { if (t->redundant) continue; 415 | 416 | if (isequal(s->cond, t->cond)) 417 | { if (strcmp(s->name->name, a->name->name) == 0 418 | && strcmp(t->name->name, b->name->name) == 0) 419 | { found = 1; 420 | t->marked = 1; 421 | break; 422 | } 423 | if (strcmp(s->name->name, t->name->name) == 0 424 | && strcmp(s->name->name, "accept_all") == 0) 425 | { found = 1; 426 | t->marked = 1; 427 | break; 428 | } 429 | } 430 | } 431 | if (!found) 432 | goto done; 433 | } 434 | result = 1; 435 | done: 436 | for (s = b->trans; s; s = s->nxt) 437 | s->marked = 0; 438 | return result; 439 | } 440 | 441 | static int 442 | buckyballs(void) 443 | { State *a, *b, *c, *d; 444 | int m, cnt=0; 445 | 446 | do { 447 | m = 0; cnt++; 448 | for (a = never; a; a = a->nxt) 449 | { if (!a->reachable) continue; 450 | 451 | if (a->redundant) continue; 452 | 453 | for (b = a->nxt; b; b = b->nxt) 454 | { if (!b->reachable) continue; 455 | 456 | if (b->redundant) continue; 457 | 458 | if (all_bucky(a, b)) 459 | { m++; 460 | if (tl_verbose) 461 | { printf("%s bucky match %s\n", 462 | a->name->name, b->name->name); 463 | } 464 | 465 | if (a->accepting && !b->accepting) 466 | { if (strcmp(b->name->name, "T0_init") == 0) 467 | { c = a; d = b; 468 | b->accepting = 1; 469 | } else 470 | { c = b; d = a; 471 | } 472 | } else 473 | { c = a; d = b; 474 | } 475 | 476 | retarget(c->name->name, d->name->name); 477 | if (!strncmp(c->name->name, "accept", 6) 478 | && Max_Red == 0) 479 | { char buf[64]; 480 | sprintf(buf, "T0%s", &(c->name->name[6])); 481 | retarget(buf, d->name->name); 482 | } 483 | break; 484 | } 485 | } } 486 | } while (m && cnt < 10); 487 | return cnt-1; 488 | } 489 | #endif 490 | 491 | static int 492 | mergestates(int v) 493 | { State *a, *b; 494 | int m, cnt=0; 495 | 496 | if (tl_verbose) 497 | return 0; 498 | 499 | do { 500 | m = 0; cnt++; 501 | for (a = never; a; a = a->nxt) 502 | { if (v && !a->reachable) continue; 503 | 504 | if (a->redundant) continue; /* 3.3.10 */ 505 | 506 | for (b = a->nxt; b; b = b->nxt) 507 | { if (v && !b->reachable) continue; 508 | 509 | if (b->redundant) continue; /* 3.3.10 */ 510 | 511 | if (all_trans_match(a, b)) 512 | { m++; 513 | if (tl_verbose) 514 | { printf("%d: state %s equals state %s\n", 515 | cnt, a->name->name, b->name->name); 516 | showtrans(a); 517 | printf("==\n"); 518 | showtrans(b); 519 | } 520 | retarget(a->name->name, b->name->name); 521 | if (!strncmp(a->name->name, "accept", 6) 522 | && Max_Red == 0) 523 | { char buf[64]; 524 | sprintf(buf, "T0%s", &(a->name->name[6])); 525 | retarget(buf, b->name->name); 526 | } 527 | break; 528 | } 529 | #if 0 530 | else if (tl_verbose) 531 | { printf("\n%d: state %s differs from state %s [%d,%d]\n", 532 | cnt, a->name->name, b->name->name, 533 | a->accepting, b->accepting); 534 | showtrans(a); 535 | printf("==\n"); 536 | showtrans(b); 537 | printf("\n"); 538 | } 539 | #endif 540 | } } 541 | } while (m && cnt < 10); 542 | return cnt-1; 543 | } 544 | 545 | static int tcnt; 546 | 547 | static void 548 | rev_trans(Transition *t) /* print transitions in reverse order... */ 549 | { 550 | if (!t) return; 551 | rev_trans(t->nxt); 552 | 553 | if (t->redundant && !tl_verbose) return; 554 | 555 | if (strcmp(t->name->name, "accept_all") == 0) /* 6.2.4 */ 556 | { /* not d_step because there may be remote refs */ 557 | fprintf(tl_out, "\t:: atomic { ("); 558 | if (dump_cond(t->cond, t->cond, 1)) 559 | fprintf(tl_out, "1"); 560 | fprintf(tl_out, ") -> assert(!("); 561 | if (dump_cond(t->cond, t->cond, 1)) 562 | fprintf(tl_out, "1"); 563 | fprintf(tl_out, ")) }\n"); 564 | } else 565 | { fprintf(tl_out, "\t:: ("); 566 | if (dump_cond(t->cond, t->cond, 1)) 567 | fprintf(tl_out, "1"); 568 | fprintf(tl_out, ") -> goto %s\n", t->name->name); 569 | } 570 | tcnt++; 571 | } 572 | 573 | static void 574 | printstate(State *b) 575 | { 576 | if (!b || (!tl_verbose && !b->reachable)) return; 577 | 578 | b->reachable = 0; /* print only once */ 579 | fprintf(tl_out, "%s:\n", b->name->name); 580 | 581 | if (tl_verbose) 582 | { fprintf(tl_out, " /* "); 583 | dump(b->colors->Other); 584 | fprintf(tl_out, " */\n"); 585 | } 586 | 587 | if (strncmp(b->name->name, "accept", 6) == 0 588 | && Max_Red == 0) 589 | fprintf(tl_out, "T0%s:\n", &(b->name->name[6])); 590 | 591 | fprintf(tl_out, "\tdo\n"); 592 | tcnt = 0; 593 | rev_trans(b->trans); 594 | if (!tcnt) fprintf(tl_out, "\t:: false\n"); 595 | fprintf(tl_out, "\tod;\n"); 596 | Total++; 597 | } 598 | 599 | void 600 | addtrans(Graph *col, char *from, Node *op, char *to) 601 | { State *b; 602 | Transition *t; 603 | 604 | t = (Transition *) tl_emalloc(sizeof(Transition)); 605 | t->name = tl_lookup(to); 606 | t->cond = Prune(dupnode(op)); 607 | 608 | if (tl_verbose) 609 | { printf("\n%s <<\t", from); dump(op); 610 | printf("\n\t"); dump(t->cond); 611 | printf(">> %s\n", t->name->name); 612 | } 613 | if (t->cond) t->cond = rewrite(t->cond); 614 | 615 | for (b = never; b; b = b->nxt) 616 | if (!strcmp(b->name->name, from)) 617 | { t->nxt = b->trans; 618 | b->trans = t; 619 | return; 620 | } 621 | b = (State *) tl_emalloc(sizeof(State)); 622 | b->name = tl_lookup(from); 623 | b->colors = col; 624 | b->trans = t; 625 | if (!strncmp(from, "accept", 6)) 626 | b->accepting = 1; 627 | b->nxt = never; 628 | never = b; 629 | } 630 | 631 | static void 632 | clr_reach(void) 633 | { State *p; 634 | for (p = never; p; p = p->nxt) 635 | p->reachable = 0; 636 | hitsall = 0; 637 | } 638 | 639 | void 640 | fsm_print(void) 641 | { State *b; int cnt1, cnt2=0; 642 | extern void put_uform(void); 643 | 644 | if (tl_clutter) clutter(); 645 | 646 | b = findstate("T0_init"); 647 | if (b && (Max_Red == 0)) 648 | b->accepting = 1; 649 | 650 | mergestates(0); 651 | b = findstate("T0_init"); 652 | 653 | fprintf(tl_out, "never %s { /* ", claim_name?claim_name:""); 654 | put_uform(); 655 | fprintf(tl_out, " */\n"); 656 | 657 | do { 658 | clr_reach(); 659 | Dfs(b); 660 | cnt1 = mergetrans(); 661 | cnt2 = mergestates(1); 662 | if (tl_verbose) 663 | printf("/* >>%d,%d<< */\n", cnt1, cnt2); 664 | } while (cnt2 > 0); 665 | 666 | #ifdef BUCKY 667 | buckyballs(); 668 | clr_reach(); 669 | Dfs(b); 670 | #endif 671 | if (b && b->accepting) 672 | fprintf(tl_out, "accept_init:\n"); 673 | 674 | if (!b && !never) 675 | { fprintf(tl_out, " 0 /* false */;\n"); 676 | } else 677 | { printstate(b); /* init state must be first */ 678 | for (b = never; b; b = b->nxt) 679 | printstate(b); 680 | } 681 | if (hitsall) 682 | fprintf(tl_out, "accept_all:\n skip\n"); 683 | fprintf(tl_out, "}\n"); 684 | } 685 | -------------------------------------------------------------------------------- /sym.c: -------------------------------------------------------------------------------- 1 | /***** spin: sym.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | */ 8 | 9 | #include "spin.h" 10 | #include "y.tab.h" 11 | 12 | extern Symbol *Fname, *owner; 13 | extern int lineno, depth, verbose, NamesNotAdded, deadvar; 14 | extern int has_hidden, m_loss, old_scope_rules; 15 | extern short has_xu; 16 | extern char CurScope[MAXSCOPESZ]; 17 | 18 | Symbol *context = ZS; 19 | Ordered *all_names = (Ordered *)0; 20 | int Nid = 0; 21 | 22 | Lextok *Mtype = (Lextok *) 0; 23 | Lextok *runstmnts = ZN; 24 | 25 | static Ordered *last_name = (Ordered *)0; 26 | static Symbol *symtab[Nhash+1]; 27 | 28 | static int 29 | samename(Symbol *a, Symbol *b) 30 | { 31 | if (!a && !b) return 1; 32 | if (!a || !b) return 0; 33 | return !strcmp(a->name, b->name); 34 | } 35 | 36 | unsigned int 37 | hash(const char *s) 38 | { unsigned int h = 0; 39 | 40 | while (*s) 41 | { h += (unsigned int) *s++; 42 | h <<= 1; 43 | if (h&(Nhash+1)) 44 | h |= 1; 45 | } 46 | return h&Nhash; 47 | } 48 | 49 | void 50 | disambiguate(void) 51 | { Ordered *walk; 52 | Symbol *sp; 53 | char *n, *m; 54 | 55 | if (old_scope_rules) 56 | return; 57 | 58 | /* prepend the scope_prefix to the names */ 59 | 60 | for (walk = all_names; walk; walk = walk->next) 61 | { sp = walk->entry; 62 | if (sp->type != 0 63 | && sp->type != LABEL 64 | && strlen((const char *)sp->bscp) > 1) 65 | { if (sp->context) 66 | { m = (char *) emalloc(strlen((const char *)sp->bscp) + 1); 67 | sprintf(m, "_%d_", sp->context->sc); 68 | if (strcmp((const char *) m, (const char *) sp->bscp) == 0) 69 | { continue; 70 | /* 6.2.0: only prepend scope for inner-blocks, 71 | not for top-level locals within a proctype 72 | this means that you can no longer use the same name 73 | for a global and a (top-level) local variable 74 | */ 75 | } } 76 | 77 | n = (char *) emalloc(strlen((const char *)sp->name) 78 | + strlen((const char *)sp->bscp) + 1); 79 | sprintf(n, "%s%s", sp->bscp, sp->name); 80 | sp->name = n; /* discard the old memory */ 81 | } } 82 | } 83 | 84 | Symbol * 85 | lookup(char *s) 86 | { Symbol *sp; Ordered *no; 87 | unsigned int h = hash(s); 88 | 89 | if (old_scope_rules) 90 | { /* same scope - global refering to global or local to local */ 91 | for (sp = symtab[h]; sp; sp = sp->next) 92 | { if (strcmp(sp->name, s) == 0 93 | && samename(sp->context, context) 94 | && samename(sp->owner, owner)) 95 | { return sp; /* found */ 96 | } } 97 | } else 98 | { /* added 6.0.0: more traditional, scope rule */ 99 | for (sp = symtab[h]; sp; sp = sp->next) 100 | { if (strcmp(sp->name, s) == 0 101 | && samename(sp->context, context) 102 | && (strcmp((const char *)sp->bscp, CurScope) == 0 103 | || strncmp((const char *)sp->bscp, CurScope, strlen((const char *)sp->bscp)) == 0) 104 | && samename(sp->owner, owner)) 105 | { 106 | if (!samename(sp->owner, owner)) 107 | { printf("spin: different container %s\n", sp->name); 108 | printf(" old: %s\n", sp->owner?sp->owner->name:"--"); 109 | printf(" new: %s\n", owner?owner->name:"--"); 110 | /* alldone(1); */ 111 | } 112 | return sp; /* found */ 113 | } } } 114 | 115 | if (context) /* in proctype, refers to global */ 116 | for (sp = symtab[h]; sp; sp = sp->next) 117 | { if (strcmp(sp->name, s) == 0 118 | && !sp->context 119 | && samename(sp->owner, owner)) 120 | { return sp; /* global */ 121 | } } 122 | 123 | sp = (Symbol *) emalloc(sizeof(Symbol)); 124 | sp->name = (char *) emalloc(strlen(s) + 1); 125 | strcpy(sp->name, s); 126 | sp->nel = 1; 127 | sp->setat = depth; 128 | sp->context = context; 129 | sp->owner = owner; /* if fld in struct */ 130 | sp->bscp = (unsigned char *) emalloc(strlen((const char *)CurScope)+1); 131 | strcpy((char *)sp->bscp, CurScope); 132 | 133 | if (NamesNotAdded == 0) 134 | { sp->next = symtab[h]; 135 | symtab[h] = sp; 136 | no = (Ordered *) emalloc(sizeof(Ordered)); 137 | no->entry = sp; 138 | if (!last_name) 139 | last_name = all_names = no; 140 | else 141 | { last_name->next = no; 142 | last_name = no; 143 | } } 144 | 145 | return sp; 146 | } 147 | 148 | void 149 | trackvar(Lextok *n, Lextok *m) 150 | { Symbol *sp = n->sym; 151 | 152 | if (!sp) return; /* a structure list */ 153 | switch (m->ntyp) { 154 | case NAME: 155 | if (m->sym->type != BIT) 156 | { sp->hidden |= 4; 157 | if (m->sym->type != BYTE) 158 | sp->hidden |= 8; 159 | } 160 | break; 161 | case CONST: 162 | if (m->val != 0 && m->val != 1) 163 | sp->hidden |= 4; 164 | if (m->val < 0 || m->val > 256) 165 | sp->hidden |= 8; /* ditto byte-equiv */ 166 | break; 167 | default: /* unknown */ 168 | sp->hidden |= (4|8); /* not known bit-equiv */ 169 | } 170 | } 171 | 172 | void 173 | trackrun(Lextok *n) 174 | { 175 | runstmnts = nn(ZN, 0, n, runstmnts); 176 | } 177 | 178 | void 179 | checkrun(Symbol *parnm, int posno) 180 | { Lextok *n, *now, *v; int i, m; 181 | int res = 0; char buf[16], buf2[16]; 182 | 183 | for (n = runstmnts; n; n = n->rgt) 184 | { now = n->lft; 185 | if (now->sym != parnm->context) 186 | continue; 187 | for (v = now->lft, i = 0; v; v = v->rgt, i++) 188 | if (i == posno) 189 | { m = v->lft->ntyp; 190 | if (m == CONST) 191 | { m = v->lft->val; 192 | if (m != 0 && m != 1) 193 | res |= 4; 194 | if (m < 0 || m > 256) 195 | res |= 8; 196 | } else if (m == NAME) 197 | { m = v->lft->sym->type; 198 | if (m != BIT) 199 | { res |= 4; 200 | if (m != BYTE) 201 | res |= 8; 202 | } 203 | } else 204 | res |= (4|8); /* unknown */ 205 | break; 206 | } } 207 | if (!(res&4) || !(res&8)) 208 | { if (!(verbose&32)) return; 209 | strcpy(buf2, (!(res&4))?"bit":"byte"); 210 | sputtype(buf, parnm->type); 211 | i = (int) strlen(buf); 212 | while (i > 0 && buf[--i] == ' ') buf[i] = '\0'; 213 | if (i == 0 || strcmp(buf, buf2) == 0) return; 214 | prehint(parnm); 215 | printf("proctype %s, '%s %s' could be declared", 216 | parnm->context?parnm->context->name:"", buf, parnm->name); 217 | printf(" '%s %s'\n", buf2, parnm->name); 218 | } 219 | } 220 | 221 | void 222 | trackchanuse(Lextok *m, Lextok *w, int t) 223 | { Lextok *n = m; int cnt = 1; 224 | while (n) 225 | { if (n->lft 226 | && n->lft->sym 227 | && n->lft->sym->type == CHAN) 228 | setaccess(n->lft->sym, w?w->sym:ZS, cnt, t); 229 | n = n->rgt; cnt++; 230 | } 231 | } 232 | 233 | void 234 | setptype(Lextok *n, int t, Lextok *vis) /* predefined types */ 235 | { int oln = lineno, cnt = 1; extern int Expand_Ok; 236 | 237 | while (n) 238 | { if (n->sym->type && !(n->sym->hidden&32)) 239 | { lineno = n->ln; Fname = n->fn; 240 | fatal("redeclaration of '%s'", n->sym->name); 241 | lineno = oln; 242 | } 243 | n->sym->type = (short) t; 244 | 245 | if (Expand_Ok) 246 | { n->sym->hidden |= (4|8|16); /* formal par */ 247 | if (t == CHAN) 248 | setaccess(n->sym, ZS, cnt, 'F'); 249 | } 250 | if (t == UNSIGNED) 251 | { if (n->sym->nbits < 0 || n->sym->nbits >= 32) 252 | fatal("(%s) has invalid width-field", n->sym->name); 253 | if (n->sym->nbits == 0) 254 | { n->sym->nbits = 16; 255 | non_fatal("unsigned without width-field", 0); 256 | } 257 | } else if (n->sym->nbits > 0) 258 | { non_fatal("(%s) only an unsigned can have width-field", 259 | n->sym->name); 260 | } 261 | if (vis) 262 | { if (strncmp(vis->sym->name, ":hide:", (size_t) 6) == 0) 263 | { n->sym->hidden |= 1; 264 | has_hidden++; 265 | if (t == BIT) 266 | fatal("bit variable (%s) cannot be hidden", 267 | n->sym->name); 268 | } else if (strncmp(vis->sym->name, ":show:", (size_t) 6) == 0) 269 | { n->sym->hidden |= 2; 270 | } else if (strncmp(vis->sym->name, ":local:", (size_t) 7) == 0) 271 | { n->sym->hidden |= 64; 272 | } 273 | } 274 | if (t == CHAN) 275 | n->sym->Nid = ++Nid; 276 | else 277 | { n->sym->Nid = 0; 278 | if (n->sym->ini 279 | && n->sym->ini->ntyp == CHAN) 280 | { Fname = n->fn; 281 | lineno = n->ln; 282 | fatal("chan initializer for non-channel %s", 283 | n->sym->name); 284 | } 285 | } 286 | if (n->sym->nel <= 0) 287 | { lineno = n->ln; Fname = n->fn; 288 | non_fatal("bad array size for '%s'", n->sym->name); 289 | lineno = oln; 290 | } 291 | n = n->rgt; cnt++; 292 | } 293 | } 294 | 295 | static void 296 | setonexu(Symbol *sp, int t) 297 | { 298 | sp->xu |= t; 299 | if (t == XR || t == XS) 300 | { if (sp->xup[t-1] 301 | && strcmp(sp->xup[t-1]->name, context->name)) 302 | { printf("error: x[rs] claims from %s and %s\n", 303 | sp->xup[t-1]->name, context->name); 304 | non_fatal("conflicting claims on chan '%s'", 305 | sp->name); 306 | } 307 | sp->xup[t-1] = context; 308 | } 309 | } 310 | 311 | static void 312 | setallxu(Lextok *n, int t) 313 | { Lextok *fp, *tl; 314 | 315 | for (fp = n; fp; fp = fp->rgt) 316 | for (tl = fp->lft; tl; tl = tl->rgt) 317 | { if (tl->sym->type == STRUCT) 318 | setallxu(tl->sym->Slst, t); 319 | else if (tl->sym->type == CHAN) 320 | setonexu(tl->sym, t); 321 | } 322 | } 323 | 324 | Lextok *Xu_List = (Lextok *) 0; 325 | 326 | void 327 | setxus(Lextok *p, int t) 328 | { Lextok *m, *n; 329 | 330 | has_xu = 1; 331 | 332 | if (m_loss && t == XS) 333 | { printf("spin: %s:%d, warning, xs tag not compatible with -m (message loss)\n", 334 | (p->fn != NULL) ? p->fn->name : "stdin", p->ln); 335 | } 336 | 337 | if (!context) 338 | { lineno = p->ln; 339 | Fname = p->fn; 340 | fatal("non-local x[rs] assertion", (char *)0); 341 | } 342 | for (m = p; m; m = m->rgt) 343 | { Lextok *Xu_new = (Lextok *) emalloc(sizeof(Lextok)); 344 | Xu_new->uiid = p->uiid; 345 | Xu_new->val = t; 346 | Xu_new->lft = m->lft; 347 | Xu_new->sym = context; 348 | Xu_new->rgt = Xu_List; 349 | Xu_List = Xu_new; 350 | 351 | n = m->lft; 352 | if (n->sym->type == STRUCT) 353 | setallxu(n->sym->Slst, t); 354 | else if (n->sym->type == CHAN) 355 | setonexu(n->sym, t); 356 | else 357 | { int oln = lineno; 358 | lineno = n->ln; Fname = n->fn; 359 | non_fatal("xr or xs of non-chan '%s'", 360 | n->sym->name); 361 | lineno = oln; 362 | } 363 | } 364 | } 365 | 366 | void 367 | setmtype(Lextok *m) 368 | { Lextok *n; 369 | int cnt, oln = lineno; 370 | 371 | if (m) { lineno = m->ln; Fname = m->fn; } 372 | 373 | if (!Mtype) 374 | Mtype = m; 375 | else 376 | { for (n = Mtype; n->rgt; n = n->rgt) 377 | ; 378 | n->rgt = m; /* concatenate */ 379 | } 380 | 381 | for (n = Mtype, cnt = 1; n; n = n->rgt, cnt++) /* syntax check */ 382 | { if (!n->lft || !n->lft->sym 383 | || n->lft->ntyp != NAME 384 | || n->lft->lft) /* indexed variable */ 385 | fatal("bad mtype definition", (char *)0); 386 | 387 | /* label the name */ 388 | if (n->lft->sym->type != MTYPE) 389 | { n->lft->sym->hidden |= 128; /* is used */ 390 | n->lft->sym->type = MTYPE; 391 | n->lft->sym->ini = nn(ZN,CONST,ZN,ZN); 392 | n->lft->sym->ini->val = cnt; 393 | } else if (n->lft->sym->ini->val != cnt) 394 | non_fatal("name %s appears twice in mtype declaration", 395 | n->lft->sym->name); 396 | } 397 | lineno = oln; 398 | if (cnt > 256) 399 | fatal("too many mtype elements (>255)", (char *)0); 400 | } 401 | 402 | int 403 | ismtype(char *str) /* name to number */ 404 | { Lextok *n; 405 | int cnt = 1; 406 | 407 | for (n = Mtype; n; n = n->rgt) 408 | { if (strcmp(str, n->lft->sym->name) == 0) 409 | return cnt; 410 | cnt++; 411 | } 412 | return 0; 413 | } 414 | 415 | int 416 | sputtype(char *foo, int m) 417 | { 418 | switch (m) { 419 | case UNSIGNED: strcpy(foo, "unsigned "); break; 420 | case BIT: strcpy(foo, "bit "); break; 421 | case BYTE: strcpy(foo, "byte "); break; 422 | case CHAN: strcpy(foo, "chan "); break; 423 | case SHORT: strcpy(foo, "short "); break; 424 | case INT: strcpy(foo, "int "); break; 425 | case MTYPE: strcpy(foo, "mtype "); break; 426 | case STRUCT: strcpy(foo, "struct"); break; 427 | case PROCTYPE: strcpy(foo, "proctype"); break; 428 | case LABEL: strcpy(foo, "label "); return 0; 429 | default: strcpy(foo, "value "); return 0; 430 | } 431 | return 1; 432 | } 433 | 434 | 435 | static int 436 | puttype(int m) 437 | { char buf[128]; 438 | 439 | if (sputtype(buf, m)) 440 | { printf("%s", buf); 441 | return 1; 442 | } 443 | return 0; 444 | } 445 | 446 | void 447 | symvar(Symbol *sp) 448 | { Lextok *m; 449 | 450 | if (!puttype(sp->type)) 451 | return; 452 | 453 | printf("\t"); 454 | if (sp->owner) printf("%s.", sp->owner->name); 455 | printf("%s", sp->name); 456 | if (sp->nel > 1 || sp->isarray == 1) printf("[%d]", sp->nel); 457 | 458 | if (sp->type == CHAN) 459 | printf("\t%d", (sp->ini)?sp->ini->val:0); 460 | else if (sp->type == STRUCT && sp->Snm != NULL) /* Frank Weil, 2.9.8 */ 461 | printf("\t%s", sp->Snm->name); 462 | else 463 | printf("\t%d", eval(sp->ini)); 464 | 465 | if (sp->owner) 466 | printf("\t<:struct-field:>"); 467 | else 468 | if (!sp->context) 469 | printf("\t<:global:>"); 470 | else 471 | printf("\t<%s>", sp->context->name); 472 | 473 | if (sp->Nid < 0) /* formal parameter */ 474 | printf("\t", -(sp->Nid)); 475 | else if (sp->type == MTYPE) 476 | printf("\t"); 477 | else if (sp->isarray) 478 | printf("\t"); 479 | else 480 | printf("\t"); 481 | 482 | if (sp->type == CHAN && sp->ini) 483 | { int i; 484 | for (m = sp->ini->rgt, i = 0; m; m = m->rgt) 485 | i++; 486 | printf("\t%d\t", i); 487 | for (m = sp->ini->rgt; m; m = m->rgt) 488 | { if (m->ntyp == STRUCT) 489 | printf("struct %s", m->sym->name); 490 | else 491 | (void) puttype(m->ntyp); 492 | if (m->rgt) printf("\t"); 493 | } 494 | } 495 | 496 | if (!old_scope_rules) 497 | { printf("\t{scope %s}", sp->bscp); 498 | } 499 | 500 | printf("\n"); 501 | } 502 | 503 | void 504 | symdump(void) 505 | { Ordered *walk; 506 | 507 | for (walk = all_names; walk; walk = walk->next) 508 | symvar(walk->entry); 509 | } 510 | 511 | void 512 | chname(Symbol *sp) 513 | { printf("chan "); 514 | if (sp->context) printf("%s-", sp->context->name); 515 | if (sp->owner) printf("%s.", sp->owner->name); 516 | printf("%s", sp->name); 517 | if (sp->nel > 1 || sp->isarray == 1) printf("[%d]", sp->nel); 518 | printf("\t"); 519 | } 520 | 521 | static struct X { 522 | int typ; char *nm; 523 | } xx[] = { 524 | { 'A', "exported as run parameter" }, 525 | { 'F', "imported as proctype parameter" }, 526 | { 'L', "used as l-value in asgnmnt" }, 527 | { 'V', "used as r-value in asgnmnt" }, 528 | { 'P', "polled in receive stmnt" }, 529 | { 'R', "used as parameter in receive stmnt" }, 530 | { 'S', "used as parameter in send stmnt" }, 531 | { 'r', "received from" }, 532 | { 's', "sent to" }, 533 | }; 534 | 535 | static void 536 | chan_check(Symbol *sp) 537 | { Access *a; int i, b=0, d; 538 | 539 | if (verbose&1) goto report; /* -C -g */ 540 | 541 | for (a = sp->access; a; a = a->lnk) 542 | if (a->typ == 'r') 543 | b |= 1; 544 | else if (a->typ == 's') 545 | b |= 2; 546 | if (b == 3 || (sp->hidden&16)) /* balanced or formal par */ 547 | return; 548 | report: 549 | chname(sp); 550 | for (i = d = 0; i < (int) (sizeof(xx)/sizeof(struct X)); i++) 551 | { b = 0; 552 | for (a = sp->access; a; a = a->lnk) 553 | if (a->typ == xx[i].typ) b++; 554 | if (b == 0) continue; d++; 555 | printf("\n\t%s by: ", xx[i].nm); 556 | for (a = sp->access; a; a = a->lnk) 557 | if (a->typ == xx[i].typ) 558 | { printf("%s", a->who->name); 559 | if (a->what) printf(" to %s", a->what->name); 560 | if (a->cnt) printf(" par %d", a->cnt); 561 | if (--b > 0) printf(", "); 562 | } 563 | } 564 | printf("%s\n", (!d)?"\n\tnever used under this name":""); 565 | } 566 | 567 | void 568 | chanaccess(void) 569 | { Ordered *walk; 570 | char buf[128]; 571 | extern int Caccess, separate; 572 | extern short has_code; 573 | 574 | for (walk = all_names; walk; walk = walk->next) 575 | { if (!walk->entry->owner) 576 | switch (walk->entry->type) { 577 | case CHAN: 578 | if (Caccess) chan_check(walk->entry); 579 | break; 580 | case MTYPE: 581 | case BIT: 582 | case BYTE: 583 | case SHORT: 584 | case INT: 585 | case UNSIGNED: 586 | if ((walk->entry->hidden&128)) /* was: 32 */ 587 | continue; 588 | 589 | if (!separate 590 | && !walk->entry->context 591 | && !has_code 592 | && deadvar) 593 | walk->entry->hidden |= 1; /* auto-hide */ 594 | 595 | if (!(verbose&32) || has_code) continue; 596 | 597 | printf("spin: %s:0, warning, ", Fname->name); 598 | sputtype(buf, walk->entry->type); 599 | if (walk->entry->context) 600 | printf("proctype %s", 601 | walk->entry->context->name); 602 | else 603 | printf("global"); 604 | printf(", '%s%s' variable is never used (other than in print stmnts)\n", 605 | buf, walk->entry->name); 606 | } } 607 | } 608 | -------------------------------------------------------------------------------- /structs.c: -------------------------------------------------------------------------------- 1 | /***** spin: structs.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | */ 8 | 9 | #include "spin.h" 10 | #include "y.tab.h" 11 | 12 | typedef struct UType { 13 | Symbol *nm; /* name of the type */ 14 | Lextok *cn; /* contents */ 15 | struct UType *nxt; /* linked list */ 16 | } UType; 17 | 18 | extern Symbol *Fname; 19 | extern int lineno, depth, Expand_Ok, has_hidden, in_for; 20 | 21 | Symbol *owner; 22 | 23 | static UType *Unames = 0; 24 | static UType *Pnames = 0; 25 | 26 | static Lextok *cpnn(Lextok *, int, int, int); 27 | extern void sr_mesg(FILE *, int, int); 28 | 29 | void 30 | setuname(Lextok *n) 31 | { UType *tmp; 32 | 33 | if (!owner) 34 | fatal("illegal reference inside typedef", (char *) 0); 35 | 36 | for (tmp = Unames; tmp; tmp = tmp->nxt) 37 | if (!strcmp(owner->name, tmp->nm->name)) 38 | { non_fatal("typename %s was defined before", 39 | tmp->nm->name); 40 | return; 41 | } 42 | 43 | tmp = (UType *) emalloc(sizeof(UType)); 44 | tmp->nm = owner; 45 | tmp->cn = n; 46 | tmp->nxt = Unames; 47 | Unames = tmp; 48 | } 49 | 50 | static void 51 | putUname(FILE *fd, UType *tmp) 52 | { Lextok *fp, *tl; 53 | 54 | if (!tmp) return; 55 | putUname(fd, tmp->nxt); /* postorder */ 56 | fprintf(fd, "struct %s { /* user defined type */\n", 57 | tmp->nm->name); 58 | for (fp = tmp->cn; fp; fp = fp->rgt) 59 | for (tl = fp->lft; tl; tl = tl->rgt) 60 | typ2c(tl->sym); 61 | fprintf(fd, "};\n"); 62 | } 63 | 64 | void 65 | putunames(FILE *fd) 66 | { 67 | putUname(fd, Unames); 68 | } 69 | 70 | int 71 | isutype(char *t) 72 | { UType *tmp; 73 | 74 | for (tmp = Unames; tmp; tmp = tmp->nxt) 75 | { if (!strcmp(t, tmp->nm->name)) 76 | return 1; 77 | } 78 | return 0; 79 | } 80 | 81 | Lextok * 82 | getuname(Symbol *t) 83 | { UType *tmp; 84 | 85 | for (tmp = Unames; tmp; tmp = tmp->nxt) 86 | { if (!strcmp(t->name, tmp->nm->name)) 87 | return tmp->cn; 88 | } 89 | fatal("%s is not a typename", t->name); 90 | return (Lextok *)0; 91 | } 92 | 93 | void 94 | setutype(Lextok *p, Symbol *t, Lextok *vis) /* user-defined types */ 95 | { int oln = lineno; 96 | Symbol *ofn = Fname; 97 | Lextok *m, *n; 98 | 99 | m = getuname(t); 100 | for (n = p; n; n = n->rgt) 101 | { lineno = n->ln; 102 | Fname = n->fn; 103 | if (n->sym->type) 104 | fatal("redeclaration of '%s'", n->sym->name); 105 | 106 | if (n->sym->nbits > 0) 107 | non_fatal("(%s) only an unsigned can have width-field", 108 | n->sym->name); 109 | 110 | if (Expand_Ok) 111 | n->sym->hidden |= (4|8|16); /* formal par */ 112 | 113 | if (vis) 114 | { if (strncmp(vis->sym->name, ":hide:", (size_t) 6) == 0) 115 | { n->sym->hidden |= 1; 116 | has_hidden++; 117 | } else if (strncmp(vis->sym->name, ":show:", (size_t) 6) == 0) 118 | n->sym->hidden |= 2; 119 | else if (strncmp(vis->sym->name, ":local:", (size_t) 7) == 0) 120 | n->sym->hidden |= 64; 121 | } 122 | n->sym->type = STRUCT; /* classification */ 123 | n->sym->Slst = m; /* structure itself */ 124 | n->sym->Snm = t; /* name of typedef */ 125 | n->sym->Nid = 0; /* this is no chan */ 126 | n->sym->hidden |= 4; 127 | if (n->sym->nel <= 0) 128 | non_fatal("bad array size for '%s'", n->sym->name); 129 | } 130 | lineno = oln; 131 | Fname = ofn; 132 | } 133 | 134 | static Symbol * 135 | do_same(Lextok *n, Symbol *v, int xinit) 136 | { Lextok *tmp, *fp, *tl; 137 | int ix = eval(n->lft); 138 | int oln = lineno; 139 | Symbol *ofn = Fname; 140 | 141 | lineno = n->ln; 142 | Fname = n->fn; 143 | 144 | /* n->sym->type == STRUCT 145 | * index: n->lft 146 | * subfields: n->rgt 147 | * structure template: n->sym->Slst 148 | * runtime values: n->sym->Sval 149 | */ 150 | if (xinit) ini_struct(v); /* once, at top level */ 151 | 152 | if (ix >= v->nel || ix < 0) 153 | { printf("spin: indexing %s[%d] - size is %d\n", 154 | v->name, ix, v->nel); 155 | fatal("indexing error \'%s\'", v->name); 156 | } 157 | if (!n->rgt || !n->rgt->lft) 158 | { non_fatal("no subfields %s", v->name); /* i.e., wants all */ 159 | lineno = oln; Fname = ofn; 160 | return ZS; 161 | } 162 | 163 | if (n->rgt->ntyp != '.') 164 | { printf("bad subfield type %d\n", n->rgt->ntyp); 165 | alldone(1); 166 | } 167 | 168 | tmp = n->rgt->lft; 169 | if (tmp->ntyp != NAME && tmp->ntyp != TYPE) 170 | { printf("bad subfield entry %d\n", tmp->ntyp); 171 | alldone(1); 172 | } 173 | for (fp = v->Sval[ix]; fp; fp = fp->rgt) 174 | for (tl = fp->lft; tl; tl = tl->rgt) 175 | if (!strcmp(tl->sym->name, tmp->sym->name)) 176 | { lineno = oln; Fname = ofn; 177 | return tl->sym; 178 | } 179 | fatal("cannot locate subfield %s", tmp->sym->name); 180 | return ZS; 181 | } 182 | 183 | int 184 | Rval_struct(Lextok *n, Symbol *v, int xinit) /* n varref, v valref */ 185 | { Symbol *tl; 186 | Lextok *tmp; 187 | int ix; 188 | 189 | if (!n || !(tl = do_same(n, v, xinit))) 190 | return 0; 191 | 192 | tmp = n->rgt->lft; 193 | if (tmp->sym->type == STRUCT) 194 | { return Rval_struct(tmp, tl, 0); 195 | } else if (tmp->rgt) 196 | fatal("non-zero 'rgt' on non-structure", 0); 197 | 198 | ix = eval(tmp->lft); 199 | /* printf("%d: ix: %d (%d) %d\n", depth, ix, tl->nel, tl->val[ix]); */ 200 | if (ix >= tl->nel || ix < 0) 201 | fatal("indexing error \'%s\'", tl->name); 202 | 203 | return cast_val(tl->type, tl->val[ix], tl->nbits); 204 | } 205 | 206 | int 207 | Lval_struct(Lextok *n, Symbol *v, int xinit, int a) /* a = assigned value */ 208 | { Symbol *tl; 209 | Lextok *tmp; 210 | int ix; 211 | 212 | if (!(tl = do_same(n, v, xinit))) 213 | return 1; 214 | 215 | tmp = n->rgt->lft; 216 | if (tmp->sym->type == STRUCT) 217 | return Lval_struct(tmp, tl, 0, a); 218 | else if (tmp->rgt) 219 | fatal("non-zero 'rgt' on non-structure", 0); 220 | 221 | ix = eval(tmp->lft); 222 | if (ix >= tl->nel || ix < 0) 223 | fatal("indexing error \'%s\'", tl->name); 224 | 225 | if (tl->nbits > 0) 226 | a = (a & ((1<nbits)-1)); 227 | 228 | if (a != tl->val[ix]) 229 | { tl->val[ix] = a; 230 | tl->setat = depth; 231 | } 232 | return 1; 233 | } 234 | 235 | int 236 | Cnt_flds(Lextok *m) 237 | { Lextok *fp, *tl, *n; 238 | int cnt = 0; 239 | 240 | if (m->ntyp == ',') 241 | { n = m; 242 | goto is_lst; 243 | } 244 | if (!m->sym || m->ntyp != STRUCT) 245 | return 1; 246 | 247 | n = getuname(m->sym); 248 | is_lst: 249 | for (fp = n; fp; fp = fp->rgt) 250 | for (tl = fp->lft; tl; tl = tl->rgt) 251 | { if (tl->sym->type == STRUCT) 252 | { if (tl->sym->nel > 1 || tl->sym->isarray) 253 | fatal("array of structures in param list, %s", 254 | tl->sym->name); 255 | cnt += Cnt_flds(tl->sym->Slst); 256 | } else 257 | cnt += tl->sym->nel; 258 | } 259 | return cnt; 260 | } 261 | 262 | int 263 | Sym_typ(Lextok *t) 264 | { Symbol *s = t->sym; 265 | 266 | if (!s) return 0; 267 | 268 | if (s->type != STRUCT) 269 | return s->type; 270 | 271 | if (!t->rgt 272 | || t->rgt->ntyp != '.' /* gh: had ! in wrong place */ 273 | || !t->rgt->lft) 274 | return STRUCT; /* not a field reference */ 275 | 276 | return Sym_typ(t->rgt->lft); 277 | } 278 | 279 | int 280 | Width_set(int *wdth, int i, Lextok *n) 281 | { Lextok *fp, *tl; 282 | int j = i, k; 283 | 284 | for (fp = n; fp; fp = fp->rgt) 285 | for (tl = fp->lft; tl; tl = tl->rgt) 286 | { if (tl->sym->type == STRUCT) 287 | j = Width_set(wdth, j, tl->sym->Slst); 288 | else 289 | { for (k = 0; k < tl->sym->nel; k++, j++) 290 | wdth[j] = tl->sym->type; 291 | } } 292 | return j; 293 | } 294 | 295 | void 296 | ini_struct(Symbol *s) 297 | { int i; Lextok *fp, *tl; 298 | 299 | if (s->type != STRUCT) /* last step */ 300 | { (void) checkvar(s, 0); 301 | return; 302 | } 303 | if (s->Sval == (Lextok **) 0) 304 | { s->Sval = (Lextok **) emalloc(s->nel * sizeof(Lextok *)); 305 | for (i = 0; i < s->nel; i++) 306 | { s->Sval[i] = cpnn(s->Slst, 1, 1, 1); 307 | 308 | for (fp = s->Sval[i]; fp; fp = fp->rgt) 309 | for (tl = fp->lft; tl; tl = tl->rgt) 310 | ini_struct(tl->sym); 311 | } } 312 | } 313 | 314 | static Lextok * 315 | cpnn(Lextok *s, int L, int R, int S) 316 | { Lextok *d; extern int Nid; 317 | 318 | if (!s) return ZN; 319 | 320 | d = (Lextok *) emalloc(sizeof(Lextok)); 321 | d->uiid = s->uiid; 322 | d->ntyp = s->ntyp; 323 | d->val = s->val; 324 | d->ln = s->ln; 325 | d->fn = s->fn; 326 | d->sym = s->sym; 327 | if (L) d->lft = cpnn(s->lft, 1, 1, S); 328 | if (R) d->rgt = cpnn(s->rgt, 1, 1, S); 329 | 330 | if (S && s->sym) 331 | { d->sym = (Symbol *) emalloc(sizeof(Symbol)); 332 | memcpy(d->sym, s->sym, sizeof(Symbol)); 333 | if (d->sym->type == CHAN) 334 | d->sym->Nid = ++Nid; 335 | } 336 | if (s->sq || s->sl) 337 | fatal("cannot happen cpnn", (char *) 0); 338 | 339 | return d; 340 | } 341 | 342 | int 343 | full_name(FILE *fd, Lextok *n, Symbol *v, int xinit) 344 | { Symbol *tl; 345 | Lextok *tmp; 346 | int hiddenarrays = 0; 347 | 348 | fprintf(fd, "%s", v->name); 349 | 350 | if (!n || !(tl = do_same(n, v, xinit))) 351 | return 0; 352 | tmp = n->rgt->lft; 353 | 354 | if (tmp->sym->type == STRUCT) 355 | { fprintf(fd, "."); 356 | hiddenarrays = full_name(fd, tmp, tl, 0); 357 | goto out; 358 | } 359 | fprintf(fd, ".%s", tl->name); 360 | out: if (tmp->sym->nel > 1 || tmp->sym->isarray == 1) 361 | { fprintf(fd, "[%d]", eval(tmp->lft)); 362 | hiddenarrays = 1; 363 | } 364 | return hiddenarrays; 365 | } 366 | 367 | void 368 | validref(Lextok *p, Lextok *c) 369 | { Lextok *fp, *tl; 370 | char lbuf[512]; 371 | 372 | for (fp = p->sym->Slst; fp; fp = fp->rgt) 373 | for (tl = fp->lft; tl; tl = tl->rgt) 374 | if (strcmp(tl->sym->name, c->sym->name) == 0) 375 | return; 376 | 377 | sprintf(lbuf, "no field '%s' defined in structure '%s'\n", 378 | c->sym->name, p->sym->name); 379 | non_fatal(lbuf, (char *) 0); 380 | } 381 | 382 | void 383 | struct_name(Lextok *n, Symbol *v, int xinit, char *buf) 384 | { Symbol *tl; 385 | Lextok *tmp; 386 | char lbuf[512]; 387 | 388 | if (!n || !(tl = do_same(n, v, xinit))) 389 | return; 390 | tmp = n->rgt->lft; 391 | if (tmp->sym->type == STRUCT) 392 | { strcat(buf, "."); 393 | struct_name(tmp, tl, 0, buf); 394 | return; 395 | } 396 | sprintf(lbuf, ".%s", tl->name); 397 | strcat(buf, lbuf); 398 | if (tmp->sym->nel > 1 || tmp->sym->isarray == 1) 399 | { sprintf(lbuf, "[%d]", eval(tmp->lft)); 400 | strcat(buf, lbuf); 401 | } 402 | } 403 | 404 | void 405 | walk2_struct(char *s, Symbol *z) 406 | { Lextok *fp, *tl; 407 | char eprefix[128]; 408 | int ix; 409 | extern void Done_case(char *, Symbol *); 410 | 411 | ini_struct(z); 412 | if (z->nel == 1 && z->isarray == 0) 413 | sprintf(eprefix, "%s%s.", s, z->name); 414 | for (ix = 0; ix < z->nel; ix++) 415 | { if (z->nel > 1 || z->isarray == 1) 416 | sprintf(eprefix, "%s%s[%d].", s, z->name, ix); 417 | for (fp = z->Sval[ix]; fp; fp = fp->rgt) 418 | for (tl = fp->lft; tl; tl = tl->rgt) 419 | { if (tl->sym->type == STRUCT) 420 | walk2_struct(eprefix, tl->sym); 421 | else if (tl->sym->type == CHAN) 422 | Done_case(eprefix, tl->sym); 423 | } } 424 | } 425 | 426 | void 427 | walk_struct(FILE *ofd, int dowhat, char *s, Symbol *z, char *a, char *b, char *c) 428 | { Lextok *fp, *tl; 429 | char eprefix[128]; 430 | int ix; 431 | 432 | ini_struct(z); 433 | if (z->nel == 1 && z->isarray == 0) 434 | sprintf(eprefix, "%s%s.", s, z->name); 435 | for (ix = 0; ix < z->nel; ix++) 436 | { if (z->nel > 1 || z->isarray == 1) 437 | sprintf(eprefix, "%s%s[%d].", s, z->name, ix); 438 | for (fp = z->Sval[ix]; fp; fp = fp->rgt) 439 | for (tl = fp->lft; tl; tl = tl->rgt) 440 | { if (tl->sym->type == STRUCT) 441 | walk_struct(ofd, dowhat, eprefix, tl->sym, a,b,c); 442 | else 443 | do_var(ofd, dowhat, eprefix, tl->sym, a,b,c); 444 | } } 445 | } 446 | 447 | void 448 | c_struct(FILE *fd, char *ipref, Symbol *z) 449 | { Lextok *fp, *tl; 450 | char pref[256], eprefix[300]; 451 | int ix; 452 | 453 | ini_struct(z); 454 | 455 | for (ix = 0; ix < z->nel; ix++) 456 | for (fp = z->Sval[ix]; fp; fp = fp->rgt) 457 | for (tl = fp->lft; tl; tl = tl->rgt) 458 | { strcpy(eprefix, ipref); 459 | if (z->nel > 1 || z->isarray == 1) 460 | { /* insert index before last '.' */ 461 | eprefix[strlen(eprefix)-1] = '\0'; 462 | sprintf(pref, "[ %d ].", ix); 463 | strcat(eprefix, pref); 464 | } 465 | if (tl->sym->type == STRUCT) 466 | { strcat(eprefix, tl->sym->name); 467 | strcat(eprefix, "."); 468 | c_struct(fd, eprefix, tl->sym); 469 | } else 470 | c_var(fd, eprefix, tl->sym); 471 | } 472 | } 473 | 474 | void 475 | dump_struct(Symbol *z, char *prefix, RunList *r) 476 | { Lextok *fp, *tl; 477 | char eprefix[256]; 478 | int ix, jx; 479 | 480 | ini_struct(z); 481 | 482 | for (ix = 0; ix < z->nel; ix++) 483 | { if (z->nel > 1 || z->isarray == 1) 484 | sprintf(eprefix, "%s[%d]", prefix, ix); 485 | else 486 | strcpy(eprefix, prefix); 487 | 488 | for (fp = z->Sval[ix]; fp; fp = fp->rgt) 489 | for (tl = fp->lft; tl; tl = tl->rgt) 490 | { if (tl->sym->type == STRUCT) 491 | { char pref[300]; 492 | strcpy(pref, eprefix); 493 | strcat(pref, "."); 494 | strcat(pref, tl->sym->name); 495 | dump_struct(tl->sym, pref, r); 496 | } else 497 | for (jx = 0; jx < tl->sym->nel; jx++) 498 | { if (tl->sym->type == CHAN) 499 | doq(tl->sym, jx, r); 500 | else 501 | { printf("\t\t"); 502 | if (r) 503 | printf("%s(%d):", r->n->name, r->pid); 504 | printf("%s.%s", eprefix, tl->sym->name); 505 | if (tl->sym->nel > 1 || tl->sym->isarray == 1) 506 | printf("[%d]", jx); 507 | printf(" = "); 508 | sr_mesg(stdout, tl->sym->val[jx], 509 | tl->sym->type == MTYPE); 510 | printf("\n"); 511 | } } } 512 | } 513 | } 514 | 515 | static int 516 | retrieve(Lextok **targ, int i, int want, Lextok *n, int Ntyp) 517 | { Lextok *fp, *tl; 518 | int j = i, k; 519 | 520 | for (fp = n; fp; fp = fp->rgt) 521 | for (tl = fp->lft; tl; tl = tl->rgt) 522 | { if (tl->sym->type == STRUCT) 523 | { j = retrieve(targ, j, want, tl->sym->Slst, Ntyp); 524 | if (j < 0) 525 | { Lextok *x = cpnn(tl, 1, 0, 0); 526 | x->rgt = nn(ZN, '.', (*targ), ZN); 527 | (*targ) = x; 528 | return -1; 529 | } 530 | } else 531 | { for (k = 0; k < tl->sym->nel; k++, j++) 532 | { if (j == want) 533 | { *targ = cpnn(tl, 1, 0, 0); 534 | (*targ)->lft = nn(ZN, CONST, ZN, ZN); 535 | (*targ)->lft->val = k; 536 | if (Ntyp) 537 | (*targ)->ntyp = (short) Ntyp; 538 | return -1; 539 | } 540 | } } } 541 | return j; 542 | } 543 | 544 | static int 545 | is_explicit(Lextok *n) 546 | { 547 | if (!n) return 0; 548 | if (!n->sym) fatal("unexpected - no symbol", 0); 549 | if (n->sym->type != STRUCT) return 1; 550 | if (!n->rgt) return 0; 551 | if (n->rgt->ntyp != '.') 552 | { lineno = n->ln; 553 | Fname = n->fn; 554 | printf("ntyp %d\n", n->rgt->ntyp); 555 | fatal("unexpected %s, no '.'", n->sym->name); 556 | } 557 | return is_explicit(n->rgt->lft); 558 | } 559 | 560 | Lextok * 561 | expand(Lextok *n, int Ok) 562 | /* turn rgt-lnked list of struct nms, into ',' list of flds */ 563 | { Lextok *x = ZN, *y; 564 | 565 | if (!Ok) return n; 566 | 567 | while (n) 568 | { y = mk_explicit(n, 1, 0); 569 | if (x) 570 | (void) tail_add(x, y); 571 | else 572 | x = y; 573 | 574 | n = n->rgt; 575 | } 576 | return x; 577 | } 578 | 579 | Lextok * 580 | mk_explicit(Lextok *n, int Ok, int Ntyp) 581 | /* produce a single ',' list of fields */ 582 | { Lextok *bld = ZN, *x; 583 | int i, cnt; extern int IArgs; 584 | 585 | if (n->sym->type != STRUCT 586 | || in_for 587 | || is_explicit(n)) 588 | return n; 589 | 590 | 591 | if (n->rgt 592 | && n->rgt->ntyp == '.' 593 | && n->rgt->lft 594 | && n->rgt->lft->sym 595 | && n->rgt->lft->sym->type == STRUCT) 596 | { Lextok *y; 597 | bld = mk_explicit(n->rgt->lft, Ok, Ntyp); 598 | for (x = bld; x; x = x->rgt) 599 | { y = cpnn(n, 1, 0, 0); 600 | y->rgt = nn(ZN, '.', x->lft, ZN); 601 | x->lft = y; 602 | } 603 | 604 | return bld; 605 | } 606 | 607 | if (!Ok || !n->sym->Slst) 608 | { if (IArgs) return n; 609 | printf("spin: saw '"); 610 | comment(stdout, n, 0); 611 | printf("'\n"); 612 | fatal("incomplete structure ref '%s'", n->sym->name); 613 | } 614 | 615 | cnt = Cnt_flds(n->sym->Slst); 616 | for (i = cnt-1; i >= 0; i--) 617 | { bld = nn(ZN, ',', ZN, bld); 618 | if (retrieve(&(bld->lft), 0, i, n->sym->Slst, Ntyp) >= 0) 619 | { printf("cannot retrieve field %d\n", i); 620 | fatal("bad structure %s", n->sym->name); 621 | } 622 | x = cpnn(n, 1, 0, 0); 623 | x->rgt = nn(ZN, '.', bld->lft, ZN); 624 | bld->lft = x; 625 | } 626 | return bld; 627 | } 628 | 629 | Lextok * 630 | tail_add(Lextok *a, Lextok *b) 631 | { Lextok *t; 632 | 633 | for (t = a; t->rgt; t = t->rgt) 634 | if (t->ntyp != ',') 635 | fatal("unexpected type - tail_add", 0); 636 | t->rgt = b; 637 | return a; 638 | } 639 | 640 | void 641 | setpname(Lextok *n) 642 | { UType *tmp; 643 | 644 | for (tmp = Pnames; tmp; tmp = tmp->nxt) 645 | if (!strcmp(n->sym->name, tmp->nm->name)) 646 | { non_fatal("proctype %s redefined", 647 | n->sym->name); 648 | return; 649 | } 650 | tmp = (UType *) emalloc(sizeof(UType)); 651 | tmp->nm = n->sym; 652 | tmp->nxt = Pnames; 653 | Pnames = tmp; 654 | } 655 | 656 | int 657 | isproctype(char *t) 658 | { UType *tmp; 659 | 660 | for (tmp = Pnames; tmp; tmp = tmp->nxt) 661 | { if (!strcmp(t, tmp->nm->name)) 662 | return 1; 663 | } 664 | return 0; 665 | } 666 | -------------------------------------------------------------------------------- /run.c: -------------------------------------------------------------------------------- 1 | /***** spin: run.c *****/ 2 | 3 | /* 4 | * This file is part of the public release of Spin. It is subject to the 5 | * terms in the LICENSE file that is included in this source directory. 6 | * Tool documentation is available at http://spinroot.com 7 | */ 8 | 9 | #include 10 | #include "spin.h" 11 | #include "y.tab.h" 12 | 13 | extern RunList *X, *run; 14 | extern Symbol *Fname; 15 | extern Element *LastStep; 16 | extern int Rvous, lineno, Tval, interactive, MadeChoice, Priority_Sum; 17 | extern int TstOnly, verbose, s_trail, xspin, jumpsteps, depth; 18 | extern int analyze, nproc, nstop, no_print, like_java, old_priority_rules; 19 | extern short Have_claim; 20 | 21 | static long Seed = 1; 22 | static int E_Check = 0, Escape_Check = 0; 23 | 24 | static int eval_sync(Element *); 25 | static int pc_enabled(Lextok *n); 26 | static int get_priority(Lextok *n); 27 | static void set_priority(Lextok *n, Lextok *m); 28 | extern void sr_buf(int, int); 29 | 30 | void 31 | Srand(unsigned int s) 32 | { Seed = s; 33 | } 34 | 35 | long 36 | Rand(void) 37 | { /* CACM 31(10), Oct 1988 */ 38 | Seed = 16807*(Seed%127773) - 2836*(Seed/127773); 39 | if (Seed <= 0) Seed += 2147483647; 40 | return Seed; 41 | } 42 | 43 | Element * 44 | rev_escape(SeqList *e) 45 | { Element *r = (Element *) 0; 46 | 47 | if (e) 48 | { if ((r = rev_escape(e->nxt)) == ZE) /* reversed order */ 49 | { r = eval_sub(e->this->frst); 50 | } } 51 | 52 | return r; 53 | } 54 | 55 | Element * 56 | eval_sub(Element *e) 57 | { Element *f, *g; 58 | SeqList *z; 59 | int i, j, k, only_pos; 60 | 61 | if (!e || !e->n) 62 | return ZE; 63 | #ifdef DEBUG 64 | printf("\n\teval_sub(%d %s: line %d) ", 65 | e->Seqno, e->esc?"+esc":"", e->n?e->n->ln:0); 66 | comment(stdout, e->n, 0); 67 | printf("\n"); 68 | #endif 69 | if (e->n->ntyp == GOTO) 70 | { if (Rvous) return ZE; 71 | LastStep = e; 72 | f = get_lab(e->n, 1); 73 | f = huntele(f, e->status, -1); /* 5.2.3: was missing */ 74 | cross_dsteps(e->n, f->n); 75 | #ifdef DEBUG 76 | printf("GOTO leads to %d\n", f->seqno); 77 | #endif 78 | return f; 79 | } 80 | if (e->n->ntyp == UNLESS) 81 | { /* escapes were distributed into sequence */ 82 | return eval_sub(e->sub->this->frst); 83 | } else if (e->sub) /* true for IF, DO, and UNLESS */ 84 | { Element *has_else = ZE; 85 | Element *bas_else = ZE; 86 | int nr_else = 0, nr_choices = 0; 87 | only_pos = -1; 88 | 89 | if (interactive 90 | && !MadeChoice && !E_Check 91 | && !Escape_Check 92 | && !(e->status&(D_ATOM)) 93 | && depth >= jumpsteps) 94 | { printf("Select stmnt ("); 95 | whoruns(0); printf(")\n"); 96 | if (nproc-nstop > 1) 97 | { printf("\tchoice 0: other process\n"); 98 | nr_choices++; 99 | only_pos = 0; 100 | } } 101 | for (z = e->sub, j=0; z; z = z->nxt) 102 | { j++; 103 | if (interactive 104 | && !MadeChoice && !E_Check 105 | && !Escape_Check 106 | && !(e->status&(D_ATOM)) 107 | && depth >= jumpsteps 108 | && z->this->frst 109 | && (xspin || (verbose&32) || Enabled0(z->this->frst))) 110 | { if (z->this->frst->n->ntyp == ELSE) 111 | { has_else = (Rvous)?ZE:z->this->frst->nxt; 112 | nr_else = j; 113 | continue; 114 | } 115 | printf("\tchoice %d: ", j); 116 | #if 0 117 | if (z->this->frst->n) 118 | printf("line %d, ", z->this->frst->n->ln); 119 | #endif 120 | if (!Enabled0(z->this->frst)) 121 | printf("unexecutable, "); 122 | else 123 | { nr_choices++; 124 | only_pos = j; 125 | } 126 | comment(stdout, z->this->frst->n, 0); 127 | printf("\n"); 128 | } } 129 | 130 | if (nr_choices == 0 && has_else) 131 | { printf("\tchoice %d: (else)\n", nr_else); 132 | only_pos = nr_else; 133 | } 134 | 135 | if (nr_choices <= 1 && only_pos != -1 && !MadeChoice) 136 | { MadeChoice = only_pos; 137 | } 138 | 139 | if (interactive && depth >= jumpsteps 140 | && !Escape_Check 141 | && !(e->status&(D_ATOM)) 142 | && !E_Check) 143 | { if (!MadeChoice) 144 | { char buf[256]; 145 | if (xspin) 146 | printf("Make Selection %d\n\n", j); 147 | else 148 | printf("Select [0-%d]: ", j); 149 | fflush(stdout); 150 | if (scanf("%64s", buf) <= 0) 151 | { printf("no input\n"); 152 | return ZE; 153 | } 154 | if (isdigit((int)buf[0])) 155 | k = atoi(buf); 156 | else 157 | { if (buf[0] == 'q') 158 | alldone(0); 159 | k = -1; 160 | } 161 | } else 162 | { k = MadeChoice; 163 | MadeChoice = 0; 164 | } 165 | if (k < 1 || k > j) 166 | { if (k != 0) printf("\tchoice outside range\n"); 167 | return ZE; 168 | } 169 | k--; 170 | } else 171 | { if (e->n && e->n->indstep >= 0) 172 | k = 0; /* select 1st executable guard */ 173 | else 174 | k = Rand()%j; /* nondeterminism */ 175 | } 176 | 177 | has_else = ZE; 178 | bas_else = ZE; 179 | for (i = 0, z = e->sub; i < j+k; i++) 180 | { if (z->this->frst 181 | && z->this->frst->n->ntyp == ELSE) 182 | { bas_else = z->this->frst; 183 | has_else = (Rvous)?ZE:bas_else->nxt; 184 | if (!interactive || depth < jumpsteps 185 | || Escape_Check 186 | || (e->status&(D_ATOM))) 187 | { z = (z->nxt)?z->nxt:e->sub; 188 | continue; 189 | } 190 | } 191 | if (z->this->frst 192 | && ((z->this->frst->n->ntyp == ATOMIC 193 | || z->this->frst->n->ntyp == D_STEP) 194 | && z->this->frst->n->sl->this->frst->n->ntyp == ELSE)) 195 | { bas_else = z->this->frst->n->sl->this->frst; 196 | has_else = (Rvous)?ZE:bas_else->nxt; 197 | if (!interactive || depth < jumpsteps 198 | || Escape_Check 199 | || (e->status&(D_ATOM))) 200 | { z = (z->nxt)?z->nxt:e->sub; 201 | continue; 202 | } 203 | } 204 | if (i >= k) 205 | { if ((f = eval_sub(z->this->frst)) != ZE) 206 | return f; 207 | else if (interactive && depth >= jumpsteps 208 | && !(e->status&(D_ATOM))) 209 | { if (!E_Check && !Escape_Check) 210 | printf("\tunexecutable\n"); 211 | return ZE; 212 | } } 213 | z = (z->nxt)?z->nxt:e->sub; 214 | } 215 | LastStep = bas_else; 216 | return has_else; 217 | } else 218 | { if (e->n->ntyp == ATOMIC 219 | || e->n->ntyp == D_STEP) 220 | { f = e->n->sl->this->frst; 221 | g = e->n->sl->this->last; 222 | g->nxt = e->nxt; 223 | if (!(g = eval_sub(f))) /* atomic guard */ 224 | return ZE; 225 | return g; 226 | } else if (e->n->ntyp == NON_ATOMIC) 227 | { f = e->n->sl->this->frst; 228 | g = e->n->sl->this->last; 229 | g->nxt = e->nxt; /* close it */ 230 | return eval_sub(f); 231 | } else if (e->n->ntyp == '.') 232 | { if (!Rvous) return e->nxt; 233 | return eval_sub(e->nxt); 234 | } else 235 | { SeqList *x; 236 | if (!(e->status & (D_ATOM)) 237 | && e->esc && (verbose&32)) 238 | { printf("Stmnt ["); 239 | comment(stdout, e->n, 0); 240 | printf("] has escape(s): "); 241 | for (x = e->esc; x; x = x->nxt) 242 | { printf("["); 243 | g = x->this->frst; 244 | if (g->n->ntyp == ATOMIC 245 | || g->n->ntyp == NON_ATOMIC) 246 | g = g->n->sl->this->frst; 247 | comment(stdout, g->n, 0); 248 | printf("] "); 249 | } 250 | printf("\n"); 251 | } 252 | #if 0 253 | if (!(e->status & D_ATOM)) /* escapes don't reach inside d_steps */ 254 | /* 4.2.4: only the guard of a d_step can have an escape */ 255 | #endif 256 | #if 1 257 | if (!s_trail) /* trail determines selections, new 5.2.5 */ 258 | #endif 259 | { Escape_Check++; 260 | if (like_java) 261 | { if ((g = rev_escape(e->esc)) != ZE) 262 | { if (verbose&4) 263 | { printf("\tEscape taken (-J) "); 264 | if (g->n && g->n->fn) 265 | printf("%s:%d", g->n->fn->name, g->n->ln); 266 | printf("\n"); 267 | } 268 | Escape_Check--; 269 | return g; 270 | } 271 | } else 272 | { for (x = e->esc; x; x = x->nxt) 273 | { if ((g = eval_sub(x->this->frst)) != ZE) 274 | { if (verbose&4) 275 | { printf("\tEscape taken "); 276 | if (g->n && g->n->fn) 277 | printf("%s:%d", g->n->fn->name, g->n->ln); 278 | printf("\n"); 279 | } 280 | Escape_Check--; 281 | return g; 282 | } } } 283 | Escape_Check--; 284 | } 285 | switch (e->n->ntyp) { 286 | case ASGN: 287 | if (check_track(e->n) == STRUCT) { break; } 288 | /* else fall thru */ 289 | case TIMEOUT: case RUN: 290 | case PRINT: case PRINTM: 291 | case C_CODE: case C_EXPR: 292 | case ASSERT: 293 | case 's': case 'r': case 'c': 294 | /* toplevel statements only */ 295 | LastStep = e; 296 | default: 297 | break; 298 | } 299 | if (Rvous) 300 | { 301 | return (eval_sync(e))?e->nxt:ZE; 302 | } 303 | return (eval(e->n))?e->nxt:ZE; 304 | } 305 | } 306 | return ZE; /* not reached */ 307 | } 308 | 309 | static int 310 | eval_sync(Element *e) 311 | { /* allow only synchronous receives 312 | and related node types */ 313 | Lextok *now = (e)?e->n:ZN; 314 | 315 | if (!now 316 | || now->ntyp != 'r' 317 | || now->val >= 2 /* no rv with a poll */ 318 | || !q_is_sync(now)) 319 | { 320 | return 0; 321 | } 322 | 323 | LastStep = e; 324 | return eval(now); 325 | } 326 | 327 | static int 328 | assign(Lextok *now) 329 | { int t; 330 | 331 | if (TstOnly) return 1; 332 | 333 | switch (now->rgt->ntyp) { 334 | case FULL: case NFULL: 335 | case EMPTY: case NEMPTY: 336 | case RUN: case LEN: 337 | t = BYTE; 338 | break; 339 | default: 340 | t = Sym_typ(now->rgt); 341 | break; 342 | } 343 | typ_ck(Sym_typ(now->lft), t, "assignment"); 344 | 345 | return setval(now->lft, eval(now->rgt)); 346 | } 347 | 348 | static int 349 | nonprogress(void) /* np_ */ 350 | { RunList *r; 351 | 352 | for (r = run; r; r = r->nxt) 353 | { if (has_lab(r->pc, 4)) /* 4=progress */ 354 | return 0; 355 | } 356 | return 1; 357 | } 358 | 359 | int 360 | eval(Lextok *now) 361 | { 362 | if (now) { 363 | lineno = now->ln; 364 | Fname = now->fn; 365 | #ifdef DEBUG 366 | printf("eval "); 367 | comment(stdout, now, 0); 368 | printf("\n"); 369 | #endif 370 | switch (now->ntyp) { 371 | case CONST: return now->val; 372 | case '!': return !eval(now->lft); 373 | case UMIN: return -eval(now->lft); 374 | case '~': return ~eval(now->lft); 375 | 376 | case '/': return (eval(now->lft) / eval(now->rgt)); 377 | case '*': return (eval(now->lft) * eval(now->rgt)); 378 | case '-': return (eval(now->lft) - eval(now->rgt)); 379 | case '+': return (eval(now->lft) + eval(now->rgt)); 380 | case '%': return (eval(now->lft) % eval(now->rgt)); 381 | case LT: return (eval(now->lft) < eval(now->rgt)); 382 | case GT: return (eval(now->lft) > eval(now->rgt)); 383 | case '&': return (eval(now->lft) & eval(now->rgt)); 384 | case '^': return (eval(now->lft) ^ eval(now->rgt)); 385 | case '|': return (eval(now->lft) | eval(now->rgt)); 386 | case LE: return (eval(now->lft) <= eval(now->rgt)); 387 | case GE: return (eval(now->lft) >= eval(now->rgt)); 388 | case NE: return (eval(now->lft) != eval(now->rgt)); 389 | case EQ: return (eval(now->lft) == eval(now->rgt)); 390 | case OR: return (eval(now->lft) || eval(now->rgt)); 391 | case AND: return (eval(now->lft) && eval(now->rgt)); 392 | case LSHIFT: return (eval(now->lft) << eval(now->rgt)); 393 | case RSHIFT: return (eval(now->lft) >> eval(now->rgt)); 394 | case '?': return (eval(now->lft) ? eval(now->rgt->lft) 395 | : eval(now->rgt->rgt)); 396 | 397 | case 'p': return remotevar(now); /* _p for remote reference */ 398 | case 'q': return remotelab(now); 399 | case 'R': return qrecv(now, 0); /* test only */ 400 | case LEN: return qlen(now); 401 | case FULL: return (qfull(now)); 402 | case EMPTY: return (qlen(now)==0); 403 | case NFULL: return (!qfull(now)); 404 | case NEMPTY: return (qlen(now)>0); 405 | case ENABLED: if (s_trail) return 1; 406 | return pc_enabled(now->lft); 407 | 408 | case GET_P: return get_priority(now->lft); 409 | case SET_P: set_priority(now->lft->lft, now->lft->rgt); return 1; 410 | 411 | case EVAL: return eval(now->lft); 412 | case PC_VAL: return pc_value(now->lft); 413 | case NONPROGRESS: return nonprogress(); 414 | case NAME: return getval(now); 415 | 416 | case TIMEOUT: return Tval; 417 | case RUN: return TstOnly?1:enable(now); 418 | 419 | case 's': return qsend(now); /* send */ 420 | case 'r': return qrecv(now, 1); /* receive or poll */ 421 | case 'c': return eval(now->lft); /* condition */ 422 | case PRINT: return TstOnly?1:interprint(stdout, now); 423 | case PRINTM: return TstOnly?1:printm(stdout, now); 424 | case ASGN: 425 | if (check_track(now) == STRUCT) { return 1; } 426 | return assign(now); 427 | 428 | case C_CODE: if (!analyze) 429 | { printf("%s:\t", now->sym->name); 430 | plunk_inline(stdout, now->sym->name, 0, 1); 431 | } 432 | return 1; /* uninterpreted */ 433 | 434 | case C_EXPR: if (!analyze) 435 | { printf("%s:\t", now->sym->name); 436 | plunk_expr(stdout, now->sym->name); 437 | printf("\n"); 438 | } 439 | return 1; /* uninterpreted */ 440 | 441 | case ASSERT: if (TstOnly || eval(now->lft)) return 1; 442 | non_fatal("assertion violated", (char *) 0); 443 | printf("spin: text of failed assertion: assert("); 444 | comment(stdout, now->lft, 0); 445 | printf(")\n"); 446 | if (s_trail && !xspin) return 1; 447 | wrapup(1); /* doesn't return */ 448 | 449 | case IF: case DO: case BREAK: case UNLESS: /* compound */ 450 | case '.': return 1; /* return label for compound */ 451 | case '@': return 0; /* stop state */ 452 | case ELSE: return 1; /* only hit here in guided trails */ 453 | 454 | case ',': /* reached through option -A with array initializer */ 455 | case 0: 456 | return 0; /* not great, but safe */ 457 | 458 | default : printf("spin: bad node type %d (run)\n", now->ntyp); 459 | if (s_trail) printf("spin: trail file doesn't match spec?\n"); 460 | fatal("aborting", 0); 461 | }} 462 | return 0; 463 | } 464 | 465 | int 466 | printm(FILE *fd, Lextok *n) 467 | { extern char Buf[]; 468 | int j; 469 | 470 | Buf[0] = '\0'; 471 | if (!no_print) 472 | if (!s_trail || depth >= jumpsteps) { 473 | if (n->lft->ismtyp) 474 | j = n->lft->val; 475 | else 476 | j = eval(n->lft); 477 | sr_buf(j, 1); 478 | dotag(fd, Buf); 479 | } 480 | return 1; 481 | } 482 | 483 | int 484 | interprint(FILE *fd, Lextok *n) 485 | { Lextok *tmp = n->lft; 486 | char c, *s = n->sym->name; 487 | int i, j; char lbuf[512]; /* matches value in sr_buf() */ 488 | extern char Buf[]; /* global, size 4096 */ 489 | char tBuf[4096]; /* match size of global Buf[] */ 490 | 491 | Buf[0] = '\0'; 492 | if (!no_print) 493 | if (!s_trail || depth >= jumpsteps) { 494 | for (i = 0; i < (int) strlen(s); i++) 495 | switch (s[i]) { 496 | case '\"': break; /* ignore */ 497 | case '\\': 498 | switch(s[++i]) { 499 | case 't': strcat(Buf, "\t"); break; 500 | case 'n': strcat(Buf, "\n"); break; 501 | default: goto onechar; 502 | } 503 | break; 504 | case '%': 505 | if ((c = s[++i]) == '%') 506 | { strcat(Buf, "%"); /* literal */ 507 | break; 508 | } 509 | if (!tmp) 510 | { non_fatal("too few print args %s", s); 511 | break; 512 | } 513 | j = eval(tmp->lft); 514 | tmp = tmp->rgt; 515 | switch(c) { 516 | case 'c': sprintf(lbuf, "%c", j); break; 517 | case 'd': sprintf(lbuf, "%d", j); break; 518 | 519 | case 'e': strcpy(tBuf, Buf); /* event name */ 520 | Buf[0] = '\0'; 521 | sr_buf(j, 1); 522 | strcpy(lbuf, Buf); 523 | strcpy(Buf, tBuf); 524 | break; 525 | 526 | case 'o': sprintf(lbuf, "%o", j); break; 527 | case 'u': sprintf(lbuf, "%u", (unsigned) j); break; 528 | case 'x': sprintf(lbuf, "%x", j); break; 529 | default: non_fatal("bad print cmd: '%s'", &s[i-1]); 530 | lbuf[0] = '\0'; break; 531 | } 532 | goto append; 533 | default: 534 | onechar: lbuf[0] = s[i]; lbuf[1] = '\0'; 535 | append: strcat(Buf, lbuf); 536 | break; 537 | } 538 | dotag(fd, Buf); 539 | } 540 | if (strlen(Buf) >= 4096) fatal("printf string too long", 0); 541 | return 1; 542 | } 543 | 544 | static int 545 | Enabled1(Lextok *n) 546 | { int i; int v = verbose; 547 | 548 | if (n) 549 | switch (n->ntyp) { 550 | case 'c': 551 | if (has_typ(n->lft, RUN)) 552 | return 1; /* conservative */ 553 | /* else fall through */ 554 | default: /* side-effect free */ 555 | verbose = 0; 556 | E_Check++; 557 | i = eval(n); 558 | E_Check--; 559 | verbose = v; 560 | return i; 561 | 562 | case SET_P: 563 | case C_CODE: case C_EXPR: 564 | case PRINT: case PRINTM: 565 | case ASGN: case ASSERT: 566 | return 1; 567 | 568 | case 's': 569 | if (q_is_sync(n)) 570 | { if (Rvous) return 0; 571 | TstOnly = 1; verbose = 0; 572 | E_Check++; 573 | i = eval(n); 574 | E_Check--; 575 | TstOnly = 0; verbose = v; 576 | return i; 577 | } 578 | return (!qfull(n)); 579 | case 'r': 580 | if (q_is_sync(n)) 581 | return 0; /* it's never a user-choice */ 582 | n->ntyp = 'R'; verbose = 0; 583 | E_Check++; 584 | i = eval(n); 585 | E_Check--; 586 | n->ntyp = 'r'; verbose = v; 587 | return i; 588 | } 589 | return 0; 590 | } 591 | 592 | int 593 | Enabled0(Element *e) 594 | { SeqList *z; 595 | 596 | if (!e || !e->n) 597 | return 0; 598 | 599 | switch (e->n->ntyp) { 600 | case '@': 601 | return X->pid == (nproc-nstop-1); 602 | case '.': 603 | case SET_P: 604 | return 1; 605 | case GOTO: 606 | if (Rvous) return 0; 607 | return 1; 608 | case UNLESS: 609 | return Enabled0(e->sub->this->frst); 610 | case ATOMIC: 611 | case D_STEP: 612 | case NON_ATOMIC: 613 | return Enabled0(e->n->sl->this->frst); 614 | } 615 | if (e->sub) /* true for IF, DO, and UNLESS */ 616 | { for (z = e->sub; z; z = z->nxt) 617 | if (Enabled0(z->this->frst)) 618 | return 1; 619 | return 0; 620 | } 621 | for (z = e->esc; z; z = z->nxt) 622 | { if (Enabled0(z->this->frst)) 623 | return 1; 624 | } 625 | #if 0 626 | printf("enabled1 "); 627 | comment(stdout, e->n, 0); 628 | printf(" ==> %s\n", Enabled1(e->n)?"yes":"nope"); 629 | #endif 630 | return Enabled1(e->n); 631 | } 632 | 633 | int 634 | pc_enabled(Lextok *n) 635 | { int i = nproc - nstop; 636 | int pid = eval(n); 637 | int result = 0; 638 | RunList *Y, *oX; 639 | 640 | if (pid == X->pid) 641 | fatal("used: enabled(pid=thisproc) [%s]", X->n->name); 642 | 643 | for (Y = run; Y; Y = Y->nxt) 644 | if (--i == pid) 645 | { oX = X; X = Y; 646 | result = Enabled0(X->pc); 647 | X = oX; 648 | break; 649 | } 650 | return result; 651 | } 652 | 653 | int 654 | pc_highest(Lextok *n) 655 | { int i = nproc - nstop; 656 | int pid = eval(n); 657 | int target = 0, result = 1; 658 | RunList *Y, *oX; 659 | 660 | if (X->prov && !eval(X->prov)) return 0; /* can't be highest unless fully enabled */ 661 | 662 | for (Y = run; Y; Y = Y->nxt) 663 | { if (--i == pid) 664 | { target = Y->priority; 665 | break; 666 | } } 667 | if (0) printf("highest for pid %d @ priority = %d\n", pid, target); 668 | 669 | oX = X; 670 | i = nproc - nstop; 671 | for (Y = run; Y; Y = Y->nxt) 672 | { i--; 673 | if (0) printf(" pid %d @ priority %d\t", Y->pid, Y->priority); 674 | if (Y->priority > target) 675 | { X = Y; 676 | if (0) printf("enabled: %s\n", Enabled0(X->pc)?"yes":"nope"); 677 | if (0) printf("provided: %s\n", eval(X->prov)?"yes":"nope"); 678 | if (Enabled0(X->pc) && (!X->prov || eval(X->prov))) 679 | { result = 0; 680 | break; 681 | } } 682 | else 683 | if (0) printf("\n"); 684 | } 685 | X = oX; 686 | 687 | return result; 688 | } 689 | 690 | int 691 | get_priority(Lextok *n) 692 | { int i = nproc - nstop; 693 | int pid = eval(n); 694 | RunList *Y; 695 | 696 | if (old_priority_rules) 697 | { return 1; 698 | } 699 | 700 | for (Y = run; Y; Y = Y->nxt) 701 | { if (--i == pid) 702 | { return Y->priority; 703 | } } 704 | return 0; 705 | } 706 | 707 | void 708 | set_priority(Lextok *n, Lextok *p) 709 | { int i = nproc - nstop - Have_claim; 710 | int pid = eval(n); 711 | RunList *Y; 712 | 713 | if (old_priority_rules) 714 | { return; 715 | } 716 | for (Y = run; Y; Y = Y->nxt) 717 | { if (--i == pid) 718 | { Priority_Sum -= Y->priority; 719 | Y->priority = eval(p); 720 | Priority_Sum += Y->priority; 721 | if (1) 722 | { printf("%3d: setting priority of proc %d (%s) to %d\n", 723 | depth, pid, Y->n->name, Y->priority); 724 | } } } 725 | if (verbose&32) 726 | { printf("\tPid\tName\tPriority\n"); 727 | for (Y = run; Y; Y = Y->nxt) 728 | { printf("\t%d\t%s\t%d\n", 729 | Y->pid, 730 | Y->n->name, 731 | Y->priority); 732 | } } 733 | } 734 | --------------------------------------------------------------------------------