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