manekineko倉金家ホームページ

趣味の部屋/ホームページ余話

必見!! ブラウザで動く言語インタプリタ

2016年11月10日公開,あとは気が向いたら適宜更新 2023年5月5日UPDATE
ブラウザだけでプログラムを組めてしかもその場で実行もできるというオールインワンインタプリタを作ってみました。javascriptで書いたC言語類似の自作プログラム言語インタプリタですが、複素数の計算や高精度計算ができ、変数、配列、各種制御構造、関数なども使えます。またSVGとCANVASのグラフィックも使えます。

ほんの遊び程度のものですが、「計算用紙 "CalcPad"」と名付けてここに公開いたします。


本邦初公開!?
他に類を見ない、純粋にブラウザ上のjavascriptで動くC言語類似の言語インタプリタ作成の記録です。
無謀とも思えるこんなおバカな?チャレンジをやる人もまずいないと思うので、大変貴重な内容および成果と言っていいかと思います。

まずは成果から。

なにはともあれお試しください。最初に作った簡単なプログラムのものです。

左のアイコンをクリックすると別窓にて表示されます。
おためし用に式の計算プログラムがセットしてあります。
[実行] ボタンで開始され、普通の計算をする感覚で複素数計算が可能です。

複素数計算プログラムをセットした calc.html 約490kB

上記アイコンを右クリックで「名前をつけてリンク先を保存」などでローカルに保存すれば保存したプログラムはいつでもそのままブラウザで実行できます。外部参照は一切していませんのでインターネット接続環境も必要ありません。
いったん開いてブラウザの「ページを保存」メニューを使って保存するとブラウザによってはjavascriptが実行されたあとの結果のページが保存されるためうまく動作しません。

以下はためしに作ってみた各種プログラムをプリセットしたCALCです。組込んである(というか読み込む)初期プログラムが違うだけであとは同じものです。まとめてみんな組み込んだのがあとの方にあります。
プログラムはローカルに保存し読み込めます。ただプログラムの言語コードがUTF-8なのでWindowsパソコンで他のソフトを使って別途編集したりしようとすると少しやりにくいかもしれません。

CALCプログラム概要
まずはお薦めのプログラムをいくつか
式の計算入力された式を計算し結果を表示します。複素数の計算もできます。
上記のものと同じですがオートスタートをセットしてみました。
多桁高精度計算多桁数字の文字列式で四則演算や累乗、階乗、累乗根などの計算を行います。
複素数は使えませんが計算の桁数はブラウザの許す限り任意です。
マンデルブロ集合グラフィック機能を使ってかの有名なマンデルブロ集合を描きます。
当初のから速度を改良し、さらに拡大位置などをマウスで簡単に設定できるようにしてあります。
マンデルアート展上記マンデルブロ集合描画プログラムで得られた見応えのあるところをいくつか集めてみました。お暇なときにでもご覧ください。
二次方程式二次方程式を解きます。係数での入力はもちろん、なんと式そのものを入力して解くこともできます。
その他いろいろ
分数計算分数のままで四則演算を行います。
連立方程式多元連立一次方程式を解きます。
素因数分解正の整数を素因数分解します。
階乗計算指定の範囲の整数の階乗の値を計算して表示します。ディフォルトで0から1000の階乗まで表示します。
素数の表示与えられた範囲の素数を求めます。
最大公約数2つの正の整数の最大公約数を求めます。
数値積分与えられた数式の定積分を数値積分して求めます。
級数の和与えられた級数の指定範囲での和を求めます。
カレンダーの作成指定された年のカレンダーを作成します。
単位換算長さ、面積、重量などの単位を換算します。
関数グラフグラフィック機能を使って関数のグラフを描きます。グラフィックの定番なのにうっかり忘れてました。
面積計算代表的な図形の面積とできれば周囲の長さを計算します。
樹を描くグラフィックを使って簡単な樹の樹形を描きます。ただし実際に樹を育てるよりは速いですがすごく時間がかかりますので(数時間から1日)、お暇な方だけどうぞ。
乱堕無グラフィック機能を使ってランダムに図形を描き続けます。
なんの役にもたたない最高にしょうもないプログラムの見本です。

...と、いろいろと細かいプログラムをいくつも作ってみたが都度別々に起動するのはめんどうで使いにくい。
そこで、 ひとつにまとめてみた。
上記全プログラム収録 calc.html (約700kB)

単にクリックして起動。
ダウンロードは
  右クリック->"名前をつけてリンク先を保存"  などで保存。
こうしたら使いやすくなった。
変数テーブルなどが大きくなって少し遅くなるかなと思っていたがほとんど変わらず全く支障はない。
今はダウンロードしてデスクトップに置いて使っている。

せっかく複素数計算ができるようにしたにもかかわらず実際は単に複素数という名を知っているというだけだったりして複素数を使った計算プログラムが少ないのはちと残念。(複素数を使うのは電子工学とか量子力学とか難しいのばかりなんだ。)



以下は今回のチャレンジの発端、経過、実現のポイントなどの記録です。
おバカなチャレンジにもそれなりの苦労がありましたので、読んでいただけるとたいへんうれしいです。


私の机の上には常時2台のパソコンが稼働しています(サーバーとしてですがふだん使いにも兼用しています)。
でもちょっと計算をするときには電卓も机の上においてあり、それでやります。少し計算が複雑になるとそれにメモ用紙が加わります。
パソコンに電卓アクセサリーも入っていますが本物の電卓の方が使いやすいので電卓アクセサリーはほとんど使いません。

考えてみればもともとは計算するために作られた機械ですから計算に使わない手はないのですが、少し複雑な計算になると手軽にできるかといえばそうでもありません。

で、ブラウザはほぼ常時開いているので、試しにブラウザで計算するプログラムを組んでみます。
計算式 : の窓の部分に 四則演算(+, -, *, /)やかっこ()などで数式を書いてEnterすると結果を表示します。

 計算式:
 →結果:


上記の計算窓のソースは周りの枠も含めて以下のようなものです。
<table style="width:100%;border-collapse:separate;background-color:#EEEEBB;" role="presentation">
<tr><td><div style="margin-left:0px;"><br />
 計算式:<input id="siki" type="text" value="" onkeydown="enter_submit(event)" style="width:70%;" />
<input type="button" value="計算" onclick="keisan();" />
<div style="width:100%;height:8px;"></div>
 →結果:<input id="kekka" type="text" style="width:70%;" value="" /><br />
<script type="text/javascript"><!--
function keisan(){
 siki  = document.getElementById("siki").value; // 入力された式を取得。
 kekka = (eval)(siki); // 計算をする(してもらう)。
 document.getElementById("kekka").value = kekka; // 結果を表示する。
}
function enter_submit(evt){
 if(!evt){ evt = window.event; }
 if(evt.keyCode == 13){ keisan(); }
}
//--></script><br />
</div></td></tr></table>
計算にはjavascriptのeval()という関数を使っています。計算式を与えると計算して結果を返してくれます。肝は単にこれだけです。あまりに簡単すぎておもしろくありません。

それに四則演算はいいとしても、sinやcosなどの数学関数を使おうとするとMath.sin()だのMath.cos()などとしなくてはなりません。javascriptはオブジェクト指向言語とやらで各種数学関数はMathオブジェクトの一部なのでこう書かなくてはならないということのようですが、よけいなお世話と押し付けも甚だしい。
Mathオブジェクトにしようがなんにしようが利用者には関係ないことで、Mathオブジェクト以外にもいろいろなsin,cosがあるのならともかく、普通の人にとってはsinはsin、cosはcosなのだから、引数の()はまあいいとしてもオブジェクト操作などはそちらでやってくれて sinはsin()、cosはcos()で使えるようにしてくれたほうがずっとありがたい。javascriptのオブジェクト指向というのは利用者のためではなく作り手の都合を押し付けている部分が多いような気がします。せめてRubyの十分の一でも見習ってくれるといいんですけどね。

それに対話的に値を入力して計算し結果をいろいろ比較してみたいなどということも簡単にはできません。たとえば2次方程式を解こうと思ったら根の公式に事前に値を代入してそれをそっくりすべて打ち込まなくてはなりません。

...使い勝手はあまりよくありません。

それに計算と言えば、なんと私は虚数とか複素数なんてのも知っているのですね。
 …実をいうと少し前にこの本(素人向け?科学雑誌 Newton別冊 "魔法の数"虚数)を読んだのでした。→

そうだ、複素数計算もできるプログラムを作ってみよう。
javascriptには数学演算や数学関数もいちおう組み込まれてます。やってやれないことはないでしょう。

...というわけで、複素数計算プログラムをつくり始めたのでした。
単なる暇つぶしのプログラム遊び程度のつもりでした。

…長かった寒い冬が過ぎて春のうららかな日差しにうきうきしながら開始したのでした。

程なくして複素数計算プログラムはできました。数学関数も使えます。これくらいならさほど難しくはありません。
言語に四則演算や三角関数、対数・指数関数などが備わっていれば、やる気になればだれでもできます。

で、実際に使ってみると...、
同じ値をいちいち幾度も打ち込まなくていいように変数がほしいな。
比較判定などの条件判定や分岐処理もしたい。繰り返し計算もしたいな。
配列や関数が定義できて使えればいいな。
簡単なグラフィック機能も装備してグラフなど描ければいいな。
....
となります。つまり構造化言語の基本機能はやっぱりほしくなります。

ついでだ、みんなやっちゃえ!! ... プログラム遊びもなんだか本格味をおびてきました。
すなわち、ここから先は言い換えれば javascriptで言語インタプリタを書く ということになります。
いよいよjavascriptの超高度なプログラミングへの挑戦です。

でもこういうものは昔からだいたいC言語でというのが常識みたいなもんだが、はたしてjavascriptでもできるかな?
インタプリタでインタプリタを動かすとなるとめちゃ遅いのは覚悟の上だが、基本的にできないということはないだろう。
それにブラウザというのはだれでもいつでも使える最も汎用的なアプリケーションだし、そこで簡単なプログラムが組めてしかも即実行できるとなればそれなりに意義はあるでしょう。
言語ソフトもサーバーもコンパイルする手間も、パソコンがあればとにかくセンス以外は何もいりません。
そうは言ってもブラウザ上のjavascriptでまともに動く構造化言語のインタプリタは見たことないな...それにjavascriptは不得手だし...などと少し不安に思いながらチャレンジを開始したのでした。

…梅の花が咲いてじきに桜も楽しめそうです。

変数はさほど苦労せずできました。配列に名前と値を設定しそれを読み書きするだけですから。

…桜も咲いて春うらら。こんな陽気が続くといいけど。

次にif, for, whileなどの制御構造も加えてみました。このへんから少し雲行きがあやしくなってきました。for,whileなどでループしている間ブラウザは固まったようになり、ループが長いと「このページのスクリプトは処理に時間がかかっているか応答しなくなっています。今すぐスクリプトを停止....」などという警告が出ます。

…桜の花とともにできる自信がはらはらと...少しづつ散りはじめました。

さらにprintやinputなどブラウザ画面との入出力関数を書いたところ、まともに動作しません。スクリプトが完全に終了してからどっとまとめて出力されたりinput欄が表示されたりで全く実用に耐えません。
ずいぶん長いこといろいろとコードを書き換えたりして悪戦苦闘していましたが、一向にらちがあきません。

このあたりまできて、普通の言語だったら全く意識すらしないこと、すなわちjavascriptは同期非同期、割込などの基本的な制御がまともにできないということにやっと気がついたのです。(そんな記事はちらほら見てはいたのですが、まさかこれほどひどいとは思ってもいませんでした。)

…ついに梅雨に入りました。しとしとと雨が降っています。気分が滅入ります。

そのうちBASICみたいな簡単な構造の言語ならともかく、そこそこの構造化言語をjavascriptで書くなどはほぼ不可能に近いのではないかとさえ思えてきました。
どうりで世の中にjavascriptで書いたまともな(長時間かかるループやプログラムと同期した入出力がちゃんとできる)構造化言語のインタプリタが存在しないはずだ。(私が知る限り構造化言語という枠を外しても Applesoft BASIC というごく初期のBASIC程度のものしか見たことはない。)

プログラム遊びをしていれば当然似たようなことを考えてやる人がいるはずですが、今まで多くの人がここらあたりで涙をのんで諦めたのでしょう。でもここで諦めてはおもしろくありません。仕事だったらとっくに諦めているところですが、これは遊びですからそうもいきません。(ん、逆か?)
会社で仕事をするふり...じゃなかった...仕事をしながらも方策をあれこれ考え、帰ってはそれを試す日々がしばらく続きました。

そして...、ついに、不可能を可能にする年寄りの知恵、な、なんと秘伝の最高奥義と秘技まで繰り出して、やっと何とかこれをのりきったのでした。プログラムはほとんどそっくり書き換えになりました。

不可能を可能にした秘伝の最高奥義とその技とは?...

最高奥義とその技を知りたい人ここクリック→

結局やったことと言えば、プログラムを一要素ずつこまぎれに実行し、都度こちらのスクリプト(処理)を終わらせておきます。あとは必要に応じて(input時)、あるいは時折(1ms毎にとか)システム(javascript&ブラウザ)に戻るということです。システムに戻ったときにブラウザとのやりとりが実行され、その都度画面表示やデータの入力、ボタン操作のチェックなどがなされます。もちろんそのあと今度はまたこちらに戻してまた続きを実行します。一見ちゃんとした処理がなされているように見せかけるわけです。

こう言うと簡単なようですが決してそうではありません。これがためにこのインタプリタのコードはとても複雑で奇々怪々なものになってしまっています。(私がこういう場合のうまいプログラミングの仕方を知らないだけかもしれないけれど。)
そうは言っても実のところ、昨今の記憶力減退が響き、少し前に書いたことや決めたことは忘れるし、まだほかが決まらないからと仮コードなどを書こうものなら最悪でそのまま忘てしまい、エラーになったりおかしな動作をするのでやっと気がつく始末です。さらには老眼でスペルミスにもなかなか気づかないなどという状況が続出。
このへんまでくるともうあとは意地でしかありません。
外は猛暑でどうせ出歩く気にもならないので、せめてクーラーの効いた部屋で悪戦苦闘していました。

…こうして暑い夏は過ぎていきます。

お彼岸のころになってやっと通常の制御や入出力などの部分がそこそこ完了。

…例年どおり彼岸花が咲いています。ほぼきっちりお彼岸になると咲くから不思議です。

そしていよいよグラフィックの段に入りました。SVGとかCANVASとかいうのを使います。
予想通り今度はブラウザの互換性に悩まされます。
昔に比べればずいぶん良くなったとは言え、Microsoft系のブラウザMSIE11, Edgeはだめ。(MSIE10以下はないのでわからないがたぶん全くだめ。)
Microsoft系以外のブラウザ、Firefox, Chrome, Operaなどはみな一発でOK!。
Microsoft系は相手にしたくないけど知人友人で使っている人がいるから仕方なく何とかEdgeだけは対応しました。
MacintoshのSafariはわかりません(近くに全然ないんだもん)。

ためしに虚数の紹介本「Nerton別冊 "魔法の数"虚数」に載っていたマンデルブロ集合というのを描いてみます。わずか百数十行程度のプログラムですが、これを描くにはけっこうな繰り返し計算が必要でプログラムの速度テストにも使われるようなもの。
やってみると、インタプリタでインタプリタを動かすだけあって予想通り予想もできないほど遅い!?。
あまりに遅くて不評だったので少しずるして高速化したがあまりこういうのには向かんかな(マンデルブロ描画)。
まあふつうのちょっとした計算やグラフなら全然問題はないし、そこそこきれいなグラフィックが描けたからよしとしよう。

いろいろとそんな苦労をしながらもやっとの思いでとにかく何とかそこそこ動くものを書き上げたのでした。
思えば開始してからずいぶん長い時間がたってしまいました。

そうは言っても当初自分なりにやろうと思ったことはだいたいなんとかやりました。

もともと自己満足の遊びの世界のもので、とうてい大手を振って世に出すような代物でもないのですが、せっかく作ったのだから「計算用紙 "CalcPad"」(以下CALCと略)と名付け、ここに公開させていただきます。

普通に計算や既存言語の勉強をしたいならプログラムソースを書けば専用サーバーでしっかりコンパイルしたり実行して結果を表示してくれるオンラインサービスも多々あるのでそちらを使っていただくことにして、こちらは言語そのものから自分でつくる、より純粋で高度なプログラム遊びの世界として見て楽しんでいただければと思います。

しかし単なる遊びでただそれだけかというとそうでもありません。
まず自分で言語をつくってみるというのはすさまじく勉強になります(やりきるには相当の覚悟が必要だけど)。さらに自分の用途に合った言語を作成すれば楽に高度な処理を書くこともできそうです。
プログラムや余計なボタンなどを隠してオートスタートをかけてしまえば、自分でつくった自分好みの言語でインタラクティブな相当おもしろいページもつくれると思います。

ターゲット言語は最初なるべくC言語互換を目指していたのですが、ついつい楽をしようとjavascriptの処理系をそのまま使った部分も多々あり、かなりjavascriptに引っ張られています。でもjavascriptもCの派生言語ですから、C, php, java, javascriptなどのどれかを知っている人ならほとんどすぐに理解できると思います。機能としては本当に基礎的なもののみで、たとえば構造体やオブジェクトのような高度なデータ構造機能はありません。

やりのこしていることなどもいくつかあります。
●いわゆる構造体やオブジェクトのようなより高度なデータ構造はありません。たぶん私自身がほとんど使わないせいです。
 どうしても必要なら関数や配列、new、copy、アクセス演算子(.)などを使えば同等のことはできるでしょう。
●そもそも数学計算からスタートしたので文字列操作系の関数はあまり充実していません。また配列操作も同様です。
 これらは言語によっても非常にちがうため、とりあえず後回しにしてそのままになっているふしもあります。欲しくなったら追加すればいいし。
●プログラムエディタやステップ実行、トレースモードなど、よりプログラミングをしやすい機能はほしいところです。
 もっともこれで本格的にプログラム開発するようなこともないだろうから、ま、いいか。
…今後は暇を見てもう少し改良を加えてみるつもりではいますが。

御礼
今回のプログラム作成にあたってはガロアの群論をも弄ぶ素人大数学者?の天人午睡さんこと福沢正男さん (http://www5e.biglobe.ne.jp/~tennin/index.html) に多大なるご協力と叱咤激励を頂きました。ここに御礼申し上げます。

…山はもみじに色づきはじめました。そろそろ冬眠の支度をしなくてはなりません。


(追記:2016.12.30)年賀状をやってみた
でもまだ今年最後の大仕事、年賀状が残っています。
せっかくグラフィック機能をつけたので試しに年賀状を書いてみようと思い立ってやってみました。
座標をいちいち数字で指定して絵を描くというのはけっこう大変だったけど何とか間に合うよう完成!
ただし絵はおもしろさを出すためわざと下手っぽく描いているのでその点くれぐれも誤解なきよう。
で、謹賀新年 → 2017年 年賀状 ...ではよいお年を。


(追記:2017.7.30)プログラムエディタをつけてみたけどあまりうまくいかなかった。
実際にこれでプログラムを組んでみるとちとやりにくい。
ふだんはパソコン(Linuxサーバー)のプログラムエディタを使っているが、それには言語のキーワードを色付けしたり語句の検索や置換をしたり括弧などの対応を表示する程度の機能はあり、せめてそれくらいの機能はほしい。

で、Aceというブラウザ上で動くプログラムエディタが公開されていたので、これをCALC用に少々改造して組み込んでみた。
でも残念なことにブラウザとの相性なのか日本語との相性なのかブラウザによって、編集位置とカーソルがずれたり、プログラムエディタがブラウザの動作を少し書き換えるのかグラフィックの文字表示がうまく動かなくなったりするので残念だけどあきらめた。

別途使い慣れたプログラムエディタでプログラムを編集すればすぐに読み込めるので、そうするのが一番確かでやりやすいと判断。プログラムエディタの搭載はやめた。



ここまでいろいろやってきたけど、プログラムもだいぶ大きくなり、もう今の劣化した頭ではそろそろ限界に近い。
このあたりでいちおうよしとしよう。

...だれか続きをやってくれるという人でもいれば嬉しいけど...。