Browse Source

Plan 9 from Bell Labs 2005-09-01

David du Colombier 18 years ago
parent
commit
2f21373f3d
55 changed files with 7104 additions and 1644 deletions
  1. 59 50
      dist/replica/_plan9.db
  2. 58 56
      dist/replica/plan9.db
  3. 60 0
      dist/replica/plan9.log
  4. 1 1
      sys/man/2/setjmp
  5. 22 25
      sys/man/8/ppp
  6. 41 31
      sys/src/9/port/chan.c
  7. 1 1
      sys/src/cmd/ip/ppp/ipaux.c
  8. 4 4
      sys/src/cmd/ip/ppp/ppp.c
  9. 5 5
      sys/src/cmd/ip/pppoe.c
  10. 16 6
      sys/src/cmd/seq.c
  11. 1 2
      sys/src/cmd/spin/README
  12. 56 20
      sys/src/cmd/spin/dstep.c
  13. 94 16
      sys/src/cmd/spin/flow.c
  14. 92 36
      sys/src/cmd/spin/guided.c
  15. 177 67
      sys/src/cmd/spin/main.c
  16. 28 15
      sys/src/cmd/spin/mesg.c
  17. 2 0
      sys/src/cmd/spin/mkfile
  18. 344 103
      sys/src/cmd/spin/pangen1.c
  19. 1110 30
      sys/src/cmd/spin/pangen1.h
  20. 279 112
      sys/src/cmd/spin/pangen2.c
  21. 116 115
      sys/src/cmd/spin/pangen2.h
  22. 22 18
      sys/src/cmd/spin/pangen3.c
  23. 106 85
      sys/src/cmd/spin/pangen3.h
  24. 42 37
      sys/src/cmd/spin/pangen4.c
  25. 19 19
      sys/src/cmd/spin/pangen4.h
  26. 100 115
      sys/src/cmd/spin/pangen5.c
  27. 14 13
      sys/src/cmd/spin/pangen5.h
  28. 2357 0
      sys/src/cmd/spin/pangen6.c
  29. 32 19
      sys/src/cmd/spin/pc_zpp.c
  30. 42 31
      sys/src/cmd/spin/ps_msc.c
  31. 140 0
      sys/src/cmd/spin/reprosrc.c
  32. 73 23
      sys/src/cmd/spin/run.c
  33. 171 79
      sys/src/cmd/spin/sched.c
  34. 89 38
      sys/src/cmd/spin/spin.h
  35. 101 24
      sys/src/cmd/spin/spin.y
  36. 781 43
      sys/src/cmd/spin/spinlex.c
  37. 55 15
      sys/src/cmd/spin/structs.c
  38. 25 19
      sys/src/cmd/spin/sym.c
  39. 8 6
      sys/src/cmd/spin/tl.h
  40. 40 48
      sys/src/cmd/spin/tl_buchi.c
  41. 11 7
      sys/src/cmd/spin/tl_cache.c
  42. 18 16
      sys/src/cmd/spin/tl_lex.c
  43. 22 20
      sys/src/cmd/spin/tl_main.c
  44. 8 6
      sys/src/cmd/spin/tl_mem.c
  45. 24 10
      sys/src/cmd/spin/tl_parse.c
  46. 12 25
      sys/src/cmd/spin/tl_rewrt.c
  47. 28 37
      sys/src/cmd/spin/tl_trans.c
  48. 27 28
      sys/src/cmd/spin/vars.c
  49. 1 1
      sys/src/cmd/spin/version.h
  50. 15 1
      sys/src/cmd/tar.c
  51. 3 2
      sys/src/cmd/tcs/utf.c
  52. 2 2
      sys/src/cmd/unix/spin/readme
  53. BIN
      sys/src/cmd/unix/spin/spin334.tar.gz
  54. BIN
      sys/src/cmd/unix/spin/spin425.tar.gz
  55. 150 162
      sys/src/games/memo.c

+ 59 - 50
dist/replica/_plan9.db

@@ -414,7 +414,7 @@
 386/bin/tail - 775 sys sys 1125346016 66169
 386/bin/tar - 775 sys sys 1120014538 96347
 386/bin/tbl - 775 sys sys 1125346017 113167
-386/bin/tcs - 775 sys sys 1115950118 256588
+386/bin/tcs - 775 sys sys 1125501123 256580
 386/bin/tee - 775 sys sys 1115950118 38428
 386/bin/telco - 775 sys sys 1115950118 103315
 386/bin/telnet - 775 sys sys 1125346017 80355
@@ -7513,7 +7513,7 @@ sys/man/2/seek - 664 sys sys 944959696 671
 sys/man/2/segattach - 664 sys sys 1015091526 4304
 sys/man/2/segbrk - 664 sys sys 944959696 825
 sys/man/2/segflush - 664 sys sys 944959695 944
-sys/man/2/setjmp - 664 sys sys 944959696 1856
+sys/man/2/setjmp - 664 sys sys 1125540984 1857
 sys/man/2/sin - 664 sys sys 944959694 967
 sys/man/2/sinh - 664 sys sys 944959694 360
 sys/man/2/sleep - 664 sys sys 944959694 984
@@ -7705,7 +7705,7 @@ sys/man/8/pem - 664 sys sys 1060263669 1189
 sys/man/8/ping - 664 sys sys 1084473185 3436
 sys/man/8/plan9.ini - 664 sys sys 1117814755 21579
 sys/man/8/pop3 - 664 sys sys 1063854676 2720
-sys/man/8/ppp - 664 sys sys 1096036494 4424
+sys/man/8/ppp - 664 sys sys 1125530075 4414
 sys/man/8/prep - 664 sys sys 1079705872 13820
 sys/man/8/qer - 664 sys sys 1067723129 4909
 sys/man/8/reboot - 664 sys sys 969499895 414
@@ -8039,7 +8039,7 @@ sys/src/9/port/alloc.c - 664 sys sys 1102093389 5645
 sys/src/9/port/allocb.c - 664 sys sys 1123676437 3340
 sys/src/9/port/auth.c - 664 sys sys 1123647282 2392
 sys/src/9/port/cache.c - 664 sys sys 1055688274 9241
-sys/src/9/port/chan.c - 664 sys sys 1123647283 29928
+sys/src/9/port/chan.c - 664 sys sys 1125517669 30203
 sys/src/9/port/cis.c - 664 sys sys 1099761153 9248
 sys/src/9/port/debugalloc.c - 664 sys sys 1014931171 10402
 sys/src/9/port/dev.c - 664 sys sys 1077896125 8247
@@ -11976,17 +11976,17 @@ sys/src/cmd/ip/ppp/compress.c - 664 sys sys 1072729513 11774
 sys/src/cmd/ip/ppp/doclient - 775 sys sys 944961007 50
 sys/src/cmd/ip/ppp/doserve - 775 sys sys 944961009 91
 sys/src/cmd/ip/ppp/dotest - 775 sys sys 944961006 152
-sys/src/cmd/ip/ppp/ipaux.c - 664 sys sys 1015090266 2326
+sys/src/cmd/ip/ppp/ipaux.c - 664 sys sys 1125529107 2328
 sys/src/cmd/ip/ppp/mkfile - 664 sys sys 1063897576 352
 sys/src/cmd/ip/ppp/mppc.c - 664 sys sys 1015090267 16624
-sys/src/cmd/ip/ppp/ppp.c - 664 sys sys 1125316087 59889
+sys/src/cmd/ip/ppp/ppp.c - 664 sys sys 1125530039 59897
 sys/src/cmd/ip/ppp/ppp.h - 664 sys sys 1091904423 8284
 sys/src/cmd/ip/ppp/testppp.c - 664 sys sys 1045505281 3011
 sys/src/cmd/ip/ppp/thw.c - 664 sys sys 1015090268 5962
 sys/src/cmd/ip/ppp/thwack.c - 664 sys sys 1015090268 8004
 sys/src/cmd/ip/ppp/thwack.h - 664 sys sys 964662210 2052
 sys/src/cmd/ip/ppp/unthwack.c - 664 sys sys 1015090268 5883
-sys/src/cmd/ip/pppoe.c - 664 sys sys 1050360937 12507
+sys/src/cmd/ip/pppoe.c - 664 sys sys 1125530113 12516
 sys/src/cmd/ip/pptp.c - 664 sys sys 1050360938 16575
 sys/src/cmd/ip/pptpd.c - 664 sys sys 1015701128 23548
 sys/src/cmd/ip/rarpd.c - 664 sys sys 1084470989 3389
@@ -12803,7 +12803,7 @@ sys/src/cmd/scuzz/scsireq.h - 664 sys sys 1113741890 5929
 sys/src/cmd/scuzz/scuzz.c - 664 sys sys 1121977163 37610
 sys/src/cmd/scuzz/sense.c - 664 sys sys 969510790 3901
 sys/src/cmd/sed.c - 664 sys sys 1100962924 27001
-sys/src/cmd/seq.c - 664 sys sys 1063854922 1484
+sys/src/cmd/seq.c - 664 sys sys 1125529033 1683
 sys/src/cmd/sh.C - 664 sys sys 1055701754 10303
 sys/src/cmd/sha1sum.c - 664 sys sys 1014926229 1017
 sys/src/cmd/size.c - 664 sys sys 944961619 717
@@ -12830,43 +12830,45 @@ sys/src/cmd/spell/spell.rc - 775 sys sys 964457135 312
 sys/src/cmd/spell/sprog.c - 664 sys sys 964540731 23030
 sys/src/cmd/spell/stop - 664 sys sys 944961232 18702
 sys/src/cmd/spin - 20000000775 sys sys 953242990 0
-sys/src/cmd/spin/README - 664 sys sys 953242984 344
-sys/src/cmd/spin/dstep.c - 664 sys sys 953242984 8805
-sys/src/cmd/spin/flow.c - 664 sys sys 953242984 15478
-sys/src/cmd/spin/guided.c - 664 sys sys 953242984 5899
-sys/src/cmd/spin/main.c - 664 sys sys 953242984 18700
-sys/src/cmd/spin/mesg.c - 664 sys sys 953242985 13596
-sys/src/cmd/spin/mkfile - 664 sys sys 953242985 669
-sys/src/cmd/spin/pangen1.c - 664 sys sys 953242985 23759
-sys/src/cmd/spin/pangen1.h - 664 sys sys 953242985 94543
-sys/src/cmd/spin/pangen2.c - 664 sys sys 956275776 66265
-sys/src/cmd/spin/pangen2.h - 664 sys sys 953242986 23128
-sys/src/cmd/spin/pangen3.c - 664 sys sys 953242986 8872
-sys/src/cmd/spin/pangen3.h - 664 sys sys 956275777 22057
-sys/src/cmd/spin/pangen4.c - 664 sys sys 953242986 8217
-sys/src/cmd/spin/pangen4.h - 664 sys sys 953242986 18957
-sys/src/cmd/spin/pangen5.c - 664 sys sys 953242986 16614
-sys/src/cmd/spin/pangen5.h - 664 sys sys 953242986 10852
-sys/src/cmd/spin/pc_zpp.c - 664 sys sys 956275778 8265
-sys/src/cmd/spin/ps_msc.c - 664 sys sys 953242987 11458
-sys/src/cmd/spin/run.c - 664 sys sys 953242987 13173
-sys/src/cmd/spin/sched.c - 664 sys sys 953242987 19359
-sys/src/cmd/spin/spin.h - 664 sys sys 953242987 10807
-sys/src/cmd/spin/spin.y - 664 sys sys 953242987 16731
-sys/src/cmd/spin/spinlex.c - 664 sys sys 953242987 13809
-sys/src/cmd/spin/structs.c - 664 sys sys 953242988 13364
-sys/src/cmd/spin/sym.c - 664 sys sys 953242988 11763
-sys/src/cmd/spin/tl.h - 664 sys sys 953242988 3254
-sys/src/cmd/spin/tl_buchi.c - 664 sys sys 953242988 13164
-sys/src/cmd/spin/tl_cache.c - 664 sys sys 953242988 5732
-sys/src/cmd/spin/tl_lex.c - 664 sys sys 953242988 3132
-sys/src/cmd/spin/tl_main.c - 664 sys sys 953242988 4331
-sys/src/cmd/spin/tl_mem.c - 664 sys sys 953242988 2592
-sys/src/cmd/spin/tl_parse.c - 664 sys sys 953242989 8007
-sys/src/cmd/spin/tl_rewrt.c - 664 sys sys 953242989 6257
-sys/src/cmd/spin/tl_trans.c - 664 sys sys 953242990 16758
-sys/src/cmd/spin/vars.c - 664 sys sys 953242990 8412
-sys/src/cmd/spin/version.h - 664 sys sys 956275780 54
+sys/src/cmd/spin/README - 664 sys sys 1125514858 311
+sys/src/cmd/spin/dstep.c - 664 sys sys 1125514858 9958
+sys/src/cmd/spin/flow.c - 664 sys sys 1125514858 17345
+sys/src/cmd/spin/guided.c - 664 sys sys 1125514858 6948
+sys/src/cmd/spin/main.c - 664 sys sys 1125514858 21713
+sys/src/cmd/spin/mesg.c - 664 sys sys 1125514858 13722
+sys/src/cmd/spin/mkfile - 664 sys sys 1125514859 696
+sys/src/cmd/spin/pangen1.c - 664 sys sys 1125514859 29801
+sys/src/cmd/spin/pangen1.h - 664 sys sys 1125514859 134192
+sys/src/cmd/spin/pangen2.c - 664 sys sys 1125514859 74348
+sys/src/cmd/spin/pangen2.h - 664 sys sys 1125514860 23109
+sys/src/cmd/spin/pangen3.c - 664 sys sys 1125514860 8941
+sys/src/cmd/spin/pangen3.h - 664 sys sys 1125514860 22484
+sys/src/cmd/spin/pangen4.c - 664 sys sys 1125514860 8180
+sys/src/cmd/spin/pangen4.h - 664 sys sys 1125514860 19033
+sys/src/cmd/spin/pangen5.c - 664 sys sys 1125514860 16851
+sys/src/cmd/spin/pangen5.h - 664 sys sys 1125514861 11145
+sys/src/cmd/spin/pangen6.c - 664 sys sys 1125514861 48633
+sys/src/cmd/spin/pc_zpp.c - 664 sys sys 1125514861 8737
+sys/src/cmd/spin/ps_msc.c - 664 sys sys 1125514861 11872
+sys/src/cmd/spin/reprosrc.c - 664 sys sys 1125514861 2978
+sys/src/cmd/spin/run.c - 664 sys sys 1125514862 14405
+sys/src/cmd/spin/sched.c - 664 sys sys 1125514862 21096
+sys/src/cmd/spin/spin.h - 664 sys sys 1125514862 12286
+sys/src/cmd/spin/spin.y - 664 sys sys 1125514862 18876
+sys/src/cmd/spin/spinlex.c - 664 sys sys 1125514862 30767
+sys/src/cmd/spin/structs.c - 664 sys sys 1125514863 14150
+sys/src/cmd/spin/sym.c - 664 sys sys 1125514863 11863
+sys/src/cmd/spin/tl.h - 664 sys sys 1125514863 3332
+sys/src/cmd/spin/tl_buchi.c - 664 sys sys 1125514863 13080
+sys/src/cmd/spin/tl_cache.c - 664 sys sys 1125514863 5831
+sys/src/cmd/spin/tl_lex.c - 664 sys sys 1125514863 3243
+sys/src/cmd/spin/tl_main.c - 664 sys sys 1125514863 4412
+sys/src/cmd/spin/tl_mem.c - 664 sys sys 1125514864 2670
+sys/src/cmd/spin/tl_parse.c - 664 sys sys 1125514864 8257
+sys/src/cmd/spin/tl_rewrt.c - 664 sys sys 1125514864 5962
+sys/src/cmd/spin/tl_trans.c - 664 sys sys 1125514864 16758
+sys/src/cmd/spin/vars.c - 664 sys sys 1125514864 8393
+sys/src/cmd/spin/version.h - 664 sys sys 1125514864 53
 sys/src/cmd/split.c - 664 sys sys 1116770353 3225
 sys/src/cmd/srv.c - 664 sys sys 1074452607 3885
 sys/src/cmd/srvfs.c - 664 sys sys 1116770384 1702
@@ -12923,7 +12925,7 @@ sys/src/cmd/tapefs/v10fs.c - 664 sys sys 1014926385 3754
 sys/src/cmd/tapefs/v6fs.c - 664 sys sys 1014926385 3971
 sys/src/cmd/tapefs/zip.h - 664 sys sys 1097914153 1428
 sys/src/cmd/tapefs/zipfs.c - 664 sys sys 1097900277 6803
-sys/src/cmd/tar.c - 664 sys sys 1119986000 21041
+sys/src/cmd/tar.c - 664 sys sys 1125515072 21269
 sys/src/cmd/tbl - 20000000775 sys sys 954038038 0
 sys/src/cmd/tbl/mkfile - 664 sys sys 944961243 268
 sys/src/cmd/tbl/t.h - 664 sys sys 944961244 3987
@@ -12991,7 +12993,7 @@ sys/src/cmd/tcs/kuten212.h - 664 sys sys 944961287 94
 sys/src/cmd/tcs/mkfile - 664 sys sys 1036724422 532
 sys/src/cmd/tcs/plan9.h - 664 sys sys 944961287 751
 sys/src/cmd/tcs/tcs.c - 664 sys sys 1044661975 51805
-sys/src/cmd/tcs/utf.c - 664 sys sys 1044661976 7951
+sys/src/cmd/tcs/utf.c - 664 sys sys 1125501123 7962
 sys/src/cmd/tee.c - 664 sys sys 954970286 1062
 sys/src/cmd/telco - 20000000775 sys sys 1015701205 0
 sys/src/cmd/telco/mkfile - 664 sys sys 944961290 201
@@ -13242,8 +13244,8 @@ sys/src/cmd/unix/netkey.c - 664 sys sys 1045152984 21761
 sys/src/cmd/unix/sam - 20000000775 sys sys 954263160 0
 sys/src/cmd/unix/sam/README - 664 sys sys 1110289373 306
 sys/src/cmd/unix/spin - 20000000775 sys sys 956275829 0
-sys/src/cmd/unix/spin/readme - 664 sys sys 956275829 271
-sys/src/cmd/unix/spin/spin334.tar.gz - 664 sys sys 956275830 264112
+sys/src/cmd/unix/spin/readme - 664 sys sys 1125514575 247
+sys/src/cmd/unix/spin/spin425.tar.gz - 664 sys sys 1125514573 330078
 sys/src/cmd/unix/tcs.shar.Z - 664 sys sys 944961315 312440
 sys/src/cmd/unix/u9fs - 20000000775 sys sys 1015092354 0
 sys/src/cmd/unix/u9fs/authnone.c - 664 sys sys 1015092351 321
@@ -13783,7 +13785,7 @@ sys/src/games/mahjongg/level.c - 664 sys sys 1095792293 2522
 sys/src/games/mahjongg/mahjongg.c - 664 sys sys 1095792293 3452
 sys/src/games/mahjongg/mahjongg.h - 664 sys sys 1095792293 1606
 sys/src/games/mahjongg/mkfile - 664 sys sys 1095792293 230
-sys/src/games/memo.c - 664 sys sys 1110436470 6837
+sys/src/games/memo.c - 664 sys sys 1125514848 6321
 sys/src/games/mkfile - 664 sys sys 1118672535 567
 sys/src/games/music - 20000000775 sys sys 1103793915 0
 sys/src/games/music/Readme - 664 sys sys 1103793914 488
@@ -14959,3 +14961,10 @@ usr/glenda/lib/profile - 664 glenda glenda 1105128663 890
 usr/glenda/readme.acme - 664 glenda glenda 1019860628 4753
 usr/glenda/readme.rio - 664 glenda glenda 1019860628 6370
 usr/glenda/tmp - 20000000775 glenda glenda 1018802620 0
+386/bin/games/memo - 775 sys sys 1125544173 156892
+386/bin/seq - 775 sys sys 1125544174 38396
+386/bin/spin - 775 sys sys 1125544175 758333
+386/bin/ip/ppp - 775 sys sys 1125544173 218875
+386/bin/ip/pppoe - 775 sys sys 1125544173 77548
+386/bin/tar - 775 sys sys 1125544175 96517
+386/bin/tcs - 775 sys sys 1125544176 256580

+ 58 - 56
dist/replica/plan9.db

@@ -252,7 +252,7 @@
 386/bin/games/jukebox - 775 sys sys 1105589128 264821
 386/bin/games/jukefs - 775 sys sys 1105589129 165320
 386/bin/games/mahjongg - 775 sys sys 1125345978 164288
-386/bin/games/memo - 775 sys sys 1115950076 157374
+386/bin/games/memo - 775 sys sys 1125544173 156892
 386/bin/games/playlistfs - 775 sys sys 1105589129 148484
 386/bin/games/sokoban - 775 sys sys 1125345978 163379
 386/bin/games/sudoku - 775 sys sys 1117249746 171666
@@ -296,8 +296,8 @@
 386/bin/ip/imap4d - 775 sys sys 1125345987 236488
 386/bin/ip/ipconfig - 775 sys sys 1125345988 137742
 386/bin/ip/ping - 775 sys sys 1116126319 77010
-386/bin/ip/ppp - 775 sys sys 1125345988 218875
-386/bin/ip/pppoe - 775 sys sys 1116126319 77535
+386/bin/ip/ppp - 775 sys sys 1125544173 218875
+386/bin/ip/pppoe - 775 sys sys 1125544173 77548
 386/bin/ip/pptp - 775 sys sys 1116126320 126658
 386/bin/ip/pptpd - 775 sys sys 1125345988 125824
 386/bin/ip/rarpd - 775 sys sys 1125345990 111572
@@ -389,7 +389,7 @@
 386/bin/scp - 775 sys sys 1119496657 151927
 386/bin/scuzz - 775 sys sys 1125346011 111604
 386/bin/sed - 775 sys sys 1125346011 89514
-386/bin/seq - 775 sys sys 1115950111 38206
+386/bin/seq - 775 sys sys 1125544174 38396
 386/bin/sha1sum - 775 sys sys 1115950111 61133
 386/bin/size - 775 sys sys 1119496658 76974
 386/bin/sleep - 775 sys sys 1085077097 3413
@@ -398,7 +398,7 @@
 386/bin/sniffer - 775 sys sys 1038443185 99028
 386/bin/snoopy - 775 sys sys 1125346014 157537
 386/bin/sort - 775 sys sys 1125346014 82276
-386/bin/spin - 775 sys sys 1116903736 655162
+386/bin/spin - 775 sys sys 1125544175 758333
 386/bin/split - 775 sys sys 1125346015 75635
 386/bin/srv - 775 sys sys 1115950113 82387
 386/bin/srvfs - 775 sys sys 1116903736 40065
@@ -412,9 +412,9 @@
 386/bin/swap - 775 sys sys 1115950116 62094
 386/bin/syscall - 775 sys sys 1115950116 73536
 386/bin/tail - 775 sys sys 1125346016 66169
-386/bin/tar - 775 sys sys 1120014538 96347
+386/bin/tar - 775 sys sys 1125544175 96517
 386/bin/tbl - 775 sys sys 1125346017 113167
-386/bin/tcs - 775 sys sys 1115950118 256588
+386/bin/tcs - 775 sys sys 1125544176 256580
 386/bin/tee - 775 sys sys 1115950118 38428
 386/bin/telco - 775 sys sys 1115950118 103315
 386/bin/telnet - 775 sys sys 1125346017 80355
@@ -7513,7 +7513,7 @@ sys/man/2/seek - 664 sys sys 944959696 671
 sys/man/2/segattach - 664 sys sys 1015091526 4304
 sys/man/2/segbrk - 664 sys sys 944959696 825
 sys/man/2/segflush - 664 sys sys 944959695 944
-sys/man/2/setjmp - 664 sys sys 944959696 1856
+sys/man/2/setjmp - 664 sys sys 1125540984 1857
 sys/man/2/sin - 664 sys sys 944959694 967
 sys/man/2/sinh - 664 sys sys 944959694 360
 sys/man/2/sleep - 664 sys sys 944959694 984
@@ -7705,7 +7705,7 @@ sys/man/8/pem - 664 sys sys 1060263669 1189
 sys/man/8/ping - 664 sys sys 1084473185 3436
 sys/man/8/plan9.ini - 664 sys sys 1117814755 21579
 sys/man/8/pop3 - 664 sys sys 1063854676 2720
-sys/man/8/ppp - 664 sys sys 1096036494 4424
+sys/man/8/ppp - 664 sys sys 1125530075 4414
 sys/man/8/prep - 664 sys sys 1079705872 13820
 sys/man/8/qer - 664 sys sys 1067723129 4909
 sys/man/8/reboot - 664 sys sys 969499895 414
@@ -8039,7 +8039,7 @@ sys/src/9/port/alloc.c - 664 sys sys 1102093389 5645
 sys/src/9/port/allocb.c - 664 sys sys 1123676437 3340
 sys/src/9/port/auth.c - 664 sys sys 1123647282 2392
 sys/src/9/port/cache.c - 664 sys sys 1055688274 9241
-sys/src/9/port/chan.c - 664 sys sys 1123647283 29928
+sys/src/9/port/chan.c - 664 sys sys 1125517669 30203
 sys/src/9/port/cis.c - 664 sys sys 1099761153 9248
 sys/src/9/port/debugalloc.c - 664 sys sys 1014931171 10402
 sys/src/9/port/dev.c - 664 sys sys 1077896125 8247
@@ -11976,17 +11976,17 @@ sys/src/cmd/ip/ppp/compress.c - 664 sys sys 1072729513 11774
 sys/src/cmd/ip/ppp/doclient - 775 sys sys 944961007 50
 sys/src/cmd/ip/ppp/doserve - 775 sys sys 944961009 91
 sys/src/cmd/ip/ppp/dotest - 775 sys sys 944961006 152
-sys/src/cmd/ip/ppp/ipaux.c - 664 sys sys 1015090266 2326
+sys/src/cmd/ip/ppp/ipaux.c - 664 sys sys 1125529107 2328
 sys/src/cmd/ip/ppp/mkfile - 664 sys sys 1063897576 352
 sys/src/cmd/ip/ppp/mppc.c - 664 sys sys 1015090267 16624
-sys/src/cmd/ip/ppp/ppp.c - 664 sys sys 1125316087 59889
+sys/src/cmd/ip/ppp/ppp.c - 664 sys sys 1125530039 59897
 sys/src/cmd/ip/ppp/ppp.h - 664 sys sys 1091904423 8284
 sys/src/cmd/ip/ppp/testppp.c - 664 sys sys 1045505281 3011
 sys/src/cmd/ip/ppp/thw.c - 664 sys sys 1015090268 5962
 sys/src/cmd/ip/ppp/thwack.c - 664 sys sys 1015090268 8004
 sys/src/cmd/ip/ppp/thwack.h - 664 sys sys 964662210 2052
 sys/src/cmd/ip/ppp/unthwack.c - 664 sys sys 1015090268 5883
-sys/src/cmd/ip/pppoe.c - 664 sys sys 1050360937 12507
+sys/src/cmd/ip/pppoe.c - 664 sys sys 1125530113 12516
 sys/src/cmd/ip/pptp.c - 664 sys sys 1050360938 16575
 sys/src/cmd/ip/pptpd.c - 664 sys sys 1015701128 23548
 sys/src/cmd/ip/rarpd.c - 664 sys sys 1084470989 3389
@@ -12803,7 +12803,7 @@ sys/src/cmd/scuzz/scsireq.h - 664 sys sys 1113741890 5929
 sys/src/cmd/scuzz/scuzz.c - 664 sys sys 1121977163 37610
 sys/src/cmd/scuzz/sense.c - 664 sys sys 969510790 3901
 sys/src/cmd/sed.c - 664 sys sys 1100962924 27001
-sys/src/cmd/seq.c - 664 sys sys 1063854922 1484
+sys/src/cmd/seq.c - 664 sys sys 1125529033 1683
 sys/src/cmd/sh.C - 664 sys sys 1055701754 10303
 sys/src/cmd/sha1sum.c - 664 sys sys 1014926229 1017
 sys/src/cmd/size.c - 664 sys sys 944961619 717
@@ -12830,43 +12830,45 @@ sys/src/cmd/spell/spell.rc - 775 sys sys 964457135 312
 sys/src/cmd/spell/sprog.c - 664 sys sys 964540731 23030
 sys/src/cmd/spell/stop - 664 sys sys 944961232 18702
 sys/src/cmd/spin - 20000000775 sys sys 953242990 0
-sys/src/cmd/spin/README - 664 sys sys 953242984 344
-sys/src/cmd/spin/dstep.c - 664 sys sys 953242984 8805
-sys/src/cmd/spin/flow.c - 664 sys sys 953242984 15478
-sys/src/cmd/spin/guided.c - 664 sys sys 953242984 5899
-sys/src/cmd/spin/main.c - 664 sys sys 953242984 18700
-sys/src/cmd/spin/mesg.c - 664 sys sys 953242985 13596
-sys/src/cmd/spin/mkfile - 664 sys sys 953242985 669
-sys/src/cmd/spin/pangen1.c - 664 sys sys 953242985 23759
-sys/src/cmd/spin/pangen1.h - 664 sys sys 953242985 94543
-sys/src/cmd/spin/pangen2.c - 664 sys sys 956275776 66265
-sys/src/cmd/spin/pangen2.h - 664 sys sys 953242986 23128
-sys/src/cmd/spin/pangen3.c - 664 sys sys 953242986 8872
-sys/src/cmd/spin/pangen3.h - 664 sys sys 956275777 22057
-sys/src/cmd/spin/pangen4.c - 664 sys sys 953242986 8217
-sys/src/cmd/spin/pangen4.h - 664 sys sys 953242986 18957
-sys/src/cmd/spin/pangen5.c - 664 sys sys 953242986 16614
-sys/src/cmd/spin/pangen5.h - 664 sys sys 953242986 10852
-sys/src/cmd/spin/pc_zpp.c - 664 sys sys 956275778 8265
-sys/src/cmd/spin/ps_msc.c - 664 sys sys 953242987 11458
-sys/src/cmd/spin/run.c - 664 sys sys 953242987 13173
-sys/src/cmd/spin/sched.c - 664 sys sys 953242987 19359
-sys/src/cmd/spin/spin.h - 664 sys sys 953242987 10807
-sys/src/cmd/spin/spin.y - 664 sys sys 953242987 16731
-sys/src/cmd/spin/spinlex.c - 664 sys sys 953242987 13809
-sys/src/cmd/spin/structs.c - 664 sys sys 953242988 13364
-sys/src/cmd/spin/sym.c - 664 sys sys 953242988 11763
-sys/src/cmd/spin/tl.h - 664 sys sys 953242988 3254
-sys/src/cmd/spin/tl_buchi.c - 664 sys sys 953242988 13164
-sys/src/cmd/spin/tl_cache.c - 664 sys sys 953242988 5732
-sys/src/cmd/spin/tl_lex.c - 664 sys sys 953242988 3132
-sys/src/cmd/spin/tl_main.c - 664 sys sys 953242988 4331
-sys/src/cmd/spin/tl_mem.c - 664 sys sys 953242988 2592
-sys/src/cmd/spin/tl_parse.c - 664 sys sys 953242989 8007
-sys/src/cmd/spin/tl_rewrt.c - 664 sys sys 953242989 6257
-sys/src/cmd/spin/tl_trans.c - 664 sys sys 953242990 16758
-sys/src/cmd/spin/vars.c - 664 sys sys 953242990 8412
-sys/src/cmd/spin/version.h - 664 sys sys 956275780 54
+sys/src/cmd/spin/README - 664 sys sys 1125514858 311
+sys/src/cmd/spin/dstep.c - 664 sys sys 1125514858 9958
+sys/src/cmd/spin/flow.c - 664 sys sys 1125514858 17345
+sys/src/cmd/spin/guided.c - 664 sys sys 1125514858 6948
+sys/src/cmd/spin/main.c - 664 sys sys 1125514858 21713
+sys/src/cmd/spin/mesg.c - 664 sys sys 1125514858 13722
+sys/src/cmd/spin/mkfile - 664 sys sys 1125514859 696
+sys/src/cmd/spin/pangen1.c - 664 sys sys 1125514859 29801
+sys/src/cmd/spin/pangen1.h - 664 sys sys 1125514859 134192
+sys/src/cmd/spin/pangen2.c - 664 sys sys 1125514859 74348
+sys/src/cmd/spin/pangen2.h - 664 sys sys 1125514860 23109
+sys/src/cmd/spin/pangen3.c - 664 sys sys 1125514860 8941
+sys/src/cmd/spin/pangen3.h - 664 sys sys 1125514860 22484
+sys/src/cmd/spin/pangen4.c - 664 sys sys 1125514860 8180
+sys/src/cmd/spin/pangen4.h - 664 sys sys 1125514860 19033
+sys/src/cmd/spin/pangen5.c - 664 sys sys 1125514860 16851
+sys/src/cmd/spin/pangen5.h - 664 sys sys 1125514861 11145
+sys/src/cmd/spin/pangen6.c - 664 sys sys 1125514861 48633
+sys/src/cmd/spin/pc_zpp.c - 664 sys sys 1125514861 8737
+sys/src/cmd/spin/ps_msc.c - 664 sys sys 1125514861 11872
+sys/src/cmd/spin/reprosrc.c - 664 sys sys 1125514861 2978
+sys/src/cmd/spin/run.c - 664 sys sys 1125514862 14405
+sys/src/cmd/spin/sched.c - 664 sys sys 1125514862 21096
+sys/src/cmd/spin/spin.h - 664 sys sys 1125514862 12286
+sys/src/cmd/spin/spin.y - 664 sys sys 1125514862 18876
+sys/src/cmd/spin/spinlex.c - 664 sys sys 1125514862 30767
+sys/src/cmd/spin/structs.c - 664 sys sys 1125514863 14150
+sys/src/cmd/spin/sym.c - 664 sys sys 1125514863 11863
+sys/src/cmd/spin/tl.h - 664 sys sys 1125514863 3332
+sys/src/cmd/spin/tl_buchi.c - 664 sys sys 1125514863 13080
+sys/src/cmd/spin/tl_cache.c - 664 sys sys 1125514863 5831
+sys/src/cmd/spin/tl_lex.c - 664 sys sys 1125514863 3243
+sys/src/cmd/spin/tl_main.c - 664 sys sys 1125514863 4412
+sys/src/cmd/spin/tl_mem.c - 664 sys sys 1125514864 2670
+sys/src/cmd/spin/tl_parse.c - 664 sys sys 1125514864 8257
+sys/src/cmd/spin/tl_rewrt.c - 664 sys sys 1125514864 5962
+sys/src/cmd/spin/tl_trans.c - 664 sys sys 1125514864 16758
+sys/src/cmd/spin/vars.c - 664 sys sys 1125514864 8393
+sys/src/cmd/spin/version.h - 664 sys sys 1125514864 53
 sys/src/cmd/split.c - 664 sys sys 1116770353 3225
 sys/src/cmd/srv.c - 664 sys sys 1074452607 3885
 sys/src/cmd/srvfs.c - 664 sys sys 1116770384 1702
@@ -12923,7 +12925,7 @@ sys/src/cmd/tapefs/v10fs.c - 664 sys sys 1014926385 3754
 sys/src/cmd/tapefs/v6fs.c - 664 sys sys 1014926385 3971
 sys/src/cmd/tapefs/zip.h - 664 sys sys 1097914153 1428
 sys/src/cmd/tapefs/zipfs.c - 664 sys sys 1097900277 6803
-sys/src/cmd/tar.c - 664 sys sys 1119986000 21041
+sys/src/cmd/tar.c - 664 sys sys 1125515072 21269
 sys/src/cmd/tbl - 20000000775 sys sys 954038038 0
 sys/src/cmd/tbl/mkfile - 664 sys sys 944961243 268
 sys/src/cmd/tbl/t.h - 664 sys sys 944961244 3987
@@ -12991,7 +12993,7 @@ sys/src/cmd/tcs/kuten212.h - 664 sys sys 944961287 94
 sys/src/cmd/tcs/mkfile - 664 sys sys 1036724422 532
 sys/src/cmd/tcs/plan9.h - 664 sys sys 944961287 751
 sys/src/cmd/tcs/tcs.c - 664 sys sys 1044661975 51805
-sys/src/cmd/tcs/utf.c - 664 sys sys 1044661976 7951
+sys/src/cmd/tcs/utf.c - 664 sys sys 1125501123 7962
 sys/src/cmd/tee.c - 664 sys sys 954970286 1062
 sys/src/cmd/telco - 20000000775 sys sys 1015701205 0
 sys/src/cmd/telco/mkfile - 664 sys sys 944961290 201
@@ -13242,8 +13244,8 @@ sys/src/cmd/unix/netkey.c - 664 sys sys 1045152984 21761
 sys/src/cmd/unix/sam - 20000000775 sys sys 954263160 0
 sys/src/cmd/unix/sam/README - 664 sys sys 1110289373 306
 sys/src/cmd/unix/spin - 20000000775 sys sys 956275829 0
-sys/src/cmd/unix/spin/readme - 664 sys sys 956275829 271
-sys/src/cmd/unix/spin/spin334.tar.gz - 664 sys sys 956275830 264112
+sys/src/cmd/unix/spin/readme - 664 sys sys 1125514575 247
+sys/src/cmd/unix/spin/spin425.tar.gz - 664 sys sys 1125514573 330078
 sys/src/cmd/unix/tcs.shar.Z - 664 sys sys 944961315 312440
 sys/src/cmd/unix/u9fs - 20000000775 sys sys 1015092354 0
 sys/src/cmd/unix/u9fs/authnone.c - 664 sys sys 1015092351 321
@@ -13783,7 +13785,7 @@ sys/src/games/mahjongg/level.c - 664 sys sys 1095792293 2522
 sys/src/games/mahjongg/mahjongg.c - 664 sys sys 1095792293 3452
 sys/src/games/mahjongg/mahjongg.h - 664 sys sys 1095792293 1606
 sys/src/games/mahjongg/mkfile - 664 sys sys 1095792293 230
-sys/src/games/memo.c - 664 sys sys 1110436470 6837
+sys/src/games/memo.c - 664 sys sys 1125514848 6321
 sys/src/games/mkfile - 664 sys sys 1118672535 567
 sys/src/games/music - 20000000775 sys sys 1103793915 0
 sys/src/games/music/Readme - 664 sys sys 1103793914 488

+ 60 - 0
dist/replica/plan9.log

@@ -21155,3 +21155,63 @@
 1125347550 230 c acme/bin/386/News - 775 sys sys 1125346044 128804
 1125347550 231 c acme/bin/386/Wiki - 775 sys sys 1125346044 127380
 1125347550 232 c acme/bin/386/spout - 775 sys sys 1125346044 61608
+1125502264 0 c 386/bin/tcs - 775 sys sys 1125501123 256580
+1125502264 1 c sys/src/cmd/tcs/utf.c - 664 sys sys 1125501123 7962
+1125514868 0 c sys/src/cmd/spin/README - 664 sys sys 1125514858 311
+1125514868 1 c sys/src/cmd/spin/dstep.c - 664 sys sys 1125514858 9958
+1125514868 2 c sys/src/cmd/spin/flow.c - 664 sys sys 1125514858 17345
+1125514868 3 c sys/src/cmd/spin/guided.c - 664 sys sys 1125514858 6948
+1125514868 4 c sys/src/cmd/spin/main.c - 664 sys sys 1125514858 21713
+1125514868 5 c sys/src/cmd/spin/mesg.c - 664 sys sys 1125514858 13722
+1125514868 6 c sys/src/cmd/spin/mkfile - 664 sys sys 1125514859 696
+1125514868 7 c sys/src/cmd/spin/pangen1.c - 664 sys sys 1125514859 29801
+1125514868 8 c sys/src/cmd/spin/pangen1.h - 664 sys sys 1125514859 134192
+1125514868 9 c sys/src/cmd/spin/pangen2.c - 664 sys sys 1125514859 74348
+1125514868 10 c sys/src/cmd/spin/pangen2.h - 664 sys sys 1125514860 23109
+1125514868 11 c sys/src/cmd/spin/pangen3.c - 664 sys sys 1125514860 8941
+1125514868 12 c sys/src/cmd/spin/pangen3.h - 664 sys sys 1125514860 22484
+1125514868 13 c sys/src/cmd/spin/pangen4.c - 664 sys sys 1125514860 8180
+1125514868 14 c sys/src/cmd/spin/pangen4.h - 664 sys sys 1125514860 19033
+1125514868 15 c sys/src/cmd/spin/pangen5.c - 664 sys sys 1125514860 16851
+1125514868 16 c sys/src/cmd/spin/pangen5.h - 664 sys sys 1125514861 11145
+1125514868 17 a sys/src/cmd/spin/pangen6.c - 664 sys sys 1125514861 48633
+1125514868 18 c sys/src/cmd/spin/pc_zpp.c - 664 sys sys 1125514861 8737
+1125514868 19 c sys/src/cmd/spin/ps_msc.c - 664 sys sys 1125514861 11872
+1125514868 20 a sys/src/cmd/spin/reprosrc.c - 664 sys sys 1125514861 2978
+1125514868 21 c sys/src/cmd/spin/run.c - 664 sys sys 1125514862 14405
+1125514868 22 c sys/src/cmd/spin/sched.c - 664 sys sys 1125514862 21096
+1125514868 23 c sys/src/cmd/spin/spin.h - 664 sys sys 1125514862 12286
+1125514868 24 c sys/src/cmd/spin/spin.y - 664 sys sys 1125514862 18876
+1125514868 25 c sys/src/cmd/spin/spinlex.c - 664 sys sys 1125514862 30767
+1125514868 26 c sys/src/cmd/spin/structs.c - 664 sys sys 1125514863 14150
+1125514868 27 c sys/src/cmd/spin/sym.c - 664 sys sys 1125514863 11863
+1125514868 28 c sys/src/cmd/spin/tl.h - 664 sys sys 1125514863 3332
+1125514868 29 c sys/src/cmd/spin/tl_buchi.c - 664 sys sys 1125514863 13080
+1125514868 30 c sys/src/cmd/spin/tl_cache.c - 664 sys sys 1125514863 5831
+1125514868 31 c sys/src/cmd/spin/tl_lex.c - 664 sys sys 1125514863 3243
+1125514868 32 c sys/src/cmd/spin/tl_main.c - 664 sys sys 1125514863 4412
+1125514868 33 c sys/src/cmd/spin/tl_mem.c - 664 sys sys 1125514864 2670
+1125514868 34 c sys/src/cmd/spin/tl_parse.c - 664 sys sys 1125514864 8257
+1125514868 35 c sys/src/cmd/spin/tl_rewrt.c - 664 sys sys 1125514864 5962
+1125514868 36 c sys/src/cmd/spin/tl_trans.c - 664 sys sys 1125514864 16758
+1125514868 37 c sys/src/cmd/spin/vars.c - 664 sys sys 1125514864 8393
+1125514868 38 c sys/src/cmd/spin/version.h - 664 sys sys 1125514864 53
+1125514868 39 c sys/src/cmd/unix/spin/readme - 664 sys sys 1125514575 247
+1125514868 40 a sys/src/cmd/unix/spin/spin425.tar.gz - 664 sys sys 1125514573 330078
+1125514868 41 c sys/src/games/memo.c - 664 sys sys 1125514848 6321
+1125514868 42 d sys/src/cmd/unix/spin/spin334.tar.gz - 664 sys sys 956275830 0
+1125516669 0 c sys/src/cmd/tar.c - 664 sys sys 1125515072 21269
+1125518469 0 c sys/src/9/port/chan.c - 664 sys sys 1125517669 30203
+1125529271 0 c sys/src/cmd/ip/ppp/ipaux.c - 664 sys sys 1125529107 2328
+1125529271 1 c sys/src/cmd/seq.c - 664 sys sys 1125529033 1683
+1125531072 0 c sys/man/8/ppp - 664 sys sys 1125530075 4414
+1125531072 1 c sys/src/cmd/ip/ppp/ppp.c - 664 sys sys 1125530039 59897
+1125531072 2 c sys/src/cmd/ip/pppoe.c - 664 sys sys 1125530113 12516
+1125541873 0 c sys/man/2/setjmp - 664 sys sys 1125540984 1857
+1125545475 0 c 386/bin/games/memo - 775 sys sys 1125544173 156892
+1125545475 1 c 386/bin/seq - 775 sys sys 1125544174 38396
+1125545475 2 c 386/bin/spin - 775 sys sys 1125544175 758333
+1125545475 3 c 386/bin/ip/ppp - 775 sys sys 1125544173 218875
+1125545475 4 c 386/bin/ip/pppoe - 775 sys sys 1125544173 77548
+1125545475 5 c 386/bin/tar - 775 sys sys 1125544175 96517
+1125545475 6 c 386/bin/tcs - 775 sys sys 1125544176 256580

+ 1 - 1
sys/man/2/setjmp

@@ -81,7 +81,7 @@ setlabel(void)
 {
 	label[JMPBUFPC] = ((ulong)f+JMPBUFDPC);
 	/* -2 leaves room for old pc and new pc in frame */
-	label[JMPBUFSP =
+	label[JMPBUFSP] =
 	        (ulong)(&stack[NSTACK-2*sizeof(ulong*)]);
 }
 .EE

+ 22 - 25
sys/man/8/ppp

@@ -34,7 +34,19 @@ ppp, pppoe, pptp, pptpd \- point to point protocol
 .PP
 .B ip/pppoe
 [
-.B -dP
+.B -Pd
+]
+[
+.B -A
+.I acname
+]
+[
+.B -S
+.I srvname
+]
+[
+.B -k
+.I keyspec
 ]
 [
 .B -m
@@ -44,7 +56,9 @@ ppp, pppoe, pptp, pptpd \- point to point protocol
 .B -x
 .I pppnetmntpt
 ]
-.I etherdir
+[
+.I ether
+]
 .PP
 .B ip/pptp
 [
@@ -180,7 +194,9 @@ the ethernet device mounted at
 .I etherdir
 (default
 .BR /net/ether0 ).
-The options are:
+The 
+.I pppoe -specific
+options are:
 .TP
 .B A
 insist on an access concentrator named
@@ -198,30 +214,11 @@ and pass
 .B -d
 to 
 .I ppp
-.TP
-.B m
-pass
-.B -m
-.I mtu
-to 
-.IR ppp ,
-default 1492
-.TP
-.B k
-pass
-.B -k
-.I keyspec
-to
-.I ppp
-.TP
-.B x
-pass
-.B -x
-.I pppnetmntpt
-to 
-.I ppp
 .PD
 .PP
+The other options are relayed to 
+.IR ppp .
+.PP
 .I Pptp
 is a client for a PPTP encrypted tunnel.
 .I Server

+ 41 - 31
sys/src/9/port/chan.c

@@ -77,11 +77,13 @@ typedef struct Elemlist Elemlist;
 
 struct Elemlist
 {
+	char	*aname;	/* original name */
 	char	*name;	/* copy of name, so '/' can be overwritten */
 	int	nelems;
 	char	**elems;
 	int	*off;
 	int	mustbedir;
+	int	nerror;
 };
 
 #define SEP(c) ((c) == 0 || (c) == '/')
@@ -897,7 +899,7 @@ walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
 	cclose(*cp);
 	*cp = c;
 	if(nerror)
-		*nerror = 0;
+		*nerror = nhave;
 	return 0;
 }
 
@@ -1015,6 +1017,7 @@ parsename(char *name, Elemlist *e)
 		*slash++ = '\0';
 		name = slash;
 	}
+	e->off[e->nelems] = name - e->name;
 }
 
 void*
@@ -1030,21 +1033,24 @@ memrchr(void *va, int c, long n)
 }
 
 void
-nameerror(char *name, char *error)
+namelenerror(char *aname, int len, char *err)
 {
-	int len;
-	char tmperr[ERRMAX], *p;
+	char *name;
 
-	strcpy(tmperr, error);	/* error might be in genbuf or tmperr */
-	len = strlen(name);
-	if(len < ERRMAX/3 || (p=strrchr(name, '/'))==nil || p==name)
-		snprint(up->genbuf, sizeof up->genbuf, "%s", name);
+	if(len < ERRMAX/3 || (name=memrchr(aname, '/', len))==nil || name==aname)
+		snprint(up->genbuf, sizeof up->genbuf, "%.*s", len, aname);
 	else
-		snprint(up->genbuf, sizeof up->genbuf, "...%s", p);
-	snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, tmperr);
+		snprint(up->genbuf, sizeof up->genbuf, "...%.*s", (int)(len-(name-aname)), name);
+	snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, err);
 	nexterror();
 }
 
+void
+nameerror(char *name, char *err)
+{
+	namelenerror(name, strlen(name), err);
+}
+
 /*
  * Turn a name into a channel.
  * &name[0] is known to be a valid address.  It may be a kernel address.
@@ -1064,7 +1070,7 @@ nameerror(char *name, char *error)
 Chan*
 namec(char *aname, int amode, int omode, ulong perm)
 {
-	int n, t, nomount, npath;
+	int n, t, nomount;
 	Chan *c, *cnew;
 	Cname *cname;
 	Elemlist e;
@@ -1073,14 +1079,14 @@ namec(char *aname, int amode, int omode, ulong perm)
 	char *createerr, tmperrbuf[ERRMAX];
 	char *name;
 
-	name = aname;
-	if(name[0] == '\0')
+	if(aname[0] == '\0')
 		error("empty file name");
-	name = validnamedup(name, 1);
+	aname = validnamedup(aname, 1);
 	if(waserror()){
-		free(name);
+		free(aname);
 		nexterror();
 	}
+	name = aname;
 
 	/*
 	 * Find the starting off point (the current slash, the root of
@@ -1134,17 +1140,24 @@ namec(char *aname, int amode, int omode, ulong perm)
 		break;
 	}
 
+	e.aname = aname;
 	e.name = nil;
 	e.elems = nil;
 	e.off = nil;
 	e.nelems = 0;
+	e.nerror = 0;
 	if(waserror()){
 		cclose(c);
 		free(e.name);
 		free(e.elems);
 		free(e.off);
-//dumpmount();
-		nexterror();
+		/*
+		 * Prepare nice error, showing first e.nerror elements of name.
+		 */
+		if(e.nerror == 0)
+			nexterror();
+		strcpy(tmperrbuf, up->errstr);
+		namelenerror(aname, (name-aname)+e.off[e.nerror], tmperrbuf);
 	}
 
 	/*
@@ -1158,8 +1171,8 @@ namec(char *aname, int amode, int omode, ulong perm)
 	if(amode == Acreate){
 		/* perm must have DMDIR if last element is / or /. */
 		if(e.mustbedir && !(perm&DMDIR)){
-			npath = e.nelems;
-			nameerror(aname, "create without DMDIR");
+			e.nerror = e.nelems;
+			error("create without DMDIR");
 		}
 
 		/* don't try to walk the last path element just yet. */
@@ -1168,23 +1181,19 @@ namec(char *aname, int amode, int omode, ulong perm)
 		e.nelems--;
 	}
 
-	if(walk(&c, e.elems, e.nelems, nomount, &npath) < 0){
-		if(npath < 0 || npath > e.nelems){
-			print("namec %s walk error npath=%d\n", aname, npath);
-			nexterror();
+	if(walk(&c, e.elems, e.nelems, nomount, &e.nerror) < 0){
+		if(e.nerror < 0 || e.nerror > e.nelems){
+			print("namec %s walk error nerror=%d\n", aname, e.nerror);
+			e.nerror = 0;
 		}
-		nameerror(aname, up->errstr);
+		nexterror();
 	}
 
-	if(e.mustbedir && !(c->qid.type&QTDIR)){
-		npath = e.nelems;
-		nameerror(aname, "not a directory");
-	}
+	if(e.mustbedir && !(c->qid.type&QTDIR))
+		error("not a directory");
 
-	if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR)){
-		npath = e.nelems;
+	if(amode == Aopen && (omode&3) == OEXEC && (c->qid.type&QTDIR))
 		error("cannot exec directory");
-	}
 
 	switch(amode){
 	case Abind:
@@ -1276,6 +1285,7 @@ if(c->umh != nil){
 		 * If omode&OEXCL is set, just give up.
 		 */
 		e.nelems++;
+		e.nerror++;
 		if(walk(&c, e.elems+e.nelems-1, 1, nomount, nil) == 0){
 			if(omode&OEXCL)
 				error(Eexist);

+ 1 - 1
sys/src/cmd/ip/ppp/ipaux.c

@@ -19,7 +19,7 @@ ptclbsum(uchar *addr, int len)
 	mdsum = 0;
 
 	x = 0;
-	if((ulong)addr & 1) {
+	if((uintptr)addr & 1) {
 		if(len) {
 			hisum += addr[0];
 			len--;

+ 4 - 4
sys/src/cmd/ip/ppp/ppp.c

@@ -2892,13 +2892,13 @@ putndb(PPP *ppp, char *net)
 	p = seprint(p, e, "ip=%I ipmask=255.255.255.255 ipgw=%I\n", ppp->local,
 			ppp->remote);
 	if(validv4(ppp->dns[0]))
-		p = seprint(p, e, "\tdns=%I", ppp->dns[0]);
+		p = seprint(p, e, "\tdns=%I\n", ppp->dns[0]);
 	if(validv4(ppp->dns[1]))
-		p = seprint(p, e, "\tdns=%I", ppp->dns[1]);
+		p = seprint(p, e, "\tdns=%I\n", ppp->dns[1]);
 	if(validv4(ppp->wins[0]))
-		p = seprint(p, e, "\twins=%I", ppp->wins[0]);
+		p = seprint(p, e, "\twins=%I\n", ppp->wins[0]);
 	if(validv4(ppp->wins[1]))
-		p = seprint(p, e, "\twins=%I", ppp->wins[1]);
+		p = seprint(p, e, "\twins=%I\n", ppp->wins[1]);
 	seprint(file, file+sizeof file, "%s/ndb", net);
 	fd = open(file, OWRITE);
 	if(fd < 0)

+ 5 - 5
sys/src/cmd/ip/pppoe.c

@@ -17,7 +17,7 @@ void execppp(int);
 int alarmed;
 int debug;
 int sessid;
-char *namesecret;
+char *keyspec;
 int primary;
 char *pppnetmtpt;
 char *acname;
@@ -32,7 +32,7 @@ int mtu = 1492;
 void
 usage(void)
 {
-	fprint(2, "usage: pppoe [-Pd] [-S srvname] [-s name:pass] [-x pppnet] ether0\n");
+	fprint(2, "usage: pppoe [-Pd] [-A acname] [-S srvname] [-k keyspec] [-m mtu] [-x pppnet] [ether0]\n");
 	exits("usage");
 }
 
@@ -73,7 +73,7 @@ main(int argc, char **argv)
 		mtu = atoi(EARGF(usage()));
 		break;
 	case 'k':
-		namesecret = EARGF(usage());
+		keyspec = EARGF(usage());
 		break;
 	case 'x':
 		pppnetmtpt = EARGF(usage());
@@ -522,9 +522,9 @@ execppp(int fd)
 		argv[argc++] = "-x";
 		argv[argc++] = pppnetmtpt;
 	}
-	if(namesecret){
+	if(keyspec){
 		argv[argc++] = "-k";
-		argv[argc++] = namesecret;
+		argv[argc++] = keyspec;
 	}
 	argv[argc] = nil;
 

+ 16 - 6
sys/src/cmd/seq.c

@@ -81,12 +81,22 @@ main(int argc, char *argv[]){
 	}
 	if(!format)
 		buildfmt();
-	for(val = min; val <= max; val += incr){
-		n = sprint(buf, format, val);
-		if(constant)
-			for(j=0; buf[j]==' '; j++)
-				buf[j] ='0';
-		write(1, buf, n);
+	if(incr > 0){
+		for(val = min; val <= max; val += incr){
+			n = sprint(buf, format, val);
+			if(constant)
+				for(j=0; buf[j]==' '; j++)
+					buf[j] ='0';
+			write(1, buf, n);
+		}
+	}else{
+		for(val = min; val >= max; val += incr){
+			n = sprint(buf, format, val);
+			if(constant)
+				for(j=0; buf[j]==' '; j++)
+					buf[j] ='0';
+			write(1, buf, n);
+		}
 	}
 	exits(0);
 }

+ 1 - 2
sys/src/cmd/spin/README

@@ -1,12 +1,11 @@
 the latest version of spin is always
 available via:
-	http://cm.bell-labs.com/cm/cs/what/spin/
+	http://spinroot.com/spin/whatispin.html
 
 to make the sources compile with the mkfile on plan 9
 the following changes were made:
 
 	omitted memory.h from spin.h
-	omitted malloc.h from ps_msc.c
 	changed /lib/cpp to /bin/cpp in main.c
 	simplified non_fatal() in main.c to remove
 	use of yychar

+ 56 - 20
sys/src/cmd/spin/dstep.c

@@ -1,14 +1,13 @@
 /***** spin: dstep.c *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 #include "spin.h"
 #ifdef PC
@@ -26,7 +25,7 @@ static int	Tj=0, Jt=0, LastGoto=0;
 static int	Tojump[MAXDSTEP], Jumpto[MAXDSTEP], Special[MAXDSTEP];
 static void	putCode(FILE *, Element *, Element *, Element *, int);
 
-extern int	Pid, claimnr;
+extern int	Pid, claimnr, separate, OkBreak;
 
 static void
 Sourced(int n, int special)
@@ -57,7 +56,7 @@ Dested(int n)
 
 static void
 Mopup(FILE *fd)
-{	int i, j; extern int OkBreak;
+{	int i, j;
 
 	for (i = 0; i < Jt; i++)
 	{	for (j = 0; j < Tj; j++)
@@ -172,10 +171,21 @@ CollectGuards(FILE *fd, Element *e, int inh)
 			fprintf(fd, "(1 /* else */)");
 			break;
 		case 'R':
+			if (inh++ > 0) fprintf(fd, " || ");
+			fprintf(fd, "("); TestOnly=1;
+			putstmnt(fd, ee->n, ee->seqno);
+			fprintf(fd, ")"); TestOnly=0;
+			break;
 		case 'r':
+			if (inh++ > 0) fprintf(fd, " || ");
+			fprintf(fd, "("); TestOnly=1;
+			putstmnt(fd, ee->n, ee->seqno);
+			fprintf(fd, ")"); TestOnly=0;
+			break;
 		case 's':
 			if (inh++ > 0) fprintf(fd, " || ");
 			fprintf(fd, "("); TestOnly=1;
+/* 4.2.1 */		if (Pid != claimnr) fprintf(fd, "(boq == -1) && ");
 			putstmnt(fd, ee->n, ee->seqno);
 			fprintf(fd, ")"); TestOnly=0;
 			break;
@@ -194,7 +204,7 @@ CollectGuards(FILE *fd, Element *e, int inh)
 }
 
 int
-putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln)
+putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln, int seqno)
 {	int isg=0; char buf[64];
 
 	NextLab[0] = "continue";
@@ -203,13 +213,13 @@ putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln)
 	switch (s->frst->n->ntyp) {
 	case UNLESS:
 		non_fatal("'unless' inside d_step - ignored", (char *) 0);
-		return putcode(fd, s->frst->n->sl->this, nxt, 0, ln);
+		return putcode(fd, s->frst->n->sl->this, nxt, 0, ln, seqno);
 	case NON_ATOMIC:
-		(void) putcode(fd, s->frst->n->sl->this, ZE, 1, ln);
+		(void) putcode(fd, s->frst->n->sl->this, ZE, 1, ln, seqno);
 		break;
 	case IF:
 		fprintf(fd, "if (!(");
-		if (!CollectGuards(fd, s->frst, 0))
+		if (!CollectGuards(fd, s->frst, 0))	/* what about boq? */
 			fprintf(fd, "1");
 		fprintf(fd, "))\n\t\t\tcontinue;");
 		isg = 1;
@@ -224,12 +234,24 @@ putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln)
 		}
 		break;
 	case 'R': /* <- can't really happen (it's part of a 'c') */
+		fprintf(fd, "if (!("); TestOnly=1;
+		putstmnt(fd, s->frst->n, s->frst->seqno);
+		fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
+		break;
 	case 'r':
-	case 's':
 		fprintf(fd, "if (!("); TestOnly=1;
 		putstmnt(fd, s->frst->n, s->frst->seqno);
 		fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
 		break;
+	case 's':
+		fprintf(fd, "if (");
+#if 1
+/* 4.2.1 */	if (Pid != claimnr) fprintf(fd, "(boq != -1) || ");
+#endif
+		fprintf(fd, "!("); TestOnly=1;
+		putstmnt(fd, s->frst->n, s->frst->seqno);
+		fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
+		break;
 	case 'c':
 		fprintf(fd, "if (!(");
 		if (Pid != claimnr) fprintf(fd, "boq == -1 && ");
@@ -237,26 +259,40 @@ putcode(FILE *fd, Sequence *s, Element *nxt, int justguards, int ln)
 		putstmnt(fd, s->frst->n->lft, s->frst->seqno);
 		fprintf(fd, "))\n\t\t\tcontinue;"); TestOnly=0;
 		break;
+	case ELSE:
+		fprintf(fd, "if (boq != -1 || (");
+		if (separate != 2) fprintf(fd, "trpt->");
+		fprintf(fd, "o_pm&1))\n\t\t\tcontinue;");
+		break;
 	case ASGN:	/* new 3.0.8 */
 		fprintf(fd, "IfNotBlocked");
 		break;
 	}
 	if (justguards) return 0;
 
-	fprintf(fd, "\n\t\tsv_save((char *)&now);\n");
-
+	fprintf(fd, "\n\t\tsv_save();\n\t\t");
+#if 1
+	fprintf(fd, "reached[%d][%d] = 1;\n\t\t", Pid, seqno);
+	fprintf(fd, "reached[%d][t->st] = 1;\n\t\t", Pid);	/* true next state */
+	fprintf(fd, "reached[%d][tt] = 1;\n", Pid);		/* true current state */
+#endif
 	sprintf(buf, "Uerror(\"block in d_step seq, line %d\")", ln);
 	NextLab[0] = buf;
 	putCode(fd, s->frst, s->extent, nxt, isg);
 
 	if (nxt)
-	{	if (FirstTime(nxt->Seqno)
+	{	extern Symbol *Fname;
+		extern int lineno;
+
+		if (FirstTime(nxt->Seqno)
 		&& (!(nxt->status & DONE2) || !(nxt->status & D_ATOM)))
 		{	fprintf(fd, "S_%.3d_0: /* 1 */\n", nxt->Seqno);
 			nxt->status |= DONE2;
 			LastGoto = 0;
 		}
 		Sourced(nxt->Seqno, 1);
+		lineno = ln;
+		Fname = nxt->n->fn;	
 		Mopup(fd);
 	}
 	unskip(s->frst->seqno);
@@ -299,7 +335,7 @@ putCode(FILE *fd, Element *f, Element *last, Element *next, int isguard)
 				if (LastGoto) break;
 				if (e->nxt)
 				{	i = target( huntele(e->nxt,
-						e->status))->Seqno;
+						e->status, -1))->Seqno;
 					fprintf(fd, "\t\tgoto S_%.3d_0;	", i);
 					fprintf(fd, "/* 'break' */\n");
 					Dested(i);
@@ -316,7 +352,7 @@ putCode(FILE *fd, Element *f, Element *last, Element *next, int isguard)
 			case GOTO:
 				if (LastGoto) break;
 				i = huntele( get_lab(e->n,1),
-					e->status)->Seqno;
+					e->status, -1)->Seqno;
 				fprintf(fd, "\t\tgoto S_%.3d_0;	", i);
 				fprintf(fd, "/* 'goto' */\n");
 				Dested(i);

+ 94 - 16
sys/src/cmd/spin/flow.c

@@ -1,14 +1,13 @@
 /***** spin: flow.c *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 #include "spin.h"
 #ifdef PC
@@ -97,6 +96,7 @@ int
 is_skip(Lextok *n)
 {
 	return (n->ntyp == PRINT
+	||	n->ntyp == PRINTM
 	||	(n->ntyp == 'c'
 		&& n->lft
 		&& n->lft->ntyp == CONST
@@ -113,15 +113,19 @@ check_sequence(Sequence *s)
 	{	n = e->n;
 		if (is_skip(n) && !has_lab(e, 0))
 		{	cnt++;
-			if (cnt > 1 && n->ntyp != PRINT)
+			if (cnt > 1
+			&&  n->ntyp != PRINT
+			&&  n->ntyp != PRINTM)
 			{	if (verbose&32)
 					printf("spin: line %d %s, redundant skip\n",
 						n->ln, n->fn->name);
-				if (le)
+				if (e != s->frst
+				&&  e != s->last
+				&&  e != s->extent)
 				{	e->status |= DONE;	/* not unreachable */
 					le->nxt = e->nxt;	/* remove it */
 					e = le;
-				} /* else, can't happen */
+				}
 			}
 		} else
 			cnt = 0;
@@ -309,6 +313,45 @@ has_chanref(Lextok *n)
 	return has_chanref(n->rgt);
 }
 
+void
+loose_ends(void)	/* properly tie-up ends of sub-sequences */
+{	Element *e, *f;
+
+	for (e = Al_El; e; e = e->Nxt)
+	{	if (!e->n
+		||  !e->nxt)
+			continue;
+		switch (e->n->ntyp) {
+		case ATOMIC:
+		case NON_ATOMIC:
+		case D_STEP:
+			f = e->nxt;
+			while (f && f->n->ntyp == '.')
+				f = f->nxt;
+			if (0) printf("link %d, {%d .. %d} -> %d (ntyp=%d) was %d\n",
+				e->seqno,
+				e->n->sl->this->frst->seqno,
+				e->n->sl->this->last->seqno,
+				f?f->seqno:-1, f?f->n->ntyp:-1,
+				e->n->sl->this->last->nxt?e->n->sl->this->last->nxt->seqno:-1);
+			if (!e->n->sl->this->last->nxt)
+				e->n->sl->this->last->nxt = f;
+			else
+			{	if (e->n->sl->this->last->nxt->n->ntyp != GOTO)
+				{	if (!f || e->n->sl->this->last->nxt->seqno != f->seqno)
+					non_fatal("unexpected: loose ends", (char *)0);
+				} else
+					e->n->sl->this->last = e->n->sl->this->last->nxt;
+				/*
+				 * fix_dest can push a goto into the nxt position
+				 * in that case the goto wins and f is not needed
+				 * but the last fields needs adjusting
+				 */
+			}
+			break;
+	}	}
+}
+
 static Element *
 if_seq(Lextok *n)
 {	int	tok = n->ntyp;
@@ -547,6 +590,7 @@ get_lab(Lextok *n, int md)
 	for (l = labtab; l; l = l->nxt)
 		if (s == l->s)
 			return (l->e);
+
 	lineno = n->ln;
 	Fname = n->fn;
 	if (md) fatal("undefined label %s", s->name);
@@ -586,12 +630,19 @@ mov_lab(Symbol *z, Element *e, Element *y)
 }
 
 void
-fix_dest(Symbol *c, Symbol *a)	/* label, proctype */
+fix_dest(Symbol *c, Symbol *a)		/* c:label name, a:proctype name */
 {	Label *l; extern Symbol *context;
 
+#if 0
+	printf("ref to label '%s' in proctype '%s', search:\n",
+		c->name, a->name);
+	for (l = labtab; l; l = l->nxt)
+		printf("	%s in	%s\n", l->s->name, l->c->name);
+#endif
+
 	for (l = labtab; l; l = l->nxt)
 	{	if (strcmp(c->name, l->s->name) == 0
-		&&  strcmp(a->name, l->c->name) == 0)
+		&&  strcmp(a->name, l->c->name) == 0)	/* ? */
 			break;
 	}
 	if (!l)
@@ -622,6 +673,10 @@ fix_dest(Symbol *c, Symbol *a)	/* label, proctype */
 		l->e->nxt = y;		/* append the goto  */
 	}
 	l->e->status |= CHECK2;	/* treat as if global */
+	if (l->e->status & (ATOM | L_ATOM | D_ATOM))
+	{	non_fatal("cannot reference label inside atomic or d_step (%s)",
+			c->name);
+	}
 }
 
 int
@@ -660,10 +715,28 @@ break_dest(void)
 
 void
 make_atomic(Sequence *s, int added)
-{
+{	Element *f;
+
 	walk_atomic(s->frst, s->last, added);
-	s->last->status &= ~ATOM;
-	s->last->status |= L_ATOM;
+
+	f = s->last;
+	switch (f->n->ntyp) {	/* is last step basic stmnt or sequence ? */
+	case NON_ATOMIC:
+	case ATOMIC:
+		/* redo and search for the last step of that sequence */
+		make_atomic(f->n->sl->this, added);
+		break;
+
+	case UNLESS:
+		/* escapes are folded into main sequence */
+		make_atomic(f->sub->this, added);
+		break;
+
+	default:
+		f->status &= ~ATOM;
+		f->status |= L_ATOM;
+		break;
+	}
 }
 
 static void
@@ -699,6 +772,11 @@ mknonat:		f->n->ntyp = NON_ATOMIC; /* can jump here */
 			h = f->n->sl;
 			walk_atomic(h->this->frst, h->this->last, added);
 			break;
+		case UNLESS:
+			if (added)
+			{ printf("spin: error, line %3d %s, unless in d_step (ignored)\n",
+			 	 f->n->ln, f->n->fn->name);
+			}
 		}
 		for (h = f->sub; h; h = h->nxt)
 			walk_atomic(h->this->frst, h->this->last, added);

+ 92 - 36
sys/src/cmd/spin/guided.c

@@ -1,14 +1,13 @@
 /***** spin: guided.c *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 #include "spin.h"
 #include <sys/types.h>
@@ -22,8 +21,8 @@
 extern RunList	*run, *X;
 extern Element	*Al_El;
 extern Symbol	*Fname, *oFname;
-extern int	verbose, lineno, xspin, jumpsteps, depth, merger;
-extern int	nproc, nstop, Tval, Rvous, m_loss, ntrail, columns;
+extern int	verbose, lineno, xspin, jumpsteps, depth, merger, cutoff;
+extern int	nproc, nstop, Tval, ntrail, columns;
 extern short	Have_claim, Skip_claim;
 extern void ana_src(int, int);
 
@@ -60,35 +59,74 @@ hookup(void)
 {	Element *e;
 
 	for (e = Al_El; e; e = e->Nxt)
-		if (e->n && e->n->ntyp == ATOMIC
-		||  e->n && e->n->ntyp == NON_ATOMIC
-		||  e->n && e->n->ntyp == D_STEP)
+		if (e->n
+		&& (e->n->ntyp == ATOMIC
+		||  e->n->ntyp == NON_ATOMIC
+		||  e->n->ntyp == D_STEP))
 			(void) huntstart(e);
 }
 
+int
+not_claim(void)
+{
+	return (!Have_claim || !X || X->pid != 0);
+}
+
 void
 match_trail(void)
 {	int i, a, nst;
 	Element *dothis;
-	RunList *oX;
-	char snap[256];
+	char snap[512], *q;
+
+	/*
+	 * if source model name is leader.pml
+	 * look for the trail file under these names:
+	 *	leader.pml.trail
+	 *	leader.pml.tra
+	 *	leader.trail
+	 *	leader.tra
+	 */
 
 	if (ntrail)
 		sprintf(snap, "%s%d.trail", oFname->name, ntrail);
 	else
 		sprintf(snap, "%s.trail", oFname->name);
-	if (!(fd = fopen(snap, "r")))
-	{	snap[strlen(snap)-2] = '\0';	/* .tra on some pc's */
-		if (!(fd = fopen(snap, "r")))
-		{	printf("spin: cannot find trail file\n");
+
+	if ((fd = fopen(snap, "r")) == NULL)
+	{	snap[strlen(snap)-2] = '\0';	/* .tra */
+		if ((fd = fopen(snap, "r")) == NULL)
+		{	if ((q = strchr(oFname->name, '.')) != NULL)
+			{	*q = '\0';
+				if (ntrail)
+					sprintf(snap, "%s%d.trail",
+						oFname->name, ntrail);
+				else
+					sprintf(snap, "%s.trail",
+						oFname->name);
+				*q = '.';
+
+				if ((fd = fopen(snap, "r")) != NULL)
+					goto okay;
+
+				snap[strlen(snap)-2] = '\0';	/* last try */
+				if ((fd = fopen(snap, "r")) != NULL)
+					goto okay;
+			}
+			printf("spin: cannot find trail file\n");
 			alldone(1);
 	}	}
-			
+okay:		
 	if (xspin == 0 && newer(oFname->name, snap))
 	printf("spin: warning, \"%s\" is newer than %s\n",
 		oFname->name, snap);
 
-	Tval = m_loss = 1; /* timeouts and losses may be part of trail */
+	Tval = 1;
+
+	/*
+	 * sets Tval because timeouts may be part of trail
+	 * this used to also set m_loss to 1, but that is
+	 * better handled with the runtime -m flag
+	 */
 
 	hookup();
 
@@ -104,6 +142,13 @@ match_trail(void)
 			}
 			continue;
 		}
+
+		if (cutoff > 0 && depth >= cutoff)
+		{	printf("-------------\n");
+			printf("depth-limit (-u%d steps) reached\n", cutoff);
+			break;
+		}
+
 		if (Skip_claim && pno == 0) continue;
 
 		for (dothis = Al_El; dothis; dothis = dothis->Nxt)
@@ -112,10 +157,12 @@ match_trail(void)
 		}
 		if (!dothis)
 		{	printf("%3d: proc %d, no matching stmnt %d\n",
-				depth, pno, nst);
+				depth, pno - Have_claim, nst);
 			lost_trail();
 		}
+
 		i = nproc - nstop + Skip_claim;
+
 		if (dothis->n->ntyp == '@')
 		{	if (pno == i-1)
 			{	run = run->nxt;
@@ -125,15 +172,19 @@ match_trail(void)
 					{	dotag(stdout, "<end>\n");
 						continue;
 					}
+					if (Have_claim && pno == 0)
+					printf("%3d: claim terminates\n",
+						depth);
+					else
 					printf("%3d: proc %d terminates\n",
-						depth, pno);
+						depth, pno - Have_claim);
 				}
 				continue;
 			}
 			if (pno <= 1) continue;	/* init dies before never */
 			printf("%3d: stop error, ", depth);
 			printf("proc %d (i=%d) trans %d, %c\n",
-				pno, i, nst, dothis->n->ntyp);
+				pno - Have_claim, i, nst, dothis->n->ntyp);
 			lost_trail();
 		}
 		for (X = run; X; X = X->nxt)
@@ -141,20 +192,20 @@ match_trail(void)
 				break;
 		}
 		if (!X)
-		{	printf("%3d: no process %d ", depth, pno);
+		{	printf("%3d: no process %d ", depth, pno - Have_claim);
 			printf("(state %d)\n", nst);
 			lost_trail();
 		}
 		X->pc  = dothis;
 		lineno = dothis->n->ln;
 		Fname  = dothis->n->fn;
-		oX = X;	/* a rendezvous could change it */
+
 		if (dothis->n->ntyp == D_STEP)
 		{	Element *g, *og = dothis;
 			do {
 				g = eval_sub(og);
 				if (g && depth >= jumpsteps
-				&& ((verbose&32) || (verbose&4)))
+				&& ((verbose&32) || ((verbose&4) && not_claim())))
 				{	if (columns != 2)
 					{	p_talk(og, 1);
 		
@@ -171,18 +222,19 @@ match_trail(void)
 				}
 				og = g;
 			} while (g && g != dothis->nxt);
-			X->pc = g?huntele(g, 0):g;
+			X->pc = g?huntele(g, 0, -1):g;
 		} else
 		{
-keepgoing:		X->pc = eval_sub(dothis);
-			X->pc = huntele(X->pc, 0);
-			if (dothis->merge_start)
+keepgoing:		if (dothis->merge_start)
 				a = dothis->merge_start;
 			else
 				a = dothis->merge;
 
+			X->pc = eval_sub(dothis);
+			if (X->pc) X->pc = huntele(X->pc, 0, a);
+
 			if (depth >= jumpsteps
-			&& ((verbose&32) || (verbose&4)))
+			&& ((verbose&32) || ((verbose&4) && not_claim())))	/* -v or -p */
 			{	if (columns != 2)
 				{	p_talk(dothis, 1);
 	
@@ -201,12 +253,17 @@ keepgoing:		X->pc = eval_sub(dothis);
 				if (verbose&1) dumpglobals();
 				if (verbose&2) dumplocal(X);
 				if (xspin) printf("\n");
+
+				if (!X->pc)
+				{	X->pc = dothis;
+					printf("\ttransition failed\n");
+					a = 0;	/* avoid inf loop */
+				}
 			}
 			if (a && X->pc && X->pc->seqno != a)
 			{	dothis = X->pc;
 				goto keepgoing;
-			}
-		}
+		}	}
 
 		if (Have_claim && X && X->pid == 0
 		&&  dothis && dothis->n
@@ -221,8 +278,7 @@ keepgoing:		X->pc = eval_sub(dothis);
 				printf("Never claim moves to line %d\t[", lastclaim);
 				comment(stdout, dothis->n, 0);
 				printf("]\n");
-			}
-	}	}
+	}	}	}
 	printf("spin: trail ends after %d steps\n", depth);
 	wrapup(0);
 }

+ 177 - 67
sys/src/cmd/spin/main.c

@@ -1,14 +1,13 @@
 /***** spin: main.c *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 #include <stdlib.h>
 #include "spin.h"
@@ -19,6 +18,9 @@
 #ifdef PC
 #include <io.h>
 #include "y_tab.h"
+
+extern int unlink(const char *);
+
 #else
 #include <unistd.h>
 #include "y.tab.h"
@@ -28,18 +30,26 @@ extern int	DstepStart, lineno, tl_terse;
 extern FILE	*yyin, *yyout, *tl_out;
 extern Symbol	*context;
 extern char	*claimproc;
+extern void	repro_src(void);
 extern void	qhide(int);
 
 Symbol	*Fname, *oFname;
 
-int	Etimeouts=0;	/* nr timeouts in program */
-int	Ntimeouts=0;	/* nr timeouts in never claim */
-int	analyze=0, columns=0, dumptab=0, has_remote=0;
-int	interactive=0, jumpsteps=0, m_loss=0, nr_errs=0;
-int	s_trail=0, ntrail=0, verbose=0, xspin=0, no_print=0, no_wrapup = 0, Caccess=0;
-int	limited_vis=0, like_java=0;
-int	dataflow = 1, merger = 1, deadvar = 1, rvopt = 0, ccache = 1;
-int	separate = 0;	/* separate compilation option */
+int	Etimeouts;	/* nr timeouts in program */
+int	Ntimeouts;	/* nr timeouts in never claim */
+int	analyze, columns, dumptab, has_remote, has_remvar;
+int	interactive, jumpsteps, m_loss, nr_errs, cutoff;
+int	s_trail, ntrail, verbose, xspin, notabs, rvopt;
+int	no_print, no_wrapup, Caccess, limited_vis, like_java;
+int	separate;	/* separate compilation */
+int	export_ast;	/* pangen5.c */
+int	inlineonly;	/* show inlined code */
+int	seedy;		/* be verbose about chosen seed */
+
+int	dataflow = 1, merger = 1, deadvar = 1, ccache = 1;
+
+static int preprocessonly, SeedUsed;
+
 #if 0
 meaning of flags on verbose:
 	1	-g global variable values
@@ -51,8 +61,6 @@ meaning of flags on verbose:
 	64	-w very verbose
 #endif
 
-static Element	*Same;
-static int	IsAsgn = 0, OrIsAsgn = 0;
 static char	Operator[] = "operator: ";
 static char	Keyword[]  = "keyword: ";
 static char	Function[] = "function-name: ";
@@ -68,27 +76,35 @@ static void	explain(int);
 		/* OS2:		"spin -Picc -E/Pd+ -E/Q+"    */
 		/* Visual C++:	"spin -PCL  -E/E             */
 #ifdef PC
-#define CPP	"cpp"		/*  or specify a full path    */
+#define CPP	"gcc -E -x c"	/* most systems have gcc anyway */
+				/* else use "cpp" */
 #else
 #ifdef SOLARIS
 #define CPP	"/usr/ccs/lib/cpp"
 #else
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
 #define CPP	"cpp"
 #else
-#define CPP	"/bin/cpp"
+#define CPP	"/bin/cpp"	/* classic Unix systems */
 #endif
 #endif
 #endif
 
 #endif
 static char	*PreProc = CPP;
+extern int	depth; /* at least some steps were made */
 
 void
 alldone(int estatus)
 {
-	if (strlen(out1) > 0)
+	if (preprocessonly == 0
+	&&  strlen(out1) > 0)
 		(void) unlink((const char *)out1);
+
+	if (seedy && !analyze && !export_ast
+	&& !s_trail && !preprocessonly && depth > 0)
+		printf("seed used: %d\n", SeedUsed);
+
 	if (xspin && (analyze || s_trail))
 	{	if (estatus)
 			printf("spin: %d error(s) - aborting\n",
@@ -101,10 +117,10 @@ alldone(int estatus)
 
 void
 preprocess(char *a, char *b, int a_tmp)
-{	char precmd[128], cmd[256]; int i;
+{	char precmd[512], cmd[1024]; int i;
 #ifdef PC
 	extern int try_zpp(char *, char *);
-	if (try_zpp(a, b)) goto out;
+	if (PreCnt == 0 && try_zpp(a, b)) goto out;
 #endif
 	strcpy(precmd, PreProc);
 	for (i = 1; i <= PreCnt; i++)
@@ -115,9 +131,13 @@ preprocess(char *a, char *b, int a_tmp)
 	if (system((const char *)cmd))
 	{	(void) unlink((const char *) b);
 		if (a_tmp) (void) unlink((const char *) a);
-		alldone(1); /* failed */
+		fprintf(stdout, "spin: preprocessing failed\n");	/* 4.1.2 was stderr */
+		alldone(1); /* no return, error exit */
 	}
-out:	if (a_tmp) (void) unlink((const char *) a);
+#ifdef PC
+out:
+#endif
+	if (a_tmp) (void) unlink((const char *) a);
 }
 
 FILE *
@@ -142,10 +162,11 @@ usage(void)
 {
 	printf("use: spin [-option] ... [-option] file\n");
 	printf("\tNote: file must always be the last argument\n");
+	printf("\t-A apply slicing algorithm\n");
 	printf("\t-a generate a verifier in pan.c\n");
 	printf("\t-B no final state details in simulations\n");
 	printf("\t-b don't execute printfs in simulation\n");
-	printf("\t-C print channel access info (structview)\n");
+	printf("\t-C print channel access info (combine with -g etc.)\n");
 	printf("\t-c columnated -s -r simulation output\n");
 	printf("\t-d produce symbol-table information\n");
 	printf("\t-Dyyy pass -Dyyy to the preprocessor\n");
@@ -155,7 +176,9 @@ usage(void)
 	printf("\t-F file  like -f, but with the LTL ");
 	printf("formula stored in a 1-line file\n");
 	printf("\t-g print all global variables\n");
+	printf("\t-h  at end of run, print value of seed for random nr generator used\n");
 	printf("\t-i interactive (random simulation)\n");
+	printf("\t-I show result of inlining and preprocessing\n");
 	printf("\t-J reverse eval order of nested unlesses\n");
 	printf("\t-jN skip the first N steps ");
 	printf("in simulation trail\n");
@@ -165,16 +188,20 @@ usage(void)
 	printf("\t-N file use never claim stored in file\n");
 	printf("\t-nN seed for random nr generator\n");
 	printf("\t-o1 turn off dataflow-optimizations in verifier\n");
-	printf("\t-o2 turn off dead variables elimination in verifier\n");
+	printf("\t-o2 don't hide write-only variables in verifier\n");
 	printf("\t-o3 turn off statement merging in verifier\n");
 	printf("\t-Pxxx use xxx for preprocessing\n");
 	printf("\t-p print all statements\n");
 	printf("\t-qN suppress io for queue N in printouts\n");
 	printf("\t-r print receive events\n");
+	printf("\t-S1 and -S2 separate pan source for claim and model\n");
 	printf("\t-s print send events\n");
+	printf("\t-T do not indent printf output\n");
+	printf("\t-t[N] follow [Nth] simulation trail\n");
+	printf("\t-Uyyy pass -Uyyy to the preprocessor\n");
+	printf("\t-uN stop a simulation run after N steps\n");
 	printf("\t-v verbose, more warnings\n");
 	printf("\t-w very verbose (when combined with -l or -g)\n");
-	printf("\t-t[N] follow [Nth] simulation trail\n");
 	printf("\t-[XYZ] reserved for use by xspin interface\n");
 	printf("\t-V print version number and exit\n");
 	alldone(1);
@@ -226,9 +253,34 @@ optimizations(char nr)
 	}
 }
 
+#if 0
+static int
+Rename(const char *old, char *new)
+{	FILE *fo, *fn;
+	char buf[1024];
+
+	if ((fo = fopen(old, "r")) == NULL)
+	{	printf("spin: cannot open %s\n", old);
+		return 1;
+	}
+	if ((fn = fopen(new, "w")) == NULL)
+	{	printf("spin: cannot create %s\n", new);
+		fclose(fo);
+		return 2;
+	}
+	while (fgets(buf, 1024, fo))
+		fputs(buf, fn);
+
+	fclose(fo);
+	fclose(fn);
+
+	return 0;	/* success */
+}
+#endif
+
 int
 main(int argc, char *argv[])
-{	Symbol *s; int preprocessonly = 0;
+{	Symbol *s;
 	int T = (int) time((time_t *)0);
 	int usedopts = 0;
 	extern void ana_src(int, int);
@@ -244,14 +296,15 @@ main(int argc, char *argv[])
 		/* generate code for separate compilation: S1 or S2 */
 		case 'S': separate = atoi(&argv[1][2]);
 			  /* fall through */
-
 		case 'a': analyze  = 1; break;
+
+		case 'A': export_ast = 1; break;
 		case 'B': no_wrapup = 1; break;
 		case 'b': no_print = 1; break;
 		case 'C': Caccess = 1; break;
 		case 'c': columns = 1; break;
 		case 'D': PreArg[++PreCnt] = (char *) &argv[1][0];
-			  break;
+			  break;	/* define */
 		case 'd': dumptab =  1; break;
 		case 'E': PreArg[++PreCnt] = (char *) &argv[1][2];
 			  break;
@@ -260,7 +313,9 @@ main(int argc, char *argv[])
 		case 'f': add_ltl = (char **) argv;
 			  argc--; argv++; break;
 		case 'g': verbose +=  1; break;
+		case 'h': seedy = 1; break;
 		case 'i': interactive = 1; break;
+		case 'I': inlineonly = 1; break;
 		case 'J': like_java = 1; break;
 		case 'j': jumpsteps = atoi(&argv[1][2]); break;
 		case 'l': verbose +=  2; break;
@@ -278,16 +333,20 @@ main(int argc, char *argv[])
 			  break;
 		case 'r': verbose +=  8; break;
 		case 's': verbose += 16; break;
+		case 'T': notabs = 1; break;
 		case 't': s_trail  =  1;
 			  if (isdigit(argv[1][2]))
 				ntrail = atoi(&argv[1][2]);
 			  break;
+		case 'U': PreArg[++PreCnt] = (char *) &argv[1][0];
+			  break;	/* undefine */
+		case 'u': cutoff = atoi(&argv[1][2]); break;	/* new 3.4.14 */
 		case 'v': verbose += 32; break;
 		case 'V': printf("%s\n", Version);
 			  alldone(0);
 			  break;
 		case 'w': verbose += 64; break;
-		case 'X': xspin = 1;
+		case 'X': xspin = notabs = 1;
 #ifndef PC
 			  signal(SIGPIPE, alldone); /* not posix... */
 #endif
@@ -316,20 +375,13 @@ main(int argc, char *argv[])
 	}
 	if (argc > 1)
 	{	char cmd[128], out2[64];
-#ifdef PC
-		strcpy(out1, "_tmp1_");
-		strcpy(out2, "_tmp2_");
-#else
-		/* extern char *tmpnam(char *);  in stdio.h */
+
+		/* must remain in current dir */
+		strcpy(out1, "pan.pre");
+
 		if (add_ltl || nvr_file)
-		{	/* must remain in current dir */
-			strcpy(out1, "_tmp1_");
-			strcpy(out2, "_tmp2_");
-		} else
-		{	(void) tmpnam(out1);
-			(void) tmpnam(out2);
-		}
-#endif
+			strcpy(out2, "pan.___");
+
 		if (add_ltl)
 		{	tl_out = cpyfile(argv[1], out2);
 			nr_errs = tl_main(2, add_ltl);	/* in tl_main.c */
@@ -353,13 +405,8 @@ main(int argc, char *argv[])
 			preprocess(argv[1], out1, 0);
 
 		if (preprocessonly)
-		{	(void) unlink("pan.pre"); /* remove old version */
-			if (rename((const char *) out1, "pan.pre") != 0)
-			{	printf("spin: rename %s failed\n", out1);
-				alldone(1);
-			}
 			alldone(0);
-		}
+
 		if (!(yyin = fopen(out1, "r")))
 		{	printf("spin: cannot open %s\n", out1);
 			alldone(1);
@@ -372,7 +419,7 @@ main(int argc, char *argv[])
 			strcpy(cmd, argv[1]);
 		oFname = Fname = lookup(cmd);
 		if (oFname->name[0] == '\"')
-		{	int i = strlen(oFname->name);
+		{	int i = (int) strlen(oFname->name);
 			oFname->name[i-1] = '\0';
 			oFname = lookup(&oFname->name[1]);
 		}
@@ -401,19 +448,30 @@ main(int argc, char *argv[])
 	if (columns == 2 && limited_vis)
 		verbose += (1+4);
 	Srand(T);	/* defined in run.c */
-	s = lookup("_");	s->type = PREDEF; /* a write only global var */
+	SeedUsed = T;
+	s = lookup("_");	s->type = PREDEF; /* write-only global var */
 	s = lookup("_p");	s->type = PREDEF;
 	s = lookup("_pid");	s->type = PREDEF;
 	s = lookup("_last");	s->type = PREDEF;
 	s = lookup("_nr_pr");	s->type = PREDEF; /* new 3.3.10 */
+
 	yyparse();
 	fclose(yyin);
+	loose_ends();
+
+	if (inlineonly)
+	{	repro_src();
+		return 0;
+	}
+
 	chanaccess();
-	if (!s_trail && (dataflow || merger))
-		ana_src(dataflow, merger);
-	sched();
-	alldone(nr_errs);
-	return 0;	/* can't get here */
+	if (!Caccess)
+	{	if (!s_trail && (dataflow || merger))
+			ana_src(dataflow, merger);
+		sched();
+		alldone(nr_errs);
+	}
+	return 0;
 }
 
 int
@@ -463,7 +521,7 @@ emalloc(int n)
 }
 
 void
-trapwonly(Lextok *n, char *s)
+trapwonly(Lextok *n, char *unused)
 {	extern int realread;
 	short i = (n->sym)?n->sym->type:0;
 
@@ -502,6 +560,7 @@ setaccess(Symbol *sp, Symbol *what, int cnt, int t)
 Lextok *
 nn(Lextok *s, int t, Lextok *ll, Lextok *rl)
 {	Lextok *n = (Lextok *) emalloc(sizeof(Lextok));
+	static int warn_nn = 0;
 
 	n->ntyp = (short) t;
 	if (s && s->fn)
@@ -558,6 +617,9 @@ nn(Lextok *s, int t, Lextok *ll, Lextok *rl)
 			}	}
 			forbidden = 0;
 			break;
+		case 'c':
+			AST_track(n, 0);	/* register as a slice criterion */
+			/* fall thru */
 		default:
 			forbidden = 0;
 			break;
@@ -566,27 +628,62 @@ nn(Lextok *s, int t, Lextok *ll, Lextok *rl)
 		{	printf("spin: never, saw "); explain(t); printf("\n");
 			fatal("incompatible with separate compilation",(char *)0);
 		}
-	} else if (t == ENABLED || t == PC_VAL)
-	{	printf("spin: Warning, using %s outside never-claim\n",
+	} else if ((t == ENABLED || t == PC_VAL) && !(warn_nn&t))
+	{	printf("spin: Warning, using %s outside never claim\n",
 			(t == ENABLED)?"enabled()":"pc_value()");
+		warn_nn |= t;
 	} else if (t == NONPROGRESS)
-	{	fatal("spin: Error, using np_ outside never-claim\n", (char *)0);
+	{	fatal("spin: Error, using np_ outside never claim\n", (char *)0);
 	}
 	return n;
 }
 
 Lextok *
-rem_lab(Symbol *a, Lextok *b, Symbol *c)
+rem_lab(Symbol *a, Lextok *b, Symbol *c)	/* proctype name, pid, label name */
 {	Lextok *tmp1, *tmp2, *tmp3;
 
 	has_remote++;
-	fix_dest(c, a);	/* in case target is jump */
+	c->type = LABEL;	/* refered to in global context here */
+	fix_dest(c, a);		/* in case target of rem_lab is jump */
 	tmp1 = nn(ZN, '?',   b, ZN); tmp1->sym = a;
 	tmp1 = nn(ZN, 'p', tmp1, ZN);
 	tmp1->sym = lookup("_p");
 	tmp2 = nn(ZN, NAME,  ZN, ZN); tmp2->sym = a;
 	tmp3 = nn(ZN, 'q', tmp2, ZN); tmp3->sym = c;
 	return nn(ZN, EQ, tmp1, tmp3);
+#if 0
+	      .---------------EQ-------.
+	     /                          \
+	   'p' -sym-> _p               'q' -sym-> c (label name)
+	   /                           /
+	 '?' -sym-> a (proctype)     NAME -sym-> a (proctype name)
+	 / 
+	b (pid expr)
+#endif
+}
+
+Lextok *
+rem_var(Symbol *a, Lextok *b, Symbol *c, Lextok *ndx)
+{	Lextok *tmp1;
+
+	has_remote++;
+	has_remvar++;
+	dataflow = 0;	/* turn off dead variable resets 4.2.5 */
+	tmp1 = nn(ZN, '?', b, ZN); tmp1->sym = a;
+	tmp1 = nn(ZN, 'p', tmp1, ndx);
+	tmp1->sym = c;
+	return tmp1;
+#if 0
+	cannot refer to struct elements
+	only to scalars and arrays
+
+	    'p' -sym-> c (variable name)
+	    / \______  possible arrayindex on c
+	   /
+	 '?' -sym-> a (proctype)
+	 / 
+	b (pid expr)
+#endif
 }
 
 static void
@@ -594,8 +691,8 @@ explain(int n)
 {	FILE *fd = stdout;
 	switch (n) {
 	default:	if (n > 0 && n < 256)
-				fprintf(fd, "%c' = '", n);
-			fprintf(fd, "%d", n);
+				fprintf(fd, "'%c' = '", n);
+			fprintf(fd, "%d'", n);
 			break;
 	case '\b':	fprintf(fd, "\\b"); break;
 	case '\t':	fprintf(fd, "\\t"); break;
@@ -614,10 +711,16 @@ explain(int n)
 	case ASSERT:	fprintf(fd, "%sassert",	Function); break;
 	case ATOMIC:	fprintf(fd, "%satomic",	Keyword); break;
 	case BREAK:	fprintf(fd, "%sbreak",	Keyword); break;
+	case C_CODE:	fprintf(fd, "%sc_code",	Keyword); break;
+	case C_DECL:	fprintf(fd, "%sc_decl",	Keyword); break;
+	case C_EXPR:	fprintf(fd, "%sc_expr",	Keyword); break;
+	case C_STATE:	fprintf(fd, "%sc_state",Keyword); break;
+	case C_TRACK:	fprintf(fd, "%sc_track",Keyword); break;
 	case CLAIM:	fprintf(fd, "%snever",	Keyword); break;
 	case CONST:	fprintf(fd, "a constant"); break;
 	case DECR:	fprintf(fd, "%s--",	Operator); break;
 	case D_STEP:	fprintf(fd, "%sd_step",	Keyword); break;
+	case D_PROCTYPE: fprintf(fd, "%sd_proctype", Keyword); break;
 	case DO:	fprintf(fd, "%sdo",	Keyword); break;
 	case DOT:	fprintf(fd, "."); break;
 	case ELSE:	fprintf(fd, "%selse",	Keyword); break;
@@ -630,11 +733,13 @@ explain(int n)
 	case GE:	fprintf(fd, "%s>=",	Operator); break;
 	case GOTO:	fprintf(fd, "%sgoto",	Keyword); break;
 	case GT:	fprintf(fd, "%s>",	Operator); break;
+	case HIDDEN:	fprintf(fd, "%shidden",	Keyword); break;
 	case IF:	fprintf(fd, "%sif",	Keyword); break;
 	case INCR:	fprintf(fd, "%s++",	Operator); break;
 	case INAME:	fprintf(fd, "inline name"); break;
 	case INLINE:	fprintf(fd, "%sinline",	Keyword); break;
 	case INIT:	fprintf(fd, "%sinit",	Keyword); break;
+	case ISLOCAL:	fprintf(fd, "%slocal",  Keyword); break;
 	case LABEL:	fprintf(fd, "a label-name"); break;
 	case LE:	fprintf(fd, "%s<=",	Operator); break;
 	case LEN:	fprintf(fd, "%slen",	Function); break;
@@ -655,15 +760,20 @@ explain(int n)
 	case PC_VAL:	fprintf(fd, "%spc_value",Function); break;
 	case PNAME:	fprintf(fd, "process name"); break;
 	case PRINT:	fprintf(fd, "%sprintf",	Function); break;
+	case PRINTM:	fprintf(fd, "%sprintm",	Function); break;
+	case PRIORITY:	fprintf(fd, "%spriority", Keyword); break;
 	case PROCTYPE:	fprintf(fd, "%sproctype",Keyword); break;
+	case PROVIDED:	fprintf(fd, "%sprovided",Keyword); break;
 	case RCV:	fprintf(fd, "%s?",	Operator); break;
 	case R_RCV:	fprintf(fd, "%s??",	Operator); break;
 	case RSHIFT:	fprintf(fd, "%s>>",	Operator); break;
 	case RUN:	fprintf(fd, "%srun",	Operator); break;
 	case SEP:	fprintf(fd, "token: ::"); break;
 	case SEMI:	fprintf(fd, ";"); break;
+	case SHOW:	fprintf(fd, "%sshow", Keyword); break;
 	case SND:	fprintf(fd, "%s!",	Operator); break;
 	case STRING:	fprintf(fd, "a string"); break;
+	case TRACE:	fprintf(fd, "%strace", Keyword); break;
 	case TIMEOUT:	fprintf(fd, "%stimeout",Keyword); break;
 	case TYPE:	fprintf(fd, "data typename"); break;
 	case TYPEDEF:	fprintf(fd, "%stypedef",Keyword); break;

+ 28 - 15
sys/src/cmd/spin/mesg.c

@@ -1,14 +1,13 @@
 /***** spin: mesg.c *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 #include "spin.h"
 #ifdef PC
@@ -17,7 +16,9 @@
 #include "y.tab.h"
 #endif
 
+#ifndef MAXQ
 #define MAXQ	2500		/* default max # queues  */
+#endif
 
 extern RunList	*X;
 extern Symbol	*Fname;
@@ -58,7 +59,7 @@ int
 qmake(Symbol *s)
 {	Lextok *m;
 	Queue *q;
-	int i; extern int analyze;
+	int i;
 
 	if (!s->ini)
 		return 0;
@@ -370,10 +371,13 @@ s_snd(Queue *q, Lextok *n)
 				||  strcmp(m->lft->sym->name, "_") != 0)
 					i = eval(m->lft);
 				else	i = 0;
+
+				if (verbose&8)
 				sr_talk(n_rem,i,"Recv ","<-",j,q_rem);
 			}
+			if (verbose&8)
 			for (i = j; i < q->nflds; i++)
-			sr_talk(n_rem, 0, "Recv ", "<-", j, q_rem);
+				sr_talk(n_rem, 0, "Recv ", "<-", j, q_rem);
 			if (columns == 2)
 				putarrow(depth, depth);
 		}
@@ -385,7 +389,7 @@ s_snd(Queue *q, Lextok *n)
 
 void
 channm(Lextok *n)
-{	char lbuf[256];
+{	char lbuf[512];
 
 	if (n->sym->type == CHAN)
 		strcat(Buf, n->sym->name);
@@ -397,6 +401,7 @@ channm(Lextok *n)
 			r = findloc(r);
 		ini_struct(r);
 		printf("%s", r->name);
+		strcpy(lbuf, "");
 		struct_name(n->lft, r, 1, lbuf);
 		strcat(Buf, lbuf);
 	} else
@@ -409,8 +414,7 @@ channm(Lextok *n)
 
 static void
 difcolumns(Lextok *n, char *tr, int v, int j, Queue *q)
-{	int cnt = 1; extern int pno;
-	Lextok *nn = ZN;
+{	extern int pno;
 
 	if (j == 0)
 	{	Buf[0] = '\0';
@@ -534,7 +538,7 @@ sr_talk(Lextok *n, int v, char *tr, char *a, int j, Queue *q)
 void
 sr_buf(int v, int j)
 {	int cnt = 1; Lextok *n;
-	char lbuf[128];
+	char lbuf[256];
 
 	for (n = Mtype; n && j; n = n->rgt, cnt++)
 		if (cnt == v)
@@ -594,7 +598,16 @@ nochan_manip(Lextok *p, Lextok *n, int d)
 {	int e = 1;
 
 	if (d == 0 && p->sym && p->sym->type == CHAN)
-		setaccess(p->sym, ZS, 0, 'L');
+	{	setaccess(p->sym, ZS, 0, 'L');
+
+		if (n && n->ntyp == CONST)
+			fatal("invalid asgn to chan", (char *) 0);
+
+		if (n && n->sym && n->sym->type == CHAN)
+		{	setaccess(n->sym, ZS, 0, 'V');
+			return;
+		}	
+	}
 
 	if (!n || n->ntyp == LEN || n->ntyp == RUN)
 		return;

+ 2 - 0
sys/src/cmd/spin/mkfile

@@ -13,8 +13,10 @@ SPIN_OS=\
 	pangen3.$O\
 	pangen4.$O\
 	pangen5.$O\
+	pangen6.$O\
 	pc_zpp.$O\
 	ps_msc.$O\
+	reprosrc.$O\
 	run.$O\
 	sched.$O\
 	spinlex.$O\

+ 344 - 103
sys/src/cmd/spin/pangen1.c

@@ -1,14 +1,13 @@
 /***** spin: pangen1.c *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 #include "spin.h"
 #ifdef PC
@@ -29,7 +28,9 @@ extern int	lineno, verbose, Pid, separate;
 extern int	nrRdy, nqs, mst, Mpars, claimnr, eventmapnr;
 extern short	has_sorted, has_random, has_provided;
 
-int	Npars=0, u_sync=0, u_async=0;
+int	Npars=0, u_sync=0, u_async=0, hastrack = 1;
+short	has_io = 0;
+short	has_state=0;	/* code contains c_state */
 
 static Symbol	*LstSet=ZS;
 static int	acceptors=0, progressors=0, nBits=0;
@@ -56,7 +57,10 @@ void
 genheader(void)
 {	ProcList *p; int i;
 
-	if (separate == 2) goto here;
+	if (separate == 2)
+	{	putunames(th);
+		goto here;
+	}
 
 	fprintf(th, "#define SYNC	%d\n", u_sync);
 	fprintf(th, "#define ASYNC	%d\n\n", u_async);
@@ -82,29 +86,39 @@ here:
 
 	ntimes(th, 0, 1, Head0);
 
-	if (separate == 2)
-	{	ntimes(th, 0, 1, Head1);
-		LstSet = ZS;
-		(void) doglobal("", PUTV);
-		fprintf(th, "	uchar sv[VECTORSZ];\n");
-		fprintf(th, "} State;\n\n");
-	} else
-	{
+	if (separate != 2)
+	{	extern void c_add_stack(FILE *);
+
 		ntimes(th, 0, 1, Header);
-		ntimes(th, 0, 1, Head1);
+		c_add_stack(th);
+		ntimes(th, 0, 1, Header0);
+	}
+	ntimes(th, 0, 1, Head1);
 
-		LstSet = ZS;
-		(void) doglobal("", PUTV);
-		fprintf(th, "	uchar sv[VECTORSZ];\n");
-		fprintf(th, "} State;\n\n");
+	LstSet = ZS;
+	(void) doglobal("", PUTV);
+
+	hastrack = c_add_sv(th);
+
+	fprintf(th, "	uchar sv[VECTORSZ];\n");
+	fprintf(th, "} State");
+#ifdef SOLARIS
+	fprintf(th,"\n#ifdef GCC\n");
+	fprintf(th, "\t__attribute__ ((aligned(8)))");
+	fprintf(th, "\n#endif\n\t");
+#endif
+	fprintf(th, ";\n\n");
+
+	fprintf(th, "#define HAS_TRACK	%d\n", hastrack);
+
+	if (separate != 2)
 		dohidden();
-	}
 }
 
 void
 genaddproc(void)
 {	ProcList *p;
-	int i;
+	int i = 0;
 
 	if (separate ==2) goto shortcut;
 
@@ -117,7 +131,7 @@ genaddproc(void)
 	ntimes(tc, 0, 1, Addp1);
 
 	if (has_provided)
-	{	fprintf(tt, "\nint\nprovided(int II, int ot, ");
+	{	fprintf(tt, "\nint\nprovided(int II, unsigned char ot, ");
 		fprintf(tt, "int tt, Trans *t)\n");
 		fprintf(tt, "{\n\tswitch(ot) {\n");
 	}
@@ -143,6 +157,14 @@ shortcut:
 	ntimes(tc, 0, 1, R8a);
 }
 
+void
+do_locinits(FILE *fd)
+{	ProcList *p;
+
+	for (p = rdy; p; p = p->nxt)
+		c_add_locinit(fd, p->tn, p->n->name);
+}
+
 void
 genother(void)
 {	ProcList *p;
@@ -190,7 +212,9 @@ genother(void)
 	ntimes(th, nrRdy+1, nrRdy+2, R2); /* +1 for np_ */
 
 	fprintf(tc, "	iniglobals();\n");
-	ntimes(tc, 0,     1, Code2);
+	ntimes(tc, 0,     1, Code2a);
+	ntimes(tc, 0,     1, Code2b);	/* bfs option */
+	ntimes(tc, 0,     1, Code2c);
 	ntimes(tc, 0,     nrRdy, R4);
 	fprintf(tc, "}\n\n");
 
@@ -245,7 +269,7 @@ end_labs(Symbol *s, int i)
 					ln[j].s);
 				goto complain;
 			}
-			if (l->e->status & ATOM)
+			if (j > 0 && (l->e->status & ATOM))
 			{	sprintf(foo, "%s label inside atomic",
 					ln[j].s);
 		complain:	lineno = l->e->n->ln;
@@ -317,7 +341,7 @@ checktype(Symbol *sp, char *s)
 	} else if (!(sp->hidden&4))
 	{	if (!(verbose&32)) return;
 		sputtype(buf, sp->type);
-		i = strlen(buf);
+		i = (int) strlen(buf);
 		while (buf[--i] == ' ') buf[i] = '\0';
 		prehint(sp);
 		if (sp->context)
@@ -329,7 +353,7 @@ checktype(Symbol *sp, char *s)
 	} else if (sp->type != BYTE && !(sp->hidden&8))
 	{	if (!(verbose&32)) return;
 		sputtype(buf, sp->type);
-		i = strlen(buf);
+		i = (int) strlen(buf);
 		while (buf[--i] == ' ') buf[i] = '\0';
 		prehint(sp);
 		if (sp->context)
@@ -342,7 +366,7 @@ checktype(Symbol *sp, char *s)
 }
 
 int
-dolocal(FILE *ofd, char *pre, int dowhat, int p, char *s, char *how)
+dolocal(FILE *ofd, char *pre, int dowhat, int p, char *s)
 {	int h, j, k=0; extern int nr_errs;
 	Ordered *walk;
 	Symbol *sp;
@@ -364,7 +388,7 @@ dolocal(FILE *ofd, char *pre, int dowhat, int p, char *s, char *how)
 					break;
 				sprintf(buf, "%s%s:", pre, s);
 				{ sprintf(buf2, "\", ((P%d *)pptr(h))->", p);
-				  sprintf(buf3, ");\n", p);
+				  sprintf(buf3, ");\n");
 				}
 				do_var(ofd, dowhat, "", sp, buf, buf2, buf3);
 				break;
@@ -385,6 +409,160 @@ dolocal(FILE *ofd, char *pre, int dowhat, int p, char *s, char *how)
 	return k;
 }
 
+void
+c_chandump(FILE *fd)
+{	Queue *q;
+	char buf[256];
+	int i;
+
+	if (!qtab)
+	{	fprintf(fd, "void\nc_chandump(int unused) ");
+		fprintf(fd, "{ unused = unused++; /* avoid complaints */ }\n");
+		return;
+	}
+
+	fprintf(fd, "void\nc_chandump(int from)\n");
+	fprintf(fd, "{	uchar *z; int slot;\n");
+
+	fprintf(fd, "	from--;\n");
+	fprintf(fd, "	if (from >= (int) now._nr_qs || from < 0)\n");
+	fprintf(fd, "	{	printf(\"pan: bad qid %%d\\n\", from+1);\n");
+	fprintf(fd, "		return;\n");
+	fprintf(fd, "	}\n");
+	fprintf(fd, "	z = qptr(from);\n");
+	fprintf(fd, "	switch (((Q0 *)z)->_t) {\n");
+
+	for (q = qtab; q; q = q->nxt)
+	{	fprintf(fd, "	case %d:\n\t\t", q->qid);
+		sprintf(buf, "((Q%d *)z)->", q->qid);
+
+		fprintf(fd, "for (slot = 0; slot < %sQlen; slot++)\n\t\t", buf);
+		fprintf(fd, "{	printf(\" [\");\n\t\t");
+		for (i = 0; i < q->nflds; i++)
+		{	if (q->fld_width[i] == MTYPE)
+			{	fprintf(fd, "\tprintm(%scontents[slot].fld%d);\n\t\t",
+				buf, i);
+			} else
+			fprintf(fd, "\tprintf(\"%%d,\", %scontents[slot].fld%d);\n\t\t",
+				buf, i);
+		}
+		fprintf(fd, "	printf(\"],\");\n\t\t");
+		fprintf(fd, "}\n\t\t");
+		fprintf(fd, "break;\n");
+	}
+	fprintf(fd, "	}\n");
+	fprintf(fd, "	printf(\"\\n\");\n}\n");
+}
+
+void
+c_var(FILE *fd, char *pref, Symbol *sp)
+{	char buf[256];
+	int i;
+
+	switch (sp->type) {
+	case STRUCT:
+		/* c_struct(fd, pref, sp); */
+		fprintf(fd, "\t\tprintf(\"\t(struct %s)\\n\");\n",
+			sp->name);
+		sprintf(buf, "%s%s.", pref, sp->name);
+		c_struct(fd, buf, sp);
+		break;
+	case BIT:   case BYTE:
+	case SHORT: case INT:
+	case UNSIGNED:
+		sputtype(buf, sp->type);
+		if (sp->nel == 1)
+		fprintf(fd, "\tprintf(\"\t%s %s:\t%%d\\n\", %s%s);\n",
+			buf, sp->name, pref, sp->name);
+		else
+		for (i = 0; i < sp->nel; i++)
+		fprintf(fd, "\tprintf(\"\t%s %s[%d]:\t%%d\\n\", %s%s[%d]);\n",
+			buf, sp->name, i, pref, sp->name, i);
+		break;
+	case CHAN:
+		if (sp->nel == 1)
+		{  fprintf(fd, "\tprintf(\"\tchan %s (=%%d):\tlen %%d:\\t\", ",
+			sp->name);
+		   fprintf(fd, "%s%s, q_len(%s%s));\n",
+			pref, sp->name, pref, sp->name);
+		   fprintf(fd, "\tc_chandump(%s%s);\n", pref, sp->name);
+		} else
+		for (i = 0; i < sp->nel; i++)
+		{  fprintf(fd, "\tprintf(\"\tchan %s[%d] (=%%d):\tlen %%d:\\t\", ",
+			sp->name, i);
+		   fprintf(fd, "%s%s[%d], q_len(%s%s[%d]));\n",
+			pref, sp->name, i, pref, sp->name, i);
+		   fprintf(fd, "\tc_chandump(%s%s[%d]);\n",
+			pref, sp->name, i);
+		}
+		break;
+	}
+}
+
+void
+c_splurge(FILE *fd, ProcList *p)
+{	Ordered *walk;
+	Symbol *sp;
+	char pref[64];
+
+	if (strcmp(p->n->name, ":never:") != 0
+	&&  strcmp(p->n->name, ":trace:") != 0
+	&&  strcmp(p->n->name, ":notrace:") != 0)
+	for (walk = all_names; walk; walk = walk->next)
+	{	sp = walk->entry;
+		if (!sp->context
+		||  strcmp(sp->context->name, p->n->name) != 0
+		||  sp->owner || (sp->hidden&1)
+		|| (sp->type == MTYPE && ismtype(sp->name)))
+			continue;
+
+		sprintf(pref, "((P%d *)pptr(pid))->", p->tn);
+		c_var(fd, pref, sp);
+	}
+}
+
+void
+c_wrapper(FILE *fd)	/* allow pan.c to print out global sv entries */
+{	Ordered *walk;
+	ProcList *p;
+	Symbol *sp;
+	Lextok *n;
+	extern Lextok *Mtype;
+	int j;
+
+	fprintf(fd, "void\nc_globals(void)\n{\t/* int i; */\n");
+	fprintf(fd, "	printf(\"global vars:\\n\");\n");
+	for (walk = all_names; walk; walk = walk->next)
+	{	sp = walk->entry;
+		if (sp->context || sp->owner || (sp->hidden&1)
+		|| (sp->type == MTYPE && ismtype(sp->name)))
+			continue;
+
+		c_var(fd, "now.", sp);
+	}
+	fprintf(fd, "}\n");
+
+	fprintf(fd, "void\nc_locals(int pid, int tp)\n{\t/* int i; */\n");
+	fprintf(fd, "	switch(tp) {\n");
+	for (p = rdy; p; p = p->nxt)
+	{	fprintf(fd, "	case %d:\n", p->tn);
+		fprintf(fd, "	\tprintf(\"local vars proc %%d (%s):\\n\", pid);\n",
+			p->n->name);
+		c_splurge(fd, p);
+		fprintf(fd, "	\tbreak;\n");
+	}
+	fprintf(fd, "	}\n}\n");
+
+	fprintf(fd, "void\nprintm(int x)\n{\n");
+	fprintf(fd, "	switch (x) {\n");
+        for (n = Mtype, j = 1; n && j; n = n->rgt, j++)
+                fprintf(fd, "\tcase %d: Printf(\"%s\"); break;\n",
+			j, n->lft->sym->name);
+	fprintf(fd, "	default: Printf(\"%%d\", x);\n");
+	fprintf(fd, "	}\n");
+	fprintf(fd, "}\n");
+}
+
 static int
 doglobal(char *pre, int dowhat)
 {	Ordered *walk;
@@ -396,7 +574,6 @@ doglobal(char *pre, int dowhat)
 	{	sp = walk->entry;
 		if (!sp->context
 		&&  !sp->owner
-	/*	&&  !(sp->hidden&1)	*/
 		&&  sp->type == Types[j])
 		{	if (Types[j] != MTYPE || !ismtype(sp->name))
 			switch (dowhat) {
@@ -513,15 +690,29 @@ static void
 put_ptype(char *s, int i, int m0, int m1)
 {	int k;
 
+	if (strcmp(s, ":init:") == 0)
+		fprintf(th, "#define Pinit	((P%d *)this)\n", i);
+
+	if (strcmp(s, ":never:") != 0
+	&&  strcmp(s, ":trace:") != 0
+	&&  strcmp(s, ":notrace:") != 0
+	&&  strcmp(s, ":init:")  != 0
+	&&  strcmp(s, "_:never_template:_") != 0
+	&&  strcmp(s, "np_")     != 0)
+		fprintf(th, "#define P%s	((P%d *)this)\n", s, i);
+
 	fprintf(th, "typedef struct P%d { /* %s */\n", i, s);
 	fprintf(th, "	unsigned _pid : 8;  /* 0..255 */\n");
 	fprintf(th, "	unsigned _t   : %d; /* proctype */\n", blog(m1));
 	fprintf(th, "	unsigned _p   : %d; /* state    */\n", blog(m0));
 	LstSet = ZS;
 	nBits = 8 + blog(m1) + blog(m0);
-	k = dolocal(tc, "", PUTV, i, s, "");	/* includes pars */
+	k = dolocal(tc, "", PUTV, i, s);	/* includes pars */
+
+	c_add_loc(th, s);
+
 	fprintf(th, "} P%d;\n", i);
-	if (!LstSet && k > 0)
+	if ((!LstSet && k > 0) || has_state)
 		fprintf(th, "#define Air%d	0\n", i);
 	else
 	{	fprintf(th, "#define Air%d	(sizeof(P%d) - ", i, i);
@@ -531,15 +722,8 @@ put_ptype(char *s, int i, int m0, int m1)
 		}
 		if ((LstSet->type != BIT && LstSet->type != UNSIGNED)
 		||   LstSet->nel != 1)
-		{	fprintf(th, "Offsetof(P%d, %s%s) - %d*sizeof(",
-				i,
-				LstSet->name,
-#if 1
-				"",
-#else
-				(LstSet->nel > 1)?"[0]":"",
-#endif
-				LstSet->nel);
+		{	fprintf(th, "Offsetof(P%d, %s) - %d*sizeof(",
+				i, LstSet->name, LstSet->nel);
 		}
 		switch(LstSet->type) {
 		case UNSIGNED:
@@ -608,7 +792,7 @@ put_pinit(ProcList *P)
 	&&  separate == 2)
 		return;
 
-	ini = huntele(e, e->status)->seqno;
+	ini = huntele(e, e->status, -1)->seqno;
 	fprintf(th, "#define start%d	%d\n", i, ini);
 	if (i == claimnr)
 	fprintf(th, "#define start_claim	%d\n", ini);
@@ -648,7 +832,7 @@ put_pinit(ProcList *P)
 		{	if (full_name(tc, t, t->sym, 1))
 			{	lineno = t->ln;
 				Fname  = t->fn;
-				fatal("hidden array in parameter, %s",
+				fatal("hidden array in parameter %s",
 				t->sym->name);
 			}
 		} else
@@ -656,12 +840,17 @@ put_pinit(ProcList *P)
 		fprintf(tc, " = par%d;\n", j);
 	}
 	fprintf(tc, "\t\t/* locals: */\n");
-	k = dolocal(tc, "", INIV, i, s->name, "");
+	k = dolocal(tc, "", INIV, i, s->name);
 	if (k > 0)
 	{	fprintf(tc, "#ifdef VAR_RANGES\n");
-		(void) dolocal(tc, "logval(\"", LOGV, i, s->name, "");
+		(void) dolocal(tc, "logval(\"", LOGV, i, s->name);
 		fprintf(tc, "#endif\n");
 	}
+
+	fprintf(tc, "#ifdef HAS_CODE\n");
+	fprintf(tc, "\t\tlocinit%d(h);\n", i);
+	fprintf(tc, "#endif\n");
+
 	dumpclaims(tc, i, s->name);
 	fprintf(tc, "\t	break;\n");
 }
@@ -669,28 +858,35 @@ put_pinit(ProcList *P)
 Element *
 huntstart(Element *f)
 {	Element *e = f;
+	Element *elast = (Element *) 0;
+	int cnt = 0;
+
+	while (elast != e && cnt++ < 20)	/* new 4.0.8 */
+	{	elast = e;
+		if (e->n)
+		{	if (e->n->ntyp == '.' && e->nxt)
+				e = e->nxt;
+			else if (e->n->ntyp == UNLESS)
+				e = e->sub->this->frst;
+	}	}
 
-	if (e->n)
-	{	if (e->n->ntyp == '.' && e->nxt)
-			e = e->nxt;
-		else if (e->n->ntyp == ATOMIC
-		     ||  e->n->ntyp == D_STEP
-		     ||  e->n->ntyp == NON_ATOMIC)
-			e->n->sl->this->last->nxt = e->nxt;
-		else if (e->n->ntyp == UNLESS)
-			return e->sub->this->frst;
-	}
+	if (cnt >= 20 || !e)
+		fatal("confusing control structure", (char *) 0);
 	return e;
 }
 
 Element *
-huntele(Element *f, int o)
+huntele(Element *f, int o, int stopat)
 {	Element *g, *e = f;
-	int cnt; /* a precaution against loops */
+	int cnt=0; /* a precaution against loops */
 
 	if (e)
-	for (cnt=0; cnt < 10 && e->n; cnt++)
-	{	switch (e->n->ntyp) {
+	for (cnt = 0; cnt < 20 && e->n; cnt++)
+	{
+		if (e->seqno == stopat)
+			break;
+
+		switch (e->n->ntyp) {
 		case GOTO:
 			g = get_lab(e->n,1);
 			cross_dsteps(e->n, g->n);
@@ -702,19 +898,20 @@ huntele(Element *f, int o)
 			g = e->nxt;
 			break;
 		case UNLESS:
-			g = huntele(e->sub->this->frst, o);
+			g = huntele(e->sub->this->frst, o, stopat);
 			break;
 		case D_STEP:
 		case ATOMIC:
 		case NON_ATOMIC:
-			e->n->sl->this->last->nxt = e->nxt;
-		default:	/* fall through */
+		default:
 			return e;
 		}
 		if ((o & ATOM) && !(g->status & ATOM))
 			return e;
 		e = g;
 	}
+	if (cnt >= 20 || !e)
+		fatal("confusing control structure", (char *) 0);
 	return e;
 }
 
@@ -743,6 +940,7 @@ typ2c(Symbol *sp)
 			nBits++;
 			break;
 		} /* else fall through */
+		if (!(sp->hidden&1) && (verbose&32))
 		printf("spin: warning: bit-array %s[%d] mapped to byte-array\n",
 			sp->name, sp->nel);
 		nBits += 8*sp->nel; /* mapped onto array of uchars */
@@ -768,6 +966,7 @@ typ2c(Symbol *sp)
 			sp->name);
 		LstSet = ZS;
 		break;
+	case CODE_FRAG:
 	case PREDEF:
 		return;
 	default:
@@ -790,22 +989,49 @@ ncases(FILE *fd, int p, int n, int m, char *c[])
 	}
 }
 
+void
+qlen_type(int qmax)
+{
+	fprintf(th, "\t");
+	if (qmax < 256)
+		fprintf(th, "uchar");
+	else if (qmax < 65535)
+		fprintf(th, "ushort");
+	else
+		fprintf(th, "uint");
+	fprintf(th, " Qlen;	/* q_size */\n");
+}
+
 void
 genaddqueue(void)
 {	char buf0[256];
-	int j;
+	int j, qmax = 0;
 	Queue *q;
 
 	ntimes(tc, 0, 1, Addq0);
+	if (has_io && !nqs)
+		fprintf(th, "#define NQS	1 /* nqs=%d, but has_io */\n", nqs);
+	else
+		fprintf(th, "#define NQS	%d\n", nqs);
 	fprintf(th, "short q_flds[%d];\n", nqs+1);
 	fprintf(th, "short q_max[%d];\n", nqs+1);
+
+	for (q = qtab; q; q = q->nxt)
+		if (q->nslots > qmax)
+			qmax = q->nslots;
+
 	for (q = qtab; q; q = q->nxt)
 	{	j = q->qid;
 		fprintf(tc, "\tcase %d: j = sizeof(Q%d);", j, j);
 		fprintf(tc, " q_flds[%d] = %d;", j, q->nflds);
 		fprintf(tc, " q_max[%d] = %d;", j, max(1,q->nslots));
 		fprintf(tc, " break;\n");
-		ntimes(th, j, j+1, R9);
+
+		fprintf(th, "typedef struct Q%d {\n", j);
+		qlen_type(qmax);	/* 4.2.2 */
+		fprintf(th, "	uchar _t;	/* q_type */\n");
+		fprintf(th, "	struct {\n");
+
 		for (j = 0; j < q->nflds; j++)
 		{	switch (q->fld_width[j]) {
 			case BIT:
@@ -832,7 +1058,12 @@ genaddqueue(void)
 		fprintf(th, "	} contents[%d];\n", max(1, q->nslots));
 		fprintf(th, "} Q%d;\n", q->qid);
 	}
-	ntimes(th, 0, 1, R10);
+
+	fprintf(th, "typedef struct Q0 {\t/* generic q */\n");
+	qlen_type(qmax);	/* 4.2.2 */
+	fprintf(th, "	uchar _t;\n");
+	fprintf(th, "} Q0;\n");
+
 	ntimes(tc, 0, 1, Addq1);
 
 	if (has_random)
@@ -866,6 +1097,7 @@ genaddqueue(void)
 		fprintf(tc, "}\n");
 	}
 
+	fprintf(tc, "#if NQS>0\n");
 	fprintf(tc, "void\nqsend(int into, int sorted");
 	for (j = 0; j < Mpars; j++)
 		fprintf(tc, ", int fld%d", j);
@@ -879,33 +1111,35 @@ genaddqueue(void)
 		if (q->nslots == 0)	/* reset handshake point */
 			fprintf(tc, "\t\t(trpt+2)->o_m = 0;\n");
 
-	if (has_sorted)
-	{	fprintf(tc, "\t\tif (!sorted) goto append%d;\n", q->qid);
-		fprintf(tc, "\t\tfor (j = 0; j < %sQlen; j++)\n", buf0);
-		fprintf(tc, "\t\t{\t/* find insertion point */\n");
-		sprintf(buf0, "((Q%d *)z)->contents[j].fld", q->qid);
-		for (j = 0; j < q->nflds; j++)
-		{	fprintf(tc, "\t\t\tif (fld%d > %s%d) continue;\n",
-					j, buf0, j);
-			fprintf(tc, "\t\t\tif (fld%d < %s%d) ", j, buf0, j);
-			fprintf(tc, "goto found%d;\n\n", q->qid);
-		}
-		fprintf(tc, "\t\t}\n");
-		fprintf(tc, "\tfound%d:\n", q->qid);
-		sprintf(buf0, "((Q%d *)z)->", q->qid);
-		fprintf(tc, "\t\tfor (k = %sQlen - 1; k >= j; k--)\n", buf0);
-		fprintf(tc, "\t\t{\t/* shift up */\n");
-		for (j = 0; j < q->nflds; j++)
-		{	fprintf(tc, "\t\t\t%scontents[k+1].fld%d = ",
-				buf0, j);
-			fprintf(tc, "%scontents[k].fld%d;\n",
-				buf0, j);
+		if (has_sorted)
+		{	fprintf(tc, "\t\tif (!sorted) goto append%d;\n", q->qid);
+			fprintf(tc, "\t\tfor (j = 0; j < %sQlen; j++)\n", buf0);
+			fprintf(tc, "\t\t{\t/* find insertion point */\n");
+			sprintf(buf0, "((Q%d *)z)->contents[j].fld", q->qid);
+			for (j = 0; j < q->nflds; j++)
+			{	fprintf(tc, "\t\t\tif (fld%d > %s%d) continue;\n",
+						j, buf0, j);
+				fprintf(tc, "\t\t\tif (fld%d < %s%d) ", j, buf0, j);
+				fprintf(tc, "goto found%d;\n\n", q->qid);
+			}
+			fprintf(tc, "\t\t}\n");
+			fprintf(tc, "\tfound%d:\n", q->qid);
+			sprintf(buf0, "((Q%d *)z)->", q->qid);
+			fprintf(tc, "\t\tfor (k = %sQlen - 1; k >= j; k--)\n", buf0);
+			fprintf(tc, "\t\t{\t/* shift up */\n");
+			for (j = 0; j < q->nflds; j++)
+			{	fprintf(tc, "\t\t\t%scontents[k+1].fld%d = ",
+					buf0, j);
+				fprintf(tc, "%scontents[k].fld%d;\n",
+					buf0, j);
+			}
+			fprintf(tc, "\t\t}\n");
+			fprintf(tc, "\tappend%d:\t/* insert in slot j */\n", q->qid);
 		}
-		fprintf(tc, "\t\t}\n");
-		fprintf(tc, "\tappend%d:\t/* insert in slot j */\n", q->qid);
-	}
 
-		fprintf(tc, "\t\t(trpt+1)->bup.oval = j;\n");
+		fprintf(tc, "#ifdef HAS_SORTED\n");
+		fprintf(tc, "\t\t(trpt+1)->ipt = j;\n");	/* ipt was bup.oval */
+		fprintf(tc, "#endif\n");
 		fprintf(tc, "\t\t%sQlen = %sQlen + 1;\n", buf0, buf0);
 		sprintf(buf0, "((Q%d *)z)->contents[j].fld", q->qid);
 		for (j = 0; j < q->nflds; j++)
@@ -939,16 +1173,23 @@ genaddqueue(void)
 			fprintf(tc, "\t\t}\n");
 		}
 		fprintf(tc, "\t\tif (done)\n");
-		fprintf(tc, "\t\t{	j = %sQlen;\n",  buf0);
-		fprintf(tc, "\t\t	%sQlen = --j;\n", buf0);
-		fprintf(tc, "\t\t	for (k=slot; k<j; k++)\n");
-		fprintf(tc, "\t\t	{\n");
-		sprintf(buf0, "\t\t\t((Q%d *)z)->contents", q->qid);
-		for (j = 0; j < q->nflds; j++)
-		{	fprintf(tc, "\t%s[k].fld%d = \n", buf0, j);
-			fprintf(tc, "\t\t%s[k+1].fld%d;\n", buf0, j);
-		}
-		fprintf(tc, "\t\t	}\n");
+		if (q->nslots == 0)
+		{	fprintf(tc, "\t\t{	j = %sQlen - 1;\n",  buf0);
+			fprintf(tc, "\t\t	%sQlen = 0;\n", buf0);
+			sprintf(buf0, "\t\t\t((Q%d *)z)->contents", q->qid);
+		} else
+	 	{	fprintf(tc, "\t\t{	j = %sQlen;\n",  buf0);
+			fprintf(tc, "\t\t	%sQlen = --j;\n", buf0);
+			fprintf(tc, "\t\t	for (k=slot; k<j; k++)\n");
+			fprintf(tc, "\t\t	{\n");
+			sprintf(buf0, "\t\t\t((Q%d *)z)->contents", q->qid);
+			for (j = 0; j < q->nflds; j++)
+			{	fprintf(tc, "\t%s[k].fld%d = \n", buf0, j);
+				fprintf(tc, "\t\t%s[k+1].fld%d;\n", buf0, j);
+			}
+			fprintf(tc, "\t\t	}\n");
+	 	}
+
 		for (j = 0; j < q->nflds; j++)
 			fprintf(tc, "%s[j].fld%d = 0;\n", buf0, j);
 		fprintf(tc, "\t\t\tif (fld+1 != %d)\n\t\t\t", q->nflds);

File diff suppressed because it is too large
+ 1110 - 30
sys/src/cmd/spin/pangen1.h


File diff suppressed because it is too large
+ 279 - 112
sys/src/cmd/spin/pangen2.c


+ 116 - 115
sys/src/cmd/spin/pangen2.h

@@ -1,14 +1,13 @@
 /***** spin: pangen2.h *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 static char *Nvr1[] = {		/* allow separate compilation */
 	"#ifdef VERI",
@@ -18,20 +17,31 @@ static char *Nvr1[] = {		/* allow separate compilation */
 	"	if (st == endclaim)",
 	"		uerror(\"claim violated!\");",
 	"	if (stopstate[VERI][st])",
-	"		uerror(\"endstate in claim reached\");",
+	"		uerror(\"end state in claim reached\");",
 	"}",
 	"#endif",
 	0,
 };
 
 static char *Pre0[] = {
+"#ifdef SC",
+	"#define _FILE_OFFSET_BITS	64",	/* to allow file sizes greater than 2Gb */
+"#endif",
 	"#include <stdio.h>",
 	"#include <signal.h>",
 	"#include <stdlib.h>",
-	"#include <string.h>",	/* was strings.h -- string.h is ANSI */
-/* new */
+	"#include <stdarg.h>",
+	"#include <string.h>",
+	"#include <ctype.h>",
 	"#include <errno.h>",
-/* end */
+"#ifdef SC",
+	"#include <sys/types.h>",	/* defines off_t */
+	"#include <sys/stat.h>",
+	"#include <fcntl.h>",
+	#ifndef PC
+	"#include <unistd.h>",
+	#endif
+"#endif",
 	"#define Offsetof(X, Y)	((unsigned long)(&(((X *)0)->Y)))",
 	"#ifndef max",
 	"#define max(a,b) (((a)<(b)) ? (b) : (a))",
@@ -64,6 +74,9 @@ static char *Preamble[] = {
 	"#endif",
 
 "#ifdef MA",
+	"#undef onstack_now",
+	"#undef onstack_put",
+	"#undef onstack_zap",
 	"#define onstack_put()	;",
 	"#define onstack_zap()	gstore((char *) &now, vsize, 4)",
 "#else",
@@ -102,7 +115,7 @@ static char *Preamble[] = {
 	"} **H_tab, **S_Tab;\n",
 
 	"typedef struct Trail {",
-	"	short st;	/* current state */",
+	"	int   st;	/* current state */",
 	"	uchar pr;	/* process id */",
 	"	uchar tau;	/* 8 bit-flags */",
 	"	uchar o_pm;	/* 8 more bit-flags */",
@@ -126,10 +139,13 @@ static char *Preamble[] = {
 	"	o_pm&64 -> the current proc applied rule2",
 	"	o_pm&128 -> a fairness, dummy move - all procs blocked",
 	"#endif",
-	"#if defined(FULLSTACK) && defined(MA)",
+	"#if defined(FULLSTACK) && defined(MA) && !defined(BFS)",
 	"	uchar proviso;",
 	"#endif",
-	"	char  o_n, o_ot, o_m;	/* to save locals */",
+	"#ifndef BFS",
+	"	uchar  o_n, o_ot;	/* to save locals */",
+	"#endif",
+	"	uchar  o_m;",
 	"#ifdef EVENT_TRACE",
 		"#if nstates_event<256",
 	"	uchar o_event;",
@@ -137,17 +153,27 @@ static char *Preamble[] = {
 	"	unsigned short o_event;",
 		"#endif",
 	"#endif",
-	"	short o_tt, o_To;", /* used in new_state()  */
-	"#ifdef HAS_UNLESS",
-	"	short e_state;	/* if escape trans - state of origin */",
+	"	int o_tt;",
+	"#ifndef BFS",
+	"	short o_To;",
+		"#ifdef RANDOMIZE",
+	"	short oo_i;",
+		"#endif",
+	"#endif",
+	"#if defined(HAS_UNLESS) && !defined(BFS)",
+	"	int e_state;	/* if escape trans - state of origin */",
 	"#endif",
-	"#if defined(FULLSTACK) && !defined(MA)",
+	"#if (defined(FULLSTACK) && !defined(MA)) || defined(BFS)",
 	"	struct H_el *ostate;	/* pointer to stored state */",
 	"#endif",
-	"#ifdef CNTRSTACK",
+	/* CNTRSTACK when !NOREDUCE && BITSTATE && SAFETY, uses LL[] */
+	"#if defined(CNTRSTACK) && !defined(BFS)",
 	"	long	j6, j7;",
 	"#endif",
 	"	Trans *o_t;",	/* transition fct, next state   */
+	"#ifdef HAS_SORTED",
+	"	short ipt;",	/* insertion slot in q */
+	"#endif",
 	"	union {",
 	"		int oval;",	/* single backup value of variable */
 	"		int *ovals;",	/* ptr to multiple values */
@@ -158,18 +184,16 @@ static char *Preamble[] = {
 	"FILE	*efd;",
 	"uchar	*this;",
 	"long	maxdepth=10000;",
+	"long	omaxdepth=10000;",
 	"#ifdef SC",	/* stack cycling */
-	"long	omaxdepth;",
 	"char	*stackfile;",
  	"#endif",
 	"uchar	*SS, *LL;",
 	"uchar	HASH_NR = 0;",
 	"",
-	"#ifdef MEMCNT",
 	"double memcnt = (double) 0;",
-	"double overhead = (double) 0;",
 	"double memlim = (double) (1<<30);",
-	"#endif",
+	"",
 	"/* for emalloc: */",
 	"static char *have;",
 	"static long left = 0L;",
@@ -197,29 +221,34 @@ static char *Preamble[] = {
 	"	0x273d1aa5,	0x8923b1dd,",
 	"	0",
 	"};",
-	"int	mreached=0, done=0, errors=0, Nrun=1, single=0;",
+	"int	mreached=0, done=0, errors=0, Nrun=1;",
 	"double	nstates=0, nlinks=0, truncs=0, truncs2=0;",
 	"double	nlost=0, nShadow=0, hcmp=0, ngrabs=0;",
+	"#ifdef BFS",
+	"double midrv=0, failedrv=0, revrv=0;",
+	"#endif",
 	"unsigned long	nr_states=0; /* nodes in DFA */",
 	"long	Fa=0, Fh=0, Zh=0, Zn=0;",
 	"long	PUT=0, PROBE=0, ZAPS=0;",
 	"long	Ccheck=0, Cholds=0;",
-	"unsigned long mask;",
-	"int	a_cycles=0, upto=1, strict=0, verbose = 0;",
+	"int	a_cycles=0, upto=1, strict=0, verbose = 0, signoff = 0;",
+	"#ifdef HAS_CODE",
+	"int	gui = 0, coltrace = 0, readtrail = 0, whichtrail = 0, onlyproc = -1;",
+	"#endif",
 	"int	state_tables=0, fairness=0, no_rck=0, Nr_Trails=0;",
+	"char	simvals[128];",
 	"#ifndef INLINE",
 	"int	TstOnly=0;",
 	"#endif",
+	"unsigned long mask, nmask;",
 	"#ifdef BITSTATE",
-	"int	ssize=22;",
+	"int	ssize=23;	/* 1 Mb */",
 	"#else",
-	"int	ssize=18;",
+	"int	ssize=19;	/* 512K slots */",
 	"#endif",
 	"int	hmax=0, svmax=0, smax=0;",
 	"int	Maxbody=0, XX;",
 	"uchar	*noptr;	/* used by macro Pptr(x) */",
-	"State	A_Root;		/* root of acceptance cycles */",
-	"State	now;		/* the full state vector */",
 	"#ifdef VAR_RANGES",
 	"void logval(char *, int);",
 	"void dumpranges(void);",
@@ -228,27 +257,35 @@ static char *Preamble[] = {
 	"#ifdef MA",
 	"#define INLINE_REV",
 	"extern void dfa_init(unsigned short);",
-	"extern int  dfa_member(unsigned short);",
-	"extern int  dfa_store(unsigned char *);",
+	"extern int  dfa_member(unsigned long);",
+	"extern int  dfa_store(uchar *);",
 	"unsigned int	maxgs = 0;",
 	"#endif",
 
-	"#if !defined(NOCOMP) || defined(BITSTATE)",
 	"State	comp_now;	/* compressed state vector */",
 	"State	comp_msk;",
 	"uchar	*Mask = (uchar *) &comp_msk;",
-	"#endif",
 	"#ifdef COLLAPSE",
 	"State	comp_tmp;",
-	"char	*scratch = (char *) &comp_tmp;",
+	"static char	*scratch = (char *) &comp_tmp;",
 	"#endif",
 
 	"Stack	*stack; 	/* for queues, processes */",
 	"Svtack	*svtack;	/* for old state vectors */",
-	"long	J1, J2, J3, J4, j1, j2, j3, j4;",
-	"long	A_depth = 0, depth = 0;",
-	"uchar	warned = 0, iterative = 0, like_java = 0, every_error = 0;",
-	"uchar	noasserts = 0, noends = 0;",
+	"#ifdef BITSTATE",
+	"static unsigned hfns = 3;	/* new default */",
+	"#endif",
+	"static unsigned long j1;",
+	"static unsigned long K1, K2;",
+	"static unsigned long j2, j3, j4;",
+	"#ifdef BITSTATE",
+#ifndef POWOW
+	"static long udmem;",
+#endif
+	"#endif",
+	"static long	A_depth = 0, depth = 0;",
+	"static uchar	warned = 0, iterative = 0, like_java = 0, every_error = 0;",
+	"static uchar	noasserts = 0, noends = 0, bounded = 0;",
 	"#if SYNC>0 && ASYNC==0",
 	"void set_recvs(void);",
 	"int  no_recvs(int);",
@@ -260,6 +297,13 @@ static char *Preamble[] = {
 	"#define IfNotBlocked	/* cannot block */",
 	"#define UnBlock     	/* don't bother */",
 	"#endif\n",
+	"#ifdef BITSTATE",
+	"int (*bstore)(char *, int);",
+	"int bstore_reg(char *, int);",
+#ifndef POWOW
+	"int bstore_mod(char *, int);",
+#endif
+	"#endif",
 	"void active_procs(void);",
 	"void cleanup(void);",
 	"void do_the_search(void);",
@@ -267,10 +311,6 @@ static char *Preamble[] = {
 	"void iniglobals(void);",
 	"void stopped(int);",
 	"void wrapup(void);",
-#if 0
-	"void bup_q(int, int);",
-	"void unbup_q(int, int);",
-#endif
 	"int *grab_ints(int);",
 	"void ungrab_ints(int *, int);",
 	0,
@@ -344,45 +384,8 @@ static char *Tail[] = {
 	"	return 0;",
 	"}",
 	"#endif",
-/* new */
-	"uchar *visited;",
-	"void",
-	"dovisit(int n, int m, int is, uchar reach[])",
-	"{	Trans *z;",
-	"	if (is >= m || !trans[n][is]",
-	"	||  is <= 0 || visited[is])",
-	"		return;",
-	"	visited[is] = 1;",
-	"	for (z = trans[n][is]; z; z = z->nxt)",
-	"	{	int i, j;",
-	"		dovisit(n, m, z->st, reach);",
-	"#ifdef HAS_UNLESS",
-	"		for (i = 0; i < HAS_UNLESS; i++)",
-	"		{	j = trans[n][is]->escp[i];",
-	"			if (!j) break;",
-	"			dovisit(n, m, j, reach);",
-	"		}",
-	"#endif",
-	"	}",
-	"}",
-	"void",
-	"check_unreachable(int n, int m, int is, short srcln[], uchar reach[])",
-	"{	int i; static int oldm=0;",
-	"	if (m > oldm)	/* not much memory */",
-	"	{	visited = (uchar *) emalloc(m * sizeof(uchar));",
-	"		oldm = m;",
-	"	} else",
-	"		memset(visited, 0, m);",
-	"	dovisit(n, m, is, reach);",
-	"	for (i = 1; i < m; i++)",
-	"		if (!visited[i] && reach[i] == 0)",
-	"		{	if (0) printf(\"%%s: merged state %%d, line %%d\\n\",",
-	"				procname[n], i, srcln[i]);",
-	"			reach[i] = 1;",
-	"		}",
-	"}",
-
 	"int cnt;",
+	"#ifdef HAS_UNLESS",
 	"int",
 	"isthere(Trans *a, int b)", /* is b already in a's list? */
 	"{	Trans *t;",
@@ -391,10 +394,11 @@ static char *Tail[] = {
 	"			return 1;",
 	"	return 0;",
 	"}",
+	"#endif",
 	"#ifndef NOREDUCE",
 	"int",
 	"mark_safety(Trans *t) /* for conditional safety */",
-	"{	int g = 0, h, i, j, k;",
+	"{	int g = 0, i, j, k;",
 	"",
 	"	if (!t) return 0;",
 	"	if (t->qu[0])",
@@ -402,7 +406,7 @@ static char *Tail[] = {
 	"",
 	"	for (i = 0; i < 2; i++)",
 	"	{	j = srinc_set(t->tpe[i]);",
-	"		if (j >= GLOBAL)",
+	"		if (j >= GLOBAL && j != ALPHA_F)",
 	"			return -1;",
 	"		if (j != LOCAL)",
 	"		{	k = srunc(t->tpe[i], j);",
@@ -420,7 +424,13 @@ static char *Tail[] = {
 	"retrans(int n, int m, int is, short srcln[], uchar reach[])",
 	"	/* process n, with m states, is=initial state */",
 	"{	Trans *T0, *T1, *T2, *T3;",
-	"	int i, j, k, p, h, g, aa;",
+	"	int i, k;",
+	"#ifndef NOREDUCE",
+	"	int g, h, j, aa;",
+	"#endif",
+	"#ifdef HAS_UNLESS",
+	"	int p;",
+	"#endif",
 	"	if (state_tables >= 4)",
 	"	{	printf(\"STEP 1 proctype %%s\\n\", ",
 	"			procname[n]);",
@@ -449,13 +459,13 @@ static char *Tail[] = {
 	"				if (!T3->nxt)",
 	"				{	T2->nxt = cpytr(T0);",
 	"					T2 = T2->nxt;",
-	"					imed(T2, T0->st, n);",
+	"					imed(T2, T0->st, n, i);",
 	"					continue;",
 	"				}",
 	"				do {	T3 = T3->nxt;",
 	"					T2->nxt = cpytr(T3);",
 	"					T2 = T2->nxt;",
-	"					imed(T2, T0->st, n);",
+	"					imed(T2, T0->st, n, i);",
 	"				} while (T3->nxt);",
 	"				cnt++;",
 	"			}",
@@ -481,7 +491,7 @@ static char *Tail[] = {
 	"			T0 = cpytr(trans[n][T1->st]);",
 	"			trans[n][i] = T0;",
 	"			reach[T1->st] = 1;",
-	"			imed(T0, T1->st, n);",
+	"			imed(T0, T1->st, n, i);",
 	"			for (T1 = T1->nxt; T1; T1 = T1->nxt)",
 	"			{",
 	"#if 0",
@@ -492,7 +502,7 @@ static char *Tail[] = {
 	"				T0->nxt = cpytr(trans[n][T1->st]);",
 	"				T0 = T0->nxt;",
 	"				reach[T1->st] = 1;",
-	"				imed(T0, T1->st, n);",
+	"				imed(T0, T1->st, n, i);",
 	"	}	}	}",
 	"	if (state_tables >= 2)",
 	"	{	printf(\"STEP 3 proctype %%s\\n\", ",
@@ -576,8 +586,8 @@ static char *Tail[] = {
 	"			{	if (!(T0->atom&8))",
 	"					goto degrade;",
 	"				for (aa = 0; aa < 2; aa++)",
-	"				{	if (srinc_set(T0->tpe[aa])",
-	"					>=  GLOBAL)",
+	"				{	j = srinc_set(T0->tpe[aa]);",
+	"					if (j >= GLOBAL && j != ALPHA_F)",
 	"						goto degrade;",
 	"					if (T0->tpe[aa]",
 	"					&&  T0->tpe[aa]",
@@ -602,13 +612,11 @@ static char *Tail[] = {
 	"			}	}	}",
 	"			if (g > 6)",
 	"			{	T1->qu[0] = 0;	/* turn it off */",
-	"#if 1",
 	"				printf(\"pan: warning, line %%d, \",",
 	"					srcln[i]);",
 	"			 	printf(\"too many stmnt types (%%d)\",",
 	"					g);",
 	"			  	printf(\" in selection\\n\");",
-	"#endif",
 	"			  goto degrade;",
 	"			}",
 	"		}",
@@ -628,27 +636,21 @@ static char *Tail[] = {
 	"		j = T1->tpe[0];",
 	"		if (T1->nxt && T1->atom&8)",
 	"		{ if (j == 5*DELTA)",
-	"		  {",
-	"#if 1",
-	"			printf(\"warning: line %%d \", srcln[i]);",
+	"		  {	printf(\"warning: line %%d \", srcln[i]);",
 	"			printf(\"mixed condition \");",
 	"			printf(\"(defeats reduction)\\n\");",
-	"#endif",
 	"			goto degrade;",
 	"		  }",
 	"		  for (T0 = T1; T0; T0 = T0->nxt)",
 	"		  for (aa = 0; aa < 2; aa++)",
 	"		  if  (T0->tpe[aa] && T0->tpe[aa] != j)",
-	"		  {",
-	"#if 1",
-	"			printf(\"warning: line %%d \", srcln[i]);",
+	"		  {	printf(\"warning: line %%d \", srcln[i]);",
 	"			printf(\"[%%d-%%d] mixed %%stion \",",
 	"				T0->tpe[aa], j, ",
 	"				(j==5*DELTA)?\"condi\":\"selec\");",
 	"			printf(\"(defeats reduction)\\n\");",
 	"			printf(\"	'%%s' <-> '%%s'\\n\",",
 	"				T1->tp, T0->tp);",
-	"#endif",
 	"			goto degrade;",
 	"		} }",
 	"	}",
@@ -683,7 +685,7 @@ static char *Tail[] = {
 	"		  		printf(\"line %%d, state %%d: has un\",",
 	"					srcln[i], i);",
 	"				printf(\"conditional self-loop\\n\");",
-	"				exit(1);",
+	"				pan_exit(1);",
 	"		}	}",
 	"		nrelse = 0;",
 	"		for (T0 = trans[n][i]; T0; T0 = T0->nxt)",
@@ -695,16 +697,16 @@ static char *Tail[] = {
 	"				procname[n]);",
 	"		  	printf(\" %%d, inherits %%d\", i, nrelse);",
 	"		  	printf(\" 'else' stmnts\\n\");",
-	"			exit(1);",
+	"			pan_exit(1);",
 	"	}	}",
-	"	check_unreachable(n, m, is, srcln, reach);",
-	"}\n",
+	"}",
 	"void",
-	"imed(Trans *T, int v, int n)	/* set intermediate state */",
+	"imed(Trans *T, int v, int n, int j)	/* set intermediate state */",
 	"{	progstate[n][T->st] |= progstate[n][v];",
 	"	accpstate[n][T->st] |= accpstate[n][v];",
 	"	stopstate[n][T->st] |= stopstate[n][v];",
-	"}\n",
+	"	mapstate[n][j] = T->st;",
+	"}",
 	"void",
 	"tagtable(int n, int m, int is, short srcln[], uchar reach[])",
 	"{	Trans *z;\n",
@@ -716,7 +718,10 @@ static char *Tail[] = {
 	"	for (z = trans[n][is]; z; z = z->nxt)",
 	"		crack(n, is, z, srcln);",
 	"	for (z = trans[n][is]; z; z = z->nxt)",
-	"	{	int i, j;",
+	"	{",
+	"#ifdef HAS_UNLESS",
+	"		int i, j;",
+	"#endif",
 	"		tagtable(n, m, z->st, srcln, reach);",
 	"#ifdef HAS_UNLESS",
 	"		for (i = 0; i < HAS_UNLESS; i++)",
@@ -726,7 +731,7 @@ static char *Tail[] = {
 	"		}",
 	"#endif",
 	"	}",
-	"}\n",
+	"}",
 	"void",
 	"crack(int n, int j, Trans *z, short srcln[])",
 	"{	int i;\n",
@@ -757,9 +762,6 @@ static char *Tail[] = {
 	"			printf(\"\\\\n\");",
 	"		else",
 	"			putchar(z->tp[i]);",
-	"#if 0",
-	"	printf(\"\\n\");",
-	"#else",
 	"	if (z->qu[0])",
 	"	{	printf(\"\\t[\");",
 	"		for (i = 0; i < 6; i++)",
@@ -769,7 +771,6 @@ static char *Tail[] = {
 	"		printf(\"]\");",
 	"	}",
 	"	printf(\"\\n\");",
-	"#endif",
 	"	fflush(stdout);",
 	"}",
 	"",
@@ -778,7 +779,7 @@ static char *Tail[] = {
 	"",
 	"typedef struct Vr_Ptr {",
 	"	char	*nm;",
-	"	unsigned char vals[BYTESIZE];",
+	"	uchar	vals[BYTESIZE];",
 	"	struct Vr_Ptr *nxt;",
 	"} Vr_Ptr;",
 	"Vr_Ptr *ranges = (Vr_Ptr *) 0;",
@@ -800,7 +801,7 @@ static char *Tail[] = {
 	"}",
 	"",
 	"void",
-	"dumpval(unsigned char X[], int range)",
+	"dumpval(uchar X[], int range)",
 	"{	int w, x, i, j = -1;",
 	"",
 	"	for (w = i = 0; w < range; w++)",

+ 22 - 18
sys/src/cmd/spin/pangen3.c

@@ -1,14 +1,13 @@
 /***** spin: pangen3.c *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 #include "spin.h"
 #ifdef PC
@@ -109,7 +108,7 @@ putsrc(Element *e)	/* match states to source lines */
 		if (tmp->st == m)
 		{	if (tmp->ln != n || tmp->fn != e->n->fn)
 			printf("putsrc mismatch %d - %d, file %s\n", n,
-				tmp->ln, tmp->fn);
+				tmp->ln, tmp->fn->name);
 			return;
 		}
 	tmp = (SRC *) emalloc(sizeof(SRC));
@@ -160,12 +159,6 @@ dumpsrc(int n, int m)
 		for (tmp = frst; tmp; lst = tmp, tmp = tmp->nxt)
 			if (tmp->st == j)
 			{	putnr(tmp->ln);
-#if 0
-				if (lst)
-					lst->nxt = tmp->nxt;
-				else
-					frst = tmp->nxt;
-#endif
 				break;
 			}
 		if (!tmp)
@@ -321,9 +314,13 @@ comwork(FILE *fd, Lextok *now, int m)
 	case 'c':	Cat3("(", now->lft, ")");
 			break;
 
-	case '?':	Cat3("( (", now->lft, ") -> ");
-			Cat3("(", now->rgt->lft, ") : ");
-			Cat3("(", now->rgt->rgt, ") )");
+	case '?':	if (now->lft)
+			{	Cat3("( (", now->lft, ") -> ");
+			}
+			if (now->rgt)
+			{	Cat3("(", now->rgt->lft, ") : ");
+				Cat3("(", now->rgt->rgt, ") )");
+			}
 			break;	
 
 	case ASGN:	comwork(fd,now->lft,m);
@@ -351,12 +348,19 @@ comwork(FILE *fd, Lextok *now, int m)
 			}
 			fprintf(fd, ")");
 			break;
+	case PRINTM:	fprintf(fd, "printm(");
+			comwork(fd, now->lft, m);
+			fprintf(fd, ")");
+			break;
 	case NAME:	putname(fd, "", now, m, "");
 			break;
 	case   'p':	putremote(fd, now, m);
 			break;
 	case   'q':	fprintf(fd, "%s", now->sym->name);
 			break;
+	case C_EXPR:	
+	case C_CODE:	fprintf(fd, "{%s}", now->sym->name);
+			break;
 	case ASSERT:	Cat3("assert(", now->lft, ")");
 			break;
 	case   '.':	fprintf(fd, ".(goto)"); break;

+ 106 - 85
sys/src/cmd/spin/pangen3.h

@@ -1,16 +1,18 @@
 /***** spin: pangen3.h *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 static char *Head0[] = {
+	"#if defined(BFS) && defined(REACH)",
+	"#undef REACH",	/* redundant with bfs */
+	"#endif",
 	"#ifdef VERI",
 		"#define BASE	1",
 	"#else",
@@ -18,7 +20,6 @@ static char *Head0[] = {
 	"#endif",
 	"typedef struct Trans {",
 	"	short atom;	/* if &2 = atomic trans; if &8 local */",
-	"	short st;	/* the nextstate */",
 	"#ifdef HAS_UNLESS",
 	"	short escp[HAS_UNLESS];	/* lists the escape states */",
 	"	short e_trans;	/* if set, this is an escp-trans */",
@@ -30,6 +31,7 @@ static char *Head0[] = {
 	"	short om;	/* completion status of preselects */",
 	"#endif",
 	"	char *tp;	/* src txt of statement */",
+	"	int st;		/* the nextstate */",
 	"	int t_id;	/* transition id, unique within proc */",
 	"	int forw;	/* index forward transition */",
 	"	int back;	/* index return  transition */",
@@ -49,8 +51,12 @@ static char *Head0[] = {
 
 static char *Header[] = {
 	"#ifdef VERBOSE",
+		"#ifndef CHECK",
 		"#define CHECK",
+		"#endif",
+		"#ifndef DEBUG",
 		"#define DEBUG",
+		"#endif",
 	"#endif",
 	"#ifdef SAFETY",
 		"#ifndef NOFAIR",
@@ -58,7 +64,9 @@ static char *Header[] = {
 		"#endif",
 	"#endif",
 	"#ifdef NOREDUCE",
+		"#ifndef XUSAFE",
 		"#define XUSAFE",
+		"#endif",
 		"#if !defined(SAFETY) && !defined(MA)",
 			"#define FULLSTACK",
 		"#endif",
@@ -74,25 +82,20 @@ static char *Header[] = {
 		"#endif",
 	"#endif",
 	"#ifdef BITSTATE",
+		"#ifndef NOCOMP",
 		"#define NOCOMP",
+		"#endif",
 		"#if !defined(LC) && defined(SC)",
 		"#define LC",
 		"#endif",
 	"#endif",
-	"#ifndef MEMCNT",
-		"#ifdef PC",
-		"#define MEMCNT	25	/* 32 Mb */",
-		"#else",
-		"#define MEMCNT	28",
-		"#endif",
-	"#endif",
-
 	"#if defined(COLLAPSE2) || defined(COLLAPSE3) || defined(COLLAPSE4)",
 		"/* accept the above for backward compatibility */",
 		"#define COLLAPSE",
 	"#endif",
 	"#ifdef HC",
-	"#define HC2",
+	"#undef HC",
+	"#define HC4",
 	"#endif",
 	"#ifdef HC0",	/* 32 bits */
 	"#define HC	0",
@@ -147,12 +150,16 @@ static char *Header[] = {
 	"#if SYNC",
 	"	short o_boq;",
 	"#endif",
+	0,
+};
+
+static char *Header0[] = {
 	"	char *body;",
 	"	struct Svtack *nxt;",
 	"	struct Svtack *lst;",
 	"} Svtack;\n",
 	"Trans ***trans;	/* 1 ptr per state per proctype */\n",
-	"#if defined(FULLSTACK)",
+	"#if defined(FULLSTACK) || defined(BFS)",
 	"struct H_el *Lstate;",
 	"#endif",
 	"int depthfound = -1;	/* loop detection */",
@@ -216,7 +223,10 @@ static char *Head1[] = {
 
 static char *Addp0[] = {
 	/* addproc(....parlist... */ ")",
-	"{	int k, j, h = now._nr_pr;",
+	"{	int j, h = now._nr_pr;",
+	"#ifndef NOCOMP",
+	"	int k;",
+	"#endif",
 	"	uchar *o_this = this;\n",
 	"#ifndef INLINE",
 	"	if (TstOnly) return (h < MAXPROC);",
@@ -258,12 +268,12 @@ static char *Addp1[] = {
 	"#endif",
 	"	now._nr_pr += 1;",
 	"	if (fairness && ((int) now._nr_pr + 1 >= (8*NFAIR)/2))",
-	"	{	printf(\"Error: too many processes -- current\");",
+	"	{	printf(\"pan: error: too many processes -- current\");",
 	"		printf(\" max is %%d procs (-DNFAIR=%%d)\\n\",",
 	"			(8*NFAIR)/2 - 2, NFAIR);",
 	"		printf(\"\\trecompile with -DNFAIR=%%d\\n\",",
 	"			NFAIR+1);",
-	"		exit(1);",
+	"		pan_exit(1);",
 	"	}",
 
 	"	vsize += j;",
@@ -294,7 +304,10 @@ static char *Addp1[] = {
 static char *Addq0[] = {
 	"int",
 	"addqueue(int n, int is_rv)",
-	"{	int j=0, i = now._nr_qs, k;\n",
+	"{	int j=0, i = now._nr_qs;",
+	"#ifndef NOCOMP",
+	"	int k;",
+	"#endif",
 	"	if (i >= MAXQ)",
 	"		Uerror(\"too many queues\");",
 	"	switch (n) {",
@@ -309,9 +322,12 @@ static char *Addq1[] = {
 	"	else",
 	"		q_skip[i] = 0;",
 	"#ifndef NOCOMP",
-	"	k = vsize; if (is_rv) k += j;",
+	"	k = vsize;",
+	"#ifndef BFS",
+	"	if (is_rv) k += j;",
+	"#endif",
 	"	for (k += q_skip[i]; k > vsize; k--)",
-	"		Mask[k-1] = 1; /* align */",
+	"		Mask[k-1] = 1;",
 	"#endif",
 	"	vsize += q_skip[i];",
 	"	q_offset[i] = vsize;",
@@ -331,7 +347,10 @@ static char *Addq1[] = {
 };
 
 static char *Addq11[] = {
-	"{	int j, k; uchar *z;\n",
+	"{	int j; uchar *z;\n",
+	"#ifdef HAS_SORTED",
+	"	int k;",
+	"#endif",
 	"	if (!into--)",
 	"	uerror(\"ref to uninitialized chan name (sending)\");",
 	"	if (into >= (int) now._nr_qs || into < 0)",
@@ -350,12 +369,15 @@ static char *Addq2[] = {
 	"	if (in_s_scope(into+1))",
 	"		require('s', into);",
 	"#endif",
-	"}\n",
+	"}",
+	"#endif\n",
 	"#if SYNC",
 	"int",
 	"q_zero(int from)",
 	"{	if (!from--)",
-	"	uerror(\"ref to uninitialized chan name (q_zero)\");",
+	"	{	uerror(\"ref to uninitialized chan name (q_zero)\");",
+	"		return 0;",
+	"	}",
 	"	switch(((Q0 *)qptr(from))->_t) {",
 	0,
 };
@@ -364,6 +386,7 @@ static char *Addq3[] = {
 	"	case 0: printf(\"queue %%d was deleted\\n\", from+1);",
 	"	}",
 	"	Uerror(\"bad queue q-zero\");",
+	"	return -1;",
 	"}",
 	"int",
 	"not_RV(int from)",
@@ -407,8 +430,10 @@ static char *Addq3[] = {
 	"	{	printf(\"pan: xs assertion violated: \");",
 	"		printf(\"access to chan <%%s> (%%d)\\npan: by \",",
 	"			q_name[x], x-1);",
-	"		printf(\"%%s (proc %%d) and by %%s (proc %%d)\\n\",",
-	"			p_name[q_sender[x]-1], q_sender[x]-1,",
+	"		if (q_sender[x] > 0 && p_name[q_sender[x]-1])",
+	"			printf(\"%%s (proc %%d) and by \",",
+	"			p_name[q_sender[x]-1], q_sender[x]-1);",
+	"		printf(\"%%s (proc %%d)\\n\",",
 	"			p_name[who], who);",
 	"		uerror(\"error, partial order reduction invalid\");",
 	"	}",
@@ -431,11 +456,12 @@ static char *Addq3[] = {
 	"	} else",
 	"	if (q_recver[x] != who+1)",
 	"	{	printf(\"pan: xr assertion violated: \");",
-	"		printf(\"access to chan %%s (%%d)\\n\",",
+	"		printf(\"access to chan %%s (%%d)\\npan: \",",
 	"			q_name[x], x-1);",
-	"		printf(\"pan: by %%s (proc %%d) \",",
+	"		if (q_recver[x] > 0 && p_name[q_recver[x]-1])",
+	"			printf(\"by %%s (proc %%d) and \",",
 	"			p_name[q_recver[x]-1], q_recver[x]-1);",
-	"		printf(\"and by %%s (proc %%d)\\n\",",
+	"		printf(\"by %%s (proc %%d)\\n\",",
 	"			p_name[who], who);",
 	"		uerror(\"error, partial order reduction invalid\");",
 	"	}",
@@ -469,6 +495,7 @@ static char *Addq4[] = {
 	"	return !q_len(from) || q_full(from);",
 	"}",
 	"#endif",
+	"#if NQS>0",
 	"int",
 	"qrecv(int from, int slot, int fld, int done)",
 	"{	uchar *z;",
@@ -491,12 +518,13 @@ static char *Addq5[] = {
 	"	default: Uerror(\"bad queue - qrecv\");",
 	"	}",
 	"	return r;",
-	"}\n",
+	"}",
+	"#endif\n",
 	"#ifndef BITSTATE",
 	"#ifdef COLLAPSE",
 	"long",
 	"col_q(int i, char *z)",
-	"{	int j, k;",
+	"{	int j=0, k;",
 	"	char *x, *y;",
 	"	Q0 *ptr = (Q0 *) qptr(i);",
 	"	switch (ptr->_t) {",
@@ -506,7 +534,7 @@ static char *Addq5[] = {
 static char *Code0[] = {
 	"void",
 	"run(void)",
-	"{	int i;",
+	"{	/* int i; */",
 	"	memset((char *)&now, 0, sizeof(State));",
 	"	vsize = sizeof(State) - VECTORSZ;",
 	"#ifndef NOVSZ",
@@ -528,6 +556,10 @@ static char *R0[] = {
 	"	progstate[%d] = (uchar *) emalloc(nstates%d);",
 	"	stopstate[%d] = (uchar *) emalloc(nstates%d);",
 	"	visstate[%d] = (uchar *) emalloc(nstates%d);",
+	"	mapstate[%d] = (short *) emalloc(nstates%d * sizeof(short));",
+	"#ifdef HAS_CODE",
+	"	NrStates[%d] = nstates%d;",
+	"#endif",
 	"	stopstate[%d][endstate%d] = 1;",
 	0,
 };
@@ -547,7 +579,7 @@ static char *R0b[] = {
 	"	  printf(\"      stmnt executed in each merge sequence is shown\\n\");",
 	"	  printf(\"      (use spin -a -o3 to disable statement merging)\\n\");",
 	"#endif",
-	"	  exit(0);",
+	"	  pan_exit(0);",
 	"	}",
 	0,
 };
@@ -572,6 +604,10 @@ static char *R2[] = {
 	"uchar *reached[%d];",
 	"uchar *stopstate[%d];",
 	"uchar *visstate[%d];",
+	"short *mapstate[%d];",
+	"#ifdef HAS_CODE",
+	"int NrStates[%d];",
+	"#endif",
 	0,
 };
 static char *R3[] = {
@@ -619,13 +655,12 @@ static char *R8a[] = {
 
 	"	for ( ; j > 0; j--, y++)",
 	"		if (!Mask[k++]) *x++ = *y;",
-	"	if (z) return (long) (x - z);",
 
 	"	for (j = 0; j < WS-1; j++)",
 	"		*x++ = 0;",
 	"	x -= j;",
-
-	"	return ordinal(scratch, x-scratch, 2+ptr->_t);",
+	"	if (z) return (long) (x - z);",
+	"	return ordinal(scratch, x-scratch, (short) (2+ptr->_t));",
 	"}",
 	"#endif",
 	"#endif",
@@ -642,30 +677,18 @@ static char *R8b[] = {
 
 	"	for ( ; j > 0; j--, y++)",
 	"		if (!Mask[k++]) *x++ = *y;",
-	"	if (z) return (long) (x - z);",
 
 	"	for (j = 0; j < WS-1; j++)",
 	"		*x++ = 0;",
 	"	x -= j;",
+	"	if (z) return (long) (x - z);",
 	"	return ordinal(scratch, x-scratch, 1); /* chan */",
 	"}",
 	"#endif",
 	"#endif",
 	0,
 };
-static char *R9[] = {
-	"typedef struct Q%d {",
-	"	uchar Qlen;	/* q_size */",
-	"	uchar _t;	/* q_type */",
-	"	struct {",
-	0,
-};
-static char *R10[] = {
-	"typedef struct Q0 {\t/* generic q */",
-	"	uchar Qlen, _t;",
-	"} Q0;",
-	0,
-};
+
 static char *R12[] = {
 	"\t\tcase %d: r = ((Q%d *)z)->contents[slot].fld%d; break;",
 	0,
@@ -673,7 +696,10 @@ static char *R12[] = {
 char *R13[] = {
 	"int ",
 	"unsend(int into)",
-	"{	int m=0, j, k; uchar *z;\n",
+	"{	int _m=0, j; uchar *z;\n",
+	"#ifdef HAS_SORTED",
+	"	int k;",
+	"#endif",
 	"	if (!into--)",
 	"		uerror(\"ref to uninitialized chan (unsend)\");",
 	"	z = qptr(into);",
@@ -685,7 +711,7 @@ char *R13[] = {
 char *R14[] = {
 	"	default: Uerror(\"bad queue - unsend\");",
 	"	}",
-	"	return m;",
+	"	return _m;",
 	"}\n",
 	"void",
 	"unrecv(int from, int slot, int fld, int fldvar, int strt)",
@@ -714,13 +740,13 @@ static char *Proto[] = {
 	"int addqueue(int, int);",
 	"/* int atoi(char *); */",
 	"int close(int);",
-#ifndef PC
+"#ifndef SC",
 	"int creat(char *, unsigned short);",
 	"int write(int, void *, unsigned);",
-#endif
+"#endif",
 	"int delproc(int, int);",
 	"int endstate(void);",
-	"int hstore(char *, int, short);",
+	"int hstore(char *, int);",
 "#ifdef MA",
 	"int gstore(char *, int, uchar);",
 "#endif",
@@ -730,17 +756,23 @@ static char *Proto[] = {
 	"int q_zero(int);",
 	"int qrecv(int, int, int, int);",
 	"int unsend(int);",
-	"void *sbrk(int);",
+	"/* void *sbrk(int); */",
 	"void Uerror(char *);",
 	"void assert(int, char *, int, int, Trans *);",
+	"void c_chandump(int);",
+	"void c_globals(void);",
+	"void c_locals(int, int);",
 	"void checkcycles(void);",
 	"void crack(int, int, Trans *, short *);",
 	"void d_hash(uchar *, int);",
+	"void s_hash(uchar *, int);",
+	"void r_hash(uchar *, int);",
 	"void delq(int);",
 	"void do_reach(void);",
+	"void pan_exit(int);",
 	"void exit(int);",
 	"void hinit(void);",
-	"void imed(Trans *, int, int);",
+	"void imed(Trans *, int, int, int);",
 	"void new_state(void);",
 	"void p_restor(int);",
 	"void putpeg(int, int);",
@@ -750,13 +782,12 @@ static char *Proto[] = {
 	"void settable(void);",
 	"void setq_claim(int, int, char *, int, char *);",
 	"void sv_restor(void);",
-	"void sv_save(char *);",
+	"void sv_save(void);",
 	"void tagtable(int, int, int, short *, uchar *);",
 	"void uerror(char *);",
 	"void unrecv(int, int, int, int, int);",
 	"void usage(FILE *);",
 	"void wrap_stats(void);",
-	"void xrefsrc(int, S_F_MAP *, int, int);",
 	"#if defined(FULLSTACK) && defined(BITSTATE)",
 	"int  onstack_now(void);",
 	"void onstack_init(void);",
@@ -776,32 +807,23 @@ static char *Proto[] = {
 static char *SvMap[] = {
 	"void",
 	"to_compile(void)",
-	"{	char ctd[1024], carg[64]; int n;",
+	"{	char ctd[1024], carg[64];",
 	"#ifdef BITSTATE",
 	"	strcpy(ctd, \"-DBITSTATE \");",
 	"#else",
 	"	strcpy(ctd, \"\");",
 	"#endif",
-	"#ifdef PC",
-	"	strcat(ctd, \"-DPC \");",
-	"#endif",
 	"#ifdef NOVSZ",
 	"	strcat(ctd, \"-DNOVSZ \");",
 	"#endif",
-	"#ifdef MEMCNT",
-		"#ifdef PC",
-		"	n = 25;",
-		"#else",
-		"	n = 28;",
-		"#endif",
-	"	if (MEMCNT != n)",
-	"	{	sprintf(carg, \"-DMEMCNT=%%d \", MEMCNT);",
-	"		strcat(ctd, carg);",
-	"	}",
-	"#endif",
 	"#ifdef MEMLIM",
 	"	sprintf(carg, \"-DMEMLIM=%%d \", MEMLIM);",
 	"	strcat(ctd, carg);",
+	"#else",
+	"#ifdef MEMCNT",
+	"	sprintf(carg, \"-DMEMCNT=%%d \", MEMCNT);",
+	"	strcat(ctd, carg);",
+	"#endif",
 	"#endif",
 	"#ifdef NOCLAIM",
 	"	strcat(ctd, \"-DNOCLAIM \");",
@@ -878,6 +900,10 @@ static char *SvMap[] = {
 	"#ifdef COLLAPSE",
 	"	strcat(ctd, \"-DCOLLAPSE \");",
 	"#endif",
+	"#ifdef MA",
+	"	sprintf(carg, \"-DMA=%%d \", MA);",
+	"	strcat(ctd, carg);",
+	"#endif",
 	"#ifdef SVDUMP",
 	"	strcat(ctd, \"-DSVDUMP \");",
 	"#endif",
@@ -897,14 +923,9 @@ static char *SvMap[] = {
 	"	strcat(ctd, \"-DSDUMP \");",
 	"#endif",
 	"#ifdef COVEST",
-	"		strcat(ctd, \"-DCOVEST \");",
-	"#endif",
-	"		printf(\"Compiled as: cc -o pan %%span.c\", ctd);",
-	"#if defined(COVEST) && defined(BITSTATE)",
-	"		printf(\" -lm\\n\");",
-	"#else",
-	"		printf(\"\\n\");",
+	"	strcat(ctd, \"-DCOVEST \");",
 	"#endif",
+	"	printf(\"Compiled as: cc -o pan %%span.c\\n\", ctd);",
 	"}",
 	0,
 };

+ 42 - 37
sys/src/cmd/spin/pangen4.c

@@ -1,14 +1,13 @@
 /***** spin: pangen4.c *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 #include "spin.h"
 #ifdef PC
@@ -18,16 +17,13 @@
 #endif
 
 extern FILE	*tc, *tb;
-extern ProcList	*cur_proc;
 extern Queue	*qtab;
 extern Symbol	*Fname;
-extern int	lineno, m_loss, Pid, eventmapnr, verbose, multi_oval;
-extern short	terse, nocast, has_provided, has_sorted;
-extern short	evalindex, withprocname, _isok;
+extern int	lineno, m_loss, Pid, eventmapnr, multi_oval;
+extern short	nocast, has_provided, has_sorted;
 extern char	*R13[], *R14[], *R15[];
 
 static void	check_proc(Lextok *, int);
-extern int	dolocal(FILE *, char *, int, int, char *, char *);
 
 void
 undostmnt(Lextok *now, int m)
@@ -52,9 +48,10 @@ undostmnt(Lextok *now, int m)
 	case FULL:	case EMPTY:	case 'R':
 	case NFULL:	case NEMPTY:	case ENABLED:
 	case '?':	case PC_VAL:	case '^':
+	case C_EXPR:
 	case NONPROGRESS:
-			putstmnt(tb, now, m);
-			break;
+		putstmnt(tb, now, m);
+		break;
 
 	case RUN:
 		fprintf(tb, "delproc(0, now._nr_pr-1)");
@@ -64,12 +61,8 @@ undostmnt(Lextok *now, int m)
 		if (Pid == eventmapnr) break;
 
 		if (m_loss)
-		{	fprintf(tb, "if (m == 2) m = unsend");
-			putname(tb, "(", now->lft, m, ")");
-		} else
-		{	fprintf(tb, "m = unsend");
-			putname(tb, "(", now->lft, m, ")");
-		}
+			fprintf(tb, "if (_m == 2) ");
+		putname(tb, "_m = unsend(", now->lft, m, ")");
 		break;
 
 	case 'r':
@@ -133,8 +126,11 @@ undostmnt(Lextok *now, int m)
 						jj++;
 					break;
 			}	}
-
 			jj = multi_oval - ii - 1;
+
+			if (now->val == 1 && multi_oval > 0)
+				jj++;	/* new 3.4.0 */
+
 			for (v = now->rgt, i = 0; v; v = v->rgt, i++)
 			{	switch(v->lft->ntyp) {
 				case CONST:
@@ -181,10 +177,16 @@ undostmnt(Lextok *now, int m)
 	case BREAK:
 		break;
 
+	case C_CODE:
+		fprintf(tb, "sv_restor();\n");
+		break;
+
 	case ASSERT:
 	case PRINT:
 		check_proc(now, m);
 		break;
+	case PRINTM:
+		break;
 
 	default:
 		printf("spin: bad node type %d (.b)\n", now->ntyp);
@@ -201,6 +203,7 @@ any_undo(Lextok *now)
 	case ASSERT:
 	case PRINT:	return any_oper(now, RUN);
 
+	case PRINTM:
 	case   '.':
 	case  GOTO:
 	case  ELSE:
@@ -240,29 +243,31 @@ genunio(void)
 	for (q = qtab; q; q = q->nxt)
 	{	fprintf(tc, "\tcase %d:\n", q->qid);
 
-	if (has_sorted)
-	{	sprintf(buf1, "((Q%d *)z)->contents", q->qid);
-		fprintf(tc, "\t\tj = trpt->bup.oval;\n");
-		fprintf(tc, "\t\tfor (k = j; k < ((Q%d *)z)->Qlen; k++)\n",
-			q->qid);
-		fprintf(tc, "\t\t{\n");
-		for (i = 0; i < q->nflds; i++)
-		fprintf(tc, "\t\t\t%s[k].fld%d = %s[k+1].fld%d;\n",
-			buf1, i, buf1, i);
-		fprintf(tc, "\t\t}\n");
-		fprintf(tc, "\t\tj = ((Q0 *)z)->Qlen;\n");
-	}
+		if (has_sorted)
+		{	sprintf(buf1, "((Q%d *)z)->contents", q->qid);
+			fprintf(tc, "#ifdef HAS_SORTED\n");
+			fprintf(tc, "\t\tj = trpt->ipt;\n");	/* ipt was bup.oval */
+			fprintf(tc, "#endif\n");
+			fprintf(tc, "\t\tfor (k = j; k < ((Q%d *)z)->Qlen; k++)\n",
+				q->qid);
+			fprintf(tc, "\t\t{\n");
+			for (i = 0; i < q->nflds; i++)
+			fprintf(tc, "\t\t\t%s[k].fld%d = %s[k+1].fld%d;\n",
+				buf1, i, buf1, i);
+			fprintf(tc, "\t\t}\n");
+			fprintf(tc, "\t\tj = ((Q0 *)z)->Qlen;\n");
+		}
 
 		sprintf(buf1, "((Q%d *)z)->contents[j].fld", q->qid);
 		for (i = 0; i < q->nflds; i++)
 			fprintf(tc, "\t\t%s%d = 0;\n", buf1, i);
 		if (q->nslots==0)
 		{	/* check if rendezvous succeeded, 1 level down */
-			fprintf(tc, "\t\tm = (trpt+1)->o_m;\n");
-			fprintf(tc, "\t\tif (m) (trpt-1)->o_pm |= 1;\n");
+			fprintf(tc, "\t\t_m = (trpt+1)->o_m;\n");
+			fprintf(tc, "\t\tif (_m) (trpt-1)->o_pm |= 1;\n");
 			fprintf(tc, "\t\tUnBlock;\n");
 		} else
-			fprintf(tc, "\t\tm = trpt->o_m;\n");
+			fprintf(tc, "\t\t_m = trpt->o_m;\n");
 
 		fprintf(tc, "\t\tbreak;\n");
 	}

+ 19 - 19
sys/src/cmd/spin/pangen4.h

@@ -1,10 +1,13 @@
 /***** spin: pangen4.h *****/
 
-/* Copyright (c) 1997-2000 by Lucent Technologies - Bell Laboratories.    */
+/* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 /* The DFA code below was written by Anuj Puri and Gerard J. Holzmann in  */
 /* May 1997, and was inspired by earlier work on data compression using   */
@@ -29,7 +32,7 @@ static char *Dfa[] = {
 	"",
 	"extern char	*emalloc(unsigned long);	/* imported routine  */",
 	"extern void	dfa_init(ushort);	/* 4 exported routines */",
-	"extern int	dfa_member(ushort);",
+	"extern int	dfa_member(ulong);",
 	"extern int	dfa_store(uchar *);",
 	"extern void	dfa_stats(void);",
 	"",
@@ -53,9 +56,6 @@ static char *Dfa[] = {
 	"static Vertex	**layers;	/* one splay tree of nodes per layer */",
 	"static Vertex	**path;		/* run of word in the DFA */",
 	"static Vertex	*R, *F, *NF;	/* Root, Final, Not-Final */",
-#if 0
-	"/* extern ulong nr_states=0;	/* number of nodes in the DFA */",
-#endif
 	"static uchar	*word, *lastword;/* string, and last string inserted */",
 	"static int	dfa_depth, iv=0, nv=0, pfrst=0, Tally;",
 	"",
@@ -204,7 +204,7 @@ static char *Dfa[] = {
 	"",
 	"static Vertex *",
 	"Delta(Vertex *v, int h)	/* v->delta[h] */",
-	"{	register Edge *e;",
+	"{	Edge *e;",
 	"",
 	"	if (v->dst[0] && h >= v->from[0] && h <= v->to[0])",
 	"		return v->dst[0];	/* oldest edge */",
@@ -219,8 +219,8 @@ static char *Dfa[] = {
 	"",
 	"static void",
 	"numDelta(Vertex *v, int d)",
-	"{	register Edge *e;",
-	"	register ulong cnt;",
+	"{	Edge *e;",
+	"	ulong cnt;",
 	"	int i;",
 	"",
 	"	for (i = 0; i < 2; i++)",
@@ -367,8 +367,8 @@ static char *Dfa[] = {
 	"",
 	"static ulong",
 	"mk_key(Vertex *v)	/* not sensitive to order */",
-	"{	register ulong m = 0, vk2 = 0;",
-	"	register Edge *e;",
+	"{	ulong m = 0, vk2 = 0;",
+	"	Edge *e;",
 	"",
 	"	if (v->dst[0])",
 	"	{	m += HASH(v->dst[0], v->to[0] - v->from[0] + 1);",
@@ -388,8 +388,8 @@ static char *Dfa[] = {
 	"",
 	"static ulong",
 	"mk_special(int sigma, Vertex *n, Vertex *v)",
-	"{	register ulong m = 0, vk2 = 0;",
-	"	register Edge *f; Vertex *last = (Vertex *) 0;",
+	"{	ulong m = 0, vk2 = 0;",
+	"	Edge *f;",
 	"	int i;",
 	"",
 	"	for (i = 0; i < 2; i++)",
@@ -471,7 +471,7 @@ static char *Dfa[] = {
 	"}",
 	"",
 	"int",
-	"dfa_member(ushort n)",
+	"dfa_member(ulong n)",
 	"{	Vertex **p, **q;",
 	"	uchar *w = &word[n];",
 	"	int i;",
@@ -495,20 +495,20 @@ static char *Dfa[] = {
 	"	memcpy(&lastword[pfrst], &sv[pfrst], dfa_depth-pfrst);",
 	"	if (pfrst > iv) pfrst = iv;",
 	"	if (pfrst > nv) pfrst = nv;",
-	"phase1:",
+	"/* phase1: */",
 	"	p = &path[pfrst]; q = (p+1); w = &word[pfrst];",
 	"	for (i = pfrst; i < dfa_depth; i++)",
 	"		*q++ = Delta(*p++, *w++);	/* (*p)->delta[*w++]; */",
 	"",
 	"	if (*p == F) return 1;	/* it's already there */",
-	"phase2:",
+	"/* phase2: */",
 	"	iv = dfa_depth;",
 	"	do {	iv--;",
 	"		old = new;",
 	"		new = find_it(path[iv], old, word[iv], iv);",
 	"	} while (new && iv > 0);",
 	"",
-	"phase3:",
+	"/* phase3: */",
 	"	nv = k = 0; s = path[0];",
 	"	for (j = 1; j <= iv; ++j) ",
 	"		if (path[j]->num > 1)",

+ 100 - 115
sys/src/cmd/spin/pangen5.c

@@ -1,14 +1,15 @@
 /***** spin: pangen5.c *****/
 
-/* Copyright (c) 1999-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1999-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Written by Gerard J. Holzmann.                                         */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 #include "spin.h"
-#include "version.h"
 #ifdef PC
 #include "y_tab.h"
 #else
@@ -21,24 +22,28 @@ typedef struct BuildStack {
 } BuildStack;
 
 extern ProcList	*rdy;
-extern int verbose, eventmapnr, claimnr, rvopt, xspin;
+extern int verbose, eventmapnr, claimnr, rvopt, export_ast, u_sync;
 extern Element *Al_El;
 
-static FSM_state *fsm;
 static FSM_state *fsm_free;
 static FSM_trans *trans_free;
-static FSM_use   *use_free;
 static BuildStack *bs, *bf;
-static FSM_state **fsm_tbl;
 static int max_st_id;
 static int cur_st_id;
-static int o_max;
+int o_max;
+FSM_state *fsm;
+FSM_state **fsm_tbl;
+FSM_use   *use_free;
 
 static void ana_seq(Sequence *);
 static void ana_stmnt(FSM_trans *, Lextok *, int);
-extern int	has_global(Lextok *);
 
-void
+extern void AST_slice(void);
+extern void AST_store(ProcList *, int);
+extern int  has_global(Lextok *);
+extern void exit(int);
+
+static void
 fsm_table(void)
 {	FSM_state *f;
 	max_st_id += 2;
@@ -118,28 +123,8 @@ good_dead(Element *e, FSM_use *u)
 }
 
 #if 0
-static int
-badjump(Element *e)
-{	Element *g;
-
-	/* e->n->ntyp == GOTO */
-	g = get_lab(e->n, 1);
-	g = huntele(g, e->status);
-	if (g && g->n) 
-	{	switch (g->n->ntyp) {
-		case ATOMIC:
-		case NON_ATOMIC:
-		case D_STEP:
-		case IF:
-		case DO:
-		case UNLESS:
-		case ELSE:
-			return 1;
-	}	}
-	return 0;
-}
-#endif
 static int howdeep = 0;
+#endif
 
 static int
 eligible(FSM_trans *v)
@@ -155,9 +140,9 @@ eligible(FSM_trans *v)
 	||  (el->status&CHECK2)		/* remotely referenced */
 	||  lt->ntyp == ATOMIC
 	||  lt->ntyp == NON_ATOMIC	/* used for inlines -- should be able to handle this */
-#if 1
 	||  lt->ntyp == IF
-#endif
+	||  lt->ntyp == C_CODE
+	||  lt->ntyp == C_EXPR
 	||  has_lab(el, 0)		/* any label at all */
 
 	||  lt->ntyp == DO
@@ -169,48 +154,13 @@ eligible(FSM_trans *v)
 	||  lt->ntyp == 'r'
 	||  lt->ntyp == 's')
 		return 0;
-#if 0
-	if (lt && lt->ntyp == GOTO && badjump(el))
-		return 0;
-#endif
+
 	if (!(el->status&(2|4)))	/* not atomic */
 	{	int unsafe = (el->status&I_GLOB)?1:has_global(el->n);
 		if (unsafe)
 			return 0;
 	}
-#if 0
-	if (lt->ntyp == IF)
-	{	SeqList *h;
-		Element *g;
-		int cnt=0, has_else=0;
-
-		/* is it clearly deterministic? */
-
-		for (h = v->step->sub; h; h = h->nxt, cnt++)
-		{	g = huntstart(h->this->frst);
-			if (!g 	|| g->esc || !g->n)
-				return 0;
-			switch (g->n->ntyp) {
-			case ELSE:
-				has_else=1;
-				/* fall through */
-			case 'c':
-				break;
-			default:
-				return 0;
-			}
-		}
-		if (cnt != 2 || !has_else)
-			return 0;
-
-/* should also be no GOTO, BREAK, or ineligible stmnts in either sequence */
-
-printf("spin: %s:%d: may have handled if\n",
-	lt->fn?lt->fn->name:"", lt->ln);
 
-		return 0;
-	}
-#endif
 	return 1;
 }
 
@@ -266,14 +216,14 @@ static int
 build_step(FSM_trans *v)
 {	FSM_state *f;
 	Element	*el = v->step;
+#if 0
 	Lextok	*lt = ZN;
+#endif
 	int	st  = v->to;
 	int	r;
 
 	if (!el) return -1;
 
-	lt = v->step->n;
-
 	if (v->step->merge)
 		return v->step->merge;	/* already done */
 
@@ -285,6 +235,7 @@ build_step(FSM_trans *v)
 
 	f = fsm_tbl[st];
 #if 0
+	lt = v->step->n;
 	if (verbose&32)
 	{	if (++howdeep == 1)
 			printf("spin: %s, line %3d, merge:\n",
@@ -299,7 +250,10 @@ build_step(FSM_trans *v)
 	v->step->merge = (r == -1) ? st : r;
 #if 0
 	if (verbose&32)
+	{	printf("	merge value: %d (st=%d,r=%d, line %d)\n",
+			v->step->merge, st, r, el->n->ln);
 		howdeep--;
+	}
 #endif
 	popbuild();
 
@@ -307,7 +261,7 @@ build_step(FSM_trans *v)
 }
 
 static void
-FSM_MERGER(char *pname)	/* find candidates for safely merging steps */
+FSM_MERGER(char *pname_unused)	/* find candidates for safely merging steps */
 {	FSM_state *f, *g;
 	FSM_trans *t;
 	Lextok	*lt;
@@ -369,11 +323,19 @@ FSM_MERGER(char *pname)	/* find candidates for safely merging steps */
 			continue;
 
 		lt = t->step->n;
+#if 0
+	4.1.3:
+	an rv send operation inside an atomic, *loses* atomicity
+	when executed
+	and should therefore never be merged with a subsequent
+	statement within the atomic sequence
+	the same is not true for non-rv send operations
+#endif
 
-		if (lt->ntyp == 'c'
+		if (lt->ntyp == 'c'	/* potentially blocking stmnts */
 		||  lt->ntyp == 'r'
-		||  lt->ntyp == 's')	/* blocking stmnts */
-		{	if (!canfill_in(t))
+		||  (lt->ntyp == 's' && u_sync == 0))	/* added !u_sync in 4.1.3 */
+		{	if (!canfill_in(t))		/* atomic, non-global, etc. */
 				continue;
 
 			g = fsm_tbl[t->to];
@@ -420,6 +382,7 @@ FSM_ANA(void)
 			u->special = n+1;	/* means, reset to 0 after use */
 	}
 
+	if (!export_ast)
 	for (f = fsm; f; f = f->nxt)
 	for (t = f->t; t; t = t->nxt)
 	for (n = 0; n < 2; n++)
@@ -430,7 +393,7 @@ FSM_ANA(void)
 				t->Val[n] = v;
 			else
 				w->nxt = v;
-#if 0
+#if q
 			if (verbose&32)
 			{	printf("%s : %3d:  %d -> %d \t",
 					t->step->n->fn->name,
@@ -453,7 +416,7 @@ FSM_ANA(void)
 	}	}
 }
 
-static void
+void
 rel_use(FSM_use *u)
 {
 	if (!u) return;
@@ -519,12 +482,9 @@ mkstate(int s)
 	return f;
 }
 
-static void
-FSM_EDGE(int from, int to, Element *e)
-{	FSM_state *f;
-	FSM_trans *t;
-
-	f = mkstate(from);	/* find it or else make it */
+static FSM_trans *
+get_trans(int to)
+{	FSM_trans *t;
 
 	if (trans_free)
 	{	t = trans_free;
@@ -532,7 +492,19 @@ FSM_EDGE(int from, int to, Element *e)
 		trans_free = trans_free->nxt;
 	} else
 		t = (FSM_trans *) emalloc(sizeof(FSM_trans));
+
 	t->to = to;
+	return t;
+}
+
+static void
+FSM_EDGE(int from, int to, Element *e)
+{	FSM_state *f;
+	FSM_trans *t;
+
+	f = mkstate(from);	/* find it or else make it */
+	t = get_trans(to);
+
 	t->step = e;
 	t->nxt = f->t;
 	f->t = t;
@@ -540,6 +512,13 @@ FSM_EDGE(int from, int to, Element *e)
 	f = mkstate(to);
 	f->in++;
 
+	if (export_ast)
+	{	t = get_trans(from);
+		t->step = e;
+		t->nxt = f->p;	/* from is a predecessor of to */
+		f->p = t;
+	}
+
 	if (t->step)
 		ana_stmnt(t, t->step->n, 0);
 }
@@ -551,10 +530,13 @@ static void
 ana_var(FSM_trans *t, Lextok *now, int usage)
 {	FSM_use *u, *v;
 
-	if (!t
-	|| !now
-	|| !now->sym
-	||  now->sym->name[0] == '_')
+	if (!t || !now || !now->sym)
+		return;
+
+	if (now->sym->name[0] == '_'
+	&&  (strcmp(now->sym->name, "_") == 0
+	||   strcmp(now->sym->name, "_pid") == 0
+	||   strcmp(now->sym->name, "_last") == 0))
 		return;
 
 	v = t->Val[usage];
@@ -606,6 +588,8 @@ ana_stmnt(FSM_trans *t, Lextok *now, int usage)
 	case ATOMIC:
 	case NON_ATOMIC:
 	case D_STEP:
+	case C_CODE:
+	case C_EXPR:
 		break;
 
 	case '!':	
@@ -641,8 +625,8 @@ ana_stmnt(FSM_trans *t, Lextok *now, int usage)
 	case AND:
 	case LSHIFT:
 	case RSHIFT:
-		ana_stmnt(t,now->lft, RVAL);
-		ana_stmnt(t,now->rgt, RVAL);
+		ana_stmnt(t, now->lft, RVAL);
+		ana_stmnt(t, now->rgt, RVAL);
 		break;
 
 	case ASGN:
@@ -656,6 +640,11 @@ ana_stmnt(FSM_trans *t, Lextok *now, int usage)
 			ana_stmnt(t, v->lft, RVAL);
 		break;
 
+	case PRINTM:
+		if (now->lft && !now->lft->ismtyp)
+			ana_stmnt(t, now->lft, RVAL);
+		break;
+
 	case 's':
 		ana_stmnt(t, now->lft, RVAL);
 		for (v = now->rgt; v; v = v->rgt)
@@ -677,8 +666,10 @@ ana_stmnt(FSM_trans *t, Lextok *now, int usage)
 
 	case '?':
 		ana_stmnt(t, now->lft, RVAL);
-		ana_stmnt(t, now->rgt->lft, RVAL);
-		ana_stmnt(t, now->rgt->rgt, RVAL);
+		if (now->rgt)
+		{	ana_stmnt(t, now->rgt->lft, RVAL);
+			ana_stmnt(t, now->rgt->rgt, RVAL);
+		}
 		break;
 
 	case NAME:
@@ -692,17 +683,18 @@ ana_stmnt(FSM_trans *t, Lextok *now, int usage)
 		break;
 
 	default:
-		printf("spin: bad node type %d (ana_stmnt)\n", now->ntyp);
+		printf("spin: bad node type %d line %d (ana_stmnt)\n", now->ntyp, now->ln);
 		fatal("aborting", (char *) 0);
 	}
 }
 
 void
-ana_src(int dataflow, int merger)
+ana_src(int dataflow, int merger)	/* called from main.c and guided.c */
 {	ProcList *p;
 	Element *e;
+#if 0
 	int counter = 1;
-
+#endif
 	for (p = rdy; p; p = p->nxt)
 	{	if (p->tn == eventmapnr
 		||  p->tn == claimnr)
@@ -724,11 +716,14 @@ ana_src(int dataflow, int merger)
 		}
 		if (merger)
 		{	FSM_MERGER(p->n->name);
-			huntele(e, e->status)->merge_in = 1; /* start-state */
+			huntele(e, e->status, -1)->merge_in = 1; /* start-state */
 #if 0
 			printf("\n");
 #endif
 		}
+		if (export_ast)
+			AST_store(p, huntele(e, e->status, -1)->seqno);
+
 		FSM_DEL();
 	}
 	for (e = Al_El; e; e = e->Nxt)
@@ -742,24 +737,14 @@ ana_src(int dataflow, int merger)
 		}
 		e->status &= ~DONE;
 	}
+	if (export_ast)
+	{	AST_slice();
+		exit(0);
+	}
 }
 
-#if 0
-void
-whichnodeis(int s)
-{	Element *e;
-	for (e = Al_El; e; e = e->Nxt)
-		if (e->seqno == s)
-		{	printf("\n\tnode %s:%d: ",
-				e->n->fn->name, e->n->ln);
-			comment(stdout, e->n, 0);
-			printf("\n");
-		}
-}
-#endif
-
 void
-spit_recvs(FILE *f1, FILE *f2)
+spit_recvs(FILE *f1, FILE *f2)	/* called from pangen2.c */
 {	Element *e;
 	Sequence *s;
 	extern int Unique;
@@ -849,10 +834,10 @@ ana_seq(Sequence *s)
 		} else 
 		{	if (e->n->ntyp == GOTO)
 			{	g = get_lab(e->n, 1);
-				g = huntele(g, e->status);
+				g = huntele(g, e->status, -1);
 				To = g->seqno;
 			} else if (e->nxt)
-			{	g = huntele(e->nxt, e->status);
+			{	g = huntele(e->nxt, e->status, -1);
 				To = g->seqno;
 			} else
 				To = 0;

+ 14 - 13
sys/src/cmd/spin/pangen5.h

@@ -1,14 +1,16 @@
 /***** spin: pangen5.h *****/
 
-/* Copyright (c) 1997-2000 by Lucent Technologies - Bell Laboratories.    */
+/* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* The checkpointing code below was written by Gerard J. Holzmann         */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 static char *Xpt[] = {
-	"#if defined(W_XPT) || defined(R_XPT)",
+	"#if defined(MA) && (defined(W_XPT) || defined(R_XPT))",
 	"static Vertex	**temptree;",
 	"static char	wbuf[4096];",
 	"static int	WCNT = 4096, wcnt=0;",
@@ -129,7 +131,6 @@ static char *Xpt[] = {
 	"static void",
 	"x_remove(void)",
 	"{	Vertex *tmp; int i, s;",
-	"#if 1",
 	"	int r, j;",
 	"	/* double-check: */",
 	"	stacker[dfa_depth-1] = 0; r = dfa_store(stacker);",
@@ -141,7 +142,6 @@ static char *Xpt[] = {
 	"		printf(\" -- not a stackstate <o:%%d,4:%%d>\\n\", r, j);",
 	"		return;",
 	"	}",
-	"#endif",
 	"	stacker[dfa_depth-1] = 1;",
 	"	s = dfa_member(dfa_depth-1);",
 	"",
@@ -291,7 +291,9 @@ static char *Xpt[] = {
 	"	yes = no = 0;",
 	"	for (i = 0; i < 2; i++)",
 	"		if ((ulong) t->dst[i] == want)",
-	"		{	if (t->from[i] <= 0 && t->to[i] >= 0)",
+	"		{	/* was t->from[i] <= 0 && t->to[i] >= 0 */",
+	"			/* but from and to are uchar */",
+	"			if (t->from[i] == 0)",
 	"				yes = 1;",
 	"			else",
 	"			if (t->from[i] <= 4 && t->to[i] >= 4)",
@@ -300,7 +302,8 @@ static char *Xpt[] = {
 	"",
 	"	for (e = t->Succ; e; e = e->Nxt)",
 	"		if ((ulong) e->Dst == want)",
-	"		{	if (INRANGE(e, 0))",
+	"		{	/* was INRANGE(e,0) but From and To are uchar */",
+	"			if ((e->From == 0) || (e->s==1 && e->S==0))",
 	"				yes = 1;",
 	"			else if (INRANGE(e, 4))",
 	"				no = 1;",
@@ -348,9 +351,7 @@ static char *Xpt[] = {
 	"",
 	"static Vertex *",
 	"x_cpy_rev(void)",
-	"{	Vertex *c, *v;",
-	"",
-	"	/* find 0 and !4 predecessor of F */",
+	"{	Vertex *c, *v;	/* find 0 and !4 predecessor of F */",
 	"",
 	"	v = x_tail(temptree[dfa_depth-1], F->key);",
 	"	if (!v) return (Vertex *) 0;",

+ 2357 - 0
sys/src/cmd/spin/pangen6.c

@@ -0,0 +1,2357 @@
+/***** spin: pangen6.c *****/
+
+/* Copyright (c) 2000-2003 by Lucent Technologies, Bell Laboratories.     */
+/* All Rights Reserved.  This software is for educational purposes only.  */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
+
+/* Abstract syntax tree analysis / slicing (spin option -A) */
+/* AST_store stores the fsms's for each proctype            */
+/* AST_track keeps track of variables used in properties    */
+/* AST_slice starts the slicing algorithm                   */
+/*      it first collects more info and then calls          */
+/*      AST_criteria to process the slice criteria          */
+
+#include "spin.h"
+#ifdef PC
+#include "y_tab.h"
+#else
+#include "y.tab.h"
+#endif
+
+extern Ordered	 *all_names;
+extern FSM_use   *use_free;
+extern FSM_state **fsm_tbl;
+extern FSM_state *fsm;
+extern int	 verbose, o_max;
+
+static FSM_trans *cur_t;
+static FSM_trans *expl_par;
+static FSM_trans *expl_var;
+static FSM_trans *explicit;
+
+extern void rel_use(FSM_use *);
+
+#define ulong	unsigned long
+
+typedef struct Pair {
+	FSM_state	*h;
+	int		b;
+	struct Pair	*nxt;
+} Pair;
+
+typedef struct AST {
+	ProcList *p;		/* proctype decl */
+	int	i_st;		/* start state */
+	int	nstates, nwords;
+	int	relevant;
+	Pair	*pairs;		/* entry and exit nodes of proper subgraphs */
+	FSM_state *fsm;		/* proctype body */
+	struct AST *nxt;	/* linked list */
+} AST;
+
+typedef struct RPN {		/* relevant proctype names */
+	Symbol	*rn;
+	struct RPN *nxt;
+} RPN;
+
+typedef struct ALIAS {		/* channel aliasing info */
+	Lextok	*cnm;		/* this chan */
+	int	origin;		/* debugging - origin of the alias */
+	struct ALIAS	*alias;	/* can be an alias for these other chans */
+	struct ALIAS	*nxt;	/* linked list */
+} ALIAS;
+
+typedef struct ChanList {
+	Lextok *s;		/* containing stmnt */
+	Lextok *n;		/* point of reference - could be struct */
+	struct ChanList *nxt;	/* linked list */
+} ChanList;
+
+/* a chan alias can be created in one of three ways:
+	assignement to chan name
+		a = b -- a is now an alias for b
+	passing chan name as parameter in run
+		run x(b) -- proctype x(chan a)
+	passing chan name through channel
+		x!b -- x?a
+ */
+
+#define USE		1
+#define DEF		2
+#define DEREF_DEF	4
+#define DEREF_USE	8
+
+static AST	*ast;
+static ALIAS	*chalcur;
+static ALIAS	*chalias;
+static ChanList	*chanlist;
+static Slicer	*slicer;
+static Slicer	*rel_vars;	/* all relevant variables */
+static int	AST_Changes;
+static int	AST_Round;
+static FSM_state no_state;
+static RPN	*rpn;
+static int	in_recv = 0;
+
+static int	AST_mutual(Lextok *, Lextok *, int);
+static void	AST_dominant(void);
+static void	AST_hidden(void);
+static void	AST_setcur(Lextok *);
+static void	check_slice(Lextok *, int);
+static void	curtail(AST *);
+static void	def_use(Lextok *, int);
+static void	name_AST_track(Lextok *, int);
+static void	show_expl(void);
+
+static int
+AST_isini(Lextok *n)	/* is this an initialized channel */
+{	Symbol *s;
+
+	if (!n || !n->sym) return 0;
+
+	s = n->sym;
+
+	if (s->type == CHAN)
+		return (s->ini->ntyp == CHAN); /* freshly instantiated */
+
+	if (s->type == STRUCT && n->rgt)
+		return AST_isini(n->rgt->lft);
+
+	return 0;
+}
+
+static void
+AST_var(Lextok *n, Symbol *s, int toplevel)
+{
+	if (!s) return;
+
+	if (toplevel)
+	{	if (s->context && s->type)
+			printf(":%s:L:", s->context->name);
+		else
+			printf("G:");
+	}
+	printf("%s", s->name); /* array indices ignored */
+
+	if (s->type == STRUCT && n && n->rgt && n->rgt->lft)
+	{	printf(":");
+		AST_var(n->rgt->lft, n->rgt->lft->sym, 0);
+	}
+}
+
+static void
+name_def_indices(Lextok *n, int code)
+{
+	if (!n || !n->sym) return;
+
+	if (n->sym->nel != 1)
+		def_use(n->lft, code);		/* process the index */
+
+	if (n->sym->type == STRUCT		/* and possible deeper ones */
+	&&  n->rgt)
+		name_def_indices(n->rgt->lft, code);
+}
+
+static void
+name_def_use(Lextok *n, int code)
+{	FSM_use *u;
+
+	if (!n) return;
+
+	if ((code&USE)
+	&&  cur_t->step
+	&&  cur_t->step->n)
+	{	switch (cur_t->step->n->ntyp) {
+		case 'c': /* possible predicate abstraction? */
+			n->sym->colnr |= 2; /* yes */
+			break;
+		default:
+			n->sym->colnr |= 1; /* no  */
+			break;
+		}
+	}
+
+	for (u = cur_t->Val[0]; u; u = u->nxt)
+		if (AST_mutual(n, u->n, 1)
+		&&  u->special == code)
+			return;
+
+	if (use_free)
+	{	u = use_free;
+		use_free = use_free->nxt;
+	} else
+		u = (FSM_use *) emalloc(sizeof(FSM_use));
+	
+	u->n = n;
+	u->special = code;
+	u->nxt = cur_t->Val[0];
+	cur_t->Val[0] = u;
+
+	name_def_indices(n, USE|(code&(~DEF)));	/* not def, but perhaps deref */
+}
+
+static void
+def_use(Lextok *now, int code)
+{	Lextok *v;
+
+	if (now)
+	switch (now->ntyp) {
+	case '!':	
+	case UMIN:	
+	case '~':
+	case 'c':
+	case ENABLED:
+	case ASSERT:
+	case EVAL:
+		def_use(now->lft, USE|code);
+		break;
+
+	case LEN:
+	case FULL:
+	case EMPTY:
+	case NFULL:
+	case NEMPTY:
+		def_use(now->lft, DEREF_USE|USE|code);
+		break;
+
+	case '/':
+	case '*':
+	case '-':
+	case '+':
+	case '%':
+	case '&':
+	case '^':
+	case '|':
+	case LE:
+	case GE:
+	case GT:
+	case LT:
+	case NE:
+	case EQ:
+	case OR:
+	case AND:
+	case LSHIFT:
+	case RSHIFT:
+		def_use(now->lft, USE|code);
+		def_use(now->rgt, USE|code); 
+		break;
+
+	case ASGN:
+		def_use(now->lft, DEF|code);
+		def_use(now->rgt, USE|code);
+		break;
+
+	case TYPE:	/* name in parameter list */
+		name_def_use(now, code);
+		break;
+
+	case NAME:
+		name_def_use(now, code);
+		break;
+
+	case RUN:
+		name_def_use(now, USE);			/* procname - not really needed */
+		for (v = now->lft; v; v = v->rgt)
+			def_use(v->lft, USE);		/* params */
+		break;
+
+	case 's':
+		def_use(now->lft, DEREF_DEF|DEREF_USE|USE|code);
+		for (v = now->rgt; v; v = v->rgt)
+			def_use(v->lft, USE|code);
+		break;
+
+	case 'r':
+		def_use(now->lft, DEREF_DEF|DEREF_USE|USE|code);
+		for (v = now->rgt; v; v = v->rgt)
+		{	if (v->lft->ntyp == EVAL)
+				def_use(v->lft, code);	/* will add USE */
+			else if (v->lft->ntyp != CONST)
+				def_use(v->lft, DEF|code);
+		}
+		break;
+
+	case 'R':
+		def_use(now->lft, DEREF_USE|USE|code);
+		for (v = now->rgt; v; v = v->rgt)
+		{	if (v->lft->ntyp == EVAL)
+				def_use(v->lft, code); /* will add USE */
+		}
+		break;
+
+	case '?':
+		def_use(now->lft, USE|code);
+		if (now->rgt)
+		{	def_use(now->rgt->lft, code);
+			def_use(now->rgt->rgt, code);
+		}
+		break;	
+
+	case PRINT:
+		for (v = now->lft; v; v = v->rgt)
+			def_use(v->lft, USE|code);
+		break;
+
+	case PRINTM:
+		def_use(now->lft, USE);
+		break;
+
+	case CONST:
+	case ELSE:	/* ? */
+	case NONPROGRESS:
+	case PC_VAL:
+	case   'p':
+	case   'q':
+		break;
+
+	case   '.':
+	case  GOTO:
+	case BREAK:
+	case   '@':
+	case D_STEP:
+	case ATOMIC:
+	case NON_ATOMIC:
+	case IF:
+	case DO:
+	case UNLESS:
+	case TIMEOUT:
+	case C_CODE:
+	case C_EXPR:
+	default:
+		break;
+	}
+}
+
+static int
+AST_add_alias(Lextok *n, int nr)
+{	ALIAS *ca;
+	int res;
+
+	for (ca = chalcur->alias; ca; ca = ca->nxt)
+		if (AST_mutual(ca->cnm, n, 1))
+		{	res = (ca->origin&nr);
+			ca->origin |= nr;	/* 1, 2, or 4 - run, asgn, or rcv */
+			return (res == 0);	/* 0 if already there with same origin */
+		}
+
+	ca = (ALIAS *) emalloc(sizeof(ALIAS));
+	ca->cnm = n;
+	ca->origin = nr;
+	ca->nxt = chalcur->alias;
+	chalcur->alias = ca;
+	return 1;
+}
+
+static void
+AST_run_alias(char *pn, char *s, Lextok *t, int parno)
+{	Lextok *v;
+	int cnt;
+
+	if (!t) return;
+
+	if (t->ntyp == RUN)
+	{	if (strcmp(t->sym->name, s) == 0)
+		for (v = t->lft, cnt = 1; v; v = v->rgt, cnt++)
+			if (cnt == parno)
+			{	AST_add_alias(v->lft, 1); /* RUN */
+				break;
+			}
+	} else
+	{	AST_run_alias(pn, s, t->lft, parno);
+		AST_run_alias(pn, s, t->rgt, parno);
+	}
+}
+
+static void
+AST_findrun(char *s, int parno)
+{	FSM_state *f;
+	FSM_trans *t;
+	AST *a;
+
+	for (a = ast; a; a = a->nxt)		/* automata       */
+	for (f = a->fsm; f; f = f->nxt)		/* control states */
+	for (t = f->t; t; t = t->nxt)		/* transitions    */
+	{	if (t->step)
+		AST_run_alias(a->p->n->name, s, t->step->n, parno);
+	}
+}
+
+static void
+AST_par_chans(ProcList *p)	/* find local chan's init'd to chan passed as param */
+{	Ordered	*walk;
+	Symbol	*sp;
+
+	for (walk = all_names; walk; walk = walk->next)
+	{	sp = walk->entry;
+		if (sp
+		&&  sp->context
+		&&  strcmp(sp->context->name, p->n->name) == 0
+		&&  sp->Nid >= 0	/* not itself a param */
+		&&  sp->type == CHAN
+		&&  sp->ini->ntyp == NAME)	/* != CONST and != CHAN */
+		{	Lextok *x = nn(ZN, 0, ZN, ZN);
+			x->sym = sp;
+			AST_setcur(x);
+			AST_add_alias(sp->ini, 2);	/* ASGN */
+	}	}
+}
+
+static void
+AST_para(ProcList *p)
+{	Lextok *f, *t, *c;
+	int cnt = 0;
+
+	AST_par_chans(p);
+
+	for (f = p->p; f; f = f->rgt) 		/* list of types */
+	for (t = f->lft; t; t = t->rgt)
+	{	if (t->ntyp != ',')
+			c = t;
+		else
+			c = t->lft;	/* expanded struct */
+
+		cnt++;
+		if (Sym_typ(c) == CHAN)
+		{	ALIAS *na = (ALIAS *) emalloc(sizeof(ALIAS));
+
+			na->cnm = c;
+			na->nxt = chalias;
+			chalcur = chalias = na;
+#if 0
+			printf("%s -- (par) -- ", p->n->name);
+			AST_var(c, c->sym, 1);
+			printf(" => <<");
+#endif
+			AST_findrun(p->n->name, cnt);
+#if 0
+			printf(">>\n");
+#endif
+		}
+	}
+}
+
+static void
+AST_haschan(Lextok *c)
+{
+	if (!c) return;
+	if (Sym_typ(c) == CHAN)
+	{	AST_add_alias(c, 2);	/* ASGN */
+#if 0
+		printf("<<");
+		AST_var(c, c->sym, 1);
+		printf(">>\n");
+#endif
+	} else
+	{	AST_haschan(c->rgt);
+		AST_haschan(c->lft);
+	}
+}
+
+static int
+AST_nrpar(Lextok *n) /* 's' or 'r' */
+{	Lextok *m;
+	int j = 0;
+
+	for (m = n->rgt; m; m = m->rgt)
+		j++;
+	return j;
+}
+
+static int
+AST_ord(Lextok *n, Lextok *s)
+{	Lextok *m;
+	int j = 0;
+
+	for (m = n->rgt; m; m = m->rgt)
+	{	j++;
+		if (s->sym == m->lft->sym)
+			return j;
+	}
+	return 0;
+}
+
+#if 0
+static void
+AST_ownership(Symbol *s)
+{
+	if (!s) return;
+	printf("%s:", s->name);
+	AST_ownership(s->owner);
+}
+#endif
+
+static int
+AST_mutual(Lextok *a, Lextok *b, int toplevel)
+{	Symbol *as, *bs;
+
+	if (!a && !b) return 1;
+
+	if (!a || !b) return 0;
+
+	as = a->sym;
+	bs = b->sym;
+
+	if (!as || !bs) return 0;
+
+	if (toplevel && as->context != bs->context)
+		return 0;
+
+	if (as->type != bs->type)
+		return 0;
+
+	if (strcmp(as->name, bs->name) != 0)
+		return 0;
+
+	if (as->type == STRUCT
+	&&  a && a->rgt && b && b->rgt)
+		return AST_mutual(a->rgt->lft, b->rgt->lft, 0);
+
+	return 1;
+}
+
+static void
+AST_setcur(Lextok *n)	/* set chalcur */
+{	ALIAS *ca;
+
+	for (ca = chalias; ca; ca = ca->nxt)
+		if (AST_mutual(ca->cnm, n, 1))	/* if same chan */
+		{	chalcur = ca;
+			return;
+		}
+
+	ca = (ALIAS *) emalloc(sizeof(ALIAS));
+	ca->cnm = n;
+	ca->nxt = chalias;
+	chalcur = chalias = ca;
+}
+
+static void
+AST_other(AST *a)	/* check chan params in asgns and recvs */
+{	FSM_state *f;
+	FSM_trans *t;
+	FSM_use *u;
+	ChanList *cl;
+
+	for (f = a->fsm; f; f = f->nxt)		/* control states */
+	for (t = f->t; t; t = t->nxt)		/* transitions    */
+	for (u = t->Val[0]; u; u = u->nxt)	/* def/use info   */
+		if (Sym_typ(u->n) == CHAN
+		&&  (u->special&DEF))		/* def of chan-name  */
+		{	AST_setcur(u->n);
+			switch (t->step->n->ntyp) {
+			case ASGN:
+				AST_haschan(t->step->n->rgt);
+				break;
+			case 'r':
+				/* guess sends where name may originate */
+				for (cl = chanlist; cl; cl = cl->nxt)	/* all sends */
+				{	int a = AST_nrpar(cl->s);
+					int b = AST_nrpar(t->step->n);
+					if (a != b)	/* matching nrs of params */
+						continue;
+
+					a = AST_ord(cl->s, cl->n);
+					b = AST_ord(t->step->n, u->n);
+					if (a != b)	/* same position in parlist */
+						continue;
+
+					AST_add_alias(cl->n, 4); /* RCV assume possible match */
+				}
+				break;
+			default:
+				printf("type = %d\n", t->step->n->ntyp);
+				non_fatal("unexpected chan def type", (char *) 0);
+				break;
+		}	}
+}
+
+static void
+AST_aliases(void)
+{	ALIAS *na, *ca;
+
+	for (na = chalias; na; na = na->nxt)
+	{	printf("\npossible aliases of ");
+		AST_var(na->cnm, na->cnm->sym, 1);
+		printf("\n\t");
+		for (ca = na->alias; ca; ca = ca->nxt)
+		{	if (!ca->cnm->sym)
+				printf("no valid name ");
+			else
+				AST_var(ca->cnm, ca->cnm->sym, 1);
+			printf("<");
+			if (ca->origin & 1) printf("RUN ");
+			if (ca->origin & 2) printf("ASGN ");
+			if (ca->origin & 4) printf("RCV ");
+			printf("[%s]", AST_isini(ca->cnm)?"Initzd":"Name");
+			printf(">");
+			if (ca->nxt) printf(", ");
+		}
+		printf("\n");
+	}
+	printf("\n");
+}
+
+static void
+AST_indirect(FSM_use *uin, FSM_trans *t, char *cause, char *pn)
+{	FSM_use *u;
+
+	/* this is a newly discovered relevant statement */
+	/* all vars it uses to contribute to its DEF are new criteria */
+
+	if (!(t->relevant&1)) AST_Changes++;
+
+	t->round = AST_Round;
+	t->relevant = 1;
+
+	if ((verbose&32) && t->step)
+	{	printf("\tDR %s [[ ", pn);
+		comment(stdout, t->step->n, 0);
+		printf("]]\n\t\tfully relevant %s", cause);
+		if (uin) { printf(" due to "); AST_var(uin->n, uin->n->sym, 1); }
+		printf("\n");
+	}
+	for (u = t->Val[0]; u; u = u->nxt)
+		if (u != uin
+		&& (u->special&(USE|DEREF_USE)))
+		{	if (verbose&32)
+			{	printf("\t\t\tuses(%d): ", u->special);
+				AST_var(u->n, u->n->sym, 1);
+				printf("\n");
+			}
+			name_AST_track(u->n, u->special);	/* add to slice criteria */
+		}
+}
+
+static void
+def_relevant(char *pn, FSM_trans *t, Lextok *n, int ischan)
+{	FSM_use *u;
+	ALIAS *na, *ca;
+	int chanref;
+
+	/* look for all DEF's of n
+	 *	mark those stmnts relevant
+	 *	mark all var USEs in those stmnts as criteria
+	 */
+
+	if (n->ntyp != ELSE)
+	for (u = t->Val[0]; u; u = u->nxt)
+	{	chanref = (Sym_typ(u->n) == CHAN);
+
+		if (ischan != chanref			/* no possible match  */
+		|| !(u->special&(DEF|DEREF_DEF)))	/* not a def */
+			continue;
+
+		if (AST_mutual(u->n, n, 1))
+		{	AST_indirect(u, t, "(exact match)", pn);
+			continue;
+		}
+
+		if (chanref)
+		for (na = chalias; na; na = na->nxt)
+		{	if (!AST_mutual(u->n, na->cnm, 1))
+				continue;
+			for (ca = na->alias; ca; ca = ca->nxt)
+				if (AST_mutual(ca->cnm, n, 1)
+				&&  AST_isini(ca->cnm))	
+				{	AST_indirect(u, t, "(alias match)", pn);
+					break;
+				}
+			if (ca) break;
+	}	}	
+}
+
+static void
+AST_relevant(Lextok *n)
+{	AST *a;
+	FSM_state *f;
+	FSM_trans *t;
+	int ischan;
+
+	/* look for all DEF's of n
+	 *	mark those stmnts relevant
+	 *	mark all var USEs in those stmnts as criteria
+	 */
+
+	if (!n) return;
+	ischan = (Sym_typ(n) == CHAN);
+
+	if (verbose&32)
+	{	printf("<<ast_relevant (ntyp=%d) ", n->ntyp);
+		AST_var(n, n->sym, 1);
+		printf(">>\n");
+	}
+
+	for (t = expl_par; t; t = t->nxt)	/* param assignments */
+	{	if (!(t->relevant&1))
+		def_relevant(":params:", t, n, ischan);
+	}
+
+	for (t = expl_var; t; t = t->nxt)
+	{	if (!(t->relevant&1))		/* var inits */
+		def_relevant(":vars:", t, n, ischan);
+	}
+
+	for (a = ast; a; a = a->nxt)		/* all other stmnts */
+	{	if (strcmp(a->p->n->name, ":never:") != 0
+		&&  strcmp(a->p->n->name, ":trace:") != 0
+		&&  strcmp(a->p->n->name, ":notrace:") != 0)
+		for (f = a->fsm; f; f = f->nxt)
+		for (t = f->t; t; t = t->nxt)
+		{	if (!(t->relevant&1))
+			def_relevant(a->p->n->name, t, n, ischan);
+	}	}
+}
+
+static int
+AST_relpar(char *s)
+{	FSM_trans *t, *T;
+	FSM_use *u;
+
+	for (T = expl_par; T; T = (T == expl_par)?expl_var: (FSM_trans *) 0)
+	for (t = T; t; t = t->nxt)
+	{	if (t->relevant&1)
+		for (u = t->Val[0]; u; u = u->nxt)
+		{	if (u->n->sym->type
+			&&  u->n->sym->context
+			&&  strcmp(u->n->sym->context->name, s) == 0)
+			{
+				if (verbose&32)
+				{	printf("proctype %s relevant, due to symbol ", s);
+					AST_var(u->n, u->n->sym, 1);
+					printf("\n");
+				}
+				return 1;
+	}	}	}
+	return 0;
+}
+
+static void
+AST_dorelevant(void)
+{	AST *a;
+	RPN *r;
+
+	for (r = rpn; r; r = r->nxt)
+	{	for (a = ast; a; a = a->nxt)
+			if (strcmp(a->p->n->name, r->rn->name) == 0)
+			{	a->relevant |= 1;
+				break;
+			}
+		if (!a)
+		fatal("cannot find proctype %s", r->rn->name);
+	}		
+}
+
+static void
+AST_procisrelevant(Symbol *s)
+{	RPN *r;
+	for (r = rpn; r; r = r->nxt)
+		if (strcmp(r->rn->name, s->name) == 0)
+			return;
+	r = (RPN *) emalloc(sizeof(RPN));
+	r->rn = s;
+	r->nxt = rpn;
+	rpn = r;
+}
+
+static int
+AST_proc_isrel(char *s)
+{	AST *a;
+
+	for (a = ast; a; a = a->nxt)
+		if (strcmp(a->p->n->name, s) == 0)
+			return (a->relevant&1);
+	non_fatal("cannot happen, missing proc in ast", (char *) 0);
+	return 0;
+}
+
+static int
+AST_scoutrun(Lextok *t)
+{
+	if (!t) return 0;
+
+	if (t->ntyp == RUN)
+		return AST_proc_isrel(t->sym->name);
+	return (AST_scoutrun(t->lft) || AST_scoutrun(t->rgt));
+}
+
+static void
+AST_tagruns(void)
+{	AST *a;
+	FSM_state *f;
+	FSM_trans *t;
+
+	/* if any stmnt inside a proctype is relevant
+	 * or any parameter passed in a run
+	 * then so are all the run statements on that proctype
+	 */
+
+	for (a = ast; a; a = a->nxt)
+	{	if (strcmp(a->p->n->name, ":never:") == 0
+		||  strcmp(a->p->n->name, ":trace:") == 0
+		||  strcmp(a->p->n->name, ":notrace:") == 0
+		||  strcmp(a->p->n->name, ":init:") == 0)
+		{	a->relevant |= 1;	/* the proctype is relevant */
+			continue;
+		}
+		if (AST_relpar(a->p->n->name))
+			a->relevant |= 1;
+		else
+		{	for (f = a->fsm; f; f = f->nxt)
+			for (t = f->t; t; t = t->nxt)
+				if (t->relevant)
+					goto yes;
+yes:			if (f)
+				a->relevant |= 1;
+		}
+	}
+
+	for (a = ast; a; a = a->nxt)
+	for (f = a->fsm; f; f = f->nxt)
+	for (t = f->t; t; t = t->nxt)
+		if (t->step
+		&&  AST_scoutrun(t->step->n))
+		{	AST_indirect((FSM_use *)0, t, ":run:", a->p->n->name);
+			/* BUT, not all actual params are relevant */
+		}
+}
+
+static void
+AST_report(AST *a, Element *e)	/* ALSO deduce irrelevant vars */
+{
+	if (!(a->relevant&2))
+	{	a->relevant |= 2;
+		printf("spin: redundant in proctype %s (for given property):\n",
+			a->p->n->name);
+	}
+	printf("      line %3d %s (state %d)",
+		e->n?e->n->ln:-1,
+		e->n?e->n->fn->name:"-",
+		e->seqno);
+	printf("	[");
+	comment(stdout, e->n, 0);
+	printf("]\n");
+}
+
+static int
+AST_always(Lextok *n)
+{
+	if (!n) return 0;
+
+	if (n->ntyp == '@'	/* -end */
+	||  n->ntyp == 'p')	/* remote reference */
+		return 1;
+	return AST_always(n->lft) || AST_always(n->rgt);
+}
+
+static void
+AST_edge_dump(AST *a, FSM_state *f)
+{	FSM_trans *t;
+	FSM_use *u;
+
+	for (t = f->t; t; t = t->nxt)	/* edges */
+	{
+		if (t->step && AST_always(t->step->n))
+			t->relevant |= 1;	/* always relevant */
+
+		if (verbose&32)
+		{	switch (t->relevant) {
+			case  0: printf("     "); break;
+			case  1: printf("*%3d ", t->round); break;
+			case  2: printf("+%3d ", t->round); break;
+			case  3: printf("#%3d ", t->round); break;
+			default: printf("? "); break;
+			}
+	
+			printf("%d\t->\t%d\t", f->from, t->to);
+			if (t->step)
+				comment(stdout, t->step->n, 0);
+			else
+				printf("Unless");
+	
+			for (u = t->Val[0]; u; u = u->nxt)
+			{	printf(" <");
+				AST_var(u->n, u->n->sym, 1);
+				printf(":%d>", u->special);
+			}
+			printf("\n");
+		} else
+		{	if (t->relevant)
+				continue;
+
+			if (t->step)
+			switch(t->step->n->ntyp) {
+			case ASGN:
+			case 's':
+			case 'r':
+			case 'c':
+				if (t->step->n->lft->ntyp != CONST)
+					AST_report(a, t->step);
+				break;
+
+			case PRINT:	/* don't report */
+			case PRINTM:
+			case ASSERT:
+			case C_CODE:
+			case C_EXPR:
+			default:
+				break;
+	}	}	}
+}
+
+static void
+AST_dfs(AST *a, int s, int vis)
+{	FSM_state *f;
+	FSM_trans *t;
+
+	f = fsm_tbl[s];
+	if (f->seen) return;
+
+	f->seen = 1;
+	if (vis) AST_edge_dump(a, f);
+
+	for (t = f->t; t; t = t->nxt)
+		AST_dfs(a, t->to, vis);
+}
+
+static void
+AST_dump(AST *a)
+{	FSM_state *f;
+
+	for (f = a->fsm; f; f = f->nxt)
+	{	f->seen = 0;
+		fsm_tbl[f->from] = f;
+	}
+
+	if (verbose&32)
+		printf("AST_START %s from %d\n", a->p->n->name, a->i_st);
+
+	AST_dfs(a, a->i_st, 1);
+}
+
+static void
+AST_sends(AST *a)
+{	FSM_state *f;
+	FSM_trans *t;
+	FSM_use *u;
+	ChanList *cl;
+
+	for (f = a->fsm; f; f = f->nxt)		/* control states */
+	for (t = f->t; t; t = t->nxt)		/* transitions    */
+	{	if (t->step
+		&&  t->step->n
+		&&  t->step->n->ntyp == 's')
+		for (u = t->Val[0]; u; u = u->nxt)
+		{	if (Sym_typ(u->n) == CHAN
+			&&  ((u->special&USE) && !(u->special&DEREF_USE)))
+			{
+#if 0
+				printf("%s -- (%d->%d) -- ",
+					a->p->n->name, f->from, t->to);
+				AST_var(u->n, u->n->sym, 1);
+				printf(" -> chanlist\n");
+#endif
+				cl = (ChanList *) emalloc(sizeof(ChanList));
+				cl->s = t->step->n;
+				cl->n = u->n;
+				cl->nxt = chanlist;
+				chanlist = cl;
+}	}	}	}
+
+static ALIAS *
+AST_alfind(Lextok *n)
+{	ALIAS *na;
+
+	for (na = chalias; na; na = na->nxt)
+		if (AST_mutual(na->cnm, n, 1))
+			return na;
+	return (ALIAS *) 0;
+}
+
+static void
+AST_trans(void)
+{	ALIAS *na, *ca, *da, *ea;
+	int nchanges;
+
+	do {
+		nchanges = 0;
+		for (na = chalias; na; na = na->nxt)
+		{	chalcur = na;
+			for (ca = na->alias; ca; ca = ca->nxt)
+			{	da = AST_alfind(ca->cnm);
+				if (da)
+				for (ea = da->alias; ea; ea = ea->nxt)
+				{	nchanges += AST_add_alias(ea->cnm,
+							ea->origin|ca->origin);
+		}	}	}
+	} while (nchanges > 0);
+
+	chalcur = (ALIAS *) 0;
+}
+
+static void
+AST_def_use(AST *a)
+{	FSM_state *f;
+	FSM_trans *t;
+
+	for (f = a->fsm; f; f = f->nxt)		/* control states */
+	for (t = f->t; t; t = t->nxt)		/* all edges */
+	{	cur_t = t;
+		rel_use(t->Val[0]);		/* redo Val; doesn't cover structs */
+		rel_use(t->Val[1]);
+		t->Val[0] = t->Val[1] = (FSM_use *) 0;
+
+		if (!t->step) continue;
+
+		def_use(t->step->n, 0);		/* def/use info, including structs */
+	}
+	cur_t = (FSM_trans *) 0;
+}
+
+static void
+name_AST_track(Lextok *n, int code)
+{	extern int nr_errs;
+#if 0
+	printf("AST_name: ");
+	AST_var(n, n->sym, 1);
+	printf(" -- %d\n", code);
+#endif
+	if (in_recv && (code&DEF) && (code&USE))
+	{	printf("spin: error: DEF and USE of same var in rcv stmnt: ");
+		AST_var(n, n->sym, 1);
+		printf(" -- %d\n", code);
+		nr_errs++;
+	}
+	check_slice(n, code);
+}
+
+void
+AST_track(Lextok *now, int code)	/* called from main.c */
+{	Lextok *v; extern int export_ast;
+
+	if (!export_ast) return;
+
+	if (now)
+	switch (now->ntyp) {
+	case LEN:
+	case FULL:
+	case EMPTY:
+	case NFULL:
+	case NEMPTY:
+		AST_track(now->lft, DEREF_USE|USE|code);
+		break;
+
+	case '/':
+	case '*':
+	case '-':
+	case '+':
+	case '%':
+	case '&':
+	case '^':
+	case '|':
+	case LE:
+	case GE:
+	case GT:
+	case LT:
+	case NE:
+	case EQ:
+	case OR:
+	case AND:
+	case LSHIFT:
+	case RSHIFT:
+		AST_track(now->rgt, USE|code);
+		/* fall through */
+	case '!':	
+	case UMIN:	
+	case '~':
+	case 'c':
+	case ENABLED:
+	case ASSERT:
+		AST_track(now->lft, USE|code);
+		break;
+
+	case EVAL:
+		AST_track(now->lft, USE|(code&(~DEF)));
+		break;
+
+	case NAME:
+		name_AST_track(now, code);
+		if (now->sym->nel != 1)
+			AST_track(now->lft, USE|code);	/* index */
+		break;
+
+	case 'R':
+		AST_track(now->lft, DEREF_USE|USE|code);
+		for (v = now->rgt; v; v = v->rgt)
+			AST_track(v->lft, code); /* a deeper eval can add USE */
+		break;
+
+	case '?':
+		AST_track(now->lft, USE|code);
+		if (now->rgt)
+		{	AST_track(now->rgt->lft, code);
+			AST_track(now->rgt->rgt, code);
+		}
+		break;
+
+/* added for control deps: */
+	case TYPE:	
+		name_AST_track(now, code);
+		break;
+	case ASGN:
+		AST_track(now->lft, DEF|code);
+		AST_track(now->rgt, USE|code);
+		break;
+	case RUN:
+		name_AST_track(now, USE);
+		for (v = now->lft; v; v = v->rgt)
+			AST_track(v->lft, USE|code);
+		break;
+	case 's':
+		AST_track(now->lft, DEREF_DEF|DEREF_USE|USE|code);
+		for (v = now->rgt; v; v = v->rgt)
+			AST_track(v->lft, USE|code);
+		break;
+	case 'r':
+		AST_track(now->lft, DEREF_DEF|DEREF_USE|USE|code);
+		for (v = now->rgt; v; v = v->rgt)
+		{	in_recv++;
+			AST_track(v->lft, DEF|code);
+			in_recv--;
+		}
+		break;
+	case PRINT:
+		for (v = now->lft; v; v = v->rgt)
+			AST_track(v->lft, USE|code);
+		break;
+	case PRINTM:
+		AST_track(now->lft, USE);
+		break;
+/* end add */
+	case   'p':
+#if 0
+			   'p' -sym-> _p
+			   /
+			 '?' -sym-> a (proctype)
+			 /
+			b (pid expr)
+#endif
+		AST_track(now->lft->lft, USE|code);
+		AST_procisrelevant(now->lft->sym);
+		break;
+
+	case CONST:
+	case ELSE:
+	case NONPROGRESS:
+	case PC_VAL:
+	case   'q':
+		break;
+
+	case   '.':
+	case  GOTO:
+	case BREAK:
+	case   '@':
+	case D_STEP:
+	case ATOMIC:
+	case NON_ATOMIC:
+	case IF:
+	case DO:
+	case UNLESS:
+	case TIMEOUT:
+	case C_CODE:
+	case C_EXPR:
+		break;
+
+	default:
+		printf("AST_track, NOT EXPECTED ntyp: %d\n", now->ntyp);
+		break;
+	}
+}
+
+static int
+AST_dump_rel(void)
+{	Slicer *rv;
+	Ordered *walk;
+	char buf[64];
+	int banner=0;
+
+	if (verbose&32)
+	{	printf("Relevant variables:\n");
+		for (rv = rel_vars; rv; rv = rv->nxt)
+		{	printf("\t");
+			AST_var(rv->n, rv->n->sym, 1);
+			printf("\n");
+		}
+		return 1;
+	}
+	for (rv = rel_vars; rv; rv = rv->nxt)
+		rv->n->sym->setat = 1;	/* mark it */
+
+	for (walk = all_names; walk; walk = walk->next)
+	{	Symbol *s;
+		s = walk->entry;
+		if (!s->setat
+		&&  (s->type != MTYPE || s->ini->ntyp != CONST)
+		&&  s->type != STRUCT	/* report only fields */
+		&&  s->type != PROCTYPE
+		&&  !s->owner
+		&&  sputtype(buf, s->type))
+		{	if (!banner)
+			{	banner = 1;
+				printf("spin: redundant vars (for given property):\n");
+			}
+			printf("\t");
+			symvar(s);
+	}	}
+	return banner;
+}
+
+static void
+AST_suggestions(void)
+{	Symbol *s;
+	Ordered *walk;
+	FSM_state *f;
+	FSM_trans *t;
+	AST *a;
+	int banner=0;
+	int talked=0;
+
+	for (walk = all_names; walk; walk = walk->next)
+	{	s = walk->entry;
+		if (s->colnr == 2	/* only used in conditionals */
+		&&  (s->type == BYTE
+		||   s->type == SHORT
+		||   s->type == INT
+		||   s->type == MTYPE))
+		{	if (!banner)
+			{	banner = 1;
+				printf("spin: consider using predicate");
+				printf(" abstraction to replace:\n");
+			}
+			printf("\t");
+			symvar(s);
+	}	}
+
+	/* look for source and sink processes */
+
+	for (a = ast; a; a = a->nxt)		/* automata       */
+	{	banner = 0;
+		for (f = a->fsm; f; f = f->nxt)	/* control states */
+		for (t = f->t; t; t = t->nxt)	/* transitions    */
+		{	if (t->step)
+			switch (t->step->n->ntyp) {
+			case 's':
+				banner |= 1;
+				break;
+			case 'r':
+				banner |= 2;
+				break;
+			case '.':
+			case D_STEP:
+			case ATOMIC:
+			case NON_ATOMIC:
+			case IF:
+			case DO:
+			case UNLESS:
+			case '@':
+			case GOTO:
+			case BREAK:
+			case PRINT:
+			case PRINTM:
+			case ASSERT:
+			case C_CODE:
+			case C_EXPR:
+				break;
+			default:
+				banner |= 4;
+				goto no_good;
+			}
+		}
+no_good:	if (banner == 1 || banner == 2)
+		{	printf("spin: proctype %s defines a %s process\n",
+				a->p->n->name,
+				banner==1?"source":"sink");
+			talked |= banner;
+		} else if (banner == 3)
+		{	printf("spin: proctype %s mimics a buffer\n",
+				a->p->n->name);
+			talked |= 4;
+		}
+	}
+	if (talked&1)
+	{	printf("\tto reduce complexity, consider merging the code of\n");
+		printf("\teach source process into the code of its target\n");
+	}
+	if (talked&2)
+	{	printf("\tto reduce complexity, consider merging the code of\n");
+		printf("\teach sink process into the code of its source\n");
+	}
+	if (talked&4)
+		printf("\tto reduce complexity, avoid buffer processes\n");
+}
+
+static void
+AST_preserve(void)
+{	Slicer *sc, *nx, *rv;
+
+	for (sc = slicer; sc; sc = nx)
+	{	if (!sc->used)
+			break;	/* done */
+
+		nx = sc->nxt;
+
+		for (rv = rel_vars; rv; rv = rv->nxt)
+			if (AST_mutual(sc->n, rv->n, 1))
+				break;
+
+		if (!rv) /* not already there */
+		{	sc->nxt = rel_vars;
+			rel_vars = sc;
+	}	}
+	slicer = sc;
+}
+
+static void
+check_slice(Lextok *n, int code)
+{	Slicer *sc;
+
+	for (sc = slicer; sc; sc = sc->nxt)
+		if (AST_mutual(sc->n, n, 1)
+		&&  sc->code == code)
+			return;	/* already there */
+
+	sc = (Slicer *) emalloc(sizeof(Slicer));
+	sc->n = n;
+
+	sc->code = code;
+	sc->used = 0;
+	sc->nxt = slicer;
+	slicer = sc;
+}
+
+static void
+AST_data_dep(void)
+{	Slicer *sc;
+
+	/* mark all def-relevant transitions */
+	for (sc = slicer; sc; sc = sc->nxt)
+	{	sc->used = 1;
+		if (verbose&32)
+		{	printf("spin: slice criterion ");
+			AST_var(sc->n, sc->n->sym, 1);
+			printf(" type=%d\n", Sym_typ(sc->n));
+		}
+		AST_relevant(sc->n);
+	}
+	AST_tagruns();	/* mark 'run's relevant if target proctype is relevant */
+}
+
+static int
+AST_blockable(AST *a, int s)
+{	FSM_state *f;
+	FSM_trans *t;
+
+	f = fsm_tbl[s];
+
+	for (t = f->t; t; t = t->nxt)
+	{	if (t->relevant&2)
+			return 1;
+
+		if (t->step && t->step->n)
+		switch (t->step->n->ntyp) {
+		case IF:
+		case DO:
+		case ATOMIC:
+		case NON_ATOMIC:
+		case D_STEP:
+			if (AST_blockable(a, t->to))
+			{	t->round = AST_Round;
+				t->relevant |= 2;
+				return 1;
+			}
+			/* else fall through */
+		default:
+			break;
+		}
+		else if (AST_blockable(a, t->to))	/* Unless */
+		{	t->round = AST_Round;
+			t->relevant |= 2;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static void
+AST_spread(AST *a, int s)
+{	FSM_state *f;
+	FSM_trans *t;
+
+	f = fsm_tbl[s];
+
+	for (t = f->t; t; t = t->nxt)
+	{	if (t->relevant&2)
+			continue;
+
+		if (t->step && t->step->n)
+			switch (t->step->n->ntyp) {
+			case IF:
+			case DO:
+			case ATOMIC:
+			case NON_ATOMIC:
+			case D_STEP:
+				AST_spread(a, t->to);
+				/* fall thru */
+			default:
+				t->round = AST_Round;
+				t->relevant |= 2;
+				break;
+			}
+		else	/* Unless */
+		{	AST_spread(a, t->to);
+			t->round = AST_Round;
+			t->relevant |= 2;
+		}
+	}
+}
+
+static int
+AST_notrelevant(Lextok *n)
+{	Slicer *s;
+
+	for (s = rel_vars; s; s = s->nxt)
+		if (AST_mutual(s->n, n, 1))
+			return 0;
+	for (s = slicer; s; s = s->nxt)
+		if (AST_mutual(s->n, n, 1))
+			return 0;
+	return 1;
+}
+
+static int
+AST_withchan(Lextok *n)
+{
+	if (!n) return 0;
+	if (Sym_typ(n) == CHAN)
+		return 1;
+	return AST_withchan(n->lft) || AST_withchan(n->rgt);
+}
+
+static int
+AST_suspect(FSM_trans *t)
+{	FSM_use *u;
+	/* check for possible overkill */
+	if (!t || !t->step || !AST_withchan(t->step->n))
+		return 0;
+	for (u = t->Val[0]; u; u = u->nxt)
+		if (AST_notrelevant(u->n))
+			return 1;
+	return 0;
+}
+
+static void
+AST_shouldconsider(AST *a, int s)
+{	FSM_state *f;
+	FSM_trans *t;
+
+	f = fsm_tbl[s];
+	for (t = f->t; t; t = t->nxt)
+	{	if (t->step && t->step->n)
+			switch (t->step->n->ntyp) {
+			case IF:
+			case DO:
+			case ATOMIC:
+			case NON_ATOMIC:
+			case D_STEP:
+				AST_shouldconsider(a, t->to);
+				break;
+			default:
+				AST_track(t->step->n, 0);
+/*
+	AST_track is called here for a blockable stmnt from which
+	a relevant stmnmt was shown to be reachable
+	for a condition this makes all USEs relevant
+	but for a channel operation it only makes the executability
+	relevant -- in those cases, parameters that aren't already
+	relevant may be replaceable with arbitrary tokens
+ */
+				if (AST_suspect(t))
+				{	printf("spin: possibly redundant parameters in: ");
+					comment(stdout, t->step->n, 0);
+					printf("\n");
+				}
+				break;
+			}
+		else	/* an Unless */
+			AST_shouldconsider(a, t->to);
+	}
+}
+
+static int
+FSM_critical(AST *a, int s)
+{	FSM_state *f;
+	FSM_trans *t;
+
+	/* is a 1-relevant stmnt reachable from this state? */
+
+	f = fsm_tbl[s];
+	if (f->seen)
+		goto done;
+	f->seen = 1;
+	f->cr   = 0;
+	for (t = f->t; t; t = t->nxt)
+		if ((t->relevant&1)
+		||  FSM_critical(a, t->to))
+		{	f->cr = 1;
+
+			if (verbose&32)
+			{	printf("\t\t\t\tcritical(%d) ", t->relevant);
+				comment(stdout, t->step->n, 0);
+				printf("\n");
+			}
+			break;
+		}
+#if 0
+	else {
+		if (verbose&32)
+		{ printf("\t\t\t\tnot-crit ");
+		  comment(stdout, t->step->n, 0);
+	 	  printf("\n");
+		}
+	}
+#endif
+done:
+	return f->cr;
+}
+
+static void
+AST_ctrl(AST *a)
+{	FSM_state *f;
+	FSM_trans *t;
+	int hit;
+
+	/* add all blockable transitions
+	 * from which relevant transitions can be reached
+	 */
+	if (verbose&32)
+		printf("CTL -- %s\n", a->p->n->name);
+
+	/* 1 : mark all blockable edges */
+	for (f = a->fsm; f; f = f->nxt)
+	{	if (!(f->scratch&2))		/* not part of irrelevant subgraph */
+		for (t = f->t; t; t = t->nxt)
+		{	if (t->step && t->step->n)
+			switch (t->step->n->ntyp) {
+			case 'r':
+			case 's':
+			case 'c':
+			case ELSE:
+				t->round = AST_Round;
+				t->relevant |= 2;	/* mark for next phases */
+				if (verbose&32)
+				{	printf("\tpremark ");
+					comment(stdout, t->step->n, 0);
+					printf("\n");
+				}
+				break;
+			default:
+				break;
+	}	}	}
+
+	/* 2: keep only 2-marked stmnts from which 1-marked stmnts can be reached */
+	for (f = a->fsm; f; f = f->nxt)
+	{	fsm_tbl[f->from] = f;
+		f->seen = 0;	/* used in dfs from FSM_critical */
+	}
+	for (f = a->fsm; f; f = f->nxt)
+	{	if (!FSM_critical(a, f->from))
+		for (t = f->t; t; t = t->nxt)
+			if (t->relevant&2)
+			{	t->relevant &= ~2;	/* clear mark */
+				if (verbose&32)
+				{	printf("\t\tnomark ");
+					comment(stdout, t->step->n, 0);
+					printf("\n");
+	}		}	}
+
+	/* 3 : lift marks across IF/DO etc. */
+	for (f = a->fsm; f; f = f->nxt)
+	{	hit = 0;
+		for (t = f->t; t; t = t->nxt)
+		{	if (t->step && t->step->n)
+			switch (t->step->n->ntyp) {
+			case IF:
+			case DO:
+			case ATOMIC:
+			case NON_ATOMIC:
+			case D_STEP:
+				if (AST_blockable(a, t->to))
+					hit = 1;
+				break;
+			default:
+				break;
+			}
+			else if (AST_blockable(a, t->to))	/* Unless */
+				hit = 1;
+
+			if (hit) break;
+		}
+		if (hit)	/* at least one outgoing trans can block */
+		for (t = f->t; t; t = t->nxt)
+		{	t->round = AST_Round;
+			t->relevant |= 2;	/* lift */
+			if (verbose&32)
+			{	printf("\t\t\tliftmark ");
+				comment(stdout, t->step->n, 0);
+				printf("\n");
+			}
+			AST_spread(a, t->to);	/* and spread to all guards */
+	}	}
+
+	/* 4: nodes with 2-marked out-edges contribute new slice criteria */
+	for (f = a->fsm; f; f = f->nxt)
+	for (t = f->t; t; t = t->nxt)
+		if (t->relevant&2)
+		{	AST_shouldconsider(a, f->from);
+			break;	/* inner loop */
+		}
+}
+
+static void
+AST_control_dep(void)
+{	AST *a;
+
+	for (a = ast; a; a = a->nxt)
+		if (strcmp(a->p->n->name, ":never:") != 0
+		&&  strcmp(a->p->n->name, ":trace:") != 0
+		&&  strcmp(a->p->n->name, ":notrace:") != 0)
+			AST_ctrl(a);
+}
+
+static void
+AST_prelabel(void)
+{	AST *a;
+	FSM_state *f;
+	FSM_trans *t;
+
+	for (a = ast; a; a = a->nxt)
+	{	if (strcmp(a->p->n->name, ":never:") != 0
+		&&  strcmp(a->p->n->name, ":trace:") != 0
+		&&  strcmp(a->p->n->name, ":notrace:") != 0)
+		for (f = a->fsm; f; f = f->nxt)
+		for (t = f->t; t; t = t->nxt)
+		{	if (t->step
+			&&  t->step->n
+			&&  t->step->n->ntyp == ASSERT
+			)
+			{	t->relevant |= 1;
+	}	}	}
+}
+
+static void
+AST_criteria(void)
+{	/*
+	 * remote labels are handled separately -- by making
+	 * sure they are not pruned away during optimization
+	 */
+	AST_Changes = 1;	/* to get started */
+	for (AST_Round = 1; slicer && AST_Changes; AST_Round++)
+	{	AST_Changes = 0;
+		AST_data_dep();
+		AST_preserve();		/* moves processed vars from slicer to rel_vars */
+		AST_dominant();		/* mark data-irrelevant subgraphs */
+		AST_control_dep();	/* can add data deps, which add control deps */
+
+		if (verbose&32)
+			printf("\n\nROUND %d -- changes %d\n",
+				AST_Round, AST_Changes);
+	}
+}
+
+static void
+AST_alias_analysis(void)		/* aliasing of promela channels */
+{	AST *a;
+
+	for (a = ast; a; a = a->nxt)
+		AST_sends(a);		/* collect chan-names that are send across chans */
+
+	for (a = ast; a; a = a->nxt)
+		AST_para(a->p);		/* aliasing of chans thru proctype parameters */
+
+	for (a = ast; a; a = a->nxt)
+		AST_other(a);		/* chan params in asgns and recvs */
+
+	AST_trans();			/* transitive closure of alias table */
+
+	if (verbose&32)
+		AST_aliases();		/* show channel aliasing info */
+}
+
+void
+AST_slice(void)
+{	AST *a;
+	int spurious = 0;
+
+	if (!slicer)
+	{	non_fatal("no slice criteria (or no claim) specified",
+		(char *) 0);
+		spurious = 1;
+	}
+	AST_dorelevant();		/* mark procs refered to in remote refs */
+
+	for (a = ast; a; a = a->nxt)
+		AST_def_use(a);		/* compute standard def/use information */
+
+	AST_hidden();			/* parameter passing and local var inits */
+
+	AST_alias_analysis();		/* channel alias analysis */
+
+	AST_prelabel();			/* mark all 'assert(...)' stmnts as relevant */
+	AST_criteria();			/* process the slice criteria from
+					 * asserts and from the never claim
+					 */
+	if (!spurious || (verbose&32))
+	{	spurious = 1;
+		for (a = ast; a; a = a->nxt)
+		{	AST_dump(a);		/* marked up result */
+			if (a->relevant&2)	/* it printed something */
+				spurious = 0;
+		}
+		if (!AST_dump_rel()		/* relevant variables */
+		&&  spurious)
+			printf("spin: no redundancies found (for given property)\n");
+	}
+	AST_suggestions();
+
+	if (verbose&32)
+		show_expl();
+}
+
+void
+AST_store(ProcList *p, int start_state)
+{	AST *n_ast;
+
+	if (strcmp(p->n->name, ":never:") != 0
+	&&  strcmp(p->n->name, ":trace:") != 0
+	&&  strcmp(p->n->name, ":notrace:") != 0)
+	{	n_ast = (AST *) emalloc(sizeof(AST));
+		n_ast->p = p;
+		n_ast->i_st = start_state;
+		n_ast->relevant = 0;
+		n_ast->fsm = fsm;
+		n_ast->nxt = ast;
+		ast = n_ast;
+	}
+	fsm = (FSM_state *) 0;	/* hide it from FSM_DEL */
+}
+
+static void
+AST_add_explicit(Lextok *d, Lextok *u)
+{	FSM_trans *e = (FSM_trans *) emalloc(sizeof(FSM_trans));
+
+	e->to = 0;			/* or start_state ? */
+	e->relevant = 0;		/* to be determined */
+	e->step = (Element *) 0;	/* left blank */
+	e->Val[0] = e->Val[1] = (FSM_use *) 0;
+
+	cur_t = e;
+
+	def_use(u, USE);
+	def_use(d, DEF);
+
+	cur_t = (FSM_trans *) 0;
+
+	e->nxt = explicit;
+	explicit = e;
+}
+
+static void
+AST_fp1(char *s, Lextok *t, Lextok *f, int parno)
+{	Lextok *v;
+	int cnt;
+
+	if (!t) return;
+
+	if (t->ntyp == RUN)
+	{	if (strcmp(t->sym->name, s) == 0)
+		for (v = t->lft, cnt = 1; v; v = v->rgt, cnt++)
+			if (cnt == parno)
+			{	AST_add_explicit(f, v->lft);
+				break;
+			}
+	} else
+	{	AST_fp1(s, t->lft, f, parno);
+		AST_fp1(s, t->rgt, f, parno);
+	}
+}
+
+static void
+AST_mk1(char *s, Lextok *c, int parno)
+{	AST *a;
+	FSM_state *f;
+	FSM_trans *t;
+
+	/* concoct an extra FSM_trans *t with the asgn of
+	 * formal par c to matching actual pars made explicit
+	 */
+
+	for (a = ast; a; a = a->nxt)		/* automata       */
+	for (f = a->fsm; f; f = f->nxt)		/* control states */
+	for (t = f->t; t; t = t->nxt)		/* transitions    */
+	{	if (t->step)
+		AST_fp1(s, t->step->n, c, parno);
+	}
+}
+
+static void
+AST_par_init(void)	/* parameter passing -- hidden assignments */
+{	AST *a;
+	Lextok *f, *t, *c;
+	int cnt;
+
+	for (a = ast; a; a = a->nxt)
+	{	if (strcmp(a->p->n->name, ":never:") == 0
+		||  strcmp(a->p->n->name, ":trace:") == 0
+		||  strcmp(a->p->n->name, ":notrace:") == 0
+		||  strcmp(a->p->n->name, ":init:") == 0)
+			continue;			/* have no params */
+
+		cnt = 0;
+		for (f = a->p->p; f; f = f->rgt)	/* types */
+		for (t = f->lft; t; t = t->rgt)		/* formals */
+		{	cnt++;				/* formal par count */
+			c = (t->ntyp != ',')? t : t->lft;	/* the formal parameter */
+			AST_mk1(a->p->n->name, c, cnt);		/* all matching run statements */
+	}	}
+}
+
+static void
+AST_var_init(void)		/* initialized vars (not chans) - hidden assignments */
+{	Ordered	*walk;
+	Lextok *x;
+	Symbol	*sp;
+	AST *a;
+
+	for (walk = all_names; walk; walk = walk->next)	
+	{	sp = walk->entry;
+		if (sp
+		&&  !sp->context		/* globals */
+		&&  sp->type != PROCTYPE
+		&&  sp->ini
+		&& (sp->type != MTYPE || sp->ini->ntyp != CONST) /* not mtype defs */
+		&&  sp->ini->ntyp != CHAN)
+		{	x = nn(ZN, TYPE, ZN, ZN);
+			x->sym = sp;
+			AST_add_explicit(x, sp->ini);
+	}	}
+
+	for (a = ast; a; a = a->nxt)
+	{	if (strcmp(a->p->n->name, ":never:") != 0
+		&&  strcmp(a->p->n->name, ":trace:") != 0
+		&&  strcmp(a->p->n->name, ":notrace:") != 0)	/* claim has no locals */
+		for (walk = all_names; walk; walk = walk->next)	
+		{	sp = walk->entry;
+			if (sp
+			&&  sp->context
+			&&  strcmp(sp->context->name, a->p->n->name) == 0
+			&&  sp->Nid >= 0	/* not a param */
+			&&  sp->type != LABEL
+			&&  sp->ini
+			&&  sp->ini->ntyp != CHAN)
+			{	x = nn(ZN, TYPE, ZN, ZN);
+				x->sym = sp;
+				AST_add_explicit(x, sp->ini);
+	}	}	}
+}
+
+static void
+show_expl(void)
+{	FSM_trans *t, *T;
+	FSM_use *u;
+
+	printf("\nExplicit List:\n");
+	for (T = expl_par; T; T = (T == expl_par)?expl_var: (FSM_trans *) 0)
+	{	for (t = T; t; t = t->nxt)
+		{	if (!t->Val[0]) continue;
+			printf("%s", t->relevant?"*":" ");
+			printf("%3d", t->round);
+			for (u = t->Val[0]; u; u = u->nxt)
+			{	printf("\t<");
+				AST_var(u->n, u->n->sym, 1);
+				printf(":%d>, ", u->special);
+			}
+			printf("\n");
+		}
+		printf("==\n");
+	}
+	printf("End\n");
+}
+
+static void
+AST_hidden(void)			/* reveal all hidden assignments */
+{
+	AST_par_init();
+	expl_par = explicit;
+	explicit = (FSM_trans *) 0;
+
+	AST_var_init();
+	expl_var = explicit;
+	explicit = (FSM_trans *) 0;
+}
+
+#define BPW	(8*sizeof(ulong))			/* bits per word */
+
+static int
+bad_scratch(FSM_state *f, int upto)
+{	FSM_trans *t;
+#if 0
+	1. all internal branch-points have else-s
+	2. all non-branchpoints have non-blocking out-edge
+	3. all internal edges are non-relevant
+	subgraphs like this need NOT contribute control-dependencies
+#endif
+
+	if (!f->seen
+	||  (f->scratch&4))
+		return 0;
+
+	if (f->scratch&8)
+		return 1;
+
+	f->scratch |= 4;
+
+	if (verbose&32) printf("X[%d:%d:%d] ", f->from, upto, f->scratch);
+
+	if (f->scratch&1)
+	{	if (verbose&32)
+			printf("\tbad scratch: %d\n", f->from);
+bad:		f->scratch &= ~4;
+	/*	f->scratch |=  8;	 wrong */
+		return 1;
+	}
+
+	if (f->from != upto)
+	for (t = f->t; t; t = t->nxt)
+		if (bad_scratch(fsm_tbl[t->to], upto))
+			goto bad;
+
+	return 0;
+}
+
+static void
+mark_subgraph(FSM_state *f, int upto)
+{	FSM_trans *t;
+
+	if (f->from == upto
+	||  !f->seen
+	||  (f->scratch&2))
+		return;
+
+	f->scratch |= 2;
+
+	for (t = f->t; t; t = t->nxt)
+		mark_subgraph(fsm_tbl[t->to], upto);
+}
+
+static void
+AST_pair(AST *a, FSM_state *h, int y)
+{	Pair *p;
+
+	for (p = a->pairs; p; p = p->nxt)
+		if (p->h == h
+		&&  p->b == y)
+			return;
+
+	p = (Pair *) emalloc(sizeof(Pair));
+	p->h = h;
+	p->b = y;
+	p->nxt = a->pairs;
+	a->pairs = p;
+}
+
+static void
+AST_checkpairs(AST *a)
+{	Pair *p;
+
+	for (p = a->pairs; p; p = p->nxt)
+	{	if (verbose&32)
+			printf("	inspect pair %d %d\n", p->b, p->h->from);
+		if (!bad_scratch(p->h, p->b))	/* subgraph is clean */
+		{	if (verbose&32)
+				printf("subgraph: %d .. %d\n", p->b, p->h->from);
+			mark_subgraph(p->h, p->b);
+		}
+	}
+}
+
+static void
+subgraph(AST *a, FSM_state *f, int out)
+{	FSM_state *h;
+	int i, j;
+	ulong *g;
+#if 0
+	reverse dominance suggests that this is a possible
+	entry and exit node for a proper subgraph
+#endif
+	h = fsm_tbl[out];
+
+	i = f->from / BPW;
+	j = f->from % BPW;
+	g = h->mod;
+
+	if (verbose&32)
+		printf("possible pair %d %d -- %d\n",
+			f->from, h->from, (g[i]&(1<<j))?1:0);
+	
+	if (g[i]&(1<<j))		/* also a forward dominance pair */
+		AST_pair(a, h, f->from);	/* record this pair */
+}
+
+static void
+act_dom(AST *a)
+{	FSM_state *f;
+	FSM_trans *t;
+	int i, j, cnt;
+
+	for (f = a->fsm; f; f = f->nxt)
+	{	if (!f->seen) continue;
+#if 0
+		f->from is the exit-node of a proper subgraph, with
+		the dominator its entry-node, if:
+		a. this node has more than 1 reachable predecessor
+		b. the dominator has more than 1 reachable successor
+		   (need reachability - in case of reverse dominance)
+		d. the dominator is reachable, and not equal to this node
+#endif
+		for (t = f->p, i = 0; t; t = t->nxt)
+			i += fsm_tbl[t->to]->seen;
+		if (i <= 1) continue;					/* a. */
+
+		for (cnt = 1; cnt < a->nstates; cnt++)	/* 0 is endstate */
+		{	if (cnt == f->from
+			||  !fsm_tbl[cnt]->seen)
+				continue;				/* c. */
+
+			i = cnt / BPW;
+			j = cnt % BPW;
+			if (!(f->dom[i]&(1<<j)))
+				continue;
+
+			for (t = fsm_tbl[cnt]->t, i = 0; t; t = t->nxt)
+				i += fsm_tbl[t->to]->seen;
+			if (i <= 1)
+				continue;				/* b. */
+
+			if (f->mod)			/* final check in 2nd phase */
+				subgraph(a, f, cnt);	/* possible entry-exit pair */
+		}
+	}
+}
+
+static void
+reachability(AST *a)
+{	FSM_state *f;
+
+	for (f = a->fsm; f; f = f->nxt)
+		f->seen = 0;		/* clear */
+	AST_dfs(a, a->i_st, 0);		/* mark 'seen' */
+}
+
+static int
+see_else(FSM_state *f)
+{	FSM_trans *t;
+
+	for (t = f->t; t; t = t->nxt)
+	{	if (t->step
+		&&  t->step->n)
+		switch (t->step->n->ntyp) {
+		case ELSE:
+			return 1;
+		case IF:
+		case DO:
+		case ATOMIC:
+		case NON_ATOMIC:
+		case D_STEP:
+			if (see_else(fsm_tbl[t->to]))
+				return 1;
+		default:
+			break;
+		}
+	}
+	return 0;
+}
+
+static int
+is_guard(FSM_state *f)
+{	FSM_state *g;
+	FSM_trans *t;
+
+	for (t = f->p; t; t = t->nxt)
+	{	g = fsm_tbl[t->to];
+		if (!g->seen)
+			continue;
+
+		if (t->step
+		&&  t->step->n)
+		switch(t->step->n->ntyp) {
+		case IF:
+		case DO:
+			return 1;
+		case ATOMIC:
+		case NON_ATOMIC:
+		case D_STEP:
+			if (is_guard(g))
+				return 1;
+		default:
+			break;
+		}
+	}
+	return 0;
+}
+
+static void
+curtail(AST *a)
+{	FSM_state *f, *g;
+	FSM_trans *t;
+	int i, haselse, isrel, blocking;
+#if 0
+	mark nodes that do not satisfy these requirements:
+	1. all internal branch-points have else-s
+	2. all non-branchpoints have non-blocking out-edge
+	3. all internal edges are non-data-relevant
+#endif
+	if (verbose&32)
+		printf("Curtail %s:\n", a->p->n->name);
+
+	for (f = a->fsm; f; f = f->nxt)
+	{	if (!f->seen
+		||  (f->scratch&(1|2)))
+			continue;
+
+		isrel = haselse = i = blocking = 0;
+
+		for (t = f->t; t; t = t->nxt)
+		{	g = fsm_tbl[t->to];
+
+			isrel |= (t->relevant&1);	/* data relevant */
+			i += g->seen;
+
+			if (t->step
+			&&  t->step->n)
+			{	switch (t->step->n->ntyp) {
+				case IF:
+				case DO:
+					haselse |= see_else(g);
+					break;
+				case 'c':
+				case 's':
+				case 'r':
+					blocking = 1;
+					break;
+		}	}	}
+#if 0
+		if (verbose&32)
+			printf("prescratch %d -- %d %d %d %d -- %d\n",
+				f->from, i, isrel, blocking, haselse, is_guard(f));
+#endif
+		if (isrel			/* 3. */		
+		||  (i == 1 && blocking)	/* 2. */
+		||  (i >  1 && !haselse))	/* 1. */
+		{	if (!is_guard(f))
+			{	f->scratch |= 1;
+				if (verbose&32)
+				printf("scratch %d -- %d %d %d %d\n",
+					f->from, i, isrel, blocking, haselse);
+			}
+		}
+	}
+}
+
+static void
+init_dom(AST *a)
+{	FSM_state *f;
+	int i, j, cnt;
+#if 0
+	(1)  D(s0) = {s0}
+	(2)  for s in S - {s0} do D(s) = S
+#endif
+
+	for (f = a->fsm; f; f = f->nxt)
+	{	if (!f->seen) continue;
+
+		f->dom = (ulong *)
+			emalloc(a->nwords * sizeof(ulong));
+
+		if (f->from == a->i_st)
+		{	i = a->i_st / BPW;
+			j = a->i_st % BPW;
+			f->dom[i] = (1<<j);			/* (1) */
+		} else						/* (2) */
+		{	for (i = 0; i < a->nwords; i++)
+				f->dom[i] = (ulong) ~0;			/* all 1's */
+
+			if (a->nstates % BPW)
+			for (i = a->nstates % BPW; i < BPW; i++)
+				f->dom[a->nwords-1] &= ~(1<<i);	/* clear tail */
+
+			for (cnt = 0; cnt < a->nstates; cnt++)
+				if (!fsm_tbl[cnt]->seen)
+				{	i = cnt / BPW;
+					j = cnt % BPW;
+					f->dom[i] &= ~(1<<j);
+	}	}		}
+}
+
+static int
+dom_perculate(AST *a, FSM_state *f)
+{	static ulong *ndom = (ulong *) 0;
+	static int on = 0;
+	int i, j, cnt = 0;
+	FSM_state *g;
+	FSM_trans *t;
+
+	if (on < a->nwords)
+	{	on = a->nwords;
+		ndom = (ulong *)
+			emalloc(on * sizeof(ulong));
+	}
+
+	for (i = 0; i < a->nwords; i++)
+		ndom[i] = (ulong) ~0;
+
+	for (t = f->p; t; t = t->nxt)	/* all reachable predecessors */
+	{	g = fsm_tbl[t->to];
+		if (g->seen)
+		for (i = 0; i < a->nwords; i++)
+			ndom[i] &= g->dom[i];	/* (5b) */
+	}
+
+	i = f->from / BPW;
+	j = f->from % BPW;
+	ndom[i] |= (1<<j);			/* (5a) */
+
+	for (i = 0; i < a->nwords; i++)
+		if (f->dom[i] != ndom[i])
+		{	cnt++;
+			f->dom[i] = ndom[i];
+		}
+
+	return cnt;
+}
+
+static void
+dom_forward(AST *a)
+{	FSM_state *f;
+	int cnt;
+
+	init_dom(a);						/* (1,2) */
+	do {
+		cnt = 0;
+		for (f = a->fsm; f; f = f->nxt)
+		{	if (f->seen
+			&&  f->from != a->i_st)			/* (4) */
+				cnt += dom_perculate(a, f);	/* (5) */
+		}
+	} while (cnt);						/* (3) */
+	dom_perculate(a, fsm_tbl[a->i_st]);
+}
+
+static void
+AST_dominant(void)
+{	FSM_state *f;
+	FSM_trans *t;
+	AST *a;
+	int oi;
+#if 0
+	find dominators
+	Aho, Sethi, & Ullman, Compilers - principles, techniques, and tools
+	Addison-Wesley, 1986, p.671.
+
+	(1)  D(s0) = {s0}
+	(2)  for s in S - {s0} do D(s) = S
+
+	(3)  while any D(s) changes do
+	(4)    for s in S - {s0} do
+	(5)	D(s) = {s} union  with intersection of all D(p)
+		where p are the immediate predecessors of s
+
+	the purpose is to find proper subgraphs
+	(one entry node, one exit node)
+#endif
+	if (AST_Round == 1)	/* computed once, reused in every round */
+	for (a = ast; a; a = a->nxt)
+	{	a->nstates = 0;
+		for (f = a->fsm; f; f = f->nxt)
+		{	a->nstates++;				/* count */
+			fsm_tbl[f->from] = f;			/* fast lookup */
+			f->scratch = 0;				/* clear scratch marks */
+		}
+		for (oi = 0; oi < a->nstates; oi++)
+			if (!fsm_tbl[oi])
+				fsm_tbl[oi] = &no_state;
+
+		a->nwords = (a->nstates + BPW - 1) / BPW;	/* round up */
+
+		if (verbose&32)
+		{	printf("%s (%d): ", a->p->n->name, a->i_st);
+			printf("states=%d (max %d), words = %d, bpw %d, overflow %d\n",
+				a->nstates, o_max, a->nwords,
+				(int) BPW, (int) (a->nstates % BPW));
+		}
+
+		reachability(a);
+		dom_forward(a);		/* forward dominance relation */
+
+		curtail(a);		/* mark ineligible edges */
+		for (f = a->fsm; f; f = f->nxt)
+		{	t = f->p;
+			f->p = f->t;
+			f->t = t;	/* invert edges */
+
+			f->mod = f->dom;
+			f->dom = (ulong *) 0;
+		}
+		oi = a->i_st;
+		if (fsm_tbl[0]->seen)	/* end-state reachable - else leave it */
+			a->i_st = 0;	/* becomes initial state */
+	
+		dom_forward(a);		/* reverse dominance -- don't redo reachability! */
+		act_dom(a);		/* mark proper subgraphs, if any */
+		AST_checkpairs(a);	/* selectively place 2 scratch-marks */
+
+		for (f = a->fsm; f; f = f->nxt)
+		{	t = f->p;
+			f->p = f->t;
+			f->t = t;	/* restore */
+		}
+		a->i_st = oi;	/* restore */
+	} else
+		for (a = ast; a; a = a->nxt)
+		{	for (f = a->fsm; f; f = f->nxt)
+			{	fsm_tbl[f->from] = f;
+				f->scratch &= 1; /* preserve 1-marks */
+			}
+			for (oi = 0; oi < a->nstates; oi++)
+				if (!fsm_tbl[oi])
+					fsm_tbl[oi] = &no_state;
+
+			curtail(a);		/* mark ineligible edges */
+
+			for (f = a->fsm; f; f = f->nxt)
+			{	t = f->p;
+				f->p = f->t;
+				f->t = t;	/* invert edges */
+			}
+	
+			AST_checkpairs(a);	/* recompute 2-marks */
+
+			for (f = a->fsm; f; f = f->nxt)
+			{	t = f->p;
+				f->p = f->t;
+				f->t = t;	/* restore */
+		}	}
+}

+ 32 - 19
sys/src/cmd/spin/pc_zpp.c

@@ -1,13 +1,16 @@
 /***** spin: pc_zpp.c *****/
 
-/* Copyright (c) 1997-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann, gerard@research.bell-labs.com  */
-/* pc_zpp.c is only used in the PC version of Spin, to avoid too great a  */
-/* reliance on the cpp command.                                           */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
+
+/* pc_zpp.c is only used in the PC version of Spin                        */
+/* it is included to avoid too great a reliance on an external cpp        */
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -20,16 +23,17 @@ enum cstate { PLAIN, IN_STRING, IN_QUOTE, S_COMM, COMMENT, E_COMM };
 #define MAXNEST	32
 #define MAXDEF	128
 #define MAXLINE	512
+#define GENEROUS 4096
 
 #define debug(x,y)	if (verbose) printf(x,y)
 
-static FILE *outpp = stdout;
+static FILE *outpp /* = stdout */;
 
 static int if_truth[MAXNEST];
 static int printing[MAXNEST];
 static int if_depth, nr_defs, verbose = 0;
 static enum cstate state = PLAIN;
-static char Out1[4096], Out2[4096];
+static char Out1[GENEROUS], Out2[GENEROUS];
 
 static struct Defines {
 	int exists;
@@ -39,6 +43,8 @@ static struct Defines {
 static int process(char *, int, char *);
 static int zpp_do(char *);
 
+extern char *emalloc(int);	/* main.c */
+
 static int
 do_define(char *p)
 {	char *q, *r, *s;
@@ -73,8 +79,8 @@ do_define(char *p)
 adddef:		for (j = 0; j < nr_defs; j++)
 			if (!strcmp(d[j].src, q))
 				d[j].exists = 0;
-		d[nr_defs].src = malloc(strlen(q)+1);
-		d[nr_defs].trg = malloc(strlen(s)+1);
+		d[nr_defs].src = emalloc(strlen(q)+1);
+		d[nr_defs].trg = emalloc(strlen(s)+1);
 		strcpy(d[nr_defs].src, q);
 		strcpy(d[nr_defs].trg, s);
 		d[nr_defs++].exists = 1;
@@ -98,7 +104,7 @@ apply(char *p0)
 
 	for (i = nr_defs-1; i >= 0; i--)
 	{	if (!d[i].exists) continue;
-		j = strlen(d[i].src);
+		j = (int) strlen(d[i].src);
 more:		in2 = strstr(startat, d[i].src);
 		if (!in2)	/* no more matches */
 		{	startat = in1;
@@ -107,6 +113,13 @@ more:		in2 = strstr(startat, d[i].src);
 		if ((in2 == in1 || !isvalid(*(in2-1)))
 		&&  (in2+j == '\0' || !isvalid(*(in2+j))))
 		{	*in2 = '\0';
+
+			if (strlen(in1)+strlen(d[i].trg)+strlen(in2+j) >= GENEROUS)
+			{
+				printf("spin: circular macro expansion %s -> %s ?\n",
+					d[i].src, d[i].trg);
+				return in1;
+			}
 			strcat(out, in1);
 			strcat(out, d[i].trg);
 			strcat(out, in2+j);
@@ -217,7 +230,7 @@ do_if(char *p)
 }
 
 static int
-do_else(char *p)
+do_else(char *unused)
 {
 	if_truth[if_depth] = 1-if_truth[if_depth];
 	printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
@@ -304,13 +317,13 @@ zpp_do(char *fnm)
 	FILE *inp; int lno = 0, nw_lno = 0;
 
 	if ((inp = fopen(fnm, "r")) == NULL)
-	{	debug("error: cannot open %s\n", fnm);
-		return 0;
+	{	fprintf(stdout, "spin: error, '%s': No such file\n", fnm);
+		return 0;	/* 4.1.2 was stderr */
 	}
 	printing[0] = if_truth[0] = 1;
 	fprintf(outpp, "#line %d \"%s\"\n", lno+1, fnm);
 	while (fgets(buf, MAXLINE, inp))
-	{	lno++; n = strlen(buf);
+	{	lno++; n = (int) strlen(buf);
 		on = 0; nw_lno = 0;
 		while (n > 2 && buf[n-2] == '\\')
 		{	buf[n-2] = '\0';
@@ -324,7 +337,7 @@ feedme:			if (!fgets(buf2, MAXLINE, inp))
 				return 0;
 			}
 			strcat(buf, buf2);
-			n = strlen(buf);
+			n = (int) strlen(buf);
 		}
 		if (in_comment(&buf[on]))
 		{	buf[n-1] = '\0'; /* eat newline */
@@ -348,8 +361,8 @@ int
 try_zpp(char *fnm, char *onm)
 {	int r;
 	if ((outpp = fopen(onm, "w")) == NULL)
-		return 0;
-	r = zpp_do(fnm);
+		return 0;
+	r = zpp_do(fnm);
 	fclose(outpp);
 	return r;	/* 1 = ok; 0 = use cpp */
 }

+ 42 - 31
sys/src/cmd/spin/ps_msc.c

@@ -1,10 +1,13 @@
 /***** spin: ps_msc.c *****/
 
-/* Copyright (c) 1997-2000 by Lucent Technologies - Bell Laboratories.    */
+/* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 /* The Postscript generation code below was written by Gerard J. Holzmann */
 /* in June 1997. Parts of the prolog template are based on similar boiler */
@@ -14,6 +17,10 @@
 #include "spin.h"
 #include "version.h"
 
+#ifdef PC
+extern void free(void *);
+#endif
+
 static char *PsPre[] = {
 	"%%%%Pages: (atend)",
 	"%%%%PageOrder: Ascend",
@@ -121,10 +128,10 @@ static char	**L;		/* text labels */
 static char	*ProcLine;	/* active processes */
 static int	pspno = 0;	/* postscript page */
 static int	ldepth = 1;
-static int	maxx, TotSteps = 4096; /* max nr of steps, about 40 pages */
+static int	maxx, TotSteps = 2*4096; /* max nr of steps, about 40 pages */
 static float	Scaler = (float) 1.0;
 
-extern int	nproc, nstop, ntrail, s_trail, pno, depth;
+extern int	ntrail, s_trail, pno, depth;
 extern Symbol	*oFname;
 extern void	exit(int);
 void putpages(void);
@@ -151,7 +158,7 @@ startpage(void)
 	fprintf(pfd, "%%%%Page: %d %d\n", pspno, pspno);
 	putlegend();
 
-	for (i = 255; i >= 0; i--)
+	for (i = TotSteps-1; i >= 0; i--)
 	{	if (!I[i]) continue;
 		spitbox(i, RH, -PH, I[i]);
 	}
@@ -161,11 +168,7 @@ startpage(void)
 	fprintf(pfd, "%d %d lineto\n", RH+MW, LH+oMH+5);
 	fprintf(pfd, "%d %d lineto\n", RH+MW, LH);
 	fprintf(pfd, "10 %d lineto\n", LH);
-#if 0
-	fprintf(pfd, "closepath\n");
-#else
 	fprintf(pfd, "closepath clip newpath\n");
-#endif
 	fprintf(pfd, "%f %f translate\n",
 		(float) RH, (float) LH);
 	memset(ProcLine, 0, 256*sizeof(char));
@@ -189,9 +192,9 @@ putprelude(void)
 
 	if (s_trail)
 	{	if (ntrail)
-		sprintf(snap, "%s%d.trail", oFname->name, ntrail);
+		sprintf(snap, "%s%d.trail", oFname?oFname->name:"msc", ntrail);
 		else
-		sprintf(snap, "%s.trail", oFname->name);
+		sprintf(snap, "%s.trail", oFname?oFname->name:"msc");
 		if (!(fd = fopen(snap, "r")))
 		{	snap[strlen(snap)-2] = '\0';
 			if (!(fd = fopen(snap, "r")))
@@ -206,8 +209,8 @@ putprelude(void)
 	M = (short *) emalloc(TotSteps * sizeof(short));
 	T = (short *) emalloc(TotSteps * sizeof(short));
 	L = (char **) emalloc(TotSteps * sizeof(char *));
-	I = (char **) emalloc(256 * sizeof(char *));
-	ProcLine = (char *) emalloc(256 * sizeof(char));
+	I = (char **) emalloc(TotSteps * sizeof(char *));
+	ProcLine = (char *) emalloc(1024 * sizeof(char));
 	startpage();
 }
 
@@ -226,13 +229,10 @@ putpostlude(void)
 }
 void
 psline(int x0, int iy0, int x1, int iy1, float r, float g, float b, int w)
-{
-	int y0 = MH-iy0;
+{	int y0 = MH-iy0;
 	int y1 = MH-iy1;
-	int dx = 5;
 
 	if (y1 > y0) y1 -= MH;
-	if (x0 > x1) dx = -5;
 
 	fprintf(pfd, "gsave\n");
 	fprintf(pfd, "%d %d moveto\n", x0*WW, y0);
@@ -268,13 +268,15 @@ putgrid(int p)
 }
 
 void
-putarrow(int from, int to) { T[D[from]] = D[to]; }
+putarrow(int from, int to)
+{
+	T[D[from]] = D[to];
+}
 
 void
 stepnumber(int i)
 {	int y = MH-(i*HH)%MH;
 
-/*	if (y == MH) y -= 5; */
 	fprintf(pfd, "gsave\n");
 	fprintf(pfd, "/Courier-Bold findfont 6 scalefont ");
 	fprintf(pfd, "ISOEncode setfont\n");
@@ -318,11 +320,11 @@ spitbox(int x, int dx, int y, char *s)
 	} else
 	{	r = (float) 1.; g = (float) 1.; b = (float) 0.;
 		if (!dx
-		&&  sscanf(s, "%d:%s", &a, &d) == 2
-		&&  a >= 0 && a <= 255)
+		&&  sscanf(s, "%d:%s", &a, d) == 2	/* was &d */
+		&&  a >= 0 && a < TotSteps)
 		{	if (!I[a]
 			||  strlen(I[a]) <= strlen(s))
-				I[a] = emalloc(strlen(s)+1);
+				I[a] = emalloc((int) strlen(s)+1);
 			strcpy(I[a], s);
 	}	}
 	colbox(x*WW+dx, MH-(y*HH)%MH, (int) bw, 4, r,g,b);
@@ -338,7 +340,6 @@ spitbox(int x, int dx, int y, char *s)
 void
 putpages(void)
 {	int i, lasti=0; float nmh;
-/*	extern int free(void *); */
 
 	if (maxx*WW > MW-RH/2)
 	{	Scaler = (float) (MW-RH/2) / (float) (maxx*WW);
@@ -346,7 +347,7 @@ putpages(void)
 		nmh = (float) MH; nmh /= Scaler; MH = (int) nmh;
 	}
 
-	for (i = 255; i >= 0; i--)
+	for (i = TotSteps-1; i >= 0; i--)
 	{	if (!I[i]) continue;
 		spitbox(i, 0, 0, I[i]);
 	}
@@ -397,7 +398,7 @@ putbox(int x)
 {
 	if (ldepth >= TotSteps)
 	{	putpostlude();
-		fprintf(stderr, "max length of %d steps exceeded",
+		fprintf(stderr, "max length of %d steps exceeded\n",
 			TotSteps);
 		fatal("postscript file truncated", (char *) 0);
 	}
@@ -407,13 +408,19 @@ putbox(int x)
 
 void
 pstext(int x, char *s)
-{	char *tmp = emalloc(strlen(s)+1);
+{	char *tmp = emalloc((int) strlen(s)+1);
 
 	strcpy(tmp, s);
 	if (depth == 0)
 		I[x] = tmp;
 	else
 	{	putbox(x);
+		if (depth >= TotSteps || ldepth >= TotSteps)
+		{	fprintf(stderr, "max nr of %d steps exceeded\n",
+				TotSteps);
+			fatal("aborting", (char *) 0);
+		}
+
 		D[depth] = ldepth;
 		R[ldepth] = depth;
 		L[ldepth] = tmp;
@@ -423,15 +430,19 @@ pstext(int x, char *s)
 
 void
 dotag(FILE *fd, char *s)
-{	extern int columns; extern RunList *X;
+{	extern int columns, notabs; extern RunList *X;
 	int i = (!strncmp(s, "MSC: ", 5))?5:0;
 	int pid = s_trail ? pno : (X?X->pid:0);
 
 	if (columns == 2)
 		pstext(pid, &s[i]);
 	else
-	{	for (i = 0; i < pid; i++)
-			printf("\t");
+	{	if (!notabs)
+		{	printf("  ");
+			for (i = 0; i <= pid; i++)
+				printf("    ");
+		}
 		fprintf(fd, "%s", s);
+		fflush(fd);
 	}
 }

+ 140 - 0
sys/src/cmd/spin/reprosrc.c

@@ -0,0 +1,140 @@
+/***** spin: reprosrc.c *****/
+
+/* Copyright (c) 2002-2003 by Lucent Technologies, Bell Laboratories.     */
+/* All Rights Reserved.  This software is for educational purposes only.  */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
+
+#include <stdio.h>
+#include "spin.h"
+#ifdef PC
+#include "y_tab.h"
+#else
+#include "y.tab.h"
+#endif
+
+static int indent = 1;
+
+extern ProcList	*rdy;
+void repro_seq(Sequence *);
+
+void
+doindent(void)
+{	int i;
+	for (i = 0; i < indent; i++)
+		printf("   ");
+}
+
+void
+repro_sub(Element *e)
+{
+	doindent();
+	switch (e->n->ntyp) {
+	case D_STEP:
+		printf("d_step {\n");
+		break;
+	case ATOMIC:
+		printf("atomic {\n");
+		break;
+	case NON_ATOMIC:
+		printf(" {\n");
+		break;
+	}
+	indent++;
+	repro_seq(e->n->sl->this);
+	indent--;
+
+	doindent();
+	printf(" };\n");
+}
+
+void
+repro_seq(Sequence *s)
+{	Element *e;
+	Symbol *v;
+	SeqList *h;
+
+	for (e = s->frst; e; e = e->nxt)
+	{
+		v = has_lab(e, 0);
+		if (v) printf("%s:\n", v->name);
+
+		if (e->n->ntyp == UNLESS)
+		{	printf("/* normal */ {\n");
+			repro_seq(e->n->sl->this);
+			doindent();
+			printf("} unless {\n");
+			repro_seq(e->n->sl->nxt->this);
+			doindent();
+			printf("}; /* end unless */\n");
+		} else if (e->sub)
+		{
+			switch (e->n->ntyp) {
+			case DO: doindent(); printf("do\n"); indent++; break;
+			case IF: doindent(); printf("if\n"); indent++; break;
+			}
+
+			for (h = e->sub; h; h = h->nxt)
+			{	indent--; doindent(); indent++; printf("::\n");
+				repro_seq(h->this);
+				printf("\n");
+			}
+
+			switch (e->n->ntyp) {
+			case DO: indent--; doindent(); printf("od;\n"); break;
+			case IF: indent--; doindent(); printf("fi;\n"); break;
+			}
+		} else
+		{	if (e->n->ntyp == ATOMIC
+			||  e->n->ntyp == D_STEP
+			||  e->n->ntyp == NON_ATOMIC)
+				repro_sub(e);
+			else if (e->n->ntyp != '.'
+			     &&  e->n->ntyp != '@'
+			     &&  e->n->ntyp != BREAK)
+			{
+				doindent();
+				if (e->n->ntyp == C_CODE)
+				{	printf("c_code ");
+					plunk_inline(stdout, e->n->sym->name, 1);
+				} else if (e->n->ntyp == 'c'
+				       &&  e->n->lft->ntyp == C_EXPR)
+				{	printf("c_expr { ");
+					plunk_expr(stdout, e->n->lft->sym->name);
+					printf("} ->\n");
+				} else
+				{	comment(stdout, e->n, 0);
+					printf(";\n");
+			}	}
+		}
+		if (e == s->last)
+			break;
+	}
+}
+
+void
+repro_proc(ProcList *p)
+{
+	if (!p) return;
+	if (p->nxt) repro_proc(p->nxt);
+
+	if (p->det) printf("D");	/* deterministic */
+	printf("proctype %s()", p->n->name);
+	if (p->prov)
+	{	printf(" provided ");
+		comment(stdout, p->prov, 0);
+	}
+	printf("\n{\n");
+	repro_seq(p->s);
+	printf("}\n");
+}
+
+void
+repro_src(void)
+{
+	repro_proc(rdy);
+}

+ 73 - 23
sys/src/cmd/spin/run.c

@@ -1,14 +1,13 @@
 /***** spin: run.c *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 #include <stdlib.h>
 #include "spin.h"
@@ -52,7 +51,7 @@ rev_escape(SeqList *e)
 	if (!e)
 		return (Element *) 0;
 
-	if (r = rev_escape(e->nxt)) /* reversed order */
+	if ((r = rev_escape(e->nxt)) != ZE) /* reversed order */
 		return r;
 
 	return eval_sub(e->this->frst);		
@@ -84,7 +83,7 @@ eval_sub(Element *e)
 	} else if (e->sub)	/* true for IF, DO, and UNLESS */
 	{	Element *has_else = ZE;
 		Element *bas_else = ZE;
-		int nr_else, nr_choices = 0;
+		int nr_else = 0, nr_choices = 0;
 
 		if (interactive
 		&& !MadeChoice && !E_Check
@@ -174,8 +173,21 @@ eval_sub(Element *e)
 					continue;
 				}
 			}
+			if (z->this->frst
+			&&  ((z->this->frst->n->ntyp == ATOMIC
+			  ||  z->this->frst->n->ntyp == D_STEP)
+			  &&  z->this->frst->n->sl->this->frst->n->ntyp == ELSE))
+			{	bas_else = z->this->frst->n->sl->this->frst;
+				has_else = (Rvous)?ZE:bas_else->nxt;
+				if (!interactive || depth < jumpsteps
+				|| Escape_Check
+				|| (e->status&(D_ATOM)))
+				{	z = (z->nxt)?z->nxt:e->sub;
+					continue;
+				}
+			}
 			if (i >= k)
-			{	if (f = eval_sub(z->this->frst))
+			{	if ((f = eval_sub(z->this->frst)) != ZE)
 					return f;
 				else if (interactive && depth >= jumpsteps
 				&& !(e->status&(D_ATOM)))
@@ -222,11 +234,13 @@ eval_sub(Element *e)
 				}
 				printf("\n");
 			}
-
+#if 0
 			if (!(e->status & D_ATOM))	/* escapes don't reach inside d_steps */
+			/* 4.2.4: only the guard of a d_step can have an escape */
+#endif
 			{	Escape_Check++;
 				if (like_java)
-				{	if (g = rev_escape(e->esc))
+				{	if ((g = rev_escape(e->esc)) != ZE)
 					{	if (verbose&4)
 							printf("\tEscape taken\n");
 						Escape_Check--;
@@ -234,7 +248,7 @@ eval_sub(Element *e)
 					}
 				} else
 				{	for (x = e->esc; x; x = x->nxt)
-					{	if (g = eval_sub(x->this->frst))
+					{	if ((g = eval_sub(x->this->frst)) != ZE)
 						{	if (verbose&4)
 								printf("\tEscape taken\n");
 							Escape_Check--;
@@ -245,7 +259,8 @@ eval_sub(Element *e)
 		
 			switch (e->n->ntyp) {
 			case TIMEOUT: case RUN:
-			case PRINT:
+			case PRINT: case PRINTM:
+			case C_CODE: case C_EXPR:
 			case ASGN: case ASSERT:
 			case 's': case 'r': case 'c':
 				/* toplevel statements only */
@@ -350,7 +365,7 @@ eval(Lextok *now)
 	case   '?': return (eval(now->lft) ? eval(now->rgt->lft)
 					   : eval(now->rgt->rgt));
 
-	case     'p': return remotevar(now);	/* only _p allowed */
+	case     'p': return remotevar(now);	/* _p for remote reference */
 	case     'q': return remotelab(now);
 	case     'R': return qrecv(now, 0);	/* test only    */
 	case     LEN: return qlen(now);
@@ -372,7 +387,18 @@ eval(Lextok *now)
 	case   'r': return qrecv(now, 1);	/* receive or poll */
 	case   'c': return eval(now->lft);	/* condition    */
 	case PRINT: return TstOnly?1:interprint(stdout, now);
+	case PRINTM: return TstOnly?1:printm(stdout, now);
 	case  ASGN: return assign(now);
+
+	case C_CODE: printf("%s:\t", now->sym->name);
+		     plunk_inline(stdout, now->sym->name, 0);
+		     return 1; /* uninterpreted */
+
+	case C_EXPR: printf("%s:\t", now->sym->name);
+		     plunk_expr(stdout, now->sym->name);
+		     printf("\n");
+		     return 1; /* uninterpreted */
+
 	case ASSERT: if (TstOnly || eval(now->lft)) return 1;
 		     non_fatal("assertion violated", (char *) 0);
 			printf("spin: text of failed assertion: assert(");
@@ -392,6 +418,25 @@ eval(Lextok *now)
 	return 0;
 }
 
+int
+printm(FILE *fd, Lextok *n)
+{	extern char Buf[];
+	int j;
+
+	Buf[0] = '\0';
+	if (!no_print)
+	if (!s_trail || depth >= jumpsteps) {
+		if (n->lft->ismtyp)
+			j = n->lft->val;
+		else
+			j = eval(n->lft);
+		Buf[0] = '\0';
+		sr_buf(j, 1);
+		dotag(fd, Buf);
+	}
+	return 1;
+}
+
 int
 interprint(FILE *fd, Lextok *n)
 {	Lextok *tmp = n->lft;
@@ -465,22 +510,24 @@ Enabled1(Lextok *n)
 		/* else fall through */
 	default:	/* side-effect free */
 		verbose = 0;
-E_Check++;
+		E_Check++;
 		i = eval(n);
-E_Check--;
+		E_Check--;
 		verbose = v;
 		return i;
 
-	case PRINT: case  ASGN: case ASSERT:
+	case C_CODE: case C_EXPR:
+	case PRINT: case PRINTM:
+	case   ASGN: case ASSERT:
 		return 1;
 
 	case 's':
 		if (q_is_sync(n))
 		{	if (Rvous) return 0;
 			TstOnly = 1; verbose = 0;
-E_Check++;
+			E_Check++;
 			i = eval(n);
-E_Check--;
+			E_Check--;
 			TstOnly = 0; verbose = v;
 			return i;
 		}
@@ -489,9 +536,9 @@ E_Check--;
 		if (q_is_sync(n))
 			return 0;	/* it's never a user-choice */
 		n->ntyp = 'R'; verbose = 0;
-E_Check++;
+		E_Check++;
 		i = eval(n);
-E_Check--;
+		E_Check--;
 		n->ntyp = 'r'; verbose = v;
 		return i;
 	}
@@ -545,6 +592,9 @@ pc_enabled(Lextok *n)
 	int result = 0;
 	RunList *Y, *oX;
 
+	if (pid == X->pid)
+		fatal("used: enabled(pid=thisproc) [%s]", X->n->name);
+
 	for (Y = run; Y; Y = Y->nxt)
 		if (--i == pid)
 		{	oX = X; X = Y;

+ 171 - 79
sys/src/cmd/spin/sched.c

@@ -1,14 +1,13 @@
 /***** spin: sched.c *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 #include <stdlib.h>
 #include "spin.h"
@@ -23,8 +22,9 @@ extern char	*claimproc, *eventmap, Buf[];
 extern Ordered	*all_names;
 extern Symbol	*Fname, *context;
 extern int	lineno, nr_errs, dumptab, xspin, jumpsteps, columns;
-extern int	u_sync, Elcnt, interactive, TstOnly;
-extern short	has_enabled, has_provided;
+extern int	u_sync, Elcnt, interactive, TstOnly, cutoff;
+extern short	has_enabled;
+extern int	limited_vis;
 
 RunList		*X   = (RunList  *) 0;
 RunList		*run = (RunList  *) 0;
@@ -46,11 +46,20 @@ runnable(ProcList *p, int weight, int noparams)
 
 	r->n  = p->n;
 	r->tn = p->tn;
-	r->pid = ++nproc-nstop-1;
-	r->pc = huntele(p->s->frst, p->s->frst->status);
+	r->pid = nproc++ - nstop + Skip_claim;
+
+	if ((verbose&4) || (verbose&32))
+		printf("Starting %s with pid %d\n", p->n->name, r->pid);
+
+	if (!p->s)
+		fatal("parsing error, no sequence %s", p->n?p->n->name:"--");
+
+	r->pc = huntele(p->s->frst, p->s->frst->status, -1);
 	r->ps = p->s;
-	if (p->s && p->s->last)
-		p->s->last->status |= ENDSTATE; /* normal endstate */
+
+	if (p->s->last)
+		p->s->last->status |= ENDSTATE; /* normal end state */
+
 	r->nxt = run;
 	r->prov = p->prov;
 	r->priority = weight;
@@ -120,22 +129,22 @@ announce(char *w)
 		firstrow = 1;
 		if (columns == 2)
 		{	sprintf(Buf, "%d:%s",
-			run->pid, run->n->name);
-			pstext(run->pid, Buf);
+			run->pid - Have_claim, run->n->name);
+			pstext(run->pid - Have_claim, Buf);
 		} else
 			printf("proc %d = %s\n",
 			run->pid - Have_claim, run->n->name);
 		return;
 	}
-#if 1
+
 	if (dumptab
 	||  analyze
 	||  s_trail
 	|| !(verbose&4))
 		return;
-#endif
+
 	if (w)
-		printf("  0:	proc - (%s) ", w);
+		printf("  0:	proc  - (%s) ", w);
 	else
 		whoruns(1);
 	printf("creates proc %2d (%s)",
@@ -146,6 +155,10 @@ announce(char *w)
 	printf("\n");
 }
 
+#ifndef MAXP
+#define MAXP	255	/* matches max nr of processes in verifier */
+#endif
+
 int
 enable(Lextok *m)
 {	ProcList *p;
@@ -155,11 +168,15 @@ enable(Lextok *m)
 	if (m->val < 1) m->val = 1;	/* minimum priority */
 	for (p = rdy; p; p = p->nxt)
 		if (strcmp(s->name, p->n->name) == 0)
-		{	runnable(p, m->val, 0);
+		{	if (nproc-nstop >= MAXP)
+			{	printf("spin: too many processes (%d max)\n", MAXP);
+				break;
+			}
+			runnable(p, m->val, 0);
 			announce((char *) 0);
 			setparams(run, p, n);
 			setlocals(run); /* after setparams */
-			return run->pid - Have_claim;	/* pid */
+			return run->pid - Have_claim + Skip_claim; /* effective simu pid */
 		}
 	return 0; /* process not found */
 }
@@ -179,7 +196,7 @@ start_claim(int n)
 	Skip_claim = 1;
 	goto done;
 found:
-	/* move claim to far end of runlist, with pid 0 */
+	/* move claim to far end of runlist, and reassign it pid 0 */
 	if (columns == 2)
 	{	depth = 0;
 		pstext(0, "0::never:");
@@ -190,23 +207,42 @@ found:
 				r->pid+1, r->n->name);
 			pstext(r->pid+1, Buf);
 	}	}
-	if (run->pid == 0) return;	/* already there */
+
+	if (run->pid == 0) return; /* it is the first process started */
 
 	q = run; run = run->nxt;
-	q->pid = 0; q->nxt = (RunList *) 0;
+	q->pid = 0; q->nxt = (RunList *) 0;	/* remove */
 done:
+	Have_claim = 1;
 	for (r = run; r; r = r->nxt)
-	{	r->pid = r->pid+1;
+	{	r->pid = r->pid+Have_claim;	/* adjust */
 		if (!r->nxt)
 		{	r->nxt = q;
 			break;
 	}	}
-	Have_claim = 1;
+}
+
+int
+f_pid(char *n)
+{	RunList *r;
+	int rval = -1;
+
+	for (r = run; r; r = r->nxt)
+		if (strcmp(n, r->n->name) == 0)
+		{	if (rval >= 0)
+			{	printf("spin: remote ref to proctype %s, ", n);
+				printf("has more than one match: %d and %d\n",
+					rval, r->pid);
+			} else
+				rval = r->pid;
+		}
+	return rval;
 }
 
 void
 wrapup(int fini)
 {
+	limited_vis = 0;
 	if (columns)
 	{	extern void putpostlude(void);
 		if (columns == 2) putpostlude();
@@ -217,7 +253,7 @@ wrapup(int fini)
 		goto short_cut;
 	if (nproc != nstop)
 	{	int ov = verbose;
-		printf("#processes: %d\n", nproc-nstop);
+		printf("#processes: %d\n", nproc-nstop - Have_claim + Skip_claim);
 		verbose &= ~4;
 		dumpglobals();
 		verbose = ov;
@@ -227,7 +263,9 @@ wrapup(int fini)
 			talk(X);
 		verbose = ov;	/* restore */
 	}
-	printf("%d processes created\n", nproc);
+	printf("%d process%s created\n",
+		nproc - Have_claim + Skip_claim,
+		(xspin || nproc!=1)?"es":"");
 short_cut:
 	if (xspin) alldone(0);	/* avoid an abort from xspin */
 	if (fini)  alldone(1);
@@ -237,7 +275,7 @@ static char is_blocked[256];
 
 static int
 p_blocked(int p)
-{	register int i, j;
+{	int i, j;
 
 	is_blocked[p%256] = 1;
 	for (i = j = 0; i < nproc - nstop; i++)
@@ -276,7 +314,7 @@ static void
 pickproc(void)
 {	SeqList *z; Element *has_else;
 	short Choices[256];
-	int j, k, nr_else;
+	int j, k, nr_else = 0;
 
 	if (nproc <= nstop+1)
 	{	X = run;
@@ -422,7 +460,7 @@ sched(void)
 {	Element *e;
 	RunList *Y=0;	/* previous process in run queue */
 	RunList *oX;
-	int go, notbeyond;
+	int go, notbeyond = 0;
 #ifdef PC
 	int bufmax = 100;
 #endif
@@ -450,11 +488,8 @@ sched(void)
 	if (eventmap)
 	printf("warning: trace assertion not used in random simulation\n");
 
-/*	if (interactive) Tval = 1; */
-
 	X = run;
 	pickproc();
-	notbeyond = 0;
 
 	while (X)
 	{	context = X->n;
@@ -462,19 +497,25 @@ sched(void)
 		{	lineno = X->pc->n->ln;
 			Fname  = X->pc->n->fn;
 		}
+		if (cutoff > 0 && depth >= cutoff)
+		{	printf("-------------\n");
+			printf("depth-limit (-u%d steps) reached\n", cutoff);
+			break;
+		}
 #ifdef PC
 		if (xspin && !interactive && --bufmax <= 0)
-		{	/* avoid buffer overflow on pc's */
+		{	int c; /* avoid buffer overflow on pc's */
 			printf("spin: type return to proceed\n");
 			fflush(stdout);
-			getc(stdin);
+			c = getc(stdin);
+			if (c == 'q') wrapup(0);
 			bufmax = 100;
 		}
 #endif
 		depth++; LastStep = ZE;
 		oX = X;	/* a rendezvous could change it */
 		go = 1;
-		if (X && X->prov
+		if (X && X->prov && X->pc
 		&& !(X->pc->status & D_ATOM)
 		&& !eval(X->prov))
 		{	if (!xspin && ((verbose&32) || (verbose&4)))
@@ -487,6 +528,7 @@ sched(void)
 		{	if (depth >= jumpsteps
 			&& ((verbose&32) || (verbose&4)))
 			{	if (X == oX)
+				if (!(e->status & D_ATOM) || (verbose&32)) /* no talking in d_steps */
 				{	p_talk(X->pc, 1);
 					printf("	[");
 					if (!LastStep) LastStep = X->pc;
@@ -495,17 +537,23 @@ sched(void)
 				}
 				if (verbose&1) dumpglobals();
 				if (verbose&2) dumplocal(X);
-				if (xspin) printf("\n");
+
+				if (!(e->status & D_ATOM))
+				if (xspin)
+					printf("\n");
+			}
+			if (oX != X)
+			{	e = silent_moves(e);
+				notbeyond = 0;
 			}
-			if (oX != X)  e = silent_moves(e);
 			oX->pc = e; LastX = X;
 
 			if (!interactive) Tval = 0;
 			memset(is_blocked, 0, 256);
 
-			if ((X->pc->status & (ATOM|L_ATOM))
-			&&  notbeyond == 0)
-			{	if (X->pc->status & L_ATOM)
+			if (X->pc && (X->pc->status & (ATOM|L_ATOM))
+			&&  (notbeyond == 0 || oX != X))
+			{	if ((X->pc->status & L_ATOM))
 					notbeyond = 1;
 				continue; /* no process switch */
 			}
@@ -535,8 +583,11 @@ sched(void)
 				{	if (Tval) break;
 					Tval = 1;
 					if (depth >= jumpsteps)
+					{	oX = X;
+						X = (RunList *) 0; /* to suppress indent */
 						dotag(stdout, "timeout\n");
-		}	}	}
+						X = oX;
+		}	}	}	}
 		Y = X;
 		pickproc();
 		notbeyond = 0;
@@ -738,6 +789,20 @@ findloc(Symbol *s)
 	return r;
 }
 
+int
+in_bound(Symbol *r, int n)
+{
+	if (!r)	return 0;
+
+	if (n >= r->nel || n < 0)
+	{	printf("spin: indexing %s[%d] - size is %d\n",
+			r->name, n, r->nel);
+		non_fatal("indexing array \'%s\'", r->name);
+		return 0;
+	}
+	return 1;
+}
+
 int
 getlocal(Lextok *sn)
 {	Symbol *r, *s = sn->sym;
@@ -746,14 +811,8 @@ getlocal(Lextok *sn)
 	r = findloc(s);
 	if (r && r->type == STRUCT)
 		return Rval_struct(sn, r, 1); /* 1 = check init */
-	if (r)
-	{	if (n >= r->nel || n < 0)
-		{	printf("spin: indexing %s[%d] - size is %d\n",
-				s->name, n, r->nel);
-			non_fatal("indexing array \'%s\'", s->name);
-		} else
-		{	return cast_val(r->type, r->val[n], r->nbits);
-	}	}
+	if (in_bound(r, n))
+		return cast_val(r->type, r->val[n], r->nbits);
 	return 0;
 }
 
@@ -762,19 +821,18 @@ setlocal(Lextok *p, int m)
 {	Symbol *r = findloc(p->sym);
 	int n = eval(p->lft);
 
-	if (!r) return 1;
-
-	if (n >= r->nel || n < 0)
-	{	printf("spin: indexing %s[%d] - size is %d\n",
-			r->name, n, r->nel);
-		non_fatal("indexing array \'%s\'", r->name);
-	} else
+	if (in_bound(r, n))
 	{	if (r->type == STRUCT)
 			(void) Lval_struct(p, r, 1, m); /* 1 = check init */
 		else
-		{	if (r->nbits > 0)
-				m = (m & ((1<<r->nbits)-1));	
+		{
+#if 0
+			if (r->nbits > 0)
+				m = (m & ((1<<r->nbits)-1));
 			r->val[n] = m;
+#else
+			r->val[n] = cast_val(r->type, m, r->nbits);
+#endif
 			r->setat = depth;
 	}	}
 
@@ -817,12 +875,14 @@ p_talk(Element *e, int lnr)
 	&&  lastnever != newnever && e)
 	{	if (xspin)
 		{	printf("MSC: ~G line %d\n", newnever);
-			printf("%3d:	proc 0 (NEVER) line   %d \"never\" ",
+#if 0
+			printf("%3d:	proc  - (NEVER) line   %d \"never\" ",
 				depth, newnever);
 			printf("(state 0)\t[printf('MSC: never\\\\n')]\n");
 		} else
-		{	printf("%3d:	proc 0 (NEVER) line   %d \"never\"\n",
+		{	printf("%3d:	proc  - (NEVER) line   %d \"never\"\n",
 				depth, newnever);
+#endif
 		}
 		lastnever = newnever;
 	}
@@ -835,7 +895,7 @@ p_talk(Element *e, int lnr)
 			e->seqno);
 		if (!xspin
 		&&  ((e->status&ENDSTATE) || has_lab(e, 2)))	/* 2=end */
-		{	printf(" <valid endstate>");
+		{	printf(" <valid end state>");
 		}
 	}
 }
@@ -846,8 +906,10 @@ remotelab(Lextok *n)
 
 	lineno = n->ln;
 	Fname  = n->fn;
-	if (n->sym->type)
+	if (n->sym->type != 0 && n->sym->type != LABEL)
+	{	printf("spin: error, type: %d\n", n->sym->type);
 		fatal("not a labelname: '%s'", n->sym->name);
+	}
 	if (n->indstep >= 0)
 	{	fatal("remote ref to label '%s' inside d_step",
 			n->sym->name);
@@ -859,29 +921,40 @@ remotelab(Lextok *n)
 
 int
 remotevar(Lextok *n)
-{	int prno, i, trick=0;
-	RunList *Y;
+{	int prno, i, added=0;
+	RunList *Y, *oX;
+	Lextok *onl;
+	Symbol *os;
 
 	lineno = n->ln;
 	Fname  = n->fn;
+
 	if (!n->lft->lft)
-	{	non_fatal("missing pid in %s", n->sym->name);
-		return 0;
-	}
+		prno = f_pid(n->lft->sym->name);
+	else
+	{	prno = eval(n->lft->lft); /* pid - can cause recursive call */
+#if 0
+		if (n->lft->lft->ntyp == CONST)	/* user-guessed pid */
+#endif
+		{	prno += Have_claim;
+			added = Have_claim;
+	}	}
 
-	prno = eval(n->lft->lft); /* pid - can cause recursive call */
-TryAgain:
+	if (prno < 0)
+		return 0;	/* non-existing process */
+#if 0
+	i = nproc - nstop;
+	for (Y = run; Y; Y = Y->nxt)
+	{	--i;
+		printf("	%s: i=%d, prno=%d, ->pid=%d\n", Y->n->name, i, prno, Y->pid);
+	}
+#endif
 	i = nproc - nstop;
 	for (Y = run; Y; Y = Y->nxt)
 	if (--i == prno)
 	{	if (strcmp(Y->n->name, n->lft->sym->name) != 0)
-		{	if (!trick && Have_claim)
-			{	trick = 1; prno++;
-				/* assumes user guessed the pid */
-				goto TryAgain;
-			}
-			printf("spin: remote reference error on '%s[%d]'\n",
-				n->lft->sym->name, prno-trick);
+		{	printf("spin: remote reference error on '%s[%d]'\n",
+				n->lft->sym->name, prno-added);
 			non_fatal("refers to wrong proctype '%s'", Y->n->name);
 		}
 		if (strcmp(n->sym->name, "_p") == 0)
@@ -890,9 +963,28 @@ TryAgain:
 			/* harmless, can only happen with -t */
 			return 0;
 		}
+#if 1
+		/* new 4.0 allow remote variables */
+		oX = X;
+		X = Y;
+
+		onl = n->lft;
+		n->lft = n->rgt;
+
+		os = n->sym;
+		n->sym = findloc(n->sym);
+
+		i = getval(n);
+
+		n->sym = os;
+		n->lft = onl;
+		X = oX;
+		return i;
+#else
 		break;
+#endif
 	}
-	printf("remote ref: %s[%d] ", n->lft->sym->name, prno-trick);
+	printf("remote ref: %s[%d] ", n->lft->sym->name, prno-added);
 	non_fatal("%s not found", n->sym->name);
 	printf("have only:\n");
 	i = nproc - nstop - 1;

+ 89 - 38
sys/src/cmd/spin/spin.h

@@ -1,18 +1,22 @@
 /***** spin: spin.h *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
+
+#ifndef SEEN_SPIN_H
+#define SEEN_SPIN_H
 
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>
+#ifndef PC
+#endif
 
 typedef struct Lextok {
 	unsigned short	ntyp;	/* node type */
@@ -27,6 +31,13 @@ typedef struct Lextok {
 	struct Lextok	*lft, *rgt; /* children in parse tree */
 } Lextok;
 
+typedef struct Slicer {
+	Lextok	*n;		/* global var, usable as slice criterion */
+	short	code;		/* type of use: DEREF_USE or normal USE */
+	short	used;		/* set when handled */
+	struct Slicer *nxt;	/* linked list */
+} Slicer;
+
 typedef struct Access {
 	struct Symbol	*who;	/* proctype name of accessor */
 	struct Symbol	*what;	/* proctype name of accessed */
@@ -44,18 +55,18 @@ typedef struct Symbol {
 				  16=formal par, 32=inline par,
 				  64=treat as if local
 				 */
-	unsigned char	colnr;	/* for use with xspin */
-	int	nbits;		/* an optional width specifier */
+	unsigned char	colnr;	/* for use with xspin during simulation */
+	int	nbits;		/* optional width specifier */
 	int	nel;		/* 1 if scalar, >1 if array   */
 	int	setat;		/* last depth value changed   */
 	int	*val;		/* runtime value(s), initl 0  */
-	struct Lextok	**Sval;	/* values for structures */
+	Lextok	**Sval;	/* values for structures */
 
 	int	xu;		/* exclusive r or w by 1 pid  */
 	struct Symbol	*xup[2];  /* xr or xs proctype  */
 	struct Access	*access;/* e.g., senders and receives of chan */
-	struct Lextok	*ini;	/* initial value, or chan-def */
-	struct Lextok	*Slst;	/* template for structure if struct */
+	Lextok	*ini;	/* initial value, or chan-def */
+	Lextok	*Slst;	/* template for structure if struct */
 	struct Symbol	*Snm;	/* name of the defining struct */
 	struct Symbol	*owner;	/* set for names of subfields in typedefs */
 	struct Symbol	*context; /* 0 if global, or procname */
@@ -69,8 +80,8 @@ typedef struct Ordered {	/* links all names in Symbol table */
 
 typedef struct Queue {
 	short	qid;		/* runtime q index */
-	short	qlen;		/* nr messages stored */
-	short	nslots, nflds;	/* capacity, flds/slot */
+	int	qlen;		/* nr messages stored */
+	int	nslots, nflds;	/* capacity, flds/slot */
 	int	setat;		/* last depth value changed */
 	int	*fld_width;	/* type of each field */
 	int	*contents;	/* the values stored */
@@ -78,26 +89,33 @@ typedef struct Queue {
 	struct Queue	*nxt;	/* linked list */
 } Queue;
 
-typedef struct FSM_use {	/* used in pangen5.c - dataflow */
-	Symbol *var;
-	int special;
-	struct FSM_use *nxt;
-} FSM_use;
+typedef struct FSM_state {	/* used in pangen5.c - dataflow */
+	int from;		/* state number */
+	int seen;		/* used for dfs */
+	int in;			/* nr of incoming edges */
+	int cr;			/* has reachable 1-relevant successor */
+	int scratch;
+	unsigned long *dom, *mod; /* to mark dominant nodes */
+	struct FSM_trans *t;	/* outgoing edges */
+	struct FSM_trans *p;	/* incoming edges, predecessors */
+	struct FSM_state *nxt;	/* linked list of all states */
+} FSM_state;
 
 typedef struct FSM_trans {	/* used in pangen5.c - dataflow */
 	int to;
-	FSM_use *Val[2];	/* 0=reads, 1=writes */
+	short	relevant;	/* when sliced */
+	short	round;		/* ditto: iteration when marked */
+	struct FSM_use *Val[2];	/* 0=reads, 1=writes */
 	struct Element *step;
 	struct FSM_trans *nxt;
 } FSM_trans;
 
-typedef struct FSM_state {	/* used in pangen5.c - dataflow */
-	int from;		/* state number */
-	int seen;		/* used for dfs */
-	int in;			/* nr of incoming edges */
-	FSM_trans *t;		/* outgoing edges list */
-	struct FSM_state *nxt;	/* linked list of all states */
-} FSM_state;
+typedef struct FSM_use {	/* used in pangen5.c - dataflow */
+	Lextok *n;
+	Symbol *var;
+	int special;
+	struct FSM_use *nxt;
+} FSM_use;
 
 typedef struct Element {
 	Lextok	*n;		/* defines the type & contents */
@@ -132,7 +150,7 @@ typedef struct Label {
 	Symbol	*s;
 	Symbol	*c;
 	Element	*e;
-	int	visible;	/* label referenced in claim */
+	int	visible;	/* label referenced in claim (slice relevant) */
 	struct Label	*nxt;
 } Label;
 
@@ -182,11 +200,14 @@ typedef	Lextok *Lexptr;
 
 #define Nhash	255    		/* slots in symbol hash-table */
 
-#define XR	  1		/* non-shared receive-only */
-#define XS	  2		/* non-shared send-only    */
-#define XX	  4		/* overrides XR or XS tag  */
+#define XR	  	1	/* non-shared receive-only */
+#define XS	  	2	/* non-shared send-only    */
+#define XX	  	4	/* overrides XR or XS tag  */
+
+#define CODE_FRAG	2	/* auto-numbered code-fragment */
+#define CODE_DECL	4	/* auto-numbered c_decl */
+#define PREDEF	  	3	/* predefined name: _p, _last */
 
-#define PREDEF	  3		/* predefined names: _p, _last */
 #define UNSIGNED  5		/* val defines width in bits */
 #define BIT	  1		/* also equal to width in bits */
 #define BYTE	  8		/* ditto */
@@ -195,6 +216,9 @@ typedef	Lextok *Lexptr;
 #define	CHAN	 64		/* not */
 #define STRUCT	128		/* user defined structure name */
 
+#define SOMETHINGBIG	65536
+#define RATHERSMALL	512
+
 #ifndef max
 #define max(a,b) (((a)<(b)) ? (b) : (a))
 #endif
@@ -204,7 +228,7 @@ enum	{ INIV, PUTV, LOGV };	/* for pangen[14].c */
 /***** prototype definitions *****/
 Element	*eval_sub(Element *);
 Element	*get_lab(Lextok *, int);
-Element	*huntele(Element *, int);
+Element	*huntele(Element *, int, int);
 Element	*huntstart(Element *);
 Element	*target(Element *);
 
@@ -214,6 +238,7 @@ Lextok	*getuname(Symbol *);
 Lextok	*mk_explicit(Lextok *, int, int);
 Lextok	*nn(Lextok *, int, Lextok *, Lextok *);
 Lextok	*rem_lab(Symbol *, Lextok *, Symbol *);
+Lextok	*rem_var(Symbol *, Lextok *, Symbol *, Lextok *);
 Lextok	*tail_add(Lextok *, Lextok *);
 
 ProcList *ready(Symbol *, Lextok *, Sequence *, int, Lextok *);
@@ -223,14 +248,16 @@ Sequence *close_seq(int);
 
 Symbol	*break_dest(void);
 Symbol	*findloc(Symbol *);
-Symbol	*lookup(char *);
 Symbol	*has_lab(Element *, int);
+Symbol	*lookup(char *);
+Symbol	*prep_inline(Symbol *, Lextok *);
 
 char	*emalloc(int);
 long	Rand(void);
 
 int	any_oper(Lextok *, int);
 int	any_undo(Lextok *);
+int	c_add_sv(FILE *);
 int	cast_val(int, int, int);
 int	checkvar(Symbol *, int);
 int	Cnt_flds(Lextok *);
@@ -244,8 +271,11 @@ int	find_maxel(Symbol *);
 int	full_name(FILE *, Lextok *, Symbol *, int);
 int	getlocal(Lextok *);
 int	getval(Lextok *);
+int	glob_inline(char *);
 int	has_typ(Lextok *, int);
+int	in_bound(Symbol *, int);
 int	interprint(FILE *, Lextok *);
+int	printm(FILE *, Lextok *);
 int	ismtype(char *);
 int	isproctype(char *);
 int	isutype(char *);
@@ -253,7 +283,7 @@ int	Lval_struct(Lextok *, Symbol *, int, int);
 int	main(int, char **);
 int	pc_value(Lextok *);
 int	proper_enabler(Lextok *);
-int	putcode(FILE *, Sequence *, Element *, int, int);
+int	putcode(FILE *, Sequence *, Element *, int, int, int);
 int	q_is_sync(Lextok *);
 int	qlen(Lextok *);
 int	qfull(Lextok *);
@@ -273,15 +303,28 @@ int	yyparse(void);
 int	yywrap(void);
 int	yylex(void);
 
+void	AST_track(Lextok *, int);
 void	add_seq(Lextok *);
 void	alldone(int);
 void	announce(char *);
+void	c_state(Symbol *, Symbol *, Symbol *);
+void	c_add_def(FILE *);
+void	c_add_loc(FILE *, char *);
+void	c_add_locinit(FILE *, int, char *);
+void	c_add_use(FILE *);
+void	c_chandump(FILE *);
+void	c_preview(void);
+void	c_struct(FILE *, char *, Symbol *);
+void	c_track(Symbol *, Symbol *, Symbol *);
+void	c_var(FILE *, char *, Symbol *);
+void	c_wrapper(FILE *);
 void	chanaccess(void);
 void	checkrun(Symbol *, int);
 void	comment(FILE *, Lextok *, int);
 void	cross_dsteps(Lextok *, Lextok *);
 void	doq(Symbol *, int, RunList *);
 void	dotag(FILE *, char *);
+void	do_locinits(FILE *);
 void	do_var(FILE *, int, char *, Symbol *, char *, char *, char *);
 void	dump_struct(Symbol *, char *, RunList *);
 void	dumpclaims(FILE *, int, char *);
@@ -289,27 +332,33 @@ void	dumpglobals(void);
 void	dumplabels(void);
 void	dumplocal(RunList *);
 void	dumpsrc(int, int);
-/* void	exit(int);	in stdlib.h */
 void	fatal(char *, char *);
 void	fix_dest(Symbol *, Symbol *);
 void	genaddproc(void);
 void	genaddqueue(void);
+void	gencodetable(FILE *);
 void	genheader(void);
 void	genother(void);
 void	gensrc(void);
 void	gensvmap(void);
 void	genunio(void);
 void	ini_struct(Symbol *);
+void	loose_ends(void);
 void	make_atomic(Sequence *, int);
 void	match_trail(void);
+void	no_side_effects(char *);
 void	nochan_manip(Lextok *, Lextok *, int);
 void	non_fatal(char *, char *);
 void	ntimes(FILE *, int, int, char *c[]);
 void	open_seq(int);
 void	p_talk(Element *, int);
 void	pickup_inline(Symbol *, Lextok *);
+void	plunk_c_decls(FILE *);
+void	plunk_c_fcts(FILE *);
+void	plunk_expr(FILE *, char *);
+void	plunk_inline(FILE *, char *, int);
 void	prehint(Symbol *);
-void	prep_inline(Symbol *, Lextok *);
+void	preruse(FILE *, Lextok *);
 void	prune_opts(Lextok *);
 void	pstext(int, char *);
 void	pushbreak(void);
@@ -334,6 +383,7 @@ void	Srand(unsigned);
 void	start_claim(int);
 void	struct_name(Lextok *, Symbol *, int, char *);
 void	symdump(void);
+void	symvar(Symbol *);
 void	trackchanuse(Lextok *, Lextok *, int);
 void	trackvar(Lextok *, Lextok *);
 void	trackrun(Lextok *);
@@ -347,3 +397,4 @@ void	varcheck(Element *, Element *);
 void	whoruns(int);
 void	wrapup(int);
 void	yyerror(char *, ...);
+#endif

+ 101 - 24
sys/src/cmd/spin/spin.y

@@ -1,14 +1,13 @@
 /***** spin: spin.y *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 %{
 #include "spin.h"
@@ -20,6 +19,8 @@
 extern  Symbol	*context, *owner;
 extern  int	u_sync, u_async, dumptab;
 extern	short	has_sorted, has_random, has_enabled, has_pcvalue, has_np;
+extern	short	has_code, has_state, has_io;
+extern	void	count_runs(Lextok *);
 extern	void	validref(Lextok *, Lextok *);
 extern	char	yytext[];
 
@@ -33,7 +34,8 @@ static	int	Embedded = 0, inEventMap = 0, has_ini = 0;
 
 %}
 
-%token	ASSERT PRINT
+%token	ASSERT PRINT PRINTM
+%token	C_CODE C_DECL C_EXPR C_STATE C_TRACK
 %token	RUN LEN ENABLED EVAL PC_VAL
 %token	TYPEDEF MTYPE INLINE LABEL OF
 %token	GOTO BREAK ELSE SEMI
@@ -80,6 +82,7 @@ unit	: proc		/* proctype { }       */
 	| events	/* event assertions   */
 	| one_decl	/* variables, chans   */
 	| utype		/* user defined types */
+	| c_fcts	/* c functions etc.   */
 	| ns		/* named sequence     */
 	| SEMI		/* optional separator */
 	| error
@@ -121,14 +124,17 @@ inst	: /* empty */	{ $$ = ZN; }
 	| ACTIVE	{ $$ = nn(ZN,CONST,ZN,ZN); $$->val = 1; }
 	| ACTIVE '[' CONST ']' {
 			  $$ = nn(ZN,CONST,ZN,ZN); $$->val = $3->val;
+			  if ($3->val > 255)
+				non_fatal("max nr of processes is 255\n", "");
 			}
 	| ACTIVE '[' NAME ']' {
 			  $$ = nn(ZN,CONST,ZN,ZN);
 			  $$->val = 0;
 			  if (!$3->sym->type)
-				non_fatal("undeclared variable %s", $3->sym->name);
+				non_fatal("undeclared variable %s",
+					$3->sym->name);
 			  else if ($3->sym->ini->ntyp != CONST)
-				non_fatal("constant initializer required for %s\n",
+				non_fatal("need constant initializer for %s\n",
 					$3->sym->name);
 			  else
 				$$->val = $3->sym->ini->val;
@@ -183,7 +189,63 @@ nm	: NAME			{ $$ = $1; }
 	;
 
 ns	: INLINE nm '('		{ NamesNotAdded++; }
-	  args ')'		{ prep_inline($2->sym, $5); NamesNotAdded--; }
+	  args ')'		{ prep_inline($2->sym, $5);
+				  NamesNotAdded--;
+				}
+	;
+
+c_fcts	: ccode			{ /* leaves pseudo-inlines with sym of
+				   * type CODE_FRAG or CODE_DECL in global context
+				   */
+				}
+	| cstate
+	;
+
+cstate	: C_STATE STRING STRING	{
+				  c_state($2->sym, $3->sym, ZS);
+				  has_code = has_state = 1;
+				}
+	| C_TRACK STRING STRING {
+				  c_track($2->sym, $3->sym, ZS);
+				  has_code = has_state = 1;
+				}
+	| C_STATE STRING STRING	STRING {
+				  c_state($2->sym, $3->sym, $4->sym);
+				  has_code = has_state = 1;
+				}
+	| C_TRACK STRING STRING STRING {
+				  c_track($2->sym, $3->sym, $4->sym);
+				  has_code = has_state = 1;
+				}
+	;
+
+ccode	: C_CODE		{ Symbol *s;
+				  NamesNotAdded++;
+				  s = prep_inline(ZS, ZN);
+				  NamesNotAdded--;
+				  $$ = nn(ZN, C_CODE, ZN, ZN);
+				  $$->sym = s;
+				  has_code = 1;
+				}
+	| C_DECL		{ Symbol *s;
+				  NamesNotAdded++;
+				  s = prep_inline(ZS, ZN);
+				  NamesNotAdded--;
+				  s->type = CODE_DECL;
+				  $$ = nn(ZN, C_CODE, ZN, ZN);
+				  $$->sym = s;
+				  has_code = 1;
+				}
+	;
+cexpr	: C_EXPR		{ Symbol *s;
+				  NamesNotAdded++;
+				  s = prep_inline(ZS, ZN);
+				  NamesNotAdded--;
+				  $$ = nn(ZN, C_EXPR, ZN, ZN);
+				  $$->sym = s;
+				  no_side_effects(s->name);
+				  has_code = 1;
+				}
 	;
 
 body	: '{'			{ open_seq(1); }
@@ -197,6 +259,8 @@ sequence: step			{ if ($1) add_seq($1); }
 
 step    : one_decl		{ $$ = ZN; }
 	| XU vref_lst		{ setxus($2, $1->val); $$ = ZN; }
+	| NAME ':' one_decl	{ fatal("label preceding declaration,", (char *)0); }
+	| NAME ':' XU		{ fatal("label predecing xr/xs claim,", 0); }
 	| stmnt			{ $$ = $1; }
 	| stmnt UNLESS stmnt	{ $$ = do_unless($1, $3); }
 	;
@@ -269,6 +333,11 @@ ch_init : '[' CONST ']' OF
 
 vardcl  : NAME  		{ $1->sym->nel = 1; $$ = $1; }
 	| NAME ':' CONST	{ $1->sym->nbits = $3->val;
+				  if ($3->val >= 8*sizeof(long))
+				  {	non_fatal("width-field %s too large",
+						$1->sym->name);
+					$3->val = 8*sizeof(long)-1;
+				  }
 				  $1->sym->nel = 1; $$ = $1;
 				}
 	| NAME '[' CONST ']'	{ $1->sym->nel = $3->val; $$ = $1; }
@@ -311,12 +380,12 @@ stmnt	: Special		{ $$ = $1; }
 	;
 
 Special : varref RCV		{ Expand_Ok++; }
-	  rargs			{ Expand_Ok--;
+	  rargs			{ Expand_Ok--; has_io++;
 				  $$ = nn($1,  'r', $1, $4);
 				  trackchanuse($4, ZN, 'R');
 				}
 	| varref SND		{ Expand_Ok++; }
-	  margs			{ Expand_Ok--;
+	  margs			{ Expand_Ok--; has_io++;
 				  $$ = nn($1, 's', $1, $4);
 				  $$->val=0; trackchanuse($4, ZN, 'S');
 				}
@@ -370,32 +439,35 @@ Stmnt	: varref ASGN expr	{ $$ = nn($1, ASGN, $1, $3);
 				}
 	| PRINT	'(' STRING	{ realread = 0; }
 	  prargs ')'		{ $$ = nn($3, PRINT, $5, ZN); realread = 1; }
-	| ASSERT full_expr    	{ $$ = nn(ZN, ASSERT, $2, ZN); }
+	| PRINTM '(' varref ')'	{ $$ = nn(ZN, PRINTM, $3, ZN); }
+	| PRINTM '(' CONST ')'	{ $$ = nn(ZN, PRINTM, $3, ZN); }
+	| ASSERT full_expr    	{ $$ = nn(ZN, ASSERT, $2, ZN); AST_track($2, 0); }
+	| ccode			{ $$ = $1; }
 	| varref R_RCV		{ Expand_Ok++; }
-	  rargs			{ Expand_Ok--;
+	  rargs			{ Expand_Ok--; has_io++;
 				  $$ = nn($1,  'r', $1, $4);
 				  $$->val = has_random = 1;
 				  trackchanuse($4, ZN, 'R');
 				}
 	| varref RCV		{ Expand_Ok++; }
-	  LT rargs GT		{ Expand_Ok--;
+	  LT rargs GT		{ Expand_Ok--; has_io++;
 				  $$ = nn($1, 'r', $1, $5);
 				  $$->val = 2;	/* fifo poll */
 				  trackchanuse($5, ZN, 'R');
 				}
 	| varref R_RCV		{ Expand_Ok++; }
-	  LT rargs GT		{ Expand_Ok--;	/* rrcv poll */
+	  LT rargs GT		{ Expand_Ok--; has_io++;	/* rrcv poll */
 				  $$ = nn($1, 'r', $1, $5);
 				  $$->val = 3; has_random = 1;
 				  trackchanuse($5, ZN, 'R');
 				}
 	| varref O_SND		{ Expand_Ok++; }
-	  margs			{ Expand_Ok--;
+	  margs			{ Expand_Ok--; has_io++;
 				  $$ = nn($1, 's', $1, $4);
 				  $$->val = has_sorted = 1;
 				  trackchanuse($4, ZN, 'S');
 				}
-	| full_expr		{ $$ = nn(ZN, 'c', $1, ZN); }
+	| full_expr		{ $$ = nn(ZN, 'c', $1, ZN); count_runs($$); }
 	| ELSE  		{ $$ = nn(ZN,ELSE,ZN,ZN);
 				}
 	| ATOMIC   '{'   	{ open_seq(0); }
@@ -485,15 +557,16 @@ expr    : '(' expr ')'		{ $$ = $2; }
 				  has_enabled++;
 				}
 	| varref RCV		{ Expand_Ok++; }
-	  '[' rargs ']'		{ Expand_Ok--;
+	  '[' rargs ']'		{ Expand_Ok--; has_io++;
 				  $$ = nn($1, 'R', $1, $5);
 				}
 	| varref R_RCV		{ Expand_Ok++; }
-	  '[' rargs ']'		{ Expand_Ok--;
+	  '[' rargs ']'		{ Expand_Ok--; has_io++;
 				  $$ = nn($1, 'R', $1, $5);
 				  $$->val = has_random = 1;
 				}
 	| varref		{ $$ = $1; trapwonly($1, "varref"); }
+	| cexpr			{ $$ = $1; }
 	| CONST 		{ $$ = nn(ZN,CONST,ZN,ZN);
 				  $$->ismtyp = $1->ismtyp;
 				  $$->val = $1->val;
@@ -505,8 +578,12 @@ expr    : '(' expr ')'		{ $$ = $2; }
 	| PC_VAL '(' expr ')'	{ $$ = nn(ZN, PC_VAL, $3, ZN);
 				  has_pcvalue++;
 				}
-	| PNAME '[' expr ']' '@'
-	  NAME			{ $$ = rem_lab($1->sym, $3, $6->sym); }
+	| PNAME '[' expr ']' '@' NAME
+	  			{ $$ = rem_lab($1->sym, $3, $6->sym); }
+	| PNAME '[' expr ']' ':' pfld
+	  			{ $$ = rem_var($1->sym, $3, $6->sym, $6->lft); }
+	| PNAME '@' NAME	{ $$ = rem_lab($1->sym, ZN, $3->sym); }
+	| PNAME ':' pfld	{ $$ = rem_var($1->sym, ZN, $3->sym, $3->lft); }
 	;
 
 Opt_priority:	/* none */	{ $$ = ZN; }

File diff suppressed because it is too large
+ 781 - 43
sys/src/cmd/spin/spinlex.c


+ 55 - 15
sys/src/cmd/spin/structs.c

@@ -1,14 +1,13 @@
 /***** spin: structs.c *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 #include "spin.h"
 #ifdef PC
@@ -23,8 +22,6 @@ typedef struct UType {
 	struct UType *nxt;	/* linked list */
 } UType;
 
-extern	Symbol	*context;
-extern	RunList	*X;
 extern	Symbol	*Fname;
 extern	int	lineno, depth, Expand_Ok;
 
@@ -254,7 +251,7 @@ is_lst:
 	for (tl = fp->lft; tl; tl = tl->rgt)
 	{	if (tl->sym->type == STRUCT)
 		{	if (tl->sym->nel != 1)
-				fatal("hidden array in parameter, %s",
+				fatal("array of structures in param list, %s",
 					tl->sym->name);
 			cnt += Cnt_flds(tl->sym->Slst);
 		}  else
@@ -275,7 +272,7 @@ Sym_typ(Lextok *t)
 	if (!t->rgt
 	||  !t->rgt->ntyp == '.'
 	||  !t->rgt->lft)
-		fatal("unexpected struct layout %s", s->name);
+		return STRUCT;	/* not a field reference */
 
 	return Sym_typ(t->rgt->lft);
 }
@@ -386,7 +383,7 @@ void
 struct_name(Lextok *n, Symbol *v, int xinit, char *buf)
 {	Symbol *tl;
 	Lextok *tmp;
-	char lbuf[128];
+	char lbuf[512];
 
 	if (!n || !(tl = do_same(n, v, xinit)))
 		return;
@@ -447,10 +444,37 @@ walk_struct(FILE *ofd, int dowhat, char *s, Symbol *z, char *a, char *b, char *c
 	}	}
 }
 
+void
+c_struct(FILE *fd, char *ipref, Symbol *z)
+{	Lextok *fp, *tl;
+	char pref[256], eprefix[256];
+	int ix;
+
+	ini_struct(z);
+
+	for (ix = 0; ix < z->nel; ix++)
+	for (fp = z->Sval[ix]; fp; fp = fp->rgt)
+	for (tl = fp->lft; tl; tl = tl->rgt)
+	{	strcpy(eprefix, ipref);
+		if (z->nel > 1)
+		{	/* insert index before last '.' */
+			eprefix[strlen(eprefix)-1] = '\0';
+			sprintf(pref, "[ %d ].", ix);
+			strcat(eprefix, pref);
+		}
+		if (tl->sym->type == STRUCT)
+		{	strcat(eprefix, tl->sym->name);
+			strcat(eprefix, ".");
+			c_struct(fd, eprefix, tl->sym);
+		} else
+			c_var(fd, eprefix, tl->sym);
+	}
+}
+
 void
 dump_struct(Symbol *z, char *prefix, RunList *r)
 {	Lextok *fp, *tl;
-	char eprefix[128];
+	char eprefix[256];
 	int ix, jx;
 
 	ini_struct(z);
@@ -464,7 +488,7 @@ dump_struct(Symbol *z, char *prefix, RunList *r)
 		for (fp = z->Sval[ix]; fp; fp = fp->rgt)
 		for (tl = fp->lft; tl; tl = tl->rgt)
 		{	if (tl->sym->type == STRUCT)
-			{	char pref[128];
+			{	char pref[256];
 				strcpy(pref, eprefix);
 				strcat(pref, ".");
 				strcat(pref, tl->sym->name);
@@ -562,6 +586,22 @@ mk_explicit(Lextok *n, int Ok, int Ntyp)
 	||  is_explicit(n))
 		return n;
 
+	if (n->rgt
+	&&  n->rgt->ntyp == '.'
+	&&  n->rgt->lft
+	&&  n->rgt->lft->sym
+	&&  n->rgt->lft->sym->type == STRUCT)
+	{	Lextok *y;
+		bld = mk_explicit(n->rgt->lft, Ok, Ntyp);
+		for (x = bld; x; x = x->rgt)
+		{	y = cpnn(n, 1, 0, 0);
+			y->rgt = nn(ZN, '.', x->lft, ZN);
+			x->lft = y;
+		}
+
+		return bld;
+	}
+
 	if (!Ok || !n->sym->Slst)
 	{	if (IArgs) return n;
 		printf("spin: saw '");

+ 25 - 19
sys/src/cmd/spin/sym.c

@@ -1,14 +1,13 @@
 /***** spin: sym.c *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 #include "spin.h"
 #ifdef PC
@@ -68,7 +67,7 @@ lookup(char *s)
 			return sp;		/* global */
 
 	sp = (Symbol *) emalloc(sizeof(Symbol));
-	sp->name = (char *) emalloc(strlen(s) + 1);
+	sp->name = (char *) emalloc((int) strlen(s) + 1);
 	strcpy(sp->name, s);
 	sp->nel = 1;
 	sp->setat = depth;
@@ -155,7 +154,7 @@ checkrun(Symbol *parnm, int posno)
 	{	if (!(verbose&32)) return;
 		strcpy(buf2, (!(res&4))?"bit":"byte");
 		sputtype(buf, parnm->type);
-		i = strlen(buf);
+		i = (int) strlen(buf);
 		while (buf[--i] == ' ') buf[i] = '\0';
 		if (strcmp(buf, buf2) == 0) return;
 		prehint(parnm);
@@ -331,7 +330,8 @@ setmtype(Lextok *m)
 			n->lft->sym->ini = nn(ZN,CONST,ZN,ZN);
 			n->lft->sym->ini->val = cnt;
 		} else if (n->lft->sym->ini->val != cnt)
-			fatal("cannot happen: setmtype", (char *) 0);
+			non_fatal("name %s appears twice in mtype declaration",
+				n->lft->sym->name);
 	}
 	lineno = oln;
 	if (cnt > 256)
@@ -382,7 +382,7 @@ puttype(int m)
 	return 0;
 }
 
-static void
+void
 symvar(Symbol *sp)
 {	Lextok *m;
 
@@ -402,10 +402,10 @@ symvar(Symbol *sp)
 		printf("\t%d", eval(sp->ini));
 
 	if (sp->owner)
-		printf("\t<struct-field>");
+		printf("\t<:struct-field:>");
 	else
 	if (!sp->context)
-		printf("\t<global>");
+		printf("\t<:global:>");
 	else
 		printf("\t<%s>", sp->context->name);
 
@@ -419,7 +419,10 @@ symvar(Symbol *sp)
 			i++;
 		printf("\t%d\t", i);
 		for (m = sp->ini->rgt; m; m = m->rgt)
-		{	(void) puttype(m->ntyp);
+		{	if (m->ntyp == STRUCT)
+				printf("struct %s", m->sym->name);
+			else
+				(void) puttype(m->ntyp);
 			if (m->rgt) printf("\t");
 		}
 	}
@@ -496,6 +499,7 @@ chanaccess(void)
 {	Ordered *walk;
 	char buf[128];
 	extern int Caccess, separate;
+	extern short has_code;
 
 	for (walk = all_names; walk; walk = walk->next)
 	{	if (!walk->entry->owner)
@@ -512,10 +516,13 @@ chanaccess(void)
 			if ((walk->entry->hidden&32))
 				continue;
 
-			if (!separate && !walk->entry->context && deadvar)
+			if (!separate
+			&&  !walk->entry->context
+			&&  !has_code
+			&&   deadvar)
 				walk->entry->hidden |= 1; /* auto-hide */
 
-			if (!(verbose&32)) continue;
+			if (!(verbose&32) || has_code) continue;
 
 			printf("spin: warning, %s, ", Fname->name);
 			sputtype(buf, walk->entry->type);
@@ -526,6 +533,5 @@ chanaccess(void)
 				printf("global");
 			printf(", '%s%s' variable is never used\n",
 				buf, walk->entry->name);
-		}
-	}
+	}	}
 }

+ 8 - 6
sys/src/cmd/spin/tl.h

@@ -1,14 +1,16 @@
 /***** tl_spin: tl.h *****/
 
-/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A.               */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
+
 /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
 /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.   */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
 
 #include <stdio.h>
 #include <string.h>

+ 40 - 48
sys/src/cmd/spin/tl_buchi.c

@@ -1,14 +1,16 @@
 /***** tl_spin: tl_buchi.c *****/
 
-/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A.               */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
+
 /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
 /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.   */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
 
 #include "tl.h"
 
@@ -77,12 +79,6 @@ Prune(Node *p)
 		if (!p->rgt)
 			return p->lft;
 		return p;
-#if 0
-/* 3.3.9 */
-	case V_OPER:
-		releasenode(1, p->lft);
-		return Prune(p->rgt);
-#endif
 	}
 	releasenode(1, p);
 	return ZN;
@@ -118,7 +114,7 @@ Dfs(State *b)
 	b->reachable = 1;
 
 	if (b->redundant)
-		printf("spin: internal error, Dfs hits redundant state %s\n",
+		printf("/* redundant state %s */\n",
 			b->name->name);
 	for (t = b->trans; t; t = t->nxt)
 	{	if (!t->redundant)
@@ -140,12 +136,8 @@ retarget(char *from, char *to)
 
 	for (b = never; b; b = b->nxt)
 	{	if (!strcmp(b->name->name, from))
-		{	b->redundant = 1;
-			for (t = b->trans; t; t = t->nxt)
-			{	/* releasenode(1, t->cond); */
-				t->cond = ZN;
-			}
-		} else
+			b->redundant = 1;
+		else
 		for (t = b->trans; t; t = t->nxt)
 		{	if (!strcmp(t->name->name, from))
 				t->name = To;
@@ -189,7 +181,7 @@ combination(Node *s, Node *t)
 #ifdef NXT
 	Node *a = nonxt(s);
 	Node *b = nonxt(t);
-#if 1
+
 	if (tl_verbose)
 	{	printf("\tnonxtA: "); dump(a);
 		printf("\n\tnonxtB: "); dump(b);
@@ -200,22 +192,6 @@ combination(Node *s, Node *t)
 		nc = True;
 	else
 		nc = tl_nn(OR, a, b);
-#else
-	if (!a)
-	{	releasenode(1, s);
-		if (!b)
-		{	releasenode(1, t);
-			nc = False;
-		} else
-		{	nc = b;
-		}
-	} else if (!b)
-	{	releasenode(1, t);
-		nc = a;
-	} else
-	{	nc = tl_nn(OR, a, b);
-	}
-#endif
 #else
 	nc = tl_nn(OR, s, t);
 #endif
@@ -309,7 +285,7 @@ showtrans(State *a)
 }
 
 static int
-mergetrans(int v)
+mergetrans(void)
 {	State *b;
 	Transition *s, *t;
 	Node *nc; int cnt = 0;
@@ -389,7 +365,11 @@ done:
 		s->marked = 0;
 	return result;
 }
+
+#ifndef NO_OPT
 #define BUCKY
+#endif
+
 #ifdef BUCKY
 static int
 all_bucky(State *a, State *b)
@@ -477,7 +457,12 @@ buckyballs(void)
 					}
 
 					if (a->accepting && !b->accepting)
-					{	c = b; d = a;
+					{	if (strcmp(b->name->name, "T0_init") == 0)
+						{	c = a; d = b;
+							b->accepting = 1;
+						} else
+						{	c = b; d = a;
+						}
 					} else
 					{	c = a; d = b;
 					}
@@ -501,10 +486,10 @@ static int
 mergestates(int v)
 {	State *a, *b;
 	int m, cnt=0;
-#if 1
+
 	if (tl_verbose)
 		return 0;
-#endif
+
 	do {
 		m = 0; cnt++;
 		for (a = never; a; a = a->nxt)
@@ -538,7 +523,8 @@ mergestates(int v)
 #if 0
 				else if (tl_verbose)
 				{	printf("\n%d: state %s differs from state %s [%d,%d]\n",
-					cnt, a->name->name, b->name->name, a->accepting, b->accepting);
+						cnt, a->name->name, b->name->name,
+						a->accepting, b->accepting);
 					showtrans(a);
 					printf("==\n");
 					showtrans(b);
@@ -574,6 +560,12 @@ printstate(State *b)
 	b->reachable = 0;	/* print only once */
 	fprintf(tl_out, "%s:\n", b->name->name);
 
+	if (tl_verbose)
+	{	fprintf(tl_out, "	/* ");
+		dump(b->colors->Other);
+		fprintf(tl_out, " */\n");
+	}
+
 	if (strncmp(b->name->name, "accept", 6) == 0
 	&&  Max_Red == 0)
 		fprintf(tl_out, "T0%s:\n", &(b->name->name[6]));
@@ -595,11 +587,11 @@ addtrans(Graph *col, char *from, Node *op, char *to)
 	t->name = tl_lookup(to);
 	t->cond = Prune(dupnode(op));
 
-if (tl_verbose)
-{ printf("\n<<\t"); dump(op);
-  printf("\n\t"); dump(t->cond);
-  printf(">> %s\n", t->name->name);
-}
+	if (tl_verbose)
+	{	printf("\n%s <<\t", from); dump(op);
+		printf("\n\t"); dump(t->cond);
+		printf(">> %s\n", t->name->name);
+	}
 	if (t->cond) t->cond = rewrite(t->cond);
 
 	for (b = never; b; b = b->nxt)
@@ -647,7 +639,7 @@ fsm_print(void)
 	do {
 		clr_reach();
 		Dfs(b);
-		cnt1 = mergetrans(1);
+		cnt1 = mergetrans();
 		cnt2 = mergestates(1);
 		if (tl_verbose)
 			printf("/* >>%d,%d<< */\n", cnt1, cnt2);
@@ -658,7 +650,7 @@ fsm_print(void)
 	clr_reach();
 	Dfs(b);
 #endif
-	if (Max_Red == 0)
+	if (b && b->accepting)
 		fprintf(tl_out, "accept_init:\n");
 
 	if (!b && !never)

+ 11 - 7
sys/src/cmd/spin/tl_cache.c

@@ -1,14 +1,16 @@
 /***** tl_spin: tl_cache.c *****/
 
-/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A.               */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
+
 /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
 /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.   */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
 
 #include "tl.h"
 
@@ -26,6 +28,7 @@ static int	ismatch(Node *, Node *);
 extern void fatal(char *, char *);
 int	sameform(Node *, Node *);
 
+#if 0
 void
 cache_dump(void)
 {	Cache *d; int nr=0;
@@ -38,6 +41,7 @@ cache_dump(void)
 	}
 	printf("============\n");
 }
+#endif
 
 Node *
 in_cache(Node *n)
@@ -58,7 +62,7 @@ cached(Node *n)
 	Node *m;
 
 	if (!n) return n;
-	if (m = in_cache(n))
+	if ((m = in_cache(n)) != ZN)
 		return m;
 
 	Caches++;

+ 18 - 16
sys/src/cmd/spin/tl_lex.c

@@ -1,14 +1,16 @@
 /***** tl_spin: tl_lex.c *****/
 
-/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A.               */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
+
 /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
 /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.   */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
 
 #include <stdlib.h>
 #include <ctype.h>
@@ -23,7 +25,7 @@ extern char	yytext[];
 #define Token(y)        tl_yylval = tl_nn(y,ZN,ZN); return y
 
 static void
-getword(int first, int (*tst)(int))
+tl_getword(int first, int (*tst)(int))
 {	int i=0; char c;
 
 	yytext[i++]= (char ) first;
@@ -34,7 +36,7 @@ getword(int first, int (*tst)(int))
 }
 
 static int
-follow(int tok, int ifyes, int ifno)
+tl_follow(int tok, int ifyes, int ifno)
 {	int c;
 	char buf[32];
 	extern int tl_yychar;
@@ -73,7 +75,7 @@ tl_lex(void)
 	} while (c == ' ');	/* '\t' is removed in tl_main.c */
 
 	if (islower(c))
-	{	getword(c, isalnum_);
+	{	tl_getword(c, isalnum_);
 		if (strcmp("true", yytext) == 0)
 		{	Token(TRUE);
 		}
@@ -102,12 +104,12 @@ tl_lex(void)
 	}
 
 	switch (c) {
-	case '/' : c = follow('\\', AND, '/'); break;
-	case '\\': c = follow('/', OR, '\\'); break;
-	case '&' : c = follow('&', AND, '&'); break;
-	case '|' : c = follow('|', OR, '|'); break;
-	case '[' : c = follow(']', ALWAYS, '['); break;
-	case '-' : c = follow('>', IMPLIES, '-'); break;
+	case '/' : c = tl_follow('\\', AND, '/'); break;
+	case '\\': c = tl_follow('/', OR, '\\'); break;
+	case '&' : c = tl_follow('&', AND, '&'); break;
+	case '|' : c = tl_follow('|', OR, '|'); break;
+	case '[' : c = tl_follow(']', ALWAYS, '['); break;
+	case '-' : c = tl_follow('>', IMPLIES, '-'); break;
 	case '!' : c = NOT; break;
 	case 'U' : c = U_OPER; break;
 	case 'V' : c = V_OPER; break;
@@ -129,7 +131,7 @@ tl_lookup(char *s)
 			return sp;
 
 	sp = (Symbol *) tl_emalloc(sizeof(Symbol));
-	sp->name = (char *) tl_emalloc(strlen(s) + 1);
+	sp->name = (char *) tl_emalloc((int) strlen(s) + 1);
 	strcpy(sp->name, s);
 	sp->next = symtab[h];
 	symtab[h] = sp;

+ 22 - 20
sys/src/cmd/spin/tl_main.c

@@ -1,14 +1,16 @@
 /***** tl_spin: tl_main.c *****/
 
-/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A.               */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
+
 /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
 /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.   */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
 
 #include "tl.h"
 
@@ -24,8 +26,8 @@ unsigned long	All_Mem = 0;
 static char	uform[4096];
 static int	hasuform=0, cnt=0;
 
-static void	tl_stats(void);
-static void	non_fatal(char *, char *);
+extern void cache_stats(void);
+extern void a_stats(void);
 
 int
 tl_Getchar(void)
@@ -48,6 +50,15 @@ tl_UnGetchar(void)
 	if (cnt > 0) cnt--;
 }
 
+static void
+tl_stats(void)
+{	extern int Stack_mx;
+	printf("total memory used: %9ld\n", All_Mem);
+	printf("largest stack sze: %9d\n", Stack_mx);
+	cache_stats();
+	a_stats();
+}
+
 int
 tl_main(int argc, char *argv[])
 {	int i;
@@ -67,7 +78,7 @@ tl_main(int argc, char *argv[])
 						argv[1][i] = ' ';
 				}
 				strcpy(uform, argv[1]);
-				hasuform = strlen(uform);
+				hasuform = (int) strlen(uform);
 				break;
 		case 'v':	tl_verbose++;
 				break;
@@ -90,15 +101,6 @@ nogood:		printf("usage:\tspin [-v] [-n] -f formula\n");
 	return tl_errs;
 }
 
-static void
-tl_stats(void)
-{	extern int Stack_mx;
-	printf("total memory used: %9ld\n", All_Mem);
-	printf("largest stack sze: %9d\n", Stack_mx);
-	cache_stats();
-	a_stats();
-}
-
 #define Binop(a)		\
 		fprintf(tl_out, "(");	\
 		dump(n->lft);		\
@@ -174,7 +176,7 @@ tl_explain(int n)
 }
 
 static void
-non_fatal(char *s1, char *s2)
+tl_non_fatal(char *s1, char *s2)
 {	extern int tl_yychar;
 	int i;
 
@@ -205,7 +207,7 @@ tl_yyerror(char *s1)
 void
 Fatal(char *s1, char *s2)
 {
-	non_fatal(s1, s2);
+	tl_non_fatal(s1, s2);
 	/* tl_stats(); */
 	exit(1);
 }

+ 8 - 6
sys/src/cmd/spin/tl_mem.c

@@ -1,14 +1,16 @@
 /***** tl_spin: tl_mem.c *****/
 
-/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A.               */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
+
 /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
 /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.   */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
 
 #include "tl.h"
 

+ 24 - 10
sys/src/cmd/spin/tl_parse.c

@@ -1,14 +1,16 @@
 /***** tl_spin: tl_parse.c *****/
 
-/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A.               */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
+
 /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
 /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.   */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
 
 #include "tl.h"
 
@@ -48,7 +50,7 @@ tl_factor(void)
 		tl_yychar = tl_yylex();
 
 		ptr = tl_factor();
-
+#ifndef NO_OPT
 		if (ptr->ntyp == FALSE
 		||  ptr->ntyp == TRUE)
 			break;	/* [] false == false */
@@ -59,7 +61,7 @@ tl_factor(void)
 
 			ptr = ptr->rgt;	/* [] (p V q) = [] q */
 		}
-
+#endif
 		ptr = tl_nn(V_OPER, False, ptr);
 		break;
 #ifdef NXT
@@ -75,6 +77,7 @@ tl_factor(void)
 		tl_yychar = tl_yylex();
 
 		ptr = tl_factor();
+#ifndef NO_OPT
 		if (ptr->ntyp == TRUE
 		||  ptr->ntyp == FALSE)
 			break;	/* <> true == true */
@@ -88,7 +91,7 @@ tl_factor(void)
 			ptr = ptr->rgt;
 			/* fall thru */
 		}
-
+#endif
 		ptr = tl_nn(U_OPER, True, ptr);
 
 		break;
@@ -118,6 +121,7 @@ bin_simpler(Node *ptr)
 	if (ptr)
 	switch (ptr->ntyp) {
 	case U_OPER:
+#ifndef NO_OPT
 		if (ptr->rgt->ntyp == TRUE
 		||  ptr->rgt->ntyp == FALSE
 		||  ptr->lft->ntyp == FALSE)
@@ -150,9 +154,11 @@ bin_simpler(Node *ptr)
 					ptr->lft->lft,
 					ptr->rgt->lft), ZN);
 		}
+#endif
 #endif
 		break;
 	case V_OPER:
+#ifndef NO_OPT
 		if (ptr->rgt->ntyp == FALSE
 		||  ptr->rgt->ntyp == TRUE
 		||  ptr->lft->ntyp == TRUE)
@@ -177,20 +183,25 @@ bin_simpler(Node *ptr)
 			ptr->rgt = ptr->rgt->rgt;
 			break;
 		}
+#endif
 		break;
 	case IMPLIES:
+#ifndef NO_OPT
 		if (isequal(ptr->lft, ptr->rgt))
 		{	ptr = True;
 			break;
 		}
+#endif
 		ptr = tl_nn(OR, Not(ptr->lft), ptr->rgt);
 		ptr = rewrite(ptr);
 		break;
 	case EQUIV:
+#ifndef NO_OPT
 		if (isequal(ptr->lft, ptr->rgt))
 		{	ptr = True;
 			break;
 		}
+#endif
 		a = rewrite(tl_nn(AND,
 			dupnode(ptr->lft),
 			dupnode(ptr->rgt)));
@@ -201,6 +212,7 @@ bin_simpler(Node *ptr)
 		ptr = rewrite(ptr);
 		break;
 	case AND:
+#ifndef NO_OPT
 		/* p && (q U p) = p */
 		if (ptr->rgt->ntyp == U_OPER
 		&&  isequal(ptr->rgt->rgt, ptr->lft))
@@ -275,9 +287,11 @@ bin_simpler(Node *ptr)
 		{	ptr = ptr->lft;
 			break;
 		}
+#endif
 		break;
 
 	case OR:
+#ifndef NO_OPT
 		/* p || (q U p) == q U p */
 		if (ptr->rgt->ntyp == U_OPER
 		&&  isequal(ptr->rgt->rgt, ptr->lft))
@@ -331,7 +345,7 @@ bin_simpler(Node *ptr)
 		{	ptr = ptr->rgt;
 			break;
 		}		
-
+#endif
 		break;
 	}
 	return ptr;

+ 12 - 25
sys/src/cmd/spin/tl_rewrt.c

@@ -1,14 +1,16 @@
 /***** tl_spin: tl_rewrt.c *****/
 
-/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A.               */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
+
 /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
 /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.   */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
 
 #include "tl.h"
 
@@ -40,7 +42,7 @@ canonical(Node *n)
 {	Node *m;	/* assumes input is right_linked */
 
 	if (!n) return n;
-	if (m = in_cache(n))
+	if ((m = in_cache(n)) != ZN)
 		return m;
 
 	n->rgt = canonical(n->rgt);
@@ -127,11 +129,7 @@ addcan(int tok, Node *n)
 		addcan(tok, n->lft);
 		return;
 	}
-#if 0
-	if ((tok == AND && n->ntyp == TRUE)
-	||  (tok == OR  && n->ntyp == FALSE))
-		return;
-#endif
+
 	N = dupnode(n);
 	if (!can)	
 	{	can = N;
@@ -196,7 +194,7 @@ Canonical(Node *n)
 
 	can = ZN;
 	addcan(tok, n);
-#if 1
+#if 0
 	Debug("\nA0: "); Dump(can); 
 	Debug("\nA1: "); Dump(n); Debug("\n");
 #endif
@@ -233,11 +231,6 @@ Canonical(Node *n)
 			{	marknode(AND, p);
 				continue;
 			}
-			if (k2->ntyp == U_OPER
-			&&  anywhere(AND, k2->rgt, can))
-			{	marknode(AND, p);
-				continue;
-			}	/* q && (p U q) = q */
 	}	}
 	if (tok == OR)
 	{	for (m = can; m; m = (m->ntyp == OR) ? m->rgt : ZN)
@@ -269,12 +262,6 @@ Canonical(Node *n)
 			{	marknode(OR, p);
 				continue;
 			}
-			if (k2->ntyp == V_OPER
-			&&  k2->lft->ntyp == FALSE
-			&&  anywhere(AND, k2->rgt, can))
-			{	marknode(OR, p);
-				continue;
-			}	/* p || (F V p) = p */
 	}	}
 	for (m = can, prev = ZN; m; )	/* remove marked nodes */
 	{	if (m->ntyp == -1)
@@ -301,7 +288,7 @@ Canonical(Node *n)
 		m = m->rgt;
 	}
 out:
-#if 1
+#if 0
 	Debug("A2: "); Dump(can); Debug("\n");
 #endif
 	if (!can)

+ 28 - 37
sys/src/cmd/spin/tl_trans.c

@@ -1,14 +1,16 @@
 /***** tl_spin: tl_trans.c *****/
 
-/* Copyright (c) 1995-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1995-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Written by Gerard J. Holzmann, Bell Laboratories, U.S.A.               */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
+
 /* Based on the translation algorithm by Gerth, Peled, Vardi, and Wolper, */
 /* presented at the PSTV Conference, held in 1995, Warsaw, Poland 1995.   */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
 
 #include "tl.h"
 
@@ -40,7 +42,7 @@ static int	set_prefix(char *, int, Graph *);
 static void	Addout(char *, char *);
 static void	fsm_trans(Graph *, int, char *);
 static void	mkbuchi(void);
-static void	expand(Graph *);
+static void	expand_g(Graph *);
 static void	fixinit(Node *);
 static void	liveness(Node *);
 static void	mk_grn(Node *);
@@ -131,6 +133,7 @@ mk_grn(Node *n)
 {	Graph *p;
 
 	n = right_linked(n);
+more:
 	for (p = Nodes_Set; p; p = p->nxt)
 		if (p->outgoing
 		&&  has_clause(AND, p, n))
@@ -138,6 +141,11 @@ mk_grn(Node *n)
 				(unsigned char) Red_cnt;
 			Lab_cnt++;
 		}
+
+	if (n->ntyp == U_OPER)	/* 3.4.0 */
+	{	n = n->rgt;
+		goto more;
+	}
 }
 
 static void
@@ -347,6 +355,14 @@ fsm_trans(Graph *p, int count, char *curnm)
 			sprintf(nwnm, "%s_%s", prefix, s->name);
 		} else
 			strcpy(nwnm, "accept_all");
+
+		if (tl_verbose)
+		{	printf("maxred=%d, count=%d, curnm=%s, nwnm=%s ",
+				Max_Red, count, curnm, nwnm);
+			printf("(greencnt=%d,%d, redcnt=%d,%d)\n",
+				r->grncnt, r->isgrn[0],
+				r->redcnt, r->isred[0]);
+		}
 		addtrans(p, curnm, r->Old, nwnm);
 	}
 }
@@ -625,10 +641,9 @@ not_new(Graph *g)
 }
 
 static void
-expand(Graph *g)
+expand_g(Graph *g)
 {	Node *now, *n1, *n2, *nx;
 	int can_release;
-	extern void cache_dump(void);
 
 	if (!g->New)
 	{	Debug2("\nDone with %s", g->name->name);
@@ -681,14 +696,7 @@ expand(Graph *g)
 	g->New = g->New->nxt;
 	now->nxt = ZN;
 
-	if (now->ntyp != TRUE
-#if 1
-/* 3.4.0 */
-		)
-#else
-/* 3.3.9 */
-	&&  now->ntyp != FALSE)
-#endif
+	if (now->ntyp != TRUE)
 	{	if (g->Old)
 		{	for (n1 = g->Old; n1->nxt; n1 = n1->nxt)
 				if (isequal(now, n1))
@@ -702,24 +710,7 @@ expand(Graph *g)
 out:
 	switch (now->ntyp) {
 	case FALSE:
-#if 1
-/* 3.4.0 */
-push_stack(g);
-#else
-		releasenode(1, now);
-		for (n1 = g->Old; n1; n1 = n2)
-		{	n2 = n1->nxt;
-			releasenode(1, n1);
-		}
-		for (n1 = g->New; n1; n1 = n2)
-		{	n2 = n1->nxt;
-			releasenode(1, n1);
-		}
-		for (n1 = g->Next; n1; n1 = n2)
-		{	n2 = n1->nxt;
-			releasenode(1, n1);
-		}
-#endif
+		push_stack(g);
 		break;
 	case TRUE:
 		releasenode(1, now);
@@ -863,9 +854,9 @@ trans(Node *p)
 	op = dupnode(p);
 
 	ng(ZS, getsym(tl_lookup("init")), p, ZN, ZN);
-	while (g = Nodes_Stack)
+	while ((g = Nodes_Stack) != (Graph *) 0)
 	{	Nodes_Stack = g->nxt;
-		expand(g);
+		expand_g(g);
 	}
 	if (newstates)
 		return;

+ 27 - 28
sys/src/cmd/spin/vars.c

@@ -1,14 +1,13 @@
 /***** spin: vars.c *****/
 
-/* Copyright (c) 1991-2000 by Lucent Technologies - Bell Laboratories     */
+/* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
 /* All Rights Reserved.  This software is for educational purposes only.  */
-/* Permission is given to distribute this code provided that this intro-  */
-/* ductory message is not removed and no monies are exchanged.            */
-/* No guarantee is expressed or implied by the distribution of this code. */
-/* Software written by Gerard J. Holzmann as part of the book:            */
-/* `Design and Validation of Computer Protocols,' ISBN 0-13-539925-4,     */
-/* Prentice Hall, Englewood Cliffs, NJ, 07632.                            */
-/* Send bug-reports and/or questions to: gerard@research.bell-labs.com    */
+/* No guarantee whatsoever is expressed or implied by the distribution of */
+/* this code.  Permission is given to distribute this code provided that  */
+/* this introductory message is not removed and no monies are exchanged.  */
+/* Software written by Gerard J. Holzmann.  For tool documentation see:   */
+/*             http://spinroot.com/                                       */
+/* Send all bug-reports and/or questions to: bugs@spinroot.com            */
 
 #include "spin.h"
 #ifdef PC
@@ -23,7 +22,7 @@ extern Symbol	*Fname;
 extern char	Buf[];
 extern int	lineno, depth, verbose, xspin, limited_vis;
 extern int	analyze, jumpsteps, nproc, nstop, columns;
-extern short	no_arrays, Have_claim, Skip_claim;
+extern short	no_arrays, Have_claim;
 extern void	sr_mesg(FILE *, int, int);
 extern void	sr_buf(int, int);
 
@@ -96,12 +95,9 @@ checkvar(Symbol *s, int n)
 {	int	i, oln = lineno;	/* calls on eval() change it */
 	Symbol	*ofnm = Fname;
 
-	if (n >= s->nel || n < 0)
-	{	printf("spin: indexing %s[%d] - size is %d\n",
-			s->name, n, s->nel);
-		non_fatal("indexing array \'%s\'", s->name);
+	if (!in_bound(s, n))
 		return 0;
-	}
+
 	if (s->type == 0)
 	{	non_fatal("undecl var %s (assuming int)", s->name);
 		s->type = INT;
@@ -139,19 +135,20 @@ getglobal(Lextok *sn)
 
 int
 cast_val(int t, int v, int w)
-{	int i=0; short s=0; unsigned char u=0;
+{	int i=0; short s=0; unsigned int u=0;
 
-	if (t == INT || t == CHAN) i = v;
+	if (t == PREDEF || t == INT || t == CHAN) i = v;	/* predef means _ */
 	else if (t == SHORT) s = (short) v;
 	else if (t == BYTE || t == MTYPE)  u = (unsigned char)v;
 	else if (t == BIT)   u = (unsigned char)(v&1);
 	else if (t == UNSIGNED)
 	{	if (w == 0)
 			fatal("cannot happen, cast_val", (char *)0);
-		u = (unsigned char)(v& ((1<<w)-1));
+	/*	u = (unsigned)(v& ((1<<w)-1));		problem when w=32	*/
+		u = (unsigned)(v& (~0u>>(8*sizeof(unsigned)-w)));	/* doug */
 	}
 
-	if (v != i+s+u)
+	if (v != i+s+ (int) u)
 	{	char buf[32]; sprintf(buf, "%d->%d (%d)", v, i+s+u, t);
 		non_fatal("value (%s) truncated in assignment", buf);
 	}
@@ -166,9 +163,7 @@ setglobal(Lextok *v, int m)
 	else
 	{	int n = eval(v->lft);
 		if (checkvar(v->sym, n))
-		{	if (v->sym->nbits > 0)
-				m = (m & ((1<<v->sym->nbits)-1));	
-			v->sym->val[n] = m;
+		{	v->sym->val[n] = cast_val(v->sym->type, m, v->sym->nbits);
 			v->sym->setat = depth;
 	}	}
 	return 1;
@@ -208,14 +203,18 @@ dumpclaims(FILE *fd, int pid, char *s)
 void
 dumpglobals(void)
 {	Ordered *walk;
-	Lextok *dummy;
+	static Lextok *dummy = ZN;
 	Symbol *sp;
 	int j;
 
+	if (!dummy)
+		dummy = nn(ZN, NAME, nn(ZN,CONST,ZN,ZN), ZN);
+
 	for (walk = all_names; walk; walk = walk->next)
 	{	sp = walk->entry;
 		if (!sp->type || sp->context || sp->owner
-		||  sp->type == PROCTYPE || sp->type == PREDEF
+		||  sp->type == PROCTYPE  || sp->type == PREDEF
+		||  sp->type == CODE_FRAG || sp->type == CODE_DECL
 		||  (sp->type == MTYPE && ismtype(sp->name)))
 			continue;
 
@@ -233,7 +232,6 @@ dumpglobals(void)
 			&&  (sp->setat < depth
 			&&   jumpsteps != depth))
 				continue;
-			dummy = nn(ZN, NAME, nn(ZN,CONST,ZN,ZN), ZN);
 			dummy->sym = sp;
 			dummy->lft->val = j;
 			/* in case of cast_val warnings, do this first: */
@@ -279,10 +277,13 @@ dumpglobals(void)
 
 void
 dumplocal(RunList *r)
-{	Lextok *dummy;
+{	static Lextok *dummy = ZN;
 	Symbol *z, *s = r->symtab;
 	int i;
 
+	if (!dummy)
+		dummy = nn(ZN, NAME, nn(ZN,CONST,ZN,ZN), ZN);
+
 	for (z = s; z; z = z->next)
 	{	if (z->type == STRUCT)
 		{	dump_struct(z, z->name, r);
@@ -298,7 +299,6 @@ dumplocal(RunList *r)
 			&&   jumpsteps != depth))
 				continue;
 
-			dummy = nn(ZN, NAME, nn(ZN,CONST,ZN,ZN), ZN);
 			dummy->sym = z;
 			dummy->lft->val = i;
 
@@ -306,8 +306,7 @@ dumplocal(RunList *r)
 				r->n->name, r->pid, z->name);
 			if (z->nel > 1) printf("[%d]", i);
 			printf(" = ");
-			sr_mesg(stdout, getval(dummy),
-				z->type == MTYPE);
+			sr_mesg(stdout, getval(dummy), z->type == MTYPE);
 			printf("\n");
 			if (limited_vis && (z->hidden&2))
 			{	int colpos;

+ 1 - 1
sys/src/cmd/spin/version.h

@@ -1 +1 @@
-#define Version	"Spin Version 3.4.0 -- 27 March 2000"
+#define Version	"Spin Version 4.2.5 -- 2 April 2005"

+ 15 - 1
sys/src/cmd/tar.c

@@ -804,6 +804,20 @@ mkpdirs(char *s)
 	}
 }
 
+/* Call access but preserve the error string. */
+static int
+xaccess(char *name, int mode)
+{
+	char err[ERRMAX];
+	int rv;
+
+	err[0] = 0;
+	errstr(err, sizeof err);
+	rv = access(name, mode);
+	errstr(err, sizeof err);
+	return rv;
+}
+
 /* copy a file from the archive into the filesystem */
 /* fname is result of name(), so has two extra bytes at beginning */
 static void
@@ -858,7 +872,7 @@ extract1(int ar, Hdr *hp, char *fname)
 					fd = create(fname, rw, mode);
 				}
 				if (fd < 0 &&
-				    (!dir || access(fname, AEXIST) < 0))
+				    (!dir || xaccess(fname, AEXIST) < 0))
 					fprint(2, "%s: can't create %s: %r\n",
 						argv0, fname);
 			}

+ 3 - 2
sys/src/cmd/tcs/utf.c

@@ -39,15 +39,16 @@ utf_in(int fd, long *notused, struct convert *out)
 		tot += n;
 		for(i=j=0; i<tot; ){
 			c = our_mbtowc(&l, buf+i, tot-i);
-			if(c == -1)
+			if(c == -2)
 				break;
-			if(c == -2){
+			if(c == -1){
 				if(squawk)
 					EPR "%s: bad UTF sequence near byte %ld in input\n", argv0, ninput+i);
 				if(clean)
 					continue;
 				nerrors++;
 				l = Runeerror;
+				c = 1;
 			}
 			runes[j++] = l;
 			i += c;

+ 2 - 2
sys/src/cmd/unix/spin/readme

@@ -1,4 +1,4 @@
 the latest version of sources, documentation, newsletters,
 workshop announcements, etc., for the Spin system can always
-be found online at: http://netlib.bell-labs.com/netlib/spin/whatispin.html
-online references live at: http://cm.bell-labs.com/cm/cs/what/spin/Man.html
+be found online at: http://spinroot.com/spin/whatispin.html
+online references live at: http://spinroot.com/spin/Man/index.html

BIN
sys/src/cmd/unix/spin/spin334.tar.gz


BIN
sys/src/cmd/unix/spin/spin425.tar.gz


+ 150 - 162
sys/src/games/memo.c

@@ -4,6 +4,8 @@
 #include <draw.h>
 #include <event.h>
 
+void memoinit(void);
+void redraw(void);
 void eresized(int);
 void resize(int i);
 void afaces(void);
@@ -11,22 +13,25 @@ void allocblocks(void);
 Image *openface(char *path);
 
 Image *face[18];
-Rectangle brect[36];
 char buf[100];
 ushort winflag, level;
+Image *back;
+Image *fore;
 
-typedef enum{
-	ninit,
-	hide,
-	disc
-}bflag;
+enum
+{
+	Eninit,
+	Eshow,
+	Ehide,
+	Edisc,
+};
 
-struct Block
+struct
 {
-	ushort nr;
-	ushort nc;
-	bflag flag;
-} block[36];
+	Image *face;
+	Rectangle r;
+	int	flag;
+}block[36];
 
 char *buttons[] =
 {
@@ -47,11 +52,13 @@ main(int argc, char *argv[])
 {
 	Mouse m;
 	int i, j;
-	ushort ran, score, attempt, prev, br[2], c[2];
+	ushort ran, score, attempt, prev, br[2];
+	Image *c[2];
 	char *fmt;
 
-	level=16;
-	fmt = "you win in %d attempts!";
+	level = 16;
+	fmt = "win in %d attempts!";
+
 	ARGBEGIN{
 	default:
 		goto Usage;
@@ -59,14 +66,16 @@ main(int argc, char *argv[])
 		level=36;
 		break;
 	}ARGEND
+
 	if(argc){
-	Usage:
+    Usage:
 		fprint(2, "usage: %s [-h]\n", argv0);
 		exits("usage");
 	}
 	if(initdraw(0,0,"memo") < 0)
 		sysfatal("initdraw failed: %r");
 	srand(time(0));
+	memoinit();
 	einit(Emouse);
 
     Start:
@@ -74,46 +83,41 @@ main(int argc, char *argv[])
 	winflag=0;
 	prev=level+1;
 	score=attempt=0;
-	for(i=0;i!=level;i++){
-		block[i].nr=i;
-		block[i].nc=20;
-		block[i].flag=ninit;
-	}
+	for(i=0;i!=level;i++)
+		block[i].flag = Eninit;
+
 	for(i=0;i!=level/2;i++){
 		for(j=0;j!=2;){
-			ran=rand()%level;
-			if(block[ran].nc==20){
-				block[ran].nc=i;
+			ran = rand()%level;
+			if(block[ran].flag == Eninit){
+				block[ran].face = face[i];
+				block[ran].flag = Eshow;
 				j++;
 			}
 		}
 	}
 	eresized(0);
-	for(;;){
-		m=emouse();
+	for(;;m=emouse())
 		if(m.buttons)
 			break;
-	}
+
 	for(i=0;i!=level;i++)
-		block[i].flag=hide;
-	eresized(0);
-	j=0;
+		block[i].flag = Ehide;
+
+	redraw();
+	j = 0;
 	for(;; m=emouse()){
 		switch(m.buttons){
 		case 1:
 			while(m.buttons){
 				for(i=0;i!=level;i++){
-					if(i!=prev && ptinrect(m.xy,brect[i])){
-						if(block[i].flag == hide  && j<2){
-							draw(	screen,
-								brect[i],
-								face[block[i].nc],
-								nil,
-								ZP);
-							c[j]=block[i].nc;
-							br[j]=i;
+					if(i!=prev && ptinrect(m.xy,block[i].r)){
+						if(block[i].flag==Ehide  && j<2){
+							block[i].flag = Eshow;
+							draw(screen, block[i].r, block[i].face, nil, ZP);
+							c[j] = block[i].face;
+							br[j] = prev = i;
 							j++;
-							prev=i;
 						}
 						break;
 					}
@@ -123,120 +127,102 @@ main(int argc, char *argv[])
 			break;
 		case 4:
 			switch(emenuhit(3, &m, &menu)) {
-				case 0:	/* restart */
-					goto Start;
-					break;
-				case 1:
-					level=16;
-					goto Start;
-					break;
-				case 2:
-					level=36;
-					goto Start;
-					break;
-				case 3:
-					exits(0);
-					break;
+			case 0:	/* restart */
+				goto Start;
+				break;
+			case 1:
+				level=16;
+				goto Start;
+				break;
+			case 2:
+				level=36;
+				goto Start;
+				break;
+			case 3:
+				exits(0);
+				break;
 			}
 		}
 		if(j==2){
 			attempt++;
-			prev=level+1;
-			j=0;
-			if(c[0]==c[1]){
+			prev = level+1;
+			j = 0;
+			if(c[0] == c[1]){
 				score++;
-				block[br[0]].flag=disc;
-				block[br[1]].flag=disc;
-				draw(	screen,
-					brect[br[0]],
-					allocimagemix(display,DPalebluegreen,DWhite),
-					nil,
-					ZP);
-				draw(	screen,
-					brect[br[1]],
-					allocimagemix(display,DPalebluegreen,DWhite),
-					nil,
-					ZP);
-			}else{
-				draw(	screen,
-					brect[br[0]],
-					allocimagemix(display, 0x00DDDDFF, 0x00DDDDFF),
-					nil,
-					ZP);
-				draw(	screen,
-					brect[br[1]],
-					allocimagemix(display, 0x00DDDDFF, 0x00DDDDFF),
-					nil,
-					ZP);
+				block[br[0]].flag = Edisc;
+				block[br[1]].flag = Edisc;
+			} else{
+				block[br[0]].flag = Ehide;
+				block[br[1]].flag = Ehide;
 			}
+			redraw();
+			continue;
 		}
-		if(score==level/2){
-			winflag=1;
+		if(score == level/2){
+			winflag = 1;
 			sprint(buf, fmt, attempt);
-			eresized(0);
-			for(;;){
-				m=emouse();
-				if((m.buttons & 1) || (m.buttons & 4))
-				break;
-			}
+			redraw();
+			for(;;m=emouse())
+				if(m.buttons&1 || m.buttons&4)
+					break;
 			goto Start;
 		}
 	}
 }
 
 void
-eresized(int new)
+memoinit(void)
 {
-	ushort i, nx, ny;
-	Point p;
-	Rectangle wr;
+	back = allocimagemix(display, DPalebluegreen,DWhite);
+	fore = allocimagemix(display, 0x00DDDDFF, 0x00DDDDFF);
+}
 
+void
+eresized(int new)
+{
 	if(new && getwindow(display, Refnone) < 0){
 		fprint(2, "can't reattach to window");
 		exits("resized");
 	}
-
 	allocblocks();
-	draw(screen, screen->r, allocimagemix(display, DPalebluegreen,DWhite), nil, ZP);
+	draw(screen, screen->r, back, nil, ZP);
+	redraw();
+}
+
+void
+redraw(void)
+{
+	int i, nx, ny;
+	Rectangle r;
+	Point p;
+
 	if(winflag == 1){
-		nx=screen->r.max.x/8;
-		ny=screen->r.max.y/4;
-		wr=Rect(screen->r.min.x+nx,
-			screen->r.min.y+ny,
-			screen->r.max.x-nx,
-			screen->r.max.y-ny);
-		draw(screen, wr, allocimagemix(display, 0x00DDDDFF, 0x00DDDDFF), nil, ZP);
-		p=addpt(wr.min, Pt(5,5));
-		draw(screen,
-		     Rpt(p, addpt(p, stringsize(font,buf))),
-		     allocimagemix(display,0x00DDDDFF,0x00DDDDFFF),
-		     nil,p);
+		p = Pt(Dx(screen->r)/8, Dy(screen->r)/4);
+		r = screen->r;
+		r.min = addpt(r.min, p);
+		r.max = subpt(r.max, p);
+		draw(screen, r, fore, nil, ZP);
+		p=addpt(r.min, Pt(5,5));
 		string(screen,p,display->black,ZP,font,buf);
-	}else{
-		for(i=0;i!=level;i++){
-			switch(block[i].flag){
-			case ninit:
-				draw(screen,brect[i],face[block[i].nc],nil,ZP);
-				break;
-			case disc:
-				draw(	screen,
-					brect[i],
-					allocimagemix(display,DPalebluegreen,DWhite),
-					nil,
-					ZP);
-				break;
-			case hide:
-				draw(	screen,
-					brect[i],
-					allocimagemix(display, 0x00DDDDFF, 0x00DDDDFF),
-					nil,
-				    	ZP);
-				break;
-			default:
-				fprint(2, "something went wrong!");
-				exits("wrong");
-				break;
-			}
+		return;
+	}
+
+	for(i=0;i!=level;i++){
+		r = block[i].r;
+		switch(block[i].flag){
+		case Eshow:
+			draw(screen, r,block[i].face,nil,ZP);
+			break;
+		case Edisc:
+			draw(screen, r, back, nil, ZP);
+			break;
+		case Ehide:
+			draw(screen, r, fore, nil, ZP);
+			break;
+		default:
+			fprint(2, "something went wrong!");
+			exits("wrong");
+			break;
 		}
 	}
 }
@@ -245,7 +231,7 @@ char *facepaths[] = {
 	/* logos */
 	"/lib/face/48x48x4/g/glenda.1",
 	"/lib/face/48x48x2/p/pjw+9ball.2",
-	
+
 	/* /sys/doc/9.ms authors */
 	"/lib/face/48x48x2/k/ken.1",
 	"/lib/face/48x48x4/b/bobf.1",
@@ -253,7 +239,7 @@ char *facepaths[] = {
 	"/lib/face/48x48x4/p/presotto.1",
 	"/lib/face/48x48x4/r/rob.1",
 	"/lib/face/48x48x4/s/sean.1",
-	
+
 	/* additional authors and luminaries for harder levels */
 	"/lib/face/48x48x4/b/bwk.1",
 	"/lib/face/48x48x4/c/cyoung.1",
@@ -271,40 +257,17 @@ void
 afaces(void)
 {
 	int i;
-	
+
 	for(i=0; i<18; i++)
 		face[i] = openface(facepaths[i]);
 }
 
-void
-allocblocks(void)
-{
-	Rectangle r, b;
-	ushort i, x, y, sq;
-
-	sq=sqrt(level);
-	resize(48*sq+sq*4+17);
-	r=insetrect(screen->r, 5);
-	r=Rect(r.min.x, r.min.y, r.min.x+48*sq+sq*4-1, r.min.y+48*sq+sq*4-1);
-	b.max.y=r.min.y;
-	for(i=level-1, y=0; y!=sq; y++){
-		b.min.y=b.max.y;
-		b.max.y=r.min.y+(r.max.y-r.min.y)*(y+1)/sq;
-		b.max.x=r.min.x;
-		for(x=0; x!=sq; x++, i--){
-			b.min.x=b.max.x;
-			b.max.x=r.min.x+(r.max.x-r.min.x)*(x+1)/sq;
-			brect[i]=insetrect(b, 2 );
-		}
-	}
-}
-
 void
 resize(int i)
 {
 	int fd;
 
-	fd=open("/dev/wctl", OWRITE);
+	fd = open("/dev/wctl", OWRITE);
 	if(fd >= 0){
 		fprint(fd, "resize -dx %d -dy %d", i, i);
 		close(fd);
@@ -317,17 +280,42 @@ openimage(char *path)
 	Image *i;
 	int fd;
 
-	fd=open(path, OREAD);
+	fd = open(path, OREAD);
 	if(fd < 0)
 		sysfatal("open %s: %r", path);
-	i=readimage(display, fd, 0);
+	i = readimage(display, fd, 0);
 	if(i == nil)
 		sysfatal("readimage %s: %r", path);
 	close(fd);
 	return i;
 }
 
-enum { Facesize = 48 };
+enum { 
+	Facesize = 48 };
+
+void
+allocblocks(void)
+{
+	Rectangle r, b;
+	ushort i, x, y, sq;
+
+	sq = sqrt(level);
+	resize(Facesize*sq+sq*4+17);
+	r = insetrect(screen->r, 5);
+	r.max.x = r.min.x+Facesize*sq+sq*4-1;
+	r.max.y = r.min.y+Facesize*sq+sq*4-1;
+	b.max.y = r.min.y;
+	for(i=level-1, y=0; y!=sq; y++){
+		b.min.y = b.max.y;
+		b.max.y = r.min.y+Dy(r)*(y+1)/sq;
+		b.max.x = r.min.x;
+		for(x=0; x!=sq; x++, i--){
+			b.min.x = b.max.x;
+			b.max.x = r.min.x+Dx(r)*(x+1)/sq;
+			block[i].r = insetrect(b, 2 );
+		}
+	}
+}
 
 Image*
 readbit(int fd, ulong chan, char *path)
@@ -370,6 +358,7 @@ readbit(int fd, ulong chan, char *path)
 	img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, 0);
 	if(img == nil)
 		return nil;
+
 	loadimage(img, img->r, data, ndata);
 	return img;
 }
@@ -379,7 +368,7 @@ openface(char *path)
 {
 	char *p;
 	int fd, n;
-	
+
 	p = strstr(path, "48x48x");
 	if(p == nil)
 		return openimage(path);
@@ -391,4 +380,3 @@ openface(char *path)
 	}
 	return openimage(path);
 }
-

Some files were not shown because too many files changed in this diff