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 */ 30 scalaTypeInitMap ::= [ 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 */ 45 outputFile(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> 57 import org.antlr.runtime._ 58 <if(TREE_PARSER)> 59 import org.antlr.runtime.tree._ 60 <endif> 61 <@end> 62 63 <docComment> 64 <recognizer> 65 >> 66 67 lexer(grammar, name, tokens, scopes, rules, numRules, filterMode, labelType="CommonToken", 68 superClass="Lexer") ::= << 69 object <grammar.recognizerName> { 70 <tokens:{it | val <it.name> = <it.type>}; separator="\n"> 71 72 <cyclicDFAs:cyclicDFA()> <! dump tables for all DFA !> 73 } 74 75 class <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 */ 121 filteringNextToken() ::= << 122 override 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 164 override def memoize(input: IntStream, 165 ruleIndex: Int, 166 ruleStartIndex: Int) = { 167 if ( state.backtracking>1 ) super.memoize(input, ruleIndex, ruleStartIndex) 168 } 169 170 override def alreadyParsedRule(input: IntStream, ruleIndex: Int):Boolean { 171 if ( state.backtracking>1 ) return super.alreadyParsedRule(input, ruleIndex) 172 return false 173 } 174 >> 175 176 actionGate() ::= "state.backtracking==0" 177 178 filteringActionGate() ::= "state.backtracking==1" 179 180 /** How to generate a parser */ 181 genericParser(grammar, name, scopes, tokens, tokenNames, rules, numRules, 182 bitsets, inputStreamType, superClass, 183 labelType, members, rewriteElementType, 184 filterMode, ASTLabelType="Object") ::= << 185 object <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 200 class <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 244 parserCtorBody() ::= << 245 <if(memoize)> 246 <if(grammar.grammarIsRoot)> 247 this.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 254 parser(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 */ 263 treeParser(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 */ 278 synpredRule(ruleName, ruleDescriptor, block, description, nakedBlock) ::= 279 << 280 // $ANTLR start <ruleName> 281 @throws(classOf[RecognitionException]) 282 def <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 299 synpred(name) ::= << 300 final 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 319 lexerSynpred(name) ::= << 320 <synpred(name)> 321 >> 322 323 ruleMemoization(name) ::= << 324 <if(memoize)> 325 if ( state.backtracking>0 && alreadyParsedRule(input, <ruleDescriptor.index>) ) { return <ruleReturnValue()> } 326 <endif> 327 >> 328 329 /** How to test for failure and return from rule */ 330 checkRuleBacktrackFailure() ::= << 331 <if(backtracking)>if (state.failed) return <ruleReturnValue()><endif> 332 >> 333 334 /** This rule has failed, exit indicating failure during backtrack */ 335 ruleBacktrackFailure() ::= << 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 */ 342 rule(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]) 349 final 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 390 catch(decl,action) ::= << 391 catch (<e.decl>) { 392 <e.action> 393 } 394 >> 395 396 ruleDeclarations() ::= << 397 <if(ruleDescriptor.hasMultipleReturnValues)> 398 val retval = new <returnType()>() 399 retval.start = input.LT(1)<\n> 400 <else> 401 <ruleDescriptor.returnScope.attributes:{ a | 402 var <a.name>: <a.type> = <if(a.initValue)><a.initValue><else><initValue(a.type)><endif> 403 }> 404 <endif> 405 <if(memoize)> 406 val <ruleDescriptor.name>_StartIndex = input.index() 407 <endif> 408 >> 409 410 ruleScopeSetUp() ::= << 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 415 ruleScopeCleanUp() ::= << 416 <ruleDescriptor.useScopes:{it | <it>_stack.pop()}; separator="\n"> 417 <ruleDescriptor.ruleScope:{it | <it.name>_stack.pop()}; separator="\n"> 418 >> 419 420 421 ruleLabelDefs() ::= << 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 433 lexerRuleLabelDefs() ::= << 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 446 ruleReturnValue() ::= << 447 <if(!ruleDescriptor.isSynPred)> 448 <if(ruleDescriptor.hasReturnValue)> 449 <if(ruleDescriptor.hasSingleReturnValue)> 450 <ruleDescriptor.singleValueReturnName> 451 <else> 452 retval 453 <endif> 454 <endif> 455 <endif> 456 >> 457 458 ruleCleanUp() ::= << 459 <if(ruleDescriptor.hasMultipleReturnValues)> 460 <if(!TREE_PARSER)> 461 retval.stop = input.LT(-1)<\n> 462 <endif> 463 <endif> 464 >> 465 466 memoize() ::= << 467 <if(memoize)> 468 <if(backtracking)> 469 if ( 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 */ 477 lexerRule(ruleName,nakedBlock,ruleDescriptor,block,memoize) ::= << 478 // $ANTLR start "<ruleName>" 479 @throws(classOf[RecognitionException]) 480 final 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 */ 515 tokensRule(ruleName,nakedBlock,args,block,ruleDescriptor) ::= << 516 @throws(classOf[RecognitionException]) 517 def mTokens(): Unit = { 518 <block><\n> 519 } 520 >> 521 522 // S U B R U L E S 523 524 /** A (...) subrule with multiple alternatives */ 525 block(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description) ::= << 526 // <fileName>:<description> 527 var alt<decisionNumber> = <maxAlt> 528 <decls> 529 <@predecision()> 530 <decision> 531 <@postdecision()> 532 <@prebranch()> 533 alt<decisionNumber> match { 534 <alts:{a | <altSwitchCase(i,a)>}> 535 case _ => 536 } 537 <@postbranch()> 538 >> 539 540 /** A rule block with multiple alternatives */ 541 ruleBlock(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description) ::= << 542 // <fileName>:<description> 543 var alt<decisionNumber> = <maxAlt> 544 <decls> 545 <@predecision()> 546 <decision> 547 <@postdecision()> 548 alt<decisionNumber> match { 549 <alts:{a | <altSwitchCase(i,a)>}> 550 case _ => 551 } 552 >> 553 554 ruleBlockSingleAlt(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 */ 563 blockSingleAlt(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 */ 572 positiveClosureBlock(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description) ::= << 573 // <fileName>:<description> 574 var cnt<decisionNumber>: Int = 0 575 <decls> 576 <@preloop()> 577 var loop<decisionNumber>_quitflag = false 578 while (!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 599 positiveClosureBlockSingleAlt ::= positiveClosureBlock 600 601 /** A (..)* block with 1 or more alternatives */ 602 closureBlock(alts,decls,decision,enclosingBlockLevel,blockLevel,decisionNumber,maxK,maxAlt,description) ::= << 603 // <fileName>:<description> 604 <decls> 605 <@preloop()> 606 var loop<decisionNumber>_quitflag = false 607 while (!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 620 closureBlockSingleAlt ::= 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 */ 625 optionalBlock ::= block 626 627 optionalBlockSingleAlt ::= 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 */ 633 altSwitchCase(altNum, alt) ::= << 634 case <altNum> => 635 <@prealt()> 636 <alt> 637 >> 638 639 /** An alternative is just a list of elements; at outermost level */ 640 alt(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 */ 653 noRewrite(rewriteBlockLevel, treeLevel) ::= "" 654 655 // E L E M E N T S 656 657 /** Dump the elements one per line */ 658 element(e) ::= << 659 <@prematch()> 660 <e.el><\n> 661 >> 662 663 /** match a token optionally with a label in front */ 664 tokenRef(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 */ 670 tokenRefAndListLabel(token,label,elementIndex,terminalOptions) ::= << 671 <tokenRef(...)> 672 <listLabel(elem=label,...)> 673 >> 674 675 listLabel(label,elem) ::= << 676 if (list_<label>==null) list_<label>=new java.util.ArrayList() 677 list_<label>.add(<elem>)<\n> 678 >> 679 680 /** match a character */ 681 charRef(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 */ 690 charRangeRef(a,b,label) ::= << 691 <if(label)> 692 <label> = input.LA(1)<\n> 693 <endif> 694 matchRange(<a>,<b>); <checkRuleBacktrackFailure()> 695 >> 696 697 /** For now, sets are interval tests and must be tested inline */ 698 matchSet(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> 706 if ( <s> ) { 707 input.consume() 708 <postmatchCode> 709 <if(!LEXER)> 710 state.errorRecovery=false<\n> 711 <endif> 712 <if(backtracking)>state.failed=false<endif> 713 } 714 else { 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 730 matchRuleBlockSet ::= matchSet 731 732 matchSetAndListLabel(s,label,elementIndex,postmatchCode) ::= << 733 <matchSet(...)> 734 <listLabel(elem=label,...)> 735 >> 736 737 /** Match a string literal */ 738 lexerStringRef(string,label,elementIndex="0") ::= << 739 <if(label)> 740 val <label>Start = getCharIndex() 741 `match`(<string>) 742 <checkRuleBacktrackFailure()> 743 val <label>StartLine<elementIndex> = getLine() 744 val <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 754 wildcard(token,label,elementIndex,terminalOptions) ::= << 755 <if(label)> 756 <label>=input.LT(1).asInstanceOf[<labelType>]<\n> 757 <endif> 758 matchAny(input) 759 <checkRuleBacktrackFailure()> 760 >> 761 762 wildcardAndListLabel(token,label,elementIndex,terminalOptions) ::= << 763 <wildcard(...)> 764 <listLabel(elem=label,...)> 765 >> 766 767 /** Match . wildcard in lexer */ 768 wildcardChar(label, elementIndex) ::= << 769 <if(label)> 770 <label> = input.LA(1)<\n> 771 <endif> 772 matchAny() 773 <checkRuleBacktrackFailure()> 774 >> 775 776 wildcardCharListLabel(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 */ 787 ruleRef(rule,label,elementIndex,args,scope) ::= << 788 pushFollow(FOLLOW_<rule.name>_in_<ruleName><elementIndex>) 789 <if(label)><label>=<endif><if(scope)><scope:delegateName()>.<endif><rule.name>(<args; separator=", ">)<\n> 790 state._fsp-=1 791 <checkRuleBacktrackFailure()> 792 >> 793 794 /** ids+=r */ 795 ruleRefAndListLabel(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 */ 806 lexerRuleRef(rule,label,args,elementIndex,scope) ::= << 807 <if(label)> 808 val <label>Start<elementIndex> = getCharIndex() 809 val <label>StartLine<elementIndex> = getLine() 810 val <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 */ 823 lexerRuleRefAndListLabel(rule,label,args,elementIndex,scope) ::= << 824 <lexerRuleRef(...)> 825 <listLabel(elem=label,...)> 826 >> 827 828 /** EOF in the lexer */ 829 lexerMatchEOF(label,elementIndex) ::= << 830 <if(label)> 831 val <label>Start<elementIndex> = getCharIndex() 832 val <label>StartLine<elementIndex> = getLine() 833 val <label>StartCharPos<elementIndex> = getCharPositionInLine() 834 `match`(EOF) 835 <checkRuleBacktrackFailure()> 836 val <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 846 recRuleDefArg() ::= "int <recRuleArg()>" 847 recRuleArg() ::= "_p" 848 recRuleAltPredicate(ruleName,opPrec) ::= "<recRuleArg()> \<= <opPrec>" 849 recRuleSetResultAction() ::= "root_0=$<ruleName>_primary.tree;" 850 recRuleSetReturnAction(src,name) ::= "$<name>=$<src>.<name>;" 851 852 /** match ^(root children) in tree parser */ 853 tree(root, actionsAfterRoot, children, nullableChildList, 854 enclosingTreeLevel, treeLevel) ::= << 855 <root:element()> 856 <actionsAfterRoot:element()> 857 <if(nullableChildList)> 858 if ( 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 */ 877 validateSemanticPredicate(pred,description) ::= << 878 if ( !(<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 886 dfaState(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= << 887 val LA<decisionNumber>_<stateNumber> = input.LA(<k>)<\n> 888 <edges; separator="\nelse "> 889 else { 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 */ 906 dfaOptionalBlockState(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= << 907 val 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 */ 917 dfaLoopbackState(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= << 918 val LA<decisionNumber>_<stateNumber> = input.LA(<k>)<\n> 919 <edges; separator="\nelse "><\n> 920 <if(eotPredictsAlt)> 921 <if(!edges)> 922 alt<decisionNumber>=<eotPredictsAlt> <! if no edges, don't gen ELSE !> 923 <else> 924 else { 925 alt<decisionNumber>=<eotPredictsAlt> 926 }<\n> 927 <endif> 928 <endif> 929 >> 930 931 /** An accept state indicates a unique alternative has been predicted */ 932 dfaAcceptState(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 */ 938 dfaEdge(labelExpr, targetState, predicates) ::= << 939 if ( (<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 */ 949 dfaStateSwitch(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= << 950 input.LA(<k>) match { 951 <edges; separator="\n"> 952 case _ => 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 964 dfaOptionalBlockStateSwitch(k,edges,eotPredictsAlt,description,stateNumber,semPredState) ::= << 965 input.LA(<k>) match { 966 <edges; separator="\n"> 967 case _ => 968 }<\n> 969 >> 970 971 dfaLoopbackStateSwitch(k, edges,eotPredictsAlt,description,stateNumber,semPredState) ::= << 972 input.LA(<k>) match { 973 <edges; separator="\n"><\n> 974 case _ => 975 <if(eotPredictsAlt)> 976 alt<decisionNumber>=<eotPredictsAlt>; 977 <endif> 978 }<\n> 979 >> 980 981 dfaEdgeSwitch(labels, targetState) ::= << 982 case <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 */ 994 dfaDecision(decisionNumber,description) ::= << 995 alt<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 */ 1006 cyclicDFA(dfa) ::= << 1007 val DFA<dfa.decisionNumber>_eotS = 1008 "<dfa.javaCompressedEOT; wrap="\"+\n \"">" 1009 val DFA<dfa.decisionNumber>_eofS = 1010 "<dfa.javaCompressedEOF; wrap="\"+\n \"">" 1011 val DFA<dfa.decisionNumber>_minS = 1012 "<dfa.javaCompressedMin; wrap="\"+\n \"">" 1013 val DFA<dfa.decisionNumber>_maxS = 1014 "<dfa.javaCompressedMax; wrap="\"+\n \"">" 1015 val DFA<dfa.decisionNumber>_acceptS = 1016 "<dfa.javaCompressedAccept; wrap="\"+\n \"">" 1017 val DFA<dfa.decisionNumber>_specialS = 1018 "<dfa.javaCompressedSpecial; wrap="\"+\n \"">}>" 1019 val DFA<dfa.decisionNumber>_transitionS: Array[String] = Array( 1020 <dfa.javaCompressedTransition:{s|"<s; wrap="\"+\n\"">"}; separator=",\n"> 1021 ) 1022 1023 val DFA<dfa.decisionNumber>_eot: Array[Short] = DFA.unpackEncodedString(DFA<dfa.decisionNumber>_eotS) 1024 val DFA<dfa.decisionNumber>_eof: Array[Short] = DFA.unpackEncodedString(DFA<dfa.decisionNumber>_eofS) 1025 val DFA<dfa.decisionNumber>_min: Array[Char] = DFA.unpackEncodedStringToUnsignedChars(DFA<dfa.decisionNumber>_minS) 1026 val DFA<dfa.decisionNumber>_max: Array[Char] = DFA.unpackEncodedStringToUnsignedChars(DFA<dfa.decisionNumber>_maxS) 1027 val DFA<dfa.decisionNumber>_accept: Array[Short] = DFA.unpackEncodedString(DFA<dfa.decisionNumber>_acceptS) 1028 val DFA<dfa.decisionNumber>_special: Array[Short] = DFA.unpackEncodedString(DFA<dfa.decisionNumber>_specialS) 1029 val DFA<dfa.decisionNumber>_transition = new Array[Array[Short]](DFA<dfa.decisionNumber>_transitionS.length) 1030 1031 for (i \<- DFA<dfa.decisionNumber>_transition.indices) { 1032 DFA<dfa.decisionNumber>_transition(i) = DFA.unpackEncodedString(DFA<dfa.decisionNumber>_transitionS(i)) 1033 } 1034 1035 class 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 */ 1084 cyclicDFAState(decisionNumber,stateNumber,edges,needErrorClause,semPredState) ::= << 1085 val LA<decisionNumber>_<stateNumber>: Int = input.LA(1)<\n> 1086 <if(semPredState)> <! get next lookahead symbol to test edges, then rewind !> 1087 val index<decisionNumber>_<stateNumber>: Int = input.index() 1088 input.rewind()<\n> 1089 <endif> 1090 s = -1 1091 <edges; separator="\nelse "> 1092 <if(semPredState)> <! return input cursor to state before we rewound !> 1093 input.seek(index<decisionNumber>_<stateNumber>)<\n> 1094 <endif> 1095 if ( 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 */ 1101 cyclicDFAEdge(labelExpr, targetStateNumber, edgeNumber, predicates) ::= << 1102 if ( (<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 */ 1108 eotDFAEdge(targetStateNumber,edgeNumber, predicates) ::= << 1109 s = <targetStateNumber><\n> 1110 >> 1111 1112 1113 // D F A E X P R E S S I O N S 1114 1115 andPredicates(left,right) ::= "(<left>&&<right>)" 1116 1117 orPredicates(operands) ::= "(<first(operands)><rest(operands):{o | ||<o>}>)" 1118 1119 notPredicate(pred) ::= "!(<evalPredicate(pred,\"\")>)" 1120 1121 evalPredicate(pred,description) ::= "(<pred>)" 1122 1123 evalSynPredicate(pred,description) ::= "<pred>()" 1124 1125 lookaheadTest(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 */ 1130 isolatedLookaheadTest(atom,k,atomAsInt) ::= "input.LA(<k>)==<atom>" 1131 1132 lookaheadRangeTest(lower,upper,k,rangeNumber,lowerAsInt,upperAsInt) ::= << 1133 (LA<decisionNumber>_<stateNumber> >= <lower> && LA<decisionNumber>_<stateNumber> \<= <upper>) 1134 >> 1135 1136 isolatedLookaheadRangeTest(lower,upper,k,rangeNumber,lowerAsInt,upperAsInt) ::= "(input.LA(<k>) >=<lower> && input.LA(<k>) \<= <upper>)" 1137 1138 setTest(ranges) ::= "<ranges; separator=\"||\">" 1139 1140 // A T T R I B U T E S 1141 1142 globalAttributeScope(scope) ::= << 1143 <if(scope.attributes)> 1144 class <scope.name>_scope { 1145 <scope.attributes:{it | var <it.name>: <it.type> = _}; separator="\n"> 1146 } 1147 val <scope.name>_stack = new collection.mutable.Stack[<scope.name>_scope]<\n> 1148 <endif> 1149 >> 1150 1151 ruleAttributeScope(scope) ::= << 1152 <if(scope.attributes)> 1153 class <scope.name>_scope { 1154 <scope.attributes:{it | var <it.name>: <it.type> = _}; separator="\n"> 1155 } 1156 val <scope.name>_stack = new collection.mutable.Stack[<scope.name>_scope]<\n> 1157 <endif> 1158 >> 1159 1160 returnStructName(r) ::= "<r.name>_return" 1161 1162 returnType() ::= << 1163 <if(ruleDescriptor.hasMultipleReturnValues)> 1164 <ruleDescriptor:returnStructName()> 1165 <else> 1166 <if(ruleDescriptor.hasSingleReturnValue)> 1167 <ruleDescriptor.singleValueReturnType> 1168 <else> 1169 Unit 1170 <endif> 1171 <endif> 1172 >> 1173 1174 /** Generate the Java type associated with a single or multiple return 1175 * values. 1176 */ 1177 ruleLabelType(referencedRule) ::= << 1178 <if(referencedRule.hasMultipleReturnValues)> 1179 <referencedRule.name>_return 1180 <else> 1181 <if(referencedRule.hasSingleReturnValue)> 1182 <referencedRule.singleValueReturnType> 1183 <else> 1184 Unit 1185 <endif> 1186 <endif> 1187 >> 1188 1189 delegateName(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 */ 1196 initValue(typeName) ::= << 1197 <scalaTypeInitMap.(typeName)> 1198 >> 1199 1200 /** Define a rule label including default value */ 1201 ruleLabelDef(label) ::= << 1202 var <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 */ 1210 returnScope(scope) ::= << 1211 <if(ruleDescriptor.hasMultipleReturnValues)> 1212 final 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 1219 parameterScope(scope) ::= << 1220 <scope.attributes:{it | <it.name>: <it.type>}; separator=", "> 1221 >> 1222 1223 parameterAttributeRef(attr) ::= "<attr.name>" 1224 parameterSetAttributeRef(attr,expr) ::= "<attr.name> =<expr>" 1225 1226 scopeAttributeRef(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 1238 scopeSetAttributeRef(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 */ 1254 isolatedDynamicScopeRef(scope) ::= "<scope>_stack" 1255 1256 /** reference an attribute of rule; might only have single return value */ 1257 ruleLabelRef(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 1265 returnAttributeRef(ruleDescriptor,attr) ::= <% 1266 <if(ruleDescriptor.hasMultipleReturnValues)> 1267 retval.<attr.name> 1268 <else> 1269 <attr.name> 1270 <endif> 1271 %> 1272 1273 returnSetAttributeRef(ruleDescriptor,attr,expr) ::= <% 1274 <if(ruleDescriptor.hasMultipleReturnValues)> 1275 retval.<attr.name> =<expr> 1276 <else> 1277 <attr.name> =<expr> 1278 <endif> 1279 %> 1280 1281 /** How to translate $tokenLabel */ 1282 tokenLabelRef(label) ::= "<label>" 1283 1284 /** ids+=ID {$ids} or e+=expr {$e} */ 1285 listLabelRef(label) ::= "list_<label>" 1286 1287 1288 // not sure the next are the right approach 1289 1290 tokenLabelPropertyRef_text(scope,attr) ::= "(if (<scope>!=null) <scope>.getText() else null)" 1291 tokenLabelPropertyRef_type(scope,attr) ::= "(if (<scope>!=null) <scope>.getType() else 0)" 1292 tokenLabelPropertyRef_line(scope,attr) ::= "(if (<scope>!=null) <scope>.getLine() else 0)" 1293 tokenLabelPropertyRef_pos(scope,attr) ::= "(if (<scope>!=null) <scope>.getCharPositionInLine() else 0)" 1294 tokenLabelPropertyRef_channel(scope,attr) ::= "(if (<scope>!=null) <scope>.getChannel() else 0)" 1295 tokenLabelPropertyRef_index(scope,attr) ::= "(if (<scope>!=null) <scope>.getTokenIndex() else 0)" 1296 tokenLabelPropertyRef_tree(scope,attr) ::= "<scope>_tree" 1297 tokenLabelPropertyRef_int(scope,attr) ::= "(if (<scope>!=null) Integer.valueOf(<scope>.getText()) else 0)" 1298 1299 ruleLabelPropertyRef_start(scope,attr) ::= "(if (<scope>!=null) <scope>.start.asInstanceOf[<labelType>] else null)" 1300 ruleLabelPropertyRef_stop(scope,attr) ::= "(if (<scope>!=null) <scope>.stop.asInstanceOf[<labelType>] else null)" 1301 ruleLabelPropertyRef_tree(scope,attr) ::= "(if (<scope>!=null) <scope>.tree.asInstanceOf[<ASTLabelType>] else null)" 1302 ruleLabelPropertyRef_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 1312 ruleLabelPropertyRef_st(scope,attr) ::= "(if (<scope>!=null) <scope>.st else null)" 1313 1314 /** Isolated $RULE ref ok in lexer as it's a Token */ 1315 lexerRuleLabel(label) ::= "<label>" 1316 1317 lexerRuleLabelPropertyRef_type(scope,attr) ::= 1318 "(if (<scope>!=null) <scope>.getType() else 0)" 1319 lexerRuleLabelPropertyRef_line(scope,attr) ::= 1320 "(if (<scope>!=null) <scope>.getLine() else 0)" 1321 lexerRuleLabelPropertyRef_pos(scope,attr) ::= 1322 "(if (<scope>!=null) <scope>.getCharPositionInLine() else -1)" 1323 lexerRuleLabelPropertyRef_channel(scope,attr) ::= 1324 "(if (<scope>!=null) <scope>.getChannel() else 0)" 1325 lexerRuleLabelPropertyRef_index(scope,attr) ::= 1326 "(if (<scope>!=null) <scope>.getTokenIndex() else 0)" 1327 lexerRuleLabelPropertyRef_text(scope,attr) ::= 1328 "(if (<scope>!=null) <scope>.getText() else null)" 1329 lexerRuleLabelPropertyRef_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: 1333 rulePropertyRef_start(scope,attr) ::= "(retval.start.asInstanceOf[<labelType>])" 1334 rulePropertyRef_stop(scope,attr) ::= "(retval.stop.asInstanceOf[<labelType>])" 1335 rulePropertyRef_tree(scope,attr) ::= "(retval.tree.asInstanceOf[<ASTLabelType>])" 1336 rulePropertyRef_text(scope,attr) ::= << 1337 <if(TREE_PARSER)> 1338 input.getTokenStream().toString( 1339 input.getTreeAdaptor().getTokenStartIndex(retval.start), 1340 input.getTreeAdaptor().getTokenStopIndex(retval.start)) 1341 <else> 1342 input.toString(retval.start,input.LT(-1)) 1343 <endif> 1344 >> 1345 rulePropertyRef_st(scope,attr) ::= "retval.st" 1346 1347 lexerRulePropertyRef_text(scope,attr) ::= "getText()" 1348 lexerRulePropertyRef_type(scope,attr) ::= "_type" 1349 lexerRulePropertyRef_line(scope,attr) ::= "state.tokenStartLine" 1350 lexerRulePropertyRef_pos(scope,attr) ::= "state.tokenStartCharPositionInLine" 1351 lexerRulePropertyRef_index(scope,attr) ::= "-1" // undefined token index in lexer 1352 lexerRulePropertyRef_channel(scope,attr) ::= "_channel" 1353 lexerRulePropertyRef_start(scope,attr) ::= "state.tokenStartCharIndex" 1354 lexerRulePropertyRef_stop(scope,attr) ::= "(getCharIndex()-1)" 1355 lexerRulePropertyRef_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 1359 ruleSetPropertyRef_tree(scope,attr,expr) ::= "retval.tree =<expr>" 1360 ruleSetPropertyRef_st(scope,attr,expr) ::= "retval.st =<expr>" 1361 1362 /** How to execute an action (only when not backtracking) */ 1363 execAction(action) ::= << 1364 <if(backtracking)> 1365 if ( <actions.(actionScope).synpredgate> ) { 1366 <action> 1367 } 1368 <else> 1369 <action> 1370 <endif> 1371 >> 1372 1373 /** How to always execute an action even when backtracking */ 1374 execForcedAction(action) ::= "<action>" 1375 1376 // M I S C (properties, etc...) 1377 1378 bitset(name, words64) ::= << 1379 val <name> = new BitSet(Array[Long](<words64:{it | <it>L};separator=",">))<\n> 1380 >> 1381 1382 codeFileExtension() ::= ".scala" 1383 1384 true_value() ::= "true" 1385 false_value() ::= "false" 1386