* ES-BASIC ver.0.2a について -(by [[K]], 2020.04.23) ** (1) ES-BASICとは? -ES-BASICはOSASK計画の川合秀実が中心となって開発しているスクリプト言語です。 -内部ではJITコンパイラ方式を採用しているため、実行はかなり高速です。 -このバージョンのWindows版は、32bit版が''57.5KB''、64bit版が''65.0KB''です(ver.0.2a時点)。 -RUNすればプログラムは直ちに実行されますが、MKEXEするとWindows向けの実行ファイルが生成されます。つまり、ES-BASICはスクリプト言語処理系(インタプリタ言語処理系)であると同時にコンパイラ言語処理系でもあります。 -コンパイラとしてのES-BASICは、単に実行ファイルが生成できるというだけではなく、既存のコンパイラではなかなか生成できないような超コンパクトな実行ファイルを生成するという特徴もあります。 -さらにプログラム中にBASICの命令とx86の機械語を混在させることができます。混ぜずにすべてアセンブラで書くことも可能です。ということでES-BASICはアセンブラであるとも言えます。 -これらすべての機能を全部合わせて65.0KBです。上記の機能のために追加のDLLやプラグインが必要になることはありません。 ** (2) プレゼン資料 -https://speakerdeck.com/hkawai --(2020.04.24)OSC2020オンライン春 ** (3) ダウンロード -http://k.osask.jp/files/esbas02b.zip 174.8KB [2020.05.15] (最新版) -http://k.osask.jp/files/esbas02a.zip 169.8KB [2020.04.23] --Windows用の実行ファイルと、ソースコードが入っています。 --[注意] Windows8以降では、exeを実行しようとすると「Windows Defender SmartScreen は認識されないアプリの起動を停止しました。」というメッセージが出て起動をブロックされるようです。 ---これが出たら「詳細情報」をクリックすることで「実行」を選べるようになります。・・・もしこれが怖かったら、実行をあきらめたほうがいいでしょう・・・(私だって責任は取れないので)。 ---(ちなみに、ソースをコンパイルして自分でexeファイルを作るという方法でも解決できます。) ---このメッセージは、実際に問題があろうとなかろうと、ダウンロードしてきた実行ファイルにデジタル署名がついていなければ、(一度許可されるまでは)必ず出てくるもののようです。 ** (4) デモ(基本機能) -基本的な使い方 --普通に起動すると、コンソールとグラフィックウィンドウの両方が出ます(グラフィックを一切使わない場合は、処理系の起動時に --consonly オプションをつけることもできます)。 --コンソールのほうに「Ok」とでて入力待ちになりますので、テキストを入力してください。 --数字で始まる一行は、プログラムだとみなして記憶します(先頭の数字は行番号だと解釈します)。 --数字で始まらない一行はダイレクトコマンドだとみなして、即座に実行します。 10 printf "hello\n"; // これは記憶されるだけでRUNするまで実行されない。 printf "hello\n"; // これは記憶されずに直ちに実行される。 --コンソールのウィンドウを閉じるか、もしくはexitコマンドを実行すると処理系が終了します。 --グラフィックウィンドウは OPENWIN 命令でサイズを変えることはできるものの、閉じることはできません。 ---- -''(4-1)「グラデーション」''(7行) --以下のプログラムを入力してRUNすると、以下のような実行結果になります。 1000 OPENWIN 256,256 1010 FOR Y=0,255 1020 FOR X=0,255 1030 C=RGBCOL(Y,X,0) 1040 SETPIX X,Y,C 1050 NEXT 1060 NEXT --http://k.osask.jp/files/esb20190827a.png ---- -''(4-2)「マンデルブロ集合」''(36行) --以下のプログラムを入力してRUNすると、下図のような実行結果になります。 --NEWコマンドを入力すればプログラムを消去できるので、ES-BASICを再起動せずに次々とコピペでデモが動かせます。 1010 OPENWIN 512,384 1020 $DI=R07; // R07をプログラム中で使いたいときの慣用句 1030 ALIAS ZX:R01, ZY:R03, XX:R06, YY:R07, CX:R08, CY:R09, N:R10, SN:R11, SX:R12, SY:R13, C:R01 1040 FOR Y=0,383 1050 FOR X=0,511 1060 SN=0 1070 FOR SX=0,3 1080 CX=(X*4+SX)*56+4673536 1090 FOR SY=0,3 1100 CY=(Y*4+SY)*_56-124928 1110 ZX=CX 1120 ZY=CY 1130 FOR N=1,446 1140 XX=ZX*:ZX>>24 1150 YY=ZY*:ZY>>24 1160 IF XX+YY>0X4000000 GOTO SKIP 1170 ZY=ZY*:ZX>>23 1180 ZX=XX+CX-YY 1190 ZY=ZY+CY 1200 NEXT 1210 SKIP: 1220 SN=SN+N 1230 NEXT 1240 NEXT 1250 N=SN>>4; // N=SN/16 (N=0...447) 1260 C=RGBCOL(N,0,0) 1270 IF N>=256 THEN 1280 C=RGBCOL(0,0,0) 1290 IF N<447 THEN 1300 C=RGBCOL(255,N-255,0) 1310 FI 1320 FI 1330 SETPIX X,Y,C 1340 NEXT 1350 LEAPFLUSHWIN 300 1360 NEXT --http://k.osask.jp/files/esb20190827b.png ---- -''(4-3)「迷路作成(穴掘り法)」''(26行) --以下のプログラムを入力してRUNすると、下図のような実行結果になります。 --NEWコマンドを入力すればプログラムを消去できるので、ES-BASICを再起動せずに次々とコピペでデモが動かせます。 1000 OPENWIN 752,496 1010 CHRBOX 47,31,0,0,1,2; // 画面を緑色(2)の塗りつぶした四角(キャラクタ番号#1)で埋め尽くす 1020 ECHR 1,1,0; // 左上に一つだけ穴をあける(キャラクタ番号#0をおく) 1030 FOR I=0,1000000 1040 X=(RAND%23)*2+1 1050 Y=(RAND%15)*2+1 1060 GETCHR X,Y,C 1070 IF C==0 THEN 1080 DOLOOP; // (X,Y)から掘り進める. 1090 D0=0; D1=0; D2=0; D3=0 1100 IF X<45 THEN GETCHR X+1,Y,C; GETCHR X+2,Y,CC; D0=C*CC; FI; // C==1&&CC==1のときのみD0=1になる 1110 IF X> 1 THEN GETCHR X-1,Y,C; GETCHR X-2,Y,CC; D1=C*CC; FI 1120 IF Y<29 THEN GETCHR X,Y+1,C; GETCHR X,Y+2,CC; D2=C*CC; FI 1130 IF Y> 1 THEN GETCHR X,Y-1,C; GETCHR X,Y-2,CC; D3=C*CC; FI 1140 D=D0+D1+D2+D3 1150 IF D==0 GOTO SKIP; // もう掘り進められない 1160 DD=RAND%D 1170 IF D0!=0 THEN IF DD==0 THEN ECHR X+1,Y,0; X=X+2; FI; DD=DD-1; FI 1180 IF D1!=0 THEN IF DD==0 THEN ECHR X-1,Y,0; X=X-2; FI; DD=DD-1; FI 1190 IF D2!=0 THEN IF DD==0 THEN ECHR X,Y+1,0; Y=Y+2; FI; DD=DD-1; FI 1200 IF D3!=0 THEN IF DD==0 THEN ECHR X,Y-1,0; Y=Y-2; FI; DD=DD-1; FI 1210 ECHR X,Y,0 1220 ENDDO 1230 SKIP: 1240 FI 1250 NEXT |http://essen.osask.jp/download/esb20191120a.png| |http://essen.osask.jp/download/esb20191120b.png| --乱数で迷路を作っているので、実行するたびに違う迷路が出てきます。 ---- -''(4-4)「キューブ回転」''(114行) --以下のプログラムを入力してRUNすると、下図のような実行結果になります。 --NEWコマンドを入力すればプログラムを消去できるので、ES-BASICを再起動せずに次々とコピペでデモが動かせます。 1000 OPENWIN 256,160 1010 ARY INT NEW VERTX[8]; ARY INT VERTX[0...]={ 2,2,2,2,0,0,0,0 } 1020 ARY INT NEW VERTY[8]; ARY INT VERTY[0...]={ 2,2,0,0,2,2,0,0 } 1030 ARY INT NEW VERTZ[8]; ARY INT VERTZ[0...]={ 2,0,2,0,2,0,2,0 } 1040 ARY INT NEW VX[8]; ARY INT NEW VY[8]; ARY INT NEW VZ[8] 1050 ARY INT NEW CENTERZ4[6] 1060 ARY INT NEW SCX[8]; ARY INT NEW SCY[8] 1070 ARY INT NEW BUF0[160]; ARY INT NEW BUF1[160] 1080 ARY INT NEW SQUAR[24] 1090 ARY INT SQUAR[0...]={ 0,4,6,2, 1,3,7,5, 0,2,3,1, 0,1,5,4, 4,5,7,6, 6,7,3,2 } 1100 FOR I=0,7 1110 X=VERTX[I]; VERTX[I]=(X-1)*50 1120 Y=VERTY[I]; VERTY[I]=(Y-1)*50 1130 Z=VERTZ[I]; VERTZ[I]=(Z-1)*50 1140 NEXT 1150 ARY INT NEW COL[6]; ARY INT COL[0...]={ 4,2,6,1,5,3 } 1160 THX=0; THY=0; THZ=0 1170 DOLOOP 1180 THX=(THX+182)&65535 1190 THY=(THY+273)&65535 1200 THZ=(THZ+364)&65535 1210 XP=FF16COS(THX); XA=FF16SIN(THX) 1220 YP=FF16COS(THY); YA=FF16SIN(THY) 1230 ZP=FF16COS(THZ); ZA=FF16SIN(THZ) 1240 FOR I=0,7 1250 S=VERTZ[I]*XP; T=VERTY[I]*XA; ZT=S+T 1260 S=VERTY[I]*XP; T=VERTZ[I]*XA; YT=S-T 1270 S=VERTX[I]*YP; T=YA*:ZT>>16; XT=S+T 1280 S=YP*:ZT>>16; T=VERTX[I]*YA; VZ[I]=S-T 1290 S=ZP*:XT>>16; T=ZA*:YT>>16; VX[I]=S-T 1300 S=ZP*:YT>>16; T=ZA*:XT>>16; VY[I]=S+T 1310 NEXT 1320 L=0; FOR I=0,5 1330 K=SQUAR[L]; S=VZ[K] 1340 K=SQUAR[L+1]; T=VZ[K]; S=S+T 1350 K=SQUAR[L+2]; T=VZ[K]; S=S+T 1360 K=SQUAR[L+3]; T=VZ[K] 1370 CENTERZ4[I]=S+T+0X70000000 1380 L=L+4 1390 NEXT 1400 FILLRECT0 160,160,48,0,0 1410 GOSUB DRAWOBJ 1420 IF EINKEY!=0 THEN END; FI 1430 EWAIT 50 1440 ENDDO 1450 // 1460 DRAWOBJ: 1470 FOR I=0,7 1480 T=(VZ[I]+13107200)>>16; // 400<<16? 1490 T=4915200/T; // 150<<16 1500 S=VX[I]*:T>>16; SCX[I]=(S>>15)+128 1510 S=VY[I]*:T>>16; SCY[I]=(S>>15)+80 1520 NEXT 1530 DOLOOP 1540 MAX=0 1550 FOR K=0,5 1560 T=CENTERZ4[K] 1570 IF MAX<T THEN MAX=T; J=K; FI 1580 NEXT 1590 IF MAX==0 THEN RETURN; FI 1600 I=J*4; CENTERZ4[J]=0 1610 K0=SQUAR[I] 1620 K1=SQUAR[I+1] 1630 K2=SQUAR[I+2] 1640 V0X=VX[K0]; V0Y=VY[K0] 1650 V1X=VX[K1]; V1Y=VY[K1] 1660 V2X=VX[K2]; V2Y=VY[K2] 1670 E0X=V1X-V0X 1680 E0Y=V1Y-V0Y 1690 E1X=V2X-V1X 1700 E1Y=V2Y-V1Y 1710 S=E0X*:E1Y>>16; T=E0Y*:E1X>>16 1720 IF S<=T THEN 1730 GOSUB DRAWPOLY 1740 FI 1750 ENDDO 1760 // 1770 DRAWPOLY:; // obj(j, i:brk) 1780 I1=I+3; K=SQUAR[I1] 1790 P0X=SCX[K]; P0Y=SCY[K] 1800 YMIN=99999; YMAX=0 1810 FOR I=I,I1 1820 K=SQUAR[I] 1830 P1X=SCX[K]; P1Y=SCY[K] 1840 IF YMIN>P1Y THEN YMIN=P1Y; FI 1850 IF YMAX<P1Y THEN YMAX=P1Y; FI 1860 IF P0Y!=P1Y THEN 1870 IF P0Y<P1Y THEN 1880 BUF=BUF0; Y0=P0Y; Y1=P1Y; DX=P1X-P0X; X=P0X 1890 ELSE 1900 BUF=BUF1; Y0=P1Y; Y1=P0Y; DX=P0X-P1X; X=P1X 1910 FI 1920 X=X<<16 1930 DX=DX<<16 1940 T=Y1-Y0; DX=DX/T 1950 IF DX>=0 THEN X=X+0X8000; ELSE X=X-0X8000; FI 1960 FOR Y=Y0,Y1 1970 BUF[Y]=X>>16 1980 X=X+DX 1990 NEXT 2000 FI 2010 P0X=P1X; P0Y=P1Y 2020 NEXT 2030 C=COL[J] 2040 FOR Y=YMIN,YMAX 2050 P0X=BUF0[Y] 2060 P1X=BUF1[Y] 2070 IF P0X<=P1X THEN 2080 FILLRECT0 P1X-P0X+1,1,P0X,Y,C 2090 ELSE 2100 FILLRECT0 P0X-P1X+1,1,P1X,Y,C 2110 FI 2120 NEXT 2130 RETURN |http://essen.osask.jp/download/esb20191120c.png| |http://essen.osask.jp/download/esb20191120d.png| |http://essen.osask.jp/download/esb20191120e.png| --こんな感じにくるくる回ります。 --このプログラムは、グラフィックウィンドウがアクティブな状態で、何かキーを押すと終了します。 ---- -''(4-5)「インベーダゲーム」''(146行) --以下のプログラムを入力してRUNすると、下図のような実行結果になります。 --NEWコマンドを入力すればプログラムを消去できるので、ES-BASICを再起動せずに次々とコピペでデモが動かせます。 1000 OPENWIN 324,228 1010 ARY INT NEW FGHT[384]; 1020 ARY INT FGHT[ 0*24...]={0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0} 1030 ARY INT FGHT[ 1*24...]={0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0} 1040 ARY INT FGHT[ 2*24...]={0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0} 1050 ARY INT FGHT[ 3*24...]={0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0} 1060 ARY INT FGHT[ 4*24...]={0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0} 1070 ARY INT FGHT[ 5*24...]={0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0} 1080 ARY INT FGHT[ 6*24...]={0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0} 1090 ARY INT FGHT[ 7*24...]={0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0} 1100 ARY INT FGHT[ 8*24...]={0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0} 1110 ARY INT FGHT[ 9*24...]={0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0} 1120 ARY INT FGHT[10*24...]={0,1,0,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,1,0} 1130 ARY INT FGHT[11*24...]={0,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,0} 1140 ARY INT FGHT[12*24...]={0,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,1,0} 1150 ARY INT FGHT[13*24...]={0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0} 1160 ARY INT FGHT[14*24...]={0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0} 1170 ARY INT FGHT[15*24...]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} 1180 C=0X00FFFF; FORNE I=0,384; T=FGHT[I]; FGHT[I]=T*C; NEXT 1190 ARY INT NEW INVD[512]; 1200 ARY INT INVD[ 0*32...]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} 1210 ARY INT INVD[ 1*32...]={0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0} 1220 ARY INT INVD[ 2*32...]={0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0} 1230 ARY INT INVD[ 3*32...]={0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0} 1240 ARY INT INVD[ 4*32...]={0,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,0} 1250 ARY INT INVD[ 5*32...]={0,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,0} 1260 ARY INT INVD[ 6*32...]={0,1,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,0} 1270 ARY INT INVD[ 7*32...]={0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0} 1280 ARY INT INVD[ 8*32...]={0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0} 1290 ARY INT INVD[ 9*32...]={0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0} 1300 ARY INT INVD[10*32...]={0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0} 1310 ARY INT INVD[11*32...]={0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0} 1320 ARY INT INVD[12*32...]={0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0} 1330 ARY INT INVD[13*32...]={0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0} 1340 ARY INT INVD[14*32...]={0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0} 1350 ARY INT INVD[15*32...]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} 1360 C=0X00FF00; FORNE I=0,512; T=INVD[I]; INVD[I]=T*C; NEXT 1370 ARY INT NEW INV[6*32] 1380 RESTART: 1390 SCORE=0; PNT=1; MWT0=20; FX=18 1400 NXTINV: 1410 IX=7; IY=1; INVLINE=5 1420 LY=0; LWT=0; MWT=MWT0 1430 IDIR=1; WUNIT=1024 1440 FORNE I=0,6 1450 FORNE J=0,26 1460 T=J%5; INV[I*32+J]=T 1470 NEXT 1480 NEXT 1490 DOLOOP 1500 // 表示 1510 GCLS 1520 GPRINTS 34,2,"SCORE: HIGH:" 1530 GPRINTI 82,2,6,SCORE; GPRINTI 226,2,6,HIGH 1540 BITBLT 24,16,FX*8+2,13*16+2,FGHT 1550 FORNE I=0,6 1560 FORNE J=0,26 1570 T=INV[I*32+J]; IF T==1 THEN 1580 BITBLT 32,16,(IX+J)*8+2,(IY+I)*16+2,INVD 1590 FI 1600 NEXT 1610 NEXT 1620 IF LY!=0 THEN 1630 FILLRECT0 2,14,LX*8+5,LY*16+3,6 1640 FI 1650 ; 1660 // インベーダ全滅判定 1670 DOLOOP 1680 J=0 1690 FORNE I=0,26 1700 T=INV[INVLINE*32+I] 1710 IF T!=0 GOTO SKIP0 1720 NEXT 1730 INVLINE=INVLINE-1 1740 IF INVLINE<0 THEN 1750 T=MWT0/3; MWT0=MWT0-T 1760 EWAIT 1024 1770 GOTO NXTINV 1780 FI 1790 ENDDO 1800 SKIP0: 1810 ; 1820 // wait処理 1830 EWAIT WUNIT 1840 WUNIT=40 1850 LWT=LWT-1 1860 ; 1870 // キー入力 1880 J=0 1890 DOLOOP 1900 I=EINKEY 1910 IF I==0X1024 THEN J=_1; FI 1920 IF I==0X1025 THEN J= 1; FI 1930 IF I==0X1026 THEN I=32; FI 1940 IF I==32 THEN IF LWT<=0 THEN 1950 LWT=15; LX=FX+1; LY=13 1960 FI; FI 1970 ENDDO I>0 1980 ; 1990 // 自機の移動 2000 I=FX+J 2010 IF I>=0 THEN IF I<=37 THEN FX=I; FI; FI 2020 ; 2030 // レーザ移動 2040 IF LY>0 THEN 2050 LY=LY-1 2060 IF LY==0 THEN 2070 PNT=PNT-10 2080 IF PNT<1 THEN PNT=1; FI 2090 FI 2100 FI 2110 ; 2120 // あたり判定 2130 J=LX-IX 2140 K=LY-IY 2150 IF K>=0 THEN IF K<=5 THEN IF J>=0 THEN IF J<=24 THEN 2160 I=INV[K*32+J] 2170 IF I>0 THEN 2180 LY=0; J=J-I 2190 FORNE I=0,6 2200 INV[K*32+J+I]=0 2210 NEXT 2220 SCORE=SCORE+PNT 2230 PNT=PNT+1 2240 IF HIGH<SCORE THEN HIGH=SCORE; FI 2250 FI 2260 FI; FI; FI; FI 2270 ; 2280 // インベーダ移動 2290 IF MWT>0 THEN 2300 MWT=MWT-1 2310 ELSE 2320 MWT=MWT0 2330 IX=IX+IDIR 2340 T=0; IF IX<0 THEN T=1; FI; IF IX>14 THEN T=1; FI; IF T!=0 THEN 2350 IF IY+INVLINE==12 THEN 2360 GPRINTS 122,98,"GAME OVER",4 2370 KWAIT 10 2380 GOTO RESTART 2390 FI 2400 IDIR=IDIR*_1 2410 IY=IY+1 2420 IX=IX+IDIR 2430 FI 2440 FI 2450 ENDDO --http://k.osask.jp/files/esb20191218d.png ---- -''(4-6)「ブロック崩し」''(140行) → [[esbasic0015]] ** (5) デモ(コンパイラ機能) -ES-BASICにはコンパイラ機能もあり、Windows用の実行ファイルを簡単に生成できます。生成された実行ファイルはもちろんesbasic.exeやもとになったソースコードなしで動きます。 -また生成される実行ファイルのサイズが非常に小さいという特徴もあり、他のコンパイラには容易には真似できないレベルになっています。 -しかし現在はグラフィック命令のコンパイルには対応していないので、残念ながらコンパイラとして使う際には、コンソール命令だけでプログラムを書く必要があります。 -しかも現在は手抜きで32bit版のES-BASICでないと正しい実行ファイルが生成できません(ちなみにWindowsはOSが64bitでも問題なくesbasic32.exeが実行可能です)。 ---- -''(5-1)「hello」''(1行 → 1076バイト) --以下のプログラムを入力して「mkexe hello.exe」すると、実行ファイルが生成されます。そしてそれを実行すると下図のような実行結果になります。 --もちろんコンパイルせずに、普通にRUNしても問題なく実行できます。 --NEWコマンドを入力すればプログラムを消去できるので、ES-BASICを再起動せずに次々とコピペでサンプルをコンパイルできます。 1000 PRINTF "hello, world\n" --http://k.osask.jp/files/pic20200423a.png ---- -''(5-2)「chars」''(4行 → 1076バイト) --以下のプログラムを入力して「mkexe chars.exe」すると、実行ファイルが生成されます。そしてそれを実行すると下図のような実行結果になります。 --もちろんコンパイルせずに、普通にRUNしても問題なく実行できます。 --NEWコマンドを入力すればプログラムを消去できるので、ES-BASICを再起動せずに次々とコピペでサンプルをコンパイルできます。 1010 FOR I=0x20,0x7e 1020 PRINTF "%c",I 1030 NEXT 1040 PRINTF "\n" --http://k.osask.jp/files/pic20200423b.png ---- -''(5-3)「カレンダー」''(21行 → 1588バイト) --以下のプログラムを入力して「mkexe calendar.exe」すると、実行ファイルが生成されます。そしてそれを実行すると下図のような実行結果になります。 --もちろんコンパイルせずに、普通にRUNしても問題なく実行できます。 --NEWコマンドを入力すればプログラムを消去できるので、ES-BASICを再起動せずに次々とコピペでサンプルをコンパイルできます。 1000 ARY STATIC CONST INT NEW A:[61] 1010 ARY STATIC CONST INT A:[0...]="Jan13Feb40Mar33Apr62May13Jun42Jul63Aug23Sep52Oct03Nov32Dec53" 1020 Y=2020; M=0; M1=0; GETARG Y, M; IF M<1 THEN M=1; M1=12; FI 1030 M=(M-1)*5; A9=0; IF Y%400==0 THEN A9=1; FI 1040 IF Y%4==0 THEN IF Y%100!=0 THEN A9=1; FI; FI 1050 DOLOOP 1060 PRINTF "\n %c%c%c %4d\n\n",A:[M],A:[M+1],A:[M+2],Y 1070 PRINTF "Sun Mon Tue Wed Thu Fri Sat\n" 1080 W=Y; IF M<=5 THEN W=Y-1; FI 1090 W0=W/4; W1=W/100; W2=W/400; W3=A:[M+3]&7 1100 W=(W+W0-W1+W2+W3)%7 1110 IF W>0 THEN FOR D=1,W; PRINTF " "; NEXT; FI 1120 D1=A:[M+4]&7; IF M==5 THEN D1=A9; FI; D1=D1+28 1130 FOR D=1,D1 1140 PRINTF " %2d ",D 1150 W=(W+1)%7 1160 IF W==0 THEN PRINTF "\n"; FI 1170 NEXT 1180 IF W>0 THEN PRINTF "\n"; FI 1190 M=M+5 1200 ENDDO M1*5>M --http://k.osask.jp/files/pic20200423c.png ---- -''(5-4)「コンソール版迷路作成」''(37行 → 1592バイト)(ver.0.2b以降用) --以下のプログラムを入力して「mkexe cmaze.exe」すると、実行ファイルが生成されます。そしてそれを実行すると下図のような実行結果になります。 --もちろんコンパイルせずに、普通にRUNしても問題なく実行できます。 --NEWコマンドを入力すればプログラムを消去できるので、ES-BASICを再起動せずに次々とコピペでサンプルをコンパイルできます。 1000 $RANDSEED=1; GETARG $RANDSEED 1005 ALIAS XY:R03, T:R06; // これを付けるとサイズを小さくできる 1010 ARY INT NEW A[1504] 1020 FOR T=0,1503; A[T]=1; NEXT 1030 A[33]=0; // 1<<5|1 // 左上に一つだけ穴をあける 1040 FOR I=0,1000000 1050 X=(RAND%23)*2+1 1060 Y=(RAND%15)*2+1 1070 XY=X<<5|Y; T=A[XY]; IF T==0 THEN 1080 DOLOOP 1090 D0=0; D1=0; D2=0; D3=0 1100 IF X<45 THEN D0=A[XY+32]; T=A[XY+64]; D0=D0&T; FI 1110 IF X> 1 THEN D1=A[XY-32]; T=A[XY-64]; D1=D1&T; FI 1120 IF Y<29 THEN D2=A[XY+ 1]; T=A[XY+ 2]; D2=D2&T; FI 1130 IF Y> 1 THEN D3=A[XY- 1]; T=A[XY- 2]; D3=D3&T; FI 1140 T=D0+D1+D2+D3 1150 IF T==0 GOTO BRK; D=T 1160 T=RAND%D 1170 IF D0!=0 THEN IF T==0 THEN A[XY+32]=0; X=X+2; FI; T=T-1; FI 1180 IF D1!=0 THEN IF T==0 THEN A[XY-32]=0; X=X-2; FI; T=T-1; FI 1190 IF D2!=0 THEN IF T==0 THEN A[XY+ 1]=0; Y=Y+2; FI; T=T-1; FI 1200 IF D3!=0 THEN IF T==0 THEN A[XY- 1]=0; Y=Y-2; FI; T=T-1; FI 1210 XY=X<<5|Y; A[XY]=0; 1220 ENDDO 1230 FI 1240 BRK: 1250 NEXT 1260 FOR Y=0,30 1270 FOR X=0,46 1280 XY=X<<5|Y; T=A[XY]; IF T==0 THEN 1290 PRINTF " " 1300 ELSE 1310 PRINTF "##" 1320 FI 1330 NEXT 1340 PRINTF "\n" 1350 NEXT --http://k.osask.jp/files/pic20200514a.png ** (6) デモ(アセンブラ機能) -以下のようにアセンブラ命令が使えます。RUNでもMKEXEでもOKです。 -将来的にはMKBINという命令を作って、これでヘッダも自作することで任意のフォーマットのファイルを出力できるようになります(MKBINはMKEXEからEXEファイルヘッダ出力機能を省略しただけの命令)。 1000 XOR ECX,ECX 1010 XOR EAX,EAX 1020 LP: 1030 INC EAX 1040 ADD ECX,EAX 1050 CMP EAX,10 1060 JNE LP 1070 MOV [SUM],ECX 1080 PRINTF "SUM=%d\n",SUM; // (注)この行はアセンブラではない ** (7) デバッグ支援機能 -ここには書ききれないので [[esb_dbg]] に書きました。 ** (8) Q&A -[Q] なぜスクリプト言語とコンパイラとアセンブラを統合するのか?従来通り別々にしておくほうがいいのではないか? --[A] 作ってみると分かるのですが、スクリプト言語とコンパイラには共通部分が多くあります(特にスクリプト言語をJITコンパイラ方式で作った場合は)。そしてこれらの実装の上にアセンブラを追加するのはわずかな追加で済みます。・・・つまりこれらは共通部分が結構あるのです。だから統合しても処理系はあまり大きくなりません。共通部分が多いものをわざわざ別々にする方が私としては不自然に思います。 --別々にしておけば、それぞれ独立して改良できるというメリットがありますが、一方で別々だとバージョンがずれて、スクリプト言語とコンパイラの互換性が維持できなくなることも起こりうるでしょう。統合されていればそのようなことは起きにくくなります。 --また統合されることで、中間ファイルを出力する、中間ファイルを読み込む、などのオーバヘッドはなくなります。 -[Q] それにしても、すごく小さい気がする。スクリプト言語だけ、コンパイラだけ、アセンブラだけとしてみても、65KBはかなり小さいと思うのだが、何か秘密はあるのか?何かずるをしているのではないか?(笑) --[A] どうもありがとうございます。ES-BASIC以外の私の過去の作品を知らないとそう感じるかもしれませんが、今までの作品と比較すると順当というか、まあそんなもんだよな、という感じです(笑)。つまり私は小さく作るのがむやみに得意なんです。 --小さく作るのは私の特技ですが、このES-BASICは[[text0010]]のTJシリーズの延長線上で作ったものです。つまり私は少ない行数で言語を作るのが得意で、行数が少ないから最終的に生成される.exeも小さいだけです。 -[Q] Windowsアプリで1076バイトって、それほどすごくない気がするよ?何年か前にコードゴルフの達人が作っていたのは600バイトくらいだったような気がする。 --[A] おお、なんと話の分かる人がいてくれた! そうなんですよ、かつてはそれくらいが最小サイズの目安だったのです。 --しかし最近はWindowsのマルウェア判定アルゴリズムが幅を利かせていて、それらのexeファイルを勝手にマルウェアだとしてはじくようになってしまったのです(自分のPCの中でビルドして作った場合は見逃してくれる場合もありますが、ダウンロードで入手すると、どんどんはじかれます)。ひどいと思いませんか?ただ小さいだけで、何も悪いことはしていないというのに!これは冤罪ですよ。 --ということで、現在のWindowsでどこまでが許されてどこまでが許されないかをいろいろ試して、それで1076バイトくらいで妥協しました。もしかしたらデジタル署名をつけることで昔のような小さいexeファイルも許してくれるかもしれないですが、ひとまず署名がなくても許される内容を出力するようにしています。 -[Q] なんか異常に小さく作ることにこだわっているみたいだけど、それは何の役に立つのか? --[A] さあ・・・(笑)。私は無駄が嫌いで、ただ削れるだけ削って、できるだけ小さくしてみたいだけです。限界を見たいのです。そしてそういうものを使うのが好きなのです。 * こめんと欄 -メガデモ制作専用の簡単完結な言語を日本で開発できれば、それなりに世界でのIT評価が高まると思う。そういう言語を待ってるんだよねー -- 名無しさん SIZE(10){2020-04-30 (木) 12:04:35} -コメントありがとうございます! そういう路線もありかもしれないですね。 -- [[K]] SIZE(10){2020-05-01 (金) 17:44:08} #comment