1	package antlr;
2	
3	/**
4	 * <b>SOFTWARE RIGHTS</b>
5	 * <p>
6	 * ANTLR 2.5.0 MageLang Institute, 1998
7	 * <p>
8	 * We reserve no legal rights to the ANTLR--it is fully in the
9	 * public domain. An individual or company may do whatever
10	 * they wish with source code distributed with ANTLR or the
11	 * code generated by ANTLR, including the incorporation of
12	 * ANTLR, or its output, into commerical software.
13	 * <p>
14	 * We encourage users to develop software with ANTLR. However,
15	 * we do ask that credit is given to us for developing
16	 * ANTLR. By "credit", we mean that if you use ANTLR or
17	 * incorporate any source code into one of your programs
18	 * (commercial product, research project, or otherwise) that
19	 * you acknowledge this fact somewhere in the documentation,
20	 * research report, etc... If you like ANTLR and have
21	 * developed a nice tool with the output, please mention that
22	 * you developed it using ANTLR. In addition, we ask that the
23	 * headers remain intact in our source code. As long as these
24	 * guidelines are kept, we expect to continue enhancing this
25	 * system and expect to make other tools available as they are
26	 * completed.
27	 * <p>
28	 * The ANTLR gang:
29	 * @version ANTLR 2.5.0 MageLang Institute, 1998
30	 * @author Terence Parr, <a href=http://www.MageLang.com>MageLang Institute</a>
31	 * @author <br>John Lilley, <a href=http://www.Empathy.com>Empathy Software</a>
32	 */
33	import antlr.collections.Stack;
34	import antlr.collections.impl.LList;
35	import antlr.collections.impl.Vector;
36	
37	public class MakeGrammar extends DefineGrammarSymbols {
38	
39		protected Stack blocks = new LList(); // track subrules--Stack<BlockContext>	
40		protected RuleRefElement lastRuleRef;
41	
42		protected RuleEndElement ruleEnd;   // used if not nested
43		protected RuleBlock ruleBlock;		// points to block of current rule.
44		protected int nested = 0;			// nesting inside a subrule
45		protected boolean grammarError = false;
46	
47		ExceptionSpec currentExceptionSpec = null;
48	
49	
50		public MakeGrammar(Tool tool_, String[] args_, LLkAnalyzer analyzer_) {
51			super(tool_, args_, analyzer_);
52		}
53		/** Abort the processing of a grammar (due to syntax errors) */
54		public void abortGrammar() {
55			String s = "unknown grammar";
56			if ( grammar!=null ) {
57				s = grammar.getClassName();
58			}
59			tool.error("aborting grammar '" + s + "' due to errors");
60			super.abortGrammar();
61		}
62		protected void addElementToCurrentAlt(AlternativeElement e) {
63			e.enclosingRuleName = ruleBlock.ruleName;
64			context().addAlternativeElement(e);
65		}
66		public void beginAlt(boolean doAutoGen_) {
67			super.beginAlt(doAutoGen_);
68			Alternative alt = new Alternative();
69			alt.setAutoGen(doAutoGen_);
70			context().block.addAlternative(alt);
71		}
72		public void beginChildList() {
73			super.beginChildList();
74			context().block.addAlternative(new Alternative());
75		}
76		/** Add an exception group to a rule (currently a no-op) */
77		public void beginExceptionGroup() {
78			super.beginExceptionGroup();
79			if (!(context().block instanceof RuleBlock))
80			{
81				tool.panic("beginExceptionGroup called outside of rule block");
82			}
83		}
84		/** Add an exception spec to an exception group or rule block */
85		public void beginExceptionSpec(Token label) {
86			// Hack the label string a bit to remove leading/trailing space.
87			if (label != null) {
88				label.setText( Tool.stripFront( Tool.stripBack(label.getText(), " \n\r\t"), " \n\r\t") );
89			}
90			super.beginExceptionSpec(label);
91			// Don't check for currentExceptionSpec!=null because syntax errors
92			// may leave it set to something.
93			currentExceptionSpec = new ExceptionSpec(label);
94		}
95		public void beginSubRule(Token label, int line, boolean not) {
96			super.beginSubRule(label,line, not);
97			// we don't know what kind of subrule it is yet.
98			// push a dummy one that will allow us to collect the
99			// alternatives.  Later, we'll switch to real object.
100			blocks.push(new BlockContext());
101			context().block = new AlternativeBlock(grammar, line, not);
102			context().altNum = 0; // reset alternative number
103			nested++;
104			// create a final node to which the last elememt of each
105			// alternative will point.
106			context().blockEnd = new BlockEndElement(grammar);
107			// make sure end node points to start of block
108			context().blockEnd.block = context().block;
109			labelElement(context().block, label);
110		}
111		public void beginTree(int line) throws SemanticException {
112			if (!(grammar instanceof TreeWalkerGrammar)) {
113				tool.error("Trees only allowed in TreeParser", line);
114				throw new SemanticException("Trees only allowed in TreeParser");
115			}
116			super.beginTree(line);
117			blocks.push(new TreeBlockContext());
118			context().block = new TreeElement(grammar, line);
119			context().altNum = 0; // reset alternative number
120		}
121		public BlockContext context() {
122			if ( blocks.height()==0 ) {
123				return null;
124			}
125			else {
126				return (BlockContext)blocks.top();
127			}
128		}
129		/**Used to build nextToken() for the lexer.
130		 * This builds a rule which has every "public" rule in the given Vector of
131		 * rules as it's alternate.  Each rule ref generates a Token object
132		 * returned in _returnToken;
133		 * @param g  The Grammar that is being processed
134		 * @param lexRules A vector of lexer rules that will be used to create an alternate block.
135		 * @param rname The name of the resulting rule.
136		 */
137		public static RuleBlock createNextTokenRule(Grammar g, Vector lexRules, String rname) {
138			// create actual rule data structure
139			RuleBlock rb = new RuleBlock(g, rname);
140			RuleEndElement ruleEnd = new RuleEndElement(g);
141			rb.setEndElement(ruleEnd);
142			ruleEnd.block = rb;
143			// Add an alternative for each element of the rules vector.
144			for (int i=0; i<lexRules.size(); i++) {
145				RuleSymbol r = (RuleSymbol)lexRules.elementAt(i);
146				if (!r.isDefined()) {
147					g.tool.error("Lexer rule " + r.id.substring(1) + " is not defined");
148				}
149				else {
150					if ( r.access.equals("public") ) {
151						RuleRefElement rr =	new RuleRefElement(g, new CommonToken(r.getId()), GrammarElement.AUTO_GEN_NONE);
152						//labelElement(rr, new Token("_rettoken"));
153						// rr.setIdAssign("_ttype");
154						rr.setLabel("_rettoken");
155						rr.enclosingRuleName = "nextToken";
156						/*
157						String aStr = "_token = _rettoken;";
158						ActionElement a = new ActionElement(g, new CommonToken(aStr));
159						rr.next = a;
160						a.next = ruleEnd;
161						*/
162						rr.next = ruleEnd;
163						Alternative alt = new Alternative(rr);
164						alt.setAutoGen(true);		// keep text of elements
165						rb.addAlternative(alt);
166						// Add a reference to the rule used for the alt
167						r.addReference(rr);
168					}
169				}
170			}
171			
172			rb.setAutoGen(true);		// keep text of elements
173	
174	/*
175			// Create a reference to EOF
176			RuleRefElement rr =	new RuleRefElement(g, new CommonToken("EOF"), GrammarElement.AUTO_GEN_NONE);
177			rr.setIdAssign("_ttype");
178			rr.next = ruleEnd;
179			rb.addAlternative(new Alternative(rr));
180			// Add a reference to the rule used for the alt
181			// r.addReference(rr);
182	*/
183	
184			rb.prepareForAnalysis();
185			//System.out.println(rb);
186			return rb;
187		}
188		/** Return block as if they had typed: "( rule )?" */
189		private AlternativeBlock createOptionalRuleRef(String rule, int line) {
190			// Make the subrule
191			AlternativeBlock blk = new AlternativeBlock(grammar, line, false);
192			
193			// Make sure rule is defined
194			if ( Character.isUpperCase(rule.charAt(0)) ) { // lexer rule?
195				rule = CodeGenerator.lexerRuleName(rule);
196			}
197			if ( !grammar.isDefined(rule) ) {
198				grammar.define(new RuleSymbol(rule));
199			}
200			
201			// Make the rule ref element
202			RuleRefElement rref = new RuleRefElement(grammar, rule, line, GrammarElement.AUTO_GEN_NONE);
203			rref.enclosingRuleName = ruleBlock.ruleName;
204			
205			// Make the end of block element
206			BlockEndElement end = new BlockEndElement(grammar);
207			end.block = blk;		// end block points back to start of blk
208			
209			// Make an alternative, putting the rule ref into it
210			Alternative alt = new Alternative(rref);
211			alt.addElement(end); // last element in alt points to end of block
212	
213			// Add the alternative to this block
214			blk.addAlternative(alt);
215			
216			// create an empty (optional) alt and add to blk
217			Alternative optAlt = new Alternative();
218			optAlt.addElement(end);	// points immediately to end of block
219			
220			blk.addAlternative(optAlt);
221	
222			blk.prepareForAnalysis();
223			return blk;
224		}
225		public void defineRuleName(Token r, String access, boolean ruleAutoGen, String docComment) throws SemanticException {
226			if ( Character.isUpperCase(r.getText().charAt(0)) ) { 
227				if (!(grammar instanceof LexerGrammar)) {
228					tool.error("Lexical rule defined outside of lexer", r.getLine());
229					throw new SemanticException("Lexical rule defined outside of lexer");
230				}
231			}
232	
233			super.defineRuleName(r, access, ruleAutoGen, docComment);
234			String id = r.getText();
235			if ( Character.isUpperCase(id.charAt(0)) ) { // lexer rule?
236				id = CodeGenerator.lexerRuleName(id);
237			}
238			RuleSymbol rs = (RuleSymbol) grammar.getSymbol(id);
239			RuleBlock rb = new RuleBlock(grammar, r.getText(), r.getLine(), ruleAutoGen);
240	
241			// Lexer rules do not generate default error handling
242			rb.setDefaultErrorHandler(grammar.getDefaultErrorHandler());
243	
244			ruleBlock = rb;
245			blocks.push(new BlockContext()); // enter new context
246			context().block = rb;
247			rs.setBlock(rb);
248			ruleEnd = new RuleEndElement(grammar);
249			rb.setEndElement(ruleEnd);
250			nested = 0;
251		}
252		public void endAlt() {
253			super.endAlt();
254			if ( nested==0 ) {	// all rule-level alts link to ruleEnd node
255				addElementToCurrentAlt(ruleEnd);
256			}
257			else {
258				addElementToCurrentAlt(context().blockEnd);
259			}
260			context().altNum++;
261		}
262		public void endChildList() {
263			super.endChildList();
264			// create a final node to which the last elememt of the single
265			// alternative will point.  Done for compatibility with analyzer.
266			// Does NOT point to any block like alternative blocks because the
267			// TreeElement is not a block.  This is used only as a placeholder.
268			BlockEndElement be = new BlockEndElement(grammar);
269			be.block = context().block;
270			addElementToCurrentAlt(be);
271		}
272		public void endExceptionGroup() {
273			super.endExceptionGroup();
274		}
275		public void endExceptionSpec() {
276			super.endExceptionSpec();
277			if (currentExceptionSpec == null)
278			{
279				tool.panic("exception processing internal error -- no active exception spec");
280			}
281			if (context().block instanceof RuleBlock)
282			{
283				// Named rule
284				((RuleBlock)context().block).addExceptionSpec(currentExceptionSpec);
285			} else {
286				// It must be a plain-old alternative block
287				if (context().currentAlt().exceptionSpec != null) {
288					tool.error("Alternative already has an exception specification", context().block.getLine());
289				}
290				else {
291					context().currentAlt().exceptionSpec = currentExceptionSpec;
292				}
293			}
294			currentExceptionSpec = null;
295		}
296		/** Called at the end of processing a grammar */
297		public void endGrammar() {
298			if (grammarError) {
299				abortGrammar();
300			}
301			else {
302				super.endGrammar();
303			}
304		}
305		public void endRule(String rule) {
306			super.endRule(rule);
307			BlockContext ctx = (BlockContext) blocks.pop();	// remove scope
308			// record the start of this block in the ending node
309			ruleEnd.block = ctx.block;
310			ruleEnd.block.prepareForAnalysis();
311			//System.out.println(ctx.block);
312		}
313		public void endSubRule() {
314			super.endSubRule();
315			nested--;
316			// remove subrule context from scope stack
317			BlockContext ctx = (BlockContext)blocks.pop();
318			AlternativeBlock block = ctx.block;
319	
320			// If the subrule is marked with ~, check that it is
321			// a valid candidate for analysis
322			if (
323				block.not &&
324				!(block instanceof SynPredBlock) &&
325				!(block instanceof ZeroOrMoreBlock) &&
326				!(block instanceof OneOrMoreBlock)
327			)
328			{
329				if (!analyzer.subruleCanBeInverted(block, grammar instanceof LexerGrammar)) {
330					String newline = System.getProperty("line.separator");
331					tool.error(
332						"This subrule cannot be inverted.  Only subrules of the form:"+newline +
333						"    (T1|T2|T3...) or" + newline +
334						"    ('c1'|'c2'|'c3'...)" + newline +
335						"may be inverted (ranges are also allowed).",
336						block.getLine()
337					);
338				}
339			}
340			
341			// add the subrule as element if not a syn pred
342			if ( block instanceof SynPredBlock ) {
343				// record a reference to the recently-recognized syn pred in the
344				// enclosing block.
345				SynPredBlock synpred = (SynPredBlock)block;
346				context().block.hasASynPred = true;
347				context().currentAlt().synPred = synpred;
348				grammar.hasSyntacticPredicate = true;
349				synpred.removeTrackingOfRuleRefs(grammar);
350			}
351			else {
352				addElementToCurrentAlt(block);
353			}
354			ctx.blockEnd.block.prepareForAnalysis();
355		}
356		public void endTree() {
357			super.endTree();
358			BlockContext ctx = (BlockContext) blocks.pop();
359			addElementToCurrentAlt(ctx.block);		// add new TreeElement to enclosing alt.
360		}
361		/** Remember that a major error occured in the grammar */
362		public void hasError() {
363			grammarError = true;
364		}
365		private void labelElement(AlternativeElement el, Token label) {
366			if ( label != null ) {
367				// Does this label already exist?
368				for (int i = 0; i < ruleBlock.labeledElements.size(); i++) {
369					AlternativeElement altEl = (AlternativeElement)ruleBlock.labeledElements.elementAt(i);
370					String l = altEl.getLabel();
371					if (l != null && l.equals(label.getText())) {
372						tool.error("Label '" + label.getText() + "' has already been defined", label.getLine());
373						return;
374					}
375				}
376				// add this node to the list of labeled elements
377				el.setLabel(label.getText());
378				ruleBlock.labeledElements.appendElement(el);
379			}
380		}
381		public void noAutoGenSubRule() {
382			context().block.setAutoGen(false);
383		}
384		public void oneOrMoreSubRule() {
385			if (context().block.not) {
386				tool.error("'~' cannot be applied to (...)* subrule", context().block.getLine());
387			}
388			// create the right kind of object now that we know what that is
389			// and switch the list of alternatives.  Adjust the stack of blocks.
390			// copy any init action also.
391			OneOrMoreBlock b = new OneOrMoreBlock(grammar);
392			setBlock(b,context().block);
393			BlockContext old = (BlockContext)blocks.pop(); // remove old scope; we want new type of subrule
394			blocks.push(new BlockContext());
395			context().block = b;
396			context().blockEnd = old.blockEnd;
397			context().blockEnd.block = b;
398		}
399		public void optionalSubRule() {
400			if (context().block.not) {
401				tool.error("'~' cannot be applied to (...)? subrule", context().block.getLine());
402			}
403			// convert (X)? -> (X|) so that we can ignore optional blocks altogether!
404			// It already thinks that we have a simple subrule, just add option block.
405			beginAlt(false);
406			endAlt();
407		}
408		public void refAction(Token action) {
409			super.refAction(action);
410			context().block.hasAnAction = true;
411			addElementToCurrentAlt(new ActionElement(grammar,action));
412		}
413		// Only called for rule blocks
414		public void refArgAction(Token action) {
415			((RuleBlock)context().block).argAction = action.getText();
416		}
417		public void refCharLiteral(Token lit, Token label, boolean inverted, int autoGenType, boolean lastInRule) {
418			if (!(grammar instanceof LexerGrammar)) {
419				tool.error("Character literal only valid in lexer", lit.getLine());
420				return;
421			}
422			super.refCharLiteral(lit, label, inverted, autoGenType, lastInRule);
423			CharLiteralElement cl = new CharLiteralElement((LexerGrammar)grammar, lit, inverted, autoGenType);
424	
425			// Generate a warning for non-lowercase ASCII when case-insensitive
426			if (
427				!((LexerGrammar)grammar).caseSensitive && cl.tokenType < 128 && 
428				Character.toLowerCase((char)cl.tokenType) != (char)cl.tokenType
429			) {
430				tool.warning("Character literal must be lowercase when caseSensitive=false", lit.getLine());
431			}
432	
433			addElementToCurrentAlt(cl);
434			labelElement(cl, label);
435	
436			// if ignore option is set, must add an optional call to the specified rule.
437			String ignore = ruleBlock.getIgnoreRule();
438			if ( !lastInRule && ignore!=null ) {
439				addElementToCurrentAlt(createOptionalRuleRef(ignore, lit.getLine()));
440			}
441		}
442		public void refCharRange(Token t1, Token t2, Token label, int autoGenType, boolean lastInRule) {
443			if (!(grammar instanceof LexerGrammar)) {
444				tool.error("Character range only valid in lexer", t1.getLine());
445				return;
446			}
447			int rangeMin = ANTLRLexer.tokenTypeForCharLiteral(t1.getText());
448			int rangeMax = ANTLRLexer.tokenTypeForCharLiteral(t2.getText());
449			if (rangeMax < rangeMin) {
450				tool.error("Malformed range.", t1.getLine());
451				return;
452			}
453	
454			// Generate a warning for non-lowercase ASCII when case-insensitive
455			if (!((LexerGrammar)grammar).caseSensitive) {
456				if (rangeMin < 128 && Character.toLowerCase((char)rangeMin) != (char)rangeMin) {
457					tool.warning("Character literal must be lowercase when caseSensitive=false", t1.getLine());
458				}
459				if (rangeMax < 128 && Character.toLowerCase((char)rangeMax) != (char)rangeMax) {
460					tool.warning("Character literal must be lowercase when caseSensitive=false", t2.getLine());
461				}
462			}
463	
464			super.refCharRange(t1, t2, label, autoGenType, lastInRule);
465			CharRangeElement cr = new CharRangeElement((LexerGrammar)grammar, t1, t2, autoGenType);
466			addElementToCurrentAlt(cr);
467			labelElement(cr, label);
468	
469			// if ignore option is set, must add an optional call to the specified rule.
470			String ignore = ruleBlock.getIgnoreRule();
471			if ( !lastInRule && ignore!=null ) {
472				addElementToCurrentAlt(createOptionalRuleRef(ignore, t1.getLine()));
473			}
474		}
475		/** Add an exception handler to an exception spec */
476		public void refExceptionHandler(Token exTypeAndName, String action) {
477			super.refExceptionHandler(exTypeAndName, action);
478			if (currentExceptionSpec == null)
479			{
480				tool.panic("exception handler processing internal error");
481			}
482			currentExceptionSpec.addHandler(new ExceptionHandler(exTypeAndName, action));
483		}
484		public void refInitAction(Token action) {
485			super.refAction(action);
486			context().block.setInitAction(action.getText());
487		}
488		public void refMemberAction(Token act) {
489			grammar.classMemberAction = act.getText();
490		}
491		public void refPreambleAction(Token act) {
492			super.refPreambleAction(act);
493		}
494		// Only called for rule blocks
495		public void refReturnAction(Token returnAction) {
496			if (grammar instanceof LexerGrammar) {
497				String name = CodeGenerator.lexerRuleName(((RuleBlock)context().block).getRuleName());
498				RuleSymbol rs = (RuleSymbol)grammar.getSymbol(name);
499				if (rs.access.equals("public")) {
500					tool.warning("public Lexical rules cannot specify return type", returnAction.getLine());
501					return;
502				}
503			}
504			((RuleBlock)context().block).returnAction = returnAction.getText();
505		}
506		public void refRule(Token idAssign, Token r, Token label, Token args, int autoGenType)
507		{
508			// Disallow parser rule references in the lexer
509			if (grammar instanceof LexerGrammar) {
510				if (!Character.isUpperCase(r.getText().charAt(0))) {
511					tool.error("Parser rule " + r.getText() + " referenced in lexer");
512					return;
513				}
514				if (autoGenType == GrammarElement.AUTO_GEN_CARET) {
515					tool.error("AST specification ^ not allowed in lexer", r.getLine());
516				}
517			}
518	
519			super.refRule(idAssign, r, label, args, autoGenType);
520			lastRuleRef = new RuleRefElement(grammar, r, autoGenType);
521			if (args != null)
522			{
523				lastRuleRef.setArgs(args.getText());
524			}
525			if (idAssign != null)
526			{
527				lastRuleRef.setIdAssign(idAssign.getText());
528			}
529			addElementToCurrentAlt(lastRuleRef);
530	
531			String id = r.getText();
532			if ( Character.isUpperCase(id.charAt(0)) ) { // lexer rule?
533				id = CodeGenerator.lexerRuleName(id);
534			}
535			// update symbol table so it knows what nodes reference the rule.
536			RuleSymbol rs = (RuleSymbol)grammar.getSymbol(id);
537			rs.addReference(lastRuleRef);
538			labelElement(lastRuleRef, label);
539		}
540		public void refSemPred(Token pred) {
541			//System.out.println("refSemPred "+pred.getText());
542			super.refSemPred(pred);
543			//System.out.println("context().block: "+context().block);
544			if ( context().currentAlt().atStart() ) {
545				context().currentAlt().semPred = pred.getText();
546			}
547			else {
548				ActionElement a = new ActionElement(grammar,pred);
549				a.isSemPred = true;
550				addElementToCurrentAlt(a);
551			}
552			//System.out.println("DONE refSemPred "+pred.getText());
553		}
554		public void refStringLiteral(Token lit, Token label, int autoGenType, boolean lastInRule) {
555			super.refStringLiteral(lit, label, autoGenType, lastInRule);
556			if (grammar instanceof TreeWalkerGrammar && autoGenType == GrammarElement.AUTO_GEN_CARET) {
557				tool.error("^ not allowed in here for tree-walker", lit.getLine());
558			}
559			StringLiteralElement sl = new StringLiteralElement(grammar, lit, autoGenType);
560	
561			// If case-insensitive, then check each char of the stirng literal
562			if (grammar instanceof LexerGrammar && !((LexerGrammar)grammar).caseSensitive) {
563				for (int i = 1; i < lit.getText().length()-1; i++) {
564					char c = lit.getText().charAt(i);
565					if (c < 128 && Character.toLowerCase(c) != c) {
566						tool.warning("Characters of string literal must be lowercase when caseSensitive=false", lit.getLine());
567						break;
568					}
569				}
570			}
571	
572			addElementToCurrentAlt(sl);
573			labelElement(sl, label);
574	
575			// if ignore option is set, must add an optional call to the specified rule.
576			String ignore = ruleBlock.getIgnoreRule();
577			if ( !lastInRule && ignore!=null ) {
578				addElementToCurrentAlt(createOptionalRuleRef(ignore, lit.getLine()));
579			}
580		}
581		public void refToken(Token idAssign, Token t, Token label, Token args,
582			boolean inverted, int autoGenType, boolean lastInRule) {
583			if (grammar instanceof LexerGrammar) {
584				// In lexer, token references are really rule references
585				/*
586				if (label != null) {
587					tool.warning("label on token reference in lexer was ignored", t.getLine());
588				}
589				*/
590				if (autoGenType == GrammarElement.AUTO_GEN_CARET) {
591					tool.error("AST specification ^ not allowed in lexer", t.getLine());
592				}
593				if (inverted) {
594					tool.error("~TOKEN is not allowed in lexer", t.getLine());
595				}
596				refRule(idAssign, t, label, args, autoGenType);
597	
598				// if ignore option is set, must add an optional call to the specified token rule.
599				String ignore = ruleBlock.getIgnoreRule();
600				if ( !lastInRule && ignore!=null ) {
601					addElementToCurrentAlt(createOptionalRuleRef(ignore, t.getLine()));
602				}
603			} else {
604				// Cannot have token ref args or assignment outside of lexer
605				if (idAssign!= null)
606				{
607					tool.error("Assignment from token reference only allowed in lexer", idAssign.getLine());
608				}
609				if (args != null)
610				{
611					tool.error("Token reference arguments only allowed in lexer", args.getLine());
612				}
613				super.refToken(idAssign, t, label, args, inverted, autoGenType, lastInRule);
614				TokenRefElement te = new TokenRefElement(grammar, t, inverted, autoGenType);
615				addElementToCurrentAlt(te);
616				labelElement(te, label);
617			}
618		}
619		public void refTokenRange(Token t1, Token t2, Token label, int autoGenType, boolean lastInRule) {
620			if (grammar instanceof LexerGrammar) {
621				tool.error("Token range not allowed in lexer", t1.getLine());
622				return;
623			}
624			TokenRangeElement tr = new TokenRangeElement(grammar, t1, t2, autoGenType);
625			if (tr.end < tr.begin) {
626				tool.error("Malformed range.", t1.getLine());
627				return;
628			}
629			super.refTokenRange(t1, t2, label, autoGenType, lastInRule);
630			addElementToCurrentAlt(tr);
631			labelElement(tr, label);
632		}
633		public void refTreeSpecifier(Token treeSpec) {
634			context().currentAlt().treeSpecifier = treeSpec;
635		}
636		public void refWildcard(Token t, Token label, int autoGenType) {
637			super.refWildcard(t, label, autoGenType);
638			WildcardElement wc = new WildcardElement(grammar, t, autoGenType);
639			addElementToCurrentAlt(wc);
640			labelElement(wc, label);
641		}
642		/** Get ready to process a new grammar */
643		public void reset() {
644			super.reset();
645			blocks = new LList();
646			lastRuleRef = null;
647			ruleEnd = null;
648			ruleBlock = null;
649			nested = 0;
650			currentExceptionSpec = null;
651			grammarError = false;
652		}
653		public void setArgOfRuleRef(Token argAction) {
654			super.setArgOfRuleRef(argAction);
655			lastRuleRef.setArgs(argAction.getText());
656		}
657		public static void setBlock(AlternativeBlock b, AlternativeBlock src) {
658			b.setAlternatives(src.getAlternatives());
659			b.initAction = src.initAction;
660			//b.lookaheadDepth = src.lookaheadDepth;
661			b.label = src.label;
662			b.hasASynPred = src.hasASynPred;
663			b.hasAnAction = src.hasAnAction;
664			b.warnWhenFollowAmbig = src.warnWhenFollowAmbig;
665			b.generateAmbigWarnings = src.generateAmbigWarnings;
666			b.line = src.line;
667		}
668		public void setRuleOption(Token key, Token value) {
669			//((RuleBlock)context().block).setOption(key, value);
670			ruleBlock.setOption(key, value);
671		}
672		public void setSubruleOption(Token key, Token value) {
673			((AlternativeBlock)context().block).setOption(key, value);
674		}
675		public void synPred() {
676			if (context().block.not) {
677				tool.error("'~' cannot be applied to syntactc predicate", context().block.getLine());
678			}
679			// create the right kind of object now that we know what that is
680			// and switch the list of alternatives.  Adjust the stack of blocks.
681			// copy any init action also.
682			SynPredBlock b = new SynPredBlock(grammar);
683			setBlock(b,context().block);
684			BlockContext old = (BlockContext)blocks.pop(); // remove old scope; we want new type of subrule
685			blocks.push(new BlockContext());
686			context().block = b;
687			context().blockEnd = old.blockEnd;
688			context().blockEnd.block = b;
689		}
690		public void zeroOrMoreSubRule() {
691			if (context().block.not) {
692				tool.error("'~' cannot be applied to (...)+ subrule", context().block.getLine());
693			}
694			// create the right kind of object now that we know what that is
695			// and switch the list of alternatives.  Adjust the stack of blocks.
696			// copy any init action also.
697			ZeroOrMoreBlock b = new ZeroOrMoreBlock(grammar);
698			setBlock(b,context().block);
699			BlockContext old = (BlockContext)blocks.pop(); // remove old scope; we want new type of subrule
700			blocks.push(new BlockContext());
701			context().block = b;
702			context().blockEnd = old.blockEnd;
703			context().blockEnd.block = b;
704		}
705	}
706