Home | History | Annotate | Download | only in Perl5
      1 /*
      2  [The "BSD license"]
      3  Copyright (c) 2005-2006 Terence Parr
      4  Copyright (c) 2007-2008 Ronald Blaschke
      5  All rights reserved.
      6 
      7  Redistribution and use in source and binary forms, with or without
      8  modification, are permitted provided that the following conditions
      9  are met:
     10  1. Redistributions of source code must retain the above copyright
     11     notice, this list of conditions and the following disclaimer.
     12  2. Redistributions in binary form must reproduce the above copyright
     13     notice, this list of conditions and the following disclaimer in the
     14     documentation and/or other materials provided with the distribution.
     15  3. The name of the author may not be used to endorse or promote products
     16     derived from this software without specific prior written permission.
     17 
     18  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 */
     29 
     30 group Perl5;
     31 
     32 /** The overall file structure of a recognizer; stores methods for rules
     33  *  and cyclic DFAs plus support code.
     34  */
     35 outputFile(LEXER,PARSER,TREE_PARSER, actionScope, actions,
     36            docComment, recognizer,
     37            name, tokens, tokenNames, rules, cyclicDFAs,
     38 	   bitsets, buildTemplate, buildAST, rewriteMode, profile,
     39 	   backtracking, synpreds, memoize, numRules,
     40 	   fileName, ANTLRVersion, generatedTimestamp, trace,
     41 	   scopes, superClass, literals) ::=
     42 <<
     43 # $ANTLR <ANTLRVersion> <fileName> <generatedTimestamp>
     44 <actions.(actionScope).header>
     45 
     46 <@imports>
     47 <if(TREE_PARSER)>
     48 <endif>
     49 <if(backtracking)>
     50 <endif>
     51 <@end>
     52 
     53 <docComment>
     54 <recognizer>
     55 >>
     56 
     57 lexer(grammar, name, tokens, scopes, rules, numRules, labelType="Token",
     58       filterMode, superClass="ANTLR::Runtime::Lexer")  ::= <<
     59 package <name>;
     60 
     61 use Carp;
     62 use English qw( -no_match_vars ) ;
     63 use Readonly;
     64 use Switch;
     65 
     66 use ANTLR::Runtime::BaseRecognizer;
     67 use ANTLR::Runtime::DFA;
     68 use ANTLR::Runtime::NoViableAltException;
     69 
     70 use Moose;
     71 
     72 extends 'ANTLR::Runtime::Lexer';
     73 
     74 Readonly my $HIDDEN => ANTLR::Runtime::BaseRecognizer->HIDDEN;
     75 sub HIDDEN { $HIDDEN }
     76 
     77 use constant {
     78     <tokens:{ <it.name> => <it.type>, }; separator="\n">
     79 };
     80 <scopes:{<if(it.isDynamicGlobalScope)><globalAttributeScope(scope=it)><endif>}>
     81 <actions.lexer.members>
     82 
     83 sub BUILD {
     84     my ($self, $arg_ref) = @_;
     85 
     86     $self->init_dfas();
     87 }
     88 
     89 sub get_grammar_file_name {
     90     return "<fileName>";
     91 }
     92 
     93 <if(filterMode)>
     94 <filteringNextToken()>
     95 <endif>
     96 <rules; separator="\n\n">
     97 
     98 <synpreds:{p | <lexerSynpred(p)>}>
     99 
    100 <cyclicDFAs:{dfa | has 'dfa<dfa.decisionNumber>';}; separator="\n">
    101 
    102 sub init_dfas {
    103     my ($self) = @_;
    104 
    105     <cyclicDFAs:{dfa |
    106     $self->dfa<dfa.decisionNumber>(<name>::DFA<dfa.decisionNumber>->new({ recognizer => $self }));
    107     }; separator="\n">
    108 
    109     return;
    110 }
    111 
    112 <cyclicDFAs:cyclicDFA()> <! dump tables for all DFA !>
    113 
    114 no Moose;
    115 __PACKAGE__->meta->make_immutable();
    116 1;
    117 
    118 >>
    119 
    120 perlTypeInitMap ::= [
    121 	"$":"undef",
    122 	"@":"()",
    123 	"%":"()",
    124 	default:"undef"
    125 ]
    126 
    127 /** A override of Lexer.nextToken() that backtracks over mTokens() looking
    128  *  for matches.  No error can be generated upon error; just rewind, consume
    129  *  a token and then try again.  backtracking needs to be set as well.
    130  *  Make rule memoization happen only at levels above 1 as we start mTokens
    131  *  at backtracking==1.
    132  */
    133 filteringNextToken() ::= <<
    134 public Token nextToken() {
    135     while (true) {
    136         if ( input.LA(1)==CharStream.EOF ) {
    137             return Token.EOF_TOKEN;
    138         }
    139         token = null;
    140 	channel = Token.DEFAULT_CHANNEL;
    141         tokenStartCharIndex = input.index();
    142         tokenStartCharPositionInLine = input.getCharPositionInLine();
    143         tokenStartLine = input.getLine();
    144 	text = null;
    145         try {
    146             int m = input.mark();
    147             backtracking=1; <! means we won't throw slow exception !>
    148             failed=false;
    149             mTokens();
    150             backtracking=0;
    151             <! mTokens backtracks with synpred at backtracking==2
    152                and we set the synpredgate to allow actions at level 1. !>
    153             if ( failed ) {
    154                 input.rewind(m);
    155                 input.consume(); <! advance one char and try again !>
    156             }
    157             else {
    158                 emit();
    159                 return token;
    160             }
    161         }
    162         catch (RecognitionException re) {
    163             // shouldn't happen in backtracking mode, but...
    164             reportError(re);
    165             recover(re);
    166         }
    167     }
    168 }
    169 
    170 public void memoize(IntStream input,
    171 		int ruleIndex,
    172 		int ruleStartIndex)
    173 {
    174 if ( backtracking>1 ) super.memoize(input, ruleIndex, ruleStartIndex);
    175 }
    176 
    177 public boolean alreadyParsedRule(IntStream input, int ruleIndex) {
    178 if ( backtracking>1 ) return super.alreadyParsedRule(input, ruleIndex);
    179 return false;
    180 }
    181 >>
    182 
    183 actionGate() ::= "$self->state->backtracking==0"
    184 
    185 filteringActionGate() ::= "backtracking==1"
    186 
    187 /** How to generate a parser */
    188 genericParser(grammar, name, scopes, tokens, tokenNames, rules, numRules,
    189               bitsets, inputStreamType, superClass, filterMode,
    190               ASTLabelType="Object", labelType, members) ::= <<
    191 package <name>;
    192 
    193 use English qw( -no_match_vars ) ;
    194 use Readonly;
    195 use Switch;
    196 use Carp;
    197 use ANTLR::Runtime::BitSet;
    198 
    199 use Moose;
    200 
    201 extends '<@superClassName><superClass><@end>';
    202 
    203 Readonly my $token_names => [
    204     "\<invalid>", "\<EOR>", "\<DOWN>", "\<UP>", <tokenNames; separator=", ">
    205 ];
    206 
    207 use constant {
    208 <tokens:{ <it.name> => <it.type>, }; separator="\n">
    209 };
    210 
    211 <bitsets:bitset(name={FOLLOW_<it.name>_in_<it.inName><it.tokenIndex>},
    212                     words64=it.bits)>
    213 
    214 <scopes:{<if(it.isDynamicGlobalScope)><globalAttributeScope(scope=it)><endif>}>
    215 <@members>
    216 <! WARNING. bug in ST: this is cut-n-paste into Dbg.stg !>
    217 
    218 sub BUILD {
    219     my ($self, $arg_ref) = @_;
    220 
    221 <if(backtracking)>
    222     $self->state->rule_memo({});<\n>
    223 <endif>
    224 }
    225 <@end>
    226 
    227 sub get_token_names {
    228     return $token_names;
    229 }
    230 
    231 sub get_grammar_file_name {
    232     return "<fileName>";
    233 }
    234 
    235 <members>
    236 
    237 <rules; separator="\n\n">
    238 
    239 <synpreds:{p | <synpred(p)>}>
    240 
    241 <cyclicDFAs:{dfa | dfa<dfa.decisionNumber> = __PACKAGE__::DFA<dfa.decisionNumber>->new($self);}; separator="\n">
    242 <cyclicDFAs:cyclicDFA()> <! dump tables for all DFA !>
    243 
    244 no Moose;
    245 __PACKAGE__->meta->make_immutable();
    246 1;
    247 __END__
    248 >>
    249 
    250 parser(grammar, name, scopes, tokens, tokenNames, rules, numRules, bitsets, ASTLabelType, superClass="ANTLR::Runtime::Parser", labelType="ANTLR::Runtime::Token", members={<actions.parser.members>}) ::= <<
    251 <genericParser(inputStreamType="ANTLR::Runtime::TokenStream", ...)>
    252 >>
    253 
    254 /** How to generate a tree parser; same as parser except the input
    255  *  stream is a different type.
    256  */
    257 treeParser(grammar, name, scopes, tokens, tokenNames, globalAction, rules, numRules, bitsets, labelType={<ASTLabelType>}, ASTLabelType="Object", superClass="ANTLR::Runtime::TreeParser", members={<actions.treeparser.members>}, filterMode) ::= <<
    258 <genericParser(inputStreamType="TreeNodeStream", ...)>
    259 >>
    260 
    261 /** A simpler version of a rule template that is specific to the imaginary
    262  *  rules created for syntactic predicates.  As they never have return values
    263  *  nor parameters etc..., just give simplest possible method.  Don't do
    264  *  any of the normal memoization stuff in here either; it's a waste.
    265  *  As predicates cannot be inlined into the invoking rule, they need to
    266  *  be in a rule by themselves.
    267  */
    268 synpredRule(ruleName, ruleDescriptor, block, description, nakedBlock) ::=
    269 <<
    270 # $ANTLR start <ruleName>
    271 sub <ruleName>_fragment {
    272 # <ruleDescriptor.parameterScope:parameterScope(scope=it)>
    273 
    274 <if(trace)>
    275     $self->traceIn("<ruleName>_fragment", <ruleDescriptor.index>);
    276     eval {
    277         <block>
    278     };
    279     $self->traceOut("<ruleName>_fragment", <ruleDescriptor.index>);
    280     if ($EVAL_ERROR) {
    281         croak $EVAL_ERROR;
    282     }
    283 <else>
    284     <block>
    285 <endif>
    286 }
    287 # $ANTLR end <ruleName>
    288 >>
    289 
    290 synpred(name) ::= <<
    291 public final boolean <name>() {
    292     backtracking++;
    293     <@start()>
    294     int start = input.mark();
    295     try {
    296         <name>_fragment(); // can never throw exception
    297     } catch (RecognitionException re) {
    298         System.err.println("impossible: "+re);
    299     }
    300     boolean success = !failed;
    301     input.rewind(start);
    302     <@stop()>
    303     backtracking--;
    304     failed=false;
    305     return success;
    306 }<\n>
    307 >>
    308 
    309 lexerSynpred(name) ::= <<
    310 <synpred(name)>
    311 >>
    312 
    313 ruleMemoization(name) ::= <<
    314 <if(memoize)>
    315 if ( backtracking>0 && alreadyParsedRule(input, <ruleDescriptor.index>) ) { return <ruleReturnValue()>; }
    316 <endif>
    317 >>
    318 
    319 /** How to test for failure and return from rule */
    320 checkRuleBacktrackFailure() ::= <<
    321 <if(backtracking)>
    322 if ($self->state->failed) {
    323     return <ruleReturnValue()>;
    324 }
    325 <endif>
    326 >>
    327 
    328 /** This rule has failed, exit indicating failure during backtrack */
    329 ruleBacktrackFailure() ::= <<
    330 <if(backtracking)>if (backtracking>0) {failed=true; return <ruleReturnValue()>;}<endif>
    331 >>
    332 
    333 /** How to generate code for a rule.  This includes any return type
    334  *  data aggregates required for multiple return values.
    335  */
    336 rule(ruleName,ruleDescriptor,block,emptyRule,description,exceptions,finally,memoize) ::= <<
    337 <ruleAttributeScope(scope=ruleDescriptor.ruleScope)>
    338 <returnScope(scope=ruleDescriptor.returnScope)>
    339 
    340 # $ANTLR start <ruleName>
    341 # <fileName>:<description>
    342 sub <ruleName>() {
    343     my ($self, <ruleDescriptor.parameterScope:parameterScope(scope=it)>) = @_;
    344     <if(trace)>$self->traceIn("<ruleName>", <ruleDescriptor.index>);<endif>
    345     <ruleScopeSetUp()>
    346     <ruleDeclarations()>
    347     <ruleLabelDefs()>
    348     <ruleDescriptor.actions.init>
    349     <@preamble()>
    350     eval {
    351         <ruleMemoization(name=ruleName)>
    352         <block>
    353         <ruleCleanUp()>
    354         <(ruleDescriptor.actions.after):execAction()>
    355     };
    356 <if(exceptions)>
    357     <exceptions:{e|<catch(decl=e.decl,action=e.action)><\n>}>
    358 <else>
    359 <if(!emptyRule)>
    360 <if(actions.(actionScope).rulecatch)>
    361     <actions.(actionScope).rulecatch>
    362 <else>
    363     my $exception = $EVAL_ERROR;
    364     if (ref $exception && $exception->isa('ANTLR::Runtime::RecognitionException')) {
    365         $self->report_error($exception);
    366         $self->recover($self->input, $exception);
    367         $exception = undef;
    368     }<\n>
    369 <endif>
    370 <endif>
    371 <endif>
    372     <if(trace)>$self->traceOut("<ruleName>", <ruleDescriptor.index>);<endif>
    373     <memoize()>
    374     <ruleScopeCleanUp()>
    375     <finally>
    376     if ($exception) {
    377         croak $exception;
    378         #$exception->rethrow();
    379     }
    380     <@postamble()>
    381     return <ruleReturnValue()>;
    382 }
    383 # $ANTLR end <ruleName>
    384 >>
    385 
    386 catch(decl,action) ::= <<
    387 catch (<e.decl>) {
    388     <e.action>
    389 }
    390 >>
    391 
    392 ruleDeclarations() ::= <<
    393 <if(ruleDescriptor.hasMultipleReturnValues)>
    394 my $retval = <returnType()>->new();
    395 $retval->set_start($self->input->LT(1));<\n>
    396 <else>
    397 <ruleDescriptor.returnScope.attributes:{ a |
    398 my $<a.name> = <if(a.initValue)><a.initValue><else><initValue(a.type)><endif>;
    399 }>
    400 <endif>
    401 <if(memoize)>
    402 my $<ruleDescriptor.name>_start_index = $self->input->index();
    403 <endif>
    404 >>
    405 
    406 ruleScopeSetUp() ::= <<
    407 <ruleDescriptor.useScopes:{<it>_stack.push(new <it>_scope());}; separator="\n">
    408 <ruleDescriptor.ruleScope:{<it.name>_stack.push(new <it.name>_scope());}; separator="\n">
    409 >>
    410 
    411 ruleScopeCleanUp() ::= <<
    412 <ruleDescriptor.useScopes:{<it>_stack.pop();}; separator="\n">
    413 <ruleDescriptor.ruleScope:{<it.name>_stack.pop();}; separator="\n">
    414 >>
    415 
    416 ruleLabelDefs() ::= <<
    417 <[ruleDescriptor.tokenLabels,ruleDescriptor.tokenListLabels]
    418     :{my $<it.label.text> = undef;}; separator="\n"
    419 >
    420 <[ruleDescriptor.tokenListLabels,ruleDescriptor.ruleListLabels]
    421     :{List list_<it.label.text>=null;}; separator="\n"
    422 >
    423 <ruleDescriptor.ruleLabels:ruleLabelDef(label=it); separator="\n">
    424 <ruleDescriptor.ruleListLabels:{ll|RuleReturnScope <ll.label.text> = null;}; separator="\n">
    425 >>
    426 
    427 lexerRuleLabelDefs() ::= <<
    428 <[ruleDescriptor.tokenLabels,
    429   ruleDescriptor.tokenListLabels,
    430   ruleDescriptor.ruleLabels]
    431     :{<labelType> <it.label.text>=null;}; separator="\n"
    432 >
    433 <ruleDescriptor.charLabels:{my $<it.label.text>;}; separator="\n">
    434 <[ruleDescriptor.tokenListLabels,
    435   ruleDescriptor.ruleListLabels,
    436   ruleDescriptor.ruleListLabels]
    437     :{List list_<it.label.text>=null;}; separator="\n"
    438 >
    439 >>
    440 
    441 ruleReturnValue() ::= <<
    442 <if(!ruleDescriptor.isSynPred)>
    443 <if(ruleDescriptor.hasReturnValue)>
    444 <if(ruleDescriptor.hasSingleReturnValue)>
    445 $<ruleDescriptor.singleValueReturnName>
    446 <else>
    447 $retval
    448 <endif>
    449 <endif>
    450 <endif>
    451 >>
    452 
    453 ruleCleanUp() ::= <<
    454 <if(ruleDescriptor.hasMultipleReturnValues)>
    455 <if(!TREE_PARSER)>
    456 $retval->set_stop($self->input->LT(-1));<\n>
    457 <endif>
    458 <endif>
    459 >>
    460 
    461 memoize() ::= <<
    462 <if(memoize)>
    463 <if(backtracking)>
    464 if ( backtracking>0 ) { memoize(input, <ruleDescriptor.index>, <ruleDescriptor.name>_StartIndex); }
    465 <endif>
    466 <endif>
    467 >>
    468 
    469 /** How to generate a rule in the lexer; naked blocks are used for
    470  *  fragment rules.
    471  */
    472 lexerRule(ruleName,nakedBlock,ruleDescriptor,block,memoize) ::= <<
    473 # $ANTLR start <ruleName>
    474 sub m_<ruleName> {
    475 # <ruleDescriptor.parameterScope:parameterScope(scope=it)>
    476     my ($self) = @_;
    477     <if(trace)>traceIn("<ruleName>", <ruleDescriptor.index>);<endif>
    478     <ruleDeclarations()>
    479     eval {
    480 <if(nakedBlock)>
    481         <ruleMemoization(name=ruleName)>
    482         <lexerRuleLabelDefs()>
    483         <ruleDescriptor.actions.init>
    484         <block><\n>
    485 <else>
    486         my $_type = <ruleName>;
    487         my $_channel = $self->DEFAULT_TOKEN_CHANNEL;
    488         <ruleMemoization(name=ruleName)>
    489         <lexerRuleLabelDefs()>
    490         <ruleDescriptor.actions.init>
    491         <block>
    492         <ruleCleanUp()>
    493         $self->state->type($_type);
    494         $self->state->channel($_channel);
    495         <(ruleDescriptor.actions.after):execAction()>
    496 <endif>
    497     };
    498     <if(trace)>traceOut("<ruleName>", <ruleDescriptor.index>);<endif>
    499     <memoize()>
    500 
    501     if ($EVAL_ERROR) {
    502         croak $EVAL_ERROR;
    503     }
    504 }
    505 # $ANTLR end <ruleName>
    506 >>
    507 
    508 /** How to generate code for the implicitly-defined lexer grammar rule
    509  *  that chooses between lexer rules.
    510  */
    511 tokensRule(ruleName,nakedBlock,args,block,ruleDescriptor) ::= <<
    512 sub m_tokens {
    513     my ($self) = @_;
    514     <block><\n>
    515 }
    516 >>
    517 
    518 // S U B R U L E S
    519 
    520 /** A (...) subrule with multiple alternatives */
    521 block(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description) ::= <<
    522 # <fileName>:<description>
    523 my $alt<decisionNumber> = <maxAlt>;
    524 <decls>
    525 <@predecision()>
    526 <decision>
    527 <@postdecision()>
    528 <@prebranch()>
    529 switch ($alt<decisionNumber>) {
    530     <alts:altSwitchCase()>
    531 }
    532 <@postbranch()>
    533 >>
    534 
    535 /** A rule block with multiple alternatives */
    536 ruleBlock(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description) ::= <<
    537 # <fileName>:<description>
    538 my $alt<decisionNumber> = <maxAlt>;
    539 <decls>
    540 <@predecision()>
    541 <decision>
    542 <@postdecision()>
    543 switch ($alt<decisionNumber>) {
    544     <alts:altSwitchCase()>
    545 }
    546 >>
    547 
    548 ruleBlockSingleAlt(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,description) ::= <<
    549 # <fileName>:<description>
    550 <decls>
    551 <@prealt()>
    552 <alts>
    553 <@postalt()>
    554 >>
    555 
    556 /** A special case of a (...) subrule with a single alternative */
    557 blockSingleAlt(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,description) ::= <<
    558 # <fileName>:<description>
    559 <decls>
    560 <@prealt()>
    561 <alts>
    562 <@postalt()>
    563 >>
    564 
    565 /** A (..)+ block with 1 or more alternatives */
    566 positiveClosureBlock(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description) ::= <<
    567 # <fileName>:<description>
    568 my $cnt<decisionNumber> = 0;
    569 <decls>
    570 <@preloop()>
    571 LOOP<decisionNumber>:
    572 while (1) {
    573     my $alt<decisionNumber> = <maxAlt>;
    574     <@predecision()>
    575     <decision>
    576     <@postdecision()>
    577     switch ($alt<decisionNumber>) {
    578 	    <alts:altSwitchCase()>
    579 	    else {
    580 	        if ( $cnt<decisionNumber> >= 1 ) { last LOOP<decisionNumber> }
    581 	        <ruleBacktrackFailure()>
    582             my $eee =
    583                 ANTLR::Runtime::EarlyExitException->new(<decisionNumber>, $self->input);
    584             <@earlyExitException()>
    585             croak $eee;
    586         }
    587     }
    588     ++$cnt<decisionNumber>;
    589 }
    590 <@postloop()>
    591 >>
    592 
    593 positiveClosureBlockSingleAlt ::= positiveClosureBlock
    594 
    595 /** A (..)* block with 1 or more alternatives */
    596 closureBlock(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description) ::= <<
    597 # <fileName>:<description>
    598 <decls>
    599 <@preloop()>
    600 LOOP<decisionNumber>:
    601 while (1) {
    602     my $alt<decisionNumber> = <maxAlt>;
    603     <@predecision()>
    604     <decision>
    605     <@postdecision()>
    606     switch ($alt<decisionNumber>) {
    607 	    <alts:altSwitchCase()>
    608 	    else { last LOOP<decisionNumber> }
    609     }
    610 }
    611 <@postloop()>
    612 >>
    613 
    614 closureBlockSingleAlt ::= closureBlock
    615 
    616 /** Optional blocks (x)? are translated to (x|) by before code generation
    617  *  so we can just use the normal block template
    618  */
    619 optionalBlock ::= block
    620 
    621 optionalBlockSingleAlt ::= block
    622 
    623 /** A case in a switch that jumps to an alternative given the alternative
    624  *  number.  A DFA predicts the alternative and then a simple switch
    625  *  does the jump to the code that actually matches that alternative.
    626  */
    627 altSwitchCase() ::= <<
    628 case <i> {
    629     <@prealt()>
    630     <it>
    631 }<\n>
    632 >>
    633 
    634 /** An alternative is just a list of elements; at outermost level */
    635 alt(elements,altNum,description,autoAST,outerAlt,treeLevel,rew) ::= <<
    636 # <fileName>:<description>
    637 {
    638 <@declarations()>
    639 <elements:element()>
    640 <rew>
    641 <@cleanup()>
    642 }
    643 >>
    644 
    645 /** What to emit when there is no rewrite.  For auto build
    646  *  mode, does nothing.
    647  */
    648 noRewrite(rewriteBlockLevel, treeLevel) ::= ""
    649 
    650 // E L E M E N T S
    651 
    652 /** Dump the elements one per line */
    653 element() ::= <<
    654 <@prematch()>
    655 <it.el><\n>
    656 >>
    657 
    658 /** match a token optionally with a label in front */
    659 tokenRef(token,label,elementIndex,terminalOptions) ::= <<
    660 <if(label)>$<label> =<endif>$self->match($self->input, <token>, $FOLLOW_<token>_in_<ruleName><elementIndex>);
    661 <checkRuleBacktrackFailure()>
    662 >>
    663 
    664 /** ids+=ID */
    665 tokenRefAndListLabel(token,label,elementIndex,terminalOptions) ::= <<
    666 <tokenRef(...)>
    667 <listLabel(elem=label,...)>
    668 >>
    669 
    670 listLabel(label,elem) ::= <<
    671 if (list_<label>==null) list_<label>=new ArrayList();
    672 list_<label>.add(<elem>);<\n>
    673 >>
    674 
    675 /** match a character */
    676 charRef(char,label) ::= <<
    677 <if(label)>
    678 <label> = $self->input->LA(1);<\n>
    679 <endif>
    680 $self->match(<char>); <checkRuleBacktrackFailure()>
    681 >>
    682 
    683 /** match a character range */
    684 charRangeRef(a,b,label) ::= <<
    685 <if(label)>
    686 <label> = $self->input->LA(1);<\n>
    687 <endif>
    688 $self->match_range(<a>,<b>); <checkRuleBacktrackFailure()>
    689 >>
    690 
    691 /** For now, sets are interval tests and must be tested inline */
    692 matchSet(s,label,elementIndex,postmatchCode="") ::= <<
    693 <if(label)>
    694 <if(LEXER)>
    695 <label>= $self->input->LA(1);<\n>
    696 <else>
    697 <label>=(<labelType>)input.LT(1);<\n>
    698 <endif>
    699 <endif>
    700 if ( <s> ) {
    701     $self->input->consume();
    702     <postmatchCode>
    703 <if(!LEXER)>
    704     $self->state->error_recovery(0);
    705 <endif>
    706     <if(backtracking)>failed=false;<endif>
    707 }
    708 else {
    709     <ruleBacktrackFailure()>
    710     my $mse =
    711         ANTLR::Runtime::MismatchedSetException->new(undef, $self->input);
    712     <@mismatchedSetException()>
    713 <if(LEXER)>
    714     $self->recover($mse);
    715     $mse->throw();
    716 <else>
    717     $mse->throw();
    718     <! use following code to make it recover inline; remove throw mse;
    719     $self->recoverFromMismatchedSet($self->input, $mse, $FOLLOW_set_in_<ruleName><elementIndex>);
    720     !>
    721 <endif>
    722 }<\n>
    723 >>
    724 
    725 matchRuleBlockSet ::= matchSet
    726 
    727 matchSetAndListLabel(s,label,elementIndex,postmatchCode) ::= <<
    728 <matchSet(...)>
    729 <listLabel(elem=label,...)>
    730 >>
    731 
    732 /** Match a string literal */
    733 lexerStringRef(string,label,elementIndex) ::= <<
    734 <if(label)>
    735 int <label>Start = getCharIndex();
    736 $self->match(<string>); <checkRuleBacktrackFailure()>
    737 <labelType> <label> = new CommonToken(input, Token.INVALID_TOKEN_TYPE, Token.DEFAULT_CHANNEL, <label>Start, getCharIndex()-1);
    738 <else>
    739 $self->match(<string>); <checkRuleBacktrackFailure()><\n>
    740 <endif>
    741 >>
    742 
    743 wildcard(label,elementIndex) ::= <<
    744 <if(label)>
    745 <label>=(<labelType>)input.LT(1);<\n>
    746 <endif>
    747 matchAny(input); <checkRuleBacktrackFailure()>
    748 >>
    749 
    750 wildcardAndListLabel(label,elementIndex) ::= <<
    751 <wildcard(...)>
    752 <listLabel(elem=label,...)>
    753 >>
    754 
    755 /** Match . wildcard in lexer */
    756 wildcardChar(label, elementIndex) ::= <<
    757 <if(label)>
    758 <label> = $self->input->LA(1);<\n>
    759 <endif>
    760 matchAny(); <checkRuleBacktrackFailure()>
    761 >>
    762 
    763 wildcardCharListLabel(label, elementIndex) ::= <<
    764 <wildcardChar(...)>
    765 <listLabel(elem=label,...)>
    766 >>
    767 
    768 /** Match a rule reference by invoking it possibly with arguments
    769  *  and a return value or values.
    770  */
    771 ruleRef(rule,label,elementIndex,args,scope) ::= <<
    772 $self->push_follow($FOLLOW_<rule.name>_in_<ruleName><elementIndex>);
    773 <if(label)>
    774 $<label> = $self-><rule.name>(<args; separator=", ">);<\n>
    775 <else>
    776 $self-><rule.name>(<args; separator=", ">);<\n>
    777 <endif>
    778 $self->state->_fsp($self->state->_fsp - 1);
    779 <checkRuleBacktrackFailure()>
    780 >>
    781 
    782 /** ids+=r */
    783 ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
    784 <ruleRef(...)>
    785 <listLabel(elem=label,...)>
    786 >>
    787 
    788 /** A lexer rule reference.
    789  *
    790  *  The 'rule' argument was the target rule name, but now
    791  *  is type Rule, whose toString is same: the rule name.
    792  *  Now though you can access full rule descriptor stuff.
    793  */
    794 lexerRuleRef(rule,label,args,elementIndex,scope) ::= <<
    795 <if(label)>
    796 int <label>Start<elementIndex> = getCharIndex();
    797 $self->m_<rule>(<args; separator=", ">); <checkRuleBacktrackFailure()>
    798 <label> = new CommonToken(input, Token.INVALID_TOKEN_TYPE, Token.DEFAULT_CHANNEL, <label>Start<elementIndex>, getCharIndex()-1);
    799 <else>
    800 $self->m_<rule.name>(<args; separator=", ">); <checkRuleBacktrackFailure()>
    801 <endif>
    802 >>
    803 
    804 /** i+=INT in lexer */
    805 lexerRuleRefAndListLabel(rule,label,args,elementIndex,scope) ::= <<
    806 <lexerRuleRef(...)>
    807 <listLabel(elem=label,...)>
    808 >>
    809 
    810 /** EOF in the lexer */
    811 lexerMatchEOF(label,elementIndex) ::= <<
    812 <if(label)>
    813 int <label>Start<elementIndex> = getCharIndex();
    814 match(EOF); <checkRuleBacktrackFailure()>
    815 <labelType> <label> = new CommonToken(input, EOF, Token.DEFAULT_CHANNEL, <label>Start<elementIndex>, getCharIndex()-1);
    816 <else>
    817 match(EOF); <checkRuleBacktrackFailure()>
    818 <endif>
    819 >>
    820 
    821 /** match ^(root children) in tree parser */
    822 tree(root, actionsAfterRoot, children, nullableChildList,
    823      enclosingTreeLevel, treeLevel) ::= <<
    824 <root:element()>
    825 <actionsAfterRoot:element()>
    826 <if(nullableChildList)>
    827 if ( input.LA(1)==Token.DOWN ) {
    828     match(input, Token.DOWN, null); <checkRuleBacktrackFailure()>
    829     <children:element()>
    830     match(input, Token.UP, null); <checkRuleBacktrackFailure()>
    831 }
    832 <else>
    833 match(input, Token.DOWN, null); <checkRuleBacktrackFailure()>
    834 <children:element()>
    835 match(input, Token.UP, null); <checkRuleBacktrackFailure()>
    836 <endif>
    837 >>
    838 
    839 /** Every predicate is used as a validating predicate (even when it is
    840  *  also hoisted into a prediction expression).
    841  */
    842 validateSemanticPredicate(pred,description) ::= <<
    843 if ( !(<evalPredicate(...)>) ) {
    844     <ruleBacktrackFailure()>
    845     throw new FailedPredicateException(input, "<ruleName>", "<description>");
    846 }
    847 >>
    848 
    849 // F i x e d  D F A  (if-then-else)
    850 
    851 dfaState(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= <<
    852 my $LA<decisionNumber>_<stateNumber> = $self->input->LA(<k>);<\n>
    853 <edges; separator="\nels">
    854 else {
    855 <if(eotPredictsAlt)>
    856     $alt<decisionNumber> = <eotPredictsAlt>;
    857 <else>
    858     <ruleBacktrackFailure()>
    859     my $nvae =
    860         ANTLR::Runtime::NoViableAltException->new({
    861             grammar_decision_description => "<description>",
    862             decision_number => <decisionNumber>,
    863             state_number => <stateNumber>,
    864             input => $self->input,
    865         });<\n>
    866     <@noViableAltException()>
    867     croak $nvae;<\n>
    868 <endif>
    869 }
    870 >>
    871 
    872 /** Same as a normal DFA state except that we don't examine lookahead
    873  *  for the bypass alternative.  It delays error detection but this
    874  *  is faster, smaller, and more what people expect.  For (X)? people
    875  *  expect "if ( LA(1)==X ) match(X);" and that's it.
    876  */
    877 dfaOptionalBlockState(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= <<
    878 my $LA<decisionNumber>_<stateNumber> = $self->input->LA(<k>);<\n>
    879 <edges; separator="\nels">
    880 >>
    881 
    882 /** A DFA state that is actually the loopback decision of a closure
    883  *  loop.  If end-of-token (EOT) predicts any of the targets then it
    884  *  should act like a default clause (i.e., no error can be generated).
    885  *  This is used only in the lexer so that for ('a')* on the end of a rule
    886  *  anything other than 'a' predicts exiting.
    887  */
    888 dfaLoopbackState(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= <<
    889 my $LA<decisionNumber>_<stateNumber> = $self->input->LA(<k>);<\n>
    890 <edges; separator="\nels"><\n>
    891 <if(eotPredictsAlt)>
    892 <if(!edges)>
    893 $alt<decisionNumber> = <eotPredictsAlt>; <! if no edges, don't gen ELSE !>
    894 <else>
    895 else {
    896     $alt<decisionNumber> = <eotPredictsAlt>;
    897 }<\n>
    898 <endif>
    899 <endif>
    900 >>
    901 
    902 /** An accept state indicates a unique alternative has been predicted */
    903 dfaAcceptState(alt) ::= "$alt<decisionNumber> = <alt>;"
    904 
    905 /** A simple edge with an expression.  If the expression is satisfied,
    906  *  enter to the target state.  To handle gated productions, we may
    907  *  have to evaluate some predicates for this edge.
    908  */
    909 dfaEdge(labelExpr, targetState, predicates) ::= <<
    910 if ( (<labelExpr>) <if(predicates)>&& (<predicates>)<endif>) {
    911     <targetState>
    912 }
    913 >>
    914 
    915 // F i x e d  D F A  (switch case)
    916 
    917 /** A DFA state where a SWITCH may be generated.  The code generator
    918  *  decides if this is possible: CodeGenerator.canGenerateSwitch().
    919  */
    920 dfaStateSwitch(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= <<
    921 switch ( $self->input->LA(<k>) ) {
    922     <edges; separator="\n">
    923     else {
    924     <if(eotPredictsAlt)>
    925         $alt<decisionNumber> = <eotPredictsAlt>;
    926     <else>
    927         <ruleBacktrackFailure()>
    928         my $nvae =
    929             ANTLR::Runtime::NoViableAltException->new({
    930                 grammar_decision_description => "<description>",
    931                 decision_number => <decisionNumber>,
    932                 state_number => <stateNumber>,
    933                 input => $self->input,
    934             });<\n>
    935         <@noViableAltException()>
    936         croak $nvae;<\n>
    937     <endif>
    938     }
    939 }<\n>
    940 >>
    941 
    942 dfaOptionalBlockStateSwitch(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= <<
    943 switch ( $self->input->LA(<k>) ) {
    944     <edges; separator="\n">
    945 }<\n>
    946 >>
    947 
    948 dfaLoopbackStateSwitch(k, edges,eotPredictsAlt,description,stateNumber,semPredState) ::= <<
    949 switch ( $self->input->LA(<k>) ) {
    950 <edges; separator="\n"><\n>
    951 <if(eotPredictsAlt)>
    952 else { $alt<decisionNumber> = <eotPredictsAlt> }<\n>
    953 <endif>
    954 }<\n>
    955 >>
    956 
    957 dfaEdgeSwitch(labels, targetState) ::= <<
    958 case [<labels:{ <it> }; separator=", ">] { <targetState> }
    959 >>
    960 
    961 // C y c l i c  D F A
    962 
    963 /** The code to initiate execution of a cyclic DFA; this is used
    964  *  in the rule to predict an alt just like the fixed DFA case.
    965  *  The <name> attribute is inherited via the parser, lexer, ...
    966  */
    967 dfaDecision(decisionNumber,description) ::= <<
    968 $alt<decisionNumber> = $self->dfa<decisionNumber>->predict($self->input);
    969 >>
    970 
    971 /* Dump DFA tables as run-length-encoded Strings of octal values.
    972  * Can't use hex as compiler translates them before compilation.
    973  * These strings are split into multiple, concatenated strings.
    974  * Java puts them back together at compile time thankfully.
    975  * Java cannot handle large static arrays, so we're stuck with this
    976  * encode/decode approach.  See analysis and runtime DFA for
    977  * the encoding methods.
    978  */
    979 cyclicDFA(dfa) ::= <<
    980 Readonly my $DFA<dfa.decisionNumber>_eot => ANTLR::Runtime::DFA->unpack_rle([ <dfa.javaCompressedEOT; separator=", "> ]);
    981 Readonly my $DFA<dfa.decisionNumber>_eof => ANTLR::Runtime::DFA->unpack_rle([ <dfa.javaCompressedEOF; separator=", "> ]);
    982 Readonly my $DFA<dfa.decisionNumber>_min => ANTLR::Runtime::DFA->unpack_rle([ <dfa.javaCompressedMin; separator=", "> ]);
    983 Readonly my $DFA<dfa.decisionNumber>_max => ANTLR::Runtime::DFA->unpack_rle([ <dfa.javaCompressedMax; separator=", "> ]);
    984 Readonly my $DFA<dfa.decisionNumber>_accept => ANTLR::Runtime::DFA->unpack_rle([ <dfa.javaCompressedAccept; separator=", "> ]);
    985 Readonly my $DFA<dfa.decisionNumber>_special => ANTLR::Runtime::DFA->unpack_rle([ <dfa.javaCompressedSpecial; separator=", "> ]);
    986 Readonly my $DFA<dfa.decisionNumber>_transition => [ <dfa.javaCompressedTransition:{s|ANTLR::Runtime::DFA->unpack_rle([ <s; separator=", "> ])}; separator=", "> ];
    987 
    988 {
    989 package <name>::DFA<dfa.decisionNumber>;
    990 use ANTLR::Runtime::Class;
    991 
    992 use strict;
    993 use warnings;
    994 
    995 extends 'ANTLR::Runtime::DFA';
    996 
    997 sub BUILD {
    998     my $self = shift;
    999     my $param_ref = __PACKAGE__->unpack_params(@_, {
   1000         spec => [
   1001             {
   1002                 name => 'recognizer',
   1003                 isa  => 'ANTLR::Runtime::BaseRecognizer'
   1004             },
   1005         ]
   1006     });
   1007 
   1008     $self->recognizer($param_ref->{recognizer});
   1009     $self->decision_number(<dfa.decisionNumber>);
   1010     $self->eot($DFA<dfa.decisionNumber>_eot);
   1011     $self->eof($DFA<dfa.decisionNumber>_eof);
   1012     $self->min($DFA<dfa.decisionNumber>_min);
   1013     $self->max($DFA<dfa.decisionNumber>_max);
   1014     $self->accept($DFA<dfa.decisionNumber>_accept);
   1015     $self->special($DFA<dfa.decisionNumber>_special);
   1016     $self->transition($DFA<dfa.decisionNumber>_transition);
   1017 }
   1018 
   1019 sub get_description {
   1020     return "<dfa.description>";
   1021 }
   1022 
   1023 <@errorMethod()>
   1024 
   1025 <if(dfa.specialStateSTs)>
   1026 sub special_state_transition {
   1027     my ($self, $param_ref) = unpack_params(@_, {
   1028         spec => [
   1029             {
   1030                 name => 's',
   1031                 type => SCALAR,
   1032             },
   1033             {
   1034                 name => 'input',
   1035                 isa  => 'ANTLR::Runtime::IntStream',
   1036             }
   1037         ]
   1038     });
   1039     my $s = $param_ref->{s};
   1040     my $input = $param_ref->{input};
   1041 
   1042     switch ($s) {
   1043         <dfa.specialStateSTs:{state |
   1044         case <i0> \{ <! compressed special state numbers 0..n-1 !>
   1045             <state>}; separator="\n">
   1046         }
   1047     }
   1048 
   1049 <if(backtracking)>
   1050     if ($self->state->backtracking > 0) {
   1051         $self->state->failed = 1;
   1052         return -1;
   1053     }<\n>
   1054 <endif>
   1055 
   1056     my $nvae =
   1057         ANTLR::Runtime::NoViableAltException->new({
   1058             grammar_decision_description => $self->get_description(),
   1059             decision_number => <dfa.decisionNumber>,
   1060             state_number => $s,
   1061             input => $input,
   1062         });<\n>
   1063     $self->error($nvae);
   1064     $nvae->throw();
   1065     }<\n>
   1066 <endif>
   1067 }<\n>
   1068 >>
   1069 
   1070 /** A state in a cyclic DFA; it's a special state and part of a big switch on
   1071  *  state.
   1072  */
   1073 cyclicDFAState(decisionNumber,stateNumber,edges,needErrorClause,semPredState) ::= <<
   1074 my $input = $self->input;
   1075 my $LA<decisionNumber>_<stateNumber> = $input->LA(1);<\n>
   1076 <if(semPredState)> <! get next lookahead symbol to test edges, then rewind !>
   1077 my $index<decisionNumber>_<stateNumber> = $input->index();
   1078 $input->rewind();<\n>
   1079 <endif>
   1080 s = -1;
   1081 <edges; separator="\nels">
   1082 <if(semPredState)> <! return input cursor to state before we rewound !>
   1083 input.seek(index<decisionNumber>_<stateNumber>);<\n>
   1084 <endif>
   1085 if ( s>=0 ) return s;
   1086 break;
   1087 >>
   1088 
   1089 /** Just like a fixed DFA edge, test the lookahead and indicate what
   1090  *  state to jump to next if successful.
   1091  */
   1092 cyclicDFAEdge(labelExpr, targetStateNumber, edgeNumber, predicates) ::= <<
   1093 if ( (<labelExpr>) <if(predicates)>&& (<predicates>)<endif>) {s = <targetStateNumber>;}<\n>
   1094 >>
   1095 
   1096 /** An edge pointing at end-of-token; essentially matches any char;
   1097  *  always jump to the target.
   1098  */
   1099 eotDFAEdge(targetStateNumber,edgeNumber, predicates) ::= <<
   1100 s = <targetStateNumber>;<\n>
   1101 >>
   1102 
   1103 
   1104 // D F A  E X P R E S S I O N S
   1105 
   1106 andPredicates(left,right) ::= "(<left> && <right>)"
   1107 
   1108 orPredicates(operands) ::= "(<first(operands)><rest(operands):{o | ||<o>}>)"
   1109 
   1110 notPredicate(pred) ::= "!(<evalPredicate(...)>)"
   1111 
   1112 evalPredicate(pred,description) ::= "<pred>"
   1113 
   1114 evalSynPredicate(pred,description) ::= "<pred>()"
   1115 
   1116 lookaheadTest(atom,k,atomAsInt) ::= "$LA<decisionNumber>_<stateNumber> eq <atom>"
   1117 
   1118 /** Sometimes a lookahead test cannot assume that LA(k) is in a temp variable
   1119  *  somewhere.  Must ask for the lookahead directly.
   1120  */
   1121 isolatedLookaheadTest(atom,k,atomAsInt) ::= "$self->input->LA(<k>) eq <atom>"
   1122 
   1123 lookaheadRangeTest(lower,upper,k,rangeNumber,lowerAsInt,upperAsInt) ::= <<
   1124 ($LA<decisionNumber>_<stateNumber> ge <lower> && $LA<decisionNumber>_<stateNumber> le <upper>)
   1125 >>
   1126 
   1127 isolatedLookaheadRangeTest(lower,upper,k,rangeNumber,lowerAsInt,upperAsInt) ::= "($self->input->LA(<k>) ge <lower> && $self->input->LA(<k>) le <upper>)"
   1128 
   1129 setTest(ranges) ::= "<ranges; separator=\" || \">"
   1130 
   1131 // A T T R I B U T E S
   1132 
   1133 globalAttributeScope(scope) ::= <<
   1134 <if(scope.attributes)>
   1135 protected static class <scope.name>_scope {
   1136     <scope.attributes:{<it.decl>;}; separator="\n">
   1137 }
   1138 protected Stack <scope.name>_stack = new Stack();<\n>
   1139 <endif>
   1140 >>
   1141 
   1142 ruleAttributeScope(scope) ::= <<
   1143 <if(scope.attributes)>
   1144 protected static class <scope.name>_scope {
   1145     <scope.attributes:{<it.decl>;}; separator="\n">
   1146 }
   1147 protected Stack <scope.name>_stack = new Stack();<\n>
   1148 <endif>
   1149 >>
   1150 
   1151 returnType() ::= <<
   1152 <if(ruleDescriptor.hasMultipleReturnValues)>
   1153 <ruleDescriptor.name>_return
   1154 <else>
   1155 <if(ruleDescriptor.hasSingleReturnValue)>
   1156 <ruleDescriptor.singleValueReturnType>
   1157 <else>
   1158 void
   1159 <endif>
   1160 <endif>
   1161 >>
   1162 
   1163 /** Generate the Java type associated with a single or multiple return
   1164  *  values.
   1165  */
   1166 ruleLabelType(referencedRule) ::= <<
   1167 <if(referencedRule.hasMultipleReturnValues)>
   1168 <referencedRule.name>_return
   1169 <else>
   1170 <if(referencedRule.hasSingleReturnValue)>
   1171 <referencedRule.singleValueReturnType>
   1172 <else>
   1173 void
   1174 <endif>
   1175 <endif>
   1176 >>
   1177 
   1178 /** Using a type to init value map, try to init a type; if not in table
   1179  *  must be an object, default value is "undef".
   1180  */
   1181 initValue(typeName) ::= <<
   1182 <if(typeName)>
   1183 <perlTypeInitMap.(typeName)>
   1184 <else>
   1185 undef
   1186 <endif>
   1187 >>
   1188 
   1189 /** Define a rule label including default value */
   1190 ruleLabelDef(label) ::= <<
   1191 my $<label.label.text> = <initValue(typeName=ruleLabelType(referencedRule=label.referencedRule))>;<\n>
   1192 >>
   1193 
   1194 /** Define a return struct for a rule if the code needs to access its
   1195  *  start/stop tokens, tree stuff, attributes, ...  Leave a hole for
   1196  *  subgroups to stick in members.
   1197  */
   1198 returnScope(scope) ::= <<
   1199 <if(ruleDescriptor.hasMultipleReturnValues)>
   1200 {
   1201     package <returnType()>;
   1202     use ANTLR::Runtime::Class;
   1203 
   1204     extends 'ANTLR::Runtime::<if(TREE_PARSER)>Tree<else>Parser<endif>RuleReturnScope';
   1205 
   1206     <scope.attributes:{public <it.decl>;}; separator="\n">
   1207     <@ruleReturnMembers()>
   1208 }
   1209 <endif>
   1210 >>
   1211 
   1212 parameterScope(scope) ::= <<
   1213 <scope.attributes:{$<it.name>}; separator=", ">
   1214 >>
   1215 
   1216 parameterAttributeRef(attr) ::= "$<attr.name>"
   1217 parameterSetAttributeRef(attr,expr) ::= "$<attr.name> =<expr>;"
   1218 
   1219 scopeAttributeRef(scope,attr,index,negIndex) ::= <<
   1220 <if(negIndex)>
   1221 ((<scope>_scope)<scope>_stack.elementAt(<scope>_stack.size()-<negIndex>-1)).<attr.name>
   1222 <else>
   1223 <if(index)>
   1224 ((<scope>_scope)<scope>_stack.elementAt(<index>)).<attr.name>
   1225 <else>
   1226 ((<scope>_scope)<scope>_stack.peek()).<attr.name>
   1227 <endif>
   1228 <endif>
   1229 >>
   1230 
   1231 scopeSetAttributeRef(scope,attr,expr,index,negIndex) ::= <<
   1232 <if(negIndex)>
   1233 ((<scope>_scope)<scope>_stack.elementAt(<scope>_stack.size()-<negIndex>-1)).<attr.name> =<expr>;
   1234 <else>
   1235 <if(index)>
   1236 ((<scope>_scope)<scope>_stack.elementAt(<index>)).<attr.name> =<expr>;
   1237 <else>
   1238 ((<scope>_scope)<scope>_stack.peek()).<attr.name> =<expr>;
   1239 <endif>
   1240 <endif>
   1241 >>
   1242 
   1243 /** $x is either global scope or x is rule with dynamic scope; refers
   1244  *  to stack itself not top of stack.  This is useful for predicates
   1245  *  like {$function.size()>0 && $function::name.equals("foo")}?
   1246  */
   1247 isolatedDynamicScopeRef(scope) ::= "<scope>_stack"
   1248 
   1249 /** reference an attribute of rule; might only have single return value */
   1250 ruleLabelRef(referencedRule,scope,attr) ::= <<
   1251 <if(referencedRule.hasMultipleReturnValues)>
   1252 $<scope>.<attr.name>
   1253 <else>
   1254 $<scope>
   1255 <endif>
   1256 >>
   1257 
   1258 returnAttributeRef(ruleDescriptor,attr) ::= <<
   1259 <if(ruleDescriptor.hasMultipleReturnValues)>
   1260 retval.<attr.name>
   1261 <else>
   1262 $<attr.name>
   1263 <endif>
   1264 >>
   1265 
   1266 returnSetAttributeRef(ruleDescriptor,attr,expr) ::= <<
   1267 <if(ruleDescriptor.hasMultipleReturnValues)>
   1268 retval.<attr.name> =<expr>;
   1269 <else>
   1270 $<attr.name> =<expr>;
   1271 <endif>
   1272 >>
   1273 
   1274 /** How to translate $tokenLabel */
   1275 tokenLabelRef(label) ::= "$<label>"
   1276 
   1277 /** ids+=ID {$ids} or e+=expr {$e} */
   1278 listLabelRef(label) ::= "list_<label>"
   1279 
   1280 
   1281 // not sure the next are the right approach
   1282 
   1283 tokenLabelPropertyRef_text(scope,attr) ::= "$<scope>->get_text()"
   1284 tokenLabelPropertyRef_type(scope,attr) ::= "<scope>.getType()"
   1285 tokenLabelPropertyRef_line(scope,attr) ::= "<scope>.getLine()"
   1286 tokenLabelPropertyRef_pos(scope,attr) ::= "<scope>.getCharPositionInLine()"
   1287 tokenLabelPropertyRef_channel(scope,attr) ::= "<scope>.getChannel()"
   1288 tokenLabelPropertyRef_index(scope,attr) ::= "<scope>.getTokenIndex()"
   1289 tokenLabelPropertyRef_tree(scope,attr) ::= "<scope>_tree"
   1290 
   1291 ruleLabelPropertyRef_start(scope,attr) ::= "((<labelType>)<scope>.start)"
   1292 ruleLabelPropertyRef_stop(scope,attr) ::= "((<labelType>)<scope>.stop)"
   1293 ruleLabelPropertyRef_tree(scope,attr) ::= "((<ASTLabelType>)<scope>.tree)"
   1294 ruleLabelPropertyRef_text(scope,attr) ::= <<
   1295 <if(TREE_PARSER)>
   1296 input.getTokenStream().toString(
   1297   input.getTreeAdaptor().getTokenStartIndex(<scope>.start),
   1298   input.getTreeAdaptor().getTokenStopIndex(<scope>.start))
   1299 <else>
   1300 substr($self->input, $<scope>->start, $<scope>->stop)
   1301 <endif>
   1302 >>
   1303 
   1304 ruleLabelPropertyRef_st(scope,attr) ::= "<scope>.st"
   1305 
   1306 /** Isolated $RULE ref ok in lexer as it's a Token */
   1307 lexerRuleLabel(label) ::= "$<label>"
   1308 
   1309 lexerRuleLabelPropertyRef_type(scope,attr) ::= "<scope>.getType()"
   1310 lexerRuleLabelPropertyRef_line(scope,attr) ::= "<scope>.getLine()"
   1311 lexerRuleLabelPropertyRef_pos(scope,attr) ::= "<scope>.getCharPositionInLine()"
   1312 lexerRuleLabelPropertyRef_channel(scope,attr) ::= "<scope>.getChannel()"
   1313 lexerRuleLabelPropertyRef_index(scope,attr) ::= "<scope>.getTokenIndex()"
   1314 lexerRuleLabelPropertyRef_text(scope,attr) ::= "<scope>.getText()"
   1315 
   1316 // Somebody may ref $template or $tree or $stop within a rule:
   1317 rulePropertyRef_start(scope,attr) ::= "((<labelType>)retval.start)"
   1318 rulePropertyRef_stop(scope,attr) ::= "((<labelType>)retval.stop)"
   1319 rulePropertyRef_tree(scope,attr) ::= "((<ASTLabelType>)retval.tree)"
   1320 rulePropertyRef_text(scope,attr) ::= <<
   1321 <if(TREE_PARSER)>
   1322 input.getTokenStream().toString(
   1323   input.getTreeAdaptor().getTokenStartIndex(retval.start),
   1324   input.getTreeAdaptor().getTokenStopIndex(retval.start))
   1325 <else>
   1326 input.toString(retval.start,input.LT(-1))
   1327 <endif>
   1328 >>
   1329 rulePropertyRef_st(scope,attr) ::= "retval.st"
   1330 
   1331 lexerRulePropertyRef_text(scope,attr) ::= "getText()"
   1332 lexerRulePropertyRef_type(scope,attr) ::= "$_type"
   1333 lexerRulePropertyRef_line(scope,attr) ::= "tokenStartLine"
   1334 lexerRulePropertyRef_pos(scope,attr) ::= "tokenStartCharPositionInLine"
   1335 lexerRulePropertyRef_index(scope,attr) ::= "-1" // undefined token index in lexer
   1336 lexerRulePropertyRef_channel(scope,attr) ::= "$_channel"
   1337 lexerRulePropertyRef_start(scope,attr) ::= "tokenStartCharIndex"
   1338 lexerRulePropertyRef_stop(scope,attr) ::= "(getCharIndex()-1)"
   1339 lexerRulePropertyRef_self(scope,attr) ::= "$self"
   1340 
   1341 // setting $st and $tree is allowed in local rule. everything else
   1342 // is flagged as error
   1343 ruleSetPropertyRef_tree(scope,attr,expr) ::= "retval.tree =<expr>;"
   1344 ruleSetPropertyRef_st(scope,attr,expr) ::= "retval.st =<expr>;"
   1345 
   1346 
   1347 /** How to execute an action */
   1348 execAction(action) ::= <<
   1349 <if(backtracking)>
   1350 <if(actions.(actionScope).synpredgate)>
   1351 if ( <actions.(actionScope).synpredgate> ) {
   1352   <action>
   1353 }
   1354 <else>
   1355 if ( backtracking==0 ) {
   1356   <action>
   1357 }
   1358 <endif>
   1359 <else>
   1360 <action>
   1361 <endif>
   1362 >>
   1363 
   1364 // M I S C (properties, etc...)
   1365 
   1366 bitset(name, words64) ::= <<
   1367 Readonly my $<name> => ANTLR::Runtime::BitSet->new({ words64 => [ <words64:{'<it>'};separator=", "> ] });<\n>
   1368 >>
   1369 
   1370 codeFileExtension() ::= ".pm"
   1371 
   1372 true() ::= "1"
   1373 false() ::= "0"
   1374