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

📄 perlhack.1

📁 视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.
💻 1
📖 第 1 页 / 共 5 页
字号:
\&    4   PV = 0xa0484e0 "hello"\e0\&    5   CUR = 5\&    6   LEN = 6.Ve.PPReading \f(CW\*(C`Devel::Peek\*(C'\fR output takes a bit of practise, so let's gothrough it line by line..PPLine 1 tells us we're looking at an \s-1SV\s0 which lives at \f(CW0xa04ecbc\fR inmemory. SVs themselves are very simple structures, but they contain apointer to a more complex structure. In this case, it's a \s-1PV\s0, astructure which holds a string value, at location \f(CW0xa041450\fR.  Line 2is the reference count; there are no other references to this data, soit's 1..PPLine 3 are the flags for this \s-1SV\s0 \- it's \s-1OK\s0 to use it as a \s-1PV\s0, it's aread-only \s-1SV\s0 (because it's a constant) and the data is a \s-1PV\s0 internally.Next we've got the contents of the string, starting at location\&\f(CW0xa0484e0\fR..PPLine 5 gives us the current length of the string \- note that this does\&\fBnot\fR 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 \f(CW\*(C`SvGROW\*(C'\fR..PPYou can get at any of these quantities from C very easily; just add\&\f(CW\*(C`Sv\*(C'\fR to the name of the field shown in the snippet, and you've got amacro which will return the value: \f(CW\*(C`SvCUR(sv)\*(C'\fR returns the currentlength of the string, \f(CW\*(C`SvREFCOUNT(sv)\*(C'\fR returns the reference count,\&\f(CW\*(C`SvPV(sv, len)\*(C'\fR returns the string itself with its length, and so on.More macros to manipulate these properties can be found in perlguts..PPLet's take an example of manipulating a \s-1PV\s0, from \f(CW\*(C`sv_catpvn\*(C'\fR, in \fIsv.c\fR.PP.Vb 5\&     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) = \*(Aq\e0\*(Aq;\&    13      (void)SvPOK_only_UTF8(sv);          /* validate pointer */\&    14      SvTAINT(sv);\&    15  }.Ve.PPThis is a function which adds a string, \f(CW\*(C`ptr\*(C'\fR, of length \f(CW\*(C`len\*(C'\fR ontothe end of the \s-1PV\s0 stored in \f(CW\*(C`sv\*(C'\fR. The first thing we do in line 6 ismake sure that the \s-1SV\s0 \fBhas\fR a valid \s-1PV\s0, by calling the \f(CW\*(C`SvPV_force\*(C'\fRmacro to force a \s-1PV\s0. As a side effect, \f(CW\*(C`tlen\*(C'\fR gets set to the currentvalue of the \s-1PV\s0, and the \s-1PV\s0 itself is returned to \f(CW\*(C`junk\*(C'\fR..PPIn line 7, we make sure that the \s-1SV\s0 will have enough room to accommodatethe old string, the new string and the null terminator. If \f(CW\*(C`LEN\*(C'\fR isn'tbig enough, \f(CW\*(C`SvGROW\*(C'\fR will reallocate space for us..PPNow, if \f(CW\*(C`junk\*(C'\fR is the same as the string we're trying to add, we cangrab the string directly from the \s-1SV\s0; \f(CW\*(C`SvPVX\*(C'\fR is the address of the \s-1PV\s0in the \s-1SV\s0..PPLine 10 does the actual catenation: the \f(CW\*(C`Move\*(C'\fR macro moves a chunk ofmemory around: we move the string \f(CW\*(C`ptr\*(C'\fR to the end of the \s-1PV\s0 \- that'sthe start of the \s-1PV\s0 plus its current length. We're moving \f(CW\*(C`len\*(C'\fR bytesof type \f(CW\*(C`char\*(C'\fR. After doing so, we need to tell Perl we've extended thestring, by altering \f(CW\*(C`CUR\*(C'\fR to reflect the new length. \f(CW\*(C`SvEND\*(C'\fR is amacro which gives us the end of the string, so that needs to be a\&\f(CW"\e0"\fR..PPLine 13 manipulates the flags; since we've changed the \s-1PV\s0, any \s-1IV\s0 or \s-1NV\s0values will no longer be valid: if we have \f(CW\*(C`$a=10; $a.="6";\*(C'\fR we don'twant to use the old \s-1IV\s0 of 10. \f(CW\*(C`SvPOK_only_utf8\*(C'\fR is a special UTF\-8\-awareversion of \f(CW\*(C`SvPOK_only\*(C'\fR, a macro which turns off the \s-1IOK\s0 and \s-1NOK\s0 flagsand turns on \s-1POK\s0. The final \f(CW\*(C`SvTAINT\*(C'\fR is a macro which launders tainteddata if taint mode is turned on..PPAVs 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..Sh "Op Trees".IX Subsection "Op Trees"First, 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\*(R"..PPAn 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..PPThe op tree is connected in two ways: you can imagine that there are two\&\*(L"routes\*(R" 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..PPThe 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 B::Terse, B::Conciseand B::Debug do..PPLet's have a look at how Perl sees \f(CW\*(C`$a = $b + $c\*(C'\fR:.PP.Vb 12\&     % perl \-MO=Terse \-e \*(Aq$a=$b+$c\*(Aq\&     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.Ve.PPLet's start in the middle, at line 4. This is a \s-1BINOP\s0, a binaryoperator, which is at location \f(CW0x8179828\fR. The specific operator inquestion is \f(CW\*(C`sassign\*(C'\fR \- scalar assignment \- and you can find the codewhich implements it in the function \f(CW\*(C`pp_sassign\*(C'\fR in \fIpp_hot.c\fR. As abinary operator, it has two children: the add operator, providing theresult of \f(CW\*(C`$b+$c\*(C'\fR, is uppermost on line 5, and the left hand side is online 10..PPLine 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\*(R",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:.PP.Vb 2\&    10          SVOP (0x816b4f0) rv2sv [15]\&    11              SVOP (0x816dcf0) gv  GV (0x80fa460) *a.Ve.PPThat is, fetch the \f(CW\*(C`a\*(C'\fR entry from the main symbol table, and then lookat the scalar component of it: \f(CW\*(C`gvsv\*(C'\fR (\f(CW\*(C`pp_gvsv\*(C'\fR into \fIpp_hot.c\fR)happens to do both these things..PPThe right hand side, starting at line 5 is similar to what we've justseen: we have the \f(CW\*(C`add\*(C'\fR op (\f(CW\*(C`pp_add\*(C'\fR also in \fIpp_hot.c\fR) add togethertwo \f(CW\*(C`gvsv\*(C'\fRs..PPNow, what's this about?.PP.Vb 3\&     1  LISTOP (0x8179888) leave\&     2      OP (0x81798b0) enter\&     3      COP (0x8179850) nextstate.Ve.PP\&\f(CW\*(C`enter\*(C'\fR and \f(CW\*(C`leave\*(C'\fR 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: \f(CW\*(C`leave\*(C'\fR is a list, and itschildren are all the statements in the block. Statements are delimitedby \f(CW\*(C`nextstate\*(C'\fR, so a block is a collection of \f(CW\*(C`nextstate\*(C'\fR ops, withthe ops to be performed for each statement being the children of\&\f(CW\*(C`nextstate\*(C'\fR. \f(CW\*(C`enter\*(C'\fR is a single op which functions as a marker..PPThat's how Perl parsed the program, from top to bottom:.PP.Vb 10\&                        Program\&                           |\&                       Statement\&                           |\&                           =\&                          / \e\&                         /   \e\&                        $a   +\&                            / \e\&                          $b   $c.Ve.PPHowever, it's impossible to \fBperform\fR the operations in this order:you have to find the values of \f(CW$b\fR and \f(CW$c\fR before you add themtogether, for instance. So, the other thread that runs through the optree is the execution order: each op has a field \f(CW\*(C`op_next\*(C'\fR 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 \f(CW\*(C`exec\*(C'\fR option to \f(CW\*(C`B::Terse\*(C'\fR:.PP.Vb 9\&     % perl \-MO=Terse,exec \-e \*(Aq$a=$b+$c\*(Aq\&     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.Ve.PPThis probably makes more sense for a human: enter a block, start astatement. Get the values of \f(CW$b\fR and \f(CW$c\fR, and add them together.Find \f(CW$a\fR, and assign one to the other. Then leave..PPThe way Perl builds up these op trees in the parsing process can beunravelled by examining \fIperly.y\fR, the \s-1YACC\s0 grammar. Let's take thepiece we need to construct the tree for \f(CW\*(C`$a = $b + $c\*(C'\fR.PP.Vb 4\&    1 term    :   term ASSIGNOP term\&    2                { $$ = newASSIGNOP(OPf_STACKED, $1, $2, $3); }\&    3         |   term ADDOP term\&    4                { $$ = newBINOP($2, 0, scalar($1), scalar($3)); }.Ve.PPIf you're not used to reading \s-1BNF\s0 grammars, this is how it works: You'refed certain things by the tokeniser, which generally end up in uppercase. Here, \f(CW\*(C`ADDOP\*(C'\fR, is provided when the tokeniser sees \f(CW\*(C`+\*(C'\fR in yourcode. \f(CW\*(C`ASSIGNOP\*(C'\fR is provided when \f(CW\*(C`=\*(C'\fR is used for assigning. These are\&\*(L"terminal symbols\*(R", because you can't get any simpler than them..PPThe grammar, lines one and three of the snippet above, tells you how tobuild up more complex forms. These complex forms, \*(L"non-terminal symbols\*(R"are generally placed in lower case. \f(CW\*(C`term\*(C'\fR here is a non-terminalsymbol, representing a single expression..PPThe 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 \*(L"reduction\*(R", and the aim of parsing is to completelyreduce the input. There are several different ways you can perform areduction, separated by vertical bars: so, \f(CW\*(C`term\*(C'\fR followed by \f(CW\*(C`=\*(C'\fRfollowed by \f(CW\*(C`term\*(C'\fR makes a \f(CW\*(C`term\*(C'\fR, and \f(CW\*(C`term\*(C'\fR followed by \f(CW\*(C`+\*(C'\fRfollowed by \f(CW\*(C`term\*(C'\fR can also make a \f(CW\*(C`term\*(C'\fR..PPSo, if you see two terms with an \f(CW\*(C`=\*(C'\fR or \f(CW\*(C`+\*(C'\fR, 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 \f(CW\*(C`=\*(C'\fR, you'll do the codein line 2. If you see \f(CW\*(C`+\*(C'\fR, you'll do the code in line 4. It's this codewhich contributes to the op tree..PP.Vb 2\&            |   term ADDOP term\&            { $$ = newBINOP($2, 0, scalar($1), scalar($3)); }.Ve.PPWhat this does is creates a new binary op, and feeds it a number ofvariables. The variables refer to the tokens: \f(CW$1\fR is the first token inthe input, \f(CW$2\fR the second, and so on \- think regular expressionbackreferences. \f(CW$$\fR is the op returned from this reduction. So, wecall \f(CW\*(C`newBINOP\*(C'\fR to create a new binary operator. The first parameter to\&\f(CW\*(C`newBINOP\*(C'\fR, a function in \fIop.c\fR, is the op type. It's an additionoperator, so we want the type to be \f(CW\*(C`ADDOP\*(C'\fR. We could specify thisdirectly, but it's right there as the second token in the input, so weuse \f(CW$2\fR. The second parameter is the op's flags: 0 means \*(L"nothingspecial\*(R". Then the things to add: the left and right hand side of ourexpression, in scalar context..Sh "Stacks".IX Subsection "Stacks"When perl executes something like \f(CW\*(C`addop\*(C'\fR, 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..IP "Argument stack" 3.IX Item "Argument stack"Arguments are passed to \s-1PP\s0 code and returned from \s-1PP\s0 code using theargument stack, \f(CW\*(C`ST\*(C'\fR. The typical way to handle arguments is to popthem off the stack, deal with them how you wish, and then push the resultback onto the stack. This is how, for instance, the cosine operatorworks:.Sp.Vb 4\&      NV value;\&      value = POPn;\&      value = Perl_cos(value);\&      XPUSHn(value);.Ve.SpWe'll see a more tricky example of this when we consider Perl's macrosbelow. \f(CW\*(C`POPn\*(C'\fR gives you the \s-1NV\s0 (floating point value) of the top \s-1SV\s0 onthe stack: the \f(CW$x\fR in \f(CW\*(C`cos($x)\*(C'\fR. Then we compute the cosine, and pushthe result back as an \s-1NV\s0. The \f(CW\*(C`X\*(C'\fR in \f(CW\*(C`XPUSHn\*(C'\fR means that the stackshould be extended if necessary \- it can't be necessary here, because weknow there's room for one

⌨️ 快捷键说明

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