xref: /aosp_15_r20/external/antlr/tool/src/main/antlr3/org/antlr/grammar/v3/CodeGenTreeWalker.g (revision 16467b971bd3e2009fad32dd79016f2c7e421deb)
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