Browse Source

- Hirotaka JOE Ohkubo's difference (0.04j4) can be merged with play statement (sound.il required)
- Consider? As the keyword debug
- Allow goto to be omitted if immediately after it is a decimal integer value
- Addition of machine language related functions
- Add tron / troff command (display execution line number)

Version 0.05 - from wonbe005.lzh

Kawamata Akira 23 years ago
parent
commit
b906d49ca1
14 changed files with 1099 additions and 98 deletions
  1. 32 0
      Makefile.tcpp10
  2. 290 0
      ctb.wb
  3. 72 12
      keywords.h
  4. 1 1
      makefile
  5. 20 0
      testcall.wb
  6. 26 0
      testint.wb
  7. 11 0
      testpeekpoke.wb
  8. 105 2
      win32text.c
  9. 5 2
      win32text.h
  10. 473 75
      wonbe.c
  11. 2 2
      wonbe.dsp
  12. BIN
      wonbe.exe
  13. BIN
      wonbe.fx
  14. 62 4
      wonbe.txt

+ 32 - 0
Makefile.tcpp10

@@ -0,0 +1,32 @@
+# Makefile for Wonbe 0.04j4
+# with GNUmake and gcc / Turbo C++ 1.0
+# Hirotaka JOE Ohkubo 2000/12/04
+
+INCLUDE = C:/WWitch/include
+C0WW = C:\\WWitch\\lib\\c0wwjpn1.obj
+LIBS = C:\\WWitch\\lib\\libww.lib C:\\WWitch\\lsic86ww\\lib\\s\\runtime.lib
+
+COPTS = -1 -j1 -d -O -Z -ms! -zPCGROUP -zSDGROUP -zGDGROUP
+CFLAGS = -DWW
+
+all: wonbe.fx wonbe32.exe
+
+wonbe.fx: wonbe.bin
+	mkfent wonbe.cf
+
+wonbe.bin: wonbe.obj
+	tlink /m /c $(C0WW) wonbe.obj, wonbe, wonbe, $(LIBS)
+	exe2fbin wonbe.exe wonbe.bin
+	rm wonbe.exe
+
+wonbe.obj: wonbe.c keywords.h
+	tcc -I$(INCLUDE) $(COPTS) $(CFLAGS) -c wonbe.c
+
+wonbe32.exe: wonbe.o win32text.o
+	gcc -o wonbe32.exe wonbe.o win32text.o -lgdi32
+
+wonbe.o: wonbe.c keywords.h
+	gcc -c -DWIN32 -DCYGWIN wonbe.c
+
+win32text.o: win32text.c win32text.h
+

+ 290 - 0
ctb.wb

@@ -0,0 +1,290 @@
+10 goto 10000
+
+1000 ' 駒表示
+1001 ' X,Y : センター座標, A : 駒データ位置, B : 0x20 で消去, 0x81A1 で '■'
+1002 y = Y : if y >= 0 then locate X,y : print chr(B);
+1003 for i=A to A+4 step 2
+1004 y = Y + @(i+1) : if y >= 0 then locate X + @(i),y : print chr(B);
+1005 next
+1006 return
+
+1100 ' 移動できるかチェック
+1101 ' U,V : センター座標, W : 駒データ位置, F : 0 OK / 1 NG
+1110 F = 1 : @(P) = 1 'ぶず
+1111 if @(1+U+V*12) then goto 1116
+1112 if @(1+U+@(W  )+(V+@(W+1))*12) then goto 1116
+1113 if @(1+U+@(W+2)+(V+@(W+3))*12) then goto 1116
+1114 if @(1+U+@(W+4)+(V+@(W+5))*12) then goto 1116
+1115 F = 0
+1116 @(P)=0 : return
+
+1200 ' スコア表示
+1210 locate 21,11
+1220 if S < 10000 then print " ";
+1230 if S <  1000 then print " ";
+1240 if S <   100 then print " ";
+1250 if S <    10 then print " ";
+1260 print S;
+1270 return
+
+1300 ' ブズ回転
+1310 O = rnd(4)+0x81A8 : locate Q+8,R-4 : print chr(O);
+1320 T = tick + 66
+1330 return
+
+1400 ' データと画面をスクロールダウン
+1401 ' Y : 消えるライン xy座標系
+1410 for i=Y*12+10 to 13 step -1 : @(i)=@(i-12) : next
+1420 for i=1 to 10 : @(i)=0 : next
+1430 for i=Y to 4 step -1 : for j=1 to 10
+1440 locate j+8,i-4 : k=@(i*12+j)
+1450 if k=1 then print "■"; : goto 1460
+1451 if k=2 then print chr(2); : goto 1460
+1452 print " ";
+1460 next : next
+1470 return
+
+3000 ' メインループ
+3010 if T < tick then gosub 1300 ' ブズ回転
+3020 if t < tick then goto 3500 ' 落とす
+
+3100 ' キースキャン
+3110 U = x : V = y : W = a
+3120 k = scan : if k and l then goto 3150 ' 一度手を離せ。
+3130 if k and scan_a  then W = @(W+6) : l = scan_a  : goto 3200
+3131 if k and scan_x2 then U = U + 1  : l = scan_x2 : goto 3200
+3132 if k and scan_x3 then V = V + 1  : l = scan_x3 : goto 3200
+3133 if k and scan_x4 then U = U - 1  : l = scan_x4 : goto 3200
+3140 l = 0 ' 何も押されていない
+3150 waitvb 1
+3160 goto 3000
+
+3200 ' キーによる駒移動
+3210 gosub 1100 ' 移動できるかチェック
+3220 if F then if l = scan_x3 then goto 3600 ' 押し込み
+3230 if F then goto 3000 ' 動かせない。おしまい。
+3240 ' 動かせる。実行。
+3250 if l = scan_x3 then l = 0 ' : t = tick + w ' 下向きだけはリピート可能
+3260 X = x+9 : Y = y-4 : A = a : B = 32 : gosub 1000 ' 今のを消す
+3270 x = U : y = V : a = W
+3280 X = x+9 : Y = y-4 : A = a : B = 0x81A1 : gosub 1000 ' 移動後を表示
+3290 goto 3000
+3299 ' メインループ終わり
+
+3500 ' 時間切れ。一つ下がる
+3510 U = x : V = y + 1 : W = a : gosub 1100
+3520 if F then goto 3600 ' 下がれない。
+3530 X = x+9 : Y = y-4 : A = a : B = 32 : gosub 1000 ' 今のを消す
+3540 y = V : Y = y-4 : B = 0x81A1 : gosub 1000 ' 移動後を表示
+3550 t = tick + w
+3560 play "o1a16" ' 落下音
+3570 goto 3000
+
+3600 ' 着底
+3610 ' 埋まったラインを消す
+3615 play "o1g8"
+3620 @(P)=1
+3621 @(1+x+y*12)=1
+3622 @(1+x+@(a  )+(y+@(a+1))*12)=1
+3623 @(1+x+@(a+2)+(y+@(a+3))*12)=1
+3624 @(1+x+@(a+4)+(y+@(a+5))*12)=1
+3630 for i=y+@(a+1) to y+@(a+5)
+3640 f=0 : @(P)=1
+3650 for j=1+i*12 to 10+i*12
+3660 if @(j)=0 then f=1
+3670 next
+3680 @(P)=0
+3690 if f then goto 3920 ' このラインは消せない。次。
+3710 if i <> R then goto 3780
+3720 ' ブズ抹消!
+3730 locate Q+8,R-4 : print chr(2);
+3740 S=S+50 : gosub 1200 : play "o4e8~c0"
+3760 P=1 : R=22 ' ブズ死亡状態
+3770 goto 3800
+3780 ' ラインだけ消去
+3790 S=S+1 : gosub 1200 : play "g16"
+3800 ' データと画面をスクロールダウン
+3810 Y=i : gosub 1400
+3870 ' ブズ復元
+3880 if P=1 then goto 3920
+3890 ' ブズが落ちてきたブロックに殴られたか?
+3900 if @(P) then P=P+12 : R=R+1 : S=S+75 : gosub 1200 : play "g16c16"
+3910 locate Q+8,R-4 : print chr(O);
+3920 next ' MAX4ブロック分ループ終了。
+
+4000 ' ブズの移動フェーズ
+4010 if P=1 then goto 4300 
+4020 locate Q+8,R-4 : print " "; : c = 4
+4030 goto 4040 + (O and 1) * 4 + (O and 2) '時計回りの苦肉の策
+4040 if @(P+1)=0 then P=P+1 : Q=Q+1 : goto 4050              ' 0x81A8 右 00
+4041 c=c-1 : if c=0 then goto 4080
+4042 if @(P-12)=0 and R>1 then P=P-12 : R=R-1 : goto 4050    ' 0x81AA 上 10
+4043 c=c-1 : if c=0 then goto 4080
+4044 if @(P-1)=0 then P=P-1 : Q=Q-1 : goto 4050              ' 0x81A9 左 01
+4045 c=c-1 : if c=0 then goto 4080
+4046 if @(P+12)=0 then P=P+12 : R=R+1 : goto 4050            ' 0x81AB 下 11
+4047 c=c-1 : if c=0 then goto 4080
+4048 goto 4040
+4050 ' 動けた! 「ぷふぁ」
+4051 ' ぶずが画面上に抜けたらゲームオーバー
+4052 if R < 4 then locate Q+8,R-3 : print chr(1);: goto 4400
+4060 gosub 1300
+4070 goto 4300
+4080 ' ぶずは囲まれた! 「ぎゃう」
+4090 S = S + 100 : gosub 1200 : play "e8~>c0" ': play "o6#0c8#1e8#2g8"
+4100 locate Q+8,R-4 : print chr(2);
+4110 @(P) = 2 : P=1 : Y=R : R=22
+4120 ' この死体でこのラインが埋まるか?
+4130 f=0
+4140 for i=Y*12+1 to Y*12+10
+4150 if @(i)=0 then f=1
+4160 next
+4170 if f then goto 4300
+4180 waitvb 7 : play "g16" : gosub 1400
+4190 S=S+1 : gosub 1200
+
+4300 ' 絶対不可侵領域を塗りつぶしてないか→ゲームオーバー
+4310 f=1
+4320 for i=1+3*12 to 10+3*12
+4330 if @(i) then f=0
+4340 next
+4350 if f then goto 5000 ' 詰まってはいない。
+4400 ' GAME OVER
+4410 play "o3edc"
+4420 locate 10, 9 : print "G A M E";
+4430 locate 10,11 : print "O V E R";
+4440 k=wait
+4450 if scan then goto 4450 ' 手を離せ。
+4455 for i=0 to 17: locate 9,i : print "          ";:next
+4460 goto 10050 ' スタート画面へ。
+
+5000 ' ブズ生成 *スタート時突入ポイント*
+5010 if P<>1 then goto 5100
+5020 Q=rnd(10)+1
+5030 R=16+rnd(7)-rnd(7) : if R = 22 then R=20
+5040 P=Q+R*12 : if @(P) then goto 5020
+5050 gosub 1300
+
+5100 ' 次の駒生成
+5110 for j=4 to 7: locate 22,j : print "    "; : next
+5120 a = b : b = rnd(19)*7+K
+5130 X = 24 : Y = 6 : B = 0x8E9F : A = b : gosub 1000
+5140 x = 5 : y = 2 ' 駒の初期位置
+5150 t = tick + w ' 次のタイムアウト
+5160 l = scan_x3 ' 下が続けて入ってしまうのを避けるため
+5170 goto 3000
+
+9999 end
+
+10000 ' いろいろ準備ちゅう...
+10010 randomize tick
+10020 gosub 20000 ' 表示初期化
+10030 play "cego6c2rco5gec2" ' テーマ音楽、でもない。
+10040 gosub 30000 '駒データ準備
+10049 ' ここから再開
+10050 locate 10, 9 : print "P U S H";
+10051 locate 10,11 : print " K E Y ";
+10060 k = wait
+10070 play "#0c#1e#2g"
+10080 for i=0 to 17: locate 9,i : print "          ";:next
+
+11000 ' ゲーム準備
+11010 b = rnd(19)*7+K ' 最初に落とす駒を準備
+11020 w = 90
+11030 for i=0 to K-1: @(i) = 0 : next
+11040 for i=0 to K-1 step 12 : @(i) = 1 : @(i+11) = 1 : next ' ばんぺいくん
+11050 for i=12*22+1 to K-1 : @(i) = 1 : next ' これもばんぺいくん(昇圧回路不要)
+11060 l = 0
+11070 P = 1 ' ぶず
+11080 S = 0 : gosub 1200 ' score
+11090 goto 5000 ' メインループ
+
+20000 ' 画面初期化
+20010 cls
+20020 for i=0 to 17: locate 8,i: print "左";: locate 19,i:print "右";: next
+20030 locate 2,3 : print "きゃっち";
+20040 locate 4,4 : print "ざ";
+20050 locate 2,5 : print "Buzz";
+20060 locate 2,7 : print "by";
+20070 locate 2,8 : print "流れ星の";
+20080 locate 3,9 : print "ジョヲ";
+20090 locate 22,2 : print "NEXT";
+20100 locate 21,3 : print "┏━━━━┓";
+20110 locate 21,4 : print "┃    ┃";
+20111 locate 21,5 : print "┃    ┃";
+20112 locate 21,6 : print "┃    ┃";
+20113 locate 21,7 : print "┃    ┃";
+20120 locate 21,8 : print "┗━━━━┛";
+20130 locate 21,10 : print "SCORE";
+29999 return
+
+30000 ' 駒の形
+30001 ' read - data 文も欲しくなる...
+30002 '   データ形式 (7 words/駒)
+30003 '   (センター座標からの x offset, y offset) × 3, 回転先駒データ位置
+30004 K = 23 * 12 : ' フィールド記憶領域の次に駒データを入れるベース位置
+30005 k = K
+30006 ' 縦棒 ID = 0
+30007 @(k  ) =  0 : @(k+1) = -2 : @(k+2) =  0 : @(k+3) = -1
+30008 @(k+4) =  0 : @(k+5) =  1 : @(k+6) = k+7: k = k + 7
+30009 ' 横棒 ID = 1
+30010 @(k  ) = -1 : @(k+1) =  0 : @(k+2) = -2 : @(k+3) =  0
+30011 @(k+4) =  1 : @(k+5) =  0 : @(k+6) = k-7: k = k + 7
+30012 ' 佐渡島 ID = 2
+30013 @(k  ) =  1 : @(k+1) =  0 : @(k+2) =  0 : @(k+3) =  1
+30014 @(k+4) = -1 : @(k+5) =  1 : @(k+6) = k+7: k = k + 7
+30015 ' 立ち佐渡島 ID = 3
+30016 @(k  ) = -1 : @(k+1) = -1 : @(k+2) = -1 : @(k+3) =  0
+30017 @(k+4) =  0 : @(k+5) =  1 : @(k+6) = k-7: k = k + 7
+30018 ' 逆佐渡島 ID = 4
+30019 @(k  ) = -1 : @(k+1) =  0 : @(k+2) =  0 : @(k+3) =  1
+30020 @(k+4) =  1 : @(k+5) =  1 : @(k+6) = k+7: k = k + 7
+30021 ' 立ち逆佐渡島 ID = 5
+30022 @(k  ) =  1 : @(k+1) = -1 : @(k+2) =  1 : @(k+3) =  0
+30023 @(k+4) =  0 : @(k+5) =  1 : @(k+6) = k-7: k = k + 7
+30024 ' L ID=6
+30025 @(k  ) =  0 : @(k+1) = -1 : @(k+2) =  0 : @(k+3) =  1
+30026 @(k+4) =  1 : @(k+5) =  1 : @(k+6) = k+7: k = k + 7
+30027 ' L+1 ID=7
+30028 @(k  ) =  1 : @(k+1) = -1 : @(k+2) =  1 : @(k+3) =  0
+30029 @(k+4) = -1 : @(k+5) =  0 : @(k+6) = k+7: k = k + 7
+30030 ' L+2 ID=8
+30031 @(k  ) = -1 : @(k+1) = -1 : @(k+2) =  0 : @(k+3) = -1
+30032 @(k+4) =  0 : @(k+5) =  1 : @(k+6) = k+7: k = k + 7
+30033 ' L+3 ID=9
+30034 @(k  ) =  1 : @(k+1) =  0 : @(k+2) = -1 : @(k+3) =  0
+30035 @(k+4) = -1 : @(k+5) =  1 : @(k+6) = k-21: k = k + 7
+30036 ' 逆L ID=10
+30037 @(k  ) =  0 : @(k+1) = -1 : @(k+2) =  0 : @(k+3) =  1
+30038 @(k+4) = -1 : @(k+5) =  1 : @(k+6) = k+7: k = k + 7
+30039 ' 逆L+1 ID=11
+30040 @(k  ) = -1 : @(k+1) =  0 : @(k+2) =  1 : @(k+3) =  0
+30041 @(k+4) =  1 : @(k+5) =  1 : @(k+6) = k+7: k = k + 7
+30042 ' 逆L+2 ID=12
+30043 @(k  ) =  1 : @(k+1) = -1 : @(k+2) =  0 : @(k+3) = -1
+30044 @(k+4) =  0 : @(k+5) =  1 : @(k+6) = k+7: k = k + 7
+30045 ' 逆L+3 ID=13
+30046 @(k  ) = -1 : @(k+1) = -1 : @(k+2) = -1 : @(k+3) =  0
+30047 @(k+4) =  1 : @(k+5) =  0 : @(k+6) = k-21: k = k + 7
+30048 ' 凸 ID=14
+30049 @(k  ) =  0 : @(k+1) = -1 : @(k+2) = -1 : @(k+3) =  0
+30050 @(k+4) =  1 : @(k+5) =  0 : @(k+6) = k+7: k = k + 7
+30051 ' 左凸 ID=15
+30052 @(k  ) =  0 : @(k+1) = -1 : @(k+2) = -1 : @(k+3) =  0
+30053 @(k+4) =  0 : @(k+5) =  1 : @(k+6) = k+7: k = k + 7
+30054 ' T ID=16
+30055 @(k  ) =  1 : @(k+1) =  0 : @(k+2) = -1 : @(k+3) =  0
+30056 @(k+4) =  0 : @(k+5) =  1 : @(k+6) = k+7: k = k + 7
+30057 ' ト ID=17
+30058 @(k  ) =  1 : @(k+1) =  0 : @(k+2) =  0 : @(k+3) = -1
+30059 @(k+4) =  0 : @(k+5) =  1 : @(k+6) = k-21: k = k + 7
+30060 ' 田 ID=18
+30061 @(k  ) =  0 : @(k+1) = -1 : @(k+2) = -1 : @(k+3) = -1
+30062 @(k+4) = -1 : @(k+5) =  0 : @(k+6) = k  : k = k + 7
+31000 return
+
+32764 ' 結局仕様書をまとめないとコーディングはできないね。
+32765 ' そう単純じゃなかった。
+32766 ' Catch the Buzz - original on Macintosh
+32767 ' reproduced with WONBE by Hirotaka JOE Ohkubo, 2000/12/07
+

+ 72 - 12
keywords.h

@@ -1,6 +1,8 @@
 /* WONBE predefined keyword IDs */
-/* First Created: Nov.3,2000 by Nashiko */
-/* Copyright 2000 (c) by Pie Dey Co.,Ltd. */
+/* First Created: Nov.3,2000 by Pie Dey Co.,Ltd. */
+
+/* This source code is distributed under GNU General Public License (GPL) */
+/* see http://www.gnu.org/ about GPL */
 
 #define	KEYWORD_IF		0x80
 #define	KEYWORD_PRINT		0x81
@@ -21,20 +23,35 @@
 #define	KEYWORD_SAVE		0x90
 #define	KEYWORD_LOAD		0x91
 #define	KEYWORD_MERGE		0x92
-#define	KEYWORD_RANDOMIZE		0x93
+#define	KEYWORD_RANDOMIZE	0x93
 #define	KEYWORD_EXIT		0x94
 #define	KEYWORD_DEBUG		0x95
 #define	KEYWORD_WAITVB		0x96
 #define	KEYWORD_FILES		0x97
-#define	KEYWORD_AND		0xa0
-#define	KEYWORD_OR		0xa1
-#define	KEYWORD_XOR		0xa2
-#define	KEYWORD_NOT		0xb0
+#define	KEYWORD_PLAY		0x98
+#define	KEYWORD_POKE		0x99
+#define	KEYWORD_CALL		0x9a
+#define	KEYWORD_INT			0x9b
+#define	KEYWORD_TRON		0x9c
+#define	KEYWORD_TROFF		0x9d
+
+#define	KEYWORD_AND			0xa0
+#define	KEYWORD_OR			0xa1
+#define	KEYWORD_XOR			0xa2
+
+#define	KEYWORD_NOT			0xb0
 #define	KEYWORD_SCAN		0xc0
 #define	KEYWORD_WAIT		0xc1
-#define	KEYWORD_RND		0xc2
-#define	KEYWORD_ABS		0xc3
+#define	KEYWORD_RND			0xc2
+#define	KEYWORD_ABS			0xc3
 #define	KEYWORD_TICK		0xc4
+#define	KEYWORD_VARPTR		0xc5
+#define	KEYWORD_VARSEG		0xc6
+#define	KEYWORD_DSEG		0xc7
+#define	KEYWORD_CSEG		0xc8
+#define	KEYWORD_SSEG		0xc9
+#define	KEYWORD_PEEK		0xca
+
 #define	KEYWORD_SCAN_A		0xd0
 #define	KEYWORD_SCAN_B		0xd1
 #define	KEYWORD_SCAN_X1		0xd2
@@ -45,15 +62,58 @@
 #define	KEYWORD_SCAN_Y2		0xd7
 #define	KEYWORD_SCAN_Y3		0xd8
 #define	KEYWORD_SCAN_Y4		0xd9
+
+#define	KEYWORD_AX			0xe0
+#define	KEYWORD_BX			0xe1
+#define	KEYWORD_CX			0xe2
+#define	KEYWORD_DX			0xe3
+#define	KEYWORD_SI			0xe4
+#define	KEYWORD_DI			0xe5
+#define	KEYWORD_DS			0xe6
+#define	KEYWORD_ES			0xe7
+#define	KEYWORD_DEFSEG		0xe8
+
 #define	KEYWORD_THEN		0xf0
-#define	KEYWORD_CHR		0xf1
-#define	KEYWORD_TO		0xf2
+#define	KEYWORD_CHR			0xf1
+#define	KEYWORD_TO			0xf2
 #define	KEYWORD_STEP		0xf3
 
 #define KEYWORDS_STATEMENT_FROM 0x80
-#define KEYWORDS_STATEMENT_TO 0x97
+#define KEYWORDS_STATEMENT_TO 0x9d
 #define KEYWORDS_2OP_FROM 0xa0
 #define KEYWORDS_2OP_TO 0xa2
 
+/*
+WONBE 中間言語フォーマット
+
+ 中間言語は1行を単位として構築される
+
+ プログラムの終わりは0x00 0x00でターミネートされる
+
+ 1行の構造
+
+WORD 行番号 (1-32767)
+任意の中間コードの列
+BYTE 0x0d 行末ターミネータ
+
+ 0x01~0x03を除けば0x0dを単純検索するだけで行末が発見できる
+
+中間コード
+0x00		(予約)
+0x01		次にあるのは10進2バイト整数
+0x02		次にあるのは16進2バイト整数
+0x03		次にあるのは可変長文字列 0x00でターミネート
+0x09		TAB
+0x0d		行末ターミネータ
+0x20~0x2f	そのコードの記号
+0x30~0x39	?
+0x3a~0x3f	そのコードの記号
+0x40		@
+0x41~0x5a	A~Z その名前の変数を示すシンボル
+0x5b~0x60	?
+0x61~0x7A	a~z その名前の変数を示すシンボル
+0x7b~0x7f	?
+0x80~0xff	キーワードの中間言語表現
+*/
 
 /* end of keywords.h */

+ 1 - 1
makefile

@@ -7,7 +7,7 @@ LINKER=..\..\vc15\bin\link
 CC=..\..\vc15\bin\cl
 ASM=..\..\vc15\bin\masm
 
-CFLAGS=/ASw /O /Gs /DWW
+CFLAGS=/ASw /O /Gs /DWW /DVC15
 AFLAGS=-Mx -DDISPLAY_MODE_JAPANESE1
 LFLAGS=/NOD /NOI /MAP
 

+ 20 - 0
testcall.wb

@@ -0,0 +1,20 @@
+100 ' test machine language call
+110 A=varptr(@(0))
+115 gosub 1000
+120 ax=1:bx=2:cx=3:dx=4:si=-1:di=-2
+130 call A
+140 if ax <> 2 then debug "axの値が期待と違います":end
+150 if bx <> 3 then debug "bxの値が期待と違います":end
+160 if cx <> 4 then debug "cxの値が期待と違います":end
+170 if dx <> 5 then debug "dxの値が期待と違います":end
+180 if si <> 0 then debug "siの値が期待と違います":end
+190 if di <> -1 then debug "diの値が期待と違います":end
+900 debug "正常終了":end
+1000 poke A+0,0x40 'inc	ax
+1010 poke A+1,0x43 'inc	bx
+1020 poke A+2,0x41 'inc	cx
+1030 poke A+3,0x42 'inc	dx
+1040 poke A+4,0x46 'inc	si
+1050 poke A+5,0x47 'inc	di
+1060 poke A+6,0xCB 'ret (FAR)
+1090 return

+ 26 - 0
testint.wb

@@ -0,0 +1,26 @@
+100 cx=22
+110 ds=varseg(@(0))
+120 dx=varptr(@(0))
+125 ax=10*256
+130 int 0x17
+140 if ax<>0 then debug "BIOS‚ªƒGƒ‰�[‚ð•Ô‚µ‚Ü‚µ‚½":end
+150 debug "name dump:";
+160 for i=0 to 15:debug peek(varptr(@(0))+i);",";:next:debug
+162 debug "name char:";
+165 for i=0 to 15:debug chr(peek(varptr(@(0))+i));:next:debug
+170 debug
+180 debug "birth_year:";@(8)
+190 debug "birth_month:";peek(varptr(@(0))+18)
+200 debug "birth_day:";peek(varptr(@(0))+19)
+210 debug "sex:";
+220 s = peek(varptr(@(0))+20)
+230 if s=0 then debug "?"
+240 if s=1 then debug "male"
+250 if s=2 then debug "female"
+260 debug "bloodtype:";
+270 b = peek(varptr(@(0))+21)
+280 if b=0 then debug "?"
+290 if b=1 then debug "A"
+300 if b=2 then debug "B"
+310 if b=3 then debug "O"
+320 if b=4 then debug "AB"

+ 11 - 0
testpeekpoke.wb

@@ -0,0 +1,11 @@
+100 a=varptr(A)
+110 s=varseg(A)
+120 debug "変数Aはオフセット";a;",セグメント";s
+130 A=0x1234
+140 defseg=s
+150 if peek(a) <> 0x34 then debug "peekが異常です(!)":end
+160 if peek(a+1) <> 0x12 then  debug "peekが異常です(2)":end
+170 poke a,0xfe
+180 poke a+1,0xdc
+190 if A <> 0xdcfe then debug "pokeが異常です":end
+900 debug "テスト完了"

+ 105 - 2
win32text.c

@@ -1,8 +1,11 @@
 // wonbe Win32 text emulation
-// First Created: Nov.4,2000 by Nashiko
-// Copyright 2000 (c) by Pie Dey Co.,Ltd.
+/* First Created: Nov.4,2000 by Pie Dey Co.,Ltd. */
+
+/* This source code is distributed under GNU General Public License (GPL) */
+/* see http://www.gnu.org/ about GPL */
 
 #include <windows.h>
+#include <stdio.h>
 #include "win32text.h"
 
 #define SCREEN_SIZE_X (224/8)
@@ -282,4 +285,104 @@ void win32_sys_wait( unsigned int val )
 	Sleep( val*10 );
 }
 
+
+static BOOL bPlayingMIDI = FALSE;
+static UINT wDeviceID;
+
+DWORD stopMIDIFile(HWND hwnd)
+{
+	if( bPlayingMIDI ) {
+		mciSendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, (DWORD)NULL);
+    	bPlayingMIDI = FALSE;
+	}
+	return 0;
+}
+
+DWORD playMIDIFile(HWND hWndNotify, LPSTR lpszMIDIFileName)
+{
+    DWORD dwReturn;
+	MCI_OPEN_PARMS mciOpenParms;
+    MCI_PLAY_PARMS mciPlayParms;
+    MCI_STATUS_PARMS mciStatusParms;
+	//MCI_SEQ_SET_PARMS mciSeqSetParms;
+
+    // Open the device by specifying the device and filename.
+    // MCI will attempt to choose the MIDI mapper as the output port.
+    mciOpenParms.lpstrDeviceType = "sequencer";
+    mciOpenParms.lpstrElementName = lpszMIDIFileName;
+    if (dwReturn = mciSendCommand((MCIDEVICEID)NULL, MCI_OPEN,
+        MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
+        (DWORD)(LPVOID) &mciOpenParms))
+    {
+        // Failed to open device. Don't close it; just return error.
+        return (dwReturn);
+    }
+
+    // The device opened successfully; get the device ID.
+    wDeviceID = mciOpenParms.wDeviceID;
+
+	bPlayingMIDI = TRUE;
+
+    // Check if the output port is the MIDI mapper.
+    mciStatusParms.dwItem = MCI_SEQ_STATUS_PORT;
+    if (dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, 
+        MCI_STATUS_ITEM, (DWORD)(LPVOID) &mciStatusParms))
+    {
+        mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD)NULL);
+        return (dwReturn);
+    }
+
+    // The output port is not the MIDI mapper. 
+    // Ask if the user wants to continue.
+    if (LOWORD(mciStatusParms.dwReturn) != MIDI_MAPPER)
+    {
+		//printf("Warning: The MIDI mapper is not available.\n");
+    }
+
+    // Begin playback. The window procedure function for the parent 
+    // window will be notified with an MM_MCINOTIFY message when 
+    // playback is complete. At this time, the window procedure closes 
+    // the device.
+    mciPlayParms.dwCallback = (DWORD) hWndNotify;
+    if (dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY, 
+        (DWORD)(LPVOID) &mciPlayParms))
+    {
+        mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD)NULL);
+        return (dwReturn);
+    }
+
+    return (0L);
+}
+
+// "テキスト音楽「サクラ」"に含まれるdsakura.dllを用いてMMLを再生します
+// サクラは以下より入手できます http://www.text2music.com/
+// dsakura.dllが無ければ音が出ないだけで、エラーにはなりません。
+void win32_play_mml( const char * mml )
+{
+	static BOOL initialized = FALSE;
+	static HMODULE hmod = NULL;
+	static FARPROC pMMLtoMIDI = NULL;
+	if( !initialized ) {
+		HMODULE hmod = LoadLibrary("dsakura");
+		if( hmod != NULL ) {
+			pMMLtoMIDI = GetProcAddress( hmod, "MMLtoMIDI" );
+		} else {
+			printf("LoadLibrary(\"dsakura\") failed\n");
+		}
+		initialized = TRUE;
+	}
+	if( pMMLtoMIDI != NULL ) {
+		char errmsg[256];
+		BOOL b;
+		stopMIDIFile(hwnd);
+		b = (*pMMLtoMIDI)(mml,"$$$.mid",errmsg);
+		if( b == FALSE ) {
+			printf("dsakura: %s\n",errmsg);
+		}
+		playMIDIFile(hwnd, "$$$.mid");
+	} else {
+		printf("play: %s\n", mml );
+	}
+}
+
 // end of win32text.c

+ 5 - 2
win32text.h

@@ -1,6 +1,8 @@
 // wonbe Win32 text emulation
-// First Created: Nov.4,2000 by Nashiko
-// Copyright 2000 (c) by Pie Dey Co.,Ltd.
+/* First Created: Nov.3,2000 by Pie Dey Co.,Ltd. */
+
+/* This source code is distributed under GNU General Public License (GPL) */
+/* see http://www.gnu.org/ about GPL */
 
 int createText();
 void clearText();
@@ -11,5 +13,6 @@ unsigned short win32_wait();
 unsigned short win32_scan();
 unsigned int win32_get_tick_count();
 void win32_sys_wait( unsigned int val );
+void win32_play_mml( const char * mml );
 
 // end of win32text.h

+ 473 - 75
wonbe.c

@@ -1,8 +1,14 @@
 /* wonbe: WonderWitch Basic Environment */
-/* First Created: Nov.3,2000 by Nashiko */
-/* Copyright 2000 (c) by Pie Dey Co.,Ltd. */
+/* First Created: Nov.3,2000 by Pie Dey Co.,Ltd. */
 
-/* This source code is for both VC++6.0 and Turbo C 2.0 */
+/* This source code is distributed under GNU General Public License (GPL) */
+/* see http://www.gnu.org/ about GPL */
+
+/* This source code is for: */
+/*   Visual C++ 1.5 (for WW binary) */
+/*   Visual C++ 6.0 (for Win32 binary) */
+/*   Turbo  C++ 1.0 (for WW binary,    by Hirotaka JOE Ohkubo) */
+/*   GNU Win32 gcc  (for Win32 binary, by Hirotaka JOE Ohkubo) */
 
 #include <stdio.h>
 #include <string.h>
@@ -22,7 +28,18 @@
 #include "win32text.h"
 #endif
 
-char myVersion[] = "0.04";
+/* cygwin でなぜか stdarg.h が読み込まれてない & __GNUC__ が効かない... */
+#ifdef CYGWIN
+#include <stdarg.h>
+#endif
+
+char myVersion[] = "0.05";
+
+#ifdef WW
+#define NEWLINE "\xa\xd"
+#else
+#define NEWLINE "\n"
+#endif
 
 #ifdef WW
 #define MEMMOVE mymemmove
@@ -37,6 +54,7 @@ typedef unsigned char BYTE;
 #endif
 typedef unsigned short WORD;
 typedef signed short SHORT;
+typedef unsigned long DWORD;
 
 #define EOL (0x0d)
 
@@ -51,6 +69,14 @@ typedef void (*NEARPROC)();
 #define WORKAREA_SIZE ((WORD)49152)
 #define LINE_SIZE (256)
 
+/* PLAY statement support */
+#ifdef WW
+#include <il_sound.h>
+SoundIL soundIL;
+extern BYTE *_heap;
+BOOL soundAvailable;
+#endif
+
 /* 実行のみのモードで動いているとき (シリアル経由で端末が居ないとき) */
 BOOL runtimeOnly;
 
@@ -141,11 +167,13 @@ typedef struct {
 KEYWORDITEM keywordsA[] = {
 	{ KEYWORD_AND,"and" },
 	{ KEYWORD_ABS,"abs" },
+	{ KEYWORD_AX,"ax"},
 	{ 0,NULL }
 };
 
 KEYWORDITEM keywordsB[] = {
 	{ KEYWORD_BREAK,"break" },
+	{ KEYWORD_BX, "bx" },
 	{ 0,NULL }
 };
 
@@ -153,17 +181,26 @@ KEYWORDITEM keywordsC[] = {
 	{ KEYWORD_CHR,"chr" },
 	{ KEYWORD_CLS,"cls" },
 	{ KEYWORD_CONT,"cont" },
+	{ KEYWORD_CALL, "call" },
+	{ KEYWORD_CSEG, "cseg" },
+	{ KEYWORD_CX,"cx" },
 	{ 0,NULL }
 };
 
 KEYWORDITEM keywordsD[] = {
 	{ KEYWORD_DEBUG,"debug" },
+	{ KEYWORD_DSEG, "dseg" },
+	{ KEYWORD_DX, "dx" },
+	{ KEYWORD_DI, "di" },
+	{ KEYWORD_DS, "ds" },
+	{ KEYWORD_DEFSEG, "defseg" },
 	{ 0,NULL }
 };
 
 KEYWORDITEM keywordsE[] = {
 	{ KEYWORD_END,"end" },
 	{ KEYWORD_EXIT,"exit" },
+	{ KEYWORD_ES, "es" },
 	{ 0,NULL }
 };
 
@@ -181,6 +218,7 @@ KEYWORDITEM keywordsG[] = {
 
 KEYWORDITEM keywordsI[] = {
 	{ KEYWORD_IF,"if" },
+	{ KEYWORD_INT, "int" },
 	{ 0,NULL }
 };
 
@@ -209,6 +247,9 @@ KEYWORDITEM keywordsO[] = {
 
 KEYWORDITEM keywordsP[] = {
 	{ KEYWORD_PRINT,"print" },
+	{ KEYWORD_PLAY,"play" },
+	{ KEYWORD_PEEK, "peek" },
+	{ KEYWORD_POKE, "poke" },
 	{ 0,NULL }
 };
 
@@ -235,12 +276,23 @@ KEYWORDITEM keywordsS[] = {
 	{ KEYWORD_SCAN_Y4,"scan_y4" },
 	{ KEYWORD_SCAN,"scan" },	/* scanはscna_Xより後になければならない */
 	{ KEYWORD_SAVE,"save" },
+	{ KEYWORD_SSEG, "sseg" },
+	{ KEYWORD_SI, "si" },
 	{ 0,NULL }
 };
+
 KEYWORDITEM keywordsT[] = {
 	{ KEYWORD_THEN,"then" },
 	{ KEYWORD_TO,"to" },
 	{ KEYWORD_TICK,"tick" },
+	{ KEYWORD_TRON,"tron" },
+	{ KEYWORD_TROFF,"troff" },
+	{ 0,NULL }
+};
+
+KEYWORDITEM keywordsV[] = {
+	{ KEYWORD_VARPTR, "varptr" },
+	{ KEYWORD_VARSEG, "varseg" },
 	{ 0,NULL }
 };
 
@@ -261,13 +313,13 @@ KEYWORDITEM * keywordsIndex[26] = {
 	keywordsI, NULL,      NULL,      keywordsL, 
 	keywordsM, keywordsN, keywordsO, keywordsP, 
 	NULL,      keywordsR, keywordsS, keywordsT, 
-	NULL,      NULL,      keywordsW, keywordsX, 
+	NULL,      keywordsV, keywordsW, keywordsX, 
 	NULL,      NULL
 };
 
 /* インタラクティブモード時の1行バッファ */
 BYTE waRawLine[LINE_SIZE];
-BYTE waCoockedLine[LINE_SIZE];
+BYTE waCookedLine[LINE_SIZE];
 
 /* コードとデータを収める領域 */
 WORD codeTop;
@@ -338,87 +390,140 @@ WORD runLineNumber;
 // REQUEST_RUN_FILE or REQUEST_LOAD_FILE経由で処理するときだけTRUEとなる
 BOOL appendMode = FALSE;
 
+// Read/Writeされる擬似変数の置き場所
+WORD defseg;
+WORD registers[KEYWORD_ES-KEYWORD_AX+1];
+
+// トレースモード(tron/troff)
+BOOL traceFlag = FALSE;
+
+// マシン語アクセス関連
+#ifdef VC15
+// VC++1.5のときに使うコード
+WORD getdseg()
+{
+	WORD s;
+	__asm mov s, ds;
+	return s;
+}
+WORD getsseg()
+{
+	WORD s;
+	__asm mov s, ss;
+	return s;
+}
+WORD getcseg()
+{
+	WORD s;
+	__asm mov s, cs;
+	return s;
+}
+#else
+WORD getdseg()
+{
+	return 0;	// DUMMY VALUE
+}
+WORD getsseg()
+{
+	return 0;	// DUMMY VALUE
+}
+WORD getcseg()
+{
+	return 0;	// DUMMY VALUE
+}
+#endif
+
 /* エラー発生 */
 void syntaxError()
 {
-	commonPrint(NULL, "Syntax Error in %d\x07\n", currentLineNumber );
+	commonPrint(NULL, "Syntax Error in %d\x7" NEWLINE, currentLineNumber );
 	bForceToReturnSuper = TRUE;
 	requestNextAction = REQUEST_INTERACTIVE;
 }
 
 void divideByZero()
 {
-	commonPrint(NULL, "Divide by 0 in %d\x07\n", currentLineNumber );
+	commonPrint(NULL, "Divide by 0 in %d\x7" NEWLINE, currentLineNumber );
 	bForceToReturnSuper = TRUE;
 	requestNextAction = REQUEST_INTERACTIVE;
 }
 
 void outOfArraySubscription()
 {
-	commonPrint(NULL, "Out of Array Subscription in %d\x07\n", currentLineNumber );
+	commonPrint(NULL, "Out of Array Subscription in %d\x7" NEWLINE, currentLineNumber );
 	bForceToReturnSuper = TRUE;
 	requestNextAction = REQUEST_INTERACTIVE;
 }
 
 void lineNumberNotFound( WORD lineNumber )
 {
-	commonPrint(NULL, "Line Number %d not Found in %d\x07\n", lineNumber, currentLineNumber );
+	commonPrint(NULL, "Line Number %d not Found in %d\x7" NEWLINE, lineNumber, currentLineNumber );
 	bForceToReturnSuper = TRUE;
 	requestNextAction = REQUEST_INTERACTIVE;
 }
 
 void stackOverflow()
 {
-	commonPrint(NULL, "Stack Overflow in %d\x07\n", currentLineNumber );
+	commonPrint(NULL, "Stack Overflow in %d\x7" NEWLINE, currentLineNumber );
 	bForceToReturnSuper = TRUE;
 	requestNextAction = REQUEST_INTERACTIVE;
 }
 
 void stackUnderflow()
 {
-	commonPrint(NULL, "Stack Underflow in %d\x07\n", currentLineNumber );
+	commonPrint(NULL, "Stack Underflow in %d\x7" NEWLINE, currentLineNumber );
 	bForceToReturnSuper = TRUE;
 	requestNextAction = REQUEST_INTERACTIVE;
 }
 
 void nextWithoutFor()
 {
-	commonPrint(NULL, "Next without For in %d\x07\n", currentLineNumber );
+	commonPrint(NULL, "Next without For in %d\x7" NEWLINE, currentLineNumber );
 	bForceToReturnSuper = TRUE;
 	requestNextAction = REQUEST_INTERACTIVE;
 }
 
 void outOfMemory()
 {
-	commonPrint(NULL, "Out of memory in %d\x07\n", currentLineNumber );
+	commonPrint(NULL, "Out of memory in %d\x7" NEWLINE, currentLineNumber );
 	bForceToReturnSuper = TRUE;
 	requestNextAction = REQUEST_INTERACTIVE;
 }
 
 void loadError()
 {
-	commonPrint(NULL, "File Not Found or Load Error in %d\x07\n", currentLineNumber );
+	commonPrint(NULL, "File Not Found or Load Error in %d\x7" NEWLINE, currentLineNumber );
 	bForceToReturnSuper = TRUE;
 	requestNextAction = REQUEST_INTERACTIVE;
 }
 
 void cantContinue()
 {
-	commonPrint(NULL, "Can't Continue in %d\x07\n", currentLineNumber );
+	commonPrint(NULL, "Can't Continue in %d\x7" NEWLINE, currentLineNumber );
 	bForceToReturnSuper = TRUE;
 	requestNextAction = REQUEST_INTERACTIVE;
 }
 
 void saveError()
 {
-	commonPrint(NULL, "Save Erroor in %d\x07\n", currentLineNumber );
+	commonPrint(NULL, "Save Erroor in %d\x7" NEWLINE, currentLineNumber );
 	bForceToReturnSuper = TRUE;
 	requestNextAction = REQUEST_INTERACTIVE;
 }
 
 void paramError()
 {
-	commonPrint(NULL, "Parameter Erroor in %d\x07\n", currentLineNumber );
+	commonPrint(NULL, "Parameter Erroor in %d\x7" NEWLINE, currentLineNumber );
+	bForceToReturnSuper = TRUE;
+	requestNextAction = REQUEST_INTERACTIVE;
+}
+
+void lineNumberZeroError()
+{
+	// このエラーはエディタが出すものなのでランタイムで発生することはあり得ない
+	// なので現在行番号を報告する意味がない
+	//commonPrint(NULL, "Invalid Line Number 0 in %d\x7" NEWLINE, currentLineNumber );
+	commonPrint(NULL, "Invalid Line Number 0\x7" NEWLINE );
 	bForceToReturnSuper = TRUE;
 	requestNextAction = REQUEST_INTERACTIVE;
 }
@@ -460,10 +565,12 @@ BYTE * skipToEOL( BYTE * p )
 	}
 }
 
-BYTE * skipToNextLine( BYTE * p )
-{
-	return skipToEOL( p+4 );	// +4は行番号2バイト行長さ2バイト
-}
+// 短い関数をインライン展開しないコンパイラ向けの最適化としてマクロ化
+#define skipToNextLine(p) ( skipToEOL(p+4)+1 )
+//BYTE * skipToNextLine( BYTE * p )
+//{
+//	return skipToEOL( p+4 );	// +4は行番号2バイト行長さ2バイト
+//}
 
 #if 1
 #define mytolower(ch) ((ch >= 'A' && ch <= 'Z')? ch - 'A' + 'a' : ch)
@@ -485,12 +592,14 @@ void clearRuntimeInfo()
 {
 	memset( globalVariables, 0, sizeof(globalVariables) );
 	memset( topLevelVariables, 0, sizeof(topLevelVariables) );
-	memset( stacks, 0, sizeof(globalVariables) );
+	memset( stacks, 0, sizeof(stacks) );
+	memset( registers, 0, sizeof(registers) );
 	executionPointer = NULL;
 	resumePointer = NULL;
 	currentLineNumber = 0;
 	localVariables = topLevelVariables;
 	stackPointer = 0;
+	defseg = getdseg();
 	srand(0);
 }
 
@@ -499,6 +608,9 @@ void processLineHeader()
 {
 	if( !bInteractive ) {
 		currentLineNumber = *((WORD *)executionPointer);
+		if( traceFlag ) {
+			commonPrint( NULL, "[%d]", currentLineNumber );
+		}
 		executionPointer += 4;	// +4は行番号2バイト行長さ2バイト
 	} else {
 		currentLineNumber = 0;
@@ -753,7 +865,7 @@ BOOL sourceDump( FILE FAR * fp, WORD from, WORD to )
 				p++;
 			}
 		}
-		b = commonPrint(fp,"\n");
+		b = commonPrint(fp,NEWLINE);
 		if( b == FALSE ) return FALSE;
 	}
 	return TRUE;
@@ -809,6 +921,9 @@ SHORT calcValue()
 		if( pvar == NULL ) return -1;
 		return *pvar;
 	}
+	if( ch >= KEYWORD_AX && ch <= KEYWORD_ES ) {
+		return registers[ch-KEYWORD_AX];
+	}
 	switch( ch ) {
 	case 0x01:	/*		次にあるのは10進2バイト整数 */
 	case 0x02:	/*		次にあるのは16進2バイト整数 */
@@ -887,6 +1002,81 @@ SHORT calcValue()
 		return 1024;
 	case KEYWORD_SCAN_Y4:
 		return 2048;
+	case KEYWORD_DEFSEG:
+		return defseg;
+	case KEYWORD_DSEG:
+		return getdseg();
+	case KEYWORD_CSEG:
+		return getcseg();
+	case KEYWORD_SSEG:
+		return getsseg();
+	case KEYWORD_VARPTR:
+	case KEYWORD_VARSEG:
+		{
+			BOOL requestSeg;
+			SHORT * refer;
+			requestSeg = (ch == KEYWORD_VARSEG);
+			while( TRUE ) {
+				ch = *executionPointer++;
+				if( ch != ' ' && ch != '\t' ) break;
+			}
+			if( ch != '(' ) {
+				syntaxError();
+				return -1;
+			}
+			while( TRUE ) {
+				ch = *executionPointer++;
+				if( ch != ' ' && ch != '\t' ) break;
+			}
+			if( ch == '@' ) {	/* is it l-value? */
+				SHORT * pvar;
+				pvar = getArrayReference();
+				if( pvar == NULL ) return -1;
+				refer = pvar;
+			} else if( ch >= 'A' && ch <= 'Z' ) {
+				refer = &globalVariables[ch-'A'];
+			} else if( ch >= 'a' && ch <= 'z' ) {
+				refer = &localVariables[ch-'a'];
+			} else if( ch >= KEYWORD_AX && ch <= KEYWORD_ES ) {
+				refer = &registers[ch-KEYWORD_AX];
+			} else if( ch == KEYWORD_DEFSEG ) {
+				refer = &defseg;
+			} else {
+				syntaxError();
+				return -1;
+			}
+			while( TRUE ) {
+				ch = *executionPointer++;
+				if( ch != ' ' && ch != '\t' ) break;
+			}
+			if( ch != ')' ) {
+				syntaxError();
+				return -1;
+			}
+#ifdef WW
+			if( requestSeg ) {
+				return getdseg();
+			} else {
+				return (SHORT)refer;
+			}
+#else
+			printf("varseg/varptr: %08x\n", refer );
+			return 0;
+#endif
+		}
+	case KEYWORD_PEEK:
+		{
+			SHORT t;
+			BYTE FAR * fulladdr;
+			t = calcValue();
+			fulladdr = (BYTE FAR *)(((DWORD)defseg << 16) + (WORD)t);
+#ifdef WW
+			return *fulladdr;
+#else
+			printf("peek: %08x\n", fulladdr );
+			return 0;
+#endif
+		}
 	}
 	syntaxError();
 	return -1;
@@ -1065,27 +1255,6 @@ void st_assignment( SHORT * pvar )	/* 
 	*pvar = val;
 }
 
-void st_if()
-{
-	SHORT val;
-	BYTE ch;
-	val = expr();
-	if( bForceToReturnSuper ) return;
-	while( TRUE ) {
-		ch = *executionPointer++;
-		if( ch != ' ' && ch != '\t' ) break;
-	}
-	if( ch != KEYWORD_THEN ) {
-		syntaxError();
-		return;
-	}
-	if( val != 0 ) {
-		return;	/* thenの次から継続実行する */
-	}
-	/* 条件不成立につき、行末まで読み飛ばす */
-	executionPointer = skipToEOL( executionPointer );
-}
-
 void printOrDebug( BOOL bPrint )
 {
 	WORD lastChar;
@@ -1170,7 +1339,7 @@ void printOrDebug( BOOL bPrint )
 		if( bPrint ) {
 			ptextNewline();
 		} else {
-			commonPrint( NULL, "\r\n" );
+			commonPrint( NULL, NEWLINE );
 		}
 	}
 }
@@ -1261,12 +1430,43 @@ void st_return()
 		if( stacks[stackPointer].type == STACK_TYPE_GOSUB ) break;
 	}
 	executionPointer = stacks[stackPointer].returnPointer;
-	if( executionPointer >= waCoockedLine && executionPointer < waCoockedLine+LINE_SIZE ) {
+	if( executionPointer >= waCookedLine && executionPointer < waCookedLine+LINE_SIZE ) {
 		bInteractive = TRUE;
 	}
 	localVariables = stacks[stackPointer].lastLocalVariables;
 }
 
+void st_if()
+{
+	SHORT val;
+	BYTE ch;
+	val = expr();
+	if( bForceToReturnSuper ) return;
+	while( TRUE ) {
+		ch = *executionPointer++;
+		if( ch != ' ' && ch != '\t' ) break;
+	}
+	if( ch != KEYWORD_THEN ) {
+		syntaxError();
+		return;
+	}
+	if( val != 0 ) {
+		while( TRUE ) {
+			ch = *executionPointer;
+			if( ch != ' ' && ch != '\t' ) break;
+			executionPointer++;
+		}
+		if( ch == 0x01 ) {
+			// thenのあとに整数が直接書かれた場合は、それにgotoする。
+			st_goto();
+			return;
+		}
+		return;	/* thenの次から継続実行する */
+	}
+	/* 条件不成立につき、行末まで読み飛ばす */
+	executionPointer = skipToEOL( executionPointer );
+}
+
 void st_for()
 {
 	BYTE ch;
@@ -1376,7 +1576,7 @@ void st_end()
 /* breakステートメント: デバッグ用の中断 */
 void st_break()
 {
-	commonPrint(NULL, "Break in %d\x07\n", currentLineNumber);
+	commonPrint(NULL, "Break in %d\x7" NEWLINE, currentLineNumber);
 	bForceToReturnSuper = TRUE;
 	requestNextAction = REQUEST_INTERACTIVE;
 	resumePointer = executionPointer;	/* contする場所はbreakの次。breakのみの例外処理 */
@@ -1568,7 +1768,7 @@ void st_waitvb()
 void st_files()
 {
 #ifdef WIN32
-	commonPrint( NULL, "files statement not implemented in Win32\x07\n" );
+	commonPrint( NULL, "files statement not implemented in Win32\x7" NEWLINE );
 #endif
 #ifdef WW
 	int i;
@@ -1599,13 +1799,166 @@ void st_files()
 					waRawLine[p++] = statbuf.info[q++];
 				}
 				waRawLine[p++] = '\0';
-				commonPrint( NULL, "%s,%ld,%d\n", waRawLine, statbuf.len, statbuf.count );
+				commonPrint( NULL, "%s,%ld,%d" NEWLINE, waRawLine, statbuf.len, statbuf.count );
 			}
 		} else {
-			commonPrint( NULL, "*File Access Error\x07\n" );
+			commonPrint( NULL, "*File Access Error\x7" NEWLINE );
+		}
+	}
+#endif
+}
+
+void st_play()
+{
+	BYTE ch;
+
+	ch = *executionPointer++;
+	while ( ch == ' ' || ch == '\t' ) {
+		ch = *executionPointer++;
+	}
+	if ( ch != 0x03 ) {
+		syntaxError();
+		return;
+	}
+ 
+#ifdef WIN32
+	win32_play_mml( executionPointer );
+#endif
+#ifdef WW
+	if ( soundAvailable ) {
+		parse_mml( _heap, executionPointer, 0 );
+		bgm_play( _heap, PLAY_SINGLE );
+	}
+#endif
+
+	executionPointer += strlen(executionPointer)+1;
+}
+
+void st_poke()
+{
+	SHORT addr, data;
+	BYTE ch;
+	BYTE FAR * fulladdr;
+	addr = expr();
+	if( bForceToReturnSuper ) return;
+	while( TRUE ) {
+		ch = *executionPointer++;
+		if( ch != ' ' && ch != '\t' ) break;
+	}
+	if( ch != ',' ) {
+		syntaxError();
+		return;
+	}
+	data = expr();
+	if( bForceToReturnSuper ) return;
+	fulladdr = (BYTE FAR *)(((DWORD)defseg << 16) + (WORD)addr);
+#ifdef WW
+	*fulladdr = data;
+#else
+	printf("poke: %08x %02x\n", fulladdr, data );
+#endif
+}
+
+void st_call()
+{
+	SHORT addr;
+	BYTE FAR * fulladdr;
+	addr = expr();
+	if( bForceToReturnSuper ) return;
+	fulladdr = (BYTE FAR *)(((DWORD)defseg << 16) + (WORD)addr);
+#ifdef WW
+#ifdef VC15
+// VC++1.5のときに使うコード
+	__asm {
+		push si
+		push di
+		push bp
+		mov ax,registers[(KEYWORD_AX-KEYWORD_AX)*2]
+		mov bx,registers[(KEYWORD_BX-KEYWORD_AX)*2]
+		mov cx,registers[(KEYWORD_CX-KEYWORD_AX)*2]
+		mov dx,registers[(KEYWORD_DX-KEYWORD_AX)*2]
+		mov si,registers[(KEYWORD_SI-KEYWORD_AX)*2]
+		mov di,registers[(KEYWORD_DI-KEYWORD_AX)*2]
+		mov es,registers[(KEYWORD_ES-KEYWORD_AX)*2]
+		push ds
+		mov ds,registers[(KEYWORD_DS-KEYWORD_AX)*2]
+		call far ptr ss:[fulladdr]
+		pop ds
+		mov registers[(KEYWORD_AX-KEYWORD_AX)*2],ax
+		mov registers[(KEYWORD_BX-KEYWORD_AX)*2],bx
+		mov registers[(KEYWORD_CX-KEYWORD_AX)*2],cx
+		mov registers[(KEYWORD_DX-KEYWORD_AX)*2],dx
+		mov registers[(KEYWORD_SI-KEYWORD_AX)*2],si
+		mov registers[(KEYWORD_DI-KEYWORD_AX)*2],di
+		mov registers[(KEYWORD_ES-KEYWORD_AX)*2],es
+		pop bp
+		pop di
+		pop si
+	}
+#else
+	// VC++ 1.5以外の処理系のためのコードは作っていません。欲しい人、自作しましょう
+#endif
+#else
+	printf("call: %08x\n", fulladdr );
+#endif
+}
+
+void st_int()
+{
+	SHORT number;
+	number = expr();
+	if( bForceToReturnSuper ) return;
+#ifdef WW
+#ifdef VC15
+// VC++1.5のときに使うコード
+	{
+		static BYTE specialIntCallCode[3] = { 0xcd, 0x00, 0xcb };
+		DWORD specialPtr;
+		specialIntCallCode[1] = (BYTE)number;
+		specialPtr = (((DWORD)getdseg() << 16) + (WORD)specialIntCallCode);
+		__asm {
+			push si
+			push di
+			push bp
+			mov ax,registers[(KEYWORD_AX-KEYWORD_AX)*2]
+			mov bx,registers[(KEYWORD_BX-KEYWORD_AX)*2]
+			mov cx,registers[(KEYWORD_CX-KEYWORD_AX)*2]
+			mov dx,registers[(KEYWORD_DX-KEYWORD_AX)*2]
+			mov si,registers[(KEYWORD_SI-KEYWORD_AX)*2]
+			mov di,registers[(KEYWORD_DI-KEYWORD_AX)*2]
+			mov es,registers[(KEYWORD_ES-KEYWORD_AX)*2]
+			push ds
+			mov ds,registers[(KEYWORD_DS-KEYWORD_AX)*2]
+			call far ptr ss:[specialPtr]
+			pop ds
+			mov registers[(KEYWORD_AX-KEYWORD_AX)*2],ax
+			mov registers[(KEYWORD_BX-KEYWORD_AX)*2],bx
+			mov registers[(KEYWORD_CX-KEYWORD_AX)*2],cx
+			mov registers[(KEYWORD_DX-KEYWORD_AX)*2],dx
+			mov registers[(KEYWORD_SI-KEYWORD_AX)*2],si
+			mov registers[(KEYWORD_DI-KEYWORD_AX)*2],di
+			mov registers[(KEYWORD_ES-KEYWORD_AX)*2],es
+			pop bp
+			pop di
+			pop si
 		}
 	}
+#else
+	// VC++ 1.5以外の処理系のためのコードは作っていません。欲しい人、自作しましょう
 #endif
+#else
+	printf("int: %04x\n", number );
+#endif
+}
+
+void st_tron()
+{
+	traceFlag = TRUE;
+}
+
+void st_troff()
+{
+	traceFlag = FALSE;
 }
 
 /* 行エディタ */
@@ -1620,10 +1973,17 @@ void editLine()
 	// 一方、中間言語翻訳の結果は先頭に0x01で始まる10進整数が行番号として入っている
 	// このギャップを転送時に解消しなければならない
 
-	// ここに来ているということは、waCoockedLine[0]が0x01つまり10進整数である //
-	assert( waCoockedLine[0] == 0x01 );
-	wishLineNumber = *((WORD*)&waCoockedLine[1]);
-	p = waCoockedLine+3;
+	// ここに来ているということは、waCookedLine[0]が0x01つまり10進整数である //
+	assert( waCookedLine[0] == 0x01 );
+	wishLineNumber = *((WORD*)&waCookedLine[1]);
+
+	/* 行番号 0 はだめ */
+	if ( wishLineNumber == 0 ) {
+		lineNumberZeroError();
+		return;
+	}
+
+	p = waCookedLine+3;
 	//target = getLineReferenceFromLineNumber( wishLineNumber );
 	target = getInsertionPointFromLineNumber( wishLineNumber );
 	lineNumber = *((WORD*)target);
@@ -1633,7 +1993,6 @@ void editLine()
 		if( ch != ' ' && ch != '\t' ) break;
 	}
 	if( ch == EOL ) {
-		WORD delta;
 		BYTE * from;
 		/* removing the line */
 		if( lineNumber == 0 || lineNumber != wishLineNumber ) {
@@ -1641,12 +2000,11 @@ void editLine()
 			return;
 		}
 		from = skipToNextLine(target);
-		delta = from-target;
 		MEMMOVE( target, from, (WORD)(dataTop-(from-wa)) );
-		dataTop -= delta;
+		dataTop -= from-target;
 	} else {
 		WORD len;	// プログラム領域上に収めるときのサイズ
-		len = skipToEOL(p)-waCoockedLine-1+2+1; //-1は0x01の分。+2は長さ情報。+1はEOL
+		len = skipToEOL(p)-waCookedLine-1+2+1; //-1は0x01の分。+2は長さ情報。+1はEOL
 		if( lineNumber == 0 || lineNumber != wishLineNumber ) {
 			/* insert new line */
 			if( dataTop + len >= WORKAREA_SIZE ) {
@@ -1660,7 +2018,7 @@ void editLine()
 			WORD lost;
 			BYTE * nextline;
 			int delta;
-			nextline = skipToNextLine(target)+1;
+			nextline = skipToNextLine(target);
 			lost = nextline-target;
 			delta = len-lost;
 			if( dataTop + delta >= WORKAREA_SIZE ) {
@@ -1671,11 +2029,11 @@ void editLine()
 			dataTop += delta;
 		}
 		// まず行番号をコピーする
-		*((WORD*)target) = *((WORD*)&waCoockedLine[1]);
+		*((WORD*)target) = *((WORD*)&waCookedLine[1]);
 		// 行の長さを収める
 		*((WORD*)(target+2)) = len;
 		// 残りをコピーする
-		MEMMOVE( target+4, waCoockedLine+3, (WORD)(len-4) );
+		MEMMOVE( target+4, waCookedLine+3, (WORD)(len-4) );
 	}
 }
 
@@ -1684,18 +2042,18 @@ void appendLine()
 {
 	BYTE * target;
 	WORD len;	// プログラム領域上に収めるときのサイズ
-	len = skipToEOL(waCoockedLine+3)-waCoockedLine-1+2+1; //-1は0x01の分。+2は長さ情報。+1はEOL
+	len = skipToEOL(waCookedLine+3)-waCookedLine-1+2+1; //-1は0x01の分。+2は長さ情報。+1はEOL
 	if( dataTop + len >= WORKAREA_SIZE ) {
 		outOfMemory();
 		return;
 	}
 	target = &wa[dataTop-5];	// -5 is len of last-line-marker
 	// まず行番号をコピーする
-	*((WORD*)target) = *((WORD*)&waCoockedLine[1]);
+	*((WORD*)target) = *((WORD*)&waCookedLine[1]);
 	// 行の長さを収める
 	*((WORD*)(target+2)) = len;
 	// 残りをコピーする
-	MEMMOVE( target+4, waCoockedLine+3, (WORD)(len-4) );
+	MEMMOVE( target+4, waCookedLine+3, (WORD)(len-4) );
 	dataTop += len;
 	wa[dataTop-5] = 0;
 	wa[dataTop-4] = 0;
@@ -1705,10 +2063,10 @@ void appendLine()
 }
 
 /* 中間言語に翻訳する */
-BOOL convertInternalCode( BYTE * waCoockedLine, const BYTE * waRawLine )
+BOOL convertInternalCode( BYTE * waCookedLine, const BYTE * waRawLine )
 {
 	const BYTE * src = waRawLine;
-	BYTE * dst = waCoockedLine;
+	BYTE * dst = waCookedLine;
 	while( TRUE ) {
 		if( *src == '\0' ) break;
 		if( *src == '\n' ) break;
@@ -1879,7 +2237,13 @@ NEARPROC statements[KEYWORDS_STATEMENT_TO-KEYWORDS_STATEMENT_FROM+1] = {
 	st_exit,
 	st_debug,
 	st_waitvb,
-	st_files
+	st_files,
+	st_play,
+	st_poke,
+	st_call,
+	st_int,
+	st_tron,
+	st_troff
 };
 
 void interpreterMain()
@@ -1926,8 +2290,14 @@ void interpreterMain()
 				st_assignment( &globalVariables[ch-'A'] );
 			} else if( ch >= 'a' && ch <= 'z' ) {
 				st_assignment( &localVariables[ch-'a'] );
+			} else if( ch >= KEYWORD_AX && ch <= KEYWORD_ES ) {
+				st_assignment( &registers[ch-KEYWORD_AX] );
+			} else if( ch == KEYWORD_DEFSEG ) {
+				st_assignment( &defseg );
 			} else if( ch >= KEYWORDS_STATEMENT_FROM && ch <= KEYWORDS_STATEMENT_TO ) {
 				(*(statements[ch-KEYWORDS_STATEMENT_FROM]))();
+			} else if( ch == '?' ) {
+				st_debug();
 			} else {
 				syntaxError();
 			}
@@ -1940,30 +2310,36 @@ void interpreterMain()
 void interactiveMain( FILE FAR * fp )
 {
 	if( fp == NULL ) {
-		commonPrint(NULL,"OK\n");
+		commonPrint(NULL,"OK" NEWLINE);
 	}
 	while( TRUE ) {
 		BOOL b;
+		WORD l;
 		if( fp == NULL ) {
 			consoleInput( waRawLine, LINE_SIZE );
 		} else {
 			char FAR * r;
 			r = fgets( waRawLine, LINE_SIZE, fp );
 			if( r == NULL ) break;
+			/* ファイル中に LF があると残ってしまうのを消す */
+			l = strlen(waRawLine)-1;
+			if ( waRawLine[l] == '\x0a' ){
+				waRawLine[l] = '\0';
+			}
 		}
 #ifdef WW
 		if( fp == NULL ) {
-			commonPrint( NULL, "\r\n" );
+			commonPrint( NULL, NEWLINE );
 		}
 #endif
 		/* 中間言語に翻訳する */
-		b = convertInternalCode( waCoockedLine, waRawLine );
+		b = convertInternalCode( waCookedLine, waRawLine );
 		if( b == FALSE ) {
 			bForceToReturnSuper = FALSE;
 			continue;
 		}
 		/* 数値で開始されているか? */
-		if( waCoockedLine[0] == 0x01 ) {
+		if( waCookedLine[0] == 0x01 ) {
 			/* 行エディタを呼び出す */
 			if( appendMode ) {
 				appendLine();
@@ -1975,7 +2351,7 @@ void interactiveMain( FILE FAR * fp )
 			}
 		} else {
 			/* その行を実行する */
-			executionPointer = waCoockedLine;
+			executionPointer = waCookedLine;
 			interpreterMain();
 		}
 		if( bForceToReturnSuper ) return;
@@ -2004,6 +2380,7 @@ void do_new()
 {
 	clearRuntimeInfo();
 	bInteractive = TRUE;
+	traceFlag = FALSE;
 	codeTop = 0;
 	wa[0] = 0;
 	wa[1] = 0;
@@ -2172,6 +2549,12 @@ int main( int argc, char *argv[] )
 	createText();
 #endif
 #ifdef WW
+#ifdef CURRENT_DIR_IS_RAM0
+	// シンボルCURRENT_DIR_IS_RAM0を定義してビルドすると
+	// カレントディレクトリは/ram0で走る
+	// 定義しなければ/rom0で走る
+	chdir("/ram0");
+#endif
 	text_screen_init();
 	b = entranceUI();
 	if( b == FALSE ) return 0;
@@ -2179,20 +2562,35 @@ int main( int argc, char *argv[] )
 		comm_set_baudrate(1);
 		comm_open();
 	}
+
+	/* PLAY statement support */
+	soundAvailable = FALSE;
+	if (open_sound_il(&soundIL) == E_FS_SUCCESS) {
+		soundAvailable = TRUE;
+		//  sounddrv_init();  いらないならわざわざ呼ばない。
+		sound_open();
+	}
 #endif
+
 	ptextCLS();
 	if( requestNextAction == REQUEST_NO_ACTION ) {
 		do_new();
 	}
 	if( !runtimeOnly ) {
-		commonPrint(NULL,"ワンべぇ WonderWitch Tiny BASIC Environment Ver %s\n",myVersion);
-		commonPrint(NULL,"Copyright 2000 (c) by Pie Dey Co.,Ltd.\n");
+		commonPrint(NULL,"ワンべぇ WonderWitch Tiny BASIC Environment Ver %s" NEWLINE,myVersion);
+		commonPrint(NULL,"Authors: Pie Dey Co.,Ltd., Hirotaka JOE Ohkubo" NEWLINE);
+		commonPrint(NULL,"This program is distributed under GNU General Public License" NEWLINE);
 	}
 	superMain();
 #ifdef WIN32
 	deleteText();
 #endif
 #ifdef WW
+	/* PLAY statement support */
+	if (soundAvailable) {
+		sound_close();
+		sounddrv_release();
+	}
 	if( !runtimeOnly ) {
 		comm_close();
 	}

+ 2 - 2
wonbe.dsp

@@ -50,7 +50,7 @@ BSC32=bscmake.exe
 # ADD BSC32 /nologo
 LINK32=link.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Winmm.lib /nologo /subsystem:console /machine:I386
 
 !ELSEIF  "$(CFG)" == "wonbe - Win32 Debug"
 
@@ -74,7 +74,7 @@ BSC32=bscmake.exe
 # ADD BSC32 /nologo
 LINK32=link.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib Winmm.lib /nologo /subsystem:console /debug /machine:I386
 
 !ENDIF 
 

BIN
wonbe.exe


BIN
wonbe.fx


File diff suppressed because it is too large
+ 62 - 4
wonbe.txt


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