recdescent.pod
来自「视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.」· POD 代码 · 共 1,783 行 · 第 1/5 页
POD
1,783 行
Note in the preceding example, that the C<E<lt>commitE<gt>> was only placedin production two. If production one had been: request: 'explain' <commit> expression then production two would be (inappropriately) skipped if a leading"explain..." was encountered.Both C<E<lt>commitE<gt>> and C<E<lt>uncommitE<gt>> directives always succeed, and their valueis always 1.=item Rejecting a productionThe C<E<lt>rejectE<gt>> directive immediately causes the current productionto fail (it is exactly equivalent to, but more obvious than, theaction C<{undef}>). A C<E<lt>rejectE<gt>> is useful when it is desirable to getthe side effects of the actions in one production, without prejudicing a matchby some other production later in the rule. For example, to inserttracing code into the parse: complex_rule: { print "In complex rule...\n"; } <reject> complex_rule: simple_rule '+' 'i' '*' simple_rule | 'i' '*' simple_rule | simple_ruleIt is also possible to specify a conditional rejection, using theform C<E<lt>reject:I<condition>E<gt>>, which only rejects if thespecified condition is true. This form of rejection is exactlyequivalent to the action C<{(I<condition>)?undef:1}E<gt>>.For example: command: save_command | restore_command | <reject: defined $::tolerant> { exit } | <error: Unknown command. Ignored.>A C<E<lt>rejectE<gt>> directive never succeeds (and hence has noassociated value). A conditional rejection may succeed (if itscondition is not satisfied), in which case its value is 1.As an extra optimization, C<Parse::RecDescent> ignores any productionwhich I<begins> with an unconditional C<E<lt>rejectE<gt>> directive,since any such production can never successfully match or have anyuseful side-effects. A level 1 warning is issued in all such cases.Note that productions beginning with conditionalC<E<lt>reject:...E<gt>> directives are I<never> "optimized away" inthis manner, even if they are always guaranteed to fail (for example:C<E<lt>reject:1E<gt>>)Due to the way grammars are parsed, there is a minor restriction on thecondition of a conditional C<E<lt>reject:...E<gt>>: it cannotcontain any raw '<' or '>' characters. For example: line: cmd <reject: $thiscolumn > max> dataresults in an error when a parser is built from this grammar (since thegrammar parser has no way of knowing whether the first > is a "less than"or the end of the C<E<lt>reject:...E<gt>>.To overcome this problem, put the condition inside a do{} block: line: cmd <reject: do{$thiscolumn > max}> dataNote that the same problem may occur in other directives that takearguments. The same solution will work in all cases.=item Skipping between terminalsThe C<E<lt>skipE<gt>> directive enables the terminal prefix used ina production to be changed. For example: OneLiner: Command <skip:'[ \t]*'> Arg(s) /;/causes only blanks and tabs to be skipped before terminals in the C<Arg>subrule (and any of I<its> subrules>, and also before the final C</;/> terminal.Once the production is complete, the previous terminal prefix isreinstated. Note that this implies that distinct productions of a rulemust reset their terminal prefixes individually.The C<E<lt>skipE<gt>> directive evaluates to the I<previous> terminal prefix,so it's easy to reinstate a prefix later in a production: Command: <skip:","> CSV(s) <skip:$item[1]> ModifierThe value specified after the colon is interpolated into a pattern, so all ofthe following are equivalent (though their efficiency increases down the list): <skip: "$colon|$comma"> # ASSUMING THE VARS HOLD THE OBVIOUS VALUES <skip: ':|,'> <skip: q{[:,]}> <skip: qr/[:,]/>There is no way of directly setting the prefix foran entire rule, except as follows: Rule: <skip: '[ \t]*'> Prod1 | <skip: '[ \t]*'> Prod2a Prod2b | <skip: '[ \t]*'> Prod3or, better: Rule: <skip: '[ \t]*'> ( Prod1 | Prod2a Prod2b | Prod3 )B<Note: Up to release 1.51 of Parse::RecDescent, an entirely differentmechanism was used for specifying terminal prefixes. The current methodis not backwards-compatible with that early approach. The current approachis stable and will not to change again.>=item ResynchronizationThe C<E<lt>resyncE<gt>> directive provides a visually distinctivemeans of consuming some of the text being parsed, usually to skip anerroneous input. In its simplest form C<E<lt>resyncE<gt>> simplyconsumes text up to and including the next newline (C<"\n">)character, succeeding only if the newline is found, in which case itcauses its surrounding rule to return zero on success.In other words, a C<E<lt>resyncE<gt>> is exactly equivalent to the tokenC</[^\n]*\n/> followed by the action S<C<{ $return = 0 }>> (except thatproductions beginning with a C<E<lt>resyncE<gt>> are ignored when generatingerror messages). A typical use might be: script : command(s) command: save_command | restore_command | <resync> # TRY NEXT LINE, IF POSSIBLEIt is also possible to explicitly specify a resynchronizationpattern, using the C<E<lt>resync:I<pattern>E<gt>> variant. This versionsucceeds only if the specified pattern matches (and consumes) theparsed text. In other words, C<E<lt>resync:I<pattern>E<gt>> is exactlyequivalent to the token C</I<pattern>/> (followed by a S<C<{ $return = 0 }>>action). For example, if commands were terminated by newlines or semi-colons: command: save_command | restore_command | <resync:[^;\n]*[;\n]>The value of a successfully matched C<E<lt>resyncE<gt>> directive (of eithertype) is the text that it consumed. Note, however, that since thedirective also sets C<$return>, a production consisting of a loneC<E<lt>resyncE<gt>> succeeds but returns the value zero (which a calling rulemay find useful to distinguish between "true" matches and "tolerant" matches).Remember that returning a zero value indicates that the rule I<succeeded> (sinceonly an C<undef> denotes failure within C<Parse::RecDescent> parsers.=item Error handlingThe C<E<lt>errorE<gt>> directive provides automatic or user-definedgeneration of error messages during a parse. In its simplest formC<E<lt>errorE<gt>> prepares an error message based onthe mismatch between the last item expected and the text which causeit to fail. For example, given the rule: McCoy: curse ',' name ', I'm a doctor, not a' a_profession '!' | pronoun 'dead,' name '!' | <error>the following strings would produce the following messages:=over 4=item "Amen, Jim!" ERROR (line 1): Invalid McCoy: Expected curse or pronoun not found=item "Dammit, Jim, I'm a doctor!" ERROR (line 1): Invalid McCoy: Expected ", I'm a doctor, not a" but found ", I'm a doctor!" instead=item "He's dead,\n" ERROR (line 2): Invalid McCoy: Expected name not found=item "He's alive!" ERROR (line 1): Invalid McCoy: Expected 'dead,' but found "alive!" instead=item "Dammit, Jim, I'm a doctor, not a pointy-eared Vulcan!" ERROR (line 1): Invalid McCoy: Expected a profession but found "pointy-eared Vulcan!" instead=backNote that, when autogenerating error messages, all underscores in anyrule name used in a message are replaced by single spaces (for example"a_production" becomes "a production"). Judicious choice of rulenames can therefore considerably improve the readability of automaticerror messages (as well as the maintainability of the originalgrammar).If the automatically generated error is not sufficient, it is possible toprovide an explicit message as part of the error directive. For example: Spock: "Fascinating ',' (name | 'Captain') '.' | "Highly illogical, doctor." | <error: He never said that!>which would result in I<all> failures to parse a "Spock" subrule printing thefollowing message: ERROR (line <N>): Invalid Spock: He never said that!The error message is treated as a "qq{...}" string and interpolatedwhen the error is generated (I<not> when the directive is specified!).Hence: <error: Mystical error near "$text">would correctly insert the ambient text string which caused the error.There are two other forms of error directive: C<E<lt>error?E<gt>> andS<C<E<lt>error?: msgE<gt>>>. These behave just like C<E<lt>errorE<gt>>and S<C<E<lt>error: msgE<gt>>> respectively, except that they areonly triggered if the rule is "committed" at the time they areencountered. For example: Scotty: "Ya kenna change the Laws of Phusics," <commit> name | name <commit> ',' 'she's goanta blaw!' | <error?>will only generate an error for a string beginning with "Ya kennachange the Laws o' Phusics," or a valid name, but which still fails to match thecorresponding production. That is, C<$parser-E<gt>Scotty("Aye, Cap'ain")> willfail silently (since neither production will "commit" the rule on thatinput), whereas S<C<$parser-E<gt>Scotty("Mr Spock, ah jest kenna do'ut!")>>will fail with the error message: ERROR (line 1): Invalid Scotty: expected 'she's goanta blaw!' but found 'I jest kenna do'ut!' instead.since in that case the second production would commit after matchingthe leading name.Note that to allow this behaviour, all C<E<lt>errorE<gt>> directives which arethe first item in a production automatically uncommit the rule justlong enough to allow their production to be attempted (that is, whentheir production fails, the commitment is reinstated so thatsubsequent productions are skipped).In order to I<permanently> uncommit the rule before an error message,it is necessary to put an explicit C<E<lt>uncommitE<gt>> before theC<E<lt>errorE<gt>>. For example: line: 'Kirk:' <commit> Kirk | 'Spock:' <commit> Spock | 'McCoy:' <commit> McCoy | <uncommit> <error?> <reject> | <resync>Error messages generated by the various C<E<lt>error...E<gt>> directivesare not displayed immediately. Instead, they are "queued" in a buffer andare only displayed once parsing ultimately fails. Moreover,C<E<lt>error...E<gt>> directives that cause one production of a ruleto fail are automatically removed from the message queueif another production subsequently causes the entire rule to succeed.This means that you can put C<E<lt>error...E<gt>> directives wherever useful diagnosis can be done,and only those associated with actual parser failure will ever bedisplayed. Also see L<"Gotchas">.As a general rule, the most useful diagnostics are usually generatedeither at the very lowest level within the grammar, or at the veryhighest. A good rule of thumb is to identify those subrules whichconsist mainly (or entirely) of terminals, and then put anC<E<lt>error...E<gt>> directive at the end of any other rule which callsone or more of those subrules.There is one other situation in which the output of the various types oferror directive is suppressed; namely, when the rule containing themis being parsed as part of a "look-ahead" (see L<"Look-ahead">). In thiscase, the error directive will still cause the rule to fail, but will doso silently.An unconditional C<E<lt>errorE<gt>> directive always fails (and hence has noassociated value). This means that encountering such a directivealways causes the production containing it to fail. Hence anC<E<lt>errorE<gt>> directive will inevitably be the last (useful) item of arule (a level 3 warning is issued if a production contains items after an unconditionalC<E<lt>errorE<gt>> directive).An C<E<lt>error?E<gt>> directive will I<succeed> (that is: fail to fail :-), ifthe current rule is uncommitted when the directive is encountered. Inthat case the directive's associated value is zero. Hence, this typeof error directive I<can> be used before the end of aproduction. For example: command: 'do' <commit> something | 'report' <commit> something | <error?: Syntax error> <error: Unknown command>B<Warning:> The C<E<lt>error?E<gt>> directive does I<not> mean "always fail (butdo so silently unless committed)". It actually means "only fail (and report) ifcommitted, otherwise I<succeed>". To achieve the "fail silently if uncommitted"semantics, it is necessary to use: rule: item <commit> item(s) | <error?> <reject> # FAIL SILENTLY UNLESS COMMITTEDHowever, because people seem to expect a lone C<E<lt>error?E<gt>> directiveto work like this: rule: item <commit> item(s) | <error?: Error message if committed> | <error: Error message if uncommitted>Parse::RecDescent automatically appends a C<E<lt>rejectE<gt>> directive if the C<E<lt>error?E<gt>> directiveis the only item in a production. A level 2 warning (see below)is issued when this happens.The level of error reporting during both parser construction andparsing is controlled by the presence or absence of four globalvariables: C<$::RD_ERRORS>, C<$::RD_WARN>, C<$::RD_HINT>, and<$::RD_TRACE>. If C<$::RD_ERRORS> is defined (and, by default, it is)then fatal errors are reported.Whenever C<$::RD_WARN> is defined, certain non-fatal problems are also reported. Warnings have an associated "level": 1, 2, or 3. The higher the level,the more serious the warning. The value of the corresponding globalvariable (C<$::RD_WARN>) determines the I<lowest> level of warning tobe displayed. Hence, to see I<all> warnings, set C<$::RD_WARN> to 1.To see only the most serious warnings set C<$::RD_WARN> to 3.By default C<$::RD_WARN> is initialized to 3, ensuring that serious butnon-fatal errors are automatically reported.See F<"DIAGNOSTICS"> for a list of the varous error and warning messagesthat Parse::RecDescent generates when these two variables are defined.Defining any of the remaining variables (which are not defined bydefault) further increases the amount of information reported.Defining C<$::RD_HINT> causes the parser generator to offermore detailed analyses and hints on both errors and warnings.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?