2007年8月4日 LL魂 オレ様言語言語の作り方 crowbar & Diksam 前橋和弥
まずは自己紹介から 氏名:前橋和弥 名古屋在住 プログラマ 著書が4冊ほど 氏名:前橋和弥 名古屋在住 プログラマ 著書が4冊ほど
宣伝? ・C言語 ポインタ完全制覇 ・C言語 体当たり学習徹底入門 ・Java謎+落とし穴徹底解明 ・センス・オブ・プログラミング (すべて技術評論社刊)
4冊目に何を書くか決める際、 「プログラミング言語の作り方」 ではどうか、と言ってみたところ、 「そんなマニアックなネタでは」 と編集さんに難色を示される。
愚痴? で、私が別ネタでようやく書き上げたところ、その発売の3日後に 「スモールコンパイラの制作で学ぶプログラムのしくみ」(リンゴ本) が出るとはどういうことか。
閑話休題 現在は、自身のWebサイト http://kmaebashi.com にて 「プログラミング言語を作る」 というページを作成中。 (停滞気味?)
crowbarとは ・「プログラミング言語を作る」 におけるサンプル言語第1弾 ※現時点で実用性はあまりないです。 ・Cに似た文法 ・変数に型がない(宣言不要。 最初の代入が宣言を兼ねる)
crowbarとは(2) ・正規表現が使用可能(小迫 さんの「鬼車」使用) ・インタプリタの記述言語はC ・yacc/lex使用 ・解析木を辿りながら実行する (RubyやPerl5と同様の方式)
crowbarとは(3) ・データ型 - 基本型…整数、実数、boolean、文字列 - 参照型…配列、オブジェクト - ネイティブポインタ型 …FILE*, 正規表現 ・exactなmark & sweep GC (ver.0.1は参照カウンタ) ・例外処理機構
命名の由来 ・crowbarは、Perlに似た実行 形態の言語である。 ・crowbarとは、英語で、こんな 工具のことである。
命名の由来(2) Perlのようなもの
機能的にはPerlには まるっきり及ばないので 「Perlのようなもの」 とはおこがましいですが…
サンプルソース(grep) # 引数チェック(トップレベル記述可能) if (ARGS.size() < 1) { fputs("エラー。", STDERR); exit(1); } # 引数から正規表現オブジェクトを生成 reg = reg_new(ARGS[0]); # 実はreg_new関数を実装しているバージョンは未公開ですが… # 続く
grep(続き) if (ARGS.size() == 1) { in_fp = STDIN; do_grep(in_fp); # 関数呼び出し } else { for (i = 1; i < ARGS.size(); i++) { in_fp = fopen(ARGS[i], "r"); do_grep(in_fp, reg); fclose(in_fp); } } # さらに続く
grep(さらに続き) # 関数定義 function do_grep(in_fp, reg) { while ((line = fgets(in_fp)) != null) { # 正規表現でマッチング if (reg_match(reg, line)) { print(line); }
クロージャ ・式の中で関数定義 ・レキシカルスコープ fp = fopen("hoge.txt", "w"); # ただの関数でforeachを実現する foreach(hoge_collection, closure(o){ # ループの外側の変数fpを参照 fputs(o.name, fp); });
オブジェクト # 組み込み関数でオブジェクトを生成 p = new_object(); # メンバは代入で増える p.x = 10; p.y = 20;
OOっぽい(JavaScriptっぽい)もの # コンストラクタ function create_point(x, y) { # thisはただのローカル変数 this = new_object(); # get_x()メソッドの定義 this.get_x = closure() { return x; } … return this;
crowbarの現状… (次の言語を作っているので) 開発休止中 飽きっぽい(?) (次の言語を作っているので) 開発休止中 飽きっぽい(?)
Diksamとは ・「プログラミング言語を作る」 におけるサンプル言語第2弾 ※現時点で実用性はさらにないです。 ・Cに似た文法
Diksamとは(2) ・変数に型がある。 ・変数は宣言が必要。 ・LLじゃないなこれは
本音(?) 型なし言語 逝ってよし http://pc.2ch.net/tech/kako/986/986355498.html 型なし言語 逝ってよし http://pc.2ch.net/tech/kako/986/986355498.html
本音(?) その2 オ 俺は「自由」より「犬の首輪」がほしいンだよォ~~ッ!! by 「銃夢」のヨルグ
Diksamとは(3) ・ソースをバイトコードにコンパ イルし、メモリ上に保持して 実行する。 ・バイトコードのファイル(Javaの classファイル相当)はない。 →単なる手抜き(ベリファイヤ 作るのむつかしい)
Diksamとは(4) ・ユーザから見れば、コンパイル の手間がかからない。 ・ユーザから見れば、コンパイル の手間がかからない。
Diksamの現状 ・四則演算、変数、制御構造、 配列、関数等は普通に使用可能。 ・ライブラリ関数は… print()のみ ・分割コンパイルが最近ようやく 動きました。 ・クラスは…実装中。
DVM(Diksam Virtual Machine) ・DiksamのVM。 ・JVMに似たスタックマシン (ていうか結構JVMのパクり)
DVMニモニックサンプル 0 push_static_int 0 3 push_int_1byte 0 5 eq_int 6 jump_if_false 17 9 push_int_1byte 1 11 pop_static_int 0 14 jump 22 17 push_int_1byte 5 19 pop_static_int 0
対応するDiksamソース int a; if (a == 0) { a = 1; } else { a = 5; }
サンプル-FizzBuzz 「1から100までの数をプリントするプログラムを書け。ただし3の倍数のときは数の代わりに「Fizz」と、5の倍数のときは「Buzz」とプリントし、3と5両方の倍数の場合には「FizzBuzz」とプリントすること。」 (http://www.aoky.net/articles/jeff_atwood/why_cant_programmers_program.htm)
ぼそっ ・あいまいな仕様だなぁ… 15の倍数のとき表示するものは 今たまたまFizzBuzzだけど、 次のバージョンアップでは 全然違う文字列になり得るの?
crowbar版 for (i = 1; i <= 100; i++) { if (i % 15 == 0) { print("FizzBuzz\n"); } elsif (i % 3 == 0) { print("Fizz\n"); } elsif (i % 5 == 0) { print("Buzz\n"); } else { print("" + i + "\n"); }
Diksam版
int print(string str); // プロトタイプ宣言 int i; for (i = 1; i <= 100; i++) { if (i % 15 == 0) { print("FizzBuzz\n"); } elsif (i % 3 == 0) { print("Fizz\n"); } elsif (i % 5 == 0) { print("Buzz\n"); } else { print("" + i + "\n"); }
FizzBuzzを再定義する ・FizzBuzzとは、「何回かに一回、特定 の処理をする」プログラムである。 ・たとえば、ゲームなんかで、何回かに 一回、「特定の敵キャラを動かす」 という処理にすれば、敵キャラごとに 動きの速さを制御できる。 ※大昔のI/Oで芸夢狂人さんがこんなことを 書いてたんだ、確か。
呼び出し側(crowbar) function main() { for (i = 1; i <= 100; i++) { FizzBuzz(i, # カウンタ # n回に1回のnを示す定数と、その時動く # 処理(クロージャ)をペアにした配列の # 配列。 {{3, closure() {print("Fizz");}}, {5, closure() {print("Buzz");}}}, # マッチしなかったときに動く処理。 closure() {print("" + i);}); print("\n"); }
FizzBuzz関数 function FizzBuzz(counter, do_proc, else_proc) { done = false; for (i = 0; i < do_proc.size(); i++) { if (counter % do_proc[i][0] == 0) { do_proc[i][1](); done = true; } if (!done) { else_proc();
ご清聴 ありがとうございました