スタックマシンとコンパイラ
YARVの仮想マシンは、YARV Maniacs 【第 2 回】 で解説されているように、「スタックマシン」という計算モデルで作られています。スタックマシンというのは、一本のスタック(末尾へのpushとpopだけができる配列)を考えて、そこへデータを入れたり出したりする演算で計算を表現する考え方です。
たとえば、
> cat test.rb (1+2) * (3+4)
こういうプログラムをYARVの命令列に直すと
> ~/yarv/rb/parse.rb test.rb ... 0000 putobject 1 # 1 をスタック に push [1] 0002 putobject 2 # 2 をスタック に push [1,2] 0004 opt_plus # 二個pop&足した結果を push [3] 0005 putobject 3 # 3 をスタックに push [3,3] 0007 putobject 4 # 4 をスタックに push [3,3,4] 0009 opt_plus # 二個pop&足した結果を push [3,7] 0010 opt_mult # 二個pop&掛けた結果を push [21] 0011 leave
こうなります。この計算モデルの特徴は、コンパイラを作るのが簡単なことです。
FOO * BAR の計算結果をスタックにpushする命令列
を生成するには
FOO の計算結果をスタックにpushする命令列 BAR の計算結果をスタックにpushする命令列 スタックの値2つを取ってきてかけ算してpushする命令
と、式の各部分に対応する命令列を、周りのことはあまり気にせずそれぞれ作って、あとは機械的にガチャコンとconcatすれば完成です(基本的には)。というわけでYARVのコンパイラも、おおむねこういう「式の各部分に対応する命令列をそれぞれ順番に作って(つまり再帰的にiseq_compile_eachを呼び出して)、ガンガンくっつけていく」という形でコンパイルしてます。