mruby ソースコード掘削 (1)
1 って言って良いのかどうか不明ですが。
なんとなく Shiro さんの Gauche の VM のスタック操作な以下のドキュメントを眺めてみるに
Scheme で言う_環境_に struct scope なオブジェクトがあたるのかどうか。でも何かちょっと違ってるカンジでもあります。
と言いつつ
codegen.c なソースをぱらぱらめくってたら lambda_body って手続きがあって、こんなことしてますね。
static int lambda_body(codegen_scope *s, node *tree, int blk) { int idx, base = s->idx; mrb_code c; s = scope_new(s->mrb, s, tree->car);
scope_new って何でしょ。て見てみたら領域確保して云々してますね。
static codegen_scope* scope_new(mrb_state *mrb, codegen_scope *prev, node *lv) { static const codegen_scope codegen_scope_zero = { 0 }; mrb_pool *pool = mrb_pool_open(mrb); codegen_scope *p = (codegen_scope *)mrb_pool_alloc(pool, sizeof(codegen_scope)); if (!p) return 0; *p = codegen_scope_zero; p->mrb = mrb; p->mpool = pool; if (!prev) return p; p->prev = prev;
うーん、中に構文木も持っててスタックも持ってるのか。
p->lv = lv; p->sp += node_len(lv)+1; /* add self */
でも sp への初期設定が微妙な感触。
気分を変えて
再度 vm 側の実装を見てみることに。mrb_run の先頭部分が以下。
mrb_value mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) { /* assert(mrb_proc_cfunc_p(proc)) */ mrb_irep *irep = proc->body.irep; mrb_code *pc = irep->iseq;
mrb_irep て何でしょうね。iseq 属性は mrb_code 型のポインタです。
mrb_code *iseq;
ちなみに codegen_start 手続きの codegen 手続き呼び出し部分には prepare irep というコメントが付いております。
あ、codegen_scope 型の iseq ぞくせい は mrb_code ですね。ふむふむ。やはり genop で codegen_scope が指す領域の iseq 属性に設定したオペコードは struct RProc に設定されているのだろう、と勝手に類推。
そういった意味では RHG の第二部あたりで云々されて構文木に変換されたオブジェクトを codegen で vm な命令と環境の操作に変換して vm がそれを評価してるのか。
つうことは Gauche みたく命令列をどんな vm の命令に変換してるかが見えたら良いのにな。とは言え現時点でレベルでは全然_精読_ではないな。とりあえず RHG の第二部をソースを見つつ読んでみたいと思います。
蛇足
久々に RHG 見たのですが、ここでも_評価器_って単語が出てきててアレでした。
追記
RHG の第二部見つつ、ということで。
parse.y のヘッダな記述に cons だの list[123456] だのってソレが多用されてます。で、規則部の記述見てみたんですが例えば以下。
| stmt modifier_if expr_value { $$ = new_if(p, cond($3), $1, 0); }
new_if の定義は以下ですね。
// (:if cond then else) static node* new_if(parser_state *p, node *a, node *b, node *c) { return list4((node*)NODE_IF, a, b, c); }
これって Lisp/Scheme じゃん。Ruby もこうなってるのかな。こんな実装になってるのを知るとますます好きになってしまうじゃないか (何
BNF な記述まで辿りついたので、もう少しごにょごにょしつつ弄くりマワしてみます。