]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/spin/tl_buchi.c
cpu: make -p work with explicit service in dialstring (same as import)
[plan9front.git] / sys / src / cmd / spin / tl_buchi.c
1 /***** tl_spin: tl_buchi.c *****/
2
3 /* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories.     */
4 /* All Rights Reserved.  This software is for educational purposes only.  */
5 /* No guarantee whatsoever is expressed or implied by the distribution of */
6 /* this code.  Permission is given to distribute this code provided that  */
7 /* this introductory message is not removed and no monies are exchanged.  */
8 /* Software written by Gerard J. Holzmann.  For tool documentation see:   */
9 /*             http://spinroot.com/                                       */
10 /* Send all bug-reports and/or questions to: bugs@spinroot.com            */
11
12 /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
13 /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.   */
14
15 #include "tl.h"
16
17 extern int tl_verbose, tl_clutter, Total, Max_Red;
18
19 FILE    *tl_out;        /* if standalone: = stdout; */
20
21 typedef struct Transition {
22         Symbol *name;
23         Node *cond;
24         int redundant, merged, marked;
25         struct Transition *nxt;
26 } Transition;
27
28 typedef struct State {
29         Symbol  *name;
30         Transition *trans;
31         Graph   *colors;
32         unsigned char redundant;
33         unsigned char accepting;
34         unsigned char reachable;
35         struct State *nxt;
36 } State;
37
38 static State *never = (State *) 0;
39 static int hitsall;
40
41 static int
42 sametrans(Transition *s, Transition *t)
43 {
44         if (strcmp(s->name->name, t->name->name) != 0)
45                 return 0;
46         return isequal(s->cond, t->cond);
47 }
48
49 static Node *
50 Prune(Node *p)
51 {
52         if (p)
53         switch (p->ntyp) {
54         case PREDICATE:
55         case NOT:
56         case FALSE:
57         case TRUE:
58 #ifdef NXT
59         case NEXT:
60 #endif
61                 return p;
62         case OR:
63                 p->lft = Prune(p->lft);
64                 if (!p->lft)
65                 {       releasenode(1, p->rgt);
66                         return ZN;
67                 }
68                 p->rgt = Prune(p->rgt);
69                 if (!p->rgt)
70                 {       releasenode(1, p->lft);
71                         return ZN;
72                 }
73                 return p;
74         case AND:
75                 p->lft = Prune(p->lft);
76                 if (!p->lft)
77                         return Prune(p->rgt);
78                 p->rgt = Prune(p->rgt);
79                 if (!p->rgt)
80                         return p->lft;
81                 return p;
82         }
83         releasenode(1, p);
84         return ZN;
85 }
86
87 static State *
88 findstate(char *nm)
89 {       State *b;
90         for (b = never; b; b = b->nxt)
91                 if (!strcmp(b->name->name, nm))
92                         return b;
93         if (strcmp(nm, "accept_all"))
94         {       if (strncmp(nm, "accept", 6))
95                 {       int i; char altnm[64];
96                         for (i = 0; i < 64; i++)
97                                 if (nm[i] == '_')
98                                         break;
99                         if (i >= 64)
100                                 Fatal("name too long %s", nm);
101                         sprintf(altnm, "accept%s", &nm[i]);
102                         return findstate(altnm);
103                 }
104         /*      Fatal("buchi: no state %s", nm); */
105         }
106         return (State *) 0;
107 }
108
109 static void
110 Dfs(State *b)
111 {       Transition *t;
112
113         if (!b || b->reachable) return;
114         b->reachable = 1;
115
116         if (b->redundant)
117                 printf("/* redundant state %s */\n",
118                         b->name->name);
119         for (t = b->trans; t; t = t->nxt)
120         {       if (!t->redundant)
121                 {       Dfs(findstate(t->name->name));
122                         if (!hitsall
123                         &&  strcmp(t->name->name, "accept_all") == 0)
124                                 hitsall = 1;
125                 }
126         }
127 }
128
129 void
130 retarget(char *from, char *to)
131 {       State *b;
132         Transition *t;
133         Symbol *To = tl_lookup(to);
134
135         if (tl_verbose) printf("replace %s with %s\n", from, to);
136
137         for (b = never; b; b = b->nxt)
138         {       if (!strcmp(b->name->name, from))
139                         b->redundant = 1;
140                 else
141                 for (t = b->trans; t; t = t->nxt)
142                 {       if (!strcmp(t->name->name, from))
143                                 t->name = To;
144         }       }
145 }
146
147 #ifdef NXT
148 static Node *
149 nonxt(Node *n)
150 {
151         switch (n->ntyp) {
152         case U_OPER:
153         case V_OPER:
154         case NEXT:
155                 return ZN;
156         case OR:
157                 n->lft = nonxt(n->lft);
158                 n->rgt = nonxt(n->rgt);
159                 if (!n->lft || !n->rgt)
160                         return True;
161                 return n;
162         case AND:
163                 n->lft = nonxt(n->lft);
164                 n->rgt = nonxt(n->rgt);
165                 if (!n->lft)
166                 {       if (!n->rgt)
167                                 n = ZN;
168                         else
169                                 n = n->rgt;
170                 } else if (!n->rgt)
171                         n = n->lft;
172                 return n;
173         }
174         return n;
175 }
176 #endif
177
178 static Node *
179 combination(Node *s, Node *t)
180 {       Node *nc;
181 #ifdef NXT
182         Node *a = nonxt(s);
183         Node *b = nonxt(t);
184
185         if (tl_verbose)
186         {       printf("\tnonxtA: "); dump(a);
187                 printf("\n\tnonxtB: "); dump(b);
188                 printf("\n");
189         }
190         /* if there's only a X(f), its equivalent to true */
191         if (!a || !b)
192                 nc = True;
193         else
194                 nc = tl_nn(OR, a, b);
195 #else
196         nc = tl_nn(OR, s, t);
197 #endif
198         if (tl_verbose)
199         {       printf("\tcombo: "); dump(nc);
200                 printf("\n");
201         }
202         return nc;
203 }
204
205 Node *
206 unclutter(Node *n, char *snm)
207 {       Node *t, *s, *v, *u;
208         Symbol *w;
209
210         /* check only simple cases like !q && q */
211         for (t = n; t; t = t->rgt)
212         {       if (t->rgt)
213                 {       if (t->ntyp != AND || !t->lft)
214                                 return n;
215                         if (t->lft->ntyp != PREDICATE
216 #ifdef NXT
217                         &&  t->lft->ntyp != NEXT
218 #endif
219                         &&  t->lft->ntyp != NOT)
220                                 return n;
221                 } else
222                 {       if (t->ntyp != PREDICATE
223 #ifdef NXT
224                         &&  t->ntyp != NEXT
225 #endif
226                         &&  t->ntyp != NOT)
227                                 return n;
228                 }
229         }
230
231         for (t = n; t; t = t->rgt)
232         {       if (t->rgt)
233                         v = t->lft;
234                 else
235                         v = t;
236                 if (v->ntyp == NOT
237                 &&  v->lft->ntyp == PREDICATE)
238                 {       w = v->lft->sym;
239                         for (s = n; s; s = s->rgt)
240                         {       if (s == t) continue;
241                                 if (s->rgt)
242                                         u = s->lft;
243                                 else
244                                         u = s;
245                                 if (u->ntyp == PREDICATE
246                                 &&  strcmp(u->sym->name, w->name) == 0)
247                                 {       if (tl_verbose)
248                                         {       printf("BINGO %s:\t", snm);
249                                                 dump(n);
250                                                 printf("\n");
251                                         }
252                                         return False;
253                                 }
254                         }
255         }       }
256         return n;
257 }
258
259 static void
260 clutter(void)
261 {       State *p;
262         Transition *s;
263
264         for (p = never; p; p = p->nxt)
265         for (s = p->trans; s; s = s->nxt)
266         {       s->cond = unclutter(s->cond, p->name->name);
267                 if (s->cond
268                 &&  s->cond->ntyp == FALSE)
269                 {       if (s != p->trans 
270                         ||  s->nxt)
271                                 s->redundant = 1;
272                 }
273         }
274 }
275
276 static void
277 showtrans(State *a)
278 {       Transition *s;
279
280         for (s = a->trans; s; s = s->nxt)
281         {       printf("%s ", s->name?s->name->name:"-");
282                 dump(s->cond);
283                 printf(" %d %d %d\n", s->redundant, s->merged, s->marked);
284         }
285 }
286
287 static int
288 mergetrans(void)
289 {       State *b;
290         Transition *s, *t;
291         Node *nc; int cnt = 0;
292
293         for (b = never; b; b = b->nxt)
294         {       if (!b->reachable) continue;
295
296                 for (s = b->trans; s; s = s->nxt)
297                 {       if (s->redundant) continue;
298
299                         for (t = s->nxt; t; t = t->nxt)
300                         if (!t->redundant
301                         &&  !strcmp(s->name->name, t->name->name))
302                         {       if (tl_verbose)
303                                 {       printf("===\nstate %s, trans to %s redundant\n",
304                                         b->name->name, s->name->name);
305                                         showtrans(b);
306                                         printf(" conditions ");
307                                         dump(s->cond); printf(" <-> ");
308                                         dump(t->cond); printf("\n");
309                                 }
310
311                                 if (!s->cond) /* same as T */
312                                 {       releasenode(1, t->cond); /* T or t */
313                                         nc = True;
314                                 } else if (!t->cond)
315                                 {       releasenode(1, s->cond);
316                                         nc = True;
317                                 } else
318                                 {       nc = combination(s->cond, t->cond);
319                                 }
320                                 t->cond = rewrite(nc);
321                                 t->merged = 1;
322                                 s->redundant = 1;
323                                 cnt++;
324                                 break;
325         }       }       }
326         return cnt;
327 }
328
329 static int
330 all_trans_match(State *a, State *b)
331 {       Transition *s, *t;
332         int found, result = 0;
333
334         if (a->accepting != b->accepting)
335                 goto done;
336
337         for (s = a->trans; s; s = s->nxt)
338         {       if (s->redundant) continue;
339                 found = 0;
340                 for (t = b->trans; t; t = t->nxt)
341                 {       if (t->redundant) continue;
342                         if (sametrans(s, t))
343                         {       found = 1;
344                                 t->marked = 1;
345                                 break;
346                 }       }
347                 if (!found)
348                         goto done;
349         }
350         for (s = b->trans; s; s = s->nxt)
351         {       if (s->redundant || s->marked) continue;
352                 found = 0;
353                 for (t = a->trans; t; t = t->nxt)
354                 {       if (t->redundant) continue;
355                         if (sametrans(s, t))
356                         {       found = 1;
357                                 break;
358                 }       }
359                 if (!found)
360                         goto done;
361         }
362         result = 1;
363 done:
364         for (s = b->trans; s; s = s->nxt)
365                 s->marked = 0;
366         return result;
367 }
368
369 #ifndef NO_OPT
370 #define BUCKY
371 #endif
372
373 #ifdef BUCKY
374 static int
375 all_bucky(State *a, State *b)
376 {       Transition *s, *t;
377         int found, result = 0;
378
379         for (s = a->trans; s; s = s->nxt)
380         {       if (s->redundant) continue;
381                 found = 0;
382                 for (t = b->trans; t; t = t->nxt)
383                 {       if (t->redundant) continue;
384
385                         if (isequal(s->cond, t->cond))
386                         {       if (strcmp(s->name->name, b->name->name) == 0
387                                 &&  strcmp(t->name->name, a->name->name) == 0)
388                                 {       found = 1;      /* they point to each other */
389                                         t->marked = 1;
390                                         break;
391                                 }
392                                 if (strcmp(s->name->name, t->name->name) == 0
393                                 &&  strcmp(s->name->name, "accept_all") == 0)
394                                 {       found = 1;
395                                         t->marked = 1;
396                                         break;
397                                 /* same exit from which there is no return */
398                                 }
399                         }
400                 }
401                 if (!found)
402                         goto done;
403         }
404         for (s = b->trans; s; s = s->nxt)
405         {       if (s->redundant || s->marked) continue;
406                 found = 0;
407                 for (t = a->trans; t; t = t->nxt)
408                 {       if (t->redundant) continue;
409
410                         if (isequal(s->cond, t->cond))
411                         {       if (strcmp(s->name->name, a->name->name) == 0
412                                 &&  strcmp(t->name->name, b->name->name) == 0)
413                                 {       found = 1;
414                                         t->marked = 1;
415                                         break;
416                                 }
417                                 if (strcmp(s->name->name, t->name->name) == 0
418                                 &&  strcmp(s->name->name, "accept_all") == 0)
419                                 {       found = 1;
420                                         t->marked = 1;
421                                         break;
422                                 }
423                         }
424                 }
425                 if (!found)
426                         goto done;
427         }
428         result = 1;
429 done:
430         for (s = b->trans; s; s = s->nxt)
431                 s->marked = 0;
432         return result;
433 }
434
435 static int
436 buckyballs(void)
437 {       State *a, *b, *c, *d;
438         int m, cnt=0;
439
440         do {
441                 m = 0; cnt++;
442                 for (a = never; a; a = a->nxt)
443                 {       if (!a->reachable) continue;
444
445                         if (a->redundant) continue;
446
447                         for (b = a->nxt; b; b = b->nxt)
448                         {       if (!b->reachable) continue;
449
450                                 if (b->redundant) continue;
451
452                                 if (all_bucky(a, b))
453                                 {       m++;
454                                         if (tl_verbose)
455                                         {       printf("%s bucky match %s\n",
456                                                 a->name->name, b->name->name);
457                                         }
458
459                                         if (a->accepting && !b->accepting)
460                                         {       if (strcmp(b->name->name, "T0_init") == 0)
461                                                 {       c = a; d = b;
462                                                         b->accepting = 1;
463                                                 } else
464                                                 {       c = b; d = a;
465                                                 }
466                                         } else
467                                         {       c = a; d = b;
468                                         }
469
470                                         retarget(c->name->name, d->name->name);
471                                         if (!strncmp(c->name->name, "accept", 6)
472                                         &&  Max_Red == 0)
473                                         {       char buf[64];
474                                                 sprintf(buf, "T0%s", &(c->name->name[6]));
475                                                 retarget(buf, d->name->name);
476                                         }
477                                         break;
478                                 }
479                 }       }
480         } while (m && cnt < 10);
481         return cnt-1;
482 }
483 #endif
484
485 static int
486 mergestates(int v)
487 {       State *a, *b;
488         int m, cnt=0;
489
490         if (tl_verbose)
491                 return 0;
492
493         do {
494                 m = 0; cnt++;
495                 for (a = never; a; a = a->nxt)
496                 {       if (v && !a->reachable) continue;
497
498                         if (a->redundant) continue; /* 3.3.10 */
499
500                         for (b = a->nxt; b; b = b->nxt)
501                         {       if (v && !b->reachable) continue;
502
503                                 if (b->redundant) continue; /* 3.3.10 */
504
505                                 if (all_trans_match(a, b))
506                                 {       m++;
507                                         if (tl_verbose)
508                                         {       printf("%d: state %s equals state %s\n",
509                                                 cnt, a->name->name, b->name->name);
510                                                 showtrans(a);
511                                                 printf("==\n");
512                                                 showtrans(b);
513                                         }
514                                         retarget(a->name->name, b->name->name);
515                                         if (!strncmp(a->name->name, "accept", 6)
516                                         &&  Max_Red == 0)
517                                         {       char buf[64];
518                                                 sprintf(buf, "T0%s", &(a->name->name[6]));
519                                                 retarget(buf, b->name->name);
520                                         }
521                                         break;
522                                 }
523 #if 0
524                                 else if (tl_verbose)
525                                 {       printf("\n%d: state %s differs from state %s [%d,%d]\n",
526                                                 cnt, a->name->name, b->name->name,
527                                                 a->accepting, b->accepting);
528                                         showtrans(a);
529                                         printf("==\n");
530                                         showtrans(b);
531                                         printf("\n");
532                                 }
533 #endif
534                 }       }
535         } while (m && cnt < 10);
536         return cnt-1;
537 }
538
539 static int tcnt;
540
541 static void
542 rev_trans(Transition *t) /* print transitions  in reverse order... */
543 {
544         if (!t) return;
545         rev_trans(t->nxt);
546
547         if (t->redundant && !tl_verbose) return;
548         fprintf(tl_out, "\t:: (");
549         if (dump_cond(t->cond, t->cond, 1))
550                 fprintf(tl_out, "1");
551         fprintf(tl_out, ") -> goto %s\n", t->name->name);
552         tcnt++;
553 }
554
555 static void
556 printstate(State *b)
557 {
558         if (!b || (!tl_verbose && !b->reachable)) return;
559
560         b->reachable = 0;       /* print only once */
561         fprintf(tl_out, "%s:\n", b->name->name);
562
563         if (tl_verbose)
564         {       fprintf(tl_out, "       /* ");
565                 dump(b->colors->Other);
566                 fprintf(tl_out, " */\n");
567         }
568
569         if (strncmp(b->name->name, "accept", 6) == 0
570         &&  Max_Red == 0)
571                 fprintf(tl_out, "T0%s:\n", &(b->name->name[6]));
572
573         fprintf(tl_out, "\tif\n");
574         tcnt = 0;
575         rev_trans(b->trans);
576         if (!tcnt) fprintf(tl_out, "\t:: false\n");
577         fprintf(tl_out, "\tfi;\n");
578         Total++;
579 }
580
581 void
582 addtrans(Graph *col, char *from, Node *op, char *to)
583 {       State *b;
584         Transition *t;
585
586         t = (Transition *) tl_emalloc(sizeof(Transition));
587         t->name = tl_lookup(to);
588         t->cond = Prune(dupnode(op));
589
590         if (tl_verbose)
591         {       printf("\n%s <<\t", from); dump(op);
592                 printf("\n\t"); dump(t->cond);
593                 printf(">> %s\n", t->name->name);
594         }
595         if (t->cond) t->cond = rewrite(t->cond);
596
597         for (b = never; b; b = b->nxt)
598                 if (!strcmp(b->name->name, from))
599                 {       t->nxt = b->trans;
600                         b->trans = t;
601                         return;
602                 }
603         b = (State *) tl_emalloc(sizeof(State));
604         b->name   = tl_lookup(from);
605         b->colors = col;
606         b->trans  = t;
607         if (!strncmp(from, "accept", 6))
608                 b->accepting = 1;
609         b->nxt = never;
610         never  = b;
611 }
612
613 static void
614 clr_reach(void)
615 {       State *p;
616         for (p = never; p; p = p->nxt)
617                 p->reachable = 0;
618         hitsall = 0;
619 }
620
621 void
622 fsm_print(void)
623 {       State *b; int cnt1, cnt2=0;
624         extern void put_uform(void);
625
626         if (tl_clutter) clutter();
627
628         b = findstate("T0_init");
629         if (Max_Red == 0)
630                 b->accepting = 1;
631
632         mergestates(0); 
633         b = findstate("T0_init");
634
635         fprintf(tl_out, "never {    /* ");
636                 put_uform();
637         fprintf(tl_out, " */\n");
638
639         do {
640                 clr_reach();
641                 Dfs(b);
642                 cnt1 = mergetrans();
643                 cnt2 = mergestates(1);
644                 if (tl_verbose)
645                         printf("/* >>%d,%d<< */\n", cnt1, cnt2);
646         } while (cnt2 > 0);
647
648 #ifdef BUCKY
649         buckyballs();
650         clr_reach();
651         Dfs(b);
652 #endif
653         if (b && b->accepting)
654                 fprintf(tl_out, "accept_init:\n");
655
656         if (!b && !never)
657         {       fprintf(tl_out, "       0 /* false */;\n");
658         } else
659         {       printstate(b);  /* init state must be first */
660                 for (b = never; b; b = b->nxt)
661                         printstate(b);
662         }
663         if (hitsall)
664         fprintf(tl_out, "accept_all:\n  skip\n");
665         fprintf(tl_out, "}\n");
666 }