『Rubyで作る奇妙なプログラミング言語』をRustで作った

タイトル見て即購入。

http://esolang-book.route477.net/

見た目的にふざけた言語(Esoteric Programing Language, esolang)の処理系をRubyでいくつか実装していく本。おれはRubyを書けないので、例のごとくRustで実装した。Rustを書けるとは言ってない。
リポジトリはこれ。

https://github.com/guricerin/esolangs


HQ9+

使用するトークンはH, Q, 9, +の4種。

  • H : Hello, World!を出力
  • Q : Quine。プログラムのソースコードをそのまま出力
  • 9 : 『99 Bottles of Beer』の歌詞を出力
  • + : 内部カウンタを1だけ増加(なお、内部カウンタを確認する術は用意されていない)

こんな仕様では当然チューリング完全ではないので、もはやプログラミング言語ですらない。言語実装のチュートリアル的存在。


Brainfuck

使用するトークンは>, <, +, -, ., ,, [, ]の8種。これらを使って一次元配列(テープ)をいじくりまわす。
テープの操作はチューリングマシンの動作をモチーフにしている。HQ9+とは違ってチューリング完全の立派なプログラミング言語である。
実は以前に実装済み。しかも任意の文法規則JSONファイルを用意することで好きなように改造可能(宣伝)。


Whitespace

使用するトークンは\0x20(半角スペース), \t(タブ文字), \n(改行文字)の3種。印刷しても見た目が真っ白になる嫌がらせ言語。
Whitespaceプログラムは、まずアセンブリに似た中間言語にコンパイルされ、仮想機械によって実行される。
演算用とリターンアドレス用の2つのスタック、ランダムアクセス可能なヒープ領域、それらの領域を制御する命令群が備わっている、いわゆるスタックマシン。なので意外なことに機能面はリッチだ。
トークンの並び順と組み合わせで命令を表現する。

ここからは標準入出力についてのやらかし余談。
標準入力と標準出力は共にターミナル上に表示されるので同一視してしまいがちだが、実際はファイルディスクリプタで区別されている。
んなの当たり前だろと思われるかもしれないが、おれはこのことを理解しているようでまったく理解していなかった。
何が言いたいのかというと、例えばWhitespaceプログラムで標準出力にEnter a number: と出力したとき、当然ターミナルには

Enter a number: 

と表示される。これに対してユーザが42を入力したとしよう。

Enter a number: 42

入力は標準入力に流し込まれるので、Whitespace処理系のRustプログラムのほうで

let mut buf = String::new();
std::io::stdin().read_line(&mut buf).unwrap();

と読み取りたいわけだが、あほなことに、この処理が終わった後のbufの中身をEnter a number: 42\nだと勘違いしてしまい(実際は42\n)、延々と唸ってしまっていた。
標準入出力がそれぞれ別物だときちんとわかっていたらこんな間違いは犯さないだろう。戒めのためにメモっておく。


Starry

著者オリジナルのesolang。使用するトークンは+, *, ., ,, \0x20(半角スペース), `, 'の7種。ソースコードがアスキーアートの星空のようになる。
例えば以下はStarryによるHello, World!プログラムだ(本書のサポートサイトより引用)。

             +               +  *       +    
 * + .        +              +  *       +   
  *     * + .            +     * + . + .    
    +     * + .              +            + 
 *         +     * * + .                 + *
 + .              + +  *           +     *  
   * + .             + * + .        +     * 
+ .           + * + .             + * + .   
           +            +  *         +     *
 * + .

Whitespaceと同じくスタックマシンで、実装が楽になるよう仕様を似せている。


Bolic

著者オリジナルのesolang。使用するトークンはUTF-8に登録されている絵文字の中から読者が任意に選ぶ。デバッグがだるくなるので、おれは本書と同じのを選んだ。
なんとここにきて再帰下降構文解析を紹介・導入する。というわけでこの言語の文法は、見た目は別として一般的なプログラミング言語と同じような木構造になっている。
4種だけの変数シンボル(スコープはグローバルのみ)、if式、while文など、簡素だが基本的な要素はそろっている。
以下はBolicによる第10項までのフィボナッチ数を表示するプログラム(本書P.197より引用)。

✪☜⑩
✷☜ ⓪ ✲☜①
♺ ✪ ☞
  ✩☜ ✷+ ✲
  ✍ ✩♪⑩
  ✷☜ ✲ ✲☜ ✩
  ✪☜ ✪−①
♘

パーサの実装は何度やっても難しい。これはおれの頭がくるくるパーだからなのか単にRustがむずいだけなのかはわからない。


他のesolang

本書の残りページでは、実装はしないが実にユニークなプログラミング言語が紹介されている。いくつか抜粋。

Befunge

一般的にプログラムというものはソースコードの上から下へ、行ごとに左から右に向かって解釈されるものだが、この言語ではその「進行方向」を上下左右自在に変更することができる(なんじゃそりゃ)。

Shakespeare

その名の通り、シェイクスピア戯曲の登場人物名や彼らのセリフがトークンとして用いられる。Shakespeareコードの美しさは文学的美しさで決まる。

Unlambda

1引数関数しか使わない。関数型言語の極致。『アンダースタンディングコンピュテーション』ではRuby流のUnlambdaを実装させられた。他にはSKIコンビネータなども。

Grass

トークンはW, w, vの3種。ソースコードが草まみれになる。
桐生ココが卒業して寂しいが、またイカれたことをやってくれると信じている。

NULL

命令は14個ある……のだが、ソースコードにはただひとつの整数しか書けない。
各命令は14個で1グループの素数にそれぞれ割り振られる形式。たとえば、2~43の素数で1グループをなし、47~107の素数で1グループをなす。そして14個の素数ごとに割り振られる命令が一巡するので、たとえば2と47は同じ命令を担当する。
ようするに、ソースコード上の整数の素因数によって命令の順番と組み合わせが構成される言語である。説明が難しい。


まとめ

書いたことのない言語の練習教材として活用できるかもしれない。チューリングマシンとかにもちょろっと触れられるので、ふざけ具合とは裏腹にCS入門という意味でも適しているのではないだろうか。もちろん言語処理系の入門にも。難易度が段階的に上がっていく感じだし。
文章のノリが軽いので読みやすく、ちょくちょく笑わせにかかってくる。アンダースタンディングコンピュテーションやnand2tetrisよりも先に読んでおきたかった本。