package antlr; /* ANTLR Translator Generator * Project led by Terence Parr at http://www.jGuru.com * Software rights: http://www.antlr.org/RIGHTS.html * * $Id: JavaCodeGenerator.java,v 1.1 2004/01/21 19:18:31 rgrimm Exp $ */ import java.util.Enumeration; import java.util.Hashtable; import java.util.HashSet; 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.java, MyLexer.java and MyParserTokenTypes.java */ public class JavaCodeGenerator extends CodeGenerator { // 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; // Grammar parameters set up to handle different grammar classes. // These are used to get instanceof tests out of code generation String labeledElementType; String labeledElementASTType; 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 */ HashSet declaredASTVariables = new HashSet(); /* 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; /** Create a Java code-generator using the given Grammar. * The caller must still call setTool, setBehavior, and setAnalyzer * before generating code. */ public JavaCodeGenerator() { super(); charFormatter = new JavaCharFormatter(); } /** 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."); } } /**Generate the parser, lexer, treeparser, and token types in Java */ 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(); // 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(); // print out the grammar with lookahead sets (and FOLLOWs) // System.out.print(g.toString()); 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 Java // 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) System.out.println("genAction(" + action + ")"); if (action.isSemPred) { genSemPred(action.actionText, action.line); } else { if (grammar.hasSyntacticPredicate) { println("if ( inputState.guessing==0 ) {"); tabs++; } // get the name of the followSet for the current rule so that we // can replace $FOLLOW in the .g file. 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 printAction(actionStr); 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 println("currentAST.child = " + tInfo.refRuleRoot + "!=null &&" + tInfo.refRuleRoot + ".getFirstChild()!=null ?"); tabs++; println(tInfo.refRuleRoot + ".getFirstChild() : " + 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) 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); JavaBlockFinishingInfo 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) System.out.println("genRuleEnd(" + end + ")"); } /** Generate code for the given grammar element. * @param blk The character literal reference to generate */ public void gen(CharLiteralElement atom) { if (DEBUG_CODE_GENERATOR) System.out.println("genChar(" + atom + ")"); if (atom.getLabel() != null) { println(atom.getLabel() + " = " + lt1Value + ";"); } boolean oldsaveText = saveText; saveText = saveText && atom.getAutoGenType() == GrammarElement.AUTO_GEN_NONE; genMatch(atom); saveText = oldsaveText; } /** Generate code for the given grammar element. * @param blk The character-range reference to generate */ public void gen(CharRangeElement r) { if (r.getLabel() != null && syntacticPredLevel == 0) { println(r.getLabel() + " = " + lt1Value + ";"); } boolean flag = ( grammar instanceof LexerGrammar && ( !saveText || r.getAutoGenType() == GrammarElement.AUTO_GEN_BANG ) ); if (flag) { println("_saveIndex=text.length();"); } println("matchRange(" + r.beginText + "," + r.endText + ");"); if (flag) { println("text.setLength(_saveIndex);"); } } /** Generate the lexer Java file */ public void gen(LexerGrammar g) throws IOException { // If debugging, create a new sempred vector for this grammar if (g.debuggingOutput) semPreds = new Vector(); setGrammar(g); if (!(grammar instanceof LexerGrammar)) { antlrTool.panic("Internal error generating lexer"); } // SAS: moved output creation to method so a subclass can change // how the output is generated (for VAJ interface) setupOutput(grammar.getClassName()); genAST = false; // no way to gen trees. saveText = true; // save consumed characters. tabs = 0; // Generate header common to all Java output files genHeader(); // Do not use printAction because we assume tabs==0 println(behavior.getHeaderAction("")); // Generate header specific to lexer Java file // println("import java.io.FileInputStream;"); println("import java.io.InputStream;"); println("import antlr.TokenStreamException;"); println("import antlr.TokenStreamIOException;"); println("import antlr.TokenStreamRecognitionException;"); println("import antlr.CharStreamException;"); println("import antlr.CharStreamIOException;"); println("import antlr.ANTLRException;"); println("import java.io.Reader;"); println("import java.util.Hashtable;"); println("import antlr." + grammar.getSuperClass() + ";"); println("import antlr.InputBuffer;"); println("import antlr.ByteBuffer;"); println("import antlr.CharBuffer;"); println("import antlr.Token;"); println("import antlr.CommonToken;"); println("import antlr.RecognitionException;"); println("import antlr.NoViableAltForCharException;"); println("import antlr.MismatchedCharException;"); println("import antlr.TokenStream;"); println("import antlr.ANTLRHashString;"); println("import antlr.LexerSharedInputState;"); println("import antlr.collections.impl.BitSet;"); println("import antlr.SemanticException;"); // Generate user-defined lexer file preamble println(grammar.preambleAction.getText()); // Generate lexer class definition String sup = null; if (grammar.superClass != null) { sup = grammar.superClass; } else { sup = "antlr." + grammar.getSuperClass(); } // print javadoc comment if any if (grammar.comment != null) { _println(grammar.comment); } // get prefix (replaces "public" and lets user specify) String prefix = "public"; Token tprefix = (Token)grammar.options.get("classHeaderPrefix"); if (tprefix != null) { String p = StringUtils.stripFrontBack(tprefix.getText(), "\"", "\""); if (p != null) { prefix = p; } } print(prefix+" "); print("class " + grammar.getClassName() + " extends " + sup); println(" implements " + grammar.tokenManager.getName() + TokenTypesFileSuffix + ", TokenStream"); 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 print( processActionForSpecialSymbols(grammar.classMemberAction.getText(), grammar.classMemberAction.getLine(), currentRule, null) ); // // Generate the constructor from InputStream, which in turn // calls the ByteBuffer constructor // println("public " + grammar.getClassName() + "(InputStream in) {"); tabs++; println("this(new ByteBuffer(in));"); tabs--; println("}"); // // Generate the constructor from Reader, which in turn // calls the CharBuffer constructor // println("public " + grammar.getClassName() + "(Reader in) {"); tabs++; println("this(new CharBuffer(in));"); tabs--; println("}"); println("public " + grammar.getClassName() + "(InputBuffer ib) {"); tabs++; // if debugging, wrap the input buffer in a debugger if (grammar.debuggingOutput) println("this(new LexerSharedInputState(new antlr.debug.DebuggingInputBuffer(ib)));"); else println("this(new LexerSharedInputState(ib));"); tabs--; println("}"); // // Generate the constructor from InputBuffer (char or byte) // println("public " + grammar.getClassName() + "(LexerSharedInputState state) {"); tabs++; println("super(state);"); // if debugging, set up array variables and call user-overridable // debugging setup method if (grammar.debuggingOutput) { println(" ruleNames = _ruleNames;"); println(" semPredNames = _semPredNames;"); println(" setupDebugging();"); } // Generate the setting of various generated options. // These need to be before the literals since ANTLRHashString depends on // the casesensitive stuff. println("caseSensitiveLiterals = " + g.caseSensitiveLiterals + ";"); println("setCaseSensitive(" + g.caseSensitive + ");"); // Generate the initialization of a hashtable // containing the string literals used in the lexer // The literals variable itself is in CharScanner println("literals = new Hashtable();"); 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.put(new ANTLRHashString(" + s.getId() + ", this), new Integer(" + s.getTokenType() + "));"); } } tabs--; Enumeration ids; println("}"); // generate the rule name array for debugging if (grammar.debuggingOutput) { println("private static final String _ruleNames[] = {"); ids = grammar.rules.elements(); int ruleNum = 0; while (ids.hasMoreElements()) { GrammarSymbol sym = (GrammarSymbol)ids.nextElement(); if (sym instanceof RuleSymbol) println(" \"" + ((RuleSymbol)sym).getId() + "\","); } 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++); } exitIfError(); } // Generate the semantic predicate map for debugging if (grammar.debuggingOutput) genSemPredMap(); // Generate the bitsets used throughout the lexer genBitsets(bitsetsUsed, ((LexerGrammar)grammar).charVocabulary.size()); println(""); println("}"); // Close the lexer output stream currentOutput.close(); currentOutput = null; } /** Generate code for the given grammar element. * @param blk The (...)+ block to generate */ public void gen(OneOrMoreBlock blk) { if (DEBUG_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(label + ":"); println("do {"); 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) { 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 + ") break " + label + ";"); } JavaBlockFinishingInfo howToFinish = genCommonBlock(blk, false); genBlockFinish( howToFinish, "if ( " + cnt + ">=1 ) { break " + label + "; } else {" + throwNoViable + "}" ); println(cnt + "++;"); tabs--; println("} while (true);"); println("}"); // Restore previous AST generation currentASTResult = saveCurrentASTResult; } /** Generate the parser Java 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"); } // Open the output stream for the parser and set the currentOutput // SAS: moved file setup so subclass could do it (for VAJ interface) setupOutput(grammar.getClassName()); genAST = grammar.buildAST; tabs = 0; // Generate the header common to all output files. genHeader(); // Do not use printAction because we assume tabs==0 println(behavior.getHeaderAction("")); // Generate header for the parser println("import antlr.TokenBuffer;"); println("import antlr.TokenStreamException;"); println("import antlr.TokenStreamIOException;"); println("import antlr.ANTLRException;"); println("import antlr." + grammar.getSuperClass() + ";"); println("import antlr.Token;"); println("import antlr.TokenStream;"); println("import antlr.RecognitionException;"); println("import antlr.NoViableAltException;"); println("import antlr.MismatchedTokenException;"); println("import antlr.SemanticException;"); println("import antlr.ParserSharedInputState;"); println("import antlr.collections.impl.BitSet;"); if ( genAST ) { println("import antlr.collections.AST;"); println("import java.util.Hashtable;"); println("import antlr.ASTFactory;"); println("import antlr.ASTPair;"); println("import antlr.collections.impl.ASTArray;"); } // Output the user-defined parser preamble println(grammar.preambleAction.getText()); // Generate parser class definition String sup = null; if (grammar.superClass != null) sup = grammar.superClass; else sup = "antlr." + grammar.getSuperClass(); // print javadoc comment if any if (grammar.comment != null) { _println(grammar.comment); } // get prefix (replaces "public" and lets user specify) String prefix = "public"; Token tprefix = (Token)grammar.options.get("classHeaderPrefix"); if (tprefix != null) { String p = StringUtils.stripFrontBack(tprefix.getText(), "\"", "\""); if (p != null) { prefix = p; } } print(prefix+" "); print("class " + grammar.getClassName() + " extends " + sup); println(" implements " + 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("private static final String _ruleNames[] = {"); 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("};"); } // Generate user-defined parser class members print( processActionForSpecialSymbols(grammar.classMemberAction.getText(), grammar.classMemberAction.getLine(), currentRule, null) ); // Generate parser class constructor from TokenBuffer println(""); println("protected " + grammar.getClassName() + "(TokenBuffer tokenBuf, int k) {"); println(" super(tokenBuf,k);"); println(" tokenNames = _tokenNames;"); // if debugging, set up arrays and call the user-overridable // debugging setup method if (grammar.debuggingOutput) { println(" ruleNames = _ruleNames;"); println(" semPredNames = _semPredNames;"); println(" setupDebugging(tokenBuf);"); } if ( grammar.buildAST ) { println(" buildTokenTypeASTClassMap();"); println(" astFactory = new ASTFactory(getTokenTypeToASTClassMap());"); } println("}"); println(""); println("public " + grammar.getClassName() + "(TokenBuffer tokenBuf) {"); println(" this(tokenBuf," + grammar.maxk + ");"); println("}"); println(""); // Generate parser class constructor from TokenStream println("protected " + grammar.getClassName() + "(TokenStream lexer, int k) {"); println(" super(lexer,k);"); println(" tokenNames = _tokenNames;"); // if debugging, set up arrays and call the user-overridable // debugging setup method if (grammar.debuggingOutput) { println(" ruleNames = _ruleNames;"); println(" semPredNames = _semPredNames;"); println(" setupDebugging(lexer);"); } if ( grammar.buildAST ) { println(" buildTokenTypeASTClassMap();"); println(" astFactory = new ASTFactory(getTokenTypeToASTClassMap());"); } println("}"); println(""); println("public " + grammar.getClassName() + "(TokenStream lexer) {"); println(" this(lexer," + grammar.maxk + ");"); println("}"); println(""); println("public " + grammar.getClassName() + "(ParserSharedInputState state) {"); println(" super(state," + grammar.maxk + ");"); println(" tokenNames = _tokenNames;"); if ( grammar.buildAST ) { println(" buildTokenTypeASTClassMap();"); println(" astFactory = new ASTFactory(getTokenTypeToASTClassMap());"); } println("}"); println(""); // 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++); } exitIfError(); } // Generate the token names genTokenStrings(); if ( grammar.buildAST ) { genTokenASTNodeMap(); } // Generate the bitsets used throughout the grammar genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType()); // Generate the semantic predicate map for debugging if (grammar.debuggingOutput) genSemPredMap(); // Close class definition println(""); println("}"); // Close the parser output stream currentOutput.close(); currentOutput = null; } /** Generate code for the given grammar element. * @param blk The rule-reference to generate */ public void gen(RuleRefElement rr) { if (DEBUG_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 ? null : " + 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.setLength(_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 println(rr.getLabel() + "_AST = (" + labeledElementASTType + ")returnAST;"); } if (genAST) { switch (rr.getAutoGenType()) { case GrammarElement.AUTO_GEN_NONE: // println("theASTFactory.addASTChild(currentAST, returnAST);"); println("astFactory.addASTChild(currentAST, returnAST);"); break; case GrammarElement.AUTO_GEN_CARET: 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) 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) 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("AST __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==ASTNULL ? null :(" + labeledElementASTType + ")_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("ASTPair __currentAST" + t.ID + " = currentAST.copy();"); // Make the next item added a child of the TreeElement root println("currentAST.root = currentAST.child;"); println("currentAST.child = null;"); } // match root if ( t.root instanceof WildcardElement ) { println("if ( _t==null ) throw new 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 Java file */ public void gen(TreeWalkerGrammar g) throws IOException { // SAS: debugging stuff removed for now... setGrammar(g); if (!(grammar instanceof TreeWalkerGrammar)) { antlrTool.panic("Internal error generating tree-walker"); } // Open the output stream for the parser and set the currentOutput // SAS: move file open to method so subclass can override it // (mainly for VAJ interface) setupOutput(grammar.getClassName()); genAST = grammar.buildAST; tabs = 0; // Generate the header common to all output files. genHeader(); // Do not use printAction because we assume tabs==0 println(behavior.getHeaderAction("")); // Generate header for the parser println("import antlr." + grammar.getSuperClass() + ";"); println("import antlr.Token;"); println("import antlr.collections.AST;"); println("import antlr.RecognitionException;"); println("import antlr.ANTLRException;"); println("import antlr.NoViableAltException;"); println("import antlr.MismatchedTokenException;"); println("import antlr.SemanticException;"); println("import antlr.collections.impl.BitSet;"); println("import antlr.ASTPair;"); println("import antlr.collections.impl.ASTArray;"); // Output the user-defined parser premamble println(grammar.preambleAction.getText()); // Generate parser class definition String sup = null; if (grammar.superClass != null) { sup = grammar.superClass; } else { sup = "antlr." + grammar.getSuperClass(); } println(""); // print javadoc comment if any if (grammar.comment != null) { _println(grammar.comment); } // get prefix (replaces "public" and lets user specify) String prefix = "public"; Token tprefix = (Token)grammar.options.get("classHeaderPrefix"); if (tprefix != null) { String p = StringUtils.stripFrontBack(tprefix.getText(), "\"", "\""); if (p != null) { prefix = p; } } print(prefix+" "); print("class " + grammar.getClassName() + " extends " + sup); println(" implements " + 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 print( processActionForSpecialSymbols(grammar.classMemberAction.getText(), grammar.classMemberAction.getLine(), currentRule, null) ); // Generate default parser class constructor println("public " + grammar.getClassName() + "() {"); tabs++; println("tokenNames = _tokenNames;"); tabs--; println("}"); println(""); // 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++); } exitIfError(); } // Generate the token names genTokenStrings(); // Generate the bitsets used throughout the grammar genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType()); // Close class definition println("}"); println(""); // Close the parser output stream currentOutput.close(); currentOutput = null; } /** 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==null ) throw new 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.setLength(_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) System.out.println("gen*(" + blk + ")"); println("{"); genBlockPreamble(blk); String label; if (blk.getLabel() != null) { label = blk.getLabel(); } else { label = "_loop" + blk.ID; } println(label + ":"); println("do {"); 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) { System.out.println("nongreedy (...)* loop; exit depth is " + blk.exitLookaheadDepth); } String predictExit = getLookaheadTestExpression(blk.exitCache, nonGreedyExitDepth); println("// nongreedy exit test"); println("if (" + predictExit + ") break " + label + ";"); } JavaBlockFinishingInfo howToFinish = genCommonBlock(blk, false); genBlockFinish(howToFinish, "break " + label + ";"); tabs--; println("} while (true);"); 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 (grammar.hasSyntacticPredicate) { // println("if ( inputState.guessing==0 ) {"); // tabs++; } println(rblk.getRuleName() + "_AST = (" + labeledElementASTType + ")currentAST.root;"); if (grammar.hasSyntacticPredicate) { // --tabs; // println("}"); } } else if (blk.getLabel() != null) { // ### future: also set AST value for labeled subrules. // println(blk.getLabel() + "_AST = ("+labeledElementASTType+")currentAST.root;"); antlrTool.warning("Labeled subrules not yet supported", 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. */ protected void genBitsets(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); genBitSet(p, i); } } /** Do something simple like: * private static final long[] mk_tokenSet_0() { * long[] data = { -2305839160922996736L, 63L, 16777216L, 0L, 0L, 0L }; * return data; * } * public static final BitSet _tokenSet_0 = new BitSet(mk_tokenSet_0()); * * Or, for large bitsets, optimize init so ranges are collapsed into loops. * This is most useful for lexers using unicode. */ private void genBitSet(BitSet p, int id) { // initialization data println( "private static final long[] mk" + getBitsetName(id) + "() {" ); int n = p.lengthInLongWords(); if ( n<BITSET_OPTIMIZE_INIT_THRESHOLD ) { println("\tlong[] data = { " + p.toStringOfWords() + "};"); } else { // will init manually, allocate space then set values println("\tlong[] data = new long["+n+"];"); long[] elems = p.toPackedArray(); for (int i = 0; i < elems.length;) { if ( elems[i]==0 ) { // done automatically by Java, don't waste time/code i++; continue; } if ( (i+1)==elems.length || elems[i]!=elems[i+1] ) { // last number or no run of numbers, just dump assignment println("\tdata["+i+"]="+elems[i]+"L;"); i++; } else { // scan to find end of run int j; for (j = i + 1; j < elems.length && elems[j]==elems[i]; j++) { } // j-1 is last member of run println("\tfor (int i = "+i+"; i<="+(j-1)+"; i++) { data[i]="+ elems[i]+"L; }"); i = j; } } } println("\treturn data;"); println("}"); // BitSet object println( "public static final BitSet " + getBitsetName(id) + " = new BitSet(" + "mk" + getBitsetName(id) + "()" + ");" ); } /** 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(JavaBlockFinishingInfo 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 init action 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) { printAction(processActionForSpecialSymbols(blk.initAction, blk.getLine(), currentRule, null)); } } /** 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("Token " + a.getLabel() + "=null;"); } 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, ga.getASTNodeType()); } else { genASTDeclaration(a); } } } } } } } /** 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) System.out.println("genCases(" + p + ")"); int[] elems; elems = p.toArray(); // Wrap cases four-per-line for lexer, one-per-line for parser int wrap = (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 JavaBlockFinishingInfo genCommonBlock(AlternativeBlock blk, boolean noTestForSingle) { int nIF = 0; boolean createdLL1Switch = false; int closingBracesOfIFSequence = 0; JavaBlockFinishingInfo finishingInfo = new JavaBlockFinishingInfo(); if (DEBUG_CODE_GENERATOR) System.out.println("genCommonBlock(" + 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) ) { if (DEBUG_CODE_GENERATOR) System.out.println("special case: ~(subrule)"); 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) { 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==null) _t=ASTNULL;"); } 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 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) System.out.println("checking depth " + altDepth); for (int i = 0; i < blk.alternatives.size(); i++) { Alternative alt = blk.getAlternativeAt(i); if (DEBUG_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 // and that are not giant unicode sets. if (createdLL1Switch && suitableForCaseExpression(alt)) { if (DEBUG_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) 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) { 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 instanceof ParserGrammar) || (grammar instanceof LexerGrammar)) && grammar.debuggingOutput) { e = "(" + e + "&& fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.PREDICTING," + 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==null) _t=ASTNULL;"); } println("if " + e + " {"); } } } nIF++; tabs++; genAlt(alt, blk); tabs--; println("}"); } } String ps = ""; for (int i = 1; i <= closingBracesOfIFSequence; i++) { 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 JavaBlockFinishingInfo(ps+"}",true,nIF>0); // close up switch statement } else { finishingInfo.postscript = ps; finishingInfo.generatedSwitch = false; finishingInfo.generatedAnIf = nIF > 0; // return new JavaBlockFinishingInfo(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) { elementRef = el.getLabel(); astNameBase = el.getLabel(); } else { elementRef = lt1Value; // Generate AST variables for unlabeled stuff astNameBase = "tmp" + astVarNumber; ; astVarNumber++; } // Generate the declaration if required. if (needASTDecl) { // Generate the declaration if (el instanceof GrammarAtom) { GrammarAtom ga = (GrammarAtom)el; if (ga.getASTNodeType() != null) { genASTDeclaration(el, astNameBase, ga.getASTNodeType()); // println(ga.getASTNodeType()+" " + astName+" = null;"); } else { genASTDeclaration(el, astNameBase, labeledElementASTType); // println(labeledElementASTType+" " + astName + " = null;"); } } else { genASTDeclaration(el, astNameBase, labeledElementASTType); // println(labeledElementASTType+" " + astName + " = null;"); } } // 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 = null;"); } // 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: println("astFactory.addASTChild(currentAST, " + astName + ");"); break; case GrammarElement.AUTO_GEN_CARET: 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(); printAction( processActionForSpecialSymbols(handler.action.getText(), handler.action.getLine(), currentRule, tInfo) ); if (grammar.hasSyntacticPredicate) { tabs--; println("} else {"); tabs++; // When guessing, rethrow exception println( "throw " + extractIdOfAction(handler.exceptionTypeAndName) + ";" ); 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++; } } protected void genASTDeclaration(AlternativeElement el) { genASTDeclaration(el, labeledElementASTType); } protected void genASTDeclaration(AlternativeElement el, String node_type) { genASTDeclaration(el, el.getLabel(), node_type); } protected void genASTDeclaration(AlternativeElement el, String var_name, String node_type) { // already declared? if (declaredASTVariables.contains(el)) return; // emit code println(node_type + " " + var_name + "_AST = null;"); // mark as declared declaredASTVariables.add(el); } /** Generate a header that is common to all Java files */ protected void genHeader() { println("// $ANTLR " + Tool.version + ": " + "\"" + antlrTool.fileMinusPath(antlrTool.grammarFile) + "\"" + " -> " + "\"" + grammar.getClassName() + ".java\"$"); } private void genLiteralsTest() { println("_ttype = testLiteralsTable(_ttype);"); } private void genLiteralsTestForPartialToken() { println("_ttype = testLiteralsTable(new String(text.getBuffer(),_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) { if (grammar instanceof LexerGrammar) { genMatchUsingAtomText(atom); } else { antlrTool.error("cannot ref character literals in grammar: " + atom); } } else if (atom instanceof TokenRefElement) { genMatchUsingAtomText(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) { 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("Token.EOF_TYPE"); } else { _print(atom.atomText); } _println(");"); if (grammar instanceof LexerGrammar && (!saveText || atom.getAutoGenType() == GrammarElement.AUTO_GEN_BANG)) { println("text.setLength(_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) { astArgs = "_t,"; } // If the literal can be mangled, generate the symbolic constant instead String mangledName = null; 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. */ 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("public Token nextToken() throws TokenStreamException {"); println("\ttry {uponEOF();}"); println("\tcatch(CharStreamIOException csioe) {"); println("\t\tthrow new TokenStreamIOException(csioe.io);"); println("\t}"); println("\tcatch(CharStreamException cse) {"); println("\t\tthrow new TokenStreamException(cse.getMessage());"); println("\t}"); println("\treturn new CommonToken(Token.EOF_TYPE, \"\");"); println("}"); 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("public Token nextToken() throws TokenStreamException {"); tabs++; println("Token theRetToken=null;"); _println("tryAgain:"); println("for (;;) {"); tabs++; println("Token _token = null;"); println("int _ttype = 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();"); println("try { // for char stream error handling"); tabs++; // Generate try around whole thing to trap scanner errors println("try { // for lexical 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()) { //String r = a.head.toString(); RuleRefElement rr = (RuleRefElement)a.head; String r = CodeGenerator.decodeLexerRuleName(rr.targetRule); antlrTool.warning("public lexical rule "+r+" is optional (can match \"nothing\")"); } } // Generate the block String newline = System.getProperty("line.separator"); JavaBlockFinishingInfo howToFinish = genCommonBlock(nextTokenBlk, false); String errFinish = "if (LA(1)==EOF_CHAR) {uponEOF(); _returnToken = makeToken(Token.EOF_TYPE);}"; errFinish += newline + "\t\t\t\t"; if (((LexerGrammar)grammar).filterMode) { if (filterRule == null) { errFinish += "else {consume(); continue 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(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\tcontinue 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==null ) continue tryAgain; // found SKIP token"); 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 (RecognitionException e) {"); tabs++; if (((LexerGrammar)grammar).filterMode) { if (filterRule == null) { println("if ( !getCommitToPath() ) {consume(); continue tryAgain;}"); } else { println("if ( !getCommitToPath() ) {"); tabs++; println("rewind(_m);"); println("resetText();"); println("try {m" + filterRule + "(false);}"); println("catch(RecognitionException ee) {"); println(" // horrendous failure: error in filter rule"); println(" reportError(ee);"); println(" consume();"); println("}"); println("continue tryAgain;"); tabs--; println("}"); } } if (nextTokenBlk.getDefaultErrorHandler()) { println("reportError(e);"); println("consume();"); } else { // pass on to invoking routine println("throw new TokenStreamRecognitionException(e);"); } tabs--; println("}"); // close CharStreamException try tabs--; println("}"); println("catch (CharStreamException cse) {"); println(" if ( cse instanceof CharStreamIOException ) {"); println(" throw new TokenStreamIOException(((CharStreamIOException)cse).io);"); println(" }"); println(" else {"); println(" throw new TokenStreamException(cse.getMessage());"); println(" }"); println("}"); // close for-loop 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) { tabs = 1; if (DEBUG_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 access and final qualifier print(s.access + " final "); // 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(")"); } // Gen throws clause and open curly _print(" throws " + exceptionThrown); if (grammar instanceof ParserGrammar) { _print(", TokenStreamException"); } else if (grammar instanceof LexerGrammar) { _print(", CharStreamException, TokenStreamException"); } // Add user-defined exceptions unless lexer (for now) if (rblk.throwsSpec != null) { if (grammar instanceof LexerGrammar) { antlrTool.error("user-defined throws spec not allowed (yet) for lexer rule " + rblk.ruleName); } else { _print(", " + rblk.throwsSpec); } } _println(" {"); tabs++; // Convert return action to variable declaration if (rblk.returnAction != null) println(rblk.returnAction + ";"); // print out definitions needed by rules for various grammar types println(commonLocalVars); if (grammar.traceRules) { if (grammar instanceof TreeWalkerGrammar) { println("traceIn(\"" + s.getId() + "\",_t);"); } else { println("traceIn(\"" + s.getId() + "\");"); } } if (grammar instanceof LexerGrammar) { // 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 = Token.EOF_TYPE;"); else println("_ttype = " + s.getId().substring(1) + ";"); println("int _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;"); } if (grammar.buildAST) { // Parser member used to pass AST returns from rule invocations println("returnAST = null;"); // Tracks AST construction // println("ASTPair currentAST = (inputState.guessing==0) ? new ASTPair() : null;"); println("ASTPair currentAST = new ASTPair();"); // User-settable return value for rule. println(labeledElementASTType + " " + s.getId() + "_AST = null;"); } 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); JavaBlockFinishingInfo 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("consume();"); println("consumeUntil(" + followSetName + ");"); } else { // Just consume one token println("if (_t!=null) {_t = _t.getNextSibling();}"); } if (grammar.hasSyntacticPredicate) { tabs--; // When guessing, rethrow exception println("} else {"); println(" throw ex;"); 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==null && _ttype!=Token.SKIP ) {"); println(" _token = makeToken(_ttype);"); println(" _token.setText(new String(text.getBuffer(), _begin, text.length()-_begin));"); println("}"); println("_returnToken = _token;"); } // 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++; // If debugging, generate calls to mark exit of rule 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; } 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(); String args = processActionForSpecialSymbols(rr.args, 0, currentRule, tInfo); if (tInfo.assignToRoot || tInfo.refRuleRoot != null) { antlrTool.error("Arguments of rule reference '" + rr.targetRule + "' cannot set or ref #" + currentRule.getRuleName(), grammar.getFilename(), rr.getLine(), rr.getColumn()); } _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) { antlrTool.warning("Missing parameters on reference to rule " + rr.targetRule, grammar.getFilename(), rr.getLine(), rr.getColumn()); } } _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," + addSemPred(escapedPred) + "," + pred + ")"; println("if (!(" + pred + "))"); println(" throw new SemanticException(\"" + escapedPred + "\");"); } /** Write an array of Strings which are the semantic predicate * expressions. The debugger will reference them by number only */ protected void genSemPredMap() { Enumeration e = semPreds.elements(); println("private String _semPredNames[] = {"); while (e.hasMoreElements()) println("\"" + e.nextElement() + "\","); println("};"); } protected void genSynPred(SynPredBlock blk, String lookaheadExpr) { if (DEBUG_CODE_GENERATOR) System.out.println("gen=>(" + blk + ")"); // Dump synpred result variable println("boolean synPredMatched" + blk.ID + " = false;"); // Gen normal lookahead test println("if (" + lookaheadExpr + ") {"); tabs++; // Save input state if (grammar instanceof TreeWalkerGrammar) { println("AST __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 synred 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() { // Generate a string for each token. This creates a static // array of Strings indexed by token type. println(""); println("public static final String[] _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)); if (i != v.size() - 1) { _print(","); } _println(""); } // Close the string array initailizer tabs--; println("};"); } /** Create and set Integer token type objects that map * to Java Class objects (which AST node to create). */ protected void genTokenASTNodeMap() { println(""); println("protected void buildTokenTypeASTClassMap() {"); // Generate a map.put("T","TNode") for each token // if heterogeneous node known for that token T. tabs++; boolean generatedNewHashtable = false; int n = 0; // Walk the token vocabulary and generate puts. Vector v = grammar.tokenManager.getVocabulary(); for (int i = 0; i < v.size(); i++) { String s = (String)v.elementAt(i); if (s != null) { TokenSymbol ts = grammar.tokenManager.getTokenSymbol(s); if (ts != null && ts.getASTNodeType() != null) { n++; if ( !generatedNewHashtable ) { // only generate if we are going to add a mapping println("tokenTypeToASTClassMap = new Hashtable();"); generatedNewHashtable = true; } println("tokenTypeToASTClassMap.put(new Integer("+s+"), "+ ts.getASTNodeType()+".class);"); } } } if ( n==0 ) { println("tokenTypeToASTClassMap=null;"); } tabs--; println("};"); } /** Generate the token types Java file */ protected void genTokenTypes(TokenManager tm) throws IOException { // Open the token output Java file and set the currentOutput stream // SAS: file open was moved to a method so a subclass can override // This was mainly for the VAJ interface setupOutput(tm.getName() + TokenTypesFileSuffix); tabs = 0; // Generate the header common to all Java files genHeader(); // Do not use printAction because we assume tabs==0 println(behavior.getHeaderAction("")); // Encapsulate the definitions in an interface. This can be done // because they are all constants. println("public interface " + tm.getName() + TokenTypesFileSuffix + " {"); tabs++; // Generate a definition for each token type Vector v = tm.getVocabulary(); // Do special tokens manually println("int EOF = " + Token.EOF_TYPE + ";"); println("int NULL_TREE_LOOKAHEAD = " + Token.NULL_TREE_LOOKAHEAD + ";"); 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("int " + sl.label + " = " + i + ";"); } else { String mangledName = mangleLiteral(s); if (mangledName != null) { // We were able to create a meaningful mangled token name println("int " + 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("int " + s + " = " + i + ";"); } } } // Close the interface tabs--; println("}"); // Close the tokens output file currentOutput.close(); currentOutput = null; exitIfError(); } /** 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(); buf.append("(" + labeledElementASTType + ")astFactory.make( (new 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 atom The grammar node for which you are creating the node * @param str The arguments to the AST constructor */ public String getASTCreateString(GrammarAtom atom, String astCtorArgs) { //System.out.println("getASTCreateString("+atom+","+astCtorArgs+")"); if (atom != null && atom.getASTNodeType() != null) { // they specified a type either on the reference or in tokens{} section return "("+atom.getASTNodeType()+")"+ "astFactory.create("+astCtorArgs+",\""+atom.getASTNodeType()+"\")"; } else { // must be an action or something since not referencing an atom return getASTCreateString(astCtorArgs); } } /** Get a string for an expression to generate creating of an AST node. * Parse the first (possibly only) argument looking for the token type. * If the token type is a valid token symbol, ask for it's AST node type * and add to the end if only 2 arguments. The forms are #[T], #[T,"t"], * and as of 2.7.2 #[T,"t",ASTclassname]. * * @param str The arguments to the AST constructor */ public String getASTCreateString(String astCtorArgs) { //System.out.println("AST CTOR: "+astCtorArgs); if ( astCtorArgs==null ) { astCtorArgs = ""; } int nCommas = 0; for (int i=0; i<astCtorArgs.length(); i++) { if ( astCtorArgs.charAt(i)==',' ) { nCommas++; } } //System.out.println("num commas="+nCommas); if ( nCommas<2 ) { // if 1 or 2 args int firstComma = astCtorArgs.indexOf(','); int lastComma = astCtorArgs.lastIndexOf(','); String tokenName = astCtorArgs; if ( nCommas>0 ) { tokenName = astCtorArgs.substring(0,firstComma); } //System.out.println("Checking for ast node type of "+tokenName); TokenSymbol ts = grammar.tokenManager.getTokenSymbol(tokenName); if ( ts!=null ) { String astNodeType = ts.getASTNodeType(); //System.out.println("node type of "+tokenName+" is "+astNodeType); String emptyText = ""; if ( nCommas==0 ) { // need to add 2nd arg of blank text for token text emptyText = ",\"\""; } if ( astNodeType!=null ) { return "("+astNodeType+")"+ "astFactory.create("+astCtorArgs+emptyText+",\""+astNodeType+"\")"; } // fall through and just do a regular create with cast on front // if necessary (it differs from default "AST"). } if ( labeledElementASTType.equals("AST") ) { return "astFactory.create("+astCtorArgs+")"; } return "("+labeledElementASTType+")"+ "astFactory.create("+astCtorArgs+")"; } // create default type or (since 2.7.2) 3rd arg is classname return "(" + labeledElementASTType + ")astFactory.create(" + astCtorArgs + ")"; } 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 )"; } 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 { 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; boolean in_var = false; String id = idParam; if (grammar instanceof TreeWalkerGrammar) { if (!grammar.buildAST) { in_var = true; } // 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; } } // 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)) { 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) { // 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. antlrTool.error("Ambiguous reference to AST element "+id+ " in rule "+currentRule.getRuleName()); return null; } else { return in_var ? s + "_in" : s; } } // 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; } } return r; } else { // 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 $var and tree-specifiers in the action. * This will replace #id and #(...) with the appropriate * function calls and/or variables etc... */ 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; // see if we have anything to do... 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.java.ActionLexer lexer = new antlr.actions.java.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 void setupGrammarParameters(Grammar g) { if (g instanceof ParserGrammar) { labeledElementASTType = "AST"; if (g.hasOption("ASTLabelType")) { Token tsuffix = g.getOption("ASTLabelType"); if (tsuffix != null) { String suffix = StringUtils.stripFrontBack(tsuffix.getText(), "\"", "\""); if (suffix != null) { labeledElementASTType = suffix; } } } labeledElementType = "Token "; labeledElementInit = "null"; commonExtraArgs = ""; commonExtraParams = ""; commonLocalVars = ""; lt1Value = "LT(1)"; exceptionThrown = "RecognitionException"; throwNoViable = "throw new NoViableAltException(LT(1), getFilename());"; } else if (g instanceof LexerGrammar) { labeledElementType = "char "; labeledElementInit = "'\\0'"; commonExtraArgs = ""; commonExtraParams = "boolean _createToken"; commonLocalVars = "int _ttype; Token _token=null; int _begin=text.length();"; lt1Value = "LA(1)"; exceptionThrown = "RecognitionException"; throwNoViable = "throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());"; } else if (g instanceof TreeWalkerGrammar) { labeledElementASTType = "AST"; labeledElementType = "AST"; if (g.hasOption("ASTLabelType")) { Token tsuffix = g.getOption("ASTLabelType"); if (tsuffix != null) { String suffix = StringUtils.stripFrontBack(tsuffix.getText(), "\"", "\""); if (suffix != null) { labeledElementASTType = suffix; labeledElementType = suffix; } } } if (!g.hasOption("ASTLabelType")) { g.setOption("ASTLabelType", new Token(ANTLRTokenTypes.STRING_LITERAL, "AST")); } labeledElementInit = "null"; commonExtraArgs = "_t"; commonExtraParams = "AST _t"; commonLocalVars = ""; lt1Value = "(" + labeledElementASTType + ")_t"; exceptionThrown = "RecognitionException"; throwNoViable = "throw new NoViableAltException(_t);"; } else { antlrTool.panic("Unknown grammar type"); } } /** This method exists so a subclass, namely VAJCodeGenerator, * can open the file in its own evil way. JavaCodeGenerator * simply opens a text file... */ public void setupOutput(String className) throws IOException { currentOutput = antlrTool.openOutputFile(className + ".java"); } }