interpvar.h
interpvar.hには、インタープリタ変数の定義が記述されています。インタープリタ変数とは、Perlのインタープリタごとに、定義される変数のことです。
インタープリタとは
Perlは、複数のインタープリタを持つことができます。Perlは、インタープリタを生成して、ソースコードの解釈を始めます。通常は、インタープリタはひとつで十分ですが、C言語のプログラムの中で、複数保持したい場合は、複数生成することが可能です。
# 複数のインタープリタ Perl - インタープリタ1 | - インタープリタ2 | - インタープリタ3
ただし、Perlがインタープリタを複数持つことができるのは「MULTIPLICITY」というマクロが有効になっているときだけです。これは、コンパイルオプションとして設定できます。自分の環境の場合は、CentOSのデフォルトのPerlであれば、有効で、perlbrewでインストールしたものは、無効になっていました。パフォーマンスは「MULTIPLICITY」が有効になっていないもののほうが、速いようです。
もし「MULTIPLICITY」が有効でなければ、Perlの構造は次のようになります。
Perl - (インタープリタなし)
=====
インタープリタ変数
インタープリタ変数は、インタープリタごとに持つ変数です。Perlのソースコードを読むときは、非常に頻繁に、interpvar.hを開くことになります。ここで、定義されている変数が、Perlのソースコードのあちらこちらで利用されているからです。
たとえば、サブルーチンのコールスタック情報、現在実行されている構文木のノード、レキシカル変数の情報、ローカル変数の情報、制御情報、SVのメモリ確保にかかわる変数、プログラムの実行の開始位置などです。
インタープリタ変数は、特殊なマクロを使って、定義されています。それは、PERLVARというマクロです。
PERLVAR(I, stack_sp, SV **) /* top of the stack */ PERLVAR(I, op, OP *) /* currently executing op */ PERLVAR(I, curpad, SV **) /* active pad (lexicals+tmps) */
PERLVARマクロを見てみましょう。「perl.h」に定義があります。
/* perl.h */ # define PERLVAR(prefix,var,type) type prefix##var;
C言語のdefine定義を使ったことがある人も「##」という記号を見た人は、少ないんじゃないでしょうか。「##」を使うと文字列が結合できます。
つまり、PERLVARマクロによって、次のように展開されます。
SV ** Istack_sp; OP * Iop; SV ** Icurpad;
でも、この変数は、Perlのソースコード上ではほとんど使われていません。多くの場合は「PL_stacksp」という変数名でアクセスされます。これは「embedvar.h」で定義されています。
#define PL_stack_sp (vTHX->Istack_sp)
ソースコードを実際に読み込んでいく上では、「PL_stack_sp」という変数名を見たなら、これは、インタープリタ変数だなとまず推測します。そして、「interpvar.h」を開いて「PERLVAR(I, stack_sp, SV **)」のような定義があるかどうかを確認します。
インタープリタ変数は「MULTIPLICITY」が有効でないときは、グローバル変数として定義される
インタープリタ変数は「MULTIPLICITY」が有効でないときは、インタープリタ変数は、グローバル変数として定義されます。その記述は「perl.h」にあります。
#if !defined(MULTIPLICITY) START_EXTERN_C # include "intrpvar.h" END_EXTERN_C #endif
vTHXは現在のインタープリタのこと
vTHXは、ひとつのインタープリタです。「MULTIPLICITY」の下では、「vTHX」は「aTHX」と「PERL_GET_INTERP」に展開されますが、一般的なPerlでは、「PERL_IMPLICIT_CONTEXT」が定義されているとして読みましょう。つまり「aTHX」に展開されると考えましょう。
#if defined(MULTIPLICITY) /* cases 2 and 3 above */ # if defined(PERL_IMPLICIT_CONTEXT) # define vTHX aTHX # else # define vTHX PERL_GET_INTERP # endif
さらに「perl.h」の中で「aTXH」は「my_perl」に展開されます。
/* perl.h */ # define aTHX my_perl
「my_perl」は、現在のインタープリタを表す変数で「perl_main.c」の中で定義されています。
/* perl.h */ static PerlInterpreter *my_perl;
PerlInterpreterは「perl.h」の中で「interpreter構造体」の別名として定義されています。
/* perl.h */ typedef struct interpreter PerlInterpreter;
そして最後に「interpreter構造体」は次のように定義されています。「interpvar.h」のインタープリタ変数の定義が、構造体のメンバとして記述されています。
/* perl.h */ struct interpreter { # include "intrpvar.h" };
「PL_stack_sp」は「my_perl->Istack_sp」に展開されるということがわかります。これは、現在のインタープリタの「Istack_sp」というメンバ変数にアクセスするということです。
まとめ
覚えておいてほしいことは、「PL_stack_sp」は「my_perl->Istack_sp」に展開されるということ。それに加えて、「MULTIPLICITY」が有効でない場合は、グローバル変数として「Istack_sp」が直接利用できるということです。「PL_stack_sp」を使うことで、複数のインタープリタを持つ場合と、持たない場合で、それを意識しないで、アクセスできます。
Perlのマクロ定義は、階層が深すぎますが、とことん深くもぐっていくと、着地点があります。