⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 perlhack.pod

📁 视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.
💻 POD
📖 第 1 页 / 共 5 页
字号:
the top C<docatch>. This then starts another third-level runops level,which executes the nextstate, pushmark and die ops on line 4. At the pointthat the second C<pp_die> is called, the C call stack looks exactly likethat above, even though we are no longer within an inner eval; this isbecause of the optimization mentioned earlier. However, the context stacknow looks like this, ie with the top CxEVAL popped:    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, leavingit as:    STACK 0: MAIN      CX 0: BLOCK  =>As usual, C<PL_restartop> is extracted from the C<CxEVAL>, and aC<JMPENV_JUMP(3)> done, which pops the C stack back to the 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    mainIn  this case, because the C<JMPENV> level recorded in the C<CxEVAL>differs from the current one, C<docatch> just does a C<JMPENV_JUMP(3)>and the C stack unwinds to:    perl_run    mainBecause C<PL_restartop> is non-null, C<run_body> starts a new runops loopand execution continues.=back=head2 Internal Variable TypesYou should by now have had a look at L<perlguts>, which tells you aboutPerl's internal variable types: SVs, HVs, AVs and the rest. If not, dothat now.These variables are used not only to represent Perl-space variables, butalso any constants in the code, as well as some structures completelyinternal to Perl. The symbol table, for instance, is an ordinary Perlhash. 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, andso on.The core L<Devel::Peek|Devel::Peek> module lets us examine SVs from aPerl program. Let's see, for instance, how Perl treats the constantC<"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 = 6Reading C<Devel::Peek> output takes a bit of practise, so let's gothrough it line by line.Line 1 tells us we're looking at an SV which lives at C<0xa04ecbc> inmemory. SVs themselves are very simple structures, but they contain apointer to a more complex structure. In this case, it's a PV, astructure which holds a string value, at location C<0xa041450>.  Line 2is the reference count; there are no other references to this data, soit's 1.Line 3 are the flags for this SV - it's OK to use it as a PV, it's aread-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 locationC<0xa0484e0>.Line 5 gives us the current length of the string - note that this doesB<not> include the null terminator. Line 6 is not the length of thestring, but the length of the currently allocated buffer; as the stringgrows, Perl automatically extends the available storage via a routinecalled C<SvGROW>.You can get at any of these quantities from C very easily; just addC<Sv> to the name of the field shown in the snippet, and you've got amacro which will return the value: C<SvCUR(sv)> returns the currentlength of the string, C<SvREFCOUNT(sv)> returns the reference count,C<SvPV(sv, len)> returns the string itself with its length, and so on.More macros to manipulate these properties can be found in L<perlguts>.Let's take an example of manipulating a PV, from C<sv_catpvn>, in F<sv.c>     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, C<ptr>, of length C<len> ontothe end of the PV stored in C<sv>. The first thing we do in line 6 ismake sure that the SV B<has> a valid PV, by calling the C<SvPV_force>macro to force a PV. As a side effect, C<tlen> gets set to the currentvalue of the PV, and the PV itself is returned to C<junk>.In line 7, we make sure that the SV will have enough room to accommodatethe old string, the new string and the null terminator. If C<LEN> isn'tbig enough, C<SvGROW> will reallocate space for us.Now, if C<junk> is the same as the string we're trying to add, we cangrab the string directly from the SV; C<SvPVX> is the address of the PVin the SV.Line 10 does the actual catenation: the C<Move> macro moves a chunk ofmemory around: we move the string C<ptr> to the end of the PV - that'sthe start of the PV plus its current length. We're moving C<len> bytesof type C<char>. After doing so, we need to tell Perl we've extended thestring, by altering C<CUR> to reflect the new length. C<SvEND> is amacro which gives us the end of the string, so that needs to be aC<"\0">.Line 13 manipulates the flags; since we've changed the PV, any IV or NVvalues will no longer be valid: if we have C<$a=10; $a.="6";> we don'twant to use the old IV of 10. C<SvPOK_only_utf8> is a special UTF-8-awareversion of C<SvPOK_only>, a macro which turns off the IOK and NOK flagsand turns on POK. The final C<SvTAINT> is a macro which launders tainteddata if taint mode is turned on.AVs and HVs are more complicated, but SVs are by far the most commonvariable type being thrown around. Having seen something of how wemanipulate these, let's go on and look at how the op tree isconstructed.=head2 Op TreesFirst, what is the op tree, anyway? The op tree is the parsedrepresentation of your program, as we saw in our section on parsing, andit's the sequence of operations that Perl goes through to execute yourprogram, as we saw in L</Running>.An op is a fundamental operation that Perl can perform: all the built-infunctions and operators are ops, and there are a series of ops whichdeal with concepts the interpreter needs internally - entering andleaving a block, ending a statement, fetching a variable, and so on.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, andsecondly, execution order tells perl what order to perform theoperations in.The easiest way to examine the op tree is to stop Perl after it hasfinished parsing, and get it to dump out the tree. This is exactly whatthe compiler backends L<B::Terse|B::Terse>, L<B::Concise|B::Concise>and L<B::Debug|B::Debug> do.Let's have a look at how Perl sees C<$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) *aLet's start in the middle, at line 4. This is a BINOP, a binaryoperator, which is at location C<0x8179828>. The specific operator inquestion is C<sassign> - scalar assignment - and you can find the codewhich implements it in the function C<pp_sassign> in F<pp_hot.c>. As abinary operator, it has two children: the add operator, providing theresult of C<$b+$c>, is uppermost on line 5, and the left hand side is online 10.Line 10 is the null op: this does exactly nothing. What is that doingthere? If you see the null op, it's a sign that something has beenoptimized away after parsing. As we mentioned in L</Optimization>,the optimization stage sometimes converts two operations into one, forexample when fetching a scalar variable. When this happens, instead ofrewriting the op tree and cleaning up the dangling pointers, it's easierjust to replace the redundant operation with the null op. Originally,the tree would have looked like this:    10          SVOP (0x816b4f0) rv2sv [15]    11              SVOP (0x816dcf0) gv  GV (0x80fa460) *aThat is, fetch the C<a> entry from the main symbol table, and then lookat the scalar component of it: C<gvsv> (C<pp_gvsv> into F<pp_hot.c>)happens to do both these things.The right hand side, starting at line 5 is similar to what we've justseen: we have the C<add> op (C<pp_add> also in F<pp_hot.c>) add togethertwo C<gvsv>s.Now, what's this about?     1  LISTOP (0x8179888) leave     2      OP (0x81798b0) enter     3      COP (0x8179850) nextstateC<enter> and C<leave> are scoping ops, and their job is to perform anyhousekeeping every time you enter and leave a block: lexical variablesare tidied up, unreferenced variables are destroyed, and so on. Everyprogram will have those first three lines: C<leave> is a list, and itschildren are all the statements in the block. Statements are delimitedby C<nextstate>, so a block is a collection of C<nextstate> ops, withthe ops to be performed for each statement being the children ofC<nextstate>. C<enter> is a single op which functions as a marker.That's how Perl parsed the program, from top to bottom:                        Program                           |                       Statement                           |                           =                          / \                         /   \                        $a   +                            / \                          $b   $cHowever, it's impossible to B<perform> the operations in this order:you have to find the values of C<$b> and C<$c> before you add themtogether, for instance. So, the other thread that runs through the optree is the execution order: each op has a field C<op_next> which pointsto the next op to be run, so following these pointers tells us how perlexecutes the code. We can traverse the tree in this order usingthe C<exec> option to C<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) leaveThis probably makes more sense for a human: enter a block, start astatement. Get the values of C<$b> and C<$c>, and add them together.Find C<$a>, and assign one to the other. Then leave.The way Perl builds up these op trees in the parsing process can beunravelled by examining F<perly.y>, the YACC grammar. Let's take thepiece we need to construct the tree for C<$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'refed certain things by the tokeniser, which generally end up in uppercase. Here, C<ADDOP>, is provided when the tokeniser sees C<+> in yourcode. C<ASSIGNOP> is provided when C<=> is used for assigning. These are"terminal symbols", because you can't get any simpler than them.The grammar, lines one and three of the snippet above, tells you how tobuild up more complex forms. These complex forms, "non-terminal symbols"are generally placed in lower case. C<term> here is a non-terminalsymbol, representing a single expression.The grammar gives you the following rule: you can make the thing on theleft 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 completelyreduce the input. There are several different ways you can perform areduction, separated by vertical bars: so, C<term> followed by C<=>followed by C<term> makes a C<term>, and C<term> followed by C<+>followed by C<term> can also make a C<term>.So, if you see two terms with an C<=> or C<+>, between them, you canturn them into a single expression. When you do this, you execute thecode in the block on the next line: if you see C<=>, you'll do the codein line 2. If you see C<+>, you'll do the code in line 4. It's this codewhich contributes to the op tree.            |   term ADDOP term            { $$ = newBINOP($2, 0, scalar($1), scalar($3)); }What this does is creates a new binary op, and feeds it a number ofvariables. The variables refer to the tokens: C<$1> is the first token inthe input, C<$2> the second, and so on - think regular expressionbackreferences. C<$$> is the op returned from this reduction. So, wecall C<newBINOP> to create a new binary operator. The first parameter toC<newBINOP>, a function in F<op.c>, is the op type. It's an additionoperator, so we want the type to be C<ADDOP>. We could specify thisdirectly, but it's right there as the second token in the input, so weuse C<$2>. The second parameter is the op's flags: 0 means "nothingspecial". Then the things to add: the left and right hand side of ourexpression, in scalar context.=head2 StacksWhen perl executes something like C<addop>, how does it pass on itsresults to the next op? The answer is, through the use of stacks. Perlhas a number of stacks to store things it's currently working on, andwe'll look at the three most important ones here.=over 3=item Argument stack

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -