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