名前¶
perlinterp - An overview of the Perl interpreter
perlinterp - Perl インタプリタの概要
説明¶
This document provides an overview of how the Perl interpreter works at the level of C code, along with pointers to the relevant C source code files.
この文書は、C コードのレベルで Perl インタプリタがどのように動作しているかの 概要を、関連する C ソースコードファイルへのポインタと共に提供します。
インタプリタの要素¶
The work of the interpreter has two main stages: compiling the code into the internal representation, or bytecode, and then executing it. "Compiled code" in perlguts explains exactly how the compilation stage happens.
インタプリタの動作には二つの主要なステージがあります: コードを内部表現(バイトコード)にコンパイルし、それを実行します。 "Compiled code" in perlguts は、コンパイルステージがどのように起こるかを 正確に説明しています。
Here is a short breakdown of perl's operation:
perl の操作について簡単に説明します:
開始¶
The action begins in perlmain.c. (or miniperlmain.c for miniperl) This is very high-level code, enough to fit on a single screen, and it resembles the code found in perlembed; most of the real action takes place in perl.c
アクションは perlmain.c で始まります(miniperl の場合は miniperlmain.c)。 これは非常に高レベルのコードで、一つの画面に収まります; また、perlembed のコードに似ています; 実際のアクションのほとんどは perl.c で行われます。
perlmain.c is generated by ExtUtils::Miniperl
from miniperlmain.c at make time, so you should make perl to follow this along.
perlmain.c は ExtUtils::Miniperl
によって miniperlmain.c から make 時に生成されますので、perl はこれに従うようにしてください。
First, perlmain.c allocates some memory and constructs a Perl interpreter, along these lines:
まず、perlmain.c はメモリを割り当て、次の行に従って Perl インタプリタを 構築します:
1 PERL_SYS_INIT3(&argc,&argv,&env);
2
3 if (!PL_do_undump) {
4 my_perl = perl_alloc();
5 if (!my_perl)
6 exit(1);
7 perl_construct(my_perl);
8 PL_perl_destruct_level = 0;
9 }
Line 1 is a macro, and its definition is dependent on your operating system. Line 3 references PL_do_undump
, a global variable - all global variables in Perl start with PL_
. This tells you whether the current running program was created with the -u
flag to perl and then undump, which means it's going to be false in any sane context.
1 行目はマクロで、その定義はオペレーティングシステムによって異なります。 3 行目はグローバル変数 PL_do_undump
を参照しています; Perl のグローバル変数はすべて PL_
で始まります。 これにより、現在実行中のプログラムが perl に対して -u
フラグを付けて 作成され、次に undump フラグを付けて作成されたかどうかがわかります。 これは、まともなコンテキストでは偽になることを意味します。
Line 4 calls a function in perl.c to allocate memory for a Perl interpreter. It's quite a simple function, and the guts of it looks like this:
4 行目では、Perl インタプリタにメモリを割り当てるために perl.c の関数を呼び出しています。 これは非常に単純な関数で、その中身は次のようになります:
my_perl = (PerlInterpreter*)PerlMem_malloc(sizeof(PerlInterpreter));
Here you see an example of Perl's system abstraction, which we'll see later: PerlMem_malloc
is either your system's malloc
, or Perl's own malloc
as defined in malloc.c if you selected that option at configure time.
PerlMem_malloc
は、システムの malloc
か、または malloc.c で 定義されている Perl 自身の malloc
(設定時にこのオプションを選択した場合)の いずれかです。
Next, in line 7, we construct the interpreter using perl_construct, also in perl.c; this sets up all the special variables that Perl needs, the stacks, and so on.
次に、7 行目で、同じく perl.c で perl_construct を使用して インタプリタを作成します; これにより、Perl が必要とするすべての特殊変数やスタックなどが設定されます。
Now we pass Perl the command line options, and tell it to go:
次に、Perl にコマンドラインオプションを渡し、実行するように指示します:
exitstatus = perl_parse(my_perl, xs_init, argc, argv, (char **)NULL);
if (!exitstatus)
perl_run(my_perl);
exitstatus = perl_destruct(my_perl);
perl_free(my_perl);
perl_parse
is actually a wrapper around S_parse_body
, as defined in perl.c, which processes the command line options, sets up any statically linked XS modules, opens the program and calls yyparse
to parse it.
perl_parse
は実際には、perl.c で定義されている S_parse_body
の ラッパーです; このラッパーはコマンドラインオプションを処理し、静的にリンクされた XS モジュールを設定し、プログラムを開き、yyparse
を 呼び出して構文解析します。
パース¶
The aim of this stage is to take the Perl source, and turn it into an op tree. We'll see what one of those looks like later. Strictly speaking, there's three things going on here.
このステージの目的は、Perl ソースを取得し、それを op 木に変換することです。 これらのうちの一つがどのように見えるかについては、後で説明します。 厳密に言えば、ここでは三つのことが起こっています。
yyparse
, the parser, lives in perly.c, although you're better off reading the original YACC input in perly.y. (Yes, Virginia, there is a YACC grammar for Perl!) The job of the parser is to take your code and "understand" it, splitting it into sentences, deciding which operands go with which operators and so on.
パーサである yyparse
は perly.c にありますが、 元の YACC 入力を perly.y で読んだ方が良いでしょう。 (そう、バージニア、これが Perl のための YACC 文法です!)。 パーサの仕事は、コードを「理解」し、それを文に分割し、 どのオペランドがどの演算子と合うかなどを決定することです。
The parser is nobly assisted by the lexer, which chunks up your input into tokens, and decides what type of thing each token is: a variable name, an operator, a bareword, a subroutine, a core function, and so on. The main point of entry to the lexer is yylex
, and that and its associated routines can be found in toke.c. Perl isn't much like other computer languages; it's highly context sensitive at times, it can be tricky to work out what sort of token something is, or where a token ends. As such, there's a lot of interplay between the tokeniser and the parser, which can get pretty frightening if you're not used to it.
パーサは字句解析器の支援を受けます; 字句解析器は入力をトークンに分割し、変数名、演算子、裸の単語、サブルーチン、 コア関数など、各トークンがどのような種類のものであるかを判断します。 字句解析器への主なエントリポイントは yylex
です; 字句解析器とそれに関連するルーチンは toke.c にあります。 Perl は他のコンピュータ言語とはあまり似ていません; コンテキストに非常に敏感な場合があり、トークンがどのような種類の ものであるか、トークンがどこで終わるかを理解するのは難しい場合があります。 そのため、トークン解析器とパーサの間には多くの相互作用があり、 これに慣れていないと非常に恐ろしくなります。
As the parser understands a Perl program, it builds up a tree of operations for the interpreter to perform during execution. The routines which construct and link together the various operations are to be found in op.c, and will be examined later.
パーサは Perl プログラムを理解すると、実行中にインタプリタが 実行するための操作木を構築します。 さまざまな操作を構築してリンクするルーチンは op.cにあり、 これは後で検討します。
最適化¶
Now the parsing stage is complete, and the finished tree represents the operations that the Perl interpreter needs to perform to execute our program. Next, Perl does a dry run over the tree looking for optimisations: constant expressions such as 3 + 4
will be computed now, and the optimizer will also see if any multiple operations can be replaced with a single one. For instance, to fetch the variable $foo
, instead of grabbing the glob *foo
and looking at the scalar component, the optimizer fiddles the op tree to use a function which directly looks up the scalar in question. The main optimizer is peep
in op.c, and many ops have their own optimizing functions.
これで構文解析段階が完了し、完成した木は Perl インタプリタが プログラムを実行するために実行する必要のある操作を表します。 次に、Perl は木を仮ここで走査して最適化を探します: 3 + 4
のような定数式はここで計算され、オプティマイザは複数の操作が 単一の操作に置き換えられるかどうかも調べます。 例えば、変数 $foo
をフェッチするために、glob *foo
を取得して スカラ成分を調べる代わりに、オプティマイザは、問題のスカラを 直接検索する関数を使用するように op 木を操作します。 メインオプティマイザは op.c の peep
であり、多くの op は 独自の最適化関数を持っています。
実行¶
Now we're finally ready to go: we have compiled Perl byte code, and all that's left to do is run it. The actual execution is done by the runops_standard
function in run.c; more specifically, it's done by these three innocent looking lines:
Perl バイトコードをコンパイルし、あとはそれを実行するだけです。 実際の実行は、run.c の runops_standard
関数によって行われます; 具体的には、次の三つの無邪気に見える行によって行われます:
while ((PL_op = PL_op->op_ppaddr(aTHX))) {
PERL_ASYNC_CHECK();
}
You may be more comfortable with the Perl version of that:
次のような Perl バージョンの方が使いやすいかもしれません:
PERL_ASYNC_CHECK() while $Perl::op = &{$Perl::op->{function}};
Well, maybe not. Anyway, each op contains a function pointer, which stipulates the function which will actually carry out the operation. This function will return the next op in the sequence - this allows for things like if
which choose the next op dynamically at run time. The PERL_ASYNC_CHECK
makes sure that things like signals interrupt execution if required.
ええと、違うかも知れません。 とにかく、各 op には関数ポインタが含まれていて、実際に操作を実行する関数を 指定します。 この関数は、シーケンス内の次の op を返します - これにより、 if
のようなものが実行時に動的に次の op を選択することができます。 PERL_ASYNC_CHECK
は、シグナルのようなものが必要に応じて実行を 中断するようにします。
The actual functions called are known as PP code, and they're spread between four files: pp_hot.c contains the "hot" code, which is most often used and highly optimized, pp_sys.c contains all the system-specific functions, pp_ctl.c contains the functions which implement control structures (if
, while
and the like) and pp.c contains everything else. These are, if you like, the C code for Perl's built-in functions and operators.
実際に呼び出される関数は PP コードと呼ばれ、四つのファイルに分散されます。 pp_hot.c には最も頻繁に使用され高度に最適化された "hot"コードが含まれ、 pp_sys.c にはシステム固有の関数がすべて含まれ、 pp_ctl.c には制御構造を実装する関数(if
、while
など)が含まれ、 pp.cにはその他のすべてが含まれます。 これらは、言ってみれば、Perl の組み込み関数と演算子の C コードです。
Note that each pp_
function is expected to return a pointer to the next op. Calls to perl subs (and eval blocks) are handled within the same runops loop, and do not consume extra space on the C stack. For example, pp_entersub
and pp_entertry
just push a CxSUB
or CxEVAL
block struct onto the context stack which contain the address of the op following the sub call or eval. They then return the first op of that sub or eval block, and so execution continues of that sub or block. Later, a pp_leavesub
or pp_leavetry
op pops the CxSUB
or CxEVAL
, retrieves the return op from it, and returns it.
各 pp_
関数は、次の op へのポインタを返すことが期待されていることに 注意してください。 perl サブルーチン (および eval ブロック)への呼び出しは、同じ runops ループ内で処理され、C スタック上の余分なスペースを消費しません。 たとえば、pp_entersub
と pp_entertry
は、 CxSUB
または CxEVAL
ブロック構造体を、サブルーチン呼び出しまたは eval に続く op のアドレスを含むコンテキストスタックにプッシュします。 次に、それらはそのサブルーチンまたは eval ブロックの最初の op を返すので、 そのサブルーチンまたはブロックの実行が継続されます。 その後、pp_leavesub
または pp_leavetry
op が CxSUB
または CxEVAL
をポップし、そこから return op を取得して返します。
例外処理¶
Perl's exception handing (i.e. die
etc.) is built on top of the low-level setjmp()
/longjmp()
C-library functions. These basically provide a way to capture the current PC and SP registers and later restore them; i.e. a longjmp()
continues at the point in code where a previous setjmp()
was done, with anything further up on the C stack being lost. This is why code should always save values using SAVE_FOO
rather than in auto variables.
Perl の例外処理(die
など)は、低レベルの setjmp()
/longjmp()
C ライブラリ関数の上に構築されています。 これらは基本的に、現在の PC と SP レジスタを取得し、後で復元する方法を 提供します; つまり、longjmp()
は、コード内で前の setjmp()
が実行された時点で 継続され、C スタック上の上位のものは失われます。 これが、コードが常に自動変数ではなく SAVE_FOO
を使用して 値を保存すべき理由です。
The perl core wraps setjmp()
etc in the macros JMPENV_PUSH
and JMPENV_JUMP
. The basic rule of perl exceptions is that exit
, and die
(in the absence of eval
) perform a JMPENV_JUMP(2)
, while die
within eval
does a JMPENV_JUMP(3)
.
perl コアは、マクロ JMPENV_PUSH
と JMPENV_JUMP
で setjmp()
などをラップします。 perl 例外の基本的なルールは、exit
と die
(eval
がない場合)は JMPENV_JUMP(2)
を実行し、eval
内の die
は JMPENV_JUMP(3)
を 実行するということです。
At entry points to perl, such as perl_parse()
, perl_run()
and call_sv(cv, G_EVAL)
each does a JMPENV_PUSH
, then enter a runops loop or whatever, and handle possible exception returns. For a 2 return, final cleanup is performed, such as popping stacks and calling CHECK
or END
blocks. Amongst other things, this is how scope cleanup still occurs during an exit
.
perl_parse()
, perl_run()
, call_sv(cv, G_EVAL)
などの perl へのエントリポイントでは、それぞれ JMPENV_PUSH
を実行し、 runops ループなどに入り、考えられる例外リターンを処理します。 2 リターンの場合は、スタックをポップしたり、CHECK
または END
ブロックを呼び出すなど、最終的なクリーンアップが実行されます。 とりわけ、exit
の実行中にスコープのクリーンアップが行われる方法は このようになっています。
If a die
can find a CxEVAL
block on the context stack, then the stack is popped to that level and the return op in that block is assigned to PL_restartop
; then a JMPENV_JUMP(3)
is performed. This normally passes control back to the guard. In the case of perl_run
and call_sv
, a non-null PL_restartop
triggers re-entry to the runops loop. The is the normal way that die
or croak
is handled within an eval
.
die
がコンテキストスタック上に CxEVAL
ブロックを見つけることが できる場合、スタックはそのレベルにポップされ、そのブロック内の return op が PL_restartop
に割り当てられます; 次に JMPENV_JUMP(3)
が実行されます。 これにより、通常は制御がガードに戻されます。 perl_run
と call_sv
の場合、非 NULL の PL_restartop
が runops ループへの再エントリを引き起こします。 これは、eval
内で die
または croak
を処理する通常の方法です。
Sometimes ops are executed within an inner runops loop, such as tie, sort or overload code. In this case, something like
内部 runops ループ(tie、sort、overload コードなど)内で op が 実行されることがあります。 この場合、以下のようになります:
sub FETCH { eval { die } }
would cause a longjmp right back to the guard in perl_run
, popping both runops loops, which is clearly incorrect. One way to avoid this is for the tie code to do a JMPENV_PUSH
before executing FETCH
in the inner runops loop, but for efficiency reasons, perl in fact just sets a flag, using CATCH_SET(TRUE)
. The pp_require
, pp_entereval
and pp_entertry
ops check this flag, and if true, they call docatch
, which does a JMPENV_PUSH
and starts a new runops level to execute the code, rather than doing it on the current loop.
これは、perl_run
のガードに対して longjmp を引き起こし、両方の runops ループをポップさせますが、これは明らかに正しくありません。 これを回避する一つの方法は、内部 runops ループで FETCH
を実行する前に、 tie コードが JMPENV_PUSH
を実行することですが、効率性の理由から、 perl は実際には CATCH_SET(TRUE)
を使用してフラグを設定するだけです。 pp_require
, pp_entereval
, pp_entertry
op はこのフラグをチェックし、 真の場合は docatch
を呼び出します; これは JMPENV_PUSH
を実行し、新しい runops レベルを開始して コードを実行します; 現在のループでは実行されません。
As a further optimisation, on exit from the eval block in the FETCH
, execution of the code following the block is still carried on in the inner loop. When an exception is raised, docatch
compares the JMPENV
level of the CxEVAL
with PL_top_env
and if they differ, just re-throws the exception. In this way any inner loops get popped.
さらなる最適化として、FETCH
の eval ブロックを終了すると、 ブロックに続くコードの実行は依然として内側のループで実行されます。 例外が発生すると、docatch
は CxEVAL
の JMPENV
レベルと PL_top_env
を比較し、両者が異なる場合は例外を再スローします。 このようにして、内側のループはポップされます。
Here's an example.
以下は例です:
1: eval { tie @a, 'A' };
2: sub A::TIEARRAY {
3: eval { die };
4: die;
5: }
To run this code, perl_run
is called, which does a JMPENV_PUSH
then enters a runops loop. This loop executes the eval and tie ops on line 1, with the eval pushing a CxEVAL
onto the context stack.
このコードを実行するために、perl_run
が呼び出され、JMPENV_PUSH
を 実行して runops ループに入ります。 このループは 1 行目の eval と tie op を実行します; eval は CxEVAL
をコンテキストスタックにプッシュします。
The pp_tie
does a CATCH_SET(TRUE)
, then starts a second runops loop to execute the body of TIEARRAY
. When it executes the entertry op on line 3, CATCH_GET
is true, so pp_entertry
calls docatch
which does a JMPENV_PUSH
and starts a third runops loop, which then executes the die op. At this point the C call stack looks like this:
pp_tie
は CATCH_SET(TRUE)
を実行し、2 番目の runops ループを開始して TIEARRAY
の本体を実行します。 3 行目の entertry op を実行すると、CATCH_GET
は真であるため、 pp_entertry
は docatch
を呼び出して JMPENV_PUSH
を実行し、 3 番目の runops ループを開始して die op を実行します。 この時点で、C コールスタックは次のようになります。
Perl_pp_die
Perl_runops # third loop
S_docatch_body
S_docatch
Perl_pp_entertry
Perl_runops # second loop
S_call_body
Perl_call_sv
Perl_pp_tie
Perl_runops # first loop
S_run_body
perl_run
main
and the context and data stacks, as shown by -Dstv
, look like:
コンテキストスタックとデータスタックは、-Dstv
で示すように、 次のようになります:
STACK 0: MAIN
CX 0: BLOCK =>
CX 1: EVAL => AV() PV("A"\0)
retop=leave
STACK 1: MAGIC
CX 0: SUB =>
retop=(null)
CX 1: EVAL => *
retop=nextstate
The die pops the first CxEVAL
off the context stack, sets PL_restartop
from it, does a JMPENV_JUMP(3)
, and control returns to the top docatch
. This then starts another third-level runops level, which executes the nextstate, pushmark and die ops on line 4. At the point that the second pp_die
is called, the C call stack looks exactly like that above, even though we are no longer within an inner eval; this is because of the optimization mentioned earlier. However, the context stack now looks like this, ie with the top CxEVAL popped:
die はコンテキストスタックから最初の CxEVAL
をポップし、そこから PL_restartop
をセットし、JMPENV_JUMP(3)
を実行し、制御はトップの docatch
に戻ります。 これにより、もう一つの第 3 レベルの runops レベルが開始され、 4 行目の nextstate、pushmark、die ops が実行されます。 2 番目の pp_die
が呼び出された時点で、C のコールスタックは上記と まったく同じように見えますが、内側の eval 内ではありません; これは前述の最適化のためです。 しかし、コンテキストスタックは次のように見えます; つまり、トップ CxEVAL がポップされます:
STACK 0: MAIN
CX 0: BLOCK =>
CX 1: EVAL => AV() PV("A"\0)
retop=leave
STACK 1: MAGIC
CX 0: SUB =>
retop=(null)
The die on line 4 pops the context stack back down to the CxEVAL, leaving it as:
4 行目の die は、コンテキストスタックを CxEVAL にポップダウンし、 次のように残します:
STACK 0: MAIN
CX 0: BLOCK =>
As usual, PL_restartop
is extracted from the CxEVAL
, and a JMPENV_JUMP(3)
done, which pops the C stack back to the docatch:
いつものように、CxEVAL
から PL_restartop
が抽出され、 JMPENV_JUMP(3)
が実行されて C スタックが docatch に戻されます:
S_docatch
Perl_pp_entertry
Perl_runops # second loop
S_call_body
Perl_call_sv
Perl_pp_tie
Perl_runops # first loop
S_run_body
perl_run
main
In this case, because the JMPENV
level recorded in the CxEVAL
differs from the current one, docatch
just does a JMPENV_JUMP(3)
and the C stack unwinds to:
この場合、CxEVAL
に記録されている JMPENV
レベルが現在のレベルと 異なるため、docatch
は JMPENV_JUMP(3)
を実行し、C スタックは 以下のように巻き戻します:
perl_run
main
Because PL_restartop
is non-null, run_body
starts a new runops loop and execution continues.
PL_restartop
は NULL でないため、run_body
は新しい runops ループを 開始し、実行が継続されます。
内部変数型¶
You should by now have had a look at perlguts, which tells you about Perl's internal variable types: SVs, HVs, AVs and the rest. If not, do that now.
perlguts を見ると、Perl の内部変数型(SV、HV、AVなど)について 知ることができます。 そうでない場合は、今すぐ見てください。
These variables are used not only to represent Perl-space variables, but also any constants in the code, as well as some structures completely internal to Perl. The symbol table, for instance, is an ordinary Perl hash. Your code is represented by an SV as it's read into the parser; any program files you call are opened via ordinary Perl filehandles, and so on.
これらの変数は、Perl スペース変数だけでなく、コード内の任意の定数や、 完全に Perl 内部の構造体を表すためにも使用されます。 例えば、シンボルテーブルは通常の Perl ハッシュです。 コードはパーサに読み込まれるときに SV によって表されます; 呼び出したプログラムファイルは通常の Perl ファイルハンドルを 介して開かれます; といったことです。
The core Devel::Peek module lets us examine SVs from a Perl program. Let's see, for instance, how Perl treats the constant "hello"
.
コア Devel::Peek モジュールを使用すると、Perl プログラムから SV を調べることができます。 例えば、Perl が定数 "hello"
をどのように処理するかを見てみましょう。
% perl -MDevel::Peek -e 'Dump("hello")'
1 SV = PV(0xa041450) at 0xa04ecbc
2 REFCNT = 1
3 FLAGS = (POK,READONLY,pPOK)
4 PV = 0xa0484e0 "hello"\0
5 CUR = 5
6 LEN = 6
Reading Devel::Peek
output takes a bit of practise, so let's go through it line by line.
Devel::Peek
の出力を読むには少し練習が必要なので、1 行ずつ 見ていきましょう。
Line 1 tells us we're looking at an SV which lives at 0xa04ecbc
in memory. SVs themselves are very simple structures, but they contain a pointer to a more complex structure. In this case, it's a PV, a structure which holds a string value, at location 0xa041450
. Line 2 is the reference count; there are no other references to this data, so it's 1.
1 行目は、メモリ内の 0xa04ecbc
に存在する SV を見ていることを示しています。 SV 自体は非常に単純な構造ですが、より複雑な構造へのポインタを含んでいます。 この場合は、それは PV で、場所 0xa041450
にある文字列値を保持する構造です。 2 行目は参照カウントです; このデータへの他の参照はないので 1 です。
Line 3 are the flags for this SV - it's OK to use it as a PV, it's a read-only SV (because it's a constant) and the data is a PV internally. Next we've got the contents of the string, starting at location 0xa0484e0
.
3 行目はこの SV のフラグです - これをPVとして使用しても問題ありません; これは読み取り専用の SV (定数であるため)であり、データは内部的に PV です。 次に、位置 0xa0484e0
から始まる文字列の内容を取得します。
Line 5 gives us the current length of the string - note that this does not include the null terminator. Line 6 is not the length of the string, but the length of the currently allocated buffer; as the string grows, Perl automatically extends the available storage via a routine called SvGROW
.
5 行目は、文字列の現在の長さを示しています - これは ヌル終端文字が含まれて いない ことに注意してください。 6 行目は文字列の長さではなく、現在割り当てられているバッファの長さです; 文字列が大きくなると、Perl は自動的に SvGROW
というルーチンを使って 利用可能な記憶域を拡張します。
You can get at any of these quantities from C very easily; just add Sv
to the name of the field shown in the snippet, and you've got a macro which will return the value: SvCUR(sv)
returns the current length of the string, SvREFCOUNT(sv)
returns the reference count, SvPV(sv, len)
returns the string itself with its length, and so on. More macros to manipulate these properties can be found in perlguts.
これらの値は C から非常に簡単に得ることができます; スニペットに示されているフィールドの名前に Sv
を追加するだけで、 その値を返すマクロができます: SvCUR(sv)
は文字列の現在の長さを返し、SvREFCOUNT(sv)
は 参照カウントを返し、SvPV(sv, len)
は文字列そのものとその長さを返します。 これらのプロパティを操作するもっと多くのマクロは perlguts にあります。
Let's take an example of manipulating a PV, from sv_catpvn
, in sv.c
sv.c の sv_catpvn
から PV を操作する例を見てみましょう。
1 void
2 Perl_sv_catpvn(pTHX_ register SV *sv, register const char *ptr, register STRLEN len)
3 {
4 STRLEN tlen;
5 char *junk;
6 junk = SvPV_force(sv, tlen);
7 SvGROW(sv, tlen + len + 1);
8 if (ptr == junk)
9 ptr = SvPVX(sv);
10 Move(ptr,SvPVX(sv)+tlen,len,char);
11 SvCUR(sv) += len;
12 *SvEND(sv) = '\0';
13 (void)SvPOK_only_UTF8(sv); /* validate pointer */
14 SvTAINT(sv);
15 }
This is a function which adds a string, ptr
, of length len
onto the end of the PV stored in sv
. The first thing we do in line 6 is make sure that the SV has a valid PV, by calling the SvPV_force
macro to force a PV. As a side effect, tlen
gets set to the current value of the PV, and the PV itself is returned to junk
.
これは、長さ len
の文字列 ptr
を、sv
に保存されている PV の末尾に 追加する関数です。 6 行目で最初に行うことは、SvPV_force
マクロを呼び出して PV を 強制することによって、SV が有効な PV を 持っている ことを確認することです。 副作用として、tlen
は PV の現在の値に設定され、PV 自体は junk
に 戻されます。
In line 7, we make sure that the SV will have enough room to accommodate the old string, the new string and the null terminator. If LEN
isn't big enough, SvGROW
will reallocate space for us.
7 行目では、SV に古い文字列、新しい文字列、ヌルターミネータを収容する 十分なスペースがあることを確認しています。 LEN
が十分に大きくない場合は、SvGROW
がスペースを再割り当てします。
Now, if junk
is the same as the string we're trying to add, we can grab the string directly from the SV; SvPVX
is the address of the PV in the SV.
junk
が追加しようとしている文字列と同じであれば、その文字列を SV から 直接取得できます; SvPVX
は SV 内の PV のアドレスです。
Line 10 does the actual catenation: the Move
macro moves a chunk of memory around: we move the string ptr
to the end of the PV - that's the start of the PV plus its current length. We're moving len
bytes of type char
. After doing so, we need to tell Perl we've extended the string, by altering CUR
to reflect the new length. SvEND
is a macro which gives us the end of the string, so that needs to be a "\0"
.
10 行目で実際の結合が行われます: Move
マクロはメモリの塊を移動します: 文字列 ptr
を PV の末尾に移動します - これは PV の先頭に現在の長さを加えたものです。 char
型の len
バイトを移動します。 その後、新しい長さを反映するように CUR
を変更して文字列を拡張したことを Perl に伝える必要があります。 SvEND
は文字列の末尾を与えるマクロなので、"\0"
である必要があります。
Line 13 manipulates the flags; since we've changed the PV, any IV or NV values will no longer be valid: if we have $a=10; $a.="6";
we don't want to use the old IV of 10. SvPOK_only_utf8
is a special UTF-8-aware version of SvPOK_only
, a macro which turns off the IOK and NOK flags and turns on POK. The final SvTAINT
is a macro which launders tainted data if taint mode is turned on.
13 行目はフラグを操作します; PV を変更したため、IV や NV の値は無効になります: $a=10; $a.="6";
があれば、古い IV の 10 は使いたくありません。 SvPOK_only_utf8
は SvPOK_only
の特別な UTF-8 対応バージョンで、 IOK と NOK フラグをオフにし、POK をオンにするマクロです。 最後の SvTAINT
は、汚染チェックモードがオンになっていれば、汚染された データを洗浄するマクロです。
AVs and HVs are more complicated, but SVs are by far the most common variable type being thrown around. Having seen something of how we manipulate these, let's go on and look at how the op tree is constructed.
AV と HV はもっと複雑ですが、SV は群を抜いて最も一般的な変数型です。 これらを操作する方法を見てきたので、次に op 木がどのように構築されるかを 見ていきましょう。
op 木¶
First, what is the op tree, anyway? The op tree is the parsed representation of your program, as we saw in our section on parsing, and it's the sequence of operations that Perl goes through to execute your program, as we saw in "Running".
まず、op 木とは何でしょうか? op 木は、構文解析のセクションで説明したように、プログラムを構文解析した 表現であり、"Running" で説明したように、Perl がプログラムを実行するために 行う一連の操作です。
An op is a fundamental operation that Perl can perform: all the built-in functions and operators are ops, and there are a series of ops which deal with concepts the interpreter needs internally - entering and leaving a block, ending a statement, fetching a variable, and so on.
op は Perl が実行できる基本的な操作です: すべての組み込み関数と演算子は op であり、ブロックの出入り、文の 終了、変数のフェッチなど、インタプリタが内部的に必要とする概念を処理する 一連の op があります。
The op tree is connected in two ways: you can imagine that there are two "routes" through it, two orders in which you can traverse the tree. First, parse order reflects how the parser understood the code, and secondly, execution order tells perl what order to perform the operations in.
op 木は二つの方法で接続されています: op 木には二つの「ルート」があり、ツリーをトラバースできる二つの 順序があると想像できます。 第 1 に、構文解析順序はパーサがコードをどのように理解したかを反映し、 第 2 に、実行順序は perl に操作を実行する順序を指示します。
The easiest way to examine the op tree is to stop Perl after it has finished parsing, and get it to dump out the tree. This is exactly what the compiler backends B::Terse, B::Concise and B::Debug do.
op 木を調べる最も簡単な方法は、Perl が構文解析を完了した後で Perl を停止し、 Perl に木をダンプさせることです。 これはまさに、コンパイラのバックエンド B::Terse、 B::Concise、B::Debug が行うことです。
Let's have a look at how Perl sees $a = $b + $c
:
Perl が $a = $b + $c
をどのように見るかを見てみましょう。
% perl -MO=Terse -e '$a=$b+$c'
1 LISTOP (0x8179888) leave
2 OP (0x81798b0) enter
3 COP (0x8179850) nextstate
4 BINOP (0x8179828) sassign
5 BINOP (0x8179800) add [1]
6 UNOP (0x81796e0) null [15]
7 SVOP (0x80fafe0) gvsv GV (0x80fa4cc) *b
8 UNOP (0x81797e0) null [15]
9 SVOP (0x8179700) gvsv GV (0x80efeb0) *c
10 UNOP (0x816b4f0) null [15]
11 SVOP (0x816dcf0) gvsv GV (0x80fa460) *a
Let's start in the middle, at line 4. This is a BINOP, a binary operator, which is at location 0x8179828
. The specific operator in question is sassign
- scalar assignment - and you can find the code which implements it in the function pp_sassign
in pp_hot.c. As a binary operator, it has two children: the add operator, providing the result of $b+$c
, is uppermost on line 5, and the left hand side is on line 10.
真ん中の 4 行目から始めましょう。 これは BINOP (二項演算子)で、位置 0x8179828
にあります。 問題となっている特定の演算子は sassign
- スカラ代入 - です; この演算子を実装するコードは、pp_hot.c の関数 pp_sassign
にあります。 二項演算子としては二つの子があります: $b+$c
の結果を与える加算演算子は 5 行目の一番上にあり、左側は 10 行目にあります。
Line 10 is the null op: this does exactly nothing. What is that doing there? If you see the null op, it's a sign that something has been optimized away after parsing. As we mentioned in "Optimization", the optimization stage sometimes converts two operations into one, for example when fetching a scalar variable. When this happens, instead of rewriting the op tree and cleaning up the dangling pointers, it's easier just to replace the redundant operation with the null op. Originally, the tree would have looked like this:
10 行目は null op です: これは何もしません。 そこで何をしているのでしょう? null op が表示された場合は、解析後に何かが最適化されたことを示しています。 "Optimization" で説明したように、最適化ステージでは、スカラ変数を フェッチする場合など、二つの演算が一つに変換されることがあります。 このような場合は、op 木を書き直して相手がいないポインタを クリーンアップする代わりに、冗長な演算を null op に置き換える方が簡単です。 本来、木は次のように表示されます:
10 SVOP (0x816b4f0) rv2sv [15]
11 SVOP (0x816dcf0) gv GV (0x80fa460) *a
That is, fetch the a
entry from the main symbol table, and then look at the scalar component of it: gvsv
(pp_gvsv
into pp_hot.c) happens to do both these things.
つまり、メインシンボルテーブルから a
エントリを取得し、その スカラコンポーネントを調べます: gsvsv
(pp_hot.c の pp_gsvsv
)は、これらの両方を実行します。
The right hand side, starting at line 5 is similar to what we've just seen: we have the add
op (pp_add
also in pp_hot.c) add together two gvsv
s.
5 行目から始まる右側は、先ほど見たものと似ています: add
op (pp_add
も pp_hot.c にあります) が二つの gsvsv
を 加算します。
Now, what's this about?
ここで、これは何でしょう?
1 LISTOP (0x8179888) leave
2 OP (0x81798b0) enter
3 COP (0x8179850) nextstate
enter
and leave
are scoping ops, and their job is to perform any housekeeping every time you enter and leave a block: lexical variables are tidied up, unreferenced variables are destroyed, and so on. Every program will have those first three lines: leave
is a list, and its children are all the statements in the block. Statements are delimited by nextstate
, so a block is a collection of nextstate
ops, with the ops to be performed for each statement being the children of nextstate
. enter
is a single op which functions as a marker.
enter
と leave
はスコープ op であり、それらの仕事は、ブロックに 入ったり出たりするたびにハウスキーピングを実行することです: レキシカル変数は整理され、参照されていない変数は破棄され、などです。 すべてのプログラムには最初の 3 行があります: leave
はリストであり、その子はブロック内のすべての文です。 文は nextstate
で区切られているため、ブロックは nextstate
op の集合であり、各文に対して実行される op は nextstate
の子となります。 enter
はマーカーとして機能する単一の op です。
That's how Perl parsed the program, from top to bottom:
このようにして、Perl はプログラムを上から下まで構文解析しました:
Program
|
Statement
|
=
/ \
/ \
$a +
/ \
$b $c
However, it's impossible to perform the operations in this order: you have to find the values of $b
and $c
before you add them together, for instance. So, the other thread that runs through the op tree is the execution order: each op has a field op_next
which points to the next op to be run, so following these pointers tells us how perl executes the code. We can traverse the tree in this order using the exec
option to B::Terse
:
しかし、この順序で操作を 実行 することは不可能です: 例えば、$b
と $c
の値を見つけてから、それらを一緒に追加する 必要があります。 そのため、op 木を通るもう一つの糸は実行順序です: 各 op には、次に実行される op を指すフィールド op_next
があるので、 これらのポインタに従って perl がどのようにコードを実行するかを 知ることができます。 exec
オプションを B::Terse
に指定すると、この順序で木を走査できます:
% perl -MO=Terse,exec -e '$a=$b+$c'
1 OP (0x8179928) enter
2 COP (0x81798c8) nextstate
3 SVOP (0x81796c8) gvsv GV (0x80fa4d4) *b
4 SVOP (0x8179798) gvsv GV (0x80efeb0) *c
5 BINOP (0x8179878) add [1]
6 SVOP (0x816dd38) gvsv GV (0x80fa468) *a
7 BINOP (0x81798a0) sassign
8 LISTOP (0x8179900) leave
This probably makes more sense for a human: enter a block, start a statement. Get the values of $b
and $c
, and add them together. Find $a
, and assign one to the other. Then leave.
これはおそらく人間にとってより分かりやすいでしょう: ブロックにを入り、文を開始します。 $b
と $c
の値を取得し、それらを加算します。 $a
を検索し、一方をもう一方に代入します。 そして離れます。
The way Perl builds up these op trees in the parsing process can be unravelled by examining perly.y, the YACC grammar. Let's take the piece we need to construct the tree for $a = $b + $c
Perl が構文解析プロセスでこれらの op 木を構築する方法は、YACC 文法である perly.y を調べることによって解明できます。 $a = $b + $c
の木を構築するために必要な部分を取り上げましょう:
1 term : term ASSIGNOP term
2 { $$ = newASSIGNOP(OPf_STACKED, $1, $2, $3); }
3 | term ADDOP term
4 { $$ = newBINOP($2, 0, scalar($1), scalar($3)); }
If you're not used to reading BNF grammars, this is how it works: You're fed certain things by the tokeniser, which generally end up in upper case. Here, ADDOP
, is provided when the tokeniser sees +
in your code. ASSIGNOP
is provided when =
is used for assigning. These are "terminal symbols", because you can't get any simpler than them.
BNF 文法を読むことに慣れていない人は、次のように動作します: ある種のものをトークナイザによって供給されます; それは通常大文字になります。 ここでは、ADDOP
は、トークナイザがコード内で +
が検出したときに 提供されます。 ASSIGNOP
は、代入のために =
が使用されたときに提供されます。 これらは「終端記号」です; これ以上単純なものは得られないからです。
The grammar, lines one and three of the snippet above, tells you how to build up more complex forms. These complex forms, "non-terminal symbols" are generally placed in lower case. term
here is a non-terminal symbol, representing a single expression.
上のスニペットの1 行目と3 行目の文法では、より複雑な形式を 構築する方法が説明されています。 これらの複合形式である「非終端記号」は、通常は小文字で配置されます。 ここで term
は、単一の式を表す非終端記号です。
The grammar gives you the following rule: you can make the thing on the left of the colon if you see all the things on the right in sequence. This is called a "reduction", and the aim of parsing is to completely reduce the input. There are several different ways you can perform a reduction, separated by vertical bars: so, term
followed by =
followed by term
makes a term
, and term
followed by +
followed by term
can also make a term
.
文法は次の規則を与えます: 右側のすべてのものを順番に見れば、 コロンの左側のものを作ることができます。 これは「還元」(reduction)と呼ばれ、構文解析の目的は入力を完全に 還元することです。 還元を実行するにはいくつかの異なる方法があり、縦棒で区切られています: つまり、term
の後に =
と term
が続くと term
を作成し、 term
の後に +
と term
が続いても term
を作成できます。
So, if you see two terms with an =
or +
, between them, you can turn them into a single expression. When you do this, you execute the code in the block on the next line: if you see =
, you'll do the code in line 2. If you see +
, you'll do the code in line 4. It's this code which contributes to the op tree.
それで、二つの項の間に =
または +
がある場合、それらを一つの式に 変換できます。 これを行うときは、次の行のブロック内のコードを実行します: =
がある場合は 2 行目のコードを実行します。 +
がある場合は 4 行目のコードを実行します。 このコードが op 木に貢献しています。
| term ADDOP term
{ $$ = newBINOP($2, 0, scalar($1), scalar($3)); }
What this does is creates a new binary op, and feeds it a number of variables. The variables refer to the tokens: $1
is the first token in the input, $2
the second, and so on - think regular expression backreferences. $$
is the op returned from this reduction. So, we call newBINOP
to create a new binary operator. The first parameter to newBINOP
, a function in op.c, is the op type. It's an addition operator, so we want the type to be ADDOP
. We could specify this directly, but it's right there as the second token in the input, so we use $2
. The second parameter is the op's flags: 0 means "nothing special". Then the things to add: the left and right hand side of our expression, in scalar context.
これにより、新しいバイナリ op が作成され、多数の変数が渡されます。 変数はトークンを参照します: $1
は入力の最初のトークン、$2
は 2 番目のトークン、という形です - 正規表現の後方参照を考えてみてください。 $$
はこの還元から返される op です。 そこで、newBINOP
を呼び出して新しい二項演算子を作成します。 op.c にある関数である newBINOP
の最初の引数は op 型です。 これは加算演算子なので、型が ADDOP
になってほしいです。 これを直接指定することもできますが、これは入力の 2 番目のトークンとして すぐそこにあるので、$2
を使用します。 2 番目の引数は op のフラグです: 0 は「特別なものがない」ことを意味します。 次に追加すべきものは、スカラコンテキストでの式の左辺と右辺です。
スタック¶
When perl executes something like addop
, how does it pass on its results to the next op? The answer is, through the use of stacks. Perl has a number of stacks to store things it's currently working on, and we'll look at the three most important ones here.
perl が addop
のようなものを実行した場合、その結果をどのように 次の op に渡すのでしょうか? 答えは、スタックを使用することです。 Perl には、現在作業中のものを保存するためのスタックが数多くありますが、 ここでは最も重要な三つのスタックについて説明します。
引数スタック¶
Arguments are passed to PP code and returned from PP code using the argument stack, ST
. The typical way to handle arguments is to pop them off the stack, deal with them how you wish, and then push the result back onto the stack. This is how, for instance, the cosine operator works:
引数は PP コードに渡され、引数スタック ST
を使用して PP コードから 返されます。 引数を処理する一般的な方法は、引数をスタックから取り出し、 必要に応じて処理した後、結果をスタックにプッシュします。 たとえば、余弦演算子は次のように動作します:
NV value;
value = POPn;
value = Perl_cos(value);
XPUSHn(value);
We'll see a more tricky example of this when we consider Perl's macros below. POPn
gives you the NV (floating point value) of the top SV on the stack: the $x
in cos($x)
. Then we compute the cosine, and push the result back as an NV. The X
in XPUSHn
means that the stack should be extended if necessary - it can't be necessary here, because we know there's room for one more item on the stack, since we've just removed one! The XPUSH*
macros at least guarantee safety.
以下に示す Perl のマクロを考えると、もっと巧妙な例を見ることになります。 POPn
はスタック上の最上位 SV の NV (浮動小数点値)を与えます: cos($x)
の $x
です。 次にコサインを計算し、その結果を NV としてプッシュします。 XPUSHn
の X
は、必要に応じてスタックを拡張する 必要があることを意味します - ここでは必要ありません; なぜなら、スタック上にもう一つの項目のためのスペースがあることが わかっているからです; なぜなら、一つを削除したばかりなのです! XPUSH*
マクロは少なくとも安全性を保証します。
Alternatively, you can fiddle with the stack directly: SP
gives you the first element in your portion of the stack, and TOP*
gives you the top SV/IV/NV/etc. on the stack. So, for instance, to do unary negation of an integer:
あるいは、スタックを直接操作することもできます: SP
は スタックのあなたの部分の最初の要素を与え、TOP*
はスタック上の最上位の SV/IV/NV などを与えます。 たとえば、整数の単項否定を行うには、次のようにします:
SETi(-TOPi);
Just set the integer value of the top stack entry to its negation.
最上位スタックエントリの整数値をその否定に設定するだけです。
Argument stack manipulation in the core is exactly the same as it is in XSUBs - see perlxstut, perlxs and perlguts for a longer description of the macros used in stack manipulation.
コアでの引数スタック操作は、XSUBs とまったく同じです - スタック操作で 使用されるマクロのより長い説明については、 perlxstut、perlxs、perlguts を参照してください。
マークスタック¶
I say "your portion of the stack" above because PP code doesn't necessarily get the whole stack to itself: if your function calls another function, you'll only want to expose the arguments aimed for the called function, and not (necessarily) let it get at your own data. The way we do this is to have a "virtual" bottom-of-stack, exposed to each function. The mark stack keeps bookmarks to locations in the argument stack usable by each function. For instance, when dealing with a tied variable, (internally, something with "P" magic) Perl has to call methods for accesses to the tied variables. However, we need to separate the arguments exposed to the method to the argument exposed to the original function - the store or fetch or whatever it may be. Here's roughly how the tied push
is implemented; see av_push
in av.c:
上で「スタックのあなたの部分」と言ったのは、PP コードが必ずしも スタック全体を自分自身に取得する必要はないからです: 関数が別の関数を呼び出す場合は、呼び出された関数を対象とした引数を 公開するだけで、(必ずしも)自分自身のデータを取得させるわけではありません。 これを行う方法は、各関数に公開される「仮想的な」スタックの最下位を 持つことです。 マークスタックは、各関数が使用できる引数スタック内の場所への ブックマークを保持します。 例えば、tie された変数を扱う場合(内部では "P" マジックのようなもの)、 Perl は tie された変数にアクセスするためにメソッドを呼び出す必要があります。 ただし、メソッドに公開される引数を、元の関数に公開される引数(store や fetch など)に分離する必要があります。 tie された push
がどのように実装されるかを大まかに説明します; av.c の av_push
を参照してください。
1 PUSHMARK(SP);
2 EXTEND(SP,2);
3 PUSHs(SvTIED_obj((SV*)av, mg));
4 PUSHs(val);
5 PUTBACK;
6 ENTER;
7 call_method("PUSH", G_SCALAR|G_DISCARD);
8 LEAVE;
Let's examine the whole implementation, for practice:
実践のために、実装全体を調べてみましょう:
1 PUSHMARK(SP);
Push the current state of the stack pointer onto the mark stack. This is so that when we've finished adding items to the argument stack, Perl knows how many things we've added recently.
スタックポインタの現在の状態をマークスタックにプッシュします。 これは、引数スタックへの項目の追加が完了したときに、Perl が最近追加した 項目の数を知るためです。
2 EXTEND(SP,2);
3 PUSHs(SvTIED_obj((SV*)av, mg));
4 PUSHs(val);
We're going to add two more items onto the argument stack: when you have a tied array, the PUSH
subroutine receives the object and the value to be pushed, and that's exactly what we have here - the tied object, retrieved with SvTIED_obj
, and the value, the SV val
.
引数スタックにさらに二つの項目を追加します: tie された配列がある場合、PUSH
サブルーチンはオブジェクトと プッシュされる値を受け取ります; そしてこれがここで得られるものです - SvTIED_obj
で取得された tie されたオブジェクトと、 その値である SV val
です。
5 PUTBACK;
Next we tell Perl to update the global stack pointer from our internal variable: dSP
only gave us a local copy, not a reference to the global.
次に、内部変数からグローバルスタックポインタを更新するように Perl に指示します: dSp
はローカルコピーだけを提供し、グローバルへの参照は提供しません。
6 ENTER;
7 call_method("PUSH", G_SCALAR|G_DISCARD);
8 LEAVE;
ENTER
and LEAVE
localise a block of code - they make sure that all variables are tidied up, everything that has been localised gets its previous value returned, and so on. Think of them as the {
and }
of a Perl block.
ENTER
と LEAVE
はコードブロックをローカル化します - すべての変数が 整理されていること、ローカル化されたすべてのものが以前の値を返すことなどを 確認します。 これらは Perl ブロックの {
と }
と考えてください。
To actually do the magic method call, we have to call a subroutine in Perl space: call_method
takes care of that, and it's described in perlcall. We call the PUSH
method in scalar context, and we're going to discard its return value. The call_method() function removes the top element of the mark stack, so there is nothing for the caller to clean up.
マジックメソッド呼び出しを実際に行うためには、Perl 空間でサブルーチンを 呼び出す必要があります: call_method
がこれを処理します; これについては perlcall で説明しています。 PUSH
メソッドをスカラコンテキストで呼び出し、その戻り値を破棄します。 call_method() 関数はマークスタックの最上位要素を削除するため、 呼び出し側がクリーンアップするものはありません。
保存スタック¶
C doesn't have a concept of local scope, so perl provides one. We've seen that ENTER
and LEAVE
are used as scoping braces; the save stack implements the C equivalent of, for example:
C にはローカルスコープという概念がないので、perl が提供しています。 ENTER
と LEAVE
がスコープを作る中かっことして 使用されていることを見てきました; 保存スタックは以下のような C に相当するものを実装しています:
{
local $foo = 42;
...
}
See "Localizing changes" in perlguts for how to use the save stack.
保存スタックの使用方法については、 "Localizing changes" in perlguts を参照してください。
大量のマクロ¶
One thing you'll notice about the Perl source is that it's full of macros. Some have called the pervasive use of macros the hardest thing to understand, others find it adds to clarity. Let's take an example, the code which implements the addition operator:
Perl ソースに関して気付くかも知れない一つのことは、Perl ソースには マクロが豊富に含まれているということです。 マクロが広く使われていることを理解するのが最も難しいとする人もいれば、 マクロが明快さを増すと考える人もいます。 例えば、加算演算子を実装するコードを例にとりましょう:
1 PP(pp_add)
2 {
3 dSP; dATARGET; tryAMAGICbin(add,opASSIGN);
4 {
5 dPOPTOPnnrl_ul;
6 SETn( left + right );
7 RETURN;
8 }
9 }
Every line here (apart from the braces, of course) contains a macro. The first line sets up the function declaration as Perl expects for PP code; line 3 sets up variable declarations for the argument stack and the target, the return value of the operation. Finally, it tries to see if the addition operation is overloaded; if so, the appropriate subroutine is called.
ここの各行(もちろん中かっこを除く)にはマクロが含まれています。 最初の行は、Perl が PP コードに期待する関数宣言を設定します。 3 行目は、引数スタックと操作の戻り値であるターゲットの変数宣言を設定します。 最後に、加算操作がオーバーロードされているかどうかを調べます; オーバーロードされている場合は、適切なサブルーチンが呼び出されます。
Line 5 is another variable declaration - all variable declarations start with d
- which pops from the top of the argument stack two NVs (hence nn
) and puts them into the variables right
and left
, hence the rl
. These are the two operands to the addition operator. Next, we call SETn
to set the NV of the return value to the result of adding the two values. This done, we return - the RETURN
macro makes sure that our return value is properly handled, and we pass the next operator to run back to the main run loop.
5 行目はもう一つの変数宣言です - すべての変数宣言は d
で始まります - これは引数スタックの先頭から二つの NV(つまり nn
)を取り出し、それらを 変数 right
と left
(つまり rl
)に入れます。 これらは加算演算子に対する二つのオペランドです。 次に、SETn
を呼び出して、戻り値の NV を二つの値を加算した結果に 設定します。 これが終われば、返ります - RETURN
マクロは返り値が適切に処理されていることを確認し、 メインの実行ループに戻るために次の演算子を渡します。
Most of these macros are explained in perlapi, and some of the more important ones are explained in perlxs as well. Pay special attention to "Background and PERL_IMPLICIT_CONTEXT" in perlguts for information on the [pad]THX_?
macros.
これらのマクロのほとんどは perlapi で説明されていますし、 より重要なマクロのいくつかは perlxs でも説明されています。 [pad]THX_?
マクロに関する情報については、 "Background and PERL_IMPLICIT_CONTEXT" in perlguts に特に注意してください。
FURTHER READING¶
For more information on the Perl internals, please see the documents listed at "Internals and C Language Interface" in perl.
Perl の内部に関するさらなる情報については、 "Internals and C Language Interface" in perl に挙げられている文書を 見てください。