* ES-BASIC #4
-(by [[K]], 2019.09.06)

** (6) 開発メモ #1
-このメモを書き始めるまで:
--[2012.09.07] OSECPU-VMを作ろうと思い立つ。・・・これより以前の歴史は長すぎるのでここには書かない。
--[2013.03.??] セキュリティキャンプの教材にOSECPU-VMを使おうと決心。
--[2013.08.??] セキュリティキャンプをやっているうちに、OSやVMよりも言語開発に興味がある人の方が多そうだなあと感じた。ということで、OSECPU-VMが一段落ついたら次は言語に行こうと思った。

--[2015.03.17] 言語開発としてKH-FDPLというのを始める。[[K]]にとってはOS/VM系開発から言語処理系開発への切り替えになる。
--[2016.02.17] C言語に永続変数を持たせる「Persistent-C」の開発を始める。・・・まあまあのものはできたけど、なんか物足りない。
--[2016.10.24] 演算子や構文を自由に作れる「Essen」の開発を始める。・・・しかし難航する。
--[2017.06.16] TL-1, TL-2, TL-3 を開発し、プログラミング言語開発入門みたいなことを始める。→[[text0010]]
--[2018.05.31] TJ01~TJ03を開発し、JITコンパイラを作るのは難しくないと立証(→[[text0010]])。・・・その後、JITコンパイラのコード生成を頑張って、C言語並みの実行速度を実現。
--[2019.02.22] OSC2019 Tokyo/Spring で Essen2019-A を発表。Essenのブランド名を冠してはいるものの、もはやJITコンパイラではない。しかしEssenで実現したいことの一部を表現できた。
--[2019.04.16] 言語を何度も作りなおすのに疲れてきたので、言語からいったん離れて、自分の開発効率を大幅に向上できるような、自分専用ライブラリを作ろうと決心。
--[2019.04.29] 開発に使う言語をC言語からC++へ変更することにした。その方が使いやすいライブラリを作りやすいと思ったので。

--[2019.07.12] ついに ES-BASIC の開発を開始する。自作ライブラリがあれば、言語開発は相当にはかどるだろうと思っていたが、実際すごくはかどった。名称のESはもちろん私の言語開発ブランドであるEssenに由来する。→[[esbasic0001]]
--[2019.07.17] PUSH、POP命令を付けることで、グローバル変数しかないのに再帰呼び出しを実現(笑)。
--[2019.07.24] 整数演算しかできないES-BASICだけど、固定小数点演算にすることでマンデルブロ集合の描画に成功。
---(ここの3週間弱は、忙しくてほとんど開発できなかった時期)
--[2019.08.15] スクロール命令を付けたので、スクロールするゲームが作れるようになった。
--[2019.08.23] SecHack365の福岡合宿で、ES-BASIC用のプログラムとして、迷路作成プログラムを作ってみた(穴掘り法)。50分くらいでできた(このうちの半分の時間はバグ取り)。なかなか楽しい。
--[2019.08.27] ラボユース合宿で、ついにプログラムがプログラムを作ってそれを即座に実行するという機能を、ES-BASICに追加。自己書き換えすら可能。ついでにここまでの成果をとりあえず公開。→[[esbasic0003]]
--[2019.09.02] 代入文で、右辺に複数の演算子があるような「式」がやっと使えるようになった。ただし演算子の優先順位は無視していて、1+2*3が9になる。それでも今までよりは格段に便利。
--[2019.09.03] 代入文以外の文脈でも式が使えるようになった。一時変数の乱発が必要なくなり、一気に便利さが増した。
--[2019.09.05] 今までどちらかと言えば軽い持ちで雑に作ってきたES-BASICであったが、たったの830行ほどの処理系でしかないのに、JITコンパイラだから手軽なのに爆速だし、REPLがあるから気軽に実行できるし、プログラムをファイルに保存しなくても、コピー&ペーストで入力して実行できるし、blaライブラリがあるから簡単にグラフィックもできるし、「ああ、もしかしたら私が理想とするプログラミング環境に今までで一番近いのはこいつなのではないか」と直感的に思った。・・・Essenの基本仕様の一つに、「演算子や構文を簡単に拡張するための機能がある」というのがあったが、830行のプログラムなら簡単に手入れできるので、言語が言語を拡張する機能を持っている必要性はもしかしたらないかもしれないとも思った。

-''[2019.09.06(金)]''
--GOTOやGOSUBのとび先で、ラベルを指定できるようになった。これで、単純に行番号を付け直してもプログラムが壊れないように作れるようになった。めでたい。
--一方で、自作ライブラリのKIndexHSクラスにはどうやらrehashまわりにバグがあるらしいことが判明したので、次はこれを直さなければいけないだろう。
--この時点で、esbasic.cppは864行。・・・行数が36行も増えたが、これはgoto先がなかったりラベル定義が重複した場合などにもきちんと対処したため。
--KIndexHSのrehashのバグは、rehashのせいではなかった。KMemPoolのallocが怪しい。しかし別のバグを直したら再発しなくなってしまったので、ひとまずこのバグは追及しないことにする。

-''[2019.09.09(月)]''
--コマンド処理で引数の省略の処理を一般化したらきっとかなり行数が減るだろうと思っていたけど、実際にやってみたら8行しか減らなかった・・・。
--他でもいろいろ工夫して、トータルで500行くらいにできないだろうかと考えているのだけど、それはかなり無理があるかもしれないと思い始めた。

-''[2019.09.11(水)]''
--プログラミング言語に依存しない汎用的な部分をライブラリに追い出して、818行まで減らしたけど、目標の500行にはほど遠い・・・。

-''[2019.09.12(木)]''
--808行にはできた。うーん、あとはJITコンパイラのコア部分を切り出せたらよいのだけど、まだライブラリへ切り出すほどの完成度じゃないんだよな・・・。
--グラフィックの機能については、言語と独立にあってもいい気がするので、これらを追い出せば行数は減らせるな・・・。マイナス70行くらいは行けるんじゃないか?

-''[2019.09.13(金)]''
--ちょっと間に合わせ感はあるけれど、とにかく上記方針で732行まで減らせた!
--「プログラムを小さくするにはどうしたらいいのか」を考えると、このプログラムの本質は何か、どの部分は汎用化してライブラリに追い出してもいいか(再利用可能か)ということを真剣に考えることになるので、すごくいいと思う。でも多くの人はそういう観点でのプログラミングはしていないだろうけど・・・。
--言語を作っていると、特にその言語固有の新しい機能とかを作った場合、それはライブラリとして切り出すことができる。ライブラリにしておけば、その自作言語を使わなくても、ライブラリを利用することで、その新しい機能を利用できるようになる。そのようにライブラリを作った後で言語側を修正すると、言語はライブラリのラッパーになっているだけで、何も新しい機能は提供していないことになる。・・・これが言語処理系の実装方法として正しい姿なのだと私は思う。
--ES-BASICにデバッグ支援機能として、LWAIT命令を付けてみた。これは、line-waitの略で、一行実行するごとにどのくらいwaitを入れるのかをマイクロ秒単位で設定できる。・・・最近のPCはどいつもこいつも速くなってしまい、「動いているところ」を見るのはかなり難しい。たいてい最終結果だけが見える。昔はすごく遅かったので、動いているところを見るのは簡単だったのに。もしかしたら、昔の速度の方がプログラミングの理解がしやすくて、デバッグもやりやすかったのかもしれない。そう思って、実行速度を下げるコマンドを付けてみた・・・というわけだ。
--正直これが有用かどうかは、今の私にはよくわからないけど(さすがにもう速度に関わらずデバッグできてしまうので)、でもプログラムに手を入れずともコマンドを実行してからRUNするだけで、実行速度を自由に上げ下げできるのは結構新鮮だった。
--いろいろ試してみて、マイクロ秒をやめてナノ秒にしてみた。1ミリ秒でも遅すぎる場合があったので。

-''[2019.09.14(土)]''
--なかなかよいアイデアを思いついた。これでES-BASICはデバッグ支援機能において、ユニークな機能を有していると言えることになりそう。
--詳しいことは後日書く予定。

-''[2019.09.17(火)]''
--[[esbasic0005]]を書いた。これはES-BASICの基本部分だけを作るのに必要なプログラムが、"kll0.h"を使った場合にどのくらいになるのかを確認するためのもの。
--とりあえず89行で書けることはわかった。

--そして Shift+End を入力すれば、いつでもただちに停止できる機能を追加した。止まった時の行番号も表示される。止まった時の変数の値もprintすればいくらでも確認できる。

-''[2019.09.18(水)]''
--[[esbasic0005]]を更新した。ライブラリ側にもうちょっと関数を増やしたら、75行まで減らせた。

-''[2019.09.19(木)]''
--私はES-BASICの中でたまにアセンブラを書きたくなる。いやその、ES-BASICがサポートしていない命令があって、でも試してみたいことがあって、そんなときにすごく便利だから。
--しかしアセンブラを作るとそれは大掛かりになってしまうので、もっと簡易的なものにしよう。とりあえずは直接機械語を書ける程度で。それだけでも私にとってはかなりありがたい。
--しかし普通にアセンブラを作るとそれは大掛かりになってしまうので、もっと簡易的なものにしよう。とりあえずは直接機械語を書ける程度で。それだけでも私にとってはかなりありがたい。
--今まで、そういう生々しい拡張(普通の言語っぽくないこと)をやるのには抵抗があったのど、どうせ自分用の言語なんだし、気楽に実装することにする。
--将来的に互換性を保たなければいけない、みたいな気構えも捨てよう。当面は何でもアリって感じで。
--そうすることで見えてくるものもあると思うので。

--4時間くらい頑張ったらできた。追加したのは60行。これでインラインアセンブラもどきの命令が使える。
--こんな感じの雰囲気。
  13         CODE `xor   0X33 #RM:EAX,EAX
  14         CODE `store 0X89 #RM:EAX,[N]
  15         LABEL FORLOOP
  16           CODE `load  0X8B #RM:EAX,ECX
  17           CODE `imul  0XF7 #RM:5,ECX
  18           CODE `shrd  0X0F 0XAC #RM:EDX,EAX 24
  19           CODE `load  0X8B #RM:ESI,EAX
  20           CODE `load  0X8B #RM:EAX,EBX
  21           CODE `imul  0XF7 #RM:5,EBX
    (中略)
  36           CODE `load  0X8B #RM:EAX,[N]
  37           CODE `inc_eax 0X40
  38           CODE `store 0X89 #RM:EAX,[N]
  39           CODE `cmp   0X81 #RM:7,EAX %446
  40           CODE `jle   0X0F 0X8E #REL:FORLOOP
--ということで、すごく気軽に機械語で遊ぶ環境ができた。mod r/mやラベル計算くらいはやってくれる。
--もちろんES-BASICの他の命令と混在できるので、一番重たいループの内側だけをcodeで書けばいい。
--何か適当なファイル名を付けてソースを保存する必要はないし、アセンブルもコンパイルも必要ない。適当に入力して、runするだけ。気に入ったらlistしてコンソールからコピペして、好きなところに貼り付けておけばなくならない。
--もちろん実行速度は爆速なので(機械語だから当然だけど)、もう速度で他の言語に負けることはなくなった。まあ自力でアセンブラで書くのなら、の話だけど。
--アセンブラなのに Shift+End で停止することができて、しかも止まったらどこまで実行していたかも教えてくれるなんて、なんかむちゃくちゃ甘やかされているというか、正直あり得ない感じがする!止まった時の変数の値も確認できてしまう、すごくアセンブラらしくない!!

-''[2019.09.20(金)]''
--ALIAS命令を付けて、レジスタ名を隠して書けるようにした。これでレジスタ割り当ての変更とかが容易になった。
--そして各行ごとの実行回数をカウントして表示する機能も付けた。これはすごい。BASICにそんな機能があっても、まあそんなものかという気はするけど、アセンブラでこれができるって相当にすごい。
--アセンブラでプログラミングしていると、ここは通っているんだろうか?みたいなことを確認したいと思うことがよくある(まあC言語でもたまに確認したくなるけど)。そんなときに、行ごとの実行回数つきのリスト表示を見たら、もう一発で分かる。あちこちにprintfを仕込んで確認するなんていうことをしないでいい。
--アセンブラの中で処理を中断してしまった時などは、なんとレジスタの中身までも確認できる(ようにした)。どこで止まったかもわかるから、本当にデバッグがはかどる。もうアセンブラじゃないみたいだ。
--ES-BASICはBASICなんだと思うとささやかなインパクトしかないのだけど、アセンブラだと思うと、もうなんてすごいんだ!と圧倒されそうになる。超快適。病み付きになりそう。我ながらすごいものを作ってしまった。
--まあ基本的な使い方としては、まずES-BASICでお気軽に書いて、行ごとの実行回数カウントを見て負荷が集中している場所を突き止めて、そこだけアセンブラで書きなおせばできあがり。とても効率がよさそう。無駄がない。
--現在ES-BASICは927行。
--11/23~11/24のOSCに出展する予定なので、それまでにオープンソースにしよう。

-''[2019.09.25(水)]''
--ES-BASICのCODE命令がやっぱり少々不便なので、ASKA命令を追加してみた(なつかしい)。
  10         ALIAS ZX:ECX, ZY:EBX, XX:ESI, YY:EDI
  11         ASKA ZX = 0
  12         ASKA ZY = 0
  13         ASKA EAX = 0
  14         ASKA [N] = EAX
  15         LABEL FORLOOP
  16           ASKA EAX = ZX
  17           ASKA IMUL ZX
  18           ASKA SHRD EAX,EDX,24
  19           ASKA XX = EAX
--おお、これはまた格段に読みやすいし書きやすい!
--内部ではASKA文をCODE文に変換してバイナリを生成している(そのほうが実装が楽そうだったので)。
--現在の行数:
---esbasic.cpp: 915行 (主要部分、以下に含まれないすべて)
---chr.cpp : 104行 (ゲーム向けの追加フォントのデータ)
---aska.cpp : 111行 (ASKA命令、CODE命令のための記述)

-''[2019.09.26(木)]''
--今日はNODEBUG命令を追加。これにより、コード範囲を NODEBUG 1 ~ NODEBUG 0 で挟んでおくと、その範囲ではShit+Endのキー入力のポーリングや実行ラインカウンタなどの処理が省略され、高速に実行される。これでデバッグがますます快適に!

-''[2019.09.27(金)]''
--ついに念願のDEBUGTRAP命令を追加。あとNORETURN命令も追加。これでデバッグのやりやすさが一つ上のレベルへ。REGS命令も追加。
--なんかMEMコマンドを実行してみたら、メモリリークが発生しているようだ。これは何とかしなければ!

-''[2019.09.30(月)]''
--メモリリークは、END命令のときの終了処理が普段と違っていたせいだった。思ったよりも簡単な問題だった。すぐに直せた。
--バッチファイルを実行する機能を実装。これも簡単だった。
--ASSERT命令を追加。デバッグモードの時、この命令はNOPになるが、高速モード時はこの命令から行末までをコメントとして扱う。
--[アイデア]変数にライトプロテクトをかけられるようにする。もちろん個別に設定可能。配列の場合は要素ごとに設定可能。これがあれば、変数を不要に書き換えようとしている場所などを容易に突き止められる。
--[アイデア]現在の全状態を復元するのに必要なバッチファイルを出力する機能。
--[アイデア]メモリリーク検出支援。
--[アイデア]確保していないメモリ域をfreeしようとしたら停止する機能。

-''[2019.10.17(木)]''
--大規模に書き直そうとして、やっぱりやめた。少しずつ書き直すほうがはかどる。
--いくつかの命令について、レジスタ変数的なものを使えるようにした。これでアセンブラを明示的に使わなくても速くなる。

-''[2019.10.18(金)]''
--ASKAだけだとつまらなくなってきたのでNASM形式のアセンブラも使えるようにした。
--乗算や右シフト付き乗算もレジスタ変数を使えるようにした。if文も対応させた。その結果、ASKAやNASMを一度も使わずとも、理想的なバイナリが出力されて十分に高速になるようになってしまった。これはすごい。[[esbasic0007]]の(9-7)を参照。

-''[2019.11.08(金)]''
--やっと64bitでもプログラムを書いてRUNしたり、LISTしたりできるようになってきた。ここまで長かった・・・。あと少しでベンチマークができる!
--(数時間後)
--おお、これでベンチマークに必要な全部の命令を移植できたぞ!たぶん。きっと。・・・何か忘れていないといいな・・・。

-''[2019.12.13(金)]''
--ああ気が付いたら長らく何も書いてなかった。でも順調に開発は進んでいる。
--ES-BASICはすごくいいのだけど、私はどちらかと言えばBASICよりもC言語の方が好きなので、自分が使うようにC言語風に作り直そうと思っている。とはいえコア部分はおそらく共通になる。名前はたぶん「ES-C」になる。

-''[2019.12.17(火)]''
--今日はES-BASICにBITBLT命令を追加して、インベーダゲームを移植した。→[[esbasic0010]]
--うーん、我ながら FORNE がカッコ悪い。FORっぽくない。FOR_くらいのほうがいいのだろうか・・・。もしくは FOR!とか?

-''[2020.01.07(火)]''
--今日はES-BASICにセキュリティ機能を付けてみた。いずれもlwaitが0以上の時に有効になる。
--(1)ゼロ割りの判定: もうゼロで割り算しても落ちないよ!(=今までは落ちたよ)
--(2)オーバーフロー判定: もうオーバーフローしたらちゃんと止まるよ!(=今までは止まらずに続行していたよ)

-''[2020.01.20(月)]''
--kozossakai氏の絶大な協力により、ES-BASICはLinuxやFreeBSDにも対応することになりそうです!
--乱数生成アルゴリズムを、Xorshiftに変更。
--OUTWIN命令を追加。

-''[2020.01.21(火)]''
--以下の命令を追加:
---CONNECT : 点を指定していくと、それをつないでいく。
---FILLOVALR : 中心と半径を指定して描く円。
---DRAWOVALR : 中心と半径を指定して描く円。
---BLTBIT : BITBLTの逆で、配列に画像を取り込む。
---BITBLTX : BITBLTに拡大縮小を可能にしたもの。
---PRINTF : printf。
---PRINTFF16 : PRINTFでFF16エンコードされた小数を表示する。

-''[2020.01.24(金)]''
--命令の引数処理のバグを修正。
--以下の命令を仕様変更:
---OUTWIN→SAVEWIN
--以下の命令を追加:
---ESCTERM
---LOADWIN
---文字列定数を使った配列への代入
---ARY INT DUMP6X

-''[2020.01.30(木)]''
--x64の機械語でちょっとわからないことがある。
--REX.Wプリフィクスを付けないPUSH reg(0x50~0x57)は、Rxxをスタックに積むのだろうか。それともExxをスタックに積むのだろうか。
--単純なルールだけで考えるのなら、REX.Wプリフィクスがつかないのなら、デフォルトは32bitなので、Exxをスタックに積むように思える。しかし、PUSHによってRSPは8減るだろうし、CALLとかはREX.WプリフィクスがなくてもスタックにRIPを積むだろう。つまりスタックに積み下ろしするときは、REX.Wは関係ないのかもしれない。
--なんでこんなことを疑問に思ったのかというと、Rxxを保存しなければいけない状況なのに、REX.Wプリフィクスのつかないコードを使っている人がいたから。
--ということで確認しよう。ES-BASICなら簡単に確認できる。
--RSIに0x11111111_11111111を代入して、0x56して、RSIを0クリアして、0x5eして、それでRSIがいくつになったのか確認してみよう。
 code 0x48 0xbe 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x56 0xbe 0x00 0x00 0x00 0x00 0x5e
--regsで結果を確認すると、RSIは0x11111111_11111111になっていた!つまりRSIレジスタはすべて復元されたので、0x56/0x5eはPUSH RSI / POP RSIであるとわかった!!

-''[2020.02.19(水)]''
--ES-BASICは大進化中。
--まず32bitの実行ファイルを出力できるようにした。まだサポートしている命令は多くないけど、とりあえずPRINTFはできる。つまりこれで、ES-BASICは単なるスクリプト言語から、コンパイラとしても使える言語に変わったことになる。・・・また、ただ出力できるだけでは面白くないので、すごく小さい.exeを出力するようにがんばってみた。
---頑張るといっても、どこが省略可能な部分なのかを根気よく調べて、それを省略しただけなんだけど。
---これで 10 PRINTF "hello, world\n" をコンパイルして作った実行ファイルは1076バイトになった。コンソールベースのカレンダー表示アプリも1588バイトで出力される。
---helloについてはもっと頑張れば1068まで減らせるのはわかっているのだけど、そこまで制御するのは面倒なので、ひとまずここで妥協した。
--また、アセンブラの命令も実装中で、これができると、esbasic.exeだけで、スクリプト言語+デバッガ+コンパイラ+アセンブラの4機能が統合されていることになる。これは攻めている!


* こめんと欄
#comment


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS