TinySCHEME のソースを読む -2 シンボル、環境

TinySCHEME のソースを読む -1 セルの構造
TinySCHEME のソースを読む -2 シンボル、環境
TinySCHEME のソースを読む -3 TinySCHEME の処理エンジン
TinySCHEME のソースを読む -4 トップレベルからの処理の流れ
TinySCHEME のソースを読む -5 define の例
tsdbg TinyScheme 用デバッグ extension

Symbol をどう表現するか

Symbol は、T_SYMBOL を _flag にしたセルと、T_STRING を _flag にしたセルの、二つのセルで表現される。T_SYMBOL セルの car 部が、T_STRING セルを指すようになっている。( 尚、T_SYMBOL セルの cdr 部は使われない。)

ただ、この表記は冗長なので、以後、セルを図で表す場合は以下のように省略して表記する:

TinySCHEME は、シンボル名を oblist (後述する) という hash テーブルで管理する。
また、T_SYMBOL セル自体は、シンボルの値というものを持たない。シンボルの値は、環境を表現する envir というセルが管理する。envir についても後述する。


oblist, vector

oblist シンボル名を管理するための hash テーブルである。実際は vector を使っており、同じ hash 値のものはリストになる。vector の要素数は 461 で固定され、増えることは無い。
vector は 1005 行目 mk_vector() によって作られる。vector は連続したセルを配列のように使い、全部で 1 + 要素数 / 2 のセルを使う。
先頭のセルは T_VECTOR セルで、要素数を数字で持つ。先頭のセル以降は、vector に格納するデータを"指す"ために使われる。これらのデータを指すために、car 部と cdr 部をそれぞれ使うことが出来るので、データのために vector が使うセルは要素数 / 2 で済む。

my-sum と name は共に hash 値が 4 で、oblist に登録されている例:

oblist に対するインターフェースは、(初期化などを除くと)以下の二つである:

    pointer oblist_add_by_name(scheme *sc, const char *name);
    pointer oblist_find_by_name(scheme *sc, const char *name);

環境, envir

TinySCHEME は環境を sc->envir で表現する。sc->envir は、現在の環境を示す T_ENVIRONMENT のセルと、その環境に属する slot のリストから成る。slot とは、シンボルとシンボルの値をそれぞれ car 部/ cdr 部に持つ cons セルである。
T_ENVIRONMENT のセルの car 部には slot のリストが格納され、envir の cdr 部には直前の環境が入る。
以下の例は、sc->envir の指す環境に、(define name "hal") と (define number 666) で定義された slog が含まれていることを示す:

global_env はグローバル環境を表す hash テーブルである。構造は oblist と全く同一である。


envir と oblist の関係

envir と oblist の関係を図にすると、以下のようになる。
この例では、二つの異なる環境に x が定義され、それぞれ値が違うが指しているシンボルは一つである:

envir に対するインターフェース

global_env が初期化されるのは、4594 行目である:

    new_frame_in_env(sc, sc->NIL);
    sc->global_env = sc->envir;

new_frame_in_env() は、二つ目の引数が NIL の場合、要素数 461 の vector を作り、vector のセルを car 部にした cons セルを作り、envir に代入する。envir に対するインターフェースは以下である:

    static void new_frame_in_env( scheme *sc, pointer old_env );
        // 新しい環境を作り、envir に代入する。
        // old_env が NIL の場合は envir の初期化
        // そうでない場合、old_env が新しい envir の cdr 部へ入る

    static INLINE void new_slot_spec_in_env( scheme *sc, pointer env, pointer variable, pointer value );
        // 環境 env に、シンボル variable と値 value から成る slot を作り、追加する

    static INLINE void new_slot_in_env( scheme *sc, pointer variable, pointer value );
        // new_slot_spec_in_env() のラッパー

    static pointer find_slot_in_env( scheme *sc, pointer env, pointer hdl, int all );
        // 環境 env から、シンボル hdl を探して slot を返す。all が 1 の場合は、env をさかのぼって検索を行う
        // シンボル hdl が環境 env に無い場合は NIL が戻る

    static INLINE void set_slot_in_env( scheme *sc, pointer slot, pointer value );
        // slot に value を代入する
        // この関数は、find_slot_in_env() で slot を取得してから、セットで呼ばれる

    static INLINE pointer slot_value_in_env( pointer slot );
        // slot の値を返す