gt:         if (label != null) {
context: package antlr;
  
  /* ANTLR Translator Generator
   * Project led by Terence Parr at http://www.cs.usfca.edu
   * Software rights: http://www.antlr.org/license.html
   *
   * $Id: //depot/code/org.antlr/release/antlr-2.7.7/antlr/MakeGrammar.java#2 $
   */
  
  import antlr.collections.Stack;
  import antlr.collections.impl.LList;
  import antlr.collections.impl.Vector;
  
  public class MakeGrammar extends DefineGrammarSymbols {
  
      protected Stack blocks = new LList(); // track subrules--Stack<BlockContext>
      protected RuleRefElement lastRuleRef;
  
      protected RuleEndElement ruleEnd;   // used if not nested
      protected RuleBlock ruleBlock;		// points to block of current rule.
      protected int nested = 0;			// nesting inside a subrule
      protected boolean grammarError = false;
  
      ExceptionSpec currentExceptionSpec = null;
  
      public MakeGrammar(Tool tool_, String[] args_, LLkAnalyzer analyzer_) {
          super(tool_, args_, analyzer_);
      }
  
      /** Abort the processing of a grammar (due to syntax errors) */
      public void abortGrammar() {
          String s = "unknown grammar";
          if (grammar != null) {
              s = grammar.getClassName();
          }
          tool.error("aborting grammar '" + s + "' due to errors");
          super.abortGrammar();
      }
  
      protected void addElementToCurrentAlt(AlternativeElement e) {
          e.enclosingRuleName = ruleBlock.ruleName;
          context().addAlternativeElement(e);
      }
  
      public void beginAlt(boolean doAutoGen_) {
          super.beginAlt(doAutoGen_);
          Alternative alt = new Alternative();
          alt.setAutoGen(doAutoGen_);
          context().block.addAlternative(alt);
      }
  
      public void beginChildList() {
          super.beginChildList();
          context().block.addAlternative(new Alternative());
      }
  
      /** Add an exception group to a rule (currently a no-op) */
      public void beginExceptionGroup() {
          super.beginExceptionGroup();
          if (!(context().block instanceof RuleBlock)) {
              tool.panic("beginExceptionGroup called outside of rule block");
          }
      }
  
      /** Add an exception spec to an exception group or rule block */
      public void beginExceptionSpec(Token label) {
          // Hack the label string a bit to remove leading/trailing space.
          if (label != null) {
              label.setText(StringUtils.stripFront(StringUtils.stripBack(label.getText(), " \n\r\t"), " \n\r\t"));
          }
          super.beginExceptionSpec(label);
          // Don't check for currentExceptionSpec!=null because syntax errors
          // may leave it set to something.
          currentExceptionSpec = new ExceptionSpec(label);
      }
  
      public void beginSubRule(Token label, Token start, boolean not) {
          super.beginSubRule(label, start, not);
          // we don't know what kind of subrule it is yet.
          // push a dummy one that will allow us to collect the
          // alternatives.  Later, we'll switch to real object.
          blocks.push(new BlockContext());
          context().block = new AlternativeBlock(grammar, start, not);
          context().altNum = 0; // reset alternative number
          nested++;
          // create a final node to which the last elememt of each
          // alternative will point.
          context().blockEnd = new BlockEndElement(grammar);
          // make sure end node points to start of block
          context().blockEnd.block = context().block;
          labelElement(context().block, label);
      }
  
      public void beginTree(Token tok) throws SemanticException {
          if (!(grammar instanceof TreeWalkerGrammar)) {
              tool.error("Trees only allowed in TreeParser", grammar.getFilename(), tok.getLine(), tok.getColumn());
              throw new SemanticException("Trees only allowed in TreeParser");
          }
          super.beginTree(tok);
          blocks.push(new TreeBlockContext());
          context().block = new TreeElement(grammar, tok);
          context().altNum = 0; // reset alternative number
      }
  
      public BlockContext context() {
          if (blocks.height() == 0) {
              return null;
          }
          else {
              return (BlockContext)blocks.top();
          }
      }
  
      /**Used to build nextToken() for the lexer.
       * This builds a rule which has every "public" rule in the given Vector of
       * rules as it's alternate.  Each rule ref generates a Token object.
       * @param g  The Grammar that is being processed
       * @param lexRules A vector of lexer rules that will be used to create an alternate block.
       * @param rname The name of the resulting rule.
       */
      public static RuleBlock createNextTokenRule(Grammar g, Vector lexRules, String rname) {
          // create actual rule data structure
          RuleBlock rb = new RuleBlock(g, rname);
          rb.setDefaultErrorHandler(g.getDefaultErrorHandler());
          RuleEndElement ruleEnd = new RuleEndElement(g);
          rb.setEndElement(ruleEnd);
          ruleEnd.block = rb;
          // Add an alternative for each element of the rules vector.
          for (int i = 0; i < lexRules.size(); i++) {
              RuleSymbol r = (RuleSymbol)lexRules.elementAt(i);
              if (!r.isDefined()) {
                  g.antlrTool.error("Lexer rule " + r.id.substring(1) + " is not defined");
              }
              else {
                  if (r.access.equals("public")) {
  					Alternative alt = new Alternative(); // create alt we'll add to ref rule
  					RuleBlock targetRuleBlock = r.getBlock();
  					Vector targetRuleAlts = targetRuleBlock.getAlternatives();
  					// collect a sem pred if only one alt and it's at the start;
  					// simple, but faster to implement until real hoisting
  					if ( targetRuleAlts!=null && targetRuleAlts.size()==1 ) {
  						Alternative onlyAlt = (Alternative)targetRuleAlts.elementAt(0);
  						if ( onlyAlt.semPred!=null ) {
  							// ok, has sem pred, make this rule ref alt have a pred
  							alt.semPred = onlyAlt.semPred;
  							// REMOVE predicate from target rule???  NOPE, another
  							// rule other than nextToken() might invoke it.
  						}
  					}
  
                      // create a rule ref to lexer rule
                      // the Token is a RULE_REF not a TOKEN_REF since the
                      // conversion to mRulename has already taken place
                      RuleRefElement rr =
                          new RuleRefElement(g,
                                             new CommonToken(ANTLRTokenTypes.RULE_REF, r.getId()),
                                             GrammarElement.AUTO_GEN_NONE);
                      rr.setLabel("theRetToken");
                      rr.enclosingRuleName = "nextToken";
                      rr.next = ruleEnd;
  					alt.addElement(rr);  		// add rule ref to alt
                      alt.setAutoGen(true);		// keep text of elements
                      rb.addAlternative(alt);		// add alt to rule block
                      r.addReference(rr);			// track ref to this rule in rule blk
                  }
              }
          }
  
          rb.setAutoGen(true);		// keep text of elements
          rb.prepareForAnalysis();
          //System.out.println(rb);
          return rb;
      }
  
      /** Return block as if they had typed: "( rule )?" */
      private AlternativeBlock createOptionalRuleRef(String rule, Token start) {
          // Make the subrule
          AlternativeBlock blk = new AlternativeBlock(grammar, start, false);
  
          // Make sure rule is defined
          String mrule = CodeGenerator.encodeLexerRuleName(rule); // can only be a lexer rule!
          if (!grammar.isDefined(mrule)) {
              grammar.define(new RuleSymbol(mrule));
          }
  
          // Make the rule ref element
          // RK: fixme probably easier to abuse start token..
          Token t = new CommonToken(ANTLRTokenTypes.TOKEN_REF, rule);
          t.setLine(start.getLine());
          t.setLine(start.getColumn());
          RuleRefElement rref =
              new RuleRefElement(grammar, t, GrammarElement.AUTO_GEN_NONE);
  
          rref.enclosingRuleName = ruleBlock.ruleName;
  
          // Make the end of block element
          BlockEndElement end = new BlockEndElement(grammar);
          end.block = blk;		// end block points back to start of blk
  
          // Make an alternative, putting the rule ref into it
          Alternative alt = new Alternative(rref);
          alt.addElement(end); // last element in alt points to end of block
  
          // Add the alternative to this block
          blk.addAlternative(alt);
  
          // create an empty (optional) alt and add to blk
          Alternative optAlt = new Alternative();
          optAlt.addElement(end);	// points immediately to end of block
  
          blk.addAlternative(optAlt);
  
          blk.prepareForAnalysis();
          return blk;
      }
  
      public void defineRuleName(Token r,
                                 String access,
                                 boolean ruleAutoGen,
                                 String docComment)
          throws SemanticException {
          //		if ( Character.isUpperCase(r.getText().charAt(0)) ) {
          if (r.type == ANTLRTokenTypes.TOKEN_REF) {
              if (!(grammar instanceof LexerGrammar)) {
                  tool.error("Lexical rule " + r.getText() +
                             " defined outside of lexer",
                             grammar.getFilename(), r.getLine(), r.getColumn());
                  r.setText(r.getText().toLowerCase());
              }
          }
          else {
              if (grammar instanceof LexerGrammar) {
                  tool.error("Lexical rule names must be upper case, '" + r.getText() +
                             "' is not",
                             grammar.getFilename(), r.getLine(), r.getColumn());
                  r.setText(r.getText().toUpperCase());
              }
          }
  
          super.defineRuleName(r, access, ruleAutoGen, docComment);
          String id = r.getText();
          //		if ( Character.isUpperCase(id.charAt(0)) ) { // lexer rule?
          if (r.type == ANTLRTokenTypes.TOKEN_REF) { // lexer rule?
              id = CodeGenerator.encodeLexerRuleName(id);
          }
          RuleSymbol rs = (RuleSymbol)grammar.getSymbol(id);
          RuleBlock rb = new RuleBlock(grammar, r.getText(), r.getLine(), ruleAutoGen);
  
          // Lexer rules do not generate default error handling
          rb.setDefaultErrorHandler(grammar.getDefaultErrorHandler());
  
          ruleBlock = rb;
          blocks.push(new BlockContext()); // enter new context
          context().block = rb;
          rs.setBlock(rb);
          ruleEnd = new RuleEndElement(grammar);
          rb.setEndElement(ruleEnd);
          nested = 0;
      }
  
      public void endAlt() {
          super.endAlt();
          if (nested == 0) {	// all rule-level alts link to ruleEnd node
              addElementToCurrentAlt(ruleEnd);
          }
          else {
              addElementToCurrentAlt(context().blockEnd);
          }
          context().altNum++;
      }
  
      public void endChildList() {
          super.endChildList();
          // create a final node to which the last elememt of the single
          // alternative will point.  Done for compatibility with analyzer.
          // Does NOT point to any block like alternative blocks because the
          // TreeElement is not a block.  This is used only as a placeholder.
          BlockEndElement be = new BlockEndElement(grammar);
          be.block = context().block;
          addElementToCurrentAlt(be);
      }
  
      public void endExceptionGroup() {
          super.endExceptionGroup();
      }
  
      public void endExceptionSpec() {
          super.endExceptionSpec();
          if (currentExceptionSpec == null) {
              tool.panic("exception processing internal error -- no active exception spec");
          }
          if (context().block instanceof RuleBlock) {
              // Named rule
              ((RuleBlock)context().block).addExceptionSpec(currentExceptionSpec);
          }
          else {
              // It must be a plain-old alternative block
              if (context().currentAlt().exceptionSpec != null) {
                  tool.error("Alternative already has an exception specification", grammar.getFilename(), context().block.getLine(), context().block.getColumn());
              }
              else {
                  context().currentAlt().exceptionSpec = currentExceptionSpec;
              }
          }
          currentExceptionSpec = null;
      }
  
      /** Called at the end of processing a grammar */
      public void endGrammar() {
          if (grammarError) {
              abortGrammar();
          }
          else {
              super.endGrammar();
          }
      }
  
      public void endRule(String rule) {
          super.endRule(rule);
          BlockContext ctx = (BlockContext)blocks.pop();	// remove scope
          // record the start of this block in the ending node
          ruleEnd.block = ctx.block;
          ruleEnd.block.prepareForAnalysis();
          //System.out.println(ctx.block);
      }
  
      public void endSubRule() {
          super.endSubRule();
          nested--;
          // remove subrule context from scope stack
          BlockContext ctx = (BlockContext)blocks.pop();
          AlternativeBlock block = ctx.block;
  
          // If the subrule is marked with ~, check that it is
          // a valid candidate for analysis
          if (
              block.not &&
              !(block instanceof SynPredBlock) &&
              !(block instanceof ZeroOrMoreBlock) &&
              !(block instanceof OneOrMoreBlock)
          ) {
              if (!analyzer.subruleCanBeInverted(block, grammar instanceof LexerGrammar)) {
                  String newline = System.getProperty("line.separator");
                  tool.error(
                      "This subrule cannot be inverted.  Only subrules of the form:" + newline +
                      "    (T1|T2|T3...) or" + newline +
                      "    ('c1'|'c2'|'c3'...)" + newline +
                      "may be inverted (ranges are also allowed).",
                      grammar.getFilename(),
                      block.getLine(), block.getColumn()
                  );
              }
          }
  
          // add the subrule as element if not a syn pred
          if (block instanceof SynPredBlock) {
              // record a reference to the recently-recognized syn pred in the
              // enclosing block.
              SynPredBlock synpred = (SynPredBlock)block;
              context().block.hasASynPred = true;
              context().currentAlt().synPred = synpred;
              grammar.hasSyntacticPredicate = true;
              synpred.removeTrackingOfRuleRefs(grammar);
          }
          else {
              addElementToCurrentAlt(block);
          }
          ctx.blockEnd.block.prepareForAnalysis();
      }
  
      public void endTree() {
          super.endTree();
          BlockContext ctx = (BlockContext)blocks.pop();
          addElementToCurrentAlt(ctx.block);		// add new TreeElement to enclosing alt.
      }
  
      /** Remember that a major error occured in the grammar */
      public void hasError() {
          grammarError = true;
      }
  
      private void labelElement(AlternativeElement el, Token label) {
  