おひさしぶりです。ブログの書き方をすっかり忘れてしまいました。
タイトルのとおり、日経ソフトウエア2010年8月号に記事を書かせていただきました。
『マイ言語「MIL」ならできる! スクリプト言語をゼロから作ろう』を書いています。
MILは、MInimum Languageの略で、本記事のためにゼロから開発した言語です。ソースコードがCで900行程度しかないので、本記事に全ソースを掲載しています。言語処理系に興味はあっても作り方は見当もつかない、という人が、無理なくソース全体を読み解けるように配慮したつもりです。
手前味噌ですが、「十数年前の私が本誌を入手したら、切り取って永久保存にしていただろう」ぐらいの価値はあると思っています。
MILは、ソースコードを読み込み、メモリ上にバイトコードを展開して実行するタイプの言語です。
使用できるデータ型は整数と文字列、関数呼び出しはありませんがgotoとgosubがあります。組み込みの関数はprint()のみです。
サンプルソースを以下に掲載します。
# print()文でhello, world. print("hello, world."); # 最初の代入が変数宣言を兼ねる。 a = 10; b = 200; # 当然演算子の優先順位は配慮します。 print(a + b * 10); i = 0; # 制御構造としてwhile文とif文が使用可能 while (i < 5) { print(i); if (i <= 2) { print("i <= 2"); } else { print("i > 0"); } i = i + 1; } # gotoが使用可能。ラベルは*ではじまる(HSPに似せました) goto *c; *b print("b"); goto *d; *c print("c"); goto *b; *d print("d"); # gosubによるサブルーチン呼び出しが可能。 gosub *sub; print("returned."); goto *end; *sub print("hello,"); print("subroutine"); print(10 + a * b); return; *end
最小の機能の言語とはいえ、たとえばアプリケーションのカスタマイズ用言語のベースとしては、そこそこ使えそうに見えないでしょうか。
MILはyacc/lexを使わず、手書きのレキシカルアナライザと再帰下降パーサを使っています。また、解析木を作らず、パーサが直接バイトコードを出力しています。
当初は、解析木を作り、解析木を再帰的に辿りながら実行していくタイプの言語(crowbarやver.5までのPerl、1.8までのRubyと同様の形式)を作ったのですが、解析木を作るところで行数がかさんでしまい、結局この方法がもっとも処理系がコンパクトに収まりました。
この方法はたとえば中田育男先生のコンパイラ本(オーム社のやつ)で作成している言語と同様の手法です。
ただ、中田先生の本のパーサは、パーサが「常時トークンひとつを先読みしている」方法なのですが、個人的に私はこの方法はわかりにくいと思っていて、MILのパーサは「読み込みすぎたトークンは押し戻す」という方法を採用しています。好みの問題なのかもしれないですが、たいていの初心者にはこちらの方が読みやすいのではないかなあ、と思っています。
上記のとおり、MILは最低限の機能しか持たない言語ではありますが、たった28ページの雑誌記事で解説しきることができているわけです。「プログラミング言語を作る」ことに興味はありつつも、なんだか難しそうだ、と思っている人には是非読んでいただきたいと思います。
それはそうと、
編集さん、悪ノリしすぎじゃないかなあ*1。
*1:や、もちろん私も掲載に同意しているわけですけどね。