1/* 2 [The "BSD license"] 3 Copyright (c) 2011 Terence Parr 4 All rights reserved. 5 6 Grammar conversion to ANTLR v3: 7 Copyright (c) 2011 Sam Harwell 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 1. Redistributions of source code must retain the above copyright 14 notice, this list of conditions and the following disclaimer. 15 2. Redistributions in binary form must reproduce the above copyright 16 notice, this list of conditions and the following disclaimer in the 17 documentation and/or other materials provided with the distribution. 18 3. The name of the author may not be used to endorse or promote products 19 derived from this software without specific prior written permission. 20 21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31*/ 32 33/** Walk a grammar and generate code by gradually building up 34 * a bigger and bigger ST. 35 * 36 * Terence Parr 37 * University of San Francisco 38 * June 15, 2004 39 */ 40tree grammar CodeGenTreeWalker; 41 42options { 43 language=Java; 44 tokenVocab = ANTLR; 45 ASTLabelType=GrammarAST; 46} 47 48@header { 49package org.antlr.grammar.v3; 50 51import org.antlr.analysis.*; 52import org.antlr.misc.*; 53import org.antlr.tool.*; 54import org.antlr.codegen.*; 55 56import java.util.HashSet; 57import java.util.Set; 58import java.util.Collection; 59import org.antlr.runtime.BitSet; 60import org.antlr.runtime.DFA; 61import org.stringtemplate.v4.ST; 62import org.stringtemplate.v4.STGroup; 63} 64 65@members { 66protected static final int RULE_BLOCK_NESTING_LEVEL = 0; 67protected static final int OUTER_REWRITE_NESTING_LEVEL = 0; 68 69private String currentRuleName = null; 70protected int blockNestingLevel = 0; 71protected int rewriteBlockNestingLevel = 0; 72private int outerAltNum = 0; 73protected ST currentBlockST = null; 74protected boolean currentAltHasASTRewrite = false; 75protected int rewriteTreeNestingLevel = 0; 76protected HashSet<Object> rewriteRuleRefs = null; 77 78public String getCurrentRuleName() { 79 return currentRuleName; 80} 81 82public void setCurrentRuleName(String value) { 83 currentRuleName = value; 84} 85 86public int getOuterAltNum() { 87 return outerAltNum; 88} 89 90public void setOuterAltNum(int value) { 91 outerAltNum = value; 92} 93 94@Override 95public void reportError(RecognitionException ex) { 96 Token token = null; 97 if (ex instanceof MismatchedTokenException) { 98 token = ((MismatchedTokenException)ex).token; 99 } else if (ex instanceof NoViableAltException) { 100 token = ((NoViableAltException)ex).token; 101 } 102 103 ErrorManager.syntaxError( 104 ErrorManager.MSG_SYNTAX_ERROR, 105 grammar, 106 token, 107 "codegen: " + ex.toString(), 108 ex ); 109} 110 111public final void reportError(String s) { 112 System.out.println("codegen: error: " + s); 113} 114 115protected CodeGenerator generator; 116protected Grammar grammar; 117protected STGroup templates; 118 119/** The overall lexer/parser template; simulate dynamically scoped 120 * attributes by making this an instance var of the walker. 121 */ 122protected ST recognizerST; 123 124protected ST outputFileST; 125protected ST headerFileST; 126 127protected String outputOption = ""; 128 129protected final ST getWildcardST(GrammarAST elementAST, GrammarAST ast_suffix, String label) { 130 String name = "wildcard"; 131 if (grammar.type == Grammar.LEXER) { 132 name = "wildcardChar"; 133 } 134 return getTokenElementST(name, name, elementAST, ast_suffix, label); 135} 136 137protected final ST getRuleElementST( String name, 138 String ruleTargetName, 139 GrammarAST elementAST, 140 GrammarAST ast_suffix, 141 String label ) { 142 Rule r = grammar.getRule( currentRuleName ); 143 String suffix = getSTSuffix(elementAST, ast_suffix, label); 144 if ( !r.isSynPred ) { 145 name += suffix; 146 } 147 // if we're building trees and there is no label, gen a label 148 // unless we're in a synpred rule. 149 if ( ( grammar.buildAST() || suffix.length() > 0 ) && label == null && 150 ( r == null || !r.isSynPred ) ) { 151 // we will need a label to do the AST or tracking, make one 152 label = generator.createUniqueLabel( ruleTargetName ); 153 CommonToken labelTok = new CommonToken( ANTLRParser.ID, label ); 154 grammar.defineRuleRefLabel( currentRuleName, labelTok, elementAST ); 155 } 156 157 ST elementST = templates.getInstanceOf( name ); 158 if ( label != null ) { 159 elementST.add( "label", label ); 160 } 161 162 163 return elementST; 164} 165 166protected final ST getTokenElementST( String name, 167 String elementName, 168 GrammarAST elementAST, 169 GrammarAST ast_suffix, 170 String label ) { 171 boolean tryUnchecked = false; 172 if (name == "matchSet" && elementAST.enclosingRuleName != null && elementAST.enclosingRuleName.length() > 0 && Rule.getRuleType(elementAST.enclosingRuleName) == Grammar.LEXER) 173 { 174 if ( ( elementAST.getParent().getType() == ANTLRLexer.ALT && elementAST.getParent().getParent().getParent().getType() == RULE && elementAST.getParent().getParent().getChildCount() == 2 ) 175 || ( elementAST.getParent().getType() == ANTLRLexer.NOT && elementAST.getParent().getParent().getParent().getParent().getType() == RULE && elementAST.getParent().getParent().getParent().getChildCount() == 2 ) ) { 176 // single alt at the start of the rule needs to be checked 177 } else { 178 tryUnchecked = true; 179 } 180 } 181 182 String suffix = getSTSuffix( elementAST, ast_suffix, label ); 183 // if we're building trees and there is no label, gen a label 184 // unless we're in a synpred rule. 185 Rule r = grammar.getRule( currentRuleName ); 186 if ( ( grammar.buildAST() || suffix.length() > 0 ) && label == null && 187 ( r == null || !r.isSynPred ) ) 188 { 189 label = generator.createUniqueLabel( elementName ); 190 CommonToken labelTok = new CommonToken( ANTLRParser.ID, label ); 191 grammar.defineTokenRefLabel( currentRuleName, labelTok, elementAST ); 192 } 193 194 ST elementST = null; 195 if ( tryUnchecked && templates.isDefined( name + "Unchecked" + suffix ) ) 196 elementST = templates.getInstanceOf( name + "Unchecked" + suffix ); 197 if ( elementST == null ) 198 elementST = templates.getInstanceOf( name + suffix ); 199 200 if ( label != null ) 201 { 202 elementST.add( "label", label ); 203 } 204 return elementST; 205} 206 207public final boolean isListLabel(String label) { 208 boolean hasListLabel = false; 209 if ( label != null ) { 210 Rule r = grammar.getRule( currentRuleName ); 211 //String stName = null; 212 if ( r != null ) 213 { 214 Grammar.LabelElementPair pair = r.getLabel( label ); 215 if ( pair != null && 216 ( pair.type == Grammar.TOKEN_LIST_LABEL || 217 pair.type == Grammar.RULE_LIST_LABEL || 218 pair.type == Grammar.WILDCARD_TREE_LIST_LABEL ) ) 219 { 220 hasListLabel = true; 221 } 222 } 223 } 224 return hasListLabel; 225} 226 227/** Return a non-empty template name suffix if the token is to be 228 * tracked, added to a tree, or both. 229 */ 230protected final String getSTSuffix(GrammarAST elementAST, GrammarAST ast_suffix, String label) { 231 if ( grammar.type == Grammar.LEXER ) 232 { 233 return ""; 234 } 235 // handle list label stuff; make element use "Track" 236 237 String operatorPart = ""; 238 String rewritePart = ""; 239 String listLabelPart = ""; 240 Rule ruleDescr = grammar.getRule( currentRuleName ); 241 if ( ast_suffix != null && !ruleDescr.isSynPred ) 242 { 243 if ( ast_suffix.getType() == ANTLRParser.ROOT ) 244 { 245 operatorPart = "RuleRoot"; 246 } 247 else if ( ast_suffix.getType() == ANTLRParser.BANG ) 248 { 249 operatorPart = "Bang"; 250 } 251 } 252 if ( currentAltHasASTRewrite && elementAST.getType() != WILDCARD ) 253 { 254 rewritePart = "Track"; 255 } 256 if ( isListLabel( label ) ) 257 { 258 listLabelPart = "AndListLabel"; 259 } 260 String STsuffix = operatorPart + rewritePart + listLabelPart; 261 //[email protected]("suffix = "+STsuffix); 262 263 return STsuffix; 264} 265 266/** Convert rewrite AST lists to target labels list */ 267protected final List<String> getTokenTypesAsTargetLabels(Collection<GrammarAST> refs) 268{ 269 if ( refs == null || refs.size() == 0 ) 270 return null; 271 272 List<String> labels = new ArrayList<String>( refs.size() ); 273 for ( GrammarAST t : refs ) 274 { 275 String label; 276 if ( t.getType() == ANTLRParser.RULE_REF || t.getType() == ANTLRParser.TOKEN_REF || t.getType() == ANTLRParser.LABEL) 277 { 278 label = t.getText(); 279 } 280 else 281 { 282 // must be char or String literal 283 label = generator.getTokenTypeAsTargetLabel(grammar.getTokenType(t.getText())); 284 } 285 labels.add( label ); 286 } 287 return labels; 288} 289 290public final void init( Grammar g ) { 291 this.grammar = g; 292 this.generator = grammar.getCodeGenerator(); 293 this.templates = generator.getTemplates(); 294} 295} 296 297public 298grammar_[Grammar g, 299 ST recognizerST, 300 ST outputFileST, 301 ST headerFileST] 302@init 303{ 304 if ( state.backtracking == 0 ) 305 { 306 init(g); 307 this.recognizerST = recognizerST; 308 this.outputFileST = outputFileST; 309 this.headerFileST = headerFileST; 310 String superClass = (String)g.getOption("superClass"); 311 outputOption = (String)g.getOption("output"); 312 if ( superClass!=null ) recognizerST.add("superClass", superClass); 313 if ( g.type!=Grammar.LEXER ) { 314 Object lt = g.getOption("ASTLabelType"); 315 if ( lt!=null ) recognizerST.add("ASTLabelType", lt); 316 } 317 if ( g.type==Grammar.TREE_PARSER && g.getOption("ASTLabelType")==null ) { 318 ErrorManager.grammarWarning(ErrorManager.MSG_MISSING_AST_TYPE_IN_TREE_GRAMMAR, 319 g, 320 null, 321 g.name); 322 } 323 if ( g.type!=Grammar.TREE_PARSER ) { 324 Object lt = g.getOption("TokenLabelType"); 325 if ( lt!=null ) recognizerST.add("labelType", lt); 326 } 327 $recognizerST.add("numRules", grammar.getRules().size()); 328 $outputFileST.add("numRules", grammar.getRules().size()); 329 $headerFileST.add("numRules", grammar.getRules().size()); 330 } 331} 332 : ( ^( LEXER_GRAMMAR grammarSpec ) 333 | ^( PARSER_GRAMMAR grammarSpec ) 334 | ^( TREE_GRAMMAR grammarSpec ) 335 | ^( COMBINED_GRAMMAR grammarSpec ) 336 ) 337 ; 338 339attrScope 340 : ^( 'scope' ID ( ^(AMPERSAND .*) )* ACTION ) 341 ; 342 343grammarSpec 344 : name=ID 345 ( cmt=DOC_COMMENT 346 { 347 outputFileST.add("docComment", $cmt.text); 348 headerFileST.add("docComment", $cmt.text); 349 } 350 )? 351 { 352 recognizerST.add("name", grammar.getRecognizerName()); 353 outputFileST.add("name", grammar.getRecognizerName()); 354 headerFileST.add("name", grammar.getRecognizerName()); 355 recognizerST.add("scopes", grammar.getGlobalScopes()); 356 headerFileST.add("scopes", grammar.getGlobalScopes()); 357 } 358 ( ^(OPTIONS .*) )? 359 ( ^(IMPORT .*) )? 360 ( ^(TOKENS .*) )? 361 (attrScope)* 362 ( ^(AMPERSAND .*) )* 363 rules[recognizerST] 364 ; 365 366rules[ST recognizerST] 367@init 368{ 369 String ruleName = ((GrammarAST)input.LT(1)).getChild(0).getText(); 370 boolean generated = grammar.generateMethodForRule(ruleName); 371} 372 : ( ( options {k=1;} : 373 {generated}? => 374 rST=rule 375 { 376 if ( $rST.code != null ) 377 { 378 recognizerST.add("rules", $rST.code); 379 outputFileST.add("rules", $rST.code); 380 headerFileST.add("rules", $rST.code); 381 } 382 } 383 | ^(RULE .*) 384 | ^(PREC_RULE .*) // ignore 385 ) 386 {{ 387 if ( input.LA(1) == RULE ) 388 { 389 ruleName = ((GrammarAST)input.LT(1)).getChild(0).getText(); 390 //System.Diagnostics.Debug.Assert( ruleName == ((GrammarAST)input.LT(1)).enclosingRuleName ); 391 generated = grammar.generateMethodForRule(ruleName); 392 } 393 }} 394 )+ 395 ; 396 397rule returns [ST code=null] 398@init 399{ 400 String initAction = null; 401 // get the dfa for the BLOCK 402 GrammarAST block2=(GrammarAST)$start.getFirstChildWithType(BLOCK); 403 org.antlr.analysis.DFA dfa = block2.getLookaheadDFA(); 404 // init blockNestingLevel so it's block level RULE_BLOCK_NESTING_LEVEL 405 // for alts of rule 406 blockNestingLevel = RULE_BLOCK_NESTING_LEVEL-1; 407 Rule ruleDescr = grammar.getRule($start.getChild(0).getText()); 408 currentRuleName = $start.getChild(0).getText(); 409 410 // For syn preds, we don't want any AST code etc... in there. 411 // Save old templates ptr and restore later. Base templates include Dbg. 412 STGroup saveGroup = templates; 413 if ( ruleDescr.isSynPred && generator.target.useBaseTemplatesForSynPredFragments() ) 414 { 415 templates = generator.getBaseTemplates(); 416 } 417 418 String description = ""; 419} 420 : ^( RULE id=ID 421 {assert currentRuleName == $id.text;} 422 (mod=modifier)? 423 ^(ARG (ARG_ACTION)?) 424 ^(RET (ARG_ACTION)?) 425 (throwsSpec)? 426 ( ^(OPTIONS .*) )? 427 (ruleScopeSpec)? 428 ( ^(AMPERSAND .*) )* 429 b=block["ruleBlock", dfa, null] 430 { 431 description = 432 grammar.grammarTreeToString((GrammarAST)$start.getFirstChildWithType(BLOCK), 433 false); 434 description = 435 generator.target.getTargetStringLiteralFromString(description); 436 $b.code.add("description", description); 437 // do not generate lexer rules in combined grammar 438 String stName = null; 439 if ( ruleDescr.isSynPred ) 440 { 441 stName = "synpredRule"; 442 } 443 else if ( grammar.type==Grammar.LEXER ) 444 { 445 if ( currentRuleName.equals(Grammar.ARTIFICIAL_TOKENS_RULENAME) ) 446 { 447 stName = "tokensRule"; 448 } 449 else 450 { 451 stName = "lexerRule"; 452 } 453 } 454 else 455 { 456 if ( !(grammar.type==Grammar.COMBINED && 457 Rule.getRuleType(currentRuleName) == Grammar.LEXER) ) 458 { 459 stName = "rule"; 460 } 461 } 462 $code = templates.getInstanceOf(stName); 463 if ( $code.getName().equals("/rule") ) 464 { 465 $code.add("emptyRule", grammar.isEmptyRule(block2)); 466 } 467 $code.add("ruleDescriptor", ruleDescr); 468 String memo = (String)grammar.getBlockOption($start,"memoize"); 469 if ( memo==null ) 470 { 471 memo = (String)grammar.getOption("memoize"); 472 } 473 if ( memo!=null && memo.equals("true") && 474 (stName.equals("rule")||stName.equals("lexerRule")) ) 475 { 476 $code.add("memoize", memo!=null && memo.equals("true")); 477 } 478 } 479 480 (exceptionGroup[$code])? 481 EOR 482 ) 483 { 484 if ( $code!=null ) 485 { 486 if ( grammar.type==Grammar.LEXER ) 487 { 488 boolean naked = 489 currentRuleName.equals(Grammar.ARTIFICIAL_TOKENS_RULENAME) || 490 ($mod.start!=null&&$mod.start.getText().equals(Grammar.FRAGMENT_RULE_MODIFIER)); 491 $code.add("nakedBlock", naked); 492 } 493 else 494 { 495 description = grammar.grammarTreeToString($start,false); 496 description = generator.target.getTargetStringLiteralFromString(description); 497 $code.add("description", description); 498 } 499 Rule theRule = grammar.getRule(currentRuleName); 500 generator.translateActionAttributeReferencesForSingleScope( 501 theRule, 502 theRule.getActions() 503 ); 504 $code.add("ruleName", currentRuleName); 505 $code.add("block", $b.code); 506 if ( initAction!=null ) 507 { 508 $code.add("initAction", initAction); 509 } 510 } 511 } 512 ; 513finally { templates = saveGroup; } 514 515modifier 516 : 'protected' 517 | 'public' 518 | 'private' 519 | 'fragment' 520 ; 521 522throwsSpec 523 : ^('throws' ID+) 524 ; 525 526ruleScopeSpec 527 : ^( 'scope' ( ^(AMPERSAND .*) )* (ACTION)? ( ID )* ) 528 ; 529 530block[String blockTemplateName, org.antlr.analysis.DFA dfa, GrammarAST label] 531 returns [ST code=null] 532options { k=1; } 533@init 534{ 535 int altNum = 0; 536 537 blockNestingLevel++; 538 if ( state.backtracking == 0 ) 539 { 540 ST decision = null; 541 if ( $dfa != null ) 542 { 543 $code = templates.getInstanceOf($blockTemplateName); 544 decision = generator.genLookaheadDecision(recognizerST,$dfa); 545 $code.add("decision", decision); 546 $code.add("decisionNumber", $dfa.getDecisionNumber()); 547 $code.add("maxK",$dfa.getMaxLookaheadDepth()); 548 $code.add("maxAlt",$dfa.getNumberOfAlts()); 549 } 550 else 551 { 552 $code = templates.getInstanceOf($blockTemplateName+"SingleAlt"); 553 } 554 $code.add("blockLevel", blockNestingLevel); 555 $code.add("enclosingBlockLevel", blockNestingLevel-1); 556 altNum = 1; 557 if ( this.blockNestingLevel==RULE_BLOCK_NESTING_LEVEL ) { 558 this.outerAltNum=1; 559 } 560 } 561} 562 : {$start.getSetValue()!=null}? => setBlock 563 { 564 $code.add("alts",$setBlock.code); 565 } 566 567 | ^( BLOCK 568 ( ^(OPTIONS .*) )? // ignore 569 ( alt=alternative[$label] rew=rewrite 570 { 571 if ( this.blockNestingLevel==RULE_BLOCK_NESTING_LEVEL ) 572 { 573 this.outerAltNum++; 574 } 575 // add the rewrite code as just another element in the alt :) 576 // (unless it's a " -> ..." rewrite 577 // ( -> ... ) 578 GrammarAST firstRewriteAST = $rew.start.findFirstType(REWRITE); 579 boolean etc = 580 $rew.start.getType()==REWRITES && 581 firstRewriteAST.getChild(0)!=null && 582 firstRewriteAST.getChild(0).getType()==ETC; 583 if ( $rew.code!=null && !etc ) 584 { 585 $alt.code.add("rew", $rew.code); 586 } 587 // add this alt to the list of alts for this block 588 $code.add("alts",$alt.code); 589 $alt.code.add("altNum", altNum); 590 $alt.code.add("outerAlt", blockNestingLevel==RULE_BLOCK_NESTING_LEVEL); 591 altNum++; 592 } 593 )+ 594 EOB 595 ) 596 ; 597finally { blockNestingLevel--; } 598 599setBlock returns [ST code=null] 600@init 601{ 602 ST setcode = null; 603 if ( state.backtracking == 0 ) 604 { 605 if ( blockNestingLevel==RULE_BLOCK_NESTING_LEVEL && grammar.buildAST() ) 606 { 607 Rule r = grammar.getRule(currentRuleName); 608 currentAltHasASTRewrite = r.hasRewrite(outerAltNum); 609 if ( currentAltHasASTRewrite ) 610 { 611 r.trackTokenReferenceInAlt($start, outerAltNum); 612 } 613 } 614 } 615} 616 : ^(s=BLOCK .*) 617 { 618 int i = ((CommonToken)$s.getToken()).getTokenIndex(); 619 if ( blockNestingLevel==RULE_BLOCK_NESTING_LEVEL ) 620 { 621 setcode = getTokenElementST("matchRuleBlockSet", "set", $s, null, null); 622 } 623 else 624 { 625 setcode = getTokenElementST("matchSet", "set", $s, null, null); 626 } 627 setcode.add("elementIndex", i); 628 //if ( grammar.type!=Grammar.LEXER ) 629 //{ 630 // generator.generateLocalFOLLOW($s,"set",currentRuleName,i); 631 //} 632 setcode.add("s", 633 generator.genSetExpr(templates,$s.getSetValue(),1,false)); 634 ST altcode=templates.getInstanceOf("alt"); 635 altcode.addAggr("elements.{el,line,pos}", 636 setcode, 637 $s.getLine(), 638 $s.getCharPositionInLine() + 1 639 ); 640 altcode.add("altNum", 1); 641 altcode.add("outerAlt", blockNestingLevel==RULE_BLOCK_NESTING_LEVEL); 642 if ( !currentAltHasASTRewrite && grammar.buildAST() ) 643 { 644 altcode.add("autoAST", true); 645 } 646 altcode.add("treeLevel", rewriteTreeNestingLevel); 647 $code = altcode; 648 } 649 ; 650 651setAlternative 652 : ^(ALT setElement+ EOA) 653 ; 654 655exceptionGroup[ST ruleST] 656 : ( exceptionHandler[$ruleST] )+ (finallyClause[$ruleST])? 657 | finallyClause[$ruleST] 658 ; 659 660exceptionHandler[ST ruleST] 661 : ^('catch' ARG_ACTION ACTION) 662 { 663 List<? extends Object> chunks = generator.translateAction(currentRuleName,$ACTION); 664 $ruleST.addAggr("exceptions.{decl,action}",$ARG_ACTION.text,chunks); 665 } 666 ; 667 668finallyClause[ST ruleST] 669 : ^('finally' ACTION) 670 { 671 List<? extends Object> chunks = generator.translateAction(currentRuleName,$ACTION); 672 $ruleST.add("finally",chunks); 673 } 674 ; 675 676alternative[GrammarAST label] returns [ST code] 677@init 678{ 679 if ( state.backtracking == 0 ) 680 { 681 $code = templates.getInstanceOf("alt"); 682 if ( blockNestingLevel==RULE_BLOCK_NESTING_LEVEL && grammar.buildAST() ) 683 { 684 Rule r = grammar.getRule(currentRuleName); 685 currentAltHasASTRewrite = r.hasRewrite(outerAltNum); 686 } 687 String description = grammar.grammarTreeToString($start, false); 688 description = generator.target.getTargetStringLiteralFromString(description); 689 $code.add("description", description); 690 $code.add("treeLevel", rewriteTreeNestingLevel); 691 if ( !currentAltHasASTRewrite && grammar.buildAST() ) 692 { 693 $code.add("autoAST", true); 694 } 695 } 696} 697 : ^( a=ALT 698 ( 699 e=element[$label,null] 700 { 701 if ($e.code != null) 702 { 703 $code.addAggr("elements.{el,line,pos}", 704 $e.code, 705 $e.start.getLine(), 706 $e.start.getCharPositionInLine() + 1 707 ); 708 } 709 } 710 )+ 711 EOA 712 ) 713 ; 714 715element[GrammarAST label, GrammarAST astSuffix] returns [ST code=null] 716options { k=1; } 717@init 718{ 719 IntSet elements=null; 720 GrammarAST ast = null; 721} 722 : ^(ROOT e=element[$label,$ROOT]) 723 { $code = $e.code; } 724 725 | ^(BANG e=element[$label,$BANG]) 726 { $code = $e.code; } 727 728 | ^( n=NOT ne=notElement[$n, $label, $astSuffix] ) 729 { $code = $ne.code; } 730 731 | ^( ASSIGN alabel=ID e=element[$alabel,$astSuffix] ) 732 { $code = $e.code; } 733 734 | ^( PLUS_ASSIGN label2=ID e=element[$label2,$astSuffix] ) 735 { $code = $e.code; } 736 737 | ^(CHAR_RANGE a=CHAR_LITERAL b=CHAR_LITERAL) 738 { 739 $code = templates.getInstanceOf("charRangeRef"); 740 String low = generator.target.getTargetCharLiteralFromANTLRCharLiteral(generator,$a.text); 741 String high = generator.target.getTargetCharLiteralFromANTLRCharLiteral(generator,$b.text); 742 $code.add("a", low); 743 $code.add("b", high); 744 if ( label!=null ) 745 { 746 $code.add("label", $label.getText()); 747 } 748 } 749 750 | ({((GrammarAST)input.LT(1)).getSetValue()==null}? (BLOCK|OPTIONAL|CLOSURE|POSITIVE_CLOSURE)) => /*{$start.getSetValue()==null}?*/ ebnf[$label] 751 { $code = $ebnf.code; } 752 753 | atom[null, $label, $astSuffix] 754 { $code = $atom.code; } 755 756 | tree_ 757 { $code = $tree_.code; } 758 759 | element_action 760 { $code = $element_action.code; } 761 762 | (sp=SEMPRED|sp=GATED_SEMPRED) 763 { 764 $code = templates.getInstanceOf("validateSemanticPredicate"); 765 $code.add("pred", generator.translateAction(currentRuleName,$sp)); 766 String description = generator.target.getTargetStringLiteralFromString($sp.text); 767 $code.add("description", description); 768 } 769 770 | SYN_SEMPRED // used only in lookahead; don't generate validating pred 771 772 | ^(SYNPRED .*) 773 774 | ^(BACKTRACK_SEMPRED .*) 775 776 | EPSILON 777 ; 778 779element_action returns [ST code=null] 780 : act=ACTION 781 { 782 $code = templates.getInstanceOf("execAction"); 783 $code.add("action", generator.translateAction(currentRuleName,$act)); 784 } 785 | act2=FORCED_ACTION 786 { 787 $code = templates.getInstanceOf("execForcedAction"); 788 $code.add("action", generator.translateAction(currentRuleName,$act2)); 789 } 790 ; 791 792notElement[GrammarAST n, GrammarAST label, GrammarAST astSuffix] returns [ST code=null] 793@init 794{ 795 IntSet elements=null; 796 String labelText = null; 797 if ( label!=null ) 798 { 799 labelText = label.getText(); 800 } 801} 802 : ( assign_c=CHAR_LITERAL 803 { 804 int ttype=0; 805 if ( grammar.type==Grammar.LEXER ) 806 { 807 ttype = Grammar.getCharValueFromGrammarCharLiteral($assign_c.text); 808 } 809 else 810 { 811 ttype = grammar.getTokenType($assign_c.text); 812 } 813 elements = grammar.complement(ttype); 814 } 815 | assign_s=STRING_LITERAL 816 { 817 int ttype=0; 818 if ( grammar.type==Grammar.LEXER ) 819 { 820 // TODO: error! 821 } 822 else 823 { 824 ttype = grammar.getTokenType($assign_s.text); 825 } 826 elements = grammar.complement(ttype); 827 } 828 | assign_t=TOKEN_REF 829 { 830 int ttype = grammar.getTokenType($assign_t.text); 831 elements = grammar.complement(ttype); 832 } 833 | ^(assign_st=BLOCK .*) 834 { 835 elements = $assign_st.getSetValue(); 836 elements = grammar.complement(elements); 837 } 838 ) 839 { 840 $code = getTokenElementST("matchSet", 841 "set", 842 (GrammarAST)$n.getChild(0), 843 astSuffix, 844 labelText); 845 $code.add("s",generator.genSetExpr(templates,elements,1,false)); 846 int i = ((CommonToken)n.getToken()).getTokenIndex(); 847 $code.add("elementIndex", i); 848 if ( grammar.type!=Grammar.LEXER ) 849 { 850 generator.generateLocalFOLLOW(n,"set",currentRuleName,i); 851 } 852 } 853 ; 854 855ebnf[GrammarAST label] returns [ST code=null] 856@init 857{ 858 org.antlr.analysis.DFA dfa=null; 859 GrammarAST b = (GrammarAST)$start.getChild(0); 860 GrammarAST eob = b.getLastChild(); // loops will use EOB DFA 861} 862 : ( { dfa = $start.getLookaheadDFA(); } 863 blk=block["block", dfa, $label] 864 { $code = $blk.code; } 865 | { dfa = $start.getLookaheadDFA(); } 866 ^( OPTIONAL blk=block["optionalBlock", dfa, $label] ) 867 { $code = $blk.code; } 868 | { dfa = eob.getLookaheadDFA(); } 869 ^( CLOSURE blk=block["closureBlock", dfa, $label] ) 870 { $code = $blk.code; } 871 | { dfa = eob.getLookaheadDFA(); } 872 ^( POSITIVE_CLOSURE blk=block["positiveClosureBlock", dfa, $label] ) 873 { $code = $blk.code; } 874 ) 875 { 876 String description = grammar.grammarTreeToString($start, false); 877 description = generator.target.getTargetStringLiteralFromString(description); 878 $code.add("description", description); 879 } 880 ; 881 882tree_ returns [ST code] 883@init 884{ 885 rewriteTreeNestingLevel++; 886 GrammarAST rootSuffix = null; 887 if ( state.backtracking == 0 ) 888 { 889 $code = templates.getInstanceOf("tree"); 890 NFAState afterDOWN = (NFAState)$start.NFATreeDownState.transition(0).target; 891 LookaheadSet s = grammar.LOOK(afterDOWN); 892 if ( s.member(Label.UP) ) { 893 // nullable child list if we can see the UP as the next token 894 // we need an "if ( input.LA(1)==Token.DOWN )" gate around 895 // the child list. 896 $code.add("nullableChildList", "true"); 897 } 898 $code.add("enclosingTreeLevel", rewriteTreeNestingLevel-1); 899 $code.add("treeLevel", rewriteTreeNestingLevel); 900 Rule r = grammar.getRule(currentRuleName); 901 if ( grammar.buildAST() && !r.hasRewrite(outerAltNum) ) { 902 rootSuffix = new GrammarAST(ROOT,"ROOT"); 903 } 904 } 905} 906 : ^( TREE_BEGIN 907 el=element[null,rootSuffix] 908 { 909 $code.addAggr("root.{el,line,pos}", 910 $el.code, 911 $el.start.getLine(), 912 $el.start.getCharPositionInLine() + 1 913 ); 914 } 915 // push all the immediately-following actions out before children 916 // so actions aren't guarded by the "if (input.LA(1)==Token.DOWN)" 917 // guard in generated code. 918 ( (element_action) => 919 act=element_action 920 { 921 $code.addAggr("actionsAfterRoot.{el,line,pos}", 922 $act.code, 923 $act.start.getLine(), 924 $act.start.getCharPositionInLine() + 1 925 ); 926 } 927 )* 928 ( el=element[null,null] 929 { 930 $code.addAggr("children.{el,line,pos}", 931 $el.code, 932 $el.start.getLine(), 933 $el.start.getCharPositionInLine() + 1 934 ); 935 } 936 )* 937 ) 938 ; 939finally { rewriteTreeNestingLevel--; } 940 941atom[GrammarAST scope, GrammarAST label, GrammarAST astSuffix] 942 returns [ST code=null] 943@init 944{ 945 String labelText=null; 946 if ( state.backtracking == 0 ) 947 { 948 if ( label!=null ) 949 { 950 labelText = label.getText(); 951 } 952 if ( grammar.type!=Grammar.LEXER && 953 ($start.getType()==RULE_REF||$start.getType()==TOKEN_REF|| 954 $start.getType()==CHAR_LITERAL||$start.getType()==STRING_LITERAL) ) 955 { 956 Rule encRule = grammar.getRule($start.enclosingRuleName); 957 if ( encRule!=null && encRule.hasRewrite(outerAltNum) && astSuffix!=null ) 958 { 959 ErrorManager.grammarError(ErrorManager.MSG_AST_OP_IN_ALT_WITH_REWRITE, 960 grammar, 961 $start.getToken(), 962 $start.enclosingRuleName, 963 outerAltNum); 964 astSuffix = null; 965 } 966 } 967 } 968} 969 : ^( r=RULE_REF (rarg=ARG_ACTION)? ) 970 { 971 grammar.checkRuleReference(scope, $r, $rarg, currentRuleName); 972 String scopeName = null; 973 if ( scope!=null ) { 974 scopeName = scope.getText(); 975 } 976 Rule rdef = grammar.getRule(scopeName, $r.text); 977 // don't insert label=r() if $label.attr not used, no ret value, ... 978 if ( !rdef.getHasReturnValue() ) { 979 labelText = null; 980 } 981 $code = getRuleElementST("ruleRef", $r.text, $r, astSuffix, labelText); 982 $code.add("rule", rdef); 983 if ( scope!=null ) { // scoped rule ref 984 Grammar scopeG = grammar.composite.getGrammar(scope.getText()); 985 $code.add("scope", scopeG); 986 } 987 else if ( rdef.grammar != this.grammar ) { // nonlocal 988 // if rule definition is not in this grammar, it's nonlocal 989 List<Grammar> rdefDelegates = rdef.grammar.getDelegates(); 990 if ( rdefDelegates.contains(this.grammar) ) { 991 $code.add("scope", rdef.grammar); 992 } 993 else { 994 // defining grammar is not a delegate, scope all the 995 // back to root, which has delegate methods for all 996 // rules. Don't use scope if we are root. 997 if ( this.grammar != rdef.grammar.composite.delegateGrammarTreeRoot.grammar ) { 998 $code.add("scope", 999 rdef.grammar.composite.delegateGrammarTreeRoot.grammar); 1000 } 1001 } 1002 } 1003 1004 if ( $rarg!=null ) { 1005 List<? extends Object> args = generator.translateAction(currentRuleName,$rarg); 1006 $code.add("args", args); 1007 } 1008 int i = ((CommonToken)r.getToken()).getTokenIndex(); 1009 $code.add("elementIndex", i); 1010 generator.generateLocalFOLLOW($r,$r.text,currentRuleName,i); 1011 $r.code = $code; 1012 } 1013 1014 | ^( t=TOKEN_REF (targ=ARG_ACTION)? ) 1015 { 1016 if ( currentAltHasASTRewrite && $t.terminalOptions!=null && 1017 $t.terminalOptions.get(Grammar.defaultTokenOption)!=null ) 1018 { 1019 ErrorManager.grammarError(ErrorManager.MSG_HETERO_ILLEGAL_IN_REWRITE_ALT, 1020 grammar, 1021 $t.getToken(), 1022 $t.text); 1023 } 1024 grammar.checkRuleReference(scope, $t, $targ, currentRuleName); 1025 if ( grammar.type==Grammar.LEXER ) 1026 { 1027 if ( grammar.getTokenType($t.text)==Label.EOF ) 1028 { 1029 $code = templates.getInstanceOf("lexerMatchEOF"); 1030 } 1031 else 1032 { 1033 $code = templates.getInstanceOf("lexerRuleRef"); 1034 if ( isListLabel(labelText) ) 1035 { 1036 $code = templates.getInstanceOf("lexerRuleRefAndListLabel"); 1037 } 1038 String scopeName = null; 1039 if ( scope!=null ) 1040 { 1041 scopeName = scope.getText(); 1042 } 1043 Rule rdef2 = grammar.getRule(scopeName, $t.text); 1044 $code.add("rule", rdef2); 1045 if ( scope!=null ) 1046 { // scoped rule ref 1047 Grammar scopeG = grammar.composite.getGrammar(scope.getText()); 1048 $code.add("scope", scopeG); 1049 } 1050 else if ( rdef2.grammar != this.grammar ) 1051 { // nonlocal 1052 // if rule definition is not in this grammar, it's nonlocal 1053 $code.add("scope", rdef2.grammar); 1054 } 1055 if ( $targ!=null ) 1056 { 1057 List<? extends Object> args = generator.translateAction(currentRuleName,$targ); 1058 $code.add("args", args); 1059 } 1060 } 1061 int i = ((CommonToken)$t.getToken()).getTokenIndex(); 1062 $code.add("elementIndex", i); 1063 if ( label!=null ) 1064 $code.add("label", labelText); 1065 } 1066 else 1067 { 1068 $code = getTokenElementST("tokenRef", $t.text, $t, astSuffix, labelText); 1069 String tokenLabel = 1070 generator.getTokenTypeAsTargetLabel(grammar.getTokenType(t.getText())); 1071 $code.add("token",tokenLabel); 1072 if ( !currentAltHasASTRewrite && $t.terminalOptions!=null ) 1073 { 1074 $code.add("terminalOptions", $t.terminalOptions); 1075 } 1076 int i = ((CommonToken)$t.getToken()).getTokenIndex(); 1077 $code.add("elementIndex", i); 1078 generator.generateLocalFOLLOW($t,tokenLabel,currentRuleName,i); 1079 } 1080 $t.code = $code; 1081 } 1082 1083 | c=CHAR_LITERAL 1084 { 1085 if ( grammar.type==Grammar.LEXER ) 1086 { 1087 $code = templates.getInstanceOf("charRef"); 1088 $code.add("char", 1089 generator.target.getTargetCharLiteralFromANTLRCharLiteral(generator,$c.text)); 1090 if ( label!=null ) 1091 { 1092 $code.add("label", labelText); 1093 } 1094 } 1095 else { // else it's a token type reference 1096 $code = getTokenElementST("tokenRef", "char_literal", $c, astSuffix, labelText); 1097 String tokenLabel = generator.getTokenTypeAsTargetLabel(grammar.getTokenType($c.text)); 1098 $code.add("token",tokenLabel); 1099 if ( $c.terminalOptions!=null ) { 1100 $code.add("terminalOptions",$c.terminalOptions); 1101 } 1102 int i = ((CommonToken)$c.getToken()).getTokenIndex(); 1103 $code.add("elementIndex", i); 1104 generator.generateLocalFOLLOW($c,tokenLabel,currentRuleName,i); 1105 } 1106 } 1107 1108 | s=STRING_LITERAL 1109 { 1110 int i = ((CommonToken)$s.getToken()).getTokenIndex(); 1111 if ( grammar.type==Grammar.LEXER ) 1112 { 1113 $code = templates.getInstanceOf("lexerStringRef"); 1114 $code.add("string", 1115 generator.target.getTargetStringLiteralFromANTLRStringLiteral(generator,$s.text)); 1116 $code.add("elementIndex", i); 1117 if ( label!=null ) 1118 { 1119 $code.add("label", labelText); 1120 } 1121 } 1122 else 1123 { 1124 // else it's a token type reference 1125 $code = getTokenElementST("tokenRef", "string_literal", $s, astSuffix, labelText); 1126 String tokenLabel = 1127 generator.getTokenTypeAsTargetLabel(grammar.getTokenType($s.text)); 1128 $code.add("token",tokenLabel); 1129 if ( $s.terminalOptions!=null ) 1130 { 1131 $code.add("terminalOptions",$s.terminalOptions); 1132 } 1133 $code.add("elementIndex", i); 1134 generator.generateLocalFOLLOW($s,tokenLabel,currentRuleName,i); 1135 } 1136 } 1137 1138 | w=WILDCARD 1139 { 1140 $code = getWildcardST($w,astSuffix,labelText); 1141 $code.add("elementIndex", ((CommonToken)$w.getToken()).getTokenIndex()); 1142 } 1143 1144 | ^(DOT ID a=atom[$ID, label, astSuffix]) // scope override on rule or token 1145 { $code = $a.code; } 1146 1147 | set[label,astSuffix] 1148 { $code = $set.code; } 1149 ; 1150 1151ast_suffix 1152 : ROOT 1153 | BANG 1154 ; 1155 1156set[GrammarAST label, GrammarAST astSuffix] returns [ST code=null] 1157@init 1158{ 1159 String labelText=null; 1160 if ( $label!=null ) 1161 { 1162 labelText = $label.getText(); 1163 } 1164} 1165 : ^(s=BLOCK .*) // only care that it's a BLOCK with setValue!=null 1166 { 1167 $code = getTokenElementST("matchSet", "set", $s, astSuffix, labelText); 1168 int i = ((CommonToken)$s.getToken()).getTokenIndex(); 1169 $code.add("elementIndex", i); 1170 if ( grammar.type!=Grammar.LEXER ) 1171 { 1172 generator.generateLocalFOLLOW($s,"set",currentRuleName,i); 1173 } 1174 $code.add("s", generator.genSetExpr(templates,$s.getSetValue(),1,false)); 1175 } 1176 ; 1177 1178setElement 1179 : CHAR_LITERAL 1180 | TOKEN_REF 1181 | STRING_LITERAL 1182 | ^(CHAR_RANGE CHAR_LITERAL CHAR_LITERAL) 1183 ; 1184 1185// REWRITE stuff 1186 1187rewrite returns [ST code=null] 1188@init 1189{ 1190 if ( state.backtracking == 0 ) 1191 { 1192 if ( $start.getType()==REWRITES ) 1193 { 1194 if ( generator.grammar.buildTemplate() ) 1195 { 1196 $code = templates.getInstanceOf("rewriteTemplate"); 1197 } 1198 else 1199 { 1200 $code = templates.getInstanceOf("rewriteCode"); 1201 $code.add("treeLevel", OUTER_REWRITE_NESTING_LEVEL); 1202 $code.add("rewriteBlockLevel", OUTER_REWRITE_NESTING_LEVEL); 1203 $code.add("referencedElementsDeep", 1204 getTokenTypesAsTargetLabels($start.rewriteRefsDeep)); 1205 Set<String> tokenLabels = 1206 grammar.getLabels($start.rewriteRefsDeep, Grammar.TOKEN_LABEL); 1207 Set<String> tokenListLabels = 1208 grammar.getLabels($start.rewriteRefsDeep, Grammar.TOKEN_LIST_LABEL); 1209 Set<String> ruleLabels = 1210 grammar.getLabels($start.rewriteRefsDeep, Grammar.RULE_LABEL); 1211 Set<String> ruleListLabels = 1212 grammar.getLabels($start.rewriteRefsDeep, Grammar.RULE_LIST_LABEL); 1213 Set<String> wildcardLabels = 1214 grammar.getLabels($start.rewriteRefsDeep, Grammar.WILDCARD_TREE_LABEL); 1215 Set<String> wildcardListLabels = 1216 grammar.getLabels($start.rewriteRefsDeep, Grammar.WILDCARD_TREE_LIST_LABEL); 1217 // just in case they ref $r for "previous value", make a stream 1218 // from retval.tree 1219 ST retvalST = templates.getInstanceOf("prevRuleRootRef"); 1220 ruleLabels.add(retvalST.render()); 1221 $code.add("referencedTokenLabels", tokenLabels); 1222 $code.add("referencedTokenListLabels", tokenListLabels); 1223 $code.add("referencedRuleLabels", ruleLabels); 1224 $code.add("referencedRuleListLabels", ruleListLabels); 1225 $code.add("referencedWildcardLabels", wildcardLabels); 1226 $code.add("referencedWildcardListLabels", wildcardListLabels); 1227 } 1228 } 1229 else 1230 { 1231 $code = templates.getInstanceOf("noRewrite"); 1232 $code.add("treeLevel", OUTER_REWRITE_NESTING_LEVEL); 1233 $code.add("rewriteBlockLevel", OUTER_REWRITE_NESTING_LEVEL); 1234 } 1235 } 1236} 1237 : ^( REWRITES 1238 ( 1239 {rewriteRuleRefs = new HashSet<Object>();} 1240 ^( r=REWRITE (pred=SEMPRED)? alt=rewrite_alternative) 1241 { 1242 rewriteBlockNestingLevel = OUTER_REWRITE_NESTING_LEVEL; 1243 List<? extends Object> predChunks = null; 1244 if ( $pred!=null ) 1245 { 1246 //predText = #pred.getText(); 1247 predChunks = generator.translateAction(currentRuleName,$pred); 1248 } 1249 String description = 1250 grammar.grammarTreeToString($r,false); 1251 description = generator.target.getTargetStringLiteralFromString(description); 1252 $code.addAggr("alts.{pred,alt,description}", 1253 predChunks, 1254 alt, 1255 description); 1256 pred=null; 1257 } 1258 )* 1259 ) 1260 | 1261 ; 1262 1263rewrite_block[String blockTemplateName] returns [ST code=null] 1264@init 1265{ 1266 rewriteBlockNestingLevel++; 1267 ST save_currentBlockST = currentBlockST; 1268 if ( state.backtracking == 0 ) 1269 { 1270 $code = templates.getInstanceOf(blockTemplateName); 1271 currentBlockST = $code; 1272 $code.add("rewriteBlockLevel", rewriteBlockNestingLevel); 1273 } 1274} 1275 : ^( BLOCK 1276 { 1277 currentBlockST.add("referencedElementsDeep", 1278 getTokenTypesAsTargetLabels($BLOCK.rewriteRefsDeep)); 1279 currentBlockST.add("referencedElements", 1280 getTokenTypesAsTargetLabels($BLOCK.rewriteRefsShallow)); 1281 } 1282 alt=rewrite_alternative 1283 EOB 1284 ) 1285 { 1286 $code.add("alt", $alt.code); 1287 } 1288 ; 1289finally { rewriteBlockNestingLevel--; currentBlockST = save_currentBlockST; } 1290 1291rewrite_alternative returns [ST code=null] 1292 : {generator.grammar.buildAST()}? 1293 ^( a=ALT {$code=templates.getInstanceOf("rewriteElementList");} 1294 ( ( 1295 el=rewrite_element 1296 {$code.addAggr("elements.{el,line,pos}", 1297 $el.code, 1298 $el.start.getLine(), 1299 $el.start.getCharPositionInLine() + 1 1300 ); 1301 } 1302 )+ 1303 | EPSILON 1304 {$code.addAggr("elements.{el,line,pos}", 1305 templates.getInstanceOf("rewriteEmptyAlt"), 1306 $a.getLine(), 1307 $a.getCharPositionInLine() + 1 1308 ); 1309 } 1310 ) 1311 EOA 1312 ) 1313 1314 | {generator.grammar.buildTemplate()}? rewrite_template 1315 { $code = $rewrite_template.code; } 1316 1317 | // reproduce same input (only AST at moment) 1318 ETC 1319 ; 1320 1321rewrite_element returns [ST code=null] 1322@init 1323{ 1324 IntSet elements=null; 1325 GrammarAST ast = null; 1326} 1327 : rewrite_atom[false] 1328 { $code = $rewrite_atom.code; } 1329 | rewrite_ebnf 1330 { $code = $rewrite_ebnf.code; } 1331 | rewrite_tree 1332 { $code = $rewrite_tree.code; } 1333 ; 1334 1335rewrite_ebnf returns [ST code=null] 1336 : ^( OPTIONAL rewrite_block["rewriteOptionalBlock"] ) 1337 { $code = $rewrite_block.code; } 1338 { 1339 String description = grammar.grammarTreeToString($start, false); 1340 description = generator.target.getTargetStringLiteralFromString(description); 1341 $code.add("description", description); 1342 } 1343 | ^( CLOSURE rewrite_block["rewriteClosureBlock"] ) 1344 { $code = $rewrite_block.code; } 1345 { 1346 String description = grammar.grammarTreeToString($start, false); 1347 description = generator.target.getTargetStringLiteralFromString(description); 1348 $code.add("description", description); 1349 } 1350 | ^( POSITIVE_CLOSURE rewrite_block["rewritePositiveClosureBlock"] ) 1351 { $code = $rewrite_block.code; } 1352 { 1353 String description = grammar.grammarTreeToString($start, false); 1354 description = generator.target.getTargetStringLiteralFromString(description); 1355 $code.add("description", description); 1356 } 1357 ; 1358 1359rewrite_tree returns [ST code] 1360@init 1361{ 1362 rewriteTreeNestingLevel++; 1363 if ( state.backtracking == 0 ) 1364 { 1365 $code = templates.getInstanceOf("rewriteTree"); 1366 $code.add("treeLevel", rewriteTreeNestingLevel); 1367 $code.add("enclosingTreeLevel", rewriteTreeNestingLevel-1); 1368 } 1369} 1370 : ^( TREE_BEGIN 1371 r=rewrite_atom[true] 1372 { 1373 $code.addAggr("root.{el,line,pos}", 1374 $r.code, 1375 $r.start.getLine(), 1376 $r.start.getCharPositionInLine() + 1 1377 ); 1378 } 1379 ( 1380 el=rewrite_element 1381 { 1382 $code.addAggr("children.{el,line,pos}", 1383 $el.code, 1384 $el.start.getLine(), 1385 $el.start.getCharPositionInLine() + 1 1386 ); 1387 } 1388 )* 1389 ) 1390 { 1391 String description = grammar.grammarTreeToString($start, false); 1392 description = generator.target.getTargetStringLiteralFromString(description); 1393 $code.add("description", description); 1394 } 1395 ; 1396finally { rewriteTreeNestingLevel--; } 1397 1398rewrite_atom[boolean isRoot] returns [ST code=null] 1399 : r=RULE_REF 1400 { 1401 String ruleRefName = $r.text; 1402 String stName = "rewriteRuleRef"; 1403 if ( isRoot ) 1404 { 1405 stName += "Root"; 1406 } 1407 $code = templates.getInstanceOf(stName); 1408 $code.add("rule", ruleRefName); 1409 if ( grammar.getRule(ruleRefName)==null ) 1410 { 1411 ErrorManager.grammarError(ErrorManager.MSG_UNDEFINED_RULE_REF, 1412 grammar, 1413 $r.getToken(), 1414 ruleRefName); 1415 $code = new ST(""); // blank; no code gen 1416 } 1417 else if ( grammar.getRule(currentRuleName) 1418 .getRuleRefsInAlt(ruleRefName,outerAltNum)==null ) 1419 { 1420 ErrorManager.grammarError(ErrorManager.MSG_REWRITE_ELEMENT_NOT_PRESENT_ON_LHS, 1421 grammar, 1422 $r.getToken(), 1423 ruleRefName); 1424 $code = new ST(""); // blank; no code gen 1425 } 1426 else 1427 { 1428 // track all rule refs as we must copy 2nd ref to rule and beyond 1429 if ( !rewriteRuleRefs.contains(ruleRefName) ) 1430 { 1431 rewriteRuleRefs.add(ruleRefName); 1432 } 1433 } 1434 } 1435 1436 | 1437 ( ^(tk=TOKEN_REF (arg=ARG_ACTION)?) 1438 | cl=CHAR_LITERAL 1439 | sl=STRING_LITERAL 1440 ) 1441 { 1442 GrammarAST term = $tk; 1443 if (term == null) term = $cl; 1444 if (term == null) term = $sl; 1445 String tokenName = $start.getToken().getText(); 1446 String stName = "rewriteTokenRef"; 1447 Rule rule = grammar.getRule(currentRuleName); 1448 Collection<String> tokenRefsInAlt = rule.getTokenRefsInAlt(outerAltNum); 1449 boolean createNewNode = !tokenRefsInAlt.contains(tokenName) || $arg!=null; 1450 if ( createNewNode ) 1451 { 1452 stName = "rewriteImaginaryTokenRef"; 1453 } 1454 if ( isRoot ) 1455 { 1456 stName += "Root"; 1457 } 1458 $code = templates.getInstanceOf(stName); 1459 if (term.terminalOptions != null) { 1460 $code.add("terminalOptions",term.terminalOptions); 1461 } 1462 if ( $arg!=null ) 1463 { 1464 List<? extends Object> args = generator.translateAction(currentRuleName,$arg); 1465 $code.add("args", args); 1466 } 1467 $code.add("elementIndex", ((CommonToken)$start.getToken()).getTokenIndex()); 1468 int ttype = grammar.getTokenType(tokenName); 1469 String tok = generator.getTokenTypeAsTargetLabel(ttype); 1470 $code.add("token", tok); 1471 if ( grammar.getTokenType(tokenName)==Label.INVALID ) 1472 { 1473 ErrorManager.grammarError(ErrorManager.MSG_UNDEFINED_TOKEN_REF_IN_REWRITE, 1474 grammar, 1475 $start.getToken(), 1476 tokenName); 1477 $code = new ST(""); // blank; no code gen 1478 } 1479 } 1480 1481 | LABEL 1482 { 1483 String labelName = $LABEL.text; 1484 Rule rule = grammar.getRule(currentRuleName); 1485 Grammar.LabelElementPair pair = rule.getLabel(labelName); 1486 if ( labelName.equals(currentRuleName) ) 1487 { 1488 // special case; ref to old value via $ rule 1489 if ( rule.hasRewrite(outerAltNum) && 1490 rule.getRuleRefsInAlt(outerAltNum).contains(labelName) ) 1491 { 1492 ErrorManager.grammarError(ErrorManager.MSG_RULE_REF_AMBIG_WITH_RULE_IN_ALT, 1493 grammar, 1494 $LABEL.getToken(), 1495 labelName); 1496 } 1497 ST labelST = templates.getInstanceOf("prevRuleRootRef"); 1498 $code = templates.getInstanceOf("rewriteRuleLabelRef"+(isRoot?"Root":"")); 1499 $code.add("label", labelST); 1500 } 1501 else if ( pair==null ) 1502 { 1503 ErrorManager.grammarError(ErrorManager.MSG_UNDEFINED_LABEL_REF_IN_REWRITE, 1504 grammar, 1505 $LABEL.getToken(), 1506 labelName); 1507 $code = new ST(""); 1508 } 1509 else 1510 { 1511 String stName = null; 1512 switch ( pair.type ) 1513 { 1514 case Grammar.TOKEN_LABEL : 1515 stName = "rewriteTokenLabelRef"; 1516 break; 1517 case Grammar.WILDCARD_TREE_LABEL : 1518 stName = "rewriteWildcardLabelRef"; 1519 break; 1520 case Grammar.WILDCARD_TREE_LIST_LABEL: 1521 stName = "rewriteRuleListLabelRef"; // acts like rule ref list for ref 1522 break; 1523 case Grammar.RULE_LABEL : 1524 stName = "rewriteRuleLabelRef"; 1525 break; 1526 case Grammar.TOKEN_LIST_LABEL : 1527 stName = "rewriteTokenListLabelRef"; 1528 break; 1529 case Grammar.RULE_LIST_LABEL : 1530 stName = "rewriteRuleListLabelRef"; 1531 break; 1532 } 1533 if ( isRoot ) 1534 { 1535 stName += "Root"; 1536 } 1537 $code = templates.getInstanceOf(stName); 1538 $code.add("label", labelName); 1539 } 1540 } 1541 1542 | ACTION 1543 { 1544 // actions in rewrite rules yield a tree object 1545 String actText = $ACTION.text; 1546 List<? extends Object> chunks = generator.translateAction(currentRuleName,$ACTION); 1547 $code = templates.getInstanceOf("rewriteNodeAction"+(isRoot?"Root":"")); 1548 $code.add("action", chunks); 1549 } 1550 ; 1551 1552public 1553rewrite_template returns [ST code=null] 1554 : ^( ALT EPSILON EOA ) {$code=templates.getInstanceOf("rewriteEmptyTemplate");} 1555 | ^( TEMPLATE (id=ID|ind=ACTION) 1556 { 1557 if ( $id!=null && $id.text.equals("template") ) 1558 { 1559 $code = templates.getInstanceOf("rewriteInlineTemplate"); 1560 } 1561 else if ( $id!=null ) 1562 { 1563 $code = templates.getInstanceOf("rewriteExternalTemplate"); 1564 $code.add("name", $id.text); 1565 } 1566 else if ( $ind!=null ) 1567 { // must be \%({expr})(args) 1568 $code = templates.getInstanceOf("rewriteIndirectTemplate"); 1569 List<? extends Object> chunks=generator.translateAction(currentRuleName,$ind); 1570 $code.add("expr", chunks); 1571 } 1572 } 1573 ^( ARGLIST 1574 ( ^( ARG arg=ID a=ACTION 1575 { 1576 // must set alt num here rather than in define.g 1577 // because actions like \%foo(name={\$ID.text}) aren't 1578 // broken up yet into trees. 1579 $a.outerAltNum = this.outerAltNum; 1580 List<? extends Object> chunks = generator.translateAction(currentRuleName,$a); 1581 $code.addAggr("args.{name,value}", $arg.text, chunks); 1582 } 1583 ) 1584 )* 1585 ) 1586 ( DOUBLE_QUOTE_STRING_LITERAL 1587 { 1588 String sl = $DOUBLE_QUOTE_STRING_LITERAL.text; 1589 String t = sl.substring( 1, sl.length() - 1 ); // strip quotes 1590 t = generator.target.getTargetStringLiteralFromString(t); 1591 $code.add("template",t); 1592 } 1593 | DOUBLE_ANGLE_STRING_LITERAL 1594 { 1595 String sl = $DOUBLE_ANGLE_STRING_LITERAL.text; 1596 String t = sl.substring( 2, sl.length() - 2 ); // strip double angle quotes 1597 t = generator.target.getTargetStringLiteralFromString(t); 1598 $code.add("template",t); 1599 } 1600 )? 1601 ) 1602 1603 | act=ACTION 1604 { 1605 // set alt num for same reason as ARGLIST above 1606 $act.outerAltNum = this.outerAltNum; 1607 $code=templates.getInstanceOf("rewriteAction"); 1608 $code.add("action", 1609 generator.translateAction(currentRuleName,$act)); 1610 } 1611 ; 1612