ES-BASIC の紹介 (一番下にダウンロードもあります)

  • (by K, 2019.11.21)

スクリプト言語 vs コンパイラ言語

  • スクリプト言語(インタプリタ言語)って、プログラムを入力してすぐに実行できて、とても手軽だと思いませんか? 「まずコンパイルして実行ファイルを生成しなければいけない」みたいなことがありません。
  • ちょっとしたことを試したいだけなら、ダイレクトコマンドでちょっと入力するだけで済みます。「わざわざソースコードを書いて、ファイル名を決めて保存して、それをビルドして、やっと結果が分かる」というのとは大きな違いです。
  • しかし、スクリプト言語は実行がとても遅いです。だから速度が要求されるケースでは、コンパイラ言語ばかりが注目されます。私はスクリプト言語が、将来のプログラミング言語の標準になるはずだと信じているので、この状況に不満を感じています。
  • じゃあ、実行速度が十分に速いスクリプト言語があったらどうでしょうか。それは「手軽さ」と「性能」を両立できたことになりますよね。でもそんなことはできるんでしょうか?・・・この夢への挑戦が「ES-BASIC」なのです!

  • これは「マンデルブロ集合」の描画に必要な演算でベンチマークを取ったものです(詳しいことはesbasic0012に書いてあります)。
  • どれもそれぞれの言語で一番スピードが出る書き方を目指して書いたうえで、実行速度を比較しています。
言語処理系のインストールサイズタイプ実行時間GCC x64 -O3比備考
GCC x64 8.1.0 -O3449256KBコンパイラ言語1.115秒1.00倍これはコンパイル時間を含んでいません。ちなみにコンパイル時間は0.37秒でした(これは複数回試した最小値です)。
ES-BASIC ver.0.1b 64bit版102KBスクリプト言語1.270秒1.14倍これはJITコンパイル時間を含んでいます。GCCに対して、1.14倍くらいの時間がかかっていることになります。
Ruby 2.6.4p104 x6475323KBスクリプト言語76.102秒68.2倍esbasic0013にテストに使ったRubyのコードがあります。
Python 3.7.485771KBスクリプト言語344.891秒309倍esbasic0013にテストに使ったPythonのコードがあります。
Python+Numbaスクリプト言語2倍?以前類似のテストをしたことがあり、その時の感触から推定(後日測定して更新します)。
JavaScript(Node.js)スクリプト言語15倍?以前類似のテストをしたことがあり、その時の感触から推定(後日測定して更新します)。
  • これを見ると、確かにコンパイラ言語であるC言語の強さは圧倒的で、ES-BASIC以外では全く勝負になっていません。スクリプト言語は遅いという一般論が常識になってしまっても文句は言えない状況です。
  • しかし我らがES-BASICは、その中にあって、かなりいい勝負をしているではありませんか!まあ14%ほど遅いには遅いので、それは認めざるをえませんが、しかしスクリプト言語の特徴である手軽さはすべて備えていても、この程度の速さは出るのです。
  • だから私は言いたいのです。「スクリプト言語だから遅いのではない。手軽さと実行速度はかなりのレベルで両立できるのだ!」と。

ES-BASIC ver.0.1b

  • 最大の特徴は、前述のとおり、スクリプト言語のくせに常識外れに実行速度が速いことです。
  • 第二の特徴は、言語処理系がとても小さいことです。まあ「開発が始まって間もないから小さいのだ」というのが、一番の理由なのではありますが、それでも、けっこうたくさんの機能は持っています。
「グラデーション」   「マンデルブロ集合」   「回転キューブ」(ぐるぐる回ります!)
この画像を表示するプログラムは7行で書けます。この画像を表示するプログラムは36行で書けます。この動画を表示するプログラムは114行で書けます。
http://k.osask.jp/files/esb20190827a.pnghttp://k.osask.jp/files/esb20190827b.pnghttp://essen.osask.jp/download/esb20191120c.png
  • (上記のプログラムの内容についての詳細はesbasic0010をごらんください。)
  • これだけの機能があっても102KBなのです(・・・命令の一覧はesbasic0011にあります)。
  • ソースコードはC言語で4927行ほどありますが、そのうちの3179行はハッシュテーブルやグラフィックライブラリなど、言語に依存しない汎用的なもので、言語としての実装は1748行しかありません。だから小さいのだとも言えます。
    • (この1748行の内訳はesbasic0011に書きました。)
  • これで分かることは、高速な実行が可能なスクリプト言語は、何かすごく難しい技術や複雑で膨大なソースコードが必要なわけではなく、シンプルに書いていくだけで作ることができるということです。

なぜこんなに高速なのか

  • ES-BASICは「JITコンパイラ」という技術を使って、プログラムを高速に実行しています。
  • これはRUN命令が来たら、直ちに(=Just-In-Time)対象のプログラムをメモリ上で一瞬でコンパイルして機械語を生成して、その機械語を実行するというものです。
  • 原理的にはこれに尽きます。・・・この説明だけを見れば簡単そうに見えますが、実際簡単です。複雑なことをやり出したら一瞬では終わらなくなってしまいます。そして簡単だからこそ1748行程度で書けるのです。

デバッグ支援機能

  • ES-BASICではデバッグ支援も大事な要素です。
  • 一般に開発時間の4~7割はデバッグの時間になっているとも言われています。そうであるならば、言語がデバッグの支援のためにできることはないかとあれこれ試みることは、十分に理にかなっていると私は思います。
  • プログラムをRUNしてみて、動作が怪しいと思ったらグラフィックウィンドウで「Shift+Home」を押します。するとすぐにPAUSEがかかるので、今どこを走っているか、変数はどうなっているかなどをPRINT命令をダイレクトコマンドで実行して確認します。納得できて続行してもいいと思えたら、RESUMEで再開します。
  • そうではなく、デバッグ中にもう怪しいところの目星がついているのなら、そこにPAUSEコマンドを書いておくこともできます。そうするとブレークポイント的に機能します。
  • 配列で添え字を間違えて対象の変数以外を書き換えて大惨事になる(=もはやどこに原因があるのかわからなくなる)というのは、まあC言語とかではたまにやらかしてしまうことですが(ようするにポインタ系のバグ)、ES-BASICは配列アクセス時に添え字の範囲をチェックしているので、そんなミスは絶対におきません。やらかす直前にちゃんとどこでやってしまいそうになったかも含めて報告してくれます。

  • そしてES-BASICのデバッグにおける目玉機能はなんといっても「DebugTrap」です。
  • 原理はとても単純で、各行を実行する直前に、指定しておいたサブルーチンを呼び出すというだけです。しかしこれにより、もし変数iが20以上になったら即座にPAUSEする、みたいなことが簡単にできます。
    9000 NODEBUG 1
    9010 LABEL TRAP
    9020 IF I>=20 THEN
    9030   PRINT "I>=20 IN ",$LINE
    9040   PAUSE
    9050 FI
    9060 RETURN
  • たったこれだけで、変数iをすべての行で監視できるようになるわけです。実際、配列アクセスなどで変数がおかしな値になっているということが指摘されてわかっても、その原因がどこなのかを突き止めるのはそれなりに面倒なことです。でもこの機能を使えば簡単に見つけられるわけです。
  • 今回は簡単な条件でしたが、もっとややこしい条件でももちろん見つけられます。IF文を書くだけのことです。
  • プログラム中に出てきた変数$LINEは特別な変数で、どこの行からGOSUBしてきたのかを確認するためのものです。これを使うと、
    9051 IF $LINE==2340 THEN PRINT "[2340] "; FI
  • みたいなこともできます。これは2340行の行頭に PRINT "[2340] "; を書き足したのと同じ効果があります。
  • また、
    9052 IF $LINE==3450 THEN NORETURN 3460; FI
  • ということもできます。これは3450行を実行せずに3460行へ帰ることになるので、3450行をコメントアウトしたのと同じことになります。
  • こうしてプログラム本体には一切手を入れずに、デバッグのための一時的な変更を記述することができるのです。

高度な機能

  • C++11には、constexpr(const-expression:定数式)という機能があり、これはユーザ定義関数を使った定数式を書いた時に、(実行時ではなく)コンパイル時にこれを計算して(!)、定数としてプログラムに埋め込んでくれるというものです。これで複雑な計算結果で決まるような定数が必要な時でも、実行時にその計算時間を要することなしに、結果が利用できるようになったわけです。
  • C++でこれが可能になった背景には、C++は大変に高度な最適化機能を標準的に持っており、その最適化機能を使うことでユーザ関数に対しても定数計算ができるようになったということがあると思います。この機能が出た時、私の周りのプログラマたちがとても喜んでいたことを今でも覚えています。
  • ではES-BASICで似たようなことはできないのでしょうか。・・・そう思ってやってみました。そもそもES-BASICはプログラムを実行して結果を得るなんてことは、スクリプト言語なのですから朝飯前です。だからプログラム内に「ここは実行時ではなくコンパイル時に実行して結果を定数として利用したい」という記述を許すことにして、適当に頑張ってみたら、すぐにできるようになりました。
  • 「高速なスクリプト言語」に、どれほどの可能性があるか、その一端を感じてもらえたら幸いです。

ところで、なぜBASICなの?

  • ES-BASICは基本構文が、1980年ごろの、全部の行に行番号が必要な(笑)、古めかしいBASICになっています。しかもプログラムを小文字で入力しても全部大文字化されるところまで同じです。
  • なにもそんな廃れた仕様を採用する必要なんてないだろうに・・・と思われますよね。はい、私だって正直そう思います。
  • じゃあ、なんで・・・って思われると思いますが、はい、そもそもES-BASICは最初はそんなたいそうなものではなかったし、たいそうなものを目指してすらいなかったのです。
  • ES-BASICは最初は冗談というか遊びで作っていただけでした。そういえば私が子供の時に使っていた昔のBASICってどんな仕様だったかな、確かこうだったよなー、くらいの気持ちで作っていただけだったのです。
  • それが・・・なんか作っているうちに意外に優秀になってしまい、じゃあこれもやってみるか、あれもやってみるかとあれこれと実験していったら、ついにここまで来てしまったのです。だから基本的には計画的な開発などしておらず、ほんとに行き当たりばったりです。一貫した方針があるようで、実はそれほどでもなく、しいて言えば「私が使いたい機能のうち、そんなに頑張らなくてもできそうなこと」を優先的にちまちまと追加してきただけなのです。

ダウンロード

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

こめんと欄


コメントお名前NameLink

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-11-24 (日) 07:05:49 (13d)