Package antlr

Source Code of antlr.CppCodeGenerator

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.6/antlr/CppCodeGenerator.java#1 $
*/

// C++ code generator by Pete Wells: pete@yamuna.demon.co.uk
// #line generation contributed by: Ric Klaren <klaren@cs.utwente.nl>

import java.util.Enumeration;
import java.util.Hashtable;
import antlr.collections.impl.BitSet;
import antlr.collections.impl.Vector;
import java.io.PrintWriter; //SAS: changed for proper text file io
import java.io.IOException;
import java.io.FileWriter;

/** Generate MyParser.cpp, MyParser.hpp, MyLexer.cpp, MyLexer.hpp
* and MyParserTokenTypes.hpp
*/
public class CppCodeGenerator extends CodeGenerator {
  boolean DEBUG_CPP_CODE_GENERATOR = false;
  // non-zero if inside syntactic predicate generation
  protected int syntacticPredLevel = 0;

  // Are we generating ASTs (for parsers and tree parsers) right now?
  protected boolean genAST = false;

  // Are we saving the text consumed (for lexers) right now?
  protected boolean saveText = false;

  // Generate #line's
  protected boolean genHashLines = true;
  // Generate constructors or not
  protected boolean noConstructors = false;

  // Used to keep track of lineno in output
  protected int outputLine;
  protected String outputFile;

  // Grammar parameters set up to handle different grammar classes.
  // These are used to get instanceof tests out of code generation
  boolean usingCustomAST = false;
  String labeledElementType;
  String labeledElementASTType; // mostly the same as labeledElementType except in parsers
  String labeledElementASTInit;
  String labeledElementInit;
  String commonExtraArgs;
  String commonExtraParams;
  String commonLocalVars;
  String lt1Value;
  String exceptionThrown;
  String throwNoViable;

  // Tracks the rule being generated.  Used for mapTreeId
  RuleBlock currentRule;
  // Tracks the rule or labeled subrule being generated.  Used for AST generation.
  String currentASTResult;
  // Mapping between the ids used in the current alt, and the
  // names of variables used to represent their AST values.
  Hashtable treeVariableMap = new Hashtable();

  /** Used to keep track of which AST variables have been defined in a rule
   * (except for the #rule_name and #rule_name_in var's
   */
  Hashtable declaredASTVariables = new Hashtable();

  // Count of unnamed generated variables
  int astVarNumber = 1;
  // Special value used to mark duplicate in treeVariableMap
  protected static final String NONUNIQUE = new String();

  public static final int caseSizeThreshold = 127; // ascii is max

  private Vector semPreds;

  // Used to keep track of which (heterogeneous AST types are used)
  // which need to be set in the ASTFactory of the generated parser
  private Vector astTypes;

  private static String namespaceStd   = "ANTLR_USE_NAMESPACE(std)";
  private static String namespaceAntlr = "ANTLR_USE_NAMESPACE(antlr)";
  private static NameSpace nameSpace = null;

  private static final String preIncludeCpp  = "pre_include_cpp";
  private static final String preIncludeHpp  = "pre_include_hpp";
  private static final String postIncludeCpp = "post_include_cpp";
  private static final String postIncludeHpp = "post_include_hpp";

  /** Create a C++ code-generator using the given Grammar.
   * The caller must still call setTool, setBehavior, and setAnalyzer
   * before generating code.
   */
  public CppCodeGenerator() {
    super();
    charFormatter = new CppCharFormatter();
  }
  /** Adds a semantic predicate string to the sem pred vector
      These strings will be used to build an array of sem pred names
      when building a debugging parser.  This method should only be
      called when the debug option is specified
   */
  protected int addSemPred(String predicate) {
    semPreds.appendElement(predicate);
    return semPreds.size()-1;
  }
  public void exitIfError()
  {
    if (antlrTool.hasError())
    {
      antlrTool.fatalError("Exiting due to errors.");
    }
  }
  protected int countLines( String s )
  {
    int lines = 0;
    for( int i = 0; i < s.length(); i++ )
    {
      if( s.charAt(i) == '\n' )
        lines++;
    }
    return lines;
  }
  /** Output a String to the currentOutput stream.
   * Ignored if string is null.
   * @param s The string to output
   */
  protected void _print(String s)
  {
    if (s != null)
    {
      outputLine += countLines(s);
      currentOutput.print(s);
    }
  }
  /** Print an action without leading tabs, attempting to
   * preserve the current indentation level for multi-line actions
   * Ignored if string is null.
   * @param s The action string to output
   */
  protected void _printAction(String s)
  {
    if (s != null)
    {
      outputLine += countLines(s)+1;
      super._printAction(s);
    }
  }
  /** Print an action stored in a token surrounded by #line stuff */
  public void printAction(Token t)
  {
    if (t != null)
    {
      genLineNo(t.getLine());
      printTabs();
      _printAction(processActionForSpecialSymbols(t.getText(), t.getLine(),
                                null, null) );
      genLineNo2();
    }
  }
  /** Print a header action by #line stuff also process any tree construction
   * @param name The name of the header part
   */
  public void printHeaderAction(String name)
  {
    Token a = (antlr.Token)behavior.headerActions.get(name);
    if (a != null)
    {
      genLineNo(a.getLine());
      println(processActionForSpecialSymbols(a.getText(), a.getLine(),
                                null, null) );
      genLineNo2();
    }
  }
  /** Output a String followed by newline, to the currentOutput stream.
   * Ignored if string is null.
   * @param s The string to output
   */
  protected void _println(String s) {
    if (s != null) {
      outputLine += countLines(s)+1;
      currentOutput.println(s);
    }
  }
  /** Output tab indent followed by a String followed by newline,
   * to the currentOutput stream.  Ignored if string is null.
   * @param s The string to output
   */
  protected void println(String s) {
    if (s != null) {
      printTabs();
      outputLine += countLines(s)+1;
      currentOutput.println(s);
    }
  }

  /** Generate a #line or // line depending on options */
  public void genLineNo(int line) {
    if ( line == 0 ) {
      line++;
    }
    if( genHashLines )
      _println("#line "+line+" \""+antlrTool.fileMinusPath(antlrTool.grammarFile)+"\"");
  }

  /** Generate a #line or // line depending on options */
  public void genLineNo(GrammarElement el)
  {
    if( el != null )
      genLineNo(el.getLine());
  }
  /** Generate a #line or // line depending on options */
  public void genLineNo(Token t)
  {
    if (t != null)
      genLineNo(t.getLine());
  }
  /** Generate a #line or // line depending on options */
  public void genLineNo2()
  {
    if( genHashLines )
    {
      _println("#line "+(outputLine+1)+" \""+outputFile+"\"");
    }
  }
  /// Bound safe isDigit
  private boolean charIsDigit( String s, int i )
  {
    return (i < s.length()) && Character.isDigit(s.charAt(i));
  }
  /** Normalize a string coming from antlr's lexer. E.g. translate java
   * escapes to values. Check their size (multibyte) bomb out if they are
   * multibyte (bit crude). Then reescape to C++ style things.
   * Used to generate strings for match() and matchRange()
   * @param lit the literal string
   * @param isCharLiteral if it's for a character literal
   *                       (enforced to be one length) and enclosed in '
   * FIXME: bombing out on mb chars. Should be done in Lexer.
   * FIXME: this is another horrible hack.
   * FIXME: life would be soooo much easier if the stuff from the lexer was
   * normalized in some way.
   */
  private String convertJavaToCppString( String lit, boolean isCharLiteral )
  {
    // System.out.println("convertJavaToCppLiteral: "+lit);
    String ret = new String();
    String s = lit;

    int i = 0;
    int val = 0;

    if( isCharLiteral // verify & strip off quotes
    {
      if( ! lit.startsWith("'") || ! lit.endsWith("'") )
        antlrTool.error("Invalid character literal: '"+lit+"'");
    }
    else
    {
      if( ! lit.startsWith("\"") || ! lit.endsWith("\"") )
        antlrTool.error("Invalid character string: '"+lit+"'");
    }
    s = lit.substring(1,lit.length()-1);

    String prefix="";
    int maxsize = 255;
    if( grammar instanceof LexerGrammar )
    {
      // vocab size seems to be 1 bigger than it actually is
      maxsize = ((LexerGrammar)grammar).charVocabulary.size() - 1;
      if( maxsize > 255 )
        prefix= "L";
    }

    // System.out.println("maxsize "+maxsize+" prefix "+prefix);

    while ( i < s.length() )
    {
      if( s.charAt(i) == '\\' )
      {
        if( s.length() == i+1 )
          antlrTool.error("Invalid escape in char literal: '"+lit+"' looking at '"+s.substring(i)+"'");

        // deal with escaped junk
        switch ( s.charAt(i+1) ) {
        case 'a' :
          val = 7;
          i += 2;
          break;
        case 'b' :
          val = 8;
          i += 2;
          break;
        case 't' :
          val = 9;
          i += 2;
          break;
        case 'n' :
          val = 10;
          i += 2;
          break;
        case 'f' :
          val = 12;
          i += 2;
          break;
        case 'r' :
          val = 13;
          i += 2;
          break;
        case '"' :
        case '\'' :
        case '\\' :
          val = s.charAt(i+1);
          i += 2;
          break;

        case 'u' :
          // Unicode char \u1234
          if( i+5 < s.length() )
          {
            val = Character.digit(s.charAt(i+2), 16) * 16 * 16 * 16 +
              Character.digit(s.charAt(i+3), 16) * 16 * 16 +
              Character.digit(s.charAt(i+4), 16) * 16 +
              Character.digit(s.charAt(i+5), 16);
            i += 6;
          }
          else
            antlrTool.error("Invalid escape in char literal: '"+lit+"' looking at '"+s.substring(i)+"'");
          break;

        case '0' :          // \123
        case '1' :
        case '2' :
        case '3' :
          if( charIsDigit(s, i+2) )
          {
            if( charIsDigit(s, i+3) )
            {
              val = (s.charAt(i+1)-'0')*8*8 + (s.charAt(i+2)-'0')*8 +
                (s.charAt(i+3)-'0');
              i += 4;
            }
            else
            {
              val = (s.charAt(i+1)-'0')*8 + (s.charAt(i+2)-'0');
              i += 3;
            }
          }
          else
          {
            val = s.charAt(i+1)-'0';
            i += 2;
          }
          break;

        case '4' :
        case '5' :
        case '6' :
        case '7' :
          if ( charIsDigit(s, i+2) )
          {
            val = (s.charAt(i+1)-'0')*8 + (s.charAt(i+2)-'0');
            i += 3;
          }
          else
          {
            val = s.charAt(i+1)-'0';
            i += 2;
          }
        default:
          antlrTool.error("Unhandled escape in char literal: '"+lit+"' looking at '"+s.substring(i)+"'");
          val = 0;
        }
      }
      else
        val = s.charAt(i++);

      if( grammar instanceof LexerGrammar )
      {
        if( val > maxsize )      // abort if too big
        {
          String offender;
          if( ( 0x20 <= val ) && ( val < 0x7F ) )
            offender = charFormatter.escapeChar(val,true);
          else
            offender = "0x"+Integer.toString(val,16);

          antlrTool.error("Character out of range in "+(isCharLiteral?"char literal":"string constant")+": '"+s+"'");
          antlrTool.error("Vocabulary size: "+maxsize+" Character "+offender);
        }
      }

      if( isCharLiteral )
      {
        // we should be at end of char literal here..
        if( i != s.length() )
          antlrTool.error("Invalid char literal: '"+lit+"'");

        if( maxsize <= 255 )
        {
          if ( (val <= 255) && (val & 0x80) != 0 )
            // the joys of sign extension in the support lib *cough*
            // actually the support lib needs to be fixed but that's a bit
            // hairy too.
            ret = "static_cast<unsigned char>('"+charFormatter.escapeChar(val,true)+"')";
          else
            ret = "'"+charFormatter.escapeChar(val,true)+"'";
        }
        else
        {
          // so wchar_t is some implementation defined int like thing
          // so this may even lead to having 16 bit or 32 bit cases...
          // I smell some extra grammar options in the future :(
          ret = "L'"+charFormatter.escapeChar(val,true)+"'";
        }
      }
      else
        ret += charFormatter.escapeChar(val,true);
    }
    if( !isCharLiteral )
      ret = prefix+"\""+ret+"\"";
    return ret;
  }
  /** Generate the parser, lexer, treeparser, and token types in C++
   */
  public void gen() {
    // Do the code generation
    try {
      // Loop over all grammars
      Enumeration grammarIter = behavior.grammars.elements();
      while (grammarIter.hasMoreElements()) {
        Grammar g = (Grammar)grammarIter.nextElement();
        if ( g.debuggingOutput ) {
          antlrTool.error(g.getFilename()+": C++ mode does not support -debug");
        }
        // Connect all the components to each other
        g.setGrammarAnalyzer(analyzer);
        g.setCodeGenerator(this);
        analyzer.setGrammar(g);
        // To get right overloading behavior across hetrogeneous grammars
        setupGrammarParameters(g);
        g.generate();
        exitIfError();
      }

      // Loop over all token managers (some of which are lexers)
      Enumeration tmIter = behavior.tokenManagers.elements();
      while (tmIter.hasMoreElements()) {
        TokenManager tm = (TokenManager)tmIter.nextElement();
        if (!tm.isReadOnly()) {
          // Write the token manager tokens as C++
          // this must appear before genTokenInterchange so that
          // labels are set on string literals
          genTokenTypes(tm);
          // Write the token manager tokens as plain text
          genTokenInterchange(tm);
        }
        exitIfError();
      }
    }
    catch (IOException e) {
      antlrTool.reportException(e, null);
    }
  }
  /** Generate code for the given grammar element.
   * @param blk The {...} action to generate
   */
  public void gen(ActionElement action) {
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genAction("+action+")");
    if ( action.isSemPred ) {
      genSemPred(action.actionText, action.line);
    }
    else {
      if ( grammar.hasSyntacticPredicate ) {
        println("if ( inputState->guessing==0 ) {");
        tabs++;
      }

      ActionTransInfo tInfo = new ActionTransInfo();
      String actionStr = processActionForSpecialSymbols(action.actionText,
                                        action.getLine(),
                                        currentRule, tInfo);

      if ( tInfo.refRuleRoot!=null ) {
        // Somebody referenced "#rule", make sure translated var is valid
        // assignment to #rule is left as a ref also, meaning that assignments
        // with no other refs like "#rule = foo();" still forces this code to be
        // generated (unnecessarily).
        println(tInfo.refRuleRoot + " = "+labeledElementASTType+"(currentAST.root);");
      }

      // dump the translated action
      genLineNo(action);
      printAction(actionStr);
      genLineNo2();

      if ( tInfo.assignToRoot ) {
        // Somebody did a "#rule=", reset internal currentAST.root
        println("currentAST.root = "+tInfo.refRuleRoot+";");
        // reset the child pointer too to be last sibling in sibling list
        // now use if else in stead of x ? y : z to shut CC 4.2 up.
        println("if ( "+tInfo.refRuleRoot+"!="+labeledElementASTInit+" &&");
        tabs++;
        println(tInfo.refRuleRoot+"->getFirstChild() != "+labeledElementASTInit+" )");
        println("  currentAST.child = "+tInfo.refRuleRoot+"->getFirstChild();");
          tabs--;
        println("else");
        tabs++;
        println("currentAST.child = "+tInfo.refRuleRoot+";");
        tabs--;
        println("currentAST.advanceChildToEnd();");
      }

      if ( grammar.hasSyntacticPredicate ) {
        tabs--;
        println("}");
      }
    }
  }

  /** Generate code for the given grammar element.
   * @param blk The "x|y|z|..." block to generate
   */
  public void gen(AlternativeBlock blk) {
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("gen("+blk+")");
    println("{");
    genBlockPreamble(blk);
    genBlockInitAction(blk);

    // Tell AST generation to build subrule result
    String saveCurrentASTResult = currentASTResult;
    if (blk.getLabel() != null) {
      currentASTResult = blk.getLabel();
    }

    boolean ok = grammar.theLLkAnalyzer.deterministic(blk);

    CppBlockFinishingInfo howToFinish = genCommonBlock(blk, true);
    genBlockFinish(howToFinish, throwNoViable);

    println("}");

    // Restore previous AST generation
    currentASTResult = saveCurrentASTResult;
  }
  /** Generate code for the given grammar element.
   * @param blk The block-end element to generate.  Block-end
   * elements are synthesized by the grammar parser to represent
   * the end of a block.
   */
  public void gen(BlockEndElement end) {
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genRuleEnd("+end+")");
  }
  /** Generate code for the given grammar element.
   * Only called from lexer grammars.
   * @param blk The character literal reference to generate
   */
  public void gen(CharLiteralElement atom) {
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR )
      System.out.println("genChar("+atom+")");

    if ( ! (grammar instanceof LexerGrammar) )
      antlrTool.error("cannot ref character literals in grammar: "+atom);

    if ( atom.getLabel() != null ) {
      println(atom.getLabel() + " = " + lt1Value + ";");
    }

    boolean oldsaveText = saveText;
    saveText = saveText && atom.getAutoGenType() == GrammarElement.AUTO_GEN_NONE;

    // if in lexer and ! on element, save buffer index to kill later
    if ( !saveText||atom.getAutoGenType()==GrammarElement.AUTO_GEN_BANG )
      println("_saveIndex = text.length();");

    print(atom.not ? "matchNot(" : "match(");
    _print(convertJavaToCppString( atom.atomText, true ));
    _println(" /* charlit */ );");

    if ( !saveText || atom.getAutoGenType() == GrammarElement.AUTO_GEN_BANG )
      println("text.erase(_saveIndex);");      // kill text atom put in buffer

    saveText = oldsaveText;
  }
  /** Generate code for the given grammar element.
   * Only called from lexer grammars.
   * @param blk The character-range reference to generate
   */
  public void gen(CharRangeElement r) {
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR )
      System.out.println("genCharRangeElement("+r.beginText+".."+r.endText+")");

    if ( ! (grammar instanceof LexerGrammar) )
      antlrTool.error("cannot ref character range in grammar: "+r);

    if ( r.getLabel() != null && syntacticPredLevel == 0) {
      println(r.getLabel() + " = " + lt1Value + ";");
    }
    // Correctly take care of saveIndex stuff...
    boolean save = ( grammar instanceof LexerGrammar &&
                ( !saveText ||
                 r.getAutoGenType() == GrammarElement.AUTO_GEN_BANG )
               );
    if (save)
         println("_saveIndex=text.length();");

    println("matchRange("+convertJavaToCppString(r.beginText,true)+
          ","+convertJavaToCppString(r.endText,true)+");");

    if (save)
         println("text.erase(_saveIndex);");
  }
  /** Generate the lexer C++ files */
  public  void gen(LexerGrammar g) throws IOException {
    // If debugging, create a new sempred vector for this grammar
    if (g.debuggingOutput)
      semPreds = new Vector();

    if( g.charVocabulary.size() > 256 )
      antlrTool.warning(g.getFilename()+": Vocabularies of this size still experimental in C++ mode (vocabulary size now: "+g.charVocabulary.size()+")");

    setGrammar(g);
    if (!(grammar instanceof LexerGrammar)) {
      antlrTool.panic("Internal error generating lexer");
    }

    genBody(g);
    genInclude(g);
  }
  /** Generate code for the given grammar element.
   * @param blk The (...)+ block to generate
   */
  public void gen(OneOrMoreBlock blk) {
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("gen+("+blk+")");
    String label;
    String cnt;
    println("{ // ( ... )+");
    genBlockPreamble(blk);
    if ( blk.getLabel() != null ) {
      cnt = "_cnt_"+blk.getLabel();
    }
    else {
      cnt = "_cnt" + blk.ID;
    }
    println("int "+cnt+"=0;");
    if ( blk.getLabel() != null ) {
      label = blk.getLabel();
    }
    else {
      label = "_loop" + blk.ID;
    }

    println("for (;;) {");
    tabs++;
    // generate the init action for ()+ ()* inside the loop
    // this allows us to do usefull EOF checking...
    genBlockInitAction(blk);

    // Tell AST generation to build subrule result
    String saveCurrentASTResult = currentASTResult;
    if (blk.getLabel() != null) {
      currentASTResult = blk.getLabel();
    }

    boolean ok = grammar.theLLkAnalyzer.deterministic(blk);

    // generate exit test if greedy set to false
    // and an alt is ambiguous with exit branch
    // or when lookahead derived purely from end-of-file
    // Lookahead analysis stops when end-of-file is hit,
    // returning set {epsilon}.  Since {epsilon} is not
    // ambig with any real tokens, no error is reported
    // by deterministic() routines and we have to check
    // for the case where the lookahead depth didn't get
    // set to NONDETERMINISTIC (this only happens when the
    // FOLLOW contains real atoms + epsilon).
    boolean generateNonGreedyExitPath = false;
    int nonGreedyExitDepth = grammar.maxk;

    if ( !blk.greedy &&
       blk.exitLookaheadDepth<=grammar.maxk &&
       blk.exitCache[blk.exitLookaheadDepth].containsEpsilon() )
    {
      generateNonGreedyExitPath = true;
      nonGreedyExitDepth = blk.exitLookaheadDepth;
    }
    else if ( !blk.greedy &&
          blk.exitLookaheadDepth==LLkGrammarAnalyzer.NONDETERMINISTIC )
    {
      generateNonGreedyExitPath = true;
    }

    // generate exit test if greedy set to false
    // and an alt is ambiguous with exit branch
    if ( generateNonGreedyExitPath ) {
      if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) {
        System.out.println("nongreedy (...)+ loop; exit depth is "+
                   blk.exitLookaheadDepth);
      }
      String predictExit =
        getLookaheadTestExpression(blk.exitCache,
                       nonGreedyExitDepth);
      println("// nongreedy exit test");
      println("if ( "+cnt+">=1 && "+predictExit+") goto "+label+";");
    }

    CppBlockFinishingInfo howToFinish = genCommonBlock(blk, false);
    genBlockFinish(
      howToFinish,
      "if ( "+cnt+">=1 ) { goto "+label+"; } else {" + throwNoViable + "}"
    );

    println(cnt+"++;");
    tabs--;
    println("}");
    println(label+":;");
    println("}  // ( ... )+");

    // Restore previous AST generation
    currentASTResult = saveCurrentASTResult;
  }
  /** Generate the parser C++ file */
  public void gen(ParserGrammar g) throws IOException {

    // if debugging, set up a new vector to keep track of sempred
    //   strings for this grammar
    if (g.debuggingOutput)
      semPreds = new Vector();

    setGrammar(g);
    if (!(grammar instanceof ParserGrammar)) {
      antlrTool.panic("Internal error generating parser");
    }

    genBody(g);
    genInclude(g);
  }
  /** Generate code for the given grammar element.
   * @param blk The rule-reference to generate
   */
  public void gen(RuleRefElement rr)
  {
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genRR("+rr+")");
    RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
    if (rs == null || !rs.isDefined())
    {
      // Is this redundant???
      antlrTool.error("Rule '" + rr.targetRule + "' is not defined", grammar.getFilename(), rr.getLine(), rr.getColumn());
      return;
    }
    if (!(rs instanceof RuleSymbol))
    {
      // Is this redundant???
      antlrTool.error("'" + rr.targetRule + "' does not name a grammar rule", grammar.getFilename(), rr.getLine(), rr.getColumn());
      return;
    }

    genErrorTryForElement(rr);

    // AST value for labeled rule refs in tree walker.
    // This is not AST construction;  it is just the input tree node value.
    if ( grammar instanceof TreeWalkerGrammar &&
      rr.getLabel() != null &&
      syntacticPredLevel == 0 )
    {
      println(rr.getLabel() + " = (_t == ASTNULL) ? "+labeledElementASTInit+" : "+lt1Value+";");
    }

    // if in lexer and ! on rule ref or alt or rule, save buffer index to
    // kill later
    if ( grammar instanceof LexerGrammar && (!saveText||rr.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) )
    {
      println("_saveIndex = text.length();");
    }

    // Process return value assignment if any
    printTabs();
    if (rr.idAssign != null)
    {
      // Warn if the rule has no return type
      if (rs.block.returnAction == null)
      {
        antlrTool.warning("Rule '" + rr.targetRule + "' has no return type", grammar.getFilename(), rr.getLine(), rr.getColumn());
      }
      _print(rr.idAssign + "=");
    } else {
      // Warn about return value if any, but not inside syntactic predicate
      if ( !(grammar instanceof LexerGrammar) && syntacticPredLevel == 0 && rs.block.returnAction != null)
      {
        antlrTool.warning("Rule '" + rr.targetRule + "' returns a value", grammar.getFilename(), rr.getLine(), rr.getColumn());
      }
    }

    // Call the rule
    GenRuleInvocation(rr);

    // if in lexer and ! on element or alt or rule, save buffer index to kill later
    if ( grammar instanceof LexerGrammar && (!saveText||rr.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
      println("text.erase(_saveIndex);");
    }

    // if not in a syntactic predicate
    if (syntacticPredLevel == 0)
    {
      boolean doNoGuessTest = (
        grammar.hasSyntacticPredicate &&
        (
          grammar.buildAST && rr.getLabel() != null ||
          (genAST && rr.getAutoGenType() == GrammarElement.AUTO_GEN_NONE)
        )
      );

      if (doNoGuessTest) {
        println("if (inputState->guessing==0) {");
        tabs++;
      }

      if (grammar.buildAST && rr.getLabel() != null)
      {
        // always gen variable for rule return on labeled rules
        // RK: hmm do I know here if the returnAST needs a cast ?
        println(rr.getLabel() + "_AST = returnAST;");
      }

      if (genAST)
      {
        switch (rr.getAutoGenType())
        {
        case GrammarElement.AUTO_GEN_NONE:
          if( usingCustomAST )
            println("astFactory->addASTChild(currentAST, "+namespaceAntlr+"RefAST(returnAST));");
          else
            println("astFactory->addASTChild( currentAST, returnAST );");
          break;
        case GrammarElement.AUTO_GEN_CARET:
          // FIXME: RK: I'm not so sure this should be an error..
          // I think it might actually work and be usefull at times.
          antlrTool.error("Internal: encountered ^ after rule reference");
          break;
        default:
          break;
        }
      }

      // if a lexer and labeled, Token label defined at rule level, just set it here
      if ( grammar instanceof LexerGrammar && rr.getLabel() != null )
      {
        println(rr.getLabel()+"=_returnToken;");
      }

      if (doNoGuessTest)
      {
        tabs--;
        println("}");
      }
    }
    genErrorCatchForElement(rr);
  }
  /** Generate code for the given grammar element.
   * @param blk The string-literal reference to generate
   */
  public void gen(StringLiteralElement atom) {
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genString("+atom+")");

    // Variable declarations for labeled elements
    if (atom.getLabel()!=null && syntacticPredLevel == 0) {
      println(atom.getLabel() + " = " + lt1Value + ";");
    }

    // AST
    genElementAST(atom);

    // is there a bang on the literal?
    boolean oldsaveText = saveText;
    saveText = saveText && atom.getAutoGenType()==GrammarElement.AUTO_GEN_NONE;

    // matching
    genMatch(atom);

    saveText = oldsaveText;

    // tack on tree cursor motion if doing a tree walker
    if (grammar instanceof TreeWalkerGrammar) {
      println("_t = _t->getNextSibling();");
    }
  }
  /** Generate code for the given grammar element.
   * @param blk The token-range reference to generate
   */
  public void gen(TokenRangeElement r) {
    genErrorTryForElement(r);
    if ( r.getLabel()!=null  && syntacticPredLevel == 0) {
      println(r.getLabel() + " = " + lt1Value + ";");
    }

    // AST
    genElementAST(r);

    // match
    println("matchRange("+r.beginText+","+r.endText+");");
    genErrorCatchForElement(r);
  }
  /** Generate code for the given grammar element.
   * @param blk The token-reference to generate
   */
  public void gen(TokenRefElement atom) {
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genTokenRef("+atom+")");
    if ( grammar instanceof LexerGrammar ) {
      antlrTool.panic("Token reference found in lexer");
    }
    genErrorTryForElement(atom);
    // Assign Token value to token label variable
    if ( atom.getLabel()!=null && syntacticPredLevel == 0) {
      println(atom.getLabel() + " = " + lt1Value + ";");
    }

    // AST
    genElementAST(atom);
    // matching
    genMatch(atom);
    genErrorCatchForElement(atom);

    // tack on tree cursor motion if doing a tree walker
    if (grammar instanceof TreeWalkerGrammar) {
      println("_t = _t->getNextSibling();");
    }
  }
  public void gen(TreeElement t) {
    // save AST cursor
    println(labeledElementType+" __t" + t.ID + " = _t;");

    // If there is a label on the root, then assign that to the variable
    if (t.root.getLabel() != null) {
      println(t.root.getLabel() + " = (_t == "+labeledElementType+"(ASTNULL)) ? "+labeledElementASTInit+" : _t;");
    }

    // check for invalid modifiers ! and ^ on tree element roots
    if ( t.root.getAutoGenType() == GrammarElement.AUTO_GEN_BANG ) {
      antlrTool.error("Suffixing a root node with '!' is not implemented",
              grammar.getFilename(), t.getLine(), t.getColumn());
      t.root.setAutoGenType(GrammarElement.AUTO_GEN_NONE);
    }
    if ( t.root.getAutoGenType() == GrammarElement.AUTO_GEN_CARET ) {
      antlrTool.warning("Suffixing a root node with '^' is redundant; already a root",
               grammar.getFilename(), t.getLine(), t.getColumn());
      t.root.setAutoGenType(GrammarElement.AUTO_GEN_NONE);
    }

    // Generate AST variables
    genElementAST(t.root);
    if (grammar.buildAST) {
      // Save the AST construction state
      println(namespaceAntlr+"ASTPair __currentAST" + t.ID + " = currentAST;");
      // Make the next item added a child of the TreeElement root
      println("currentAST.root = currentAST.child;");
      println("currentAST.child = "+labeledElementASTInit+";");
    }

    // match root
    if ( t.root instanceof WildcardElement ) {
      println("if ( _t == ASTNULL ) throw "+namespaceAntlr+"MismatchedTokenException();");
    }
    else {
      genMatch(t.root);
    }
    // move to list of children
    println("_t = _t->getFirstChild();");

    // walk list of children, generating code for each
    for (int i=0; i<t.getAlternatives().size(); i++) {
      Alternative a = t.getAlternativeAt(i);
      AlternativeElement e = a.head;
      while ( e != null ) {
        e.generate();
        e = e.next;
      }
    }

    if (grammar.buildAST) {
      // restore the AST construction state to that just after the
      // tree root was added
      println("currentAST = __currentAST" + t.ID + ";");
    }
    // restore AST cursor
    println("_t = __t" + t.ID + ";");
    // move cursor to sibling of tree just parsed
    println("_t = _t->getNextSibling();");
  }
  /** Generate the tree-parser C++ files */
  public void gen(TreeWalkerGrammar g) throws IOException {
    setGrammar(g);
    if (!(grammar instanceof TreeWalkerGrammar)) {
      antlrTool.panic("Internal error generating tree-walker");
    }

    genBody(g);
    genInclude(g);
  }
  /** Generate code for the given grammar element.
   * @param wc The wildcard element to generate
   */
  public void gen(WildcardElement wc) {
    // Variable assignment for labeled elements
    if (wc.getLabel()!=null && syntacticPredLevel == 0) {
      println(wc.getLabel() + " = " + lt1Value + ";");
    }

    // AST
    genElementAST(wc);
    // Match anything but EOF
    if (grammar instanceof TreeWalkerGrammar) {
      println("if ( _t == "+labeledElementASTInit+" ) throw "+namespaceAntlr+"MismatchedTokenException();");
    }
    else if (grammar instanceof LexerGrammar) {
      if ( grammar instanceof LexerGrammar &&
          (!saveText||wc.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
        println("_saveIndex = text.length();");
      }
      println("matchNot(EOF/*_CHAR*/);");
      if ( grammar instanceof LexerGrammar &&
          (!saveText||wc.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
        println("text.erase(_saveIndex);");      // kill text atom put in buffer
      }
    }
    else {
      println("matchNot(" + getValueString(Token.EOF_TYPE) + ");");
    }

    // tack on tree cursor motion if doing a tree walker
    if (grammar instanceof TreeWalkerGrammar) {
      println("_t = _t->getNextSibling();");
    }
  }
  /** Generate code for the given grammar element.
   * @param blk The (...)* block to generate
   */
  public void gen(ZeroOrMoreBlock blk) {
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("gen*("+blk+")");
    println("{ // ( ... )*");
    genBlockPreamble(blk);
    String label;
    if ( blk.getLabel() != null ) {
      label = blk.getLabel();
    }
    else {
      label = "_loop" + blk.ID;
    }
    println("for (;;) {");
    tabs++;
    // generate the init action for ()+ ()* inside the loop
    // this allows us to do usefull EOF checking...
    genBlockInitAction(blk);

    // Tell AST generation to build subrule result
    String saveCurrentASTResult = currentASTResult;
    if (blk.getLabel() != null) {
      currentASTResult = blk.getLabel();
    }

    boolean ok = grammar.theLLkAnalyzer.deterministic(blk);

    // generate exit test if greedy set to false
    // and an alt is ambiguous with exit branch
    // or when lookahead derived purely from end-of-file
    // Lookahead analysis stops when end-of-file is hit,
    // returning set {epsilon}.  Since {epsilon} is not
    // ambig with any real tokens, no error is reported
    // by deterministic() routines and we have to check
    // for the case where the lookahead depth didn't get
    // set to NONDETERMINISTIC (this only happens when the
    // FOLLOW contains real atoms + epsilon).
    boolean generateNonGreedyExitPath = false;
    int nonGreedyExitDepth = grammar.maxk;

    if ( !blk.greedy &&
       blk.exitLookaheadDepth<=grammar.maxk &&
       blk.exitCache[blk.exitLookaheadDepth].containsEpsilon() )
    {
      generateNonGreedyExitPath = true;
      nonGreedyExitDepth = blk.exitLookaheadDepth;
    }
    else if ( !blk.greedy &&
          blk.exitLookaheadDepth==LLkGrammarAnalyzer.NONDETERMINISTIC )
    {
      generateNonGreedyExitPath = true;
    }
    if ( generateNonGreedyExitPath ) {
      if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) {
        System.out.println("nongreedy (...)* loop; exit depth is "+
                   blk.exitLookaheadDepth);
      }
      String predictExit =
        getLookaheadTestExpression(blk.exitCache,
                       nonGreedyExitDepth);
      println("// nongreedy exit test");
      println("if ("+predictExit+") goto "+label+";");
    }

    CppBlockFinishingInfo howToFinish = genCommonBlock(blk, false);
    genBlockFinish(howToFinish, "goto " + label + ";");

    tabs--;
    println("}");
    println(label+":;");
    println("} // ( ... )*");

    // Restore previous AST generation
    currentASTResult = saveCurrentASTResult;
  }
  /** Generate an alternative.
    * @param alt  The alternative to generate
    * @param blk The block to which the alternative belongs
    */
  protected void genAlt(Alternative alt, AlternativeBlock blk)
  {
    // Save the AST generation state, and set it to that of the alt
    boolean savegenAST = genAST;
    genAST = genAST && alt.getAutoGen();

    boolean oldsaveTest = saveText;
    saveText = saveText && alt.getAutoGen();

    // Reset the variable name map for the alternative
    Hashtable saveMap = treeVariableMap;
    treeVariableMap = new Hashtable();

    // Generate try block around the alt for  error handling
    if (alt.exceptionSpec != null) {
      println("try {      // for error handling");
      tabs++;
    }

    AlternativeElement elem = alt.head;
    while ( !(elem instanceof BlockEndElement) ) {
      elem.generate(); // alt can begin with anything. Ask target to gen.
      elem = elem.next;
    }

    if ( genAST)
    {
      if (blk instanceof RuleBlock)
      {
        // Set the AST return value for the rule
        RuleBlock rblk = (RuleBlock)blk;
        if( usingCustomAST )
          println(rblk.getRuleName() + "_AST = "+labeledElementASTType+"(currentAST.root);");
        else
          println(rblk.getRuleName() + "_AST = currentAST.root;");
      }
      else if (blk.getLabel() != null) {
        // ### future: also set AST value for labeled subrules.
        // println(blk.getLabel() + "_AST = "+labeledElementASTType+"(currentAST.root);");
        antlrTool.warning("Labeled subrules are not implemented", grammar.getFilename(), blk.getLine(), blk.getColumn());
      }
    }

    if (alt.exceptionSpec != null)
    {
      // close try block
      tabs--;
      println("}");
      genErrorHandler(alt.exceptionSpec);
    }

    genAST = savegenAST;
    saveText = oldsaveTest;

    treeVariableMap = saveMap;
  }
  /** Generate all the bitsets to be used in the parser or lexer
   * Generate the raw bitset data like "long _tokenSet1_data[] = {...};"
   * and the BitSet object declarations like
   * "BitSet _tokenSet1 = new BitSet(_tokenSet1_data);"
   * Note that most languages do not support object initialization inside a
   * class definition, so other code-generators may have to separate the
   * bitset declarations from the initializations (e.g., put the
   * initializations in the generated constructor instead).
   * @param bitsetList The list of bitsets to generate.
   * @param maxVocabulary Ensure that each generated bitset can contain at
   *        least this value.
   * @param prefix string glued in from of bitset names used for namespace
   *        qualifications.
   */
  protected void genBitsets(
    Vector bitsetList,
    int maxVocabulary,
    String prefix
  )
  {
    TokenManager tm = grammar.tokenManager;

    println("");

    for (int i = 0; i < bitsetList.size(); i++)
    {
      BitSet p = (BitSet)bitsetList.elementAt(i);
      // Ensure that generated BitSet is large enough for vocabulary
      p.growToInclude(maxVocabulary);

      // initialization data
      println(
        "const unsigned long " + prefix + getBitsetName(i) + "_data_" + "[] = { " +
        p.toStringOfHalfWords() +
        " };"
      );

      // Dump the contents of the bitset in readable format...
      String t = "// ";

      for( int j = 0; j < tm.getVocabulary().size(); j++ )
      {
        if ( p.member( j ) )
        {
          if ( (grammar instanceof LexerGrammar) )
          {
            // only dump out for pure printable ascii.
            if( ( 0x20 <= j ) && ( j < 0x7F ) && (j != '\\') )
              t += charFormatter.escapeChar(j,true)+" ";
            else
              t += "0x"+Integer.toString(j,16)+" ";
          }
          else
            t += tm.getTokenStringAt(j)+" ";

          if( t.length() > 70 )
          {
            println(t);
            t = "// ";
          }
        }
      }
      if ( t != "// " )
        println(t);

      // BitSet object
      println(
        "const "+namespaceAntlr+"BitSet " + prefix + getBitsetName(i) + "(" +
        getBitsetName(i) + "_data_," + p.size()/32 +
        ");"
      );
    }
  }
  protected void genBitsetsHeader(
    Vector bitsetList,
    int maxVocabulary
  ) {
    println("");
    for (int i = 0; i < bitsetList.size(); i++)
    {
      BitSet p = (BitSet)bitsetList.elementAt(i);
      // Ensure that generated BitSet is large enough for vocabulary
      p.growToInclude(maxVocabulary);
      // initialization data
      println("static const unsigned long " + getBitsetName(i) + "_data_" + "[];");
      // BitSet object
      println("static const "+namespaceAntlr+"BitSet " + getBitsetName(i) + ";");
    }
  }
  /** Generate the finish of a block, using a combination of the info
   * returned from genCommonBlock() and the action to perform when
   * no alts were taken
   * @param howToFinish The return of genCommonBlock()
   * @param noViableAction What to generate when no alt is taken
   */
  private void genBlockFinish(CppBlockFinishingInfo howToFinish, String noViableAction)
  {
    if (howToFinish.needAnErrorClause &&
       (howToFinish.generatedAnIf || howToFinish.generatedSwitch)) {
      if ( howToFinish.generatedAnIf ) {
        println("else {");
      }
      else {
        println("{");
      }
      tabs++;
      println(noViableAction);
      tabs--;
      println("}");
    }

    if ( howToFinish.postscript!=null ) {
      println(howToFinish.postscript);
    }
  }
  /** Generate the initaction for a block, which may be a RuleBlock or a
   * plain AlternativeBLock.
   * @blk The block for which the preamble is to be generated.
   */
  protected void genBlockInitAction( AlternativeBlock blk )
  {
    // dump out init action
    if ( blk.initAction!=null ) {
      genLineNo(blk);
      printAction(processActionForSpecialSymbols(blk.initAction, blk.line,
                                   currentRule, null) );
      genLineNo2();
    }
  }
  /** Generate the header for a block, which may be a RuleBlock or a
   * plain AlternativeBlock. This generates any variable declarations
   * and syntactic-predicate-testing variables.
   * @blk The block for which the preamble is to be generated.
   */
  protected void genBlockPreamble(AlternativeBlock blk) {
    // define labels for rule blocks.
    if ( blk instanceof RuleBlock ) {
      RuleBlock rblk = (RuleBlock)blk;
      if ( rblk.labeledElements!=null ) {
        for (int i=0; i<rblk.labeledElements.size(); i++) {

          AlternativeElement a = (AlternativeElement)rblk.labeledElements.elementAt(i);
          //System.out.println("looking at labeled element: "+a);
          // Variables for labeled rule refs and subrules are different than
          // variables for grammar atoms.  This test is a little tricky because
          // we want to get all rule refs and ebnf, but not rule blocks or
          // syntactic predicates
          if (
            a instanceof RuleRefElement ||
            a instanceof AlternativeBlock &&
            !(a instanceof RuleBlock) &&
            !(a instanceof SynPredBlock) )
          {
            if ( !(a instanceof RuleRefElement) &&
                ((AlternativeBlock)a).not &&
                analyzer.subruleCanBeInverted(((AlternativeBlock)a), grammar instanceof LexerGrammar)
            ) {
              // Special case for inverted subrules that will be
              // inlined. Treat these like token or char literal
              // references
              println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
              if (grammar.buildAST) {
                genASTDeclaration( a );
              }
            }
            else
            {
              if (grammar.buildAST)
              {
                // Always gen AST variables for labeled elements,
                // even if the element itself is marked with !
                genASTDeclaration( a );
              }
              if ( grammar instanceof LexerGrammar )
                println(namespaceAntlr+"RefToken "+a.getLabel()+";");

              if (grammar instanceof TreeWalkerGrammar) {
                // always generate rule-ref variables for tree walker
                println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
              }
            }
          }
          else
          {
            // It is a token or literal reference.  Generate the
            // correct variable type for this grammar
            println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
            // In addition, generate *_AST variables if building ASTs
            if (grammar.buildAST)
            {
              if (a instanceof GrammarAtom &&
                 ((GrammarAtom)a).getASTNodeType() != null )
              {
                GrammarAtom ga = (GrammarAtom)a;
                genASTDeclaration( a, "Ref"+ga.getASTNodeType() );
              }
              else
              {
                genASTDeclaration( a );
              }
            }
          }
        }
      }
    }
  }
  public void genBody(LexerGrammar g) throws IOException
  {
    outputFile = grammar.getClassName() + ".cpp";
    outputLine = 1;
    currentOutput = antlrTool.openOutputFile(outputFile);
    //SAS: changed for proper text file io

    genAST = false// no way to gen trees.
    saveText = true// save consumed characters.

    tabs=0;

    // Generate header common to all C++ output files
    genHeader(outputFile);

    printHeaderAction(preIncludeCpp);
    // Generate header specific to lexer C++ file
    println("#include \"" + grammar.getClassName() + ".hpp\"");
    println("#include <antlr/CharBuffer.hpp>");
    println("#include <antlr/TokenStreamException.hpp>");
    println("#include <antlr/TokenStreamIOException.hpp>");
    println("#include <antlr/TokenStreamRecognitionException.hpp>");
    println("#include <antlr/CharStreamException.hpp>");
    println("#include <antlr/CharStreamIOException.hpp>");
    println("#include <antlr/NoViableAltForCharException.hpp>");
    if (grammar.debuggingOutput)
      println("#include <antlr/DebuggingInputBuffer.hpp>");
    println("");
    printHeaderAction(postIncludeCpp);

    if (nameSpace != null)
      nameSpace.emitDeclarations(currentOutput);

    // Generate user-defined lexer file preamble
    printAction(grammar.preambleAction);

    // Generate lexer class definition
    String sup=null;
    if ( grammar.superClass!=null ) {
      sup = grammar.superClass;
    }
    else {
      sup = grammar.getSuperClass();
      if (sup.lastIndexOf('.') != -1)
        sup = sup.substring(sup.lastIndexOf('.')+1);
      sup = namespaceAntlr + sup;
    }

    if( noConstructors )
    {
      println("#if 0");
      println("// constructor creation turned of with 'noConstructor' option");
    }
    //
    // Generate the constructor from InputStream
    //
    println(grammar.getClassName() + "::" + grammar.getClassName() + "(" + namespaceStd + "istream& in)");
    tabs++;
    // if debugging, wrap the input buffer in a debugger
    if (grammar.debuggingOutput)
      println(": " + sup + "(new "+namespaceAntlr+"DebuggingInputBuffer(new "+namespaceAntlr+"CharBuffer(in)),"+g.caseSensitive+")");
    else
      println(": " + sup + "(new "+namespaceAntlr+"CharBuffer(in),"+g.caseSensitive+")");
    tabs--;
    println("{");
    tabs++;

    // if debugging, set up array variables and call user-overridable
    //   debugging setup method
    if ( grammar.debuggingOutput ) {
      println("setRuleNames(_ruleNames);");
      println("setSemPredNames(_semPredNames);");
      println("setupDebugging();");
    }

//    println("setCaseSensitive("+g.caseSensitive+");");
    println("initLiterals();");
    tabs--;
    println("}");
    println("");

    // Generate the constructor from InputBuffer
    println(grammar.getClassName() + "::" + grammar.getClassName() + "("+namespaceAntlr+"InputBuffer& ib)");
    tabs++;
    // if debugging, wrap the input buffer in a debugger
    if (grammar.debuggingOutput)
      println(": " + sup + "(new "+namespaceAntlr+"DebuggingInputBuffer(ib),"+g.caseSensitive+")");
    else
      println(": " + sup + "(ib,"+g.caseSensitive+")");
    tabs--;
    println("{");
    tabs++;

    // if debugging, set up array variables and call user-overridable
    //   debugging setup method
    if ( grammar.debuggingOutput ) {
      println("setRuleNames(_ruleNames);");
      println("setSemPredNames(_semPredNames);");
      println("setupDebugging();");
    }

//    println("setCaseSensitive("+g.caseSensitive+");");
    println("initLiterals();");
    tabs--;
    println("}");
    println("");

    // Generate the constructor from LexerSharedInputState
    println(grammar.getClassName() + "::" + grammar.getClassName() + "(const "+namespaceAntlr+"LexerSharedInputState& state)");
    tabs++;
    println(": " + sup + "(state,"+g.caseSensitive+")");
    tabs--;
    println("{");
    tabs++;

    // if debugging, set up array variables and call user-overridable
    //   debugging setup method
    if ( grammar.debuggingOutput ) {
      println("setRuleNames(_ruleNames);");
      println("setSemPredNames(_semPredNames);");
      println("setupDebugging();");
    }

//    println("setCaseSensitive("+g.caseSensitive+");");
    println("initLiterals();");
    tabs--;
    println("}");
    println("");

    if( noConstructors )
    {
      println("// constructor creation turned of with 'noConstructor' option");
      println("#endif");
    }

    println("void " + grammar.getClassName() + "::initLiterals()");
    println("{");
    tabs++;
    // Generate the initialization of the map
    // containing the string literals used in the lexer
    // The literals variable itself is in CharScanner
    Enumeration keys = grammar.tokenManager.getTokenSymbolKeys();
    while ( keys.hasMoreElements() ) {
      String key = (String)keys.nextElement();
      if ( key.charAt(0) != '"' ) {
        continue;
      }
      TokenSymbol sym = grammar.tokenManager.getTokenSymbol(key);
      if ( sym instanceof StringLiteralSymbol ) {
        StringLiteralSymbol s = (StringLiteralSymbol)sym;
        println("literals["+s.getId()+"] = "+s.getTokenType()+";");
      }
    }

    // Generate the setting of various generated options.
    tabs--;
    println("}");

    Enumeration ids;
    // generate the rule name array for debugging
    if (grammar.debuggingOutput) {
      println("const char* "+grammar.getClassName()+"::_ruleNames[] = {");
      tabs++;

      ids = grammar.rules.elements();
      int ruleNum=0;
      while ( ids.hasMoreElements() ) {
        GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
        if ( sym instanceof RuleSymbol)
          println("\""+((RuleSymbol)sym).getId()+"\",");
      }
      println("0");
      tabs--;
      println("};");
    }

    // Generate nextToken() rule.
    // nextToken() is a synthetic lexer rule that is the implicit OR of all
    // user-defined lexer rules.
    genNextToken();

    // Generate code for each rule in the lexer
    ids = grammar.rules.elements();
    int ruleNum=0;
    while ( ids.hasMoreElements() ) {
      RuleSymbol sym = (RuleSymbol) ids.nextElement();
      // Don't generate the synthetic rules
      if (!sym.getId().equals("mnextToken")) {
        genRule(sym, false, ruleNum++, grammar.getClassName() + "::");
      }
      exitIfError();
    }

    // Generate the semantic predicate map for debugging
    if (grammar.debuggingOutput)
      genSemPredMap(grammar.getClassName() + "::");

    // Generate the bitsets used throughout the lexer
    genBitsets(bitsetsUsed, ((LexerGrammar)grammar).charVocabulary.size(), grammar.getClassName() + "::" );

    println("");
    if (nameSpace != null)
      nameSpace.emitClosures(currentOutput);

    // Close the lexer output stream
    currentOutput.close();
    currentOutput = null;
  }
  public void genInitFactory( Grammar g )
  {
    // Generate the method to initialize an ASTFactory when we're
    // building AST's
    String param_name = "factory ";
    if( ! g.buildAST )
      param_name = "";

    println("void "+ g.getClassName() + "::initializeASTFactory( "+namespaceAntlr+"ASTFactory& "+param_name+")");
    println("{");
    tabs++;

    if( g.buildAST )
    {
      // sort out custom AST types... synchronize token manager with token
      // specs on rules (and other stuff we were able to see from
      // action.g) (imperfect of course)
      TokenManager tm = grammar.tokenManager;
      Enumeration tokens = tm.getTokenSymbolKeys();
      while( tokens.hasMoreElements() )
      {
        String tok = (String)tokens.nextElement();
        TokenSymbol ts = tm.getTokenSymbol(tok);
        // if we have a custom type and there's not a more local override
        // of the tokentype then mark this as the type for the tokentype
        if( ts.getASTNodeType() != null )
        {
          // ensure capacity with this pseudo vector...
          astTypes.ensureCapacity(ts.getTokenType());
          String type = (String)astTypes.elementAt(ts.getTokenType());
          if( type == null )
            astTypes.setElementAt(ts.getASTNodeType(),ts.getTokenType());
          else
          {
            // give a warning over action taken if the types are unequal
            if( ! ts.getASTNodeType().equals(type) )
            {
              antlrTool.warning("Token "+tok+" taking most specific AST type",grammar.getFilename(),1,1);
              antlrTool.warning("  using "+type+" ignoring "+ts.getASTNodeType(),grammar.getFilename(),1,1);
            }
          }
        }
      }
      // now actually write out all the registered types. (except the default
      // type.
      for( int i = 0; i < astTypes.size(); i++ )
      {
        String type = (String)astTypes.elementAt(i);
        if( type != null )
        {
          println("factory.registerFactory("+i
              +", \""+type+"\", "+type+"::factory);");
        }
      }
      println("factory.setMaxNodeType("+grammar.tokenManager.maxTokenType()+");");
    }
    tabs--;
    println("}");
  }
  // FIXME: and so why are we passing here a g param while inside
  // we merrily use the global grammar.
  public void genBody(ParserGrammar g) throws IOException
  {
    // Open the output stream for the parser and set the currentOutput
    outputFile = grammar.getClassName() + ".cpp";
    outputLine = 1;
    currentOutput = antlrTool.openOutputFile(outputFile);

    genAST = grammar.buildAST;

    tabs = 0;

    // Generate the header common to all output files.
    genHeader(outputFile);

    printHeaderAction(preIncludeCpp);

    // Generate header for the parser
    println("#include \"" + grammar.getClassName() + ".hpp\"");
    println("#include <antlr/NoViableAltException.hpp>");
    println("#include <antlr/SemanticException.hpp>");
    println("#include <antlr/ASTFactory.hpp>");

    printHeaderAction(postIncludeCpp);

    if (nameSpace != null)
      nameSpace.emitDeclarations(currentOutput);

    // Output the user-defined parser preamble
    printAction(grammar.preambleAction);

    String sup=null;
    if ( grammar.superClass!=null )
      sup = grammar.superClass;
    else {
      sup = grammar.getSuperClass();
      if (sup.lastIndexOf('.') != -1)
        sup = sup.substring(sup.lastIndexOf('.')+1);
      sup = namespaceAntlr + sup;
    }

    // set up an array of all the rule names so the debugger can
    // keep track of them only by number -- less to store in tree...
    if (grammar.debuggingOutput) {
      println("const char* "+grammar.getClassName()+"::_ruleNames[] = {");
      tabs++;

      Enumeration ids = grammar.rules.elements();
      int ruleNum=0;
      while ( ids.hasMoreElements() ) {
        GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
        if ( sym instanceof RuleSymbol)
          println("\""+((RuleSymbol)sym).getId()+"\",");
      }
      println("0");
      tabs--;
      println("};");
    }

    // Generate _initialize function
    // disabled since it isn't used anymore..

//    println("void " + grammar.getClassName() + "::_initialize(void)");
//    println("{");
//    tabs++;

    // if debugging, set up arrays and call the user-overridable
    //   debugging setup method
//    if ( grammar.debuggingOutput ) {
//      println("setRuleNames(_ruleNames);");
//      println("setSemPredNames(_semPredNames);");
//      println("setupDebugging();");
//    }
//    tabs--;
//    println("}");
    if( noConstructors )
    {
      println("#if 0");
      println("// constructor creation turned of with 'noConstructor' option");
    }

    // Generate parser class constructor from TokenBuffer
    print(grammar.getClassName() + "::" + grammar.getClassName());
    println("("+namespaceAntlr+"TokenBuffer& tokenBuf, int k)");
    println(": " + sup + "(tokenBuf,k)");
    println("{");
//    tabs++;
//    println("_initialize();");
//    tabs--;
    println("}");
    println("");

    print(grammar.getClassName() + "::" + grammar.getClassName());
    println("("+namespaceAntlr+"TokenBuffer& tokenBuf)");
    println(": " + sup + "(tokenBuf," + grammar.maxk + ")");
    println("{");
//    tabs++;
//    println("_initialize();");
//    tabs--;
    println("}");
    println("");

    // Generate parser class constructor from TokenStream
    print(grammar.getClassName() + "::" + grammar.getClassName());
    println("("+namespaceAntlr+"TokenStream& lexer, int k)");
    println(": " + sup + "(lexer,k)");
    println("{");
//    tabs++;
//    println("_initialize();");
//    tabs--;
    println("}");
    println("");

    print(grammar.getClassName() + "::" + grammar.getClassName());
    println("("+namespaceAntlr+"TokenStream& lexer)");
    println(": " + sup + "(lexer," + grammar.maxk + ")");
    println("{");
//    tabs++;
//    println("_initialize();");
//    tabs--;
    println("}");
    println("");

    print(grammar.getClassName() + "::" + grammar.getClassName());
    println("(const "+namespaceAntlr+"ParserSharedInputState& state)");
    println(": " + sup + "(state," + grammar.maxk + ")");
    println("{");
//    tabs++;
//    println("_initialize();");
//    tabs--;
    println("}");
    println("");

    if( noConstructors )
    {
      println("// constructor creation turned of with 'noConstructor' option");
      println("#endif");
    }

    astTypes = new Vector();

    // Generate code for each rule in the grammar
    Enumeration ids = grammar.rules.elements();
    int ruleNum=0;
    while ( ids.hasMoreElements() ) {
      GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
      if ( sym instanceof RuleSymbol) {
        RuleSymbol rs = (RuleSymbol)sym;
        genRule(rs, rs.references.size()==0, ruleNum++, grammar.getClassName() + "::");
      }
      exitIfError();
    }

    genInitFactory( g );

    // Generate the token names
    genTokenStrings(grammar.getClassName() + "::");

    // Generate the bitsets used throughout the grammar
    genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType(), grammar.getClassName() + "::" );

    // Generate the semantic predicate map for debugging
    if (grammar.debuggingOutput)
      genSemPredMap(grammar.getClassName() + "::");

    // Close class definition
    println("");
    println("");
    if (nameSpace != null)
      nameSpace.emitClosures(currentOutput);

    // Close the parser output stream
    currentOutput.close();
    currentOutput = null;
  }
  public void genBody(TreeWalkerGrammar g) throws IOException
  {
    // Open the output stream for the parser and set the currentOutput
    outputFile = grammar.getClassName() + ".cpp";
    outputLine = 1;
    currentOutput = antlrTool.openOutputFile(outputFile);
    //SAS: changed for proper text file io

    genAST = grammar.buildAST;
    tabs = 0;

    // Generate the header common to all output files.
    genHeader(outputFile);

    printHeaderAction(preIncludeCpp);

    // Generate header for the parser
    println("#include \"" + grammar.getClassName() + ".hpp\"");
    println("#include <antlr/Token.hpp>");
    println("#include <antlr/AST.hpp>");
    println("#include <antlr/NoViableAltException.hpp>");
    println("#include <antlr/MismatchedTokenException.hpp>");
    println("#include <antlr/SemanticException.hpp>");
    println("#include <antlr/BitSet.hpp>");

    printHeaderAction(postIncludeCpp);

    if (nameSpace != null)
      nameSpace.emitDeclarations(currentOutput);

    // Output the user-defined parser premamble
    printAction(grammar.preambleAction);

    // Generate parser class definition
    String sup = null;
    if ( grammar.superClass!=null ) {
      sup = grammar.superClass;
    }
    else {
      sup = grammar.getSuperClass();
      if (sup.lastIndexOf('.') != -1)
        sup = sup.substring(sup.lastIndexOf('.')+1);
      sup = namespaceAntlr + sup;
    }
    if( noConstructors )
    {
      println("#if 0");
      println("// constructor creation turned of with 'noConstructor' option");
    }

    // Generate default parser class constructor
    println(grammar.getClassName() + "::" + grammar.getClassName() + "()");
    println("\t: "+namespaceAntlr+"TreeParser() {");
    tabs++;
//    println("setTokenNames(_tokenNames);");
    tabs--;
    println("}");

    if( noConstructors )
    {
      println("// constructor creation turned of with 'noConstructor' option");
      println("#endif");
    }
    println("");

    astTypes = new Vector();

    // Generate code for each rule in the grammar
    Enumeration ids = grammar.rules.elements();
    int ruleNum=0;
    String ruleNameInits = "";
    while ( ids.hasMoreElements() ) {
      GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
      if ( sym instanceof RuleSymbol) {
        RuleSymbol rs = (RuleSymbol)sym;
        genRule(rs, rs.references.size()==0, ruleNum++, grammar.getClassName() + "::");
      }
      exitIfError();
    }

    // Generate the ASTFactory initialization function
    genInitFactory( grammar );
    // Generate the token names
    genTokenStrings(grammar.getClassName() + "::");

    // Generate the bitsets used throughout the grammar
    genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType(), grammar.getClassName() + "::" );

    // Close class definition
    println("");
    println("");

    if (nameSpace != null)
      nameSpace.emitClosures(currentOutput);

    // Close the parser output stream
    currentOutput.close();
    currentOutput = null;
  }
  /** Generate a series of case statements that implement a BitSet test.
   * @param p The Bitset for which cases are to be generated
   */
  protected void genCases(BitSet p) {
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genCases("+p+")");
    int[] elems;

    elems = p.toArray();
    // Wrap cases four-per-line for lexer, one-per-line for parser
    int wrap = 1; //(grammar instanceof LexerGrammar) ? 4 : 1;
    int j=1;
    boolean startOfLine = true;
    for (int i = 0; i < elems.length; i++) {
      if (j==1) {
        print("");
      } else {
        _print("  ");
      }
      _print("case " + getValueString(elems[i]) + ":");

      if (j==wrap) {
        _println("");
        startOfLine = true;
        j=1;
      }
      else {
        j++;
        startOfLine = false;
      }
    }
    if (!startOfLine) {
      _println("");
    }
  }
  /** Generate common code for a block of alternatives; return a postscript
   * that needs to be generated at the end of the block.  Other routines
   * may append else-clauses and such for error checking before the postfix
   * is generated.
   * If the grammar is a lexer, then generate alternatives in an order where
   * alternatives requiring deeper lookahead are generated first, and
   * EOF in the lookahead set reduces the depth of the lookahead.
   * @param blk The block to generate
   * @param noTestForSingle If true, then it does not generate a test for a single alternative.
   */
  public CppBlockFinishingInfo genCommonBlock(
    AlternativeBlock blk,
    boolean noTestForSingle )
  {
    int nIF=0;
    boolean createdLL1Switch = false;
    int closingBracesOfIFSequence = 0;
    CppBlockFinishingInfo finishingInfo = new CppBlockFinishingInfo();
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genCommonBlk("+blk+")");

    // Save the AST generation state, and set it to that of the block
    boolean savegenAST = genAST;
    genAST = genAST && blk.getAutoGen();

    boolean oldsaveTest = saveText;
    saveText = saveText && blk.getAutoGen();

    // Is this block inverted?  If so, generate special-case code
    if ( blk.not &&
      analyzer.subruleCanBeInverted(blk, grammar instanceof LexerGrammar) )
    {
      Lookahead p = analyzer.look(1, blk);
      // Variable assignment for labeled elements
      if (blk.getLabel() != null && syntacticPredLevel == 0) {
        println(blk.getLabel() + " = " + lt1Value + ";");
      }

      // AST
      genElementAST(blk);

      String astArgs="";
      if (grammar instanceof TreeWalkerGrammar) {
        if( usingCustomAST )
          astArgs=namespaceAntlr+"RefAST"+"(_t),";
        else
          astArgs="_t,";
      }

      // match the bitset for the alternative
      println("match(" + astArgs + getBitsetName(markBitsetForGen(p.fset)) + ");");

      // tack on tree cursor motion if doing a tree walker
      if (grammar instanceof TreeWalkerGrammar)
      {
        println("_t = _t->getNextSibling();");
      }
      return finishingInfo;
    }

    // Special handling for single alt
    if (blk.getAlternatives().size() == 1)
    {
      Alternative alt = blk.getAlternativeAt(0);
      // Generate a warning if there is a synPred for single alt.
      if (alt.synPred != null)
      {
        antlrTool.warning(
                 "Syntactic predicate superfluous for single alternative",
                 grammar.getFilename(),
                 blk.getAlternativeAt(0).synPred.getLine(),
                 blk.getAlternativeAt(0).synPred.getColumn()
        );
      }
      if (noTestForSingle)
      {
        if (alt.semPred != null)
        {
          // Generate validating predicate
          genSemPred(alt.semPred, blk.line);
        }
        genAlt(alt, blk);
        return finishingInfo;
      }
    }

    // count number of simple LL(1) cases; only do switch for
    // many LL(1) cases (no preds, no end of token refs)
    // We don't care about exit paths for (...)*, (...)+
    // because we don't explicitly have a test for them
    // as an alt in the loop.
    //
    // Also, we now count how many unicode lookahead sets
    // there are--they must be moved to DEFAULT or ELSE
    // clause.

    int nLL1 = 0;
    for (int i=0; i<blk.getAlternatives().size(); i++)
    {
      Alternative a = blk.getAlternativeAt(i);
      if ( suitableForCaseExpression(a) )
        nLL1++;
    }

    // do LL(1) cases
    if ( nLL1 >= makeSwitchThreshold )
    {
      // Determine the name of the item to be compared
      String testExpr = lookaheadString(1);
      createdLL1Switch = true;
      // when parsing trees, convert null to valid tree node with NULL lookahead
      if ( grammar instanceof TreeWalkerGrammar )
      {
        println("if (_t == "+labeledElementASTInit+" )");
        tabs++;
        println("_t = ASTNULL;");
        tabs--;
      }
      println("switch ( "+testExpr+") {");
      for (int i=0; i<blk.alternatives.size(); i++)
      {
        Alternative alt = blk.getAlternativeAt(i);
        // ignore any non-LL(1) alts, predicated alts or end-of-token alts
        // or end-of-token alts for case expressions
        if ( !suitableForCaseExpression(alt) )
        {
          continue;
        }
        Lookahead p = alt.cache[1];
        if (p.fset.degree() == 0 && !p.containsEpsilon())
        {
          antlrTool.warning("Alternate omitted due to empty prediction set",
            grammar.getFilename(),
            alt.head.getLine(), alt.head.getColumn());
        }
        else
        {
          genCases(p.fset);
          println("{");
          tabs++;
          genAlt(alt, blk);
          println("break;");
          tabs--;
          println("}");
        }
      }
      println("default:");
      tabs++;
    }

    // do non-LL(1) and nondeterministic cases
    // This is tricky in the lexer, because of cases like:
    //     STAR : '*' ;
    //     ASSIGN_STAR : "*=";
    // Since nextToken is generated without a loop, then the STAR will
    // have end-of-token as it's lookahead set for LA(2).  So, we must generate the
    // alternatives containing trailing end-of-token in their lookahead sets *after*
    // the alternatives without end-of-token.  This implements the usual
    // lexer convention that longer matches come before shorter ones, e.g.
    // "*=" matches ASSIGN_STAR not STAR
    //
    // For non-lexer grammars, this does not sort the alternates by depth
    // Note that alts whose lookahead is purely end-of-token at k=1 end up
    // as default or else clauses.
    int startDepth = (grammar instanceof LexerGrammar) ? grammar.maxk : 0;
    for (int altDepth = startDepth; altDepth >= 0; altDepth--) {
      if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("checking depth "+altDepth);
      for (int i=0; i<blk.alternatives.size(); i++) {
        Alternative alt = blk.getAlternativeAt(i);
        if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genAlt: "+i);
        // if we made a switch above, ignore what we already took care
        // of.  Specifically, LL(1) alts with no preds
        // that do not have end-of-token in their prediction set
        if ( createdLL1Switch &&
           suitableForCaseExpression(alt) )
        {
          if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR )
            System.out.println("ignoring alt because it was in the switch");
          continue;
        }
        String e;

        boolean unpredicted = false;

        if (grammar instanceof LexerGrammar) {
          // Calculate the "effective depth" of the alt, which is the max
          // depth at which cache[depth]!=end-of-token
          int effectiveDepth = alt.lookaheadDepth;
          if (effectiveDepth == GrammarAnalyzer.NONDETERMINISTIC)
          {
            // use maximum lookahead
            effectiveDepth = grammar.maxk;
          }
          while ( effectiveDepth >= 1 &&
               alt.cache[effectiveDepth].containsEpsilon() )
          {
            effectiveDepth--;
          }
          // Ignore alts whose effective depth is other than the ones we
          // are generating for this iteration.
          if (effectiveDepth != altDepth)
          {
            if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR )
              System.out.println("ignoring alt because effectiveDepth!=altDepth;"+effectiveDepth+"!="+altDepth);
            continue;
          }
          unpredicted = lookaheadIsEmpty(alt, effectiveDepth);
          e = getLookaheadTestExpression(alt, effectiveDepth);
        }
        else
        {
          unpredicted = lookaheadIsEmpty(alt, grammar.maxk);
          e = getLookaheadTestExpression(alt, grammar.maxk);
        }

        // Was it a big unicode range that forced unsuitability
        // for a case expression?
        if ( alt.cache[1].fset.degree() > caseSizeThreshold &&
            suitableForCaseExpression(alt))
        {
          if ( nIF==0 )
          {
            // generate this only for the first if the elseif's
            // are covered by this one
            if ( grammar instanceof TreeWalkerGrammar ) {
              println("if (_t == "+labeledElementASTInit+" )");
              tabs++;
              println("_t = ASTNULL;");
              tabs--;
            }
            println("if " + e + " {");
          }
          else
            println("else if " + e + " {");
        }
        else if (unpredicted &&
              alt.semPred==null &&
              alt.synPred==null)
        {
          // The alt has empty prediction set and no
          // predicate to help out.  if we have not
          // generated a previous if, just put {...} around
          // the end-of-token clause
          if ( nIF==0 ) {
            println("{");
          }
          else {
            println("else {");
          }
          finishingInfo.needAnErrorClause = false;
        }
        else
        {
          // check for sem and syn preds
          // Add any semantic predicate expression to the lookahead test
          if ( alt.semPred != null ) {
            // if debugging, wrap the evaluation of the predicate in a method
            //
            // translate $ and # references
            ActionTransInfo tInfo = new ActionTransInfo();
            String actionStr = processActionForSpecialSymbols(alt.semPred,
                                      blk.line,
                                      currentRule,
                                      tInfo);
            // ignore translation info...we don't need to do anything with it.

            // call that will inform SemanticPredicateListeners of the
            // result
            if ( grammar.debuggingOutput &&
                ((grammar instanceof ParserGrammar) || (grammar instanceof LexerGrammar))
               )
              e = "("+e+"&& fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.PREDICTING,"+ //FIXME
                  addSemPred(charFormatter.escapeString(actionStr))+","+actionStr+"))";
            else
              e = "("+e+"&&("+actionStr +"))";
          }

          // Generate any syntactic predicates
          if ( nIF>0 ) {
            if ( alt.synPred != null ) {
              println("else {");
              tabs++;
              genSynPred( alt.synPred, e );
              closingBracesOfIFSequence++;
            }
            else {
              println("else if " + e + " {");
            }
          }
          else {
            if ( alt.synPred != null ) {
              genSynPred( alt.synPred, e );
            }
            else {
              // when parsing trees, convert null to valid tree node
              // with NULL lookahead.
              if ( grammar instanceof TreeWalkerGrammar ) {
                println("if (_t == "+labeledElementASTInit+" )");
                tabs++;
                println("_t = ASTNULL;");
                tabs--;
              }
              println("if " + e + " {");
            }
          }

        }

        nIF++;
        tabs++;
        genAlt(alt, blk);
        tabs--;
        println("}");
      }
    }
    String ps = "";
    for (int i=1; i<=closingBracesOfIFSequence; i++) {
      tabs--; // does JavaCodeGenerator need this?
      ps+="}";
    }

    // Restore the AST generation state
    genAST = savegenAST;

    // restore save text state
    saveText=oldsaveTest;

    // Return the finishing info.
    if ( createdLL1Switch ) {
      tabs--;
      finishingInfo.postscript = ps+"}";
      finishingInfo.generatedSwitch = true;
      finishingInfo.generatedAnIf = nIF>0;
      //return new CppBlockFinishingInfo(ps+"}",true,nIF>0); // close up switch statement

    }
    else {
      finishingInfo.postscript = ps;
      finishingInfo.generatedSwitch = false;
      finishingInfo.generatedAnIf = nIF>0;
      //return new CppBlockFinishingInfo(ps, false,nIF>0);
    }
    return finishingInfo;
  }

  private static boolean suitableForCaseExpression(Alternative a) {
    return a.lookaheadDepth == 1 &&
      a.semPred == null &&
      !a.cache[1].containsEpsilon() &&
      a.cache[1].fset.degree()<=caseSizeThreshold;
  }

  /** Generate code to link an element reference into the AST
   */
  private void genElementAST(AlternativeElement el) {

    // handle case where you're not building trees, but are in tree walker.
    // Just need to get labels set up.
    if ( grammar instanceof TreeWalkerGrammar && !grammar.buildAST )
    {
      String elementRef;
      String astName;

      // Generate names and declarations of the AST variable(s)
      if (el.getLabel() == null)
      {
        elementRef = lt1Value;
        // Generate AST variables for unlabeled stuff
        astName = "tmp" + astVarNumber + "_AST";
        astVarNumber++;
        // Map the generated AST variable in the alternate
        mapTreeVariable(el, astName);
        // Generate an "input" AST variable also
        println(labeledElementASTType+" "+astName+"_in = "+elementRef+";");
      }
      return;
    }

    if (grammar.buildAST && syntacticPredLevel == 0)
    {
      boolean needASTDecl =
        ( genAST && (el.getLabel() != null ||
          el.getAutoGenType() != GrammarElement.AUTO_GEN_BANG ));

      // RK: if we have a grammar element always generate the decl
      // since some guy can access it from an action and we can't
      // peek ahead (well not without making a mess).
      // I'd prefer taking this out.
      if( el.getAutoGenType() != GrammarElement.AUTO_GEN_BANG &&
         (el instanceof TokenRefElement) )
        needASTDecl = true;

      boolean doNoGuessTest =
        ( grammar.hasSyntacticPredicate && needASTDecl );

      String elementRef;
      String astNameBase;

      // Generate names and declarations of the AST variable(s)
      if (el.getLabel() != null)
      {
        // if the element is labeled use that name...
        elementRef = el.getLabel();
        astNameBase = el.getLabel();
      }
      else
      {
        // else generate a temporary name...
        elementRef = lt1Value;
        // Generate AST variables for unlabeled stuff
        astNameBase = "tmp" + astVarNumber;
        astVarNumber++;
      }

      // Generate the declaration if required.
      if ( needASTDecl )
      {
        if ( el instanceof GrammarAtom )
        {
          GrammarAtom ga = (GrammarAtom)el;
          if ( ga.getASTNodeType()!=null )
          {
            genASTDeclaration( el, astNameBase, "Ref"+ga.getASTNodeType() );
//            println("Ref"+ga.getASTNodeType()+" " + astName + ";");
          }
          else
          {
            genASTDeclaration( el, astNameBase, labeledElementASTType );
//            println(labeledElementASTType+" " + astName + " = "+labeledElementASTInit+";");
          }
        }
        else
        {
          genASTDeclaration( el, astNameBase, labeledElementASTType );
//          println(labeledElementASTType+" " + astName + " = "+labeledElementASTInit+";");
        }
      }

      // for convenience..
      String astName = astNameBase + "_AST";

      // Map the generated AST variable in the alternate
      mapTreeVariable(el, astName);
      if (grammar instanceof TreeWalkerGrammar)
      {
        // Generate an "input" AST variable also
        println(labeledElementASTType+" " + astName + "_in = "+labeledElementASTInit+";");
      }

      // Enclose actions with !guessing
      if (doNoGuessTest) {
        println("if ( inputState->guessing == 0 ) {");
        tabs++;
      }

      // if something has a label assume it will be used
      // so we must initialize the RefAST
      if (el.getLabel() != null)
      {
        if ( el instanceof GrammarAtom )
        {
          println(astName + " = "+
                getASTCreateString((GrammarAtom)el,elementRef) + ";");
        }
        else
        {
          println(astName + " = "+
                getASTCreateString(elementRef) + ";");
        }
      }

      // if it has no label but a declaration exists initialize it.
      if( el.getLabel() == null && needASTDecl )
      {
        elementRef = lt1Value;
        if ( el instanceof GrammarAtom )
        {
          println(astName + " = "+
                getASTCreateString((GrammarAtom)el,elementRef) + ";");
        }
        else
        {
          println(astName + " = "+
                getASTCreateString(elementRef) + ";");
        }
        // Map the generated AST variable in the alternate
        if (grammar instanceof TreeWalkerGrammar)
        {
          // set "input" AST variable also
          println(astName + "_in = " + elementRef + ";");
        }
      }

      if (genAST)
      {
        switch (el.getAutoGenType())
        {
        case GrammarElement.AUTO_GEN_NONE:
          if( usingCustomAST ||
             (el instanceof GrammarAtom &&
              ((GrammarAtom)el).getASTNodeType() != null) )
            println("astFactory->addASTChild(currentAST, "+namespaceAntlr+"RefAST("+ astName + "));");
          else
            println("astFactory->addASTChild(currentAST, "+ astName + ");");
          //            println("astFactory.addASTChild(currentAST, "+namespaceAntlr+"RefAST(" + astName + "));");
          break;
        case GrammarElement.AUTO_GEN_CARET:
          if( usingCustomAST ||
             (el instanceof GrammarAtom &&
             ((GrammarAtom)el).getASTNodeType() != null) )
            println("astFactory->makeASTRoot(currentAST, "+namespaceAntlr+"RefAST(" + astName + "));");
          else
            println("astFactory->makeASTRoot(currentAST, " + astName + ");");
          break;
        default:
          break;
        }
      }
      if (doNoGuessTest)
      {
        tabs--;
        println("}");
      }
    }
  }
  /** Close the try block and generate catch phrases
   * if the element has a labeled handler in the rule
   */
  private void genErrorCatchForElement(AlternativeElement el) {
    if (el.getLabel() == null) return;
    String r = el.enclosingRuleName;
    if ( grammar instanceof LexerGrammar ) {
      r = CodeGenerator.encodeLexerRuleName(el.enclosingRuleName);
    }
    RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r);
    if (rs == null) {
      antlrTool.panic("Enclosing rule not found!");
    }
    ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
    if (ex != null) {
      tabs--;
      println("}");
      genErrorHandler(ex);
    }
  }
  /** Generate the catch phrases for a user-specified error handler */
  private void genErrorHandler(ExceptionSpec ex)
  {
    // Each ExceptionHandler in the ExceptionSpec is a separate catch
    for (int i = 0; i < ex.handlers.size(); i++)
    {
      ExceptionHandler handler = (ExceptionHandler)ex.handlers.elementAt(i);
      // Generate catch phrase
      println("catch (" + handler.exceptionTypeAndName.getText() + ") {");
      tabs++;
      if (grammar.hasSyntacticPredicate) {
        println("if (inputState->guessing==0) {");
        tabs++;
      }

      // When not guessing, execute user handler action
      ActionTransInfo tInfo = new ActionTransInfo();
      genLineNo(handler.action);
      printAction(
        processActionForSpecialSymbols( handler.action.getText(),
                             handler.action.getLine(),
                             currentRule, tInfo )
      );
      genLineNo2();

      if (grammar.hasSyntacticPredicate)
      {
        tabs--;
        println("} else {");
        tabs++;
        // When guessing, rethrow exception
        println("throw;");
        tabs--;
        println("}");
      }
      // Close catch phrase
      tabs--;
      println("}");
    }
  }
  /** Generate a try { opening if the element has a labeled handler in the rule */
  private void genErrorTryForElement(AlternativeElement el) {
    if (el.getLabel() == null) return;
    String r = el.enclosingRuleName;
    if ( grammar instanceof LexerGrammar ) {
      r = CodeGenerator.encodeLexerRuleName(el.enclosingRuleName);
    }
    RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r);
    if (rs == null) {
      antlrTool.panic("Enclosing rule not found!");
    }
    ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
    if (ex != null) {
      println("try { // for error handling");
      tabs++;
    }
  }
  /** Generate a header that is common to all C++ files */
  protected void genHeader(String fileName)
  {
    println("/* $ANTLR "+antlrTool.version+": "+
        "\""+antlrTool.fileMinusPath(antlrTool.grammarFile)+"\""+
        " -> "+
        "\""+fileName+"\"$ */");
  }

  // these are unique to C++ mode
  public void genInclude(LexerGrammar g) throws IOException
  {
    outputFile = grammar.getClassName() + ".hpp";
    outputLine = 1;
    currentOutput = antlrTool.openOutputFile(outputFile);
    //SAS: changed for proper text file io

    genAST = false// no way to gen trees.
    saveText = true// save consumed characters.

    tabs=0;

    // Generate a guard wrapper
    println("#ifndef INC_"+grammar.getClassName()+"_hpp_");
    println("#define INC_"+grammar.getClassName()+"_hpp_");
    println("");

    printHeaderAction(preIncludeHpp);

    println("#include <antlr/config.hpp>");

    // Generate header common to all C++ output files
    genHeader(outputFile);

    // Generate header specific to lexer header file
    println("#include <antlr/CommonToken.hpp>");
    println("#include <antlr/InputBuffer.hpp>");
    println("#include <antlr/BitSet.hpp>");
    println("#include \"" + grammar.tokenManager.getName() + TokenTypesFileSuffix+".hpp\"");

    // Find the name of the super class
    String sup=null;
    if ( grammar.superClass!=null ) {
      sup = grammar.superClass;

      println("\n// Include correct superclass header with a header statement for example:");
      println("// header \"post_include_hpp\" {");
      println("// #include \""+sup+".hpp\"");
      println("// }");
      println("// Or....");
      println("// header {");
      println("// #include \""+sup+".hpp\"");
      println("// }\n");
    }
    else {
      sup = grammar.getSuperClass();
      if (sup.lastIndexOf('.') != -1)
        sup = sup.substring(sup.lastIndexOf('.')+1);
      println("#include <antlr/"+sup+".hpp>");
      sup = namespaceAntlr + sup;
    }

    // Do not use printAction because we assume tabs==0
    printHeaderAction(postIncludeHpp);

    if (nameSpace != null)
         nameSpace.emitDeclarations(currentOutput);

    printHeaderAction("");

    // print javadoc comment if any
    if ( grammar.comment!=null ) {
      _println(grammar.comment);
    }

    // Generate lexer class definition
    print("class CUSTOM_API " + grammar.getClassName() + " : public " + sup);
    println(", public " + grammar.tokenManager.getName() + TokenTypesFileSuffix);

    Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
    if ( tsuffix != null ) {
      String suffix = StringUtils.stripFrontBack(tsuffix.getText(),"\"","\"");
      if ( suffix != null ) {
        print(", "+suffix)// must be an interface name for Java
      }
    }
    println("{");

    // Generate user-defined lexer class members
    if (grammar.classMemberAction != null) {
      genLineNo(grammar.classMemberAction);
      print(
        processActionForSpecialSymbols(grammar.classMemberAction.getText(),
                             grammar.classMemberAction.getLine(),
                             currentRule, null)
      );
      genLineNo2();
    }

    // Generate initLiterals() method
    tabs=0;
    println("private:");
    tabs=1;
    println("void initLiterals();");

    // Generate getCaseSensitiveLiterals() method
    tabs=0;
    println("public:");
    tabs=1;
    println("bool getCaseSensitiveLiterals() const");
    println("{");
    tabs++;
    println("return "+g.caseSensitiveLiterals + ";");
    tabs--;
    println("}");

    // Make constructors public
    tabs=0;
    println("public:");
    tabs=1;

    if( noConstructors )
    {
      tabs = 0;
      println("#if 0");
      println("// constructor creation turned of with 'noConstructor' option");
      tabs = 1;
    }

    // Generate the constructor from std::istream
    println(grammar.getClassName() + "(" + namespaceStd + "istream& in);");

    // Generate the constructor from InputBuffer
    println(grammar.getClassName() + "("+namespaceAntlr+"InputBuffer& ib);");

    println(grammar.getClassName() + "(const "+namespaceAntlr+"LexerSharedInputState& state);");
    if( noConstructors )
    {
      tabs = 0;
      println("// constructor creation turned of with 'noConstructor' option");
      println("#endif");
      tabs = 1;
    }

    // Generate nextToken() rule.
    // nextToken() is a synthetic lexer rule that is the implicit OR of all
    // user-defined lexer rules.
    println(namespaceAntlr+"RefToken nextToken();");

    // Generate code for each rule in the lexer
    Enumeration ids = grammar.rules.elements();
    while ( ids.hasMoreElements() ) {
      RuleSymbol sym = (RuleSymbol) ids.nextElement();
      // Don't generate the synthetic rules
      if (!sym.getId().equals("mnextToken")) {
        genRuleHeader(sym, false);
      }
      exitIfError();
    }

    // Make the rest private
    tabs=0;
    println("private:");
    tabs=1;

    // generate the rule name array for debugging
    if ( grammar.debuggingOutput ) {
      println("static const char* _ruleNames[];");
    }

    // Generate the semantic predicate map for debugging
    if (grammar.debuggingOutput)
      println("static const char* _semPredNames[];");

    // Generate the bitsets used throughout the lexer
    genBitsetsHeader(bitsetsUsed, ((LexerGrammar)grammar).charVocabulary.size());

    tabs=0;
    println("};");
    println("");
    if (nameSpace != null)
      nameSpace.emitClosures(currentOutput);

    // Generate a guard wrapper
    println("#endif /*INC_"+grammar.getClassName()+"_hpp_*/");

    // Close the lexer output stream
    currentOutput.close();
    currentOutput = null;
  }
  public void genInclude(ParserGrammar g) throws IOException
  {
    // Open the output stream for the parser and set the currentOutput
    outputFile = grammar.getClassName() + ".hpp";
    outputLine = 1;
    currentOutput = antlrTool.openOutputFile(outputFile);
    //SAS: changed for proper text file io

    genAST = grammar.buildAST;

    tabs = 0;

    // Generate a guard wrapper
    println("#ifndef INC_"+grammar.getClassName()+"_hpp_");
    println("#define INC_"+grammar.getClassName()+"_hpp_");
    println("");
    printHeaderAction(preIncludeHpp);
    println("#include <antlr/config.hpp>");

    // Generate the header common to all output files.
    genHeader(outputFile);

    // Generate header for the parser
    println("#include <antlr/TokenStream.hpp>");
    println("#include <antlr/TokenBuffer.hpp>");
    println("#include \"" + grammar.tokenManager.getName() + TokenTypesFileSuffix+".hpp\"");

    // Generate parser class definition
    String sup=null;
    if ( grammar.superClass!=null ) {
      sup = grammar.superClass;
      println("\n// Include correct superclass header with a header statement for example:");
      println("// header \"post_include_hpp\" {");
      println("// #include \""+sup+".hpp\"");
      println("// }");
      println("// Or....");
      println("// header {");
      println("// #include \""+sup+".hpp\"");
      println("// }\n");
    }
    else {
      sup = grammar.getSuperClass();
      if (sup.lastIndexOf('.') != -1)
        sup = sup.substring(sup.lastIndexOf('.')+1);
      println("#include <antlr/"+sup+".hpp>");
      sup = namespaceAntlr + sup;
    }
    println("");

    // Do not use printAction because we assume tabs==0
    printHeaderAction(postIncludeHpp);

    if (nameSpace != null)
      nameSpace.emitDeclarations(currentOutput);

    printHeaderAction("");

    // print javadoc comment if any
    if ( grammar.comment!=null ) {
      _println(grammar.comment);
    }

    // generate the actual class definition
    print("class CUSTOM_API " + grammar.getClassName() + " : public " + sup);
    println(", public " + grammar.tokenManager.getName() + TokenTypesFileSuffix);

    Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
    if ( tsuffix != null ) {
      String suffix = StringUtils.stripFrontBack(tsuffix.getText(),"\"","\"");
      if ( suffix != null )
        print(", "+suffix)// must be an interface name for Java
    }
    println("{");

    // set up an array of all the rule names so the debugger can
    // keep track of them only by number -- less to store in tree...
    if (grammar.debuggingOutput) {
      println("public: static const char* _ruleNames[];");
    }
    // Generate user-defined parser class members
    if (grammar.classMemberAction != null) {
      genLineNo(grammar.classMemberAction.getLine());
      print(
        processActionForSpecialSymbols(grammar.classMemberAction.getText(),
                             grammar.classMemberAction.getLine(),
                             currentRule, null)
      );
      genLineNo2();
    }
    println("public:");
    tabs = 1;
    println("void initializeASTFactory( "+namespaceAntlr+"ASTFactory& factory );");
//    println("// called from constructors");
//    println("void _initialize( void );");

    // Generate parser class constructor from TokenBuffer
    tabs=0;
    if( noConstructors )
    {
      println("#if 0");
      println("// constructor creation turned of with 'noConstructor' option");
    }
    println("protected:");
    tabs=1;
    println(grammar.getClassName() + "("+namespaceAntlr+"TokenBuffer& tokenBuf, int k);");
    tabs=0;
    println("public:");
    tabs=1;
    println(grammar.getClassName() + "("+namespaceAntlr+"TokenBuffer& tokenBuf);");

    // Generate parser class constructor from TokenStream
    tabs=0;
    println("protected:");
    tabs=1;
    println(grammar.getClassName()+"("+namespaceAntlr+"TokenStream& lexer, int k);");
    tabs=0;
    println("public:");
    tabs=1;
    println(grammar.getClassName()+"("+namespaceAntlr+"TokenStream& lexer);");

    println(grammar.getClassName()+"(const "+namespaceAntlr+"ParserSharedInputState& state);");
    if( noConstructors )
    {
      tabs = 0;
      println("// constructor creation turned of with 'noConstructor' option");
      println("#endif");
      tabs = 1;
    }

    println("int getNumTokens() const");
    println("{"); tabs++;
    println("return "+grammar.getClassName()+"::NUM_TOKENS;");
    tabs--; println("}");
    println("const char* getTokenName( int type ) const");
    println("{"); tabs++;
    println("if( type > getNumTokens() ) return 0;");
    println("return "+grammar.getClassName()+"::tokenNames[type];");
    tabs--; println("}");
    println("const char* const* getTokenNames() const");
    println("{"); tabs++;
    println("return "+grammar.getClassName()+"::tokenNames;");
    tabs--; println("}");

    // Generate code for each rule in the grammar
    Enumeration ids = grammar.rules.elements();
    while ( ids.hasMoreElements() ) {
      GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
      if ( sym instanceof RuleSymbol) {
        RuleSymbol rs = (RuleSymbol)sym;
        genRuleHeader(rs, rs.references.size()==0);
      }
      exitIfError();
    }

    // RK: when we are using a custom ast override Parser::getAST to return
    // the custom AST type. Ok, this does not work anymore with newer
    // compilers gcc 3.2.x and up. The reference counter is probably
    // getting in the way.
    // So now we just patch the return type back to RefAST
    tabs = 0; println("public:"); tabs = 1;
    println(namespaceAntlr+"RefAST getAST()");
    println("{");
    if( usingCustomAST )
    {
      tabs++;
      println("return "+namespaceAntlr+"RefAST(returnAST);");
      tabs--;
    }
    else
    {
      tabs++;
      println("return returnAST;");
      tabs--;
    }
    println("}");
    println("");

    tabs=0; println("protected:"); tabs=1;
    println(labeledElementASTType+" returnAST;");

    // Make the rest private
    tabs=0;
    println("private:");
    tabs=1;

    // Generate the token names
    println("static const char* tokenNames[];");
    // and how many there are of them
    _println("#ifndef NO_STATIC_CONSTS");
    println("static const int NUM_TOKENS = "+grammar.tokenManager.getVocabulary().size()+";");
    _println("#else");
    println("enum {");
    println("\tNUM_TOKENS = "+grammar.tokenManager.getVocabulary().size());
    println("};");
    _println("#endif");

    // Generate the bitsets used throughout the grammar
    genBitsetsHeader(bitsetsUsed, grammar.tokenManager.maxTokenType());

    // Generate the semantic predicate map for debugging
    if (grammar.debuggingOutput)
      println("static const char* _semPredNames[];");

    // Close class definition
    tabs=0;
    println("};");
    println("");
    if (nameSpace != null)
      nameSpace.emitClosures(currentOutput);

    // Generate a guard wrapper
    println("#endif /*INC_"+grammar.getClassName()+"_hpp_*/");

    // Close the parser output stream
    currentOutput.close();
    currentOutput = null;
  }
  public void genInclude(TreeWalkerGrammar g) throws IOException
  {
    // Open the output stream for the parser and set the currentOutput
    outputFile = grammar.getClassName() + ".hpp";
    outputLine = 1;
    currentOutput = antlrTool.openOutputFile(outputFile);
    //SAS: changed for proper text file io

    genAST = grammar.buildAST;
    tabs = 0;

    // Generate a guard wrapper
    println("#ifndef INC_"+grammar.getClassName()+"_hpp_");
    println("#define INC_"+grammar.getClassName()+"_hpp_");
    println("");
    printHeaderAction(preIncludeHpp);
    println("#include <antlr/config.hpp>");
    println("#include \"" + grammar.tokenManager.getName() + TokenTypesFileSuffix+".hpp\"");

    // Generate the header common to all output files.
    genHeader(outputFile);

    // Find the name of the super class
    String sup=null;
    if ( grammar.superClass!=null ) {
      sup = grammar.superClass;
      println("\n// Include correct superclass header with a header statement for example:");
      println("// header \"post_include_hpp\" {");
      println("// #include \""+sup+".hpp\"");
      println("// }");
      println("// Or....");
      println("// header {");
      println("// #include \""+sup+".hpp\"");
      println("// }\n");
    }
    else {
      sup = grammar.getSuperClass();
      if (sup.lastIndexOf('.') != -1)
        sup = sup.substring(sup.lastIndexOf('.')+1);
      println("#include <antlr/"+sup+".hpp>");
      sup = namespaceAntlr + sup;
    }
    println("");

    // Generate header for the parser
    //
    // Do not use printAction because we assume tabs==0
    printHeaderAction(postIncludeHpp);

    if (nameSpace != null)
      nameSpace.emitDeclarations(currentOutput);

    printHeaderAction("");

    // print javadoc comment if any
    if ( grammar.comment!=null ) {
      _println(grammar.comment);
    }

    // Generate parser class definition
    print("class CUSTOM_API " + grammar.getClassName() + " : public "+sup);
    println(", public " + grammar.tokenManager.getName() + TokenTypesFileSuffix);

    Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
    if ( tsuffix != null ) {
      String suffix = StringUtils.stripFrontBack(tsuffix.getText(),"\"","\"");
      if ( suffix != null ) {
        print(", "+suffix)// must be an interface name for Java
      }
    }
    println("{");

    // Generate user-defined parser class members
    if (grammar.classMemberAction != null) {
      genLineNo(grammar.classMemberAction.getLine());
      print(
          processActionForSpecialSymbols(grammar.classMemberAction.getText(),
                               grammar.classMemberAction.getLine(),
                               currentRule, null)
          );
      genLineNo2();
    }

    // Generate default parser class constructor
    tabs=0;
    println("public:");

    if( noConstructors )
    {
      println("#if 0");
      println("// constructor creation turned of with 'noConstructor' option");
    }
    tabs=1;
    println(grammar.getClassName() + "();");
    if( noConstructors )
    {
      tabs = 0;
      println("#endif");
      tabs = 1;
    }

    // Generate declaration for the initializeFactory method
    println("static void initializeASTFactory( "+namespaceAntlr+"ASTFactory& factory );");

    println("int getNumTokens() const");
    println("{"); tabs++;
    println("return "+grammar.getClassName()+"::NUM_TOKENS;");
    tabs--; println("}");
    println("const char* getTokenName( int type ) const");
    println("{"); tabs++;
    println("if( type > getNumTokens() ) return 0;");
    println("return "+grammar.getClassName()+"::tokenNames[type];");
    tabs--; println("}");
    println("const char* const* getTokenNames() const");
    println("{"); tabs++;
    println("return "+grammar.getClassName()+"::tokenNames;");
    tabs--; println("}");

    // Generate code for each rule in the grammar
    Enumeration ids = grammar.rules.elements();
    String ruleNameInits = "";
    while ( ids.hasMoreElements() ) {
      GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
      if ( sym instanceof RuleSymbol) {
        RuleSymbol rs = (RuleSymbol)sym;
        genRuleHeader(rs, rs.references.size()==0);
      }
      exitIfError();
    }
    tabs = 0; println("public:"); tabs = 1;
    println(namespaceAntlr+"RefAST getAST()");
    println("{");
    if( usingCustomAST )
    {
      tabs++;
      println("return "+namespaceAntlr+"RefAST(returnAST);");
      tabs--;
    }
    else
    {
      tabs++;
      println("return returnAST;");
      tabs--;
    }
    println("}");
    println("");

    tabs=0; println("protected:"); tabs=1;
    println(labeledElementASTType+" returnAST;");
    println(labeledElementASTType+" _retTree;");

    // Make the rest private
    tabs=0;
    println("private:");
    tabs=1;

    // Generate the token names
    println("static const char* tokenNames[];");
    // and how many there are of them
    _println("#ifndef NO_STATIC_CONSTS");
    println("static const int NUM_TOKENS = "+grammar.tokenManager.getVocabulary().size()+";");
    _println("#else");
    println("enum {");
    println("\tNUM_TOKENS = "+grammar.tokenManager.getVocabulary().size());
    println("};");
    _println("#endif");

    // Generate the bitsets used throughout the grammar
    genBitsetsHeader(bitsetsUsed, grammar.tokenManager.maxTokenType());

    // Close class definition
    tabs=0;
    println("};");
    println("");
    if (nameSpace != null)
      nameSpace.emitClosures(currentOutput);

    // Generate a guard wrapper
    println("#endif /*INC_"+grammar.getClassName()+"_hpp_*/");

    // Close the parser output stream
    currentOutput.close();
    currentOutput = null;
  }
  /// for convenience
  protected void genASTDeclaration( AlternativeElement el ) {
    genASTDeclaration( el, labeledElementASTType );
  }
  /// for convenience
  protected void genASTDeclaration( AlternativeElement el, String node_type ) {
    genASTDeclaration( el, el.getLabel(), node_type );
  }
  /// Generate (if not already done) a declaration for the AST for el.
  protected void genASTDeclaration( AlternativeElement el, String var_name, String node_type ) {
    // already declared?
    if( declaredASTVariables.contains(el) )
      return;

    String init = labeledElementASTInit;

    if (el instanceof GrammarAtom &&
       ((GrammarAtom)el).getASTNodeType() != null )
      init = "Ref"+((GrammarAtom)el).getASTNodeType()+"("+labeledElementASTInit+")";

    // emit code
    println(node_type+" " + var_name + "_AST = "+init+";");

    // mark as declared
    declaredASTVariables.put(el, el);
  }
  private void genLiteralsTest() {
    println("_ttype = testLiteralsTable(_ttype);");
  }
  private void genLiteralsTestForPartialToken() {
    println("_ttype = testLiteralsTable(text.substr(_begin, text.length()-_begin),_ttype);");
  }
  protected void genMatch(BitSet b) {
  }
  protected void genMatch(GrammarAtom atom) {
    if ( atom instanceof StringLiteralElement ) {
      if ( grammar instanceof LexerGrammar ) {
        genMatchUsingAtomText(atom);
      }
      else {
        genMatchUsingAtomTokenType(atom);
      }
    }
    else if ( atom instanceof CharLiteralElement ) {
      // Lexer case is handled in the gen( CharLiteralElement x )
      antlrTool.error("cannot ref character literals in grammar: "+atom);
    }
    else if ( atom instanceof TokenRefElement ) {
      genMatchUsingAtomTokenType(atom);
    } else if (atom instanceof WildcardElement) {
      gen((WildcardElement)atom);
    }
  }
  protected void genMatchUsingAtomText(GrammarAtom atom) {
    // match() for trees needs the _t cursor
    String astArgs="";
    if (grammar instanceof TreeWalkerGrammar) {
      if( usingCustomAST )
        astArgs=namespaceAntlr+"RefAST"+"(_t),";
      else
        astArgs="_t,";
    }

    // if in lexer and ! on element, save buffer index to kill later
    if ( grammar instanceof LexerGrammar && (!saveText||atom.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
      println("_saveIndex = text.length();");
    }

    print(atom.not ? "matchNot(" : "match(");
    _print(astArgs);

    // print out what to match
    if (atom.atomText.equals("EOF")) {
      // horrible hack to handle EOF case
      _print(namespaceAntlr+"Token::EOF_TYPE");
    }
    else
    {
      if( grammar instanceof LexerGrammar // lexer needs special handling
      {
        String cppstring = convertJavaToCppString( atom.atomText, false );
        _print(cppstring);
      }
      else
        _print(atom.atomText);
    }

    _println(");");

    if ( grammar instanceof LexerGrammar && (!saveText||atom.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
      println("text.erase(_saveIndex);");      // kill text atom put in buffer
    }
  }
  protected void genMatchUsingAtomTokenType(GrammarAtom atom) {
    // match() for trees needs the _t cursor
    String astArgs="";
    if (grammar instanceof TreeWalkerGrammar) {
      if( usingCustomAST )
        astArgs=namespaceAntlr+"RefAST"+"(_t),";
      else
        astArgs="_t,";
    }

    // If the literal can be mangled, generate the symbolic constant instead
    String s = astArgs + getValueString(atom.getType());

    // matching
    println( (atom.not ? "matchNot(" : "match(") + s + ");");
  }
  /** Generate the nextToken() rule.
   * nextToken() is a synthetic lexer rule that is the implicit OR of all
   * user-defined lexer rules.
   * @param RuleBlock
   */
  public void genNextToken() {
    // Are there any public rules?  If not, then just generate a
    // fake nextToken().
    boolean hasPublicRules = false;
    for (int i = 0; i < grammar.rules.size(); i++) {
      RuleSymbol rs = (RuleSymbol)grammar.rules.elementAt(i);
      if ( rs.isDefined() && rs.access.equals("public") ) {
        hasPublicRules = true;
        break;
      }
    }
    if (!hasPublicRules) {
      println("");
      println(namespaceAntlr+"RefToken "+grammar.getClassName()+"::nextToken() { return "+namespaceAntlr+"RefToken(new "+namespaceAntlr+"CommonToken("+namespaceAntlr+"Token::EOF_TYPE, \"\")); }");
      println("");
      return;
    }

    // Create the synthesized nextToken() rule
    RuleBlock nextTokenBlk = MakeGrammar.createNextTokenRule(grammar, grammar.rules, "nextToken");
    // Define the nextToken rule symbol
    RuleSymbol nextTokenRs = new RuleSymbol("mnextToken");
    nextTokenRs.setDefined();
    nextTokenRs.setBlock(nextTokenBlk);
    nextTokenRs.access = "private";
    grammar.define(nextTokenRs);
    // Analyze the nextToken rule
    boolean ok = grammar.theLLkAnalyzer.deterministic(nextTokenBlk);

    // Generate the next token rule
    String filterRule=null;
    if ( ((LexerGrammar)grammar).filterMode ) {
      filterRule = ((LexerGrammar)grammar).filterRule;
    }

    println("");
    println(namespaceAntlr+"RefToken "+grammar.getClassName()+"::nextToken()");
    println("{");
    tabs++;
    println(namespaceAntlr+"RefToken theRetToken;");
    println("for (;;) {");
    tabs++;
    println(namespaceAntlr+"RefToken theRetToken;");
    println("int _ttype = "+namespaceAntlr+"Token::INVALID_TYPE;");
    if ( ((LexerGrammar)grammar).filterMode ) {
      println("setCommitToPath(false);");
      if ( filterRule!=null ) {
        // Here's a good place to ensure that the filter rule actually exists
        if ( !grammar.isDefined(CodeGenerator.encodeLexerRuleName(filterRule)) ) {
          grammar.antlrTool.error("Filter rule "+filterRule+" does not exist in this lexer");
        }
        else {
          RuleSymbol rs = (RuleSymbol)grammar.getSymbol(CodeGenerator.encodeLexerRuleName(filterRule));
          if ( !rs.isDefined() ) {
            grammar.antlrTool.error("Filter rule "+filterRule+" does not exist in this lexer");
          }
          else if ( rs.access.equals("public") ) {
            grammar.antlrTool.error("Filter rule "+filterRule+" must be protected");
          }
        }
        println("int _m;");
        println("_m = mark();");
      }
    }
    println("resetText();");

    // Generate try around whole thing to trap scanner errors
    println("try {   // for lexical and char stream error handling");
    tabs++;

    // Test for public lexical rules with empty paths
    for (int i=0; i<nextTokenBlk.getAlternatives().size(); i++) {
      Alternative a = nextTokenBlk.getAlternativeAt(i);
      if ( a.cache[1].containsEpsilon() ) {
        antlrTool.warning("found optional path in nextToken()");
      }
    }

    // Generate the block
    String newline = System.getProperty("line.separator");
    CppBlockFinishingInfo howToFinish = genCommonBlock(nextTokenBlk, false);
    String errFinish = "if (LA(1)==EOF_CHAR)"+newline+
      "\t\t\t\t{"+newline+"\t\t\t\t\tuponEOF();"+newline+
      "\t\t\t\t\t_returnToken = makeToken("+namespaceAntlr+"Token::EOF_TYPE);"+
      newline+"\t\t\t\t}";
    errFinish += newline+"\t\t\t\t";
    if ( ((LexerGrammar)grammar).filterMode ) {
      if ( filterRule==null ) {
        errFinish += "else {consume(); goto tryAgain;}";
      }
      else {
        errFinish += "else {"+newline+
            "\t\t\t\t\tcommit();"+newline+
            "\t\t\t\t\ttry {m"+filterRule+"(false);}"+newline+
            "\t\t\t\t\tcatch("+namespaceAntlr+"RecognitionException& e) {"+newline+
            "\t\t\t\t\t  // catastrophic failure"+newline+
            "\t\t\t\t\t  reportError(e);"+newline+
            "\t\t\t\t\t  consume();"+newline+
            "\t\t\t\t\t}"+newline+
             "\t\t\t\t\tgoto tryAgain;"+newline+
             "\t\t\t\t}";
      }
    }
    else {
      errFinish += "else {"+throwNoViable+"}";
    }
    genBlockFinish(howToFinish, errFinish);

    // at this point a valid token has been matched, undo "mark" that was done
    if ( ((LexerGrammar)grammar).filterMode && filterRule!=null ) {
      println("commit();");
    }

    // Generate literals test if desired
    // make sure _ttype is set first; note _returnToken must be
    // non-null as the rule was required to create it.
    println("if ( !_returnToken )"+newline+
          "\t\t\t\tgoto tryAgain; // found SKIP token"+newline);
    println("_ttype = _returnToken->getType();");
    if ( ((LexerGrammar)grammar).getTestLiterals()) {
      genLiteralsTest();
    }

    // return token created by rule reference in switch
    println("_returnToken->setType(_ttype);");
    println("return _returnToken;");

    // Close try block
    tabs--;
    println("}");
    println("catch ("+namespaceAntlr+"RecognitionException& e) {");
    tabs++;
    if ( ((LexerGrammar)grammar).filterMode ) {
      if ( filterRule==null ) {
        println("if ( !getCommitToPath() ) {");
        tabs++;
        println("consume();");
        println("goto tryAgain;");
        tabs--;
        println("}");
      }
      else {
        println("if ( !getCommitToPath() ) {");
        tabs++;
        println("rewind(_m);");
        println("resetText();");
        println("try {m"+filterRule+"(false);}");
        println("catch("+namespaceAntlr+"RecognitionException& ee) {");
        println("  // horrendous failure: error in filter rule");
        println("  reportError(ee);");
        println("  consume();");
        println("}");
        // println("goto tryAgain;");
        tabs--;
        println("}");
        println("else");
      }
    }
    if ( nextTokenBlk.getDefaultErrorHandler() ) {
      println("{");
      tabs++;
      println("reportError(e);");
      println("consume();");
      tabs--;
      println("}");
    }
    else {
        // pass on to invoking routine
          tabs++;
        println("throw "+namespaceAntlr+"TokenStreamRecognitionException(e);");
       tabs--;
    }

    // close CharStreamException try
    tabs--;
    println("}");
    println("catch ("+namespaceAntlr+"CharStreamIOException& csie) {");
    println("\tthrow "+namespaceAntlr+"TokenStreamIOException(csie.io);");
    println("}");
    println("catch ("+namespaceAntlr+"CharStreamException& cse) {");
    println("\tthrow "+namespaceAntlr+"TokenStreamException(cse.getMessage());");
    println("}");

    // close for-loop
    _println("tryAgain:;");
    tabs--;
    println("}");

    // close method nextToken
    tabs--;
    println("}");
    println("");
  }
  /** Gen a named rule block.
   * ASTs are generated for each element of an alternative unless
   * the rule or the alternative have a '!' modifier.
   *
   * If an alternative defeats the default tree construction, it
   * must set <rule>_AST to the root of the returned AST.
   *
   * Each alternative that does automatic tree construction, builds
   * up root and child list pointers in an ASTPair structure.
   *
   * A rule finishes by setting the returnAST variable from the
   * ASTPair.
   *
   * @param rule The name of the rule to generate
   * @param startSymbol true if the rule is a start symbol (i.e., not referenced elsewhere)
  */
  public void genRule(RuleSymbol s, boolean startSymbol, int ruleNum, String prefix) {
//    tabs=1; // JavaCodeGenerator needs this
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genRule("+ s.getId() +")");
    if ( !s.isDefined() ) {
      antlrTool.error("undefined rule: "+ s.getId());
      return;
    }

    // Generate rule return type, name, arguments
    RuleBlock rblk = s.getBlock();

    currentRule = rblk;
    currentASTResult = s.getId();

    // clear list of declared ast variables..
    declaredASTVariables.clear();

    // Save the AST generation state, and set it to that of the rule
    boolean savegenAST = genAST;
    genAST = genAST && rblk.getAutoGen();

    // boolean oldsaveTest = saveText;
    saveText = rblk.getAutoGen();

    // print javadoc comment if any
    if ( s.comment!=null ) {
      _println(s.comment);
    }

    // Gen method return type (note lexer return action set at rule creation)
    if (rblk.returnAction != null)
    {
      // Has specified return value
      _print(extractTypeOfAction(rblk.returnAction, rblk.getLine(), rblk.getColumn()) + " ");
    } else {
      // No specified return value
      _print("void ");
    }

    // Gen method name
    _print(prefix + s.getId() + "(");

    // Additional rule parameters common to all rules for this grammar
    _print(commonExtraParams);
    if (commonExtraParams.length() != 0 && rblk.argAction != null ) {
      _print(",");
    }

    // Gen arguments
    if (rblk.argAction != null)
    {
      // Has specified arguments
      _println("");
// FIXME: make argAction also a token? Hmmmmm
//      genLineNo(rblk);
      tabs++;

      // Process arguments for default arguments
      // newer gcc's don't accept these in two places (header/cpp)
      //
      // Old appraoch with StringBuffer gave trouble with gcj.
      //
      // RK: Actually this breaks with string default arguments containing
      // a comma's or equal signs. Then again the old StringBuffer method
      // suffered from the same.
      String oldarg = rblk.argAction;
      String newarg = "";

      String comma = "";
      int eqpos = oldarg.indexOf( '=' );
      if( eqpos != -1 )
      {
        int cmpos = 0;
        while( cmpos != -1 && eqpos != -1 )
        {
          newarg = newarg + comma + oldarg.substring( 0, eqpos ).trim();
          comma = ", ";
          cmpos = oldarg.indexOf( ',', eqpos );
          if( cmpos != -1 )
          {
            // cut off part we just handled
            oldarg = oldarg.substring( cmpos+1 ).trim();
            eqpos = oldarg.indexOf( '=' );
            if( eqpos == -1 )
              newarg = newarg+comma+oldarg;
          }
        }
      }
      else
        newarg = oldarg;

      println( newarg );

//      println(rblk.argAction);
      tabs--;
      print(") ");
//      genLineNo2();  // gcc gives error on the brace... hope it works for the others too
    } else {
      // No specified arguments
      _print(") ");
    }
    _println("{");
    tabs++;

    if (grammar.traceRules) {
      if ( grammar instanceof TreeWalkerGrammar ) {
        if ( usingCustomAST )
          println("Tracer traceInOut(this,\""+ s.getId() +"\","+namespaceAntlr+"RefAST"+"(_t));");
        else
          println("Tracer traceInOut(this,\""+ s.getId() +"\",_t);");
      }
      else {
        println("Tracer traceInOut(this, \""+ s.getId() +"\");");
      }
    }

    // Convert return action to variable declaration
    if (rblk.returnAction != null)
    {
      genLineNo(rblk);
      println(rblk.returnAction + ";");
      genLineNo2();
    }

    // print out definitions needed by rules for various grammar types
    if (!commonLocalVars.equals(""))
      println(commonLocalVars);

    if ( grammar instanceof LexerGrammar ) {
      // RK: why is this here? It seems not supported in the rest of the
      // tool.
      // lexer rule default return value is the rule's token name
      // This is a horrible hack to support the built-in EOF lexer rule.
      if (s.getId().equals("mEOF"))
        println("_ttype = "+namespaceAntlr+"Token::EOF_TYPE;");
      else
        println("_ttype = "+ s.getId().substring(1)+";");
      println(namespaceStd+"string::size_type _saveIndex;");    // used for element! (so we can kill text matched for element)
/*
      println("boolean old_saveConsumedInput=saveConsumedInput;");
      if ( !rblk.getAutoGen() ) {      // turn off "save input" if ! on rule
        println("saveConsumedInput=false;");
      }
*/
    }

    // if debugging, write code to mark entry to the rule
    if ( grammar.debuggingOutput)
        if (grammar instanceof ParserGrammar)
        println("fireEnterRule(" + ruleNum + ",0);");
      else if (grammar instanceof LexerGrammar)
        println("fireEnterRule(" + ruleNum + ",_ttype);");

    // Generate trace code if desired
//    if ( grammar.debuggingOutput || grammar.traceRules) {
//      println("try { // debugging");
//      tabs++;
//    }

    // Initialize AST variables
    if (grammar instanceof TreeWalkerGrammar) {
      // "Input" value for rule
//      println(labeledElementASTType+" " + s.getId() + "_AST_in = "+labeledElementASTType+"(_t);");
      println(labeledElementASTType+" " + s.getId() + "_AST_in = (_t == "+labeledElementASTType+"(ASTNULL)) ? "+labeledElementASTInit+" : _t;");
    }
    if (grammar.buildAST) {
      // Parser member used to pass AST returns from rule invocations
      println("returnAST = "+labeledElementASTInit+";");
      // Tracks AST construction
      println(namespaceAntlr+"ASTPair currentAST;"); // = new ASTPair();");
      // User-settable return value for rule.
      println(labeledElementASTType+" " + s.getId() + "_AST = "+labeledElementASTInit+";");
    }

    genBlockPreamble(rblk);
    genBlockInitAction(rblk);
    println("");

    // Search for an unlabeled exception specification attached to the rule
    ExceptionSpec unlabeledUserSpec = rblk.findExceptionSpec("");

    // Generate try block around the entire rule for  error handling
    if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler() ) {
      println("try {      // for error handling");
      tabs++;
    }

    // Generate the alternatives
    if ( rblk.alternatives.size()==1 )
    {
      // One alternative -- use simple form
      Alternative alt = rblk.getAlternativeAt(0);
      String pred = alt.semPred;
      if ( pred!=null )
        genSemPred(pred, currentRule.line);
      if (alt.synPred != null) {
        antlrTool.warning(
          "Syntactic predicate ignored for single alternative",
          grammar.getFilename(),
          alt.synPred.getLine(),
          alt.synPred.getColumn()
        );
      }
      genAlt(alt, rblk);
    }
    else
    {
      // Multiple alternatives -- generate complex form
      boolean ok = grammar.theLLkAnalyzer.deterministic(rblk);

      CppBlockFinishingInfo howToFinish = genCommonBlock(rblk, false);
      genBlockFinish(howToFinish, throwNoViable);
    }

    // Generate catch phrase for error handling
    if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler() ) {
      // Close the try block
      tabs--;
      println("}");
    }

    // Generate user-defined or default catch phrases
    if (unlabeledUserSpec != null)
    {
      genErrorHandler(unlabeledUserSpec);
    }
    else if (rblk.getDefaultErrorHandler())
    {
      // Generate default catch phrase
      println("catch (" + exceptionThrown + "& ex) {");
      tabs++;
      // Generate code to handle error if not guessing
      if (grammar.hasSyntacticPredicate) {
        println("if( inputState->guessing == 0 ) {");
        tabs++;
      }
      println("reportError(ex);");
      if ( !(grammar instanceof TreeWalkerGrammar) )
      {
        // Generate code to consume until token in k==1 follow set
        Lookahead follow = grammar.theLLkAnalyzer.FOLLOW(1, rblk.endNode);
        String followSetName = getBitsetName(markBitsetForGen(follow.fset));
        println("recover(ex," + followSetName + ");");
      }
      else
      {
        // Just consume one token
        println("if ( _t != "+labeledElementASTInit+" )");
        tabs++;
        println("_t = _t->getNextSibling();");
        tabs--;
      }
      if (grammar.hasSyntacticPredicate)
      {
        tabs--;
        // When guessing, rethrow exception
        println("} else {");
        tabs++;
        println("throw;");
        tabs--;
        println("}");
      }
      // Close catch phrase
      tabs--;
      println("}");
    }

    // Squirrel away the AST "return" value
    if (grammar.buildAST) {
      println("returnAST = " + s.getId() + "_AST;");
    }

    // Set return tree value for tree walkers
    if ( grammar instanceof TreeWalkerGrammar ) {
      println("_retTree = _t;");
    }

    // Generate literals test for lexer rules so marked
    if (rblk.getTestLiterals()) {
      if ( s.access.equals("protected") ) {
        genLiteralsTestForPartialToken();
      }
      else {
        genLiteralsTest();
      }
    }

    // if doing a lexer rule, dump code to create token if necessary
    if ( grammar instanceof LexerGrammar ) {
      println("if ( _createToken && _token=="+namespaceAntlr+"nullToken && _ttype!="+namespaceAntlr+"Token::SKIP ) {");
      println("   _token = makeToken(_ttype);");
      println("   _token->setText(text.substr(_begin, text.length()-_begin));");
      println("}");
      println("_returnToken = _token;");
      // It should be easy for an optimizing compiler to realize this does nothing
      // but it avoids the warning about the variable being unused.
      println("_saveIndex=0;");
    }

    // Gen the return statement if there is one (lexer has hard-wired return action)
    if (rblk.returnAction != null) {
      println("return " + extractIdOfAction(rblk.returnAction, rblk.getLine(), rblk.getColumn()) + ";");
    }

//    if ( grammar.debuggingOutput || grammar.traceRules) {
////      tabs--;
////      println("} finally { // debugging");
////      tabs++;
//
//      // Generate trace code if desired
//      if ( grammar.debuggingOutput)
//        if (grammar instanceof ParserGrammar)
//          println("fireExitRule(" + ruleNum + ",0);");
//        else if (grammar instanceof LexerGrammar)
//          println("fireExitRule(" + ruleNum + ",_ttype);");
//
////      if (grammar.traceRules) {
////        if ( grammar instanceof TreeWalkerGrammar ) {
////          println("traceOut(\""+ s.getId() +"\",_t);");
////        }
////        else {
////          println("traceOut(\""+ s.getId() +"\");");
////        }
////      }
////
////      tabs--;
////      println("}");
//    }

    tabs--;
    println("}");
    println("");

    // Restore the AST generation state
    genAST = savegenAST;

    // restore char save state
    // saveText = oldsaveTest;
  }
  public void genRuleHeader(RuleSymbol s, boolean startSymbol) {
    tabs=1;
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("genRuleHeader("+ s.getId() +")");
    if ( !s.isDefined() ) {
      antlrTool.error("undefined rule: "+ s.getId());
      return;
    }

    // Generate rule return type, name, arguments
    RuleBlock rblk = s.getBlock();
    currentRule = rblk;
    currentASTResult = s.getId();

    // Save the AST generation state, and set it to that of the rule
    boolean savegenAST = genAST;
    genAST = genAST && rblk.getAutoGen();

    // boolean oldsaveTest = saveText;
    saveText = rblk.getAutoGen();

    // Gen method access
    print(s.access + ": ");

    // Gen method return type (note lexer return action set at rule creation)
    if (rblk.returnAction != null)
    {
      // Has specified return value
      _print(extractTypeOfAction(rblk.returnAction, rblk.getLine(), rblk.getColumn()) + " ");
    } else {
      // No specified return value
      _print("void ");
    }

    // Gen method name
    _print(s.getId() + "(");

    // Additional rule parameters common to all rules for this grammar
    _print(commonExtraParams);
    if (commonExtraParams.length() != 0 && rblk.argAction != null ) {
      _print(",");
    }

    // Gen arguments
    if (rblk.argAction != null)
    {
      // Has specified arguments
      _println("");
      tabs++;
      println(rblk.argAction);
      tabs--;
      print(")");
    } else {
      // No specified arguments
      _print(")");
    }
    _println(";");

    tabs--;

    // Restore the AST generation state
    genAST = savegenAST;

    // restore char save state
    // saveText = oldsaveTest;
  }
  private void GenRuleInvocation(RuleRefElement rr) {
    // dump rule name
    _print(rr.targetRule + "(");

    // lexers must tell rule if it should set _returnToken
    if ( grammar instanceof LexerGrammar ) {
      // if labeled, could access Token, so tell rule to create
      if ( rr.getLabel() != null ) {
        _print("true");
      }
      else {
        _print("false");
      }
      if (commonExtraArgs.length() != 0 || rr.args!=null ) {
        _print(",");
      }
    }

    // Extra arguments common to all rules for this grammar
    _print(commonExtraArgs);
    if (commonExtraArgs.length() != 0 && rr.args!=null ) {
      _print(",");
    }

    // Process arguments to method, if any
    RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
    if (rr.args != null)
    {
      // When not guessing, execute user arg action
      ActionTransInfo tInfo = new ActionTransInfo();
      // FIXME: fix line number passed to processActionForTreeSpecifiers here..
      // this one might be a bit off..
      String args = processActionForSpecialSymbols(rr.args, rr.line,
                                    currentRule, tInfo);
      if ( tInfo.assignToRoot || tInfo.refRuleRoot!=null )
      {
        antlrTool.error("Arguments of rule reference '" + rr.targetRule + "' cannot set or ref #"+
          currentRule.getRuleName()+" on line "+rr.getLine());
      }
      _print(args);

      // Warn if the rule accepts no arguments
      if (rs.block.argAction == null)
      {
        antlrTool.warning("Rule '" + rr.targetRule + "' accepts no arguments",
          grammar.getFilename(),
          rr.getLine(), rr.getColumn());
      }
    }
    else
    {
      // For C++, no warning if rule has parameters, because there may be default
      // values for all of the parameters
      //if (rs.block.argAction != null) {
      //  tool.warning("Missing parameters on reference to rule "+rr.targetRule, rr.getLine());
      //}
    }
    _println(");");

    // move down to the first child while parsing
    if ( grammar instanceof TreeWalkerGrammar ) {
      println("_t = _retTree;");
    }
  }
  protected void genSemPred(String pred, int line) {
    // translate $ and # references
    ActionTransInfo tInfo = new ActionTransInfo();
    pred = processActionForSpecialSymbols(pred, line, currentRule, tInfo);
    // ignore translation info...we don't need to do anything with it.
    String escapedPred = charFormatter.escapeString(pred);

    // if debugging, wrap the semantic predicate evaluation in a method
    // that can tell SemanticPredicateListeners the result
    if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) ||
        (grammar instanceof LexerGrammar)))
      pred = "fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.VALIDATING," //FIXME
        + addSemPred(escapedPred) + "," + pred + ")";
    println("if (!(" + pred + "))");
    tabs++;
    println("throw "+namespaceAntlr+"SemanticException(\"" + escapedPred + "\");");
    tabs--;
  }
  /** Write an array of Strings which are the semantic predicate
   *  expressions.  The debugger will reference them by number only
   */
  protected void genSemPredMap(String prefix) {
    Enumeration e = semPreds.elements();
    println("const char* " + prefix + "_semPredNames[] = {");
    tabs++;
    while(e.hasMoreElements())
      println("\""+e.nextElement()+"\",");
    println("0");
    tabs--;
    println("};");
  }
  protected void genSynPred(SynPredBlock blk, String lookaheadExpr) {
    if ( DEBUG_CODE_GENERATOR || DEBUG_CPP_CODE_GENERATOR ) System.out.println("gen=>("+blk+")");

    // Dump synpred result variable
    println("bool synPredMatched" + blk.ID + " = false;");
    // Gen normal lookahead test
    println("if (" + lookaheadExpr + ") {");
    tabs++;

    // Save input state
    if ( grammar instanceof TreeWalkerGrammar ) {
      println(labeledElementType + " __t" + blk.ID + " = _t;");
    }
    else {
      println("int _m" + blk.ID + " = mark();");
    }

    // Once inside the try, assume synpred works unless exception caught
    println("synPredMatched" + blk.ID + " = true;");
    println("inputState->guessing++;");

    // if debugging, tell listeners that a synpred has started
    if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) ||
       (grammar instanceof LexerGrammar))) {
      println("fireSyntacticPredicateStarted();");
    }

    syntacticPredLevel++;
    println("try {");
    tabs++;
    gen((AlternativeBlock)blk);    // gen code to test predicate
    tabs--;
    //println("System.out.println(\"pred "+blk+" succeeded\");");
    println("}");
    println("catch (" + exceptionThrown + "& pe) {");
    tabs++;
    println("synPredMatched"+blk.ID+" = false;");
    //println("System.out.println(\"pred "+blk+" failed\");");
    tabs--;
    println("}");

    // Restore input state
    if ( grammar instanceof TreeWalkerGrammar ) {
      println("_t = __t"+blk.ID+";");
    }
    else {
      println("rewind(_m"+blk.ID+");");
    }

    println("inputState->guessing--;");

    // if debugging, tell listeners how the synpred turned out
    if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) ||
         (grammar instanceof LexerGrammar))) {
      println("if (synPredMatched" + blk.ID +")");
      println("  fireSyntacticPredicateSucceeded();");
      println("else");
      println("  fireSyntacticPredicateFailed();");
    }

    syntacticPredLevel--;
    tabs--;

    // Close lookahead test
    println("}");

    // Test synpred result
    println("if ( synPredMatched"+blk.ID+" ) {");
  }
  /** Generate a static array containing the names of the tokens,
   * indexed by the token type values.  This static array is used
   * to format error messages so that the token identifers or literal
   * strings are displayed instead of the token numbers.
   *
   * If a lexical rule has a paraphrase, use it rather than the
   * token label.
   */
  public void genTokenStrings(String prefix) {
    // Generate a string for each token.  This creates a static
    // array of Strings indexed by token type.
//    println("");
    println("const char* " + prefix + "tokenNames[] = {");
    tabs++;

    // Walk the token vocabulary and generate a Vector of strings
    // from the tokens.
    Vector v = grammar.tokenManager.getVocabulary();
    for (int i = 0; i < v.size(); i++)
    {
      String s = (String)v.elementAt(i);
      if (s == null)
      {
        s = "<"+String.valueOf(i)+">";
      }
      if ( !s.startsWith("\"") && !s.startsWith("<") ) {
        TokenSymbol ts = (TokenSymbol)grammar.tokenManager.getTokenSymbol(s);
        if ( ts!=null && ts.getParaphrase()!=null ) {
          s = StringUtils.stripFrontBack(ts.getParaphrase(), "\"", "\"");
        }
      }
      print(charFormatter.literalString(s));
      _println(",");
    }
    println("0");

    // Close the string array initailizer
    tabs--;
    println("};");
  }
  /** Generate the token types C++ file */
  protected void genTokenTypes(TokenManager tm) throws IOException {
    // Open the token output header file and set the currentOutput stream
    outputFile = tm.getName() + TokenTypesFileSuffix+".hpp";
    outputLine = 1;
    currentOutput = antlrTool.openOutputFile(outputFile);
    //SAS: changed for proper text file io

    tabs = 0;

    // Generate a guard wrapper
    println("#ifndef INC_"+tm.getName()+TokenTypesFileSuffix+"_hpp_");
    println("#define INC_"+tm.getName()+TokenTypesFileSuffix+"_hpp_");
    println("");

    if (nameSpace != null)
      nameSpace.emitDeclarations(currentOutput);

    // Generate the header common to all C++ files
    genHeader(outputFile);

    // Encapsulate the definitions in an interface.  This can be done
    // because they are all constants.
    println("");
    println("#ifndef CUSTOM_API");
    println("# define CUSTOM_API");
    println("#endif");
    println("");
    // In the case that the .hpp is included from C source (flexLexer!)
    // we just turn things into a plain enum
    println("#ifdef __cplusplus");
    println("struct CUSTOM_API " + tm.getName() + TokenTypesFileSuffix+" {");
    println("#endif");
    tabs++;
    println("enum {");
    tabs++;

    // Generate a definition for each token type
    Vector v = tm.getVocabulary();

    // Do special tokens manually
    println("EOF_ = " + Token.EOF_TYPE + ",");

    // Move the other special token to the end, so we can solve
    // the superfluous comma problem easily

    for (int i = Token.MIN_USER_TYPE; i < v.size(); i++) {
      String s = (String)v.elementAt(i);
      if (s != null) {
        if ( s.startsWith("\"") ) {
          // a string literal
          StringLiteralSymbol sl = (StringLiteralSymbol)tm.getTokenSymbol(s);
          if ( sl==null ) {
            antlrTool.panic("String literal "+s+" not in symbol table");
          }
          else if ( sl.label != null ) {
            println(sl.label + " = " + i + ",");
          }
          else {
            String mangledName = mangleLiteral(s);
            if (mangledName != null) {
              // We were able to create a meaningful mangled token name
              println(mangledName + " = " + i + ",");
              // if no label specified, make the label equal to the mangled name
              sl.label = mangledName;
            }
            else {
              println("// " + s + " = " + i);
            }
          }
        }
        else if ( !s.startsWith("<") ) {
          println(s + " = " + i + ",");
        }
      }
    }

    // Moved from above
    println("NULL_TREE_LOOKAHEAD = " + Token.NULL_TREE_LOOKAHEAD);

    // Close the enum
    tabs--;
    println("};");

    // Close the interface
    tabs--;
    println("#ifdef __cplusplus");
    println("};");
    println("#endif");

    if (nameSpace != null)
      nameSpace.emitClosures(currentOutput);

    // Generate a guard wrapper
    println("#endif /*INC_"+tm.getName()+TokenTypesFileSuffix+"_hpp_*/");

    // Close the tokens output file
    currentOutput.close();
    currentOutput = null;
    exitIfError();
  }
  /** Process a string for an simple expression for use in xx/action.g
   * it is used to cast simple tokens/references to the right type for
   * the generated language. Basically called for every element in
   * the vector to getASTCreateString(vector V)
   * @param str A String.
   */
  public String processStringForASTConstructor( String str )
  {
    if( usingCustomAST &&
      ((grammar instanceof TreeWalkerGrammar) ||
       (grammar instanceof ParserGrammar))  &&
      !(grammar.tokenManager.tokenDefined(str) ) )
    {
//      System.out.println("processStringForASTConstructor: "+str+" with cast");
      return namespaceAntlr+"RefAST("+str+")";
    }
    else
    {
//      System.out.println("processStringForASTConstructor: "+str);
      return str;
    }
  }
  /** Get a string for an expression to generate creation of an AST subtree.
    * @param v A Vector of String, where each element is an expression
    * in the target language yielding an AST node.
    */
  public String getASTCreateString(Vector v) {
    if (v.size() == 0) {
      return "";
    }
    StringBuffer buf = new StringBuffer();
    // the labeledElementASTType here can probably be a cast or nothing
    // in the case of ! usingCustomAST
    buf.append(labeledElementASTType+
          "(astFactory->make((new "+namespaceAntlr+
            "ASTArray("+v.size()+"))");
    for (int i = 0; i < v.size(); i++) {
      buf.append("->add("+ v.elementAt(i) + ")");
    }
    buf.append("))");
    return buf.toString();
  }
  /** Get a string for an expression to generate creating of an AST node
   * @param str The arguments to the AST constructor
   */
  public String getASTCreateString(GrammarAtom atom, String str) {
    if ( atom!=null && atom.getASTNodeType() != null ) {

      // this atom is using a heterogeneous AST type. (and maybe a local
      // override we can't see at the TokenManager level)
      // make note of the factory needed to generate it..
      // later this is inserted into the initializeFactory method.
      astTypes.ensureCapacity(atom.getType());
      String type = (String)astTypes.elementAt(atom.getType());
      if( type == null )
        astTypes.setElementAt(atom.getASTNodeType(),atom.getType());
      else
      {
        // give a warning over action taken if the types are unequal
        if( ! atom.getASTNodeType().equals(type) )
        {
          antlrTool.warning("Attempt to redefine AST type for "+atom.getText(),grammar.getFilename(),atom.getLine(),atom.getColumn());
          antlrTool.warning(" from \""+type+"\" to \""+atom.getASTNodeType()+"\" sticking to \""+type+"\"",grammar.getFilename(),atom.getLine(),atom.getColumn());
        }
        else
          astTypes.setElementAt(atom.getASTNodeType(),atom.getType());
      }
      // after above init the factory knows what to generate...
      return "astFactory->create("+str+")";
    }
    else
    {
      // FIXME: This is *SO* ugly! but it will have to do for now...
      // 2.7.2 will have better I hope
      // this is due to the usage of getASTCreateString from inside
      // actions/cpp/action.g
      boolean is_constructor = false;
      if( str.indexOf(',') != -1 )
        is_constructor = grammar.tokenManager.tokenDefined(str.substring(0,str.indexOf(',')));

//      System.out.println("getAstCreateString(as): "+str+" "+grammar.tokenManager.tokenDefined(str));
      if( usingCustomAST &&
         (grammar instanceof TreeWalkerGrammar) &&
        !(grammar.tokenManager.tokenDefined(str) ) &&
        ! is_constructor )
        return "astFactory->create("+namespaceAntlr+"RefAST("+str+"))";
      else
        return "astFactory->create("+str+")";
    }
  }

  /** Get a string for an expression to generate creating of an AST node
   * @param str The arguments to the AST constructor
   */
  public String getASTCreateString(String str) {
//    System.out.println("getAstCreateString(str): "+str+" "+grammar.tokenManager.tokenDefined(str));
    if( usingCustomAST )
      return labeledElementASTType+"(astFactory->create("+namespaceAntlr+"RefAST("+str+")))";
    else
      return "astFactory->create("+str+")";
  }

  protected String getLookaheadTestExpression(Lookahead[] look, int k) {
    StringBuffer e = new StringBuffer(100);
    boolean first = true;

    e.append("(");
    for (int i = 1; i <= k; i++) {
      BitSet p = look[i].fset;
      if (!first) {
        e.append(") && (");
      }
      first = false;

      // Syn preds can yield <end-of-syn-pred> (epsilon) lookahead.
      // There is no way to predict what that token would be.  Just
      // allow anything instead.
      if (look[i].containsEpsilon()) {
        e.append("true");
      } else {
        e.append(getLookaheadTestTerm(i, p));
      }
    }
    e.append(")");

    return e.toString();
  }
  /** Generate a lookahead test expression for an alternate.  This
   * will be a series of tests joined by '&&' and enclosed by '()',
   * the number of such tests being determined by the depth of the lookahead.
   */
  protected String getLookaheadTestExpression(Alternative alt, int maxDepth) {
    int depth = alt.lookaheadDepth;
    if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) {
      // if the decision is nondeterministic, do the best we can: LL(k)
      // any predicates that are around will be generated later.
      depth = grammar.maxk;
    }

    if ( maxDepth==0 ) {
      // empty lookahead can result from alt with sem pred
      // that can see end of token.  E.g., A : {pred}? ('a')? ;
      return "true";
    }

/*
boolean first = true;
    for (int i=1; i<=depth && i<=maxDepth; i++) {
      BitSet p = alt.cache[i].fset;
      if (!first) {
        e.append(") && (");
      }
      first = false;

      // Syn preds can yield <end-of-syn-pred> (epsilon) lookahead.
      // There is no way to predict what that token would be.  Just
      // allow anything instead.
      if ( alt.cache[i].containsEpsilon() ) {
        e.append("true");
      }
      else {
        e.append(getLookaheadTestTerm(i, p));
      }
    }

    e.append(")");
*/

    return "(" + getLookaheadTestExpression(alt.cache,depth) + ")";
  }
  /**Generate a depth==1 lookahead test expression given the BitSet.
   * This may be one of:
   * 1) a series of 'x==X||' tests
   * 2) a range test using >= && <= where possible,
   * 3) a bitset membership test for complex comparisons
   * @param k The lookahead level
   * @param p The lookahead set for level k
   */
  protected String getLookaheadTestTerm(int k, BitSet p) {
    // Determine the name of the item to be compared
    String ts = lookaheadString(k);

    // Generate a range expression if possible
    int[] elems = p.toArray();
    if (elementsAreRange(elems)) {
      return getRangeExpression(k, elems);
    }

    // Generate a bitset membership test if possible
    StringBuffer e;
    int degree = p.degree();
    if ( degree == 0 ) {
      return "true";
    }

    if (degree >= bitsetTestThreshold) {
      int bitsetIdx = markBitsetForGen(p);
      return getBitsetName(bitsetIdx) + ".member(" + ts + ")";
    }

    // Otherwise, generate the long-winded series of "x==X||" tests
    e = new StringBuffer();
    for (int i = 0; i < elems.length; i++) {
      // Get the compared-to item (token or character value)
      String cs = getValueString(elems[i]);

      // Generate the element comparison
      if( i > 0 ) e.append(" || ");
      e.append(ts);
      e.append(" == ");
      e.append(cs);
    }
    return e.toString();
  }
  /** Return an expression for testing a contiguous renage of elements
   * @param k The lookahead level
   * @param elems The elements representing the set, usually from BitSet.toArray().
   * @return String containing test expression.
   */
  public String getRangeExpression(int k, int[] elems) {
    if (!elementsAreRange(elems)) {
      antlrTool.panic("getRangeExpression called with non-range");
    }
    int begin = elems[0];
    int end = elems[elems.length-1];
    return
      "(" + lookaheadString(k) + " >= " + getValueString(begin) + " && " +
        lookaheadString(k) + " <= " + getValueString(end) + ")";
  }
  /** getValueString: get a string representation of a token or char value
   * @param value The token or char value
   */
  private String getValueString(int value) {
    String cs;
    if ( grammar instanceof LexerGrammar ) {
      cs = charFormatter.literalChar(value);
    }
    else
    {
      TokenSymbol ts = grammar.tokenManager.getTokenSymbolAt(value);
      if ( ts == null ) {
        return ""+value; // return token type as string
        // tool.panic("vocabulary for token type " + value + " is null");
      }
      String tId = ts.getId();
      if ( ts instanceof StringLiteralSymbol ) {
        // if string literal, use predefined label if any
        // if no predefined, try to mangle into LITERAL_xxx.
        // if can't mangle, use int value as last resort
        StringLiteralSymbol sl = (StringLiteralSymbol)ts;
        String label = sl.getLabel();
        if ( label!=null ) {
          cs = label;
        }
        else {
          cs = mangleLiteral(tId);
          if (cs == null) {
            cs = String.valueOf(value);
          }
        }
      }
      else {
        if ( tId.equals("EOF") )
          cs = namespaceAntlr+"Token::EOF_TYPE";
        else
          cs = tId;
      }
    }
    return cs;
  }
  /**Is the lookahead for this alt empty? */
  protected boolean lookaheadIsEmpty(Alternative alt, int maxDepth) {
    int depth = alt.lookaheadDepth;
    if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) {
      depth = grammar.maxk;
    }
    for (int i=1; i<=depth && i<=maxDepth; i++) {
      BitSet p = alt.cache[i].fset;
      if (p.degree() != 0) {
        return false;
      }
    }
    return true;
  }
  private String lookaheadString(int k) {
    if (grammar instanceof TreeWalkerGrammar) {
      return "_t->getType()";
    }
    return "LA(" + k + ")";
  }
  /** Mangle a string literal into a meaningful token name.  This is
    * only possible for literals that are all characters.  The resulting
    * mangled literal name is literalsPrefix with the text of the literal
    * appended.
    * @return A string representing the mangled literal, or null if not possible.
    */
  private String mangleLiteral(String s) {
    String mangled = antlrTool.literalsPrefix;
    for (int i = 1; i < s.length()-1; i++) {
      if (!Character.isLetter(s.charAt(i)) &&
         s.charAt(i) != '_') {
        return null;
      }
      mangled += s.charAt(i);
    }
    if ( antlrTool.upperCaseMangledLiterals ) {
      mangled = mangled.toUpperCase();
    }
    return mangled;
  }
  /** Map an identifier to it's corresponding tree-node variable.
    * This is context-sensitive, depending on the rule and alternative
    * being generated
    * @param idParam The identifier name to map
    * @return The mapped id (which may be the same as the input), or null if the mapping is invalid due to duplicates
    */
  public String mapTreeId(String idParam, ActionTransInfo transInfo) {
    // if not in an action of a rule, nothing to map.
    if ( currentRule==null ) return idParam;
//    System.out.print("mapTreeId: "+idParam+" "+currentRule.getRuleName()+" ");

    boolean in_var = false;
    String id = idParam;
    if (grammar instanceof TreeWalkerGrammar)
    {
//      RK: hmmm this seems odd. If buildAST is false it translates
//      #rulename_in to 'rulename_in' else to 'rulename_AST_in' which indeed
//      exists. disabling for now.. and hope it doesn't blow up somewhere.
      if ( !grammar.buildAST )
      {
        in_var = true;
//        System.out.println("in_var1");
      }
      // If the id ends with "_in", then map it to the input variable
//      else
      if (id.length() > 3 && id.lastIndexOf("_in") == id.length()-3)
      {
        // Strip off the "_in"
        id = id.substring(0, id.length()-3);
        in_var = true;
//        System.out.println("in_var2");
      }
    }
//    System.out.print(in_var+"\t");

    // Check the rule labels.  If id is a label, then the output
    // variable is label_AST, and the input variable is plain label.
    for (int i = 0; i < currentRule.labeledElements.size(); i++)
    {
      AlternativeElement elt = (AlternativeElement)currentRule.labeledElements.elementAt(i);
      if (elt.getLabel().equals(id))
      {
//        if( in_var )
//          System.out.println("returning (vec) "+(in_var ? id : id + "_AST"));
        return in_var ? id : id + "_AST";
      }
    }

    // Failing that, check the id-to-variable map for the alternative.
    // If the id is in the map, then output variable is the name in the
    // map, and input variable is name_in
    String s = (String)treeVariableMap.get(id);
    if (s != null)
    {
      if (s == NONUNIQUE)
      {
//        if( in_var )
//          System.out.println("returning null (nonunique)");
        // There is more than one element with this id
        antlrTool.error("Ambiguous reference to AST element "+id+
                " in rule "+currentRule.getRuleName());
        return null;
      }
      else if (s.equals(currentRule.getRuleName()))
      {
        // a recursive call to the enclosing rule is
        // ambiguous with the rule itself.
//        if( in_var )
//          System.out.println("returning null (rulename)");
        antlrTool.error("Ambiguous reference to AST element "+id+
                " in rule "+currentRule.getRuleName());
        return null;
      }
      else
      {
//        if( in_var )
//        System.out.println("returning "+(in_var?s+"_in":s));
        return in_var ? s + "_in" : s;
      }
    }

//    System.out.println("Last check: "+id+" == "+currentRule.getRuleName());
    // Failing that, check the rule name itself.  Output variable
    // is rule_AST; input variable is rule_AST_in (treeparsers).
    if( id.equals(currentRule.getRuleName()) )
    {
      String r = in_var ? id + "_AST_in" : id + "_AST";
      if ( transInfo!=null ) {
        if ( !in_var ) {
          transInfo.refRuleRoot = r;
        }
      }
//      if( in_var )
//        System.out.println("returning (r) "+r);
      return r;
    }
    else
    {
//      if( in_var )
//      System.out.println("returning (last) "+id);
      // id does not map to anything -- return itself.
      return id;
    }
  }
  /** Given an element and the name of an associated AST variable,
    * create a mapping between the element "name" and the variable name.
    */
  private void mapTreeVariable(AlternativeElement e, String name)
  {
    // For tree elements, defer to the root
    if (e instanceof TreeElement) {
      mapTreeVariable( ((TreeElement)e).root, name);
      return;
    }

    // Determine the name of the element, if any, for mapping purposes
    String elName = null;

    // Don't map labeled items
    if (e.getLabel() == null) {
      if (e instanceof TokenRefElement) {
        // use the token id
        elName = ((TokenRefElement)e).atomText;
      }
      else if (e instanceof RuleRefElement) {
        // use the rule name
        elName = ((RuleRefElement)e).targetRule;
      }
    }
    // Add the element to the tree variable map if it has a name
    if (elName != null) {
      if (treeVariableMap.get(elName) != null) {
        // Name is already in the map -- mark it as duplicate
        treeVariableMap.remove(elName);
        treeVariableMap.put(elName, NONUNIQUE);
      }
      else {
        treeVariableMap.put(elName, name);
      }
    }
  }

  /** Lexically process tree-specifiers in the action.
   * This will replace #id and #(...) with the appropriate
   * function calls and/or variables.
   */
  protected String processActionForSpecialSymbols(String actionStr,
                                  int line,
                                  RuleBlock currentRule,
                                  ActionTransInfo tInfo)
  {
    if ( actionStr==null || actionStr.length()==0 )
      return null;

    // The action trans info tells us (at the moment) whether an
    // assignment was done to the rule's tree root.
    if (grammar==null)
      return actionStr;

    if ((grammar.buildAST && actionStr.indexOf('#') != -1) ||
       grammar instanceof TreeWalkerGrammar ||
       ((grammar instanceof LexerGrammar ||
        grammar instanceof ParserGrammar)
          && actionStr.indexOf('$') != -1) )
    {
      // Create a lexer to read an action and return the translated version
      antlr.actions.cpp.ActionLexer lexer =
        new antlr.actions.cpp.ActionLexer(actionStr, currentRule, this, tInfo);
      lexer.setLineOffset(line);
      lexer.setFilename(grammar.getFilename());
      lexer.setTool(antlrTool);

      try {
        lexer.mACTION(true);
        actionStr = lexer.getTokenObject().getText();
        // System.out.println("action translated: "+actionStr);
        // System.out.println("trans info is "+tInfo);
      }
      catch (RecognitionException ex) {
        lexer.reportError(ex);
        return actionStr;
      }
      catch (TokenStreamException tex) {
        antlrTool.panic("Error reading action:"+actionStr);
        return actionStr;
      }
      catch (CharStreamException io) {
        antlrTool.panic("Error reading action:"+actionStr);
        return actionStr;
      }
    }
    return actionStr;
  }

  private String fixNameSpaceOption( String ns )
  {
    ns = StringUtils.stripFrontBack(ns,"\"","\"");
    if( ns.length() > 2 &&
       !ns.substring(ns.length()-2, ns.length()).equals("::") )
    ns += "::";
    return ns;
  }

  private void setupGrammarParameters(Grammar g) {
    if (g instanceof ParserGrammar ||
       g instanceof LexerGrammar  ||
       g instanceof TreeWalkerGrammar
      )
    {
      /* RK: options also have to be added to Grammar.java and for options
       * on the file level entries have to be defined in
       * DefineGrammarSymbols.java and passed around via 'globals' in
       * antlrTool.java
       */
      if( antlrTool.nameSpace != null )
        nameSpace = antlrTool.nameSpace;

      if( antlrTool.namespaceStd != null )
        namespaceStd = fixNameSpaceOption(antlrTool.namespaceStd);

      if( antlrTool.namespaceAntlr != null )
        namespaceAntlr = fixNameSpaceOption(antlrTool.namespaceAntlr);

      genHashLines = antlrTool.genHashLines;

      /* let grammar level options override filelevel ones...
       */
      if( g.hasOption("namespace") ) {
        Token t = g.getOption("namespace");
        if( t != null ) {
          nameSpace = new NameSpace(t.getText());
        }
      }
      if( g.hasOption("namespaceAntlr") ) {
        Token t = g.getOption("namespaceAntlr");
        if( t != null ) {
          String ns = StringUtils.stripFrontBack(t.getText(),"\"","\"");
          if ( ns != null ) {
            if( ns.length() > 2 &&
               !ns.substring(ns.length()-2, ns.length()).equals("::") )
              ns += "::";
            namespaceAntlr = ns;
          }
        }
      }
      if( g.hasOption("namespaceStd") ) {
        Token t = g.getOption("namespaceStd");
        if( t != null ) {
          String ns = StringUtils.stripFrontBack(t.getText(),"\"","\"");
          if ( ns != null ) {
            if( ns.length() > 2 &&
               !ns.substring(ns.length()-2, ns.length()).equals("::") )
              ns += "::";
            namespaceStd = ns;
          }
        }
      }
      if( g.hasOption("genHashLines") ) {
        Token t = g.getOption("genHashLines");
        if( t != null ) {
          String val = StringUtils.stripFrontBack(t.getText(),"\"","\"");
          genHashLines = val.equals("true");
        }
      }
      noConstructors = antlrTool.noConstructors;  // get the default
      if( g.hasOption("noConstructors") ) {
        Token t = g.getOption("noConstructors");
        if( (t != null) && !(t.getText().equals("true") || t.getText().equals("false")))
          antlrTool.error("noConstructors option must be true or false", antlrTool.getGrammarFile(), t.getLine(), t.getColumn());
        noConstructors = t.getText().equals("true");
      }
    }
    if (g instanceof ParserGrammar) {
      labeledElementASTType = namespaceAntlr+"RefAST";
      labeledElementASTInit = namespaceAntlr+"nullAST";
      if ( g.hasOption("ASTLabelType") ) {
        Token tsuffix = g.getOption("ASTLabelType");
        if ( tsuffix != null ) {
          String suffix = StringUtils.stripFrontBack(tsuffix.getText(),"\"","\"");
          if ( suffix != null ) {
            usingCustomAST = true;
            labeledElementASTType = suffix;
            labeledElementASTInit = suffix+"("+namespaceAntlr+"nullAST)";
          }
        }
      }
      labeledElementType = namespaceAntlr+"RefToken ";
      labeledElementInit = namespaceAntlr+"nullToken";
      commonExtraArgs = "";
      commonExtraParams = "";
      commonLocalVars = "";
      lt1Value = "LT(1)";
      exceptionThrown = namespaceAntlr+"RecognitionException";
      throwNoViable = "throw "+namespaceAntlr+"NoViableAltException(LT(1), getFilename());";
    }
    else if (g instanceof LexerGrammar) {
      labeledElementType = "char ";
      labeledElementInit = "'\\0'";
      commonExtraArgs = "";
      commonExtraParams = "bool _createToken";
      commonLocalVars = "int _ttype; "+namespaceAntlr+"RefToken _token; "+namespaceStd+"string::size_type _begin = text.length();";
      lt1Value = "LA(1)";
      exceptionThrown = namespaceAntlr+"RecognitionException";
      throwNoViable = "throw "+namespaceAntlr+"NoViableAltForCharException(LA(1), getFilename(), getLine(), getColumn());";
    }
    else if (g instanceof TreeWalkerGrammar) {
      labeledElementInit = namespaceAntlr+"nullAST";
      labeledElementASTInit = namespaceAntlr+"nullAST";
      labeledElementASTType = namespaceAntlr+"RefAST";
      labeledElementType = namespaceAntlr+"RefAST";
      commonExtraParams = namespaceAntlr+"RefAST _t";
      throwNoViable = "throw "+namespaceAntlr+"NoViableAltException(_t);";
      lt1Value = "_t";
      if ( g.hasOption("ASTLabelType") ) {
        Token tsuffix = g.getOption("ASTLabelType");
        if ( tsuffix != null ) {
          String suffix = StringUtils.stripFrontBack(tsuffix.getText(),"\"","\"");
          if ( suffix != null ) {
            usingCustomAST = true;
            labeledElementASTType = suffix;
            labeledElementType = suffix;
            labeledElementInit = suffix+"("+namespaceAntlr+"nullAST)";
            labeledElementASTInit = labeledElementInit;
            commonExtraParams = suffix+" _t";
            throwNoViable = "throw "+namespaceAntlr+"NoViableAltException("+namespaceAntlr+"RefAST(_t));";
            lt1Value = "_t";
          }
        }
      }
      if ( !g.hasOption("ASTLabelType") ) {
        g.setOption("ASTLabelType", new Token(ANTLRTokenTypes.STRING_LITERAL,namespaceAntlr+"RefAST"));
      }
      commonExtraArgs = "_t";
      commonLocalVars = "";
      exceptionThrown = namespaceAntlr+"RecognitionException";
    }
    else {
      antlrTool.panic("Unknown grammar type");
    }
  }
}
TOP

Related Classes of antlr.CppCodeGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.