ひとり勉強会

ひとり楽しく勉強会

YARVソースコード勉強会 (3)

第3回です。今日はいよいよコンパイル処理の本陣に切り込みます。
コンパイルの大元締め関数はただひとつ、iseq_compile_each @ compile.c です。

static int
iseq_compile_each(yarv_iseq_t *iseq, LINK_ANCHOR *ret,
                  NODE * node, int poped)
{
  ...
  type = nd_type(node);
  switch (type) {
    case NODE_METHOD:{
      ...
    case NODE_FBODY:{
      ...
  }
  ...
}

基本的にこの関数は、1個の巨大なswitch文です。構文木のノードの種類によって分岐しています。引数などは次の通り。

  • iseq : 命令列を表すRubyオブジェクト。ここにはメタ情報を入れたり出したり。
  • ret : コンパイル結果の命令列を入れておくリスト構造。
  • node : コンパイルしたい式の構文木。この木を再帰的にたどりながらコンパイルしていく。
  • poped : あとで説明
  • 返値 : コンパイル成功したら COMPILE_OK、失敗したら COMPILE_NG

木を再帰的にコンパイルしていくので、この関数の中で自分自身を頻繁に呼び出すことになります。iseq_compile_eachの呼び出しはマクロ化されています。poped引数決め打ち版とそうでない版の3通りがあります。

#define COMPILE(anchor, desc, node) \
  (debug_compile("== " desc "\n", \
                 iseq_compile_each(iseq, anchor, node, 0)))
#define COMPILE_POPED(anchor, desc, node)    \
  (debug_compile("== " desc "\n", \
                 iseq_compile_each(iseq, anchor, node, 1)))
#define COMPILE_(anchor, desc, node, poped)  \
  (debug_compile("== " desc "\n", \
            iseq_compile_each(iseq, anchor, node, poped)))