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) プレゼン資料

(3) ダウンロード

  • Windows用の実行ファイルと、ソースコードが入っています。
  • [注意] Windows8以降では、exeを実行しようとすると「Windows Defender SmartScreen は認識されないアプリの起動を停止しました。」というメッセージが出て起動をブロックされるようです。
    • これが出たら「詳細情報」をクリックすることで「実行」を選べるようになります。・・・もしこれが怖かったら、実行をあきらめたほうがいいでしょう・・・(私だって責任は取れないので)。
    • (ちなみに、ソースをコンパイルして自分でexeファイルを作るという方法でも解決できます。)
    • このメッセージは、実際に問題があろうとなかろうと、ダウンロードしてきた実行ファイルにデジタル署名がついていなければ、(一度許可されるまでは)必ず出てくるもののようです。

  • 「30日でできる!OS自作入門」で作った「はりぼてOS」上で動く、ES-BASIC ver.0.2b → esb02b_hrb
    • つまり自作OS上で動く自作言語

(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評価が高まると思う。そういう言語を待ってるんだよねー -- 名無しさん 2020-04-30 (木) 12:04:35
  • コメントありがとうございます! そういう路線もありかもしれないですね。 -- K 2020-05-01 (金) 17:44:08

コメントお名前NameLink

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2020-06-04 (木) 17:33:22 (109d)