インタプリタの構成

ソースコード

README.EXT の最後のほうでは Ruby のソースコードを 4 つに分類して 紹介されている。まずはそれに従った分類を示そう。

  1. Ruby言語のコア
  2. ユーティリティ
  3. Rubyコマンドの実装
  4. クラスライブラリ

「Ruby コマンドの実装」とはシェルから ruby .... と打って実行するときの ruby コマンドのことで、引数の解釈などを行っている部分だ。それ以外に Ruby を 利用したコマンドとしては Ruby を内蔵したもの、たとえば jed や modruby などが 挙げられる。

また、クラスライブラリは拡張モジュールとほぼ同じ方法で実装されている。 ただしこのなかには Ruby のコアが依存しているクラスもあって、特に String と Array が全般に渡って重要である。

実行の概要

Ruby はインタプリタとして構築されている。つまり起動時にテキストの入力を 構文解析し、それに従って実行する。構文解析自体の詳しい説明は本筋でないので ここでは省略する。詳しくは Racc の ユーザマニュアルなどを見てほしい。しかし Ruby の動作を知るだけならば とりあえず以下のことを知っていれば十分である。

まず入力は単なる「文字」の列である。次にスキャナと呼ばれる部分がこれを 「単語」に分割する。最後にパーサ (構文解析器) がその列の中に構造を見付ける。 「構造」とは、普段ソースコードを追う時のことを考えてみるとわかると思うが、 「if は条件式と本体で作られていて、その本体の中にはまた文の並びがあって…」 というような関係のことである。ソースコードがきれいに書かれているとすれば、 インデントで示してある階層関係がそのままインタプリタが見付ける構造の関係に なるはずである。ただしもちろんインデントで示せるのは文単位の構造だけであって、 文の中にも構造があることを忘れてはいけない。

さて、パーサが見付けた構造は構文木として出力される。構文木とは C の構造体を ポインタで木の形に連結したものである。その様子は例えば以下のようになる。


[if]
    [expr]            条件式
    [stmt]            条件が真の時に実行する文のリスト
    [stmt stmt]       条件が偽の時に実行する文のリスト
[while]
    [expr]            条件式
    [stmt stmt stmt]  条件が真の間実行される文のリスト
[assign]
    [lhs]             代入の左辺 (変数名など)
    [rhs]             代入の右辺 (代入する値)

[ ] で囲まれた部分が C の構造体でそれをノードと呼ぶ。インデントしたのは その上のノードからポインタでつながっているノードである。この例なら、 [if] ノードには三つのノードが保持されていて、それぞれが「条件」「真の文」 「偽の文」を意味しているということである。また同じ高さで並んでいるのは 逐次実行を表す。つまりここでは if while assign の順に実行される。

構文木で重要なのは、保持するノードの種類はなんでもいいという点である。 例えば上の例では「条件」に保持するノードは expr と書いてあるが、これは 単に「式」ということで、式であるノードならなんでもいい。例えば代入だとか 足し算、引き算、メソッドコール、定数、などなど、どれでもいいということである。 これで本当に大丈夫なのかはコアの説明のところで詳細を見ていくことにする。

構文木が実行 (すなわちソースコード) の表現であるとすると、一方には データの表現があるはずである。つまり Ruby オブジェクトの空間である。 そして言ってみれば Ruby インタプリタというのはこの二つの空間の接点を 作り出す機構である。このことは「実行」を「CPU」、「データ」を「メモリ」と 言い換えてみればさらにはっきりするであろう。

さて、この Ruby Hacking Guide ではまずこの二つの主役のうち、 データとの関りの側面から見ていくことにする。