0001: package persistence.antlr;
0002:
0003: /* ANTLR Translator Generator
0004: * Project led by Terence Parr at http://www.jGuru.com
0005: * Software rights: http://www.antlr.org/license.html
0006: *
0007: */
0008:
0009: //
0010: // ANTLR C# Code Generator by Micheal Jordan
0011: // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com
0012: // Anthony Oguntimehin
0013: //
0014: // With many thanks to Eric V. Smith from the ANTLR list.
0015: //
0016: // HISTORY:
0017: //
0018: // 17-May-2002 kunle Fixed bug in OctalToUnicode() - was processing non-Octal escape sequences
0019: // Also added namespace support based on Cpp version.
0020: // 07-Jun-2002 kunle Added Scott Ellis's _saveIndex creation optimizations
0021: // 09-Sep-2002 richardN Richard Ney's bug-fix for literals table construction.
0022: // [ Hashtable ctor needed instance of hash code provider not it's class name. ]
0023: // 17-Sep-2002 kunle & Added all Token ID definitions as data member of every Lexer/Parser/TreeParser
0024: // AOg [ A by-product of problem-solving phase of the hetero-AST changes below
0025: // but, it breaks nothing and restores "normal" ANTLR codegen behaviour. ]
0026: // 19-Oct-2002 kunle & Completed the work required to support heterogenous ASTs (many changes)
0027: // AOg &
0028: // michealj
0029: // 14-Nov-2002 michealj Added "initializeASTFactory()" to support flexible ASTFactory initialization.
0030: // [ Thanks to Ric Klaren - for suggesting it and implementing it for Cpp. ]
0031: // 18-Nov-2002 kunle Added fix to make xx_tokenSet_xx names CLS compliant.
0032: // 01-Dec-2002 richardN Patch to reduce "unreachable code" warnings
0033: // 01-Dec-2002 richardN Fix to generate correct TreeParser token-type classnames.
0034: // 12-Jan-2002 kunle & Generated Lexers, Parsers and TreeParsers now support ANTLR's tracing option.
0035: // michealj
0036: // 12-Jan-2003 kunle Fixed issue where initializeASTFactory() was generated when "buildAST=false"
0037: // 14-Jan-2003 AOg initializeASTFactory(AST factory) method was modifying the Parser's "astFactory"
0038: // member rather than it's own "factory" parameter. Fixed.
0039: // 18-Jan-2003 kunle & Fixed reported issues with ASTFactory create() calls for hetero ASTs
0040: // michealj - code generated for LEXER token with hetero-AST option specified does not compile
0041: // - code generated for imaginary tokens with hetero-AST option specified uses default AST type
0042: // - code generated for per-TokenRef hetero-AST option specified does not compile
0043: // 18-Jan-2003 kunle initializeASTFactory(AST) method is now a static public member
0044: // 18-May-2003 kunle Changes to address outstanding reported issues::
0045: // - Fixed reported issues with support for case-sensitive literals
0046: // - persistence.antlr.SemanticException now imported for all Lexers.
0047: // [ This exception is thrown on predicate failure. ]
0048: // 12-Jan-2004 kunle Added fix for reported issue with un-compileable generated lexers
0049: //
0050: //
0051: import java.util.Enumeration;
0052: import java.util.Hashtable;
0053: import persistence.antlr.collections.impl.BitSet;
0054: import persistence.antlr.collections.impl.Vector;
0055: import java.io.PrintWriter; //SAS: changed for proper text file io
0056: import java.io.IOException;
0057: import java.io.FileWriter;
0058:
0059: /** Generates MyParser.cs, MyLexer.cs and MyParserTokenTypes.cs */
0060: public class CSharpCodeGenerator extends CodeGenerator {
0061: // non-zero if inside syntactic predicate generation
0062: protected int syntacticPredLevel = 0;
0063:
0064: // Are we generating ASTs (for parsers and tree parsers) right now?
0065: protected boolean genAST = false;
0066:
0067: // Are we saving the text consumed (for lexers) right now?
0068: protected boolean saveText = false;
0069:
0070: // Grammar parameters set up to handle different grammar classes.
0071: // These are used to get instanceof tests out of code generation
0072: boolean usingCustomAST = false;
0073: String labeledElementType;
0074: String labeledElementASTType;
0075: String labeledElementInit;
0076: String commonExtraArgs;
0077: String commonExtraParams;
0078: String commonLocalVars;
0079: String lt1Value;
0080: String exceptionThrown;
0081: String throwNoViable;
0082:
0083: // Tracks the rule being generated. Used for mapTreeId
0084: RuleBlock currentRule;
0085: // Tracks the rule or labeled subrule being generated. Used for AST generation.
0086: String currentASTResult;
0087:
0088: /** Mapping between the ids used in the current alt, and the
0089: * names of variables used to represent their AST values.
0090: */
0091: Hashtable treeVariableMap = new Hashtable();
0092:
0093: /** Used to keep track of which AST variables have been defined in a rule
0094: * (except for the #rule_name and #rule_name_in var's
0095: */
0096: Hashtable declaredASTVariables = new Hashtable();
0097:
0098: /* Count of unnamed generated variables */
0099: int astVarNumber = 1;
0100:
0101: /** Special value used to mark duplicate in treeVariableMap */
0102: protected static final String NONUNIQUE = new String();
0103:
0104: public static final int caseSizeThreshold = 127; // ascii is max
0105:
0106: private Vector semPreds;
0107: // Used to keep track of which (heterogeneous AST types are used)
0108: // which need to be set in the ASTFactory of the generated parser
0109: private java.util.Vector astTypes;
0110:
0111: private static CSharpNameSpace nameSpace = null;
0112:
0113: // _saveIndex creation optimization -- don't create it unless we need to use it
0114: boolean bSaveIndexCreated = false;
0115:
0116: /** Create a CSharp code-generator using the given Grammar.
0117: * The caller must still call setTool, setBehavior, and setAnalyzer
0118: * before generating code.
0119: */
0120: public CSharpCodeGenerator() {
0121: super ();
0122: charFormatter = new CSharpCharFormatter();
0123: }
0124:
0125: /** Adds a semantic predicate string to the sem pred vector
0126: These strings will be used to build an array of sem pred names
0127: when building a debugging parser. This method should only be
0128: called when the debug option is specified
0129: */
0130: protected int addSemPred(String predicate) {
0131: semPreds.appendElement(predicate);
0132: return semPreds.size() - 1;
0133: }
0134:
0135: public void exitIfError() {
0136: if (antlrTool.hasError()) {
0137: antlrTool.fatalError("Exiting due to errors.");
0138: }
0139: }
0140:
0141: /**Generate the parser, lexer, treeparser, and token types in CSharp */
0142: public void gen() {
0143: // Do the code generation
0144: try {
0145: // Loop over all grammars
0146: Enumeration grammarIter = behavior.grammars.elements();
0147: while (grammarIter.hasMoreElements()) {
0148: Grammar g = (Grammar) grammarIter.nextElement();
0149: // Connect all the components to each other
0150: g.setGrammarAnalyzer(analyzer);
0151: g.setCodeGenerator(this );
0152: analyzer.setGrammar(g);
0153: // To get right overloading behavior across heterogeneous grammars
0154: setupGrammarParameters(g);
0155: g.generate();
0156: exitIfError();
0157: }
0158:
0159: // Loop over all token managers (some of which are lexers)
0160: Enumeration tmIter = behavior.tokenManagers.elements();
0161: while (tmIter.hasMoreElements()) {
0162: TokenManager tm = (TokenManager) tmIter.nextElement();
0163: if (!tm.isReadOnly()) {
0164: // Write the token manager tokens as CSharp
0165: // this must appear before genTokenInterchange so that
0166: // labels are set on string literals
0167: genTokenTypes(tm);
0168: // Write the token manager tokens as plain text
0169: genTokenInterchange(tm);
0170: }
0171: exitIfError();
0172: }
0173: } catch (IOException e) {
0174: antlrTool.reportException(e, null);
0175: }
0176: }
0177:
0178: /** Generate code for the given grammar element.
0179: * @param blk The {...} action to generate
0180: */
0181: public void gen(ActionElement action) {
0182: if (DEBUG_CODE_GENERATOR)
0183: System.out.println("genAction(" + action + ")");
0184: if (action.isSemPred) {
0185: genSemPred(action.actionText, action.line);
0186: } else {
0187: if (grammar.hasSyntacticPredicate) {
0188: println("if (0==inputState.guessing)");
0189: println("{");
0190: tabs++;
0191: }
0192:
0193: ActionTransInfo tInfo = new ActionTransInfo();
0194: String actionStr = processActionForSpecialSymbols(
0195: action.actionText, action.getLine(), currentRule,
0196: tInfo);
0197:
0198: if (tInfo.refRuleRoot != null) {
0199: // Somebody referenced "#rule", make sure translated var is valid
0200: // assignment to #rule is left as a ref also, meaning that assignments
0201: // with no other refs like "#rule = foo();" still forces this code to be
0202: // generated (unnecessarily).
0203: println(tInfo.refRuleRoot + " = ("
0204: + labeledElementASTType + ")currentAST.root;");
0205: }
0206:
0207: // dump the translated action
0208: printAction(actionStr);
0209:
0210: if (tInfo.assignToRoot) {
0211: // Somebody did a "#rule=", reset internal currentAST.root
0212: println("currentAST.root = " + tInfo.refRuleRoot + ";");
0213: // reset the child pointer too to be last sibling in sibling list
0214: println("if ( (null != " + tInfo.refRuleRoot
0215: + ") && (null != " + tInfo.refRuleRoot
0216: + ".getFirstChild()) )");
0217: tabs++;
0218: println("currentAST.child = " + tInfo.refRuleRoot
0219: + ".getFirstChild();");
0220: tabs--;
0221: println("else");
0222: tabs++;
0223: println("currentAST.child = " + tInfo.refRuleRoot + ";");
0224: tabs--;
0225: println("currentAST.advanceChildToEnd();");
0226: }
0227:
0228: if (grammar.hasSyntacticPredicate) {
0229: tabs--;
0230: println("}");
0231: }
0232: }
0233: }
0234:
0235: /** Generate code for the given grammar element.
0236: * @param blk The "x|y|z|..." block to generate
0237: */
0238: public void gen(AlternativeBlock blk) {
0239: if (DEBUG_CODE_GENERATOR)
0240: System.out.println("gen(" + blk + ")");
0241: println("{");
0242: tabs++;
0243:
0244: genBlockPreamble(blk);
0245: genBlockInitAction(blk);
0246:
0247: // Tell AST generation to build subrule result
0248: String saveCurrentASTResult = currentASTResult;
0249: if (blk.getLabel() != null) {
0250: currentASTResult = blk.getLabel();
0251: }
0252:
0253: boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
0254:
0255: CSharpBlockFinishingInfo howToFinish = genCommonBlock(blk, true);
0256: genBlockFinish(howToFinish, throwNoViable);
0257:
0258: tabs--;
0259: println("}");
0260:
0261: // Restore previous AST generation
0262: currentASTResult = saveCurrentASTResult;
0263: }
0264:
0265: /** Generate code for the given grammar element.
0266: * @param blk The block-end element to generate. Block-end
0267: * elements are synthesized by the grammar parser to represent
0268: * the end of a block.
0269: */
0270: public void gen(BlockEndElement end) {
0271: if (DEBUG_CODE_GENERATOR)
0272: System.out.println("genRuleEnd(" + end + ")");
0273: }
0274:
0275: /** Generate code for the given grammar element.
0276: * @param blk The character literal reference to generate
0277: */
0278: public void gen(CharLiteralElement atom) {
0279: if (DEBUG_CODE_GENERATOR)
0280: System.out.println("genChar(" + atom + ")");
0281:
0282: if (atom.getLabel() != null) {
0283: println(atom.getLabel() + " = " + lt1Value + ";");
0284: }
0285:
0286: boolean oldsaveText = saveText;
0287: saveText = saveText
0288: && atom.getAutoGenType() == GrammarElement.AUTO_GEN_NONE;
0289: genMatch(atom);
0290: saveText = oldsaveText;
0291: }
0292:
0293: /** Generate code for the given grammar element.
0294: * @param blk The character-range reference to generate
0295: */
0296: public void gen(CharRangeElement r) {
0297: if (r.getLabel() != null && syntacticPredLevel == 0) {
0298: println(r.getLabel() + " = " + lt1Value + ";");
0299: }
0300: boolean flag = (grammar instanceof LexerGrammar && (!saveText || (r
0301: .getAutoGenType() == GrammarElement.AUTO_GEN_BANG)));
0302: if (flag)
0303: println("_saveIndex = text.Length;");
0304:
0305: println("matchRange(" + OctalToUnicode(r.beginText) + ","
0306: + OctalToUnicode(r.endText) + ");");
0307:
0308: if (flag)
0309: println("text.Length = _saveIndex;");
0310: }
0311:
0312: /** Generate the lexer CSharp file */
0313: public void gen(LexerGrammar g) throws IOException {
0314: // If debugging, create a new sempred vector for this grammar
0315: if (g.debuggingOutput)
0316: semPreds = new Vector();
0317:
0318: setGrammar(g);
0319: if (!(grammar instanceof LexerGrammar)) {
0320: antlrTool.panic("Internal error generating lexer");
0321: }
0322: genBody(g);
0323: }
0324:
0325: /** Generate code for the given grammar element.
0326: * @param blk The (...)+ block to generate
0327: */
0328: public void gen(OneOrMoreBlock blk) {
0329: if (DEBUG_CODE_GENERATOR)
0330: System.out.println("gen+(" + blk + ")");
0331: String label;
0332: String cnt;
0333: println("{ // ( ... )+");
0334: genBlockPreamble(blk);
0335: if (blk.getLabel() != null) {
0336: cnt = "_cnt_" + blk.getLabel();
0337: } else {
0338: cnt = "_cnt" + blk.ID;
0339: }
0340: println("int " + cnt + "=0;");
0341: if (blk.getLabel() != null) {
0342: label = blk.getLabel();
0343: } else {
0344: label = "_loop" + blk.ID;
0345: }
0346:
0347: println("for (;;)");
0348: println("{");
0349: tabs++;
0350: // generate the init action for ()+ ()* inside the loop
0351: // this allows us to do usefull EOF checking...
0352: genBlockInitAction(blk);
0353:
0354: // Tell AST generation to build subrule result
0355: String saveCurrentASTResult = currentASTResult;
0356: if (blk.getLabel() != null) {
0357: currentASTResult = blk.getLabel();
0358: }
0359:
0360: boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
0361:
0362: // generate exit test if greedy set to false
0363: // and an alt is ambiguous with exit branch
0364: // or when lookahead derived purely from end-of-file
0365: // Lookahead analysis stops when end-of-file is hit,
0366: // returning set {epsilon}. Since {epsilon} is not
0367: // ambig with any real tokens, no error is reported
0368: // by deterministic() routines and we have to check
0369: // for the case where the lookahead depth didn't get
0370: // set to NONDETERMINISTIC (this only happens when the
0371: // FOLLOW contains real atoms + epsilon).
0372: boolean generateNonGreedyExitPath = false;
0373: int nonGreedyExitDepth = grammar.maxk;
0374:
0375: if (!blk.greedy
0376: && blk.exitLookaheadDepth <= grammar.maxk
0377: && blk.exitCache[blk.exitLookaheadDepth]
0378: .containsEpsilon()) {
0379: generateNonGreedyExitPath = true;
0380: nonGreedyExitDepth = blk.exitLookaheadDepth;
0381: } else if (!blk.greedy
0382: && blk.exitLookaheadDepth == LLkGrammarAnalyzer.NONDETERMINISTIC) {
0383: generateNonGreedyExitPath = true;
0384: }
0385:
0386: // generate exit test if greedy set to false
0387: // and an alt is ambiguous with exit branch
0388: if (generateNonGreedyExitPath) {
0389: if (DEBUG_CODE_GENERATOR) {
0390: System.out
0391: .println("nongreedy (...)+ loop; exit depth is "
0392: + blk.exitLookaheadDepth);
0393: }
0394: String predictExit = getLookaheadTestExpression(
0395: blk.exitCache, nonGreedyExitDepth);
0396: println("// nongreedy exit test");
0397: println("if ((" + cnt + " >= 1) && " + predictExit
0398: + ") goto " + label + "_breakloop;");
0399: }
0400:
0401: CSharpBlockFinishingInfo howToFinish = genCommonBlock(blk,
0402: false);
0403: genBlockFinish(howToFinish, "if (" + cnt + " >= 1) { goto "
0404: + label + "_breakloop; } else { " + throwNoViable
0405: + "; }");
0406:
0407: println(cnt + "++;");
0408: tabs--;
0409: println("}");
0410: _print(label + "_breakloop:");
0411: println(";");
0412: println("} // ( ... )+");
0413:
0414: // Restore previous AST generation
0415: currentASTResult = saveCurrentASTResult;
0416: }
0417:
0418: /** Generate the parser CSharp file */
0419: public void gen(ParserGrammar g) throws IOException {
0420:
0421: // if debugging, set up a new vector to keep track of sempred
0422: // strings for this grammar
0423: if (g.debuggingOutput)
0424: semPreds = new Vector();
0425:
0426: setGrammar(g);
0427: if (!(grammar instanceof ParserGrammar)) {
0428: antlrTool.panic("Internal error generating parser");
0429: }
0430: genBody(g);
0431: }
0432:
0433: /** Generate code for the given grammar element.
0434: * @param blk The rule-reference to generate
0435: */
0436: public void gen(RuleRefElement rr) {
0437: if (DEBUG_CODE_GENERATOR)
0438: System.out.println("genRR(" + rr + ")");
0439: RuleSymbol rs = (RuleSymbol) grammar.getSymbol(rr.targetRule);
0440: if (rs == null || !rs.isDefined()) {
0441: // Is this redundant???
0442: antlrTool.error("Rule '" + rr.targetRule
0443: + "' is not defined", grammar.getFilename(), rr
0444: .getLine(), rr.getColumn());
0445: return;
0446: }
0447: if (!(rs instanceof RuleSymbol)) {
0448: // Is this redundant???
0449: antlrTool.error("'" + rr.targetRule
0450: + "' does not name a grammar rule", grammar
0451: .getFilename(), rr.getLine(), rr.getColumn());
0452: return;
0453: }
0454:
0455: genErrorTryForElement(rr);
0456:
0457: // AST value for labeled rule refs in tree walker.
0458: // This is not AST construction; it is just the input tree node value.
0459: if (grammar instanceof TreeWalkerGrammar
0460: && rr.getLabel() != null && syntacticPredLevel == 0) {
0461: println(rr.getLabel() + " = _t==ASTNULL ? null : "
0462: + lt1Value + ";");
0463: }
0464:
0465: // if in lexer and ! on rule ref or alt or rule, save buffer index to kill later
0466: if (grammar instanceof LexerGrammar
0467: && (!saveText || rr.getAutoGenType() == GrammarElement.AUTO_GEN_BANG)) {
0468: declareSaveIndexVariableIfNeeded();
0469: println("_saveIndex = text.Length;");
0470: }
0471:
0472: // Process return value assignment if any
0473: printTabs();
0474: if (rr.idAssign != null) {
0475: // Warn if the rule has no return type
0476: if (rs.block.returnAction == null) {
0477: antlrTool.warning("Rule '" + rr.targetRule
0478: + "' has no return type",
0479: grammar.getFilename(), rr.getLine(), rr
0480: .getColumn());
0481: }
0482: _print(rr.idAssign + "=");
0483: } else {
0484: // Warn about return value if any, but not inside syntactic predicate
0485: if (!(grammar instanceof LexerGrammar)
0486: && syntacticPredLevel == 0
0487: && rs.block.returnAction != null) {
0488: antlrTool.warning("Rule '" + rr.targetRule
0489: + "' returns a value", grammar.getFilename(),
0490: rr.getLine(), rr.getColumn());
0491: }
0492: }
0493:
0494: // Call the rule
0495: GenRuleInvocation(rr);
0496:
0497: // if in lexer and ! on element or alt or rule, save buffer index to kill later
0498: if (grammar instanceof LexerGrammar
0499: && (!saveText || rr.getAutoGenType() == GrammarElement.AUTO_GEN_BANG)) {
0500: declareSaveIndexVariableIfNeeded();
0501: println("text.Length = _saveIndex;");
0502: }
0503:
0504: // if not in a syntactic predicate
0505: if (syntacticPredLevel == 0) {
0506: boolean doNoGuessTest = (grammar.hasSyntacticPredicate && (grammar.buildAST
0507: && rr.getLabel() != null || (genAST && rr
0508: .getAutoGenType() == GrammarElement.AUTO_GEN_NONE)));
0509: if (doNoGuessTest) {
0510: println("if (0 == inputState.guessing)");
0511: println("{");
0512: tabs++;
0513: }
0514:
0515: if (grammar.buildAST && rr.getLabel() != null) {
0516: // always gen variable for rule return on labeled rules
0517: println(rr.getLabel() + "_AST = ("
0518: + labeledElementASTType + ")returnAST;");
0519: }
0520: if (genAST) {
0521: switch (rr.getAutoGenType()) {
0522: case GrammarElement.AUTO_GEN_NONE:
0523: if (usingCustomAST)
0524: println("astFactory.addASTChild(currentAST, (AST)returnAST);");
0525: else
0526: println("astFactory.addASTChild(currentAST, returnAST);");
0527: break;
0528: case GrammarElement.AUTO_GEN_CARET:
0529: antlrTool
0530: .error("Internal: encountered ^ after rule reference");
0531: break;
0532: default:
0533: break;
0534: }
0535: }
0536:
0537: // if a lexer and labeled, Token label defined at rule level, just set it here
0538: if (grammar instanceof LexerGrammar
0539: && rr.getLabel() != null) {
0540: println(rr.getLabel() + " = returnToken_;");
0541: }
0542:
0543: if (doNoGuessTest) {
0544: tabs--;
0545: println("}");
0546: }
0547: }
0548: genErrorCatchForElement(rr);
0549: }
0550:
0551: /** Generate code for the given grammar element.
0552: * @param blk The string-literal reference to generate
0553: */
0554: public void gen(StringLiteralElement atom) {
0555: if (DEBUG_CODE_GENERATOR)
0556: System.out.println("genString(" + atom + ")");
0557:
0558: // Variable declarations for labeled elements
0559: if (atom.getLabel() != null && syntacticPredLevel == 0) {
0560: println(atom.getLabel() + " = " + lt1Value + ";");
0561: }
0562:
0563: // AST
0564: genElementAST(atom);
0565:
0566: // is there a bang on the literal?
0567: boolean oldsaveText = saveText;
0568: saveText = saveText
0569: && atom.getAutoGenType() == GrammarElement.AUTO_GEN_NONE;
0570:
0571: // matching
0572: genMatch(atom);
0573:
0574: saveText = oldsaveText;
0575:
0576: // tack on tree cursor motion if doing a tree walker
0577: if (grammar instanceof TreeWalkerGrammar) {
0578: println("_t = _t.getNextSibling();");
0579: }
0580: }
0581:
0582: /** Generate code for the given grammar element.
0583: * @param blk The token-range reference to generate
0584: */
0585: public void gen(TokenRangeElement r) {
0586: genErrorTryForElement(r);
0587: if (r.getLabel() != null && syntacticPredLevel == 0) {
0588: println(r.getLabel() + " = " + lt1Value + ";");
0589: }
0590:
0591: // AST
0592: genElementAST(r);
0593:
0594: // match
0595: println("matchRange(" + OctalToUnicode(r.beginText) + ","
0596: + OctalToUnicode(r.endText) + ");");
0597: genErrorCatchForElement(r);
0598: }
0599:
0600: /** Generate code for the given grammar element.
0601: * @param blk The token-reference to generate
0602: */
0603: public void gen(TokenRefElement atom) {
0604: if (DEBUG_CODE_GENERATOR)
0605: System.out.println("genTokenRef(" + atom + ")");
0606: if (grammar instanceof LexerGrammar) {
0607: antlrTool.panic("Token reference found in lexer");
0608: }
0609: genErrorTryForElement(atom);
0610: // Assign Token value to token label variable
0611: if (atom.getLabel() != null && syntacticPredLevel == 0) {
0612: println(atom.getLabel() + " = " + lt1Value + ";");
0613: }
0614:
0615: // AST
0616: genElementAST(atom);
0617: // matching
0618: genMatch(atom);
0619: genErrorCatchForElement(atom);
0620:
0621: // tack on tree cursor motion if doing a tree walker
0622: if (grammar instanceof TreeWalkerGrammar) {
0623: println("_t = _t.getNextSibling();");
0624: }
0625: }
0626:
0627: public void gen(TreeElement t) {
0628: // save AST cursor
0629: println("AST __t" + t.ID + " = _t;");
0630:
0631: // If there is a label on the root, then assign that to the variable
0632: if (t.root.getLabel() != null) {
0633: println(t.root.getLabel() + " = (ASTNULL == _t) ? null : ("
0634: + labeledElementASTType + ")_t;");
0635: }
0636:
0637: // check for invalid modifiers ! and ^ on tree element roots
0638: if (t.root.getAutoGenType() == GrammarElement.AUTO_GEN_BANG) {
0639: antlrTool
0640: .error(
0641: "Suffixing a root node with '!' is not implemented",
0642: grammar.getFilename(), t.getLine(), t
0643: .getColumn());
0644: t.root.setAutoGenType(GrammarElement.AUTO_GEN_NONE);
0645: }
0646: if (t.root.getAutoGenType() == GrammarElement.AUTO_GEN_CARET) {
0647: antlrTool
0648: .warning(
0649: "Suffixing a root node with '^' is redundant; already a root",
0650: grammar.getFilename(), t.getLine(), t
0651: .getColumn());
0652: t.root.setAutoGenType(GrammarElement.AUTO_GEN_NONE);
0653: }
0654:
0655: // Generate AST variables
0656: genElementAST(t.root);
0657: if (grammar.buildAST) {
0658: // Save the AST construction state
0659: println("ASTPair __currentAST" + t.ID
0660: + " = currentAST.copy();");
0661: // Make the next item added a child of the TreeElement root
0662: println("currentAST.root = currentAST.child;");
0663: println("currentAST.child = null;");
0664: }
0665:
0666: // match root
0667: if (t.root instanceof WildcardElement) {
0668: println("if (null == _t) throw new MismatchedTokenException();");
0669: } else {
0670: genMatch(t.root);
0671: }
0672: // move to list of children
0673: println("_t = _t.getFirstChild();");
0674:
0675: // walk list of children, generating code for each
0676: for (int i = 0; i < t.getAlternatives().size(); i++) {
0677: Alternative a = t.getAlternativeAt(i);
0678: AlternativeElement e = a.head;
0679: while (e != null) {
0680: e.generate();
0681: e = e.next;
0682: }
0683: }
0684:
0685: if (grammar.buildAST) {
0686: // restore the AST construction state to that just after the
0687: // tree root was added
0688: println("currentAST = __currentAST" + t.ID + ";");
0689: }
0690: // restore AST cursor
0691: println("_t = __t" + t.ID + ";");
0692: // move cursor to sibling of tree just parsed
0693: println("_t = _t.getNextSibling();");
0694: }
0695:
0696: /** Generate the tree-parser CSharp file */
0697: public void gen(TreeWalkerGrammar g) throws IOException {
0698: // SAS: debugging stuff removed for now...
0699: setGrammar(g);
0700: if (!(grammar instanceof TreeWalkerGrammar)) {
0701: antlrTool.panic("Internal error generating tree-walker");
0702: }
0703: genBody(g);
0704: }
0705:
0706: /** Generate code for the given grammar element.
0707: * @param wc The wildcard element to generate
0708: */
0709: public void gen(WildcardElement wc) {
0710: // Variable assignment for labeled elements
0711: if (wc.getLabel() != null && syntacticPredLevel == 0) {
0712: println(wc.getLabel() + " = " + lt1Value + ";");
0713: }
0714:
0715: // AST
0716: genElementAST(wc);
0717: // Match anything but EOF
0718: if (grammar instanceof TreeWalkerGrammar) {
0719: println("if (null == _t) throw new MismatchedTokenException();");
0720: } else if (grammar instanceof LexerGrammar) {
0721: if (grammar instanceof LexerGrammar
0722: && (!saveText || wc.getAutoGenType() == GrammarElement.AUTO_GEN_BANG)) {
0723: declareSaveIndexVariableIfNeeded();
0724: println("_saveIndex = text.Length;");
0725: }
0726: println("matchNot(EOF/*_CHAR*/);");
0727: if (grammar instanceof LexerGrammar
0728: && (!saveText || wc.getAutoGenType() == GrammarElement.AUTO_GEN_BANG)) {
0729: declareSaveIndexVariableIfNeeded();
0730: println("text.Length = _saveIndex;"); // kill text atom put in buffer
0731: }
0732: } else {
0733: println("matchNot(" + getValueString(Token.EOF_TYPE) + ");");
0734: }
0735:
0736: // tack on tree cursor motion if doing a tree walker
0737: if (grammar instanceof TreeWalkerGrammar) {
0738: println("_t = _t.getNextSibling();");
0739: }
0740: }
0741:
0742: /** Generate code for the given grammar element.
0743: * @param blk The (...)* block to generate
0744: */
0745: public void gen(ZeroOrMoreBlock blk) {
0746: if (DEBUG_CODE_GENERATOR)
0747: System.out.println("gen*(" + blk + ")");
0748: println("{ // ( ... )*");
0749: tabs++;
0750: genBlockPreamble(blk);
0751: String label;
0752: if (blk.getLabel() != null) {
0753: label = blk.getLabel();
0754: } else {
0755: label = "_loop" + blk.ID;
0756: }
0757: println("for (;;)");
0758: println("{");
0759: tabs++;
0760: // generate the init action for ()+ ()* inside the loop
0761: // this allows us to do usefull EOF checking...
0762: genBlockInitAction(blk);
0763:
0764: // Tell AST generation to build subrule result
0765: String saveCurrentASTResult = currentASTResult;
0766: if (blk.getLabel() != null) {
0767: currentASTResult = blk.getLabel();
0768: }
0769:
0770: boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
0771:
0772: // generate exit test if greedy set to false
0773: // and an alt is ambiguous with exit branch
0774: // or when lookahead derived purely from end-of-file
0775: // Lookahead analysis stops when end-of-file is hit,
0776: // returning set {epsilon}. Since {epsilon} is not
0777: // ambig with any real tokens, no error is reported
0778: // by deterministic() routines and we have to check
0779: // for the case where the lookahead depth didn't get
0780: // set to NONDETERMINISTIC (this only happens when the
0781: // FOLLOW contains real atoms + epsilon).
0782: boolean generateNonGreedyExitPath = false;
0783: int nonGreedyExitDepth = grammar.maxk;
0784:
0785: if (!blk.greedy
0786: && blk.exitLookaheadDepth <= grammar.maxk
0787: && blk.exitCache[blk.exitLookaheadDepth]
0788: .containsEpsilon()) {
0789: generateNonGreedyExitPath = true;
0790: nonGreedyExitDepth = blk.exitLookaheadDepth;
0791: } else if (!blk.greedy
0792: && blk.exitLookaheadDepth == LLkGrammarAnalyzer.NONDETERMINISTIC) {
0793: generateNonGreedyExitPath = true;
0794: }
0795: if (generateNonGreedyExitPath) {
0796: if (DEBUG_CODE_GENERATOR) {
0797: System.out
0798: .println("nongreedy (...)* loop; exit depth is "
0799: + blk.exitLookaheadDepth);
0800: }
0801: String predictExit = getLookaheadTestExpression(
0802: blk.exitCache, nonGreedyExitDepth);
0803: println("// nongreedy exit test");
0804: println("if (" + predictExit + ") goto " + label
0805: + "_breakloop;");
0806: }
0807:
0808: CSharpBlockFinishingInfo howToFinish = genCommonBlock(blk,
0809: false);
0810: genBlockFinish(howToFinish, "goto " + label + "_breakloop;");
0811:
0812: tabs--;
0813: println("}");
0814: _print(label + "_breakloop:");
0815: println(";");
0816: tabs--;
0817: println("} // ( ... )*");
0818:
0819: // Restore previous AST generation
0820: currentASTResult = saveCurrentASTResult;
0821: }
0822:
0823: /** Generate an alternative.
0824: * @param alt The alternative to generate
0825: * @param blk The block to which the alternative belongs
0826: */
0827: protected void genAlt(Alternative alt, AlternativeBlock blk) {
0828: // Save the AST generation state, and set it to that of the alt
0829: boolean savegenAST = genAST;
0830: genAST = genAST && alt.getAutoGen();
0831:
0832: boolean oldsaveTest = saveText;
0833: saveText = saveText && alt.getAutoGen();
0834:
0835: // Reset the variable name map for the alternative
0836: Hashtable saveMap = treeVariableMap;
0837: treeVariableMap = new Hashtable();
0838:
0839: // Generate try block around the alt for error handling
0840: if (alt.exceptionSpec != null) {
0841: println("try // for error handling");
0842: println("{");
0843: tabs++;
0844: }
0845:
0846: AlternativeElement elem = alt.head;
0847: while (!(elem instanceof BlockEndElement)) {
0848: elem.generate(); // alt can begin with anything. Ask target to gen.
0849: elem = elem.next;
0850: }
0851:
0852: if (genAST) {
0853: if (blk instanceof RuleBlock) {
0854: // Set the AST return value for the rule
0855: RuleBlock rblk = (RuleBlock) blk;
0856: if (usingCustomAST) {
0857: println(rblk.getRuleName() + "_AST = ("
0858: + labeledElementASTType
0859: + ")currentAST.root;");
0860: } else {
0861: println(rblk.getRuleName()
0862: + "_AST = currentAST.root;");
0863: }
0864: } else if (blk.getLabel() != null) {
0865: // ### future: also set AST value for labeled subrules.
0866: // println(blk.getLabel() + "_AST = ("+labeledElementASTType+")currentAST.root;");
0867: antlrTool.warning("Labeled subrules not yet supported",
0868: grammar.getFilename(), blk.getLine(), blk
0869: .getColumn());
0870: }
0871: }
0872:
0873: if (alt.exceptionSpec != null) {
0874: // close try block
0875: tabs--;
0876: println("}");
0877: genErrorHandler(alt.exceptionSpec);
0878: }
0879:
0880: genAST = savegenAST;
0881: saveText = oldsaveTest;
0882:
0883: treeVariableMap = saveMap;
0884: }
0885:
0886: /** Generate all the bitsets to be used in the parser or lexer
0887: * Generate the raw bitset data like "long _tokenSet1_data[] = {...};"
0888: * and the BitSet object declarations like "BitSet _tokenSet1 = new BitSet(_tokenSet1_data);"
0889: * Note that most languages do not support object initialization inside a
0890: * class definition, so other code-generators may have to separate the
0891: * bitset declarations from the initializations (e.g., put the initializations
0892: * in the generated constructor instead).
0893: * @param bitsetList The list of bitsets to generate.
0894: * @param maxVocabulary Ensure that each generated bitset can contain at least this value.
0895: */
0896: protected void genBitsets(Vector bitsetList, int maxVocabulary) {
0897: println("");
0898: for (int i = 0; i < bitsetList.size(); i++) {
0899: BitSet p = (BitSet) bitsetList.elementAt(i);
0900: // Ensure that generated BitSet is large enough for vocabulary
0901: p.growToInclude(maxVocabulary);
0902: genBitSet(p, i);
0903: }
0904: }
0905:
0906: /** Do something simple like:
0907: * private static final long[] mk_tokenSet_0() {
0908: * long[] data = { -2305839160922996736L, 63L, 16777216L, 0L, 0L, 0L };
0909: * return data;
0910: * }
0911: * public static final BitSet _tokenSet_0 = new BitSet(mk_tokenSet_0());
0912: *
0913: * Or, for large bitsets, optimize init so ranges are collapsed into loops.
0914: * This is most useful for lexers using unicode.
0915: */
0916: private void genBitSet(BitSet p, int id) {
0917: // initialization data
0918: println("private static long[] mk_" + getBitsetName(id) + "()");
0919: println("{");
0920: tabs++;
0921: int n = p.lengthInLongWords();
0922: if (n < BITSET_OPTIMIZE_INIT_THRESHOLD) {
0923: println("long[] data = { " + p.toStringOfWords() + "};");
0924: } else {
0925: // will init manually, allocate space then set values
0926: println("long[] data = new long[" + n + "];");
0927: long[] elems = p.toPackedArray();
0928: for (int i = 0; i < elems.length;) {
0929: if ((i + 1) == elems.length || elems[i] != elems[i + 1]) {
0930: // last number or no run of numbers, just dump assignment
0931: println("data[" + i + "]=" + elems[i] + "L;");
0932: i++;
0933: } else {
0934: // scan to find end of run
0935: int j;
0936: for (j = i + 1; j < elems.length
0937: && elems[j] == elems[i]; j++) {
0938: ;
0939: }
0940: // j-1 is last member of run
0941: println("for (int i = " + i + "; i<=" + (j - 1)
0942: + "; i++) { data[i]=" + elems[i] + "L; }");
0943: i = j;
0944: }
0945: }
0946: }
0947:
0948: println("return data;");
0949: tabs--;
0950: println("}");
0951: // BitSet object
0952: println("public static readonly BitSet " + getBitsetName(id)
0953: + " = new BitSet(" + "mk_" + getBitsetName(id) + "()"
0954: + ");");
0955: }
0956:
0957: /** Given the index of a bitset in the bitset list, generate a unique name.
0958: * Specific code-generators may want to override this
0959: * if the language does not allow '_' or numerals in identifiers.
0960: * @param index The index of the bitset in the bitset list.
0961: */
0962: protected String getBitsetName(int index) {
0963: return "tokenSet_" + index + "_";
0964: }
0965:
0966: /** Generate the finish of a block, using a combination of the info
0967: * returned from genCommonBlock() and the action to perform when
0968: * no alts were taken
0969: * @param howToFinish The return of genCommonBlock()
0970: * @param noViableAction What to generate when no alt is taken
0971: */
0972: private void genBlockFinish(CSharpBlockFinishingInfo howToFinish,
0973: String noViableAction) {
0974:
0975: if (howToFinish.needAnErrorClause
0976: && (howToFinish.generatedAnIf || howToFinish.generatedSwitch)) {
0977: if (howToFinish.generatedAnIf) {
0978: println("else");
0979: println("{");
0980: } else {
0981: println("{");
0982: }
0983: tabs++;
0984: println(noViableAction);
0985: tabs--;
0986: println("}");
0987: }
0988:
0989: if (howToFinish.postscript != null) {
0990: if (howToFinish.needAnErrorClause
0991: && howToFinish.generatedSwitch
0992: && !howToFinish.generatedAnIf
0993: && noViableAction != null) {
0994: // Check to make sure that noViableAction is only a throw statement
0995: if (noViableAction.indexOf("throw") == 0
0996: || noViableAction.indexOf("goto") == 0) {
0997: // Remove the break statement since it isn't reachable with a throw exception
0998: int endOfBreak = howToFinish.postscript
0999: .indexOf("break;") + 6;
1000: String newPostScript = howToFinish.postscript
1001: .substring(endOfBreak);
1002: println(newPostScript);
1003: } else {
1004: println(howToFinish.postscript);
1005: }
1006: } else {
1007: println(howToFinish.postscript);
1008: }
1009: }
1010: }
1011:
1012: /** Generate the init action for a block, which may be a RuleBlock or a
1013: * plain AlternativeBLock.
1014: * @blk The block for which the preamble is to be generated.
1015: */
1016: protected void genBlockInitAction(AlternativeBlock blk) {
1017: // dump out init action
1018: if (blk.initAction != null) {
1019: printAction(processActionForSpecialSymbols(blk.initAction,
1020: blk.getLine(), currentRule, null));
1021: }
1022: }
1023:
1024: /** Generate the header for a block, which may be a RuleBlock or a
1025: * plain AlternativeBLock. This generates any variable declarations
1026: * and syntactic-predicate-testing variables.
1027: * @blk The block for which the preamble is to be generated.
1028: */
1029: protected void genBlockPreamble(AlternativeBlock blk) {
1030: // define labels for rule blocks.
1031: if (blk instanceof RuleBlock) {
1032: RuleBlock rblk = (RuleBlock) blk;
1033: if (rblk.labeledElements != null) {
1034: for (int i = 0; i < rblk.labeledElements.size(); i++) {
1035:
1036: AlternativeElement a = (AlternativeElement) rblk.labeledElements
1037: .elementAt(i);
1038: //System.out.println("looking at labeled element: "+a);
1039: //Variables for labeled rule refs and
1040: //subrules are different than variables for
1041: //grammar atoms. This test is a little tricky
1042: //because we want to get all rule refs and ebnf,
1043: //but not rule blocks or syntactic predicates
1044: if (a instanceof RuleRefElement
1045: || a instanceof AlternativeBlock
1046: && !(a instanceof RuleBlock)
1047: && !(a instanceof SynPredBlock)) {
1048:
1049: if (!(a instanceof RuleRefElement)
1050: && ((AlternativeBlock) a).not
1051: && analyzer
1052: .subruleCanBeInverted(
1053: ((AlternativeBlock) a),
1054: grammar instanceof LexerGrammar)) {
1055: // Special case for inverted subrules that
1056: // will be inlined. Treat these like
1057: // token or char literal references
1058: println(labeledElementType + " "
1059: + a.getLabel() + " = "
1060: + labeledElementInit + ";");
1061: if (grammar.buildAST) {
1062: genASTDeclaration(a);
1063: }
1064: } else {
1065: if (grammar.buildAST) {
1066: // Always gen AST variables for
1067: // labeled elements, even if the
1068: // element itself is marked with !
1069: genASTDeclaration(a);
1070: }
1071: if (grammar instanceof LexerGrammar) {
1072: println("Token " + a.getLabel()
1073: + " = null;");
1074: }
1075: if (grammar instanceof TreeWalkerGrammar) {
1076: // always generate rule-ref variables
1077: // for tree walker
1078: println(labeledElementType + " "
1079: + a.getLabel() + " = "
1080: + labeledElementInit + ";");
1081: }
1082: }
1083: } else {
1084: // It is a token or literal reference. Generate the
1085: // correct variable type for this grammar
1086: println(labeledElementType + " " + a.getLabel()
1087: + " = " + labeledElementInit + ";");
1088: // In addition, generate *_AST variables if building ASTs
1089: if (grammar.buildAST) {
1090: //println(labeledElementASTType+" " + a.getLabel() + "_AST = null;");
1091: if (a instanceof GrammarAtom
1092: && ((GrammarAtom) a)
1093: .getASTNodeType() != null) {
1094: GrammarAtom ga = (GrammarAtom) a;
1095: genASTDeclaration(a, ga
1096: .getASTNodeType());
1097: } else {
1098: genASTDeclaration(a);
1099: }
1100: }
1101: }
1102: }
1103: }
1104: }
1105: }
1106:
1107: public void genBody(LexerGrammar g) throws IOException {
1108: // SAS: moved output creation to method so a subclass can change
1109: // how the output is generated (for VAJ interface)
1110: setupOutput(grammar.getClassName());
1111:
1112: genAST = false; // no way to gen trees.
1113: saveText = true; // save consumed characters.
1114:
1115: tabs = 0;
1116:
1117: // Generate header common to all CSharp output files
1118: genHeader();
1119: // Do not use printAction because we assume tabs==0
1120: println(behavior.getHeaderAction(""));
1121:
1122: // Generate the CSharp namespace declaration (if specified)
1123: if (nameSpace != null)
1124: nameSpace.emitDeclarations(currentOutput);
1125: tabs++;
1126:
1127: // Generate header specific to lexer CSharp file
1128: // println("import java.io.FileInputStream;");
1129: println("// Generate header specific to lexer CSharp file");
1130: println("using System;");
1131: println("using Stream = System.IO.Stream;");
1132: println("using TextReader = System.IO.TextReader;");
1133: println("using Hashtable = System.Collections.Hashtable;");
1134: println("using Comparer = System.Collections.Comparer;");
1135: if (!(g.caseSensitiveLiterals)) {
1136: println("using CaseInsensitiveHashCodeProvider = System.Collections.CaseInsensitiveHashCodeProvider;");
1137: println("using CaseInsensitiveComparer = System.Collections.CaseInsensitiveComparer;");
1138: }
1139: println("");
1140: println("using TokenStreamException = persistence.antlr.TokenStreamException;");
1141: println("using TokenStreamIOException = persistence.antlr.TokenStreamIOException;");
1142: println("using TokenStreamRecognitionException = persistence.antlr.TokenStreamRecognitionException;");
1143: println("using CharStreamException = persistence.antlr.CharStreamException;");
1144: println("using CharStreamIOException = persistence.antlr.CharStreamIOException;");
1145: println("using ANTLRException = persistence.antlr.ANTLRException;");
1146: println("using CharScanner = persistence.antlr.CharScanner;");
1147: println("using InputBuffer = persistence.antlr.InputBuffer;");
1148: println("using ByteBuffer = persistence.antlr.ByteBuffer;");
1149: println("using CharBuffer = persistence.antlr.CharBuffer;");
1150: println("using Token = persistence.antlr.Token;");
1151: println("using CommonToken = persistence.antlr.CommonToken;");
1152: println("using SemanticException = persistence.antlr.SemanticException;");
1153: println("using RecognitionException = persistence.antlr.RecognitionException;");
1154: println("using NoViableAltForCharException = persistence.antlr.NoViableAltForCharException;");
1155: println("using MismatchedCharException = persistence.antlr.MismatchedCharException;");
1156: println("using TokenStream = persistence.antlr.TokenStream;");
1157: println("using LexerSharedInputState = persistence.antlr.LexerSharedInputState;");
1158: println("using BitSet = persistence.antlr.collections.impl.BitSet;");
1159:
1160: // Generate user-defined lexer file preamble
1161: println(grammar.preambleAction.getText());
1162:
1163: // Generate lexer class definition
1164: String sup = null;
1165: if (grammar.super Class != null) {
1166: sup = grammar.super Class;
1167: } else {
1168: sup = "persistence.antlr." + grammar.getSuperClass();
1169: }
1170:
1171: // print javadoc comment if any
1172: if (grammar.comment != null) {
1173: _println(grammar.comment);
1174: }
1175:
1176: Token tprefix = (Token) grammar.options
1177: .get("classHeaderPrefix");
1178: if (tprefix == null) {
1179: print("public ");
1180: } else {
1181: String p = StringUtils.stripFrontBack(tprefix.getText(),
1182: "\"", "\"");
1183: if (p == null) {
1184: print("public ");
1185: } else {
1186: print(p + " ");
1187: }
1188: }
1189:
1190: print("class " + grammar.getClassName() + " : " + sup);
1191: println(", TokenStream");
1192: Token tsuffix = (Token) grammar.options
1193: .get("classHeaderSuffix");
1194: if (tsuffix != null) {
1195: String suffix = StringUtils.stripFrontBack(tsuffix
1196: .getText(), "\"", "\"");
1197: if (suffix != null) {
1198: print(", " + suffix); // must be an interface name for CSharp
1199: }
1200: }
1201: println(" {");
1202: tabs++;
1203:
1204: // Generate 'const' definitions for Token IDs
1205: genTokenDefinitions(grammar.tokenManager);
1206:
1207: // Generate user-defined lexer class members
1208: print(processActionForSpecialSymbols(grammar.classMemberAction
1209: .getText(), grammar.classMemberAction.getLine(),
1210: currentRule, null));
1211:
1212: //
1213: // Generate the constructor from InputStream, which in turn
1214: // calls the ByteBuffer constructor
1215: //
1216: println("public " + grammar.getClassName()
1217: + "(Stream ins) : this(new ByteBuffer(ins))");
1218: println("{");
1219: println("}");
1220: println("");
1221:
1222: //
1223: // Generate the constructor from Reader, which in turn
1224: // calls the CharBuffer constructor
1225: //
1226: println("public " + grammar.getClassName()
1227: + "(TextReader r) : this(new CharBuffer(r))");
1228: println("{");
1229: println("}");
1230: println("");
1231:
1232: print("public " + grammar.getClassName() + "(InputBuffer ib)");
1233: // if debugging, wrap the input buffer in a debugger
1234: if (grammar.debuggingOutput)
1235: println(" : this(new LexerSharedInputState(new persistence.antlr.debug.DebuggingInputBuffer(ib)))");
1236: else
1237: println(" : this(new LexerSharedInputState(ib))");
1238: println("{");
1239: println("}");
1240: println("");
1241:
1242: //
1243: // Generate the constructor from InputBuffer (char or byte)
1244: //
1245: println("public " + grammar.getClassName()
1246: + "(LexerSharedInputState state) : base(state)");
1247: println("{");
1248: tabs++;
1249: println("initialize();");
1250: tabs--;
1251: println("}");
1252:
1253: // Generate the initialize function
1254: println("private void initialize()");
1255: println("{");
1256: tabs++;
1257:
1258: // if debugging, set up array variables and call user-overridable
1259: // debugging setup method
1260: if (grammar.debuggingOutput) {
1261: println("ruleNames = _ruleNames;");
1262: println("semPredNames = _semPredNames;");
1263: println("setupDebugging();");
1264: }
1265:
1266: // Generate the setting of various generated options.
1267: // These need to be before the literals since ANTLRHashString depends on
1268: // the casesensitive stuff.
1269: println("caseSensitiveLiterals = " + g.caseSensitiveLiterals
1270: + ";");
1271: println("setCaseSensitive(" + g.caseSensitive + ");");
1272:
1273: // Generate the initialization of a hashtable
1274: // containing the string literals used in the lexer
1275: // The literals variable itself is in CharScanner
1276: if (g.caseSensitiveLiterals)
1277: println("literals = new Hashtable(null, Comparer.Default);");
1278: else
1279: println("literals = new Hashtable(CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);");
1280: Enumeration keys = grammar.tokenManager.getTokenSymbolKeys();
1281: while (keys.hasMoreElements()) {
1282: String key = (String) keys.nextElement();
1283: if (key.charAt(0) != '"') {
1284: continue;
1285: }
1286: TokenSymbol sym = grammar.tokenManager.getTokenSymbol(key);
1287: if (sym instanceof StringLiteralSymbol) {
1288: StringLiteralSymbol s = (StringLiteralSymbol) sym;
1289: println("literals.Add(" + s.getId() + ", "
1290: + s.getTokenType() + ");");
1291: }
1292: }
1293:
1294: Enumeration ids;
1295: tabs--;
1296: println("}");
1297:
1298: // generate the rule name array for debugging
1299: if (grammar.debuggingOutput) {
1300: println("private const string[] _ruleNames = {");
1301:
1302: ids = grammar.rules.elements();
1303: int ruleNum = 0;
1304: while (ids.hasMoreElements()) {
1305: GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
1306: if (sym instanceof RuleSymbol)
1307: println(" \"" + ((RuleSymbol) sym).getId() + "\",");
1308: }
1309: println("};");
1310: }
1311:
1312: // Generate nextToken() rule.
1313: // nextToken() is a synthetic lexer rule that is the implicit OR of all
1314: // user-defined lexer rules.
1315: genNextToken();
1316:
1317: // Generate code for each rule in the lexer
1318: ids = grammar.rules.elements();
1319: int ruleNum = 0;
1320: while (ids.hasMoreElements()) {
1321: RuleSymbol sym = (RuleSymbol) ids.nextElement();
1322: // Don't generate the synthetic rules
1323: if (!sym.getId().equals("mnextToken")) {
1324: genRule(sym, false, ruleNum++, grammar.tokenManager);
1325: }
1326: exitIfError();
1327: }
1328:
1329: // Generate the semantic predicate map for debugging
1330: if (grammar.debuggingOutput)
1331: genSemPredMap();
1332:
1333: // Generate the bitsets used throughout the lexer
1334: genBitsets(bitsetsUsed, ((LexerGrammar) grammar).charVocabulary
1335: .size());
1336:
1337: println("");
1338: tabs--;
1339: println("}");
1340:
1341: tabs--;
1342: // Generate the CSharp namespace closures (if required)
1343: if (nameSpace != null)
1344: nameSpace.emitClosures(currentOutput);
1345:
1346: // Close the lexer output stream
1347: currentOutput.close();
1348: currentOutput = null;
1349: }
1350:
1351: public void genInitFactory(Grammar g) {
1352: if (g.buildAST) {
1353: // Generate the method to initialize an ASTFactory when we're
1354: // building AST's
1355: println("static public void initializeASTFactory( ASTFactory factory )");
1356: println("{");
1357: tabs++;
1358:
1359: println("factory.setMaxNodeType("
1360: + g.tokenManager.maxTokenType() + ");");
1361:
1362: // Walk the token vocabulary and generate code to register every TokenID->ASTNodeType
1363: // mapping specified in the tokens {...} section with the ASTFactory.
1364: Vector v = g.tokenManager.getVocabulary();
1365: for (int i = 0; i < v.size(); i++) {
1366: String s = (String) v.elementAt(i);
1367: if (s != null) {
1368: TokenSymbol ts = g.tokenManager.getTokenSymbol(s);
1369: if (ts != null && ts.getASTNodeType() != null) {
1370: println("factory.setTokenTypeASTNodeType(" + s
1371: + ", \"" + ts.getASTNodeType() + "\");");
1372: }
1373: }
1374: }
1375:
1376: tabs--;
1377: println("}");
1378: }
1379: }
1380:
1381: public void genBody(ParserGrammar g) throws IOException {
1382: // Open the output stream for the parser and set the currentOutput
1383: // SAS: moved file setup so subclass could do it (for VAJ interface)
1384: setupOutput(grammar.getClassName());
1385:
1386: genAST = grammar.buildAST;
1387:
1388: tabs = 0;
1389:
1390: // Generate the header common to all output files.
1391: genHeader();
1392: // Do not use printAction because we assume tabs==0
1393: println(behavior.getHeaderAction(""));
1394:
1395: // Generate the CSharp namespace declaration (if specified)
1396: if (nameSpace != null)
1397: nameSpace.emitDeclarations(currentOutput);
1398: tabs++;
1399:
1400: // Generate header for the parser
1401: println("// Generate the header common to all output files.");
1402: println("using System;");
1403: println("");
1404: println("using TokenBuffer = persistence.antlr.TokenBuffer;");
1405: println("using TokenStreamException = persistence.antlr.TokenStreamException;");
1406: println("using TokenStreamIOException = persistence.antlr.TokenStreamIOException;");
1407: println("using ANTLRException = persistence.antlr.ANTLRException;");
1408: println("using " + grammar.getSuperClass()
1409: + " = persistence.antlr." + grammar.getSuperClass()
1410: + ";");
1411: println("using Token = persistence.antlr.Token;");
1412: println("using TokenStream = persistence.antlr.TokenStream;");
1413: println("using RecognitionException = persistence.antlr.RecognitionException;");
1414: println("using NoViableAltException = persistence.antlr.NoViableAltException;");
1415: println("using MismatchedTokenException = persistence.antlr.MismatchedTokenException;");
1416: println("using SemanticException = persistence.antlr.SemanticException;");
1417: println("using ParserSharedInputState = persistence.antlr.ParserSharedInputState;");
1418: println("using BitSet = persistence.antlr.collections.impl.BitSet;");
1419: if (genAST) {
1420: println("using AST = persistence.antlr.collections.AST;");
1421: println("using ASTPair = persistence.antlr.ASTPair;");
1422: println("using ASTFactory = persistence.antlr.ASTFactory;");
1423: println("using ASTArray = persistence.antlr.collections.impl.ASTArray;");
1424: }
1425:
1426: // Output the user-defined parser preamble
1427: println(grammar.preambleAction.getText());
1428:
1429: // Generate parser class definition
1430: String sup = null;
1431: if (grammar.super Class != null)
1432: sup = grammar.super Class;
1433: else
1434: sup = "persistence.antlr." + grammar.getSuperClass();
1435:
1436: // print javadoc comment if any
1437: if (grammar.comment != null) {
1438: _println(grammar.comment);
1439: }
1440:
1441: Token tprefix = (Token) grammar.options
1442: .get("classHeaderPrefix");
1443: if (tprefix == null) {
1444: print("public ");
1445: } else {
1446: String p = StringUtils.stripFrontBack(tprefix.getText(),
1447: "\"", "\"");
1448: if (p == null) {
1449: print("public ");
1450: } else {
1451: print(p + " ");
1452: }
1453: }
1454:
1455: println("class " + grammar.getClassName() + " : " + sup);
1456:
1457: Token tsuffix = (Token) grammar.options
1458: .get("classHeaderSuffix");
1459: if (tsuffix != null) {
1460: String suffix = StringUtils.stripFrontBack(tsuffix
1461: .getText(), "\"", "\"");
1462: if (suffix != null)
1463: print(" , " + suffix); // must be an interface name for CSharp
1464: }
1465: println("{");
1466: tabs++;
1467:
1468: // Generate 'const' definitions for Token IDs
1469: genTokenDefinitions(grammar.tokenManager);
1470:
1471: // set up an array of all the rule names so the debugger can
1472: // keep track of them only by number -- less to store in tree...
1473: if (grammar.debuggingOutput) {
1474: println("private const string[] _ruleNames = {");
1475: tabs++;
1476:
1477: Enumeration ids = grammar.rules.elements();
1478: int ruleNum = 0;
1479: while (ids.hasMoreElements()) {
1480: GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
1481: if (sym instanceof RuleSymbol)
1482: println(" \"" + ((RuleSymbol) sym).getId() + "\",");
1483: }
1484: tabs--;
1485: println("};");
1486: }
1487:
1488: // Generate user-defined parser class members
1489: print(processActionForSpecialSymbols(grammar.classMemberAction
1490: .getText(), grammar.classMemberAction.getLine(),
1491: currentRule, null));
1492:
1493: // Generate parser class constructor from TokenBuffer
1494: println("");
1495: println("protected void initialize()");
1496: println("{");
1497: tabs++;
1498: println("tokenNames = tokenNames_;");
1499:
1500: if (grammar.buildAST)
1501: println("initializeFactory();");
1502:
1503: // if debugging, set up arrays and call the user-overridable
1504: // debugging setup method
1505: if (grammar.debuggingOutput) {
1506: println("ruleNames = _ruleNames;");
1507: println("semPredNames = _semPredNames;");
1508: println("setupDebugging(tokenBuf);");
1509: }
1510: tabs--;
1511: println("}");
1512: println("");
1513:
1514: println("");
1515: println("protected " + grammar.getClassName()
1516: + "(TokenBuffer tokenBuf, int k) : base(tokenBuf, k)");
1517: println("{");
1518: tabs++;
1519: println("initialize();");
1520: tabs--;
1521: println("}");
1522: println("");
1523:
1524: println("public " + grammar.getClassName()
1525: + "(TokenBuffer tokenBuf) : this(tokenBuf,"
1526: + grammar.maxk + ")");
1527: println("{");
1528: println("}");
1529: println("");
1530:
1531: // Generate parser class constructor from TokenStream
1532: println("protected " + grammar.getClassName()
1533: + "(TokenStream lexer, int k) : base(lexer,k)");
1534: println("{");
1535: tabs++;
1536: println("initialize();");
1537: tabs--;
1538: println("}");
1539: println("");
1540:
1541: println("public " + grammar.getClassName()
1542: + "(TokenStream lexer) : this(lexer," + grammar.maxk
1543: + ")");
1544: println("{");
1545: println("}");
1546: println("");
1547:
1548: println("public " + grammar.getClassName()
1549: + "(ParserSharedInputState state) : base(state,"
1550: + grammar.maxk + ")");
1551: println("{");
1552: tabs++;
1553: println("initialize();");
1554: tabs--;
1555: println("}");
1556: println("");
1557:
1558: astTypes = new java.util.Vector(100);
1559:
1560: // Generate code for each rule in the grammar
1561: Enumeration ids = grammar.rules.elements();
1562: int ruleNum = 0;
1563: while (ids.hasMoreElements()) {
1564: GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
1565: if (sym instanceof RuleSymbol) {
1566: RuleSymbol rs = (RuleSymbol) sym;
1567: genRule(rs, rs.references.size() == 0, ruleNum++,
1568: grammar.tokenManager);
1569: }
1570: exitIfError();
1571: }
1572: if (usingCustomAST) {
1573: // when we are using a custom AST, overload Parser.getAST() to return the
1574: // custom AST type
1575: println("public new " + labeledElementASTType + " getAST()");
1576: println("{");
1577: tabs++;
1578: println("return (" + labeledElementASTType + ") returnAST;");
1579: tabs--;
1580: println("}");
1581: println("");
1582: }
1583:
1584: // Generate the method that initializes the ASTFactory when we're
1585: // building AST's
1586: println("private void initializeFactory()");
1587: println("{");
1588: tabs++;
1589: if (grammar.buildAST) {
1590: println("if (astFactory == null)");
1591: println("{");
1592: tabs++;
1593: if (usingCustomAST) {
1594: println("astFactory = new ASTFactory(\""
1595: + labeledElementASTType + "\");");
1596: } else
1597: println("astFactory = new ASTFactory();");
1598: tabs--;
1599: println("}");
1600: println("initializeASTFactory( astFactory );");
1601: }
1602: tabs--;
1603: println("}");
1604: genInitFactory(g);
1605:
1606: // Generate the token names
1607: genTokenStrings();
1608:
1609: // Generate the bitsets used throughout the grammar
1610: genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType());
1611:
1612: // Generate the semantic predicate map for debugging
1613: if (grammar.debuggingOutput)
1614: genSemPredMap();
1615:
1616: // Close class definition
1617: println("");
1618: tabs--;
1619: println("}");
1620:
1621: tabs--;
1622: // Generate the CSharp namespace closures (if required)
1623: if (nameSpace != null)
1624: nameSpace.emitClosures(currentOutput);
1625:
1626: // Close the parser output stream
1627: currentOutput.close();
1628: currentOutput = null;
1629: }
1630:
1631: public void genBody(TreeWalkerGrammar g) throws IOException {
1632: // Open the output stream for the parser and set the currentOutput
1633: // SAS: move file open to method so subclass can override it
1634: // (mainly for VAJ interface)
1635: setupOutput(grammar.getClassName());
1636:
1637: genAST = grammar.buildAST;
1638: tabs = 0;
1639:
1640: // Generate the header common to all output files.
1641: genHeader();
1642: // Do not use printAction because we assume tabs==0
1643: println(behavior.getHeaderAction(""));
1644:
1645: // Generate the CSharp namespace declaration (if specified)
1646: if (nameSpace != null)
1647: nameSpace.emitDeclarations(currentOutput);
1648: tabs++;
1649:
1650: // Generate header specific to the tree-parser CSharp file
1651: println("// Generate header specific to the tree-parser CSharp file");
1652: println("using System;");
1653: println("");
1654: println("using " + grammar.getSuperClass()
1655: + " = persistence.antlr." + grammar.getSuperClass()
1656: + ";");
1657: println("using Token = persistence.antlr.Token;");
1658: println("using AST = persistence.antlr.collections.AST;");
1659: println("using RecognitionException = persistence.antlr.RecognitionException;");
1660: println("using ANTLRException = persistence.antlr.ANTLRException;");
1661: println("using NoViableAltException = persistence.antlr.NoViableAltException;");
1662: println("using MismatchedTokenException = persistence.antlr.MismatchedTokenException;");
1663: println("using SemanticException = persistence.antlr.SemanticException;");
1664: println("using BitSet = persistence.antlr.collections.impl.BitSet;");
1665: println("using ASTPair = persistence.antlr.ASTPair;");
1666: println("using ASTFactory = persistence.antlr.ASTFactory;");
1667: println("using ASTArray = persistence.antlr.collections.impl.ASTArray;");
1668:
1669: // Output the user-defined parser premamble
1670: println(grammar.preambleAction.getText());
1671:
1672: // Generate parser class definition
1673: String sup = null;
1674: if (grammar.super Class != null) {
1675: sup = grammar.super Class;
1676: } else {
1677: sup = "persistence.antlr." + grammar.getSuperClass();
1678: }
1679: println("");
1680:
1681: // print javadoc comment if any
1682: if (grammar.comment != null) {
1683: _println(grammar.comment);
1684: }
1685:
1686: Token tprefix = (Token) grammar.options
1687: .get("classHeaderPrefix");
1688: if (tprefix == null) {
1689: print("public ");
1690: } else {
1691: String p = StringUtils.stripFrontBack(tprefix.getText(),
1692: "\"", "\"");
1693: if (p == null) {
1694: print("public ");
1695: } else {
1696: print(p + " ");
1697: }
1698: }
1699:
1700: println("class " + grammar.getClassName() + " : " + sup);
1701: Token tsuffix = (Token) grammar.options
1702: .get("classHeaderSuffix");
1703: if (tsuffix != null) {
1704: String suffix = StringUtils.stripFrontBack(tsuffix
1705: .getText(), "\"", "\"");
1706: if (suffix != null) {
1707: print(" , " + suffix); // must be an interface name for CSharp
1708: }
1709: }
1710: println("{");
1711: tabs++;
1712:
1713: // Generate 'const' definitions for Token IDs
1714: genTokenDefinitions(grammar.tokenManager);
1715:
1716: // Generate user-defined parser class members
1717: print(processActionForSpecialSymbols(grammar.classMemberAction
1718: .getText(), grammar.classMemberAction.getLine(),
1719: currentRule, null));
1720:
1721: // Generate default parser class constructor
1722: println("public " + grammar.getClassName() + "()");
1723: println("{");
1724: tabs++;
1725: println("tokenNames = tokenNames_;");
1726: tabs--;
1727: println("}");
1728: println("");
1729:
1730: astTypes = new java.util.Vector();
1731: // Generate code for each rule in the grammar
1732: Enumeration ids = grammar.rules.elements();
1733: int ruleNum = 0;
1734: String ruleNameInits = "";
1735: while (ids.hasMoreElements()) {
1736: GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
1737: if (sym instanceof RuleSymbol) {
1738: RuleSymbol rs = (RuleSymbol) sym;
1739: genRule(rs, rs.references.size() == 0, ruleNum++,
1740: grammar.tokenManager);
1741: }
1742: exitIfError();
1743: }
1744:
1745: if (usingCustomAST) {
1746: // when we are using a custom ast override Parser.getAST to return the
1747: // custom AST type
1748: println("public new " + labeledElementASTType + " getAST()");
1749: println("{");
1750: tabs++;
1751: println("return (" + labeledElementASTType + ") returnAST;");
1752: tabs--;
1753: println("}");
1754: println("");
1755: }
1756:
1757: // Generate the ASTFactory initialization function
1758: genInitFactory(grammar);
1759:
1760: // Generate the token names
1761: genTokenStrings();
1762:
1763: // Generate the bitsets used throughout the grammar
1764: genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType());
1765:
1766: // Close class definition
1767: tabs--;
1768: println("}");
1769: println("");
1770:
1771: tabs--;
1772: // Generate the CSharp namespace closures (if required)
1773: if (nameSpace != null)
1774: nameSpace.emitClosures(currentOutput);
1775:
1776: // Close the parser output stream
1777: currentOutput.close();
1778: currentOutput = null;
1779: }
1780:
1781: /** Generate a series of case statements that implement a BitSet test.
1782: * @param p The Bitset for which cases are to be generated
1783: */
1784: protected void genCases(BitSet p) {
1785: if (DEBUG_CODE_GENERATOR)
1786: System.out.println("genCases(" + p + ")");
1787: int[] elems;
1788:
1789: elems = p.toArray();
1790: // Wrap cases four-per-line for lexer, one-per-line for parser
1791: int wrap = (grammar instanceof LexerGrammar) ? 4 : 1;
1792: int j = 1;
1793: boolean startOfLine = true;
1794: for (int i = 0; i < elems.length; i++) {
1795: if (j == 1) {
1796: print("");
1797: } else {
1798: _print(" ");
1799: }
1800: _print("case " + getValueString(elems[i]) + ":");
1801: if (j == wrap) {
1802: _println("");
1803: startOfLine = true;
1804: j = 1;
1805: } else {
1806: j++;
1807: startOfLine = false;
1808: }
1809: }
1810: if (!startOfLine) {
1811: _println("");
1812: }
1813: }
1814:
1815: /**Generate common code for a block of alternatives; return a
1816: * postscript that needs to be generated at the end of the
1817: * block. Other routines may append else-clauses and such for
1818: * error checking before the postfix is generated. If the
1819: * grammar is a lexer, then generate alternatives in an order
1820: * where alternatives requiring deeper lookahead are generated
1821: * first, and EOF in the lookahead set reduces the depth of
1822: * the lookahead. @param blk The block to generate @param
1823: * noTestForSingle If true, then it does not generate a test
1824: * for a single alternative.
1825: */
1826: public CSharpBlockFinishingInfo genCommonBlock(
1827: AlternativeBlock blk, boolean noTestForSingle) {
1828: int nIF = 0;
1829: boolean createdLL1Switch = false;
1830: int closingBracesOfIFSequence = 0;
1831: CSharpBlockFinishingInfo finishingInfo = new CSharpBlockFinishingInfo();
1832: if (DEBUG_CODE_GENERATOR)
1833: System.out.println("genCommonBlock(" + blk + ")");
1834:
1835: // Save the AST generation state, and set it to that of the block
1836: boolean savegenAST = genAST;
1837: genAST = genAST && blk.getAutoGen();
1838:
1839: boolean oldsaveTest = saveText;
1840: saveText = saveText && blk.getAutoGen();
1841:
1842: // Is this block inverted? If so, generate special-case code
1843: if (blk.not
1844: && analyzer.subruleCanBeInverted(blk,
1845: grammar instanceof LexerGrammar)) {
1846: if (DEBUG_CODE_GENERATOR)
1847: System.out.println("special case: ~(subrule)");
1848: Lookahead p = analyzer.look(1, blk);
1849: // Variable assignment for labeled elements
1850: if (blk.getLabel() != null && syntacticPredLevel == 0) {
1851: println(blk.getLabel() + " = " + lt1Value + ";");
1852: }
1853:
1854: // AST
1855: genElementAST(blk);
1856:
1857: String astArgs = "";
1858: if (grammar instanceof TreeWalkerGrammar) {
1859: if (usingCustomAST)
1860: astArgs = "(AST)_t,";
1861: else
1862: astArgs = "_t,";
1863: }
1864:
1865: // match the bitset for the alternative
1866: println("match(" + astArgs
1867: + getBitsetName(markBitsetForGen(p.fset)) + ");");
1868:
1869: // tack on tree cursor motion if doing a tree walker
1870: if (grammar instanceof TreeWalkerGrammar) {
1871: println("_t = _t.getNextSibling();");
1872: }
1873: return finishingInfo;
1874: }
1875:
1876: // Special handling for single alt
1877: if (blk.getAlternatives().size() == 1) {
1878: Alternative alt = blk.getAlternativeAt(0);
1879: // Generate a warning if there is a synPred for single alt.
1880: if (alt.synPred != null) {
1881: antlrTool
1882: .warning(
1883: "Syntactic predicate superfluous for single alternative",
1884: grammar.getFilename(), blk
1885: .getAlternativeAt(0).synPred
1886: .getLine(), blk
1887: .getAlternativeAt(0).synPred
1888: .getColumn());
1889: }
1890: if (noTestForSingle) {
1891: if (alt.semPred != null) {
1892: // Generate validating predicate
1893: genSemPred(alt.semPred, blk.line);
1894: }
1895: genAlt(alt, blk);
1896: return finishingInfo;
1897: }
1898: }
1899:
1900: // count number of simple LL(1) cases; only do switch for
1901: // many LL(1) cases (no preds, no end of token refs)
1902: // We don't care about exit paths for (...)*, (...)+
1903: // because we don't explicitly have a test for them
1904: // as an alt in the loop.
1905: //
1906: // Also, we now count how many unicode lookahead sets
1907: // there are--they must be moved to DEFAULT or ELSE
1908: // clause.
1909: int nLL1 = 0;
1910: for (int i = 0; i < blk.getAlternatives().size(); i++) {
1911: Alternative a = blk.getAlternativeAt(i);
1912: if (suitableForCaseExpression(a)) {
1913: nLL1++;
1914: }
1915: }
1916:
1917: // do LL(1) cases
1918: if (nLL1 >= makeSwitchThreshold) {
1919: // Determine the name of the item to be compared
1920: String testExpr = lookaheadString(1);
1921: createdLL1Switch = true;
1922: // when parsing trees, convert null to valid tree node with NULL lookahead
1923: if (grammar instanceof TreeWalkerGrammar) {
1924: println("if (null == _t)");
1925: tabs++;
1926: println("_t = ASTNULL;");
1927: tabs--;
1928: }
1929: println("switch ( " + testExpr + " )");
1930: println("{");
1931: //tabs++;
1932: for (int i = 0; i < blk.alternatives.size(); i++) {
1933: Alternative alt = blk.getAlternativeAt(i);
1934: // ignore any non-LL(1) alts, predicated alts,
1935: // or end-of-token alts for case expressions
1936: bSaveIndexCreated = false;
1937: if (!suitableForCaseExpression(alt)) {
1938: continue;
1939: }
1940: Lookahead p = alt.cache[1];
1941: if (p.fset.degree() == 0 && !p.containsEpsilon()) {
1942: antlrTool
1943: .warning(
1944: "Alternate omitted due to empty prediction set",
1945: grammar.getFilename(), alt.head
1946: .getLine(), alt.head
1947: .getColumn());
1948: } else {
1949: genCases(p.fset);
1950: println("{");
1951: tabs++;
1952: genAlt(alt, blk);
1953: println("break;");
1954: tabs--;
1955: println("}");
1956: }
1957: }
1958: println("default:");
1959: tabs++;
1960: }
1961:
1962: // do non-LL(1) and nondeterministic cases This is tricky in
1963: // the lexer, because of cases like: STAR : '*' ; ASSIGN_STAR
1964: // : "*="; Since nextToken is generated without a loop, then
1965: // the STAR will have end-of-token as it's lookahead set for
1966: // LA(2). So, we must generate the alternatives containing
1967: // trailing end-of-token in their lookahead sets *after* the
1968: // alternatives without end-of-token. This implements the
1969: // usual lexer convention that longer matches come before
1970: // shorter ones, e.g. "*=" matches ASSIGN_STAR not STAR
1971: //
1972: // For non-lexer grammars, this does not sort the alternates
1973: // by depth Note that alts whose lookahead is purely
1974: // end-of-token at k=1 end up as default or else clauses.
1975: int startDepth = (grammar instanceof LexerGrammar) ? grammar.maxk
1976: : 0;
1977: for (int altDepth = startDepth; altDepth >= 0; altDepth--) {
1978: if (DEBUG_CODE_GENERATOR)
1979: System.out.println("checking depth " + altDepth);
1980: for (int i = 0; i < blk.alternatives.size(); i++) {
1981: Alternative alt = blk.getAlternativeAt(i);
1982: if (DEBUG_CODE_GENERATOR)
1983: System.out.println("genAlt: " + i);
1984: // if we made a switch above, ignore what we already took care
1985: // of. Specifically, LL(1) alts with no preds
1986: // that do not have end-of-token in their prediction set
1987: // and that are not giant unicode sets.
1988: if (createdLL1Switch && suitableForCaseExpression(alt)) {
1989: if (DEBUG_CODE_GENERATOR)
1990: System.out
1991: .println("ignoring alt because it was in the switch");
1992: continue;
1993: }
1994: String e;
1995:
1996: boolean unpredicted = false;
1997:
1998: if (grammar instanceof LexerGrammar) {
1999: // Calculate the "effective depth" of the alt,
2000: // which is the max depth at which
2001: // cache[depth]!=end-of-token
2002: int effectiveDepth = alt.lookaheadDepth;
2003: if (effectiveDepth == GrammarAnalyzer.NONDETERMINISTIC) {
2004: // use maximum lookahead
2005: effectiveDepth = grammar.maxk;
2006: }
2007: while (effectiveDepth >= 1
2008: && alt.cache[effectiveDepth]
2009: .containsEpsilon()) {
2010: effectiveDepth--;
2011: }
2012: // Ignore alts whose effective depth is other than
2013: // the ones we are generating for this iteration.
2014: if (effectiveDepth != altDepth) {
2015: if (DEBUG_CODE_GENERATOR)
2016: System.out
2017: .println("ignoring alt because effectiveDepth!=altDepth;"
2018: + effectiveDepth
2019: + "!="
2020: + altDepth);
2021: continue;
2022: }
2023: unpredicted = lookaheadIsEmpty(alt, effectiveDepth);
2024: e = getLookaheadTestExpression(alt, effectiveDepth);
2025: } else {
2026: unpredicted = lookaheadIsEmpty(alt, grammar.maxk);
2027: e = getLookaheadTestExpression(alt, grammar.maxk);
2028: }
2029:
2030: // Was it a big unicode range that forced unsuitability
2031: // for a case expression?
2032: if (alt.cache[1].fset.degree() > caseSizeThreshold
2033: && suitableForCaseExpression(alt)) {
2034: if (nIF == 0) {
2035: println("if " + e);
2036: println("{");
2037: } else {
2038: println("else if " + e);
2039: println("{");
2040: }
2041: } else if (unpredicted && alt.semPred == null
2042: && alt.synPred == null) {
2043: // The alt has empty prediction set and no
2044: // predicate to help out. if we have not
2045: // generated a previous if, just put {...} around
2046: // the end-of-token clause
2047: if (nIF == 0) {
2048: println("{");
2049: } else {
2050: println("else {");
2051: }
2052: finishingInfo.needAnErrorClause = false;
2053: } else {
2054: // check for sem and syn preds
2055: // Add any semantic predicate expression to the lookahead test
2056: if (alt.semPred != null) {
2057: // if debugging, wrap the evaluation of the predicate in a method
2058: //
2059: // translate $ and # references
2060: ActionTransInfo tInfo = new ActionTransInfo();
2061: String actionStr = processActionForSpecialSymbols(
2062: alt.semPred, blk.line, currentRule,
2063: tInfo);
2064: // ignore translation info...we don't need to
2065: // do anything with it. call that will inform
2066: // SemanticPredicateListeners of the result
2067: if (((grammar instanceof ParserGrammar) || (grammar instanceof LexerGrammar))
2068: && grammar.debuggingOutput) {
2069: e = "("
2070: + e
2071: + "&& fireSemanticPredicateEvaluated(persistence.antlr.debug.SemanticPredicateEvent.PREDICTING,"
2072: + //FIXME
2073: addSemPred(charFormatter
2074: .escapeString(actionStr))
2075: + "," + actionStr + "))";
2076: } else {
2077: e = "(" + e + "&&(" + actionStr + "))";
2078: }
2079: }
2080:
2081: // Generate any syntactic predicates
2082: if (nIF > 0) {
2083: if (alt.synPred != null) {
2084: println("else {");
2085: tabs++;
2086: genSynPred(alt.synPred, e);
2087: closingBracesOfIFSequence++;
2088: } else {
2089: println("else if " + e + " {");
2090: }
2091: } else {
2092: if (alt.synPred != null) {
2093: genSynPred(alt.synPred, e);
2094: } else {
2095: // when parsing trees, convert null to valid tree node
2096: // with NULL lookahead.
2097: if (grammar instanceof TreeWalkerGrammar) {
2098: println("if (_t == null)");
2099: tabs++;
2100: println("_t = ASTNULL;");
2101: tabs--;
2102: }
2103: println("if " + e);
2104: println("{");
2105: }
2106: }
2107:
2108: }
2109:
2110: nIF++;
2111: tabs++;
2112: genAlt(alt, blk);
2113: tabs--;
2114: println("}");
2115: }
2116: }
2117:
2118: String ps = "";
2119: for (int i = 1; i <= closingBracesOfIFSequence; i++) {
2120: ps += "}";
2121: }
2122:
2123: // Restore the AST generation state
2124: genAST = savegenAST;
2125:
2126: // restore save text state
2127: saveText = oldsaveTest;
2128:
2129: // Return the finishing info.
2130: if (createdLL1Switch) {
2131: tabs--;
2132: finishingInfo.postscript = ps + "break; }";
2133: finishingInfo.generatedSwitch = true;
2134: finishingInfo.generatedAnIf = nIF > 0;
2135: //return new CSharpBlockFinishingInfo(ps+"}",true,nIF>0); // close up switch statement
2136:
2137: } else {
2138: finishingInfo.postscript = ps;
2139: finishingInfo.generatedSwitch = false;
2140: finishingInfo.generatedAnIf = nIF > 0;
2141: // return new CSharpBlockFinishingInfo(ps, false,nIF>0);
2142: }
2143: return finishingInfo;
2144: }
2145:
2146: private static boolean suitableForCaseExpression(Alternative a) {
2147: return a.lookaheadDepth == 1 && a.semPred == null
2148: && !a.cache[1].containsEpsilon()
2149: && a.cache[1].fset.degree() <= caseSizeThreshold;
2150: }
2151:
2152: /** Generate code to link an element reference into the AST */
2153: private void genElementAST(AlternativeElement el) {
2154: // handle case where you're not building trees, but are in tree walker.
2155: // Just need to get labels set up.
2156: if (grammar instanceof TreeWalkerGrammar && !grammar.buildAST) {
2157: String elementRef;
2158: String astName;
2159:
2160: // Generate names and declarations of the AST variable(s)
2161: if (el.getLabel() == null) {
2162: elementRef = lt1Value;
2163: // Generate AST variables for unlabeled stuff
2164: astName = "tmp" + astVarNumber + "_AST";
2165: astVarNumber++;
2166: // Map the generated AST variable in the alternate
2167: mapTreeVariable(el, astName);
2168: // Generate an "input" AST variable also
2169: println(labeledElementASTType + " " + astName
2170: + "_in = " + elementRef + ";");
2171: }
2172: return;
2173: }
2174:
2175: if (grammar.buildAST && syntacticPredLevel == 0) {
2176: boolean needASTDecl = (genAST && (el.getLabel() != null || (el
2177: .getAutoGenType() != GrammarElement.AUTO_GEN_BANG)));
2178:
2179: // RK: if we have a grammar element always generate the decl
2180: // since some guy can access it from an action and we can't
2181: // peek ahead (well not without making a mess).
2182: // I'd prefer taking this out.
2183: if (el.getAutoGenType() != GrammarElement.AUTO_GEN_BANG
2184: && (el instanceof TokenRefElement))
2185: needASTDecl = true;
2186:
2187: boolean doNoGuessTest = (grammar.hasSyntacticPredicate && needASTDecl);
2188:
2189: String elementRef;
2190: String astNameBase;
2191:
2192: // Generate names and declarations of the AST variable(s)
2193: if (el.getLabel() != null) {
2194: // if the element is labeled use that name...
2195: elementRef = el.getLabel();
2196: astNameBase = el.getLabel();
2197: } else {
2198: // else generate a temporary name...
2199: elementRef = lt1Value;
2200: // Generate AST variables for unlabeled stuff
2201: astNameBase = "tmp" + astVarNumber;
2202: astVarNumber++;
2203: }
2204:
2205: // Generate the declaration if required.
2206: if (needASTDecl) {
2207: // Generate the declaration
2208: if (el instanceof GrammarAtom) {
2209: GrammarAtom ga = (GrammarAtom) el;
2210: if (ga.getASTNodeType() != null) {
2211: genASTDeclaration(el, astNameBase, ga
2212: .getASTNodeType());
2213: //println(ga.getASTNodeType()+" " + astName+" = null;");
2214: } else {
2215: genASTDeclaration(el, astNameBase,
2216: labeledElementASTType);
2217: //println(labeledElementASTType+" " + astName + " = null;");
2218: }
2219: } else {
2220: genASTDeclaration(el, astNameBase,
2221: labeledElementASTType);
2222: //println(labeledElementASTType+" " + astName + " = null;");
2223: }
2224: }
2225:
2226: // for convenience..
2227: String astName = astNameBase + "_AST";
2228:
2229: // Map the generated AST variable in the alternate
2230: mapTreeVariable(el, astName);
2231: if (grammar instanceof TreeWalkerGrammar) {
2232: // Generate an "input" AST variable also
2233: println(labeledElementASTType + " " + astName
2234: + "_in = null;");
2235: }
2236:
2237: // Enclose actions with !guessing
2238: if (doNoGuessTest) {
2239: //println("if (0 == inputState.guessing)");
2240: //println("{");
2241: //tabs++;
2242: }
2243:
2244: // if something has a label assume it will be used
2245: // so we must initialize the RefAST
2246: if (el.getLabel() != null) {
2247: if (el instanceof GrammarAtom) {
2248: println(astName
2249: + " = "
2250: + getASTCreateString((GrammarAtom) el,
2251: elementRef) + ";");
2252: } else {
2253: println(astName + " = "
2254: + getASTCreateString(elementRef) + ";");
2255: }
2256: }
2257:
2258: // if it has no label but a declaration exists initialize it.
2259: if (el.getLabel() == null && needASTDecl) {
2260: elementRef = lt1Value;
2261: if (el instanceof GrammarAtom) {
2262: println(astName
2263: + " = "
2264: + getASTCreateString((GrammarAtom) el,
2265: elementRef) + ";");
2266: } else {
2267: println(astName + " = "
2268: + getASTCreateString(elementRef) + ";");
2269: }
2270: // Map the generated AST variable in the alternate
2271: if (grammar instanceof TreeWalkerGrammar) {
2272: // set "input" AST variable also
2273: println(astName + "_in = " + elementRef + ";");
2274: }
2275: }
2276:
2277: if (genAST) {
2278: switch (el.getAutoGenType()) {
2279: case GrammarElement.AUTO_GEN_NONE:
2280: if (usingCustomAST
2281: || ((el instanceof GrammarAtom) && (((GrammarAtom) el)
2282: .getASTNodeType() != null)))
2283: println("astFactory.addASTChild(currentAST, (AST)"
2284: + astName + ");");
2285: else
2286: println("astFactory.addASTChild(currentAST, "
2287: + astName + ");");
2288: break;
2289: case GrammarElement.AUTO_GEN_CARET:
2290: if (usingCustomAST
2291: || ((el instanceof GrammarAtom) && (((GrammarAtom) el)
2292: .getASTNodeType() != null)))
2293: println("astFactory.makeASTRoot(currentAST, (AST)"
2294: + astName + ");");
2295: else
2296: println("astFactory.makeASTRoot(currentAST, "
2297: + astName + ");");
2298: break;
2299: default:
2300: break;
2301: }
2302: }
2303: if (doNoGuessTest) {
2304: //tabs--;
2305: //println("}");
2306: }
2307: }
2308: }
2309:
2310: /** Close the try block and generate catch phrases
2311: * if the element has a labeled handler in the rule
2312: */
2313: private void genErrorCatchForElement(AlternativeElement el) {
2314: if (el.getLabel() == null)
2315: return;
2316: String r = el.enclosingRuleName;
2317: if (grammar instanceof LexerGrammar) {
2318: r = CodeGenerator.encodeLexerRuleName(el.enclosingRuleName);
2319: }
2320: RuleSymbol rs = (RuleSymbol) grammar.getSymbol(r);
2321: if (rs == null) {
2322: antlrTool.panic("Enclosing rule not found!");
2323: }
2324: ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
2325: if (ex != null) {
2326: tabs--;
2327: println("}");
2328: genErrorHandler(ex);
2329: }
2330: }
2331:
2332: /** Generate the catch phrases for a user-specified error handler */
2333: private void genErrorHandler(ExceptionSpec ex) {
2334: // Each ExceptionHandler in the ExceptionSpec is a separate catch
2335: for (int i = 0; i < ex.handlers.size(); i++) {
2336: ExceptionHandler handler = (ExceptionHandler) ex.handlers
2337: .elementAt(i);
2338: // Generate catch phrase
2339: println("catch (" + handler.exceptionTypeAndName.getText()
2340: + ")");
2341: println("{");
2342: tabs++;
2343: if (grammar.hasSyntacticPredicate) {
2344: println("if (0 == inputState.guessing)");
2345: println("{");
2346: tabs++;
2347: }
2348:
2349: // When not guessing, execute user handler action
2350: ActionTransInfo tInfo = new ActionTransInfo();
2351: printAction(processActionForSpecialSymbols(handler.action
2352: .getText(), handler.action.getLine(), currentRule,
2353: tInfo));
2354:
2355: if (grammar.hasSyntacticPredicate) {
2356: tabs--;
2357: println("}");
2358: println("else");
2359: println("{");
2360: tabs++;
2361: // When guessing, rethrow exception
2362: //println("throw " + extractIdOfAction(handler.exceptionTypeAndName) + ";");
2363: println("throw;");
2364: tabs--;
2365: println("}");
2366: }
2367: // Close catch phrase
2368: tabs--;
2369: println("}");
2370: }
2371: }
2372:
2373: /** Generate a try { opening if the element has a labeled handler in the rule */
2374: private void genErrorTryForElement(AlternativeElement el) {
2375: if (el.getLabel() == null)
2376: return;
2377: String r = el.enclosingRuleName;
2378: if (grammar instanceof LexerGrammar) {
2379: r = CodeGenerator.encodeLexerRuleName(el.enclosingRuleName);
2380: }
2381: RuleSymbol rs = (RuleSymbol) grammar.getSymbol(r);
2382: if (rs == null) {
2383: antlrTool.panic("Enclosing rule not found!");
2384: }
2385: ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
2386: if (ex != null) {
2387: println("try // for error handling");
2388: println("{");
2389: tabs++;
2390: }
2391: }
2392:
2393: protected void genASTDeclaration(AlternativeElement el) {
2394: genASTDeclaration(el, labeledElementASTType);
2395: }
2396:
2397: protected void genASTDeclaration(AlternativeElement el,
2398: String node_type) {
2399: genASTDeclaration(el, el.getLabel(), node_type);
2400: }
2401:
2402: protected void genASTDeclaration(AlternativeElement el,
2403: String var_name, String node_type) {
2404: // already declared?
2405: if (declaredASTVariables.contains(el))
2406: return;
2407:
2408: // emit code
2409: //String s = StringUtils.stripFrontBack(node_type, "\"", "\"");
2410: //println(s + " " + var_name + "_AST = null;");
2411: println(node_type + " " + var_name + "_AST = null;");
2412:
2413: // mark as declared
2414: declaredASTVariables.put(el, el);
2415: }
2416:
2417: /** Generate a header that is common to all CSharp files */
2418: protected void genHeader() {
2419: println("// $ANTLR " + Tool.version + ": " + "\""
2420: + antlrTool.fileMinusPath(antlrTool.grammarFile) + "\""
2421: + " -> " + "\"" + grammar.getClassName() + ".cs\"$");
2422: }
2423:
2424: private void genLiteralsTest() {
2425: println("_ttype = testLiteralsTable(_ttype);");
2426: }
2427:
2428: private void genLiteralsTestForPartialToken() {
2429: println("_ttype = testLiteralsTable(text.ToString(_begin, text.Length-_begin), _ttype);");
2430: }
2431:
2432: protected void genMatch(BitSet b) {
2433: }
2434:
2435: protected void genMatch(GrammarAtom atom) {
2436: if (atom instanceof StringLiteralElement) {
2437: if (grammar instanceof LexerGrammar) {
2438: genMatchUsingAtomText(atom);
2439: } else {
2440: genMatchUsingAtomTokenType(atom);
2441: }
2442: } else if (atom instanceof CharLiteralElement) {
2443: if (grammar instanceof LexerGrammar) {
2444: genMatchUsingAtomText(atom);
2445: } else {
2446: antlrTool
2447: .error("cannot ref character literals in grammar: "
2448: + atom);
2449: }
2450: } else if (atom instanceof TokenRefElement) {
2451: genMatchUsingAtomText(atom);
2452: } else if (atom instanceof WildcardElement) {
2453: gen((WildcardElement) atom);
2454: }
2455: }
2456:
2457: protected void genMatchUsingAtomText(GrammarAtom atom) {
2458: // match() for trees needs the _t cursor
2459: String astArgs = "";
2460: if (grammar instanceof TreeWalkerGrammar) {
2461: if (usingCustomAST)
2462: astArgs = "(AST)_t,";
2463: else
2464: astArgs = "_t,";
2465: }
2466:
2467: // if in lexer and ! on element, save buffer index to kill later
2468: if (grammar instanceof LexerGrammar
2469: && (!saveText || atom.getAutoGenType() == GrammarElement.AUTO_GEN_BANG)) {
2470: declareSaveIndexVariableIfNeeded();
2471: println("_saveIndex = text.Length;");
2472: }
2473:
2474: print(atom.not ? "matchNot(" : "match(");
2475: _print(astArgs);
2476:
2477: // print out what to match
2478: if (atom.atomText.equals("EOF")) {
2479: // horrible hack to handle EOF case
2480: _print("Token.EOF_TYPE");
2481: } else {
2482: _print(atom.atomText);
2483: }
2484: _println(");");
2485:
2486: if (grammar instanceof LexerGrammar
2487: && (!saveText || atom.getAutoGenType() == GrammarElement.AUTO_GEN_BANG)) {
2488: declareSaveIndexVariableIfNeeded();
2489: println("text.Length = _saveIndex;"); // kill text atom put in buffer
2490: }
2491: }
2492:
2493: protected void genMatchUsingAtomTokenType(GrammarAtom atom) {
2494: // match() for trees needs the _t cursor
2495: String astArgs = "";
2496: if (grammar instanceof TreeWalkerGrammar) {
2497: if (usingCustomAST)
2498: astArgs = "(AST)_t,";
2499: else
2500: astArgs = "_t,";
2501: }
2502:
2503: // If the literal can be mangled, generate the symbolic constant instead
2504: String mangledName = null;
2505: String s = astArgs + getValueString(atom.getType());
2506:
2507: // matching
2508: println((atom.not ? "matchNot(" : "match(") + s + ");");
2509: }
2510:
2511: /** Generate the nextToken() rule. nextToken() is a synthetic
2512: * lexer rule that is the implicit OR of all user-defined
2513: * lexer rules.
2514: */
2515: public void genNextToken() {
2516: // Are there any public rules? If not, then just generate a
2517: // fake nextToken().
2518: boolean hasPublicRules = false;
2519: for (int i = 0; i < grammar.rules.size(); i++) {
2520: RuleSymbol rs = (RuleSymbol) grammar.rules.elementAt(i);
2521: if (rs.isDefined() && rs.access.equals("public")) {
2522: hasPublicRules = true;
2523: break;
2524: }
2525: }
2526: if (!hasPublicRules) {
2527: println("");
2528: println("override public Token nextToken()\t\t\t//throws TokenStreamException");
2529: println("{");
2530: tabs++;
2531: println("try");
2532: println("{");
2533: tabs++;
2534: println("uponEOF();");
2535: tabs--;
2536: println("}");
2537: println("catch(CharStreamIOException csioe)");
2538: println("{");
2539: tabs++;
2540: println("throw new TokenStreamIOException(csioe.io);");
2541: tabs--;
2542: println("}");
2543: println("catch(CharStreamException cse)");
2544: println("{");
2545: tabs++;
2546: println("throw new TokenStreamException(cse.Message);");
2547: tabs--;
2548: println("}");
2549: println("return new CommonToken(Token.EOF_TYPE, \"\");");
2550: tabs--;
2551: println("}");
2552: println("");
2553: return;
2554: }
2555:
2556: // Create the synthesized nextToken() rule
2557: RuleBlock nextTokenBlk = MakeGrammar.createNextTokenRule(
2558: grammar, grammar.rules, "nextToken");
2559: // Define the nextToken rule symbol
2560: RuleSymbol nextTokenRs = new RuleSymbol("mnextToken");
2561: nextTokenRs.setDefined();
2562: nextTokenRs.setBlock(nextTokenBlk);
2563: nextTokenRs.access = "private";
2564: grammar.define(nextTokenRs);
2565: // Analyze the nextToken rule
2566: boolean ok = grammar.theLLkAnalyzer.deterministic(nextTokenBlk);
2567:
2568: // Generate the next token rule
2569: String filterRule = null;
2570: if (((LexerGrammar) grammar).filterMode) {
2571: filterRule = ((LexerGrammar) grammar).filterRule;
2572: }
2573:
2574: println("");
2575: println("override public Token nextToken()\t\t\t//throws TokenStreamException");
2576: println("{");
2577: tabs++;
2578: println("Token theRetToken = null;");
2579: _println("tryAgain:");
2580: println("for (;;)");
2581: println("{");
2582: tabs++;
2583: println("Token _token = null;");
2584: println("int _ttype = Token.INVALID_TYPE;");
2585: if (((LexerGrammar) grammar).filterMode) {
2586: println("setCommitToPath(false);");
2587: if (filterRule != null) {
2588: // Here's a good place to ensure that the filter rule actually exists
2589: if (!grammar.isDefined(CodeGenerator
2590: .encodeLexerRuleName(filterRule))) {
2591: grammar.antlrTool.error("Filter rule " + filterRule
2592: + " does not exist in this lexer");
2593: } else {
2594: RuleSymbol rs = (RuleSymbol) grammar
2595: .getSymbol(CodeGenerator
2596: .encodeLexerRuleName(filterRule));
2597: if (!rs.isDefined()) {
2598: grammar.antlrTool.error("Filter rule "
2599: + filterRule
2600: + " does not exist in this lexer");
2601: } else if (rs.access.equals("public")) {
2602: grammar.antlrTool.error("Filter rule "
2603: + filterRule + " must be protected");
2604: }
2605: }
2606: println("int _m;");
2607: println("_m = mark();");
2608: }
2609: }
2610: println("resetText();");
2611:
2612: println("try // for char stream error handling");
2613: println("{");
2614: tabs++;
2615:
2616: // Generate try around whole thing to trap scanner errors
2617: println("try // for lexical error handling");
2618: println("{");
2619: tabs++;
2620:
2621: // Test for public lexical rules with empty paths
2622: for (int i = 0; i < nextTokenBlk.getAlternatives().size(); i++) {
2623: Alternative a = nextTokenBlk.getAlternativeAt(i);
2624: if (a.cache[1].containsEpsilon()) {
2625: //String r = a.head.toString();
2626: RuleRefElement rr = (RuleRefElement) a.head;
2627: String r = CodeGenerator
2628: .decodeLexerRuleName(rr.targetRule);
2629: antlrTool.warning("public lexical rule " + r
2630: + " is optional (can match \"nothing\")");
2631: }
2632: }
2633:
2634: // Generate the block
2635: String newline = System.getProperty("line.separator");
2636: CSharpBlockFinishingInfo howToFinish = genCommonBlock(
2637: nextTokenBlk, false);
2638: String errFinish = "if (LA(1)==EOF_CHAR) { uponEOF(); returnToken_ = makeToken(Token.EOF_TYPE); }";
2639: errFinish += newline + "\t\t\t\t";
2640: if (((LexerGrammar) grammar).filterMode) {
2641: if (filterRule == null) {
2642: //kunle: errFinish += "else { consume(); continue tryAgain; }";
2643: errFinish += "\t\t\t\telse";
2644: errFinish += "\t\t\t\t{";
2645: errFinish += "\t\t\t\t\tconsume();";
2646: errFinish += "\t\t\t\t\tgoto tryAgain;";
2647: errFinish += "\t\t\t\t}";
2648: } else {
2649: errFinish += "\t\t\t\t\telse" + newline + "\t\t\t\t\t{"
2650: + newline + "\t\t\t\t\tcommit();" + newline
2651: + "\t\t\t\t\ttry {m" + filterRule + "(false);}"
2652: + newline
2653: + "\t\t\t\t\tcatch(RecognitionException e)"
2654: + newline + "\t\t\t\t\t{" + newline
2655: + "\t\t\t\t\t // catastrophic failure"
2656: + newline + "\t\t\t\t\t reportError(e);"
2657: + newline + "\t\t\t\t\t consume();" + newline
2658: + "\t\t\t\t\t}" + newline
2659: + "\t\t\t\t\tgoto tryAgain;" + newline
2660: + "\t\t\t\t}";
2661: }
2662: } else {
2663: errFinish += "else {" + throwNoViable + "}";
2664: }
2665: genBlockFinish(howToFinish, errFinish);
2666:
2667: // at this point a valid token has been matched, undo "mark" that was done
2668: if (((LexerGrammar) grammar).filterMode && filterRule != null) {
2669: println("commit();");
2670: }
2671:
2672: // Generate literals test if desired
2673: // make sure _ttype is set first; note returnToken_ must be
2674: // non-null as the rule was required to create it.
2675: println("if ( null==returnToken_ ) goto tryAgain; // found SKIP token");
2676: println("_ttype = returnToken_.Type;");
2677: if (((LexerGrammar) grammar).getTestLiterals()) {
2678: genLiteralsTest();
2679: }
2680:
2681: // return token created by rule reference in switch
2682: println("returnToken_.Type = _ttype;");
2683: println("return returnToken_;");
2684:
2685: // Close try block
2686: tabs--;
2687: println("}");
2688: println("catch (RecognitionException e) {");
2689: tabs++;
2690: if (((LexerGrammar) grammar).filterMode) {
2691: if (filterRule == null) {
2692: println("if (!getCommitToPath())");
2693: println("{");
2694: tabs++;
2695: println("consume();");
2696: println("goto tryAgain;");
2697: tabs--;
2698: println("}");
2699: } else {
2700: println("if (!getCommitToPath())");
2701: println("{");
2702: tabs++;
2703: println("rewind(_m);");
2704: println("resetText();");
2705: println("try {m" + filterRule + "(false);}");
2706: println("catch(RecognitionException ee) {");
2707: println(" // horrendous failure: error in filter rule");
2708: println(" reportError(ee);");
2709: println(" consume();");
2710: println("}");
2711: //println("goto tryAgain;");
2712: tabs--;
2713: println("}");
2714: println("else");
2715: }
2716: }
2717: if (nextTokenBlk.getDefaultErrorHandler()) {
2718: println("{");
2719: tabs++;
2720: println("reportError(e);");
2721: println("consume();");
2722: tabs--;
2723: println("}");
2724: } else {
2725: // pass on to invoking routine
2726: tabs++;
2727: println("throw new TokenStreamRecognitionException(e);");
2728: tabs--;
2729: }
2730: tabs--;
2731: println("}");
2732:
2733: // close CharStreamException try
2734: tabs--;
2735: println("}");
2736: println("catch (CharStreamException cse) {");
2737: println(" if ( cse is CharStreamIOException ) {");
2738: println(" throw new TokenStreamIOException(((CharStreamIOException)cse).io);");
2739: println(" }");
2740: println(" else {");
2741: println(" throw new TokenStreamException(cse.Message);");
2742: println(" }");
2743: println("}");
2744:
2745: // close for-loop
2746: tabs--;
2747: println("}");
2748:
2749: // close method nextToken
2750: tabs--;
2751: println("}");
2752: println("");
2753: }
2754:
2755: /** Gen a named rule block.
2756: * ASTs are generated for each element of an alternative unless
2757: * the rule or the alternative have a '!' modifier.
2758: *
2759: * If an alternative defeats the default tree construction, it
2760: * must set <rule>_AST to the root of the returned AST.
2761: *
2762: * Each alternative that does automatic tree construction, builds
2763: * up root and child list pointers in an ASTPair structure.
2764: *
2765: * A rule finishes by setting the returnAST variable from the
2766: * ASTPair.
2767: *
2768: * @param rule The name of the rule to generate
2769: * @param startSymbol true if the rule is a start symbol (i.e., not referenced elsewhere)
2770: */
2771: public void genRule(RuleSymbol s, boolean startSymbol, int ruleNum,
2772: TokenManager tm) {
2773: tabs = 1;
2774: if (DEBUG_CODE_GENERATOR)
2775: System.out.println("genRule(" + s.getId() + ")");
2776: if (!s.isDefined()) {
2777: antlrTool.error("undefined rule: " + s.getId());
2778: return;
2779: }
2780:
2781: // Generate rule return type, name, arguments
2782: RuleBlock rblk = s.getBlock();
2783: currentRule = rblk;
2784: currentASTResult = s.getId();
2785:
2786: // clear list of declared ast variables..
2787: declaredASTVariables.clear();
2788:
2789: // Save the AST generation state, and set it to that of the rule
2790: boolean savegenAST = genAST;
2791: genAST = genAST && rblk.getAutoGen();
2792:
2793: // boolean oldsaveTest = saveText;
2794: saveText = rblk.getAutoGen();
2795:
2796: // print javadoc comment if any
2797: if (s.comment != null) {
2798: _println(s.comment);
2799: }
2800:
2801: // Gen method access and final qualifier
2802: //print(s.access + " final ");
2803: print(s.access + " ");
2804:
2805: // Gen method return type (note lexer return action set at rule creation)
2806: if (rblk.returnAction != null) {
2807: // Has specified return value
2808: _print(extractTypeOfAction(rblk.returnAction, rblk
2809: .getLine(), rblk.getColumn())
2810: + " ");
2811: } else {
2812: // No specified return value
2813: _print("void ");
2814: }
2815:
2816: // Gen method name
2817: _print(s.getId() + "(");
2818:
2819: // Additional rule parameters common to all rules for this grammar
2820: _print(commonExtraParams);
2821: if (commonExtraParams.length() != 0 && rblk.argAction != null) {
2822: _print(",");
2823: }
2824:
2825: // Gen arguments
2826: if (rblk.argAction != null) {
2827: // Has specified arguments
2828: _println("");
2829: tabs++;
2830: println(rblk.argAction);
2831: tabs--;
2832: print(")");
2833: } else {
2834: // No specified arguments
2835: _print(")");
2836: }
2837:
2838: // Gen throws clause and open curly
2839: _print(" //throws " + exceptionThrown);
2840: if (grammar instanceof ParserGrammar) {
2841: _print(", TokenStreamException");
2842: } else if (grammar instanceof LexerGrammar) {
2843: _print(", CharStreamException, TokenStreamException");
2844: }
2845: // Add user-defined exceptions unless lexer (for now)
2846: if (rblk.throwsSpec != null) {
2847: if (grammar instanceof LexerGrammar) {
2848: antlrTool
2849: .error("user-defined throws spec not allowed (yet) for lexer rule "
2850: + rblk.ruleName);
2851: } else {
2852: _print(", " + rblk.throwsSpec);
2853: }
2854: }
2855:
2856: _println("");
2857: _println("{");
2858: tabs++;
2859:
2860: // Convert return action to variable declaration
2861: if (rblk.returnAction != null)
2862: println(rblk.returnAction + ";");
2863:
2864: // print out definitions needed by rules for various grammar types
2865: println(commonLocalVars);
2866:
2867: if (grammar.traceRules) {
2868: if (grammar instanceof TreeWalkerGrammar) {
2869: if (usingCustomAST)
2870: println("traceIn(\"" + s.getId() + "\",(AST)_t);");
2871: else
2872: println("traceIn(\"" + s.getId() + "\",_t);");
2873: } else {
2874: println("traceIn(\"" + s.getId() + "\");");
2875: }
2876: }
2877:
2878: if (grammar instanceof LexerGrammar) {
2879: // lexer rule default return value is the rule's token name
2880: // This is a horrible hack to support the built-in EOF lexer rule.
2881: if (s.getId().equals("mEOF"))
2882: println("_ttype = Token.EOF_TYPE;");
2883: else
2884: println("_ttype = " + s.getId().substring(1) + ";");
2885:
2886: // delay creation of _saveIndex until we need it OK?
2887: bSaveIndexCreated = false;
2888:
2889: /*
2890: println("boolean old_saveConsumedInput=saveConsumedInput;");
2891: if ( !rblk.getAutoGen() ) { // turn off "save input" if ! on rule
2892: println("saveConsumedInput=false;");
2893: }
2894: */
2895: }
2896:
2897: // if debugging, write code to mark entry to the rule
2898: if (grammar.debuggingOutput)
2899: if (grammar instanceof ParserGrammar)
2900: println("fireEnterRule(" + ruleNum + ",0);");
2901: else if (grammar instanceof LexerGrammar)
2902: println("fireEnterRule(" + ruleNum + ",_ttype);");
2903:
2904: // Generate trace code if desired
2905: if (grammar.debuggingOutput || grammar.traceRules) {
2906: println("try { // debugging");
2907: tabs++;
2908: }
2909:
2910: // Initialize AST variables
2911: if (grammar instanceof TreeWalkerGrammar) {
2912: // "Input" value for rule
2913: println(labeledElementASTType + " " + s.getId()
2914: + "_AST_in = (" + labeledElementASTType + ")_t;");
2915: }
2916: if (grammar.buildAST) {
2917: // Parser member used to pass AST returns from rule invocations
2918: println("returnAST = null;");
2919: // Tracks AST construction
2920: // println("ASTPair currentAST = (inputState.guessing==0) ? new ASTPair() : null;");
2921: println("ASTPair currentAST = new ASTPair();");
2922: // User-settable return value for rule.
2923: println(labeledElementASTType + " " + s.getId()
2924: + "_AST = null;");
2925: }
2926:
2927: genBlockPreamble(rblk);
2928: genBlockInitAction(rblk);
2929: println("");
2930:
2931: // Search for an unlabeled exception specification attached to the rule
2932: ExceptionSpec unlabeledUserSpec = rblk.findExceptionSpec("");
2933:
2934: // Generate try block around the entire rule for error handling
2935: if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler()) {
2936: println("try { // for error handling");
2937: tabs++;
2938: }
2939:
2940: // Generate the alternatives
2941: if (rblk.alternatives.size() == 1) {
2942: // One alternative -- use simple form
2943: Alternative alt = rblk.getAlternativeAt(0);
2944: String pred = alt.semPred;
2945: if (pred != null)
2946: genSemPred(pred, currentRule.line);
2947: if (alt.synPred != null) {
2948: antlrTool
2949: .warning(
2950: "Syntactic predicate ignored for single alternative",
2951: grammar.getFilename(), alt.synPred
2952: .getLine(), alt.synPred
2953: .getColumn());
2954: }
2955: genAlt(alt, rblk);
2956: } else {
2957: // Multiple alternatives -- generate complex form
2958: boolean ok = grammar.theLLkAnalyzer.deterministic(rblk);
2959:
2960: CSharpBlockFinishingInfo howToFinish = genCommonBlock(rblk,
2961: false);
2962: genBlockFinish(howToFinish, throwNoViable);
2963: }
2964:
2965: // Generate catch phrase for error handling
2966: if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler()) {
2967: // Close the try block
2968: tabs--;
2969: println("}");
2970: }
2971:
2972: // Generate user-defined or default catch phrases
2973: if (unlabeledUserSpec != null) {
2974: genErrorHandler(unlabeledUserSpec);
2975: } else if (rblk.getDefaultErrorHandler()) {
2976: // Generate default catch phrase
2977: println("catch (" + exceptionThrown + " ex)");
2978: println("{");
2979: tabs++;
2980: // Generate code to handle error if not guessing
2981: if (grammar.hasSyntacticPredicate) {
2982: println("if (0 == inputState.guessing)");
2983: println("{");
2984: tabs++;
2985: }
2986: println("reportError(ex);");
2987: if (!(grammar instanceof TreeWalkerGrammar)) {
2988: // Generate code to consume until token in k==1 follow set
2989: Lookahead follow = grammar.theLLkAnalyzer.FOLLOW(1,
2990: rblk.endNode);
2991: String followSetName = getBitsetName(markBitsetForGen(follow.fset));
2992: println("consume();");
2993: println("consumeUntil(" + followSetName + ");");
2994: } else {
2995: // Just consume one token
2996: println("if (null != _t)");
2997: println("{");
2998: tabs++;
2999: println("_t = _t.getNextSibling();");
3000: tabs--;
3001: println("}");
3002: }
3003: if (grammar.hasSyntacticPredicate) {
3004: tabs--;
3005: // When guessing, rethrow exception
3006: println("}");
3007: println("else");
3008: println("{");
3009: tabs++;
3010: //println("throw ex;");
3011: println("throw;");
3012: tabs--;
3013: println("}");
3014: }
3015: // Close catch phrase
3016: tabs--;
3017: println("}");
3018: }
3019:
3020: // Squirrel away the AST "return" value
3021: if (grammar.buildAST) {
3022: println("returnAST = " + s.getId() + "_AST;");
3023: }
3024:
3025: // Set return tree value for tree walkers
3026: if (grammar instanceof TreeWalkerGrammar) {
3027: println("retTree_ = _t;");
3028: }
3029:
3030: // Generate literals test for lexer rules so marked
3031: if (rblk.getTestLiterals()) {
3032: if (s.access.equals("protected")) {
3033: genLiteralsTestForPartialToken();
3034: } else {
3035: genLiteralsTest();
3036: }
3037: }
3038:
3039: // if doing a lexer rule, dump code to create token if necessary
3040: if (grammar instanceof LexerGrammar) {
3041: println("if (_createToken && (null == _token) && (_ttype != Token.SKIP))");
3042: println("{");
3043: tabs++;
3044: println("_token = makeToken(_ttype);");
3045: println("_token.setText(text.ToString(_begin, text.Length-_begin));");
3046: tabs--;
3047: println("}");
3048: println("returnToken_ = _token;");
3049: }
3050:
3051: // Gen the return statement if there is one (lexer has hard-wired return action)
3052: if (rblk.returnAction != null) {
3053: println("return "
3054: + extractIdOfAction(rblk.returnAction, rblk
3055: .getLine(), rblk.getColumn()) + ";");
3056: }
3057:
3058: if (grammar.debuggingOutput || grammar.traceRules) {
3059: tabs--;
3060: println("}");
3061: println("finally");
3062: println("{ // debugging");
3063: tabs++;
3064:
3065: // If debugging, generate calls to mark exit of rule
3066: if (grammar.debuggingOutput)
3067: if (grammar instanceof ParserGrammar)
3068: println("fireExitRule(" + ruleNum + ",0);");
3069: else if (grammar instanceof LexerGrammar)
3070: println("fireExitRule(" + ruleNum + ",_ttype);");
3071:
3072: if (grammar.traceRules) {
3073: if (grammar instanceof TreeWalkerGrammar) {
3074: println("traceOut(\"" + s.getId() + "\",_t);");
3075: } else {
3076: println("traceOut(\"" + s.getId() + "\");");
3077: }
3078: }
3079:
3080: tabs--;
3081: println("}");
3082: }
3083:
3084: tabs--;
3085: println("}");
3086: println("");
3087:
3088: // Restore the AST generation state
3089: genAST = savegenAST;
3090:
3091: // restore char save state
3092: // saveText = oldsaveTest;
3093: }
3094:
3095: private void GenRuleInvocation(RuleRefElement rr) {
3096: // dump rule name
3097: _print(rr.targetRule + "(");
3098:
3099: // lexers must tell rule if it should set returnToken_
3100: if (grammar instanceof LexerGrammar) {
3101: // if labeled, could access Token, so tell rule to create
3102: if (rr.getLabel() != null) {
3103: _print("true");
3104: } else {
3105: _print("false");
3106: }
3107: if (commonExtraArgs.length() != 0 || rr.args != null) {
3108: _print(",");
3109: }
3110: }
3111:
3112: // Extra arguments common to all rules for this grammar
3113: _print(commonExtraArgs);
3114: if (commonExtraArgs.length() != 0 && rr.args != null) {
3115: _print(",");
3116: }
3117:
3118: // Process arguments to method, if any
3119: RuleSymbol rs = (RuleSymbol) grammar.getSymbol(rr.targetRule);
3120: if (rr.args != null) {
3121: // When not guessing, execute user arg action
3122: ActionTransInfo tInfo = new ActionTransInfo();
3123: String args = processActionForSpecialSymbols(rr.args, 0,
3124: currentRule, tInfo);
3125: if (tInfo.assignToRoot || tInfo.refRuleRoot != null) {
3126: antlrTool.error("Arguments of rule reference '"
3127: + rr.targetRule + "' cannot set or ref #"
3128: + currentRule.getRuleName(), grammar
3129: .getFilename(), rr.getLine(), rr.getColumn());
3130: }
3131: _print(args);
3132:
3133: // Warn if the rule accepts no arguments
3134: if (rs.block.argAction == null) {
3135: antlrTool.warning("Rule '" + rr.targetRule
3136: + "' accepts no arguments", grammar
3137: .getFilename(), rr.getLine(), rr.getColumn());
3138: }
3139: } else {
3140: // For C++, no warning if rule has parameters, because there may be default
3141: // values for all of the parameters
3142: if (rs.block.argAction != null) {
3143: antlrTool.warning(
3144: "Missing parameters on reference to rule "
3145: + rr.targetRule, grammar.getFilename(),
3146: rr.getLine(), rr.getColumn());
3147: }
3148: }
3149: _println(");");
3150:
3151: // move down to the first child while parsing
3152: if (grammar instanceof TreeWalkerGrammar) {
3153: println("_t = retTree_;");
3154: }
3155: }
3156:
3157: protected void genSemPred(String pred, int line) {
3158: // translate $ and # references
3159: ActionTransInfo tInfo = new ActionTransInfo();
3160: pred = processActionForSpecialSymbols(pred, line, currentRule,
3161: tInfo);
3162: // ignore translation info...we don't need to do anything with it.
3163: String escapedPred = charFormatter.escapeString(pred);
3164:
3165: // if debugging, wrap the semantic predicate evaluation in a method
3166: // that can tell SemanticPredicateListeners the result
3167: if (grammar.debuggingOutput
3168: && ((grammar instanceof ParserGrammar) || (grammar instanceof LexerGrammar)))
3169: pred = "fireSemanticPredicateEvaluated(persistence.antlr.debug.SemanticPredicateEvent.VALIDATING,"
3170: + addSemPred(escapedPred) + "," + pred + ")";
3171: println("if (!(" + pred + "))");
3172: println(" throw new SemanticException(\"" + escapedPred
3173: + "\");");
3174: }
3175:
3176: /** Write an array of Strings which are the semantic predicate
3177: * expressions. The debugger will reference them by number only
3178: */
3179: protected void genSemPredMap() {
3180: Enumeration e = semPreds.elements();
3181: println("private string[] _semPredNames = {");
3182: tabs++;
3183: while (e.hasMoreElements())
3184: println("\"" + e.nextElement() + "\",");
3185: tabs--;
3186: println("};");
3187: }
3188:
3189: protected void genSynPred(SynPredBlock blk, String lookaheadExpr) {
3190: if (DEBUG_CODE_GENERATOR)
3191: System.out.println("gen=>(" + blk + ")");
3192:
3193: // Dump synpred result variable
3194: println("bool synPredMatched" + blk.ID + " = false;");
3195: // Gen normal lookahead test
3196: println("if (" + lookaheadExpr + ")");
3197: println("{");
3198: tabs++;
3199:
3200: // Save input state
3201: if (grammar instanceof TreeWalkerGrammar) {
3202: println("AST __t" + blk.ID + " = _t;");
3203: } else {
3204: println("int _m" + blk.ID + " = mark();");
3205: }
3206:
3207: // Once inside the try, assume synpred works unless exception caught
3208: println("synPredMatched" + blk.ID + " = true;");
3209: println("inputState.guessing++;");
3210:
3211: // if debugging, tell listeners that a synpred has started
3212: if (grammar.debuggingOutput
3213: && ((grammar instanceof ParserGrammar) || (grammar instanceof LexerGrammar))) {
3214: println("fireSyntacticPredicateStarted();");
3215: }
3216:
3217: syntacticPredLevel++;
3218: println("try {");
3219: tabs++;
3220: gen((AlternativeBlock) blk); // gen code to test predicate
3221: tabs--;
3222: //println("System.out.println(\"pred "+blk+" succeeded\");");
3223: println("}");
3224: //kunle: lose a few warnings cheaply
3225: // println("catch (" + exceptionThrown + " pe)");
3226: println("catch (" + exceptionThrown + ")");
3227: println("{");
3228: tabs++;
3229: println("synPredMatched" + blk.ID + " = false;");
3230: //println("System.out.println(\"pred "+blk+" failed\");");
3231: tabs--;
3232: println("}");
3233:
3234: // Restore input state
3235: if (grammar instanceof TreeWalkerGrammar) {
3236: println("_t = __t" + blk.ID + ";");
3237: } else {
3238: println("rewind(_m" + blk.ID + ");");
3239: }
3240:
3241: println("inputState.guessing--;");
3242:
3243: // if debugging, tell listeners how the synpred turned out
3244: if (grammar.debuggingOutput
3245: && ((grammar instanceof ParserGrammar) || (grammar instanceof LexerGrammar))) {
3246: println("if (synPredMatched" + blk.ID + ")");
3247: println(" fireSyntacticPredicateSucceeded();");
3248: println("else");
3249: println(" fireSyntacticPredicateFailed();");
3250: }
3251:
3252: syntacticPredLevel--;
3253: tabs--;
3254:
3255: // Close lookahead test
3256: println("}");
3257:
3258: // Test synred result
3259: println("if ( synPredMatched" + blk.ID + " )");
3260: println("{");
3261: }
3262:
3263: /** Generate a static array containing the names of the tokens,
3264: * indexed by the token type values. This static array is used
3265: * to format error messages so that the token identifers or literal
3266: * strings are displayed instead of the token numbers.
3267: *
3268: * If a lexical rule has a paraphrase, use it rather than the
3269: * token label.
3270: */
3271: public void genTokenStrings() {
3272: // Generate a string for each token. This creates a static
3273: // array of Strings indexed by token type.
3274: println("");
3275: println("public static readonly string[] tokenNames_ = new string[] {");
3276: tabs++;
3277:
3278: // Walk the token vocabulary and generate a Vector of strings
3279: // from the tokens.
3280: Vector v = grammar.tokenManager.getVocabulary();
3281: for (int i = 0; i < v.size(); i++) {
3282: String s = (String) v.elementAt(i);
3283: if (s == null) {
3284: s = "<" + String.valueOf(i) + ">";
3285: }
3286: if (!s.startsWith("\"") && !s.startsWith("<")) {
3287: TokenSymbol ts = (TokenSymbol) grammar.tokenManager
3288: .getTokenSymbol(s);
3289: if (ts != null && ts.getParaphrase() != null) {
3290: s = StringUtils.stripFrontBack(ts.getParaphrase(),
3291: "\"", "\"");
3292: }
3293: } else if (s.startsWith("\"")) {
3294: s = StringUtils.stripFrontBack(s, "\"", "\"");
3295: }
3296: print(charFormatter.literalString(s));
3297: if (i != v.size() - 1) {
3298: _print(",");
3299: }
3300: _println("");
3301: }
3302:
3303: // Close the string array initailizer
3304: tabs--;
3305: println("};");
3306: }
3307:
3308: /** Generate the token types CSharp file */
3309: protected void genTokenTypes(TokenManager tm) throws IOException {
3310: // Open the token output CSharp file and set the currentOutput stream
3311: // SAS: file open was moved to a method so a subclass can override
3312: // This was mainly for the VAJ interface
3313: setupOutput(tm.getName() + TokenTypesFileSuffix);
3314:
3315: tabs = 0;
3316:
3317: // Generate the header common to all CSharp files
3318: genHeader();
3319: // Do not use printAction because we assume tabs==0
3320: println(behavior.getHeaderAction(""));
3321:
3322: // Generate the CSharp namespace declaration (if specified)
3323: if (nameSpace != null)
3324: nameSpace.emitDeclarations(currentOutput);
3325: tabs++;
3326:
3327: // Encapsulate the definitions in a class. This has to be done as a class because
3328: // they are all constants and CSharp inteface types cannot contain constants.
3329: println("public class " + tm.getName() + TokenTypesFileSuffix);
3330: //println("public class " + getTokenTypesClassName());
3331: println("{");
3332: tabs++;
3333:
3334: genTokenDefinitions(tm);
3335:
3336: // Close the interface
3337: tabs--;
3338: println("}");
3339:
3340: tabs--;
3341: // Generate the CSharp namespace closures (if required)
3342: if (nameSpace != null)
3343: nameSpace.emitClosures(currentOutput);
3344:
3345: // Close the tokens output file
3346: currentOutput.close();
3347: currentOutput = null;
3348: exitIfError();
3349: }
3350:
3351: protected void genTokenDefinitions(TokenManager tm)
3352: throws IOException {
3353: // Generate a definition for each token type
3354: Vector v = tm.getVocabulary();
3355:
3356: // Do special tokens manually
3357: println("public const int EOF = " + Token.EOF_TYPE + ";");
3358: println("public const int NULL_TREE_LOOKAHEAD = "
3359: + Token.NULL_TREE_LOOKAHEAD + ";");
3360:
3361: for (int i = Token.MIN_USER_TYPE; i < v.size(); i++) {
3362: String s = (String) v.elementAt(i);
3363: if (s != null) {
3364: if (s.startsWith("\"")) {
3365: // a string literal
3366: StringLiteralSymbol sl = (StringLiteralSymbol) tm
3367: .getTokenSymbol(s);
3368: if (sl == null) {
3369: antlrTool.panic("String literal " + s
3370: + " not in symbol table");
3371: } else if (sl.label != null) {
3372: println("public const int " + sl.label + " = "
3373: + i + ";");
3374: } else {
3375: String mangledName = mangleLiteral(s);
3376: if (mangledName != null) {
3377: // We were able to create a meaningful mangled token name
3378: println("public const int " + mangledName
3379: + " = " + i + ";");
3380: // if no label specified, make the label equal to the mangled name
3381: sl.label = mangledName;
3382: } else {
3383: println("// " + s + " = " + i);
3384: }
3385: }
3386: } else if (!s.startsWith("<")) {
3387: println("public const int " + s + " = " + i + ";");
3388: }
3389: }
3390: }
3391: println("");
3392: }
3393:
3394: /** Process a string for an simple expression for use in xx/action.g
3395: * it is used to cast simple tokens/references to the right type for
3396: * the generated language. Basically called for every element in
3397: * the vector to getASTCreateString(vector V)
3398: * @param str A String.
3399: */
3400: public String processStringForASTConstructor(String str) {
3401: /*
3402: System.out.println("processStringForASTConstructor: str = "+str+
3403: ", custom = "+(new Boolean(usingCustomAST)).toString()+
3404: ", tree = "+(new Boolean((grammar instanceof TreeWalkerGrammar))).toString()+
3405: ", parser = "+(new Boolean((grammar instanceof ParserGrammar))).toString()+
3406: ", notDefined = "+(new Boolean((!(grammar.tokenManager.tokenDefined(str))))).toString()
3407: );
3408: */
3409: if (usingCustomAST
3410: && ((grammar instanceof TreeWalkerGrammar) || (grammar instanceof ParserGrammar))
3411: && !(grammar.tokenManager.tokenDefined(str))) {
3412: //System.out.println("processStringForASTConstructor: "+str+" with cast");
3413: return "(AST)" + str;
3414: } else {
3415: //System.out.println("processStringForASTConstructor: "+str);
3416: return str;
3417: }
3418: }
3419:
3420: /** Get a string for an expression to generate creation of an AST subtree.
3421: * @param v A Vector of String, where each element is an expression
3422: * in the target language yielding an AST node.
3423: */
3424: public String getASTCreateString(Vector v) {
3425: if (v.size() == 0) {
3426: return "";
3427: }
3428: StringBuffer buf = new StringBuffer();
3429: buf.append("(" + labeledElementASTType
3430: + ")astFactory.make( (new ASTArray(" + v.size() + "))");
3431: for (int i = 0; i < v.size(); i++) {
3432: buf.append(".add(" + v.elementAt(i) + ")");
3433: }
3434: buf.append(")");
3435: return buf.toString();
3436: }
3437:
3438: /** Get a string for an expression to generate creating of an AST node
3439: * @param atom The grammar node for which you are creating the node
3440: * @param str The arguments to the AST constructor
3441: */
3442: public String getASTCreateString(GrammarAtom atom,
3443: String astCtorArgs) {
3444: String astCreateString = "astFactory.create(" + astCtorArgs
3445: + ")";
3446:
3447: if (atom == null)
3448: return getASTCreateString(astCtorArgs);
3449: else {
3450: if (atom.getASTNodeType() != null) {
3451: // this Atom was instantiated from a Token that had an "AST" option - associating
3452: // it with a specific heterogeneous AST type - applied to either:
3453: // 1) it's underlying TokenSymbol (in the "tokens {} section" or,
3454: // 2) a particular token reference in the grammar
3455: //
3456: // For option (1), we simply generate a cast to hetero-AST type
3457: // For option (2), we generate a call to factory.create(Token, ASTNodeType) and cast it too
3458: TokenSymbol ts = grammar.tokenManager
3459: .getTokenSymbol(atom.getText());
3460: if ((ts == null)
3461: || (ts.getASTNodeType() != atom
3462: .getASTNodeType()))
3463: astCreateString = "(" + atom.getASTNodeType()
3464: + ") astFactory.create(" + astCtorArgs
3465: + ", \"" + atom.getASTNodeType() + "\")";
3466: else if ((ts != null) && (ts.getASTNodeType() != null))
3467: astCreateString = "(" + ts.getASTNodeType() + ") "
3468: + astCreateString;
3469: } else if (usingCustomAST)
3470: astCreateString = "(" + labeledElementASTType + ") "
3471: + astCreateString;
3472: }
3473: return astCreateString;
3474: }
3475:
3476: /** Returns a string expression that creates an AST node using the specified
3477: * AST constructor argument string.
3478: * Parses the first (possibly only) argument in the supplied AST ctor argument
3479: * string to obtain the token type -- ctorID.
3480: *
3481: * IF the token type is a valid token symbol AND
3482: * it has an associated AST node type AND
3483: * this is not a #[ID, "T", "ASTType"] constructor
3484: * THEN
3485: * generate a call to factory.create(ID, Text, token.ASTNodeType())
3486: *
3487: * #[ID, "T", "ASTType"] constructors are mapped to astFactory.create(ID, "T", "ASTType")
3488: *
3489: * The supported AST constructor forms are:
3490: * #[ID]
3491: * #[ID, "text"]
3492: * #[ID, "text", ASTclassname] -- introduced in 2.7.2
3493: *
3494: * @param astCtorArgs The arguments to the AST constructor
3495: */
3496: public String getASTCreateString(String astCtorArgs) {
3497: // kunle: 19-Aug-2002
3498: // This AST creation string is almost certainly[*1] a manual tree construction request.
3499: // From the manual [I couldn't read ALL of the code ;-)], this can only be one of:
3500: // 1) #[ID] -- 'astCtorArgs' contains: 'ID' (without quotes) or,
3501: // 2) #[ID, "T"] -- 'astCtorArgs' contains: 'ID, "Text"' (without single quotes) or,
3502: // kunle: 08-Dec-2002 - 2.7.2a6
3503: // 3) #[ID, "T", "ASTTypeName"] -- 'astCtorArgs' contains: 'ID, "T", "ASTTypeName"' (without single quotes)
3504: //
3505: // [*1] In my tests, 'atom' was '== null' only for manual tree construction requests
3506:
3507: if (astCtorArgs == null) {
3508: astCtorArgs = "";
3509: }
3510: String astCreateString = "astFactory.create(" + astCtorArgs
3511: + ")";
3512: String ctorID = astCtorArgs;
3513: String ctorText = null;
3514: int commaIndex;
3515: boolean ctorIncludesCustomType = false; // Is this a #[ID, "t", "ASTType"] constructor?
3516:
3517: commaIndex = astCtorArgs.indexOf(',');
3518: if (commaIndex != -1) {
3519: ctorID = astCtorArgs.substring(0, commaIndex); // the 'ID' portion of #[ID, "Text"]
3520: ctorText = astCtorArgs.substring(commaIndex + 1,
3521: astCtorArgs.length()); // the 'Text' portion of #[ID, "Text"]
3522: commaIndex = ctorText.indexOf(',');
3523: if (commaIndex != -1) {
3524: // This is an AST creation of the form: #[ID, "Text", "ASTTypename"]
3525: // Support for this was introduced with 2.7.2a6
3526: // create default type or (since 2.7.2) 3rd arg is classname
3527: ctorIncludesCustomType = true;
3528: }
3529: }
3530: TokenSymbol ts = grammar.tokenManager.getTokenSymbol(ctorID);
3531: if ((null != ts) && (null != ts.getASTNodeType()))
3532: astCreateString = "(" + ts.getASTNodeType() + ") "
3533: + astCreateString;
3534: else if (usingCustomAST)
3535: astCreateString = "(" + labeledElementASTType + ") "
3536: + astCreateString;
3537:
3538: return astCreateString;
3539: }
3540:
3541: protected String getLookaheadTestExpression(Lookahead[] look, int k) {
3542: StringBuffer e = new StringBuffer(100);
3543: boolean first = true;
3544:
3545: e.append("(");
3546: for (int i = 1; i <= k; i++) {
3547: BitSet p = look[i].fset;
3548: if (!first) {
3549: e.append(") && (");
3550: }
3551: first = false;
3552:
3553: // Syn preds can yield <end-of-syn-pred> (epsilon) lookahead.
3554: // There is no way to predict what that token would be. Just
3555: // allow anything instead.
3556: if (look[i].containsEpsilon()) {
3557: e.append("true");
3558: } else {
3559: e.append(getLookaheadTestTerm(i, p));
3560: }
3561: }
3562: e.append(")");
3563:
3564: return e.toString();
3565: }
3566:
3567: /**Generate a lookahead test expression for an alternate. This
3568: * will be a series of tests joined by '&&' and enclosed by '()',
3569: * the number of such tests being determined by the depth of the lookahead.
3570: */
3571: protected String getLookaheadTestExpression(Alternative alt,
3572: int maxDepth) {
3573: int depth = alt.lookaheadDepth;
3574: if (depth == GrammarAnalyzer.NONDETERMINISTIC) {
3575: // if the decision is nondeterministic, do the best we can: LL(k)
3576: // any predicates that are around will be generated later.
3577: depth = grammar.maxk;
3578: }
3579:
3580: if (maxDepth == 0) {
3581: // empty lookahead can result from alt with sem pred
3582: // that can see end of token. E.g., A : {pred}? ('a')? ;
3583: return "( true )";
3584: }
3585: return "(" + getLookaheadTestExpression(alt.cache, depth) + ")";
3586: }
3587:
3588: /**Generate a depth==1 lookahead test expression given the BitSet.
3589: * This may be one of:
3590: * 1) a series of 'x==X||' tests
3591: * 2) a range test using >= && <= where possible,
3592: * 3) a bitset membership test for complex comparisons
3593: * @param k The lookahead level
3594: * @param p The lookahead set for level k
3595: */
3596: protected String getLookaheadTestTerm(int k, BitSet p) {
3597: // Determine the name of the item to be compared
3598: String ts = lookaheadString(k);
3599:
3600: // Generate a range expression if possible
3601: int[] elems = p.toArray();
3602: if (elementsAreRange(elems)) {
3603: return getRangeExpression(k, elems);
3604: }
3605:
3606: // Generate a bitset membership test if possible
3607: StringBuffer e;
3608: int degree = p.degree();
3609: if (degree == 0) {
3610: return "true";
3611: }
3612:
3613: if (degree >= bitsetTestThreshold) {
3614: int bitsetIdx = markBitsetForGen(p);
3615: return getBitsetName(bitsetIdx) + ".member(" + ts + ")";
3616: }
3617:
3618: // Otherwise, generate the long-winded series of "x==X||" tests
3619: e = new StringBuffer();
3620: for (int i = 0; i < elems.length; i++) {
3621: // Get the compared-to item (token or character value)
3622: String cs = getValueString(elems[i]);
3623:
3624: // Generate the element comparison
3625: if (i > 0)
3626: e.append("||");
3627: e.append(ts);
3628: e.append("==");
3629: e.append(cs);
3630: }
3631: return e.toString();
3632: }
3633:
3634: /** Return an expression for testing a contiguous renage of elements
3635: * @param k The lookahead level
3636: * @param elems The elements representing the set, usually from BitSet.toArray().
3637: * @return String containing test expression.
3638: */
3639: public String getRangeExpression(int k, int[] elems) {
3640: if (!elementsAreRange(elems)) {
3641: antlrTool.panic("getRangeExpression called with non-range");
3642: }
3643: int begin = elems[0];
3644: int end = elems[elems.length - 1];
3645:
3646: return "(" + lookaheadString(k) + " >= "
3647: + getValueString(begin) + " && " + lookaheadString(k)
3648: + " <= " + getValueString(end) + ")";
3649: }
3650:
3651: /** getValueString: get a string representation of a token or char value
3652: * @param value The token or char value
3653: */
3654: private String getValueString(int value) {
3655: String cs;
3656: if (grammar instanceof LexerGrammar) {
3657: cs = charFormatter.literalChar(value);
3658: } else {
3659: TokenSymbol ts = grammar.tokenManager
3660: .getTokenSymbolAt(value);
3661: if (ts == null) {
3662: return "" + value; // return token type as string
3663: // antlrTool.panic("vocabulary for token type " + value + " is null");
3664: }
3665: String tId = ts.getId();
3666: if (ts instanceof StringLiteralSymbol) {
3667: // if string literal, use predefined label if any
3668: // if no predefined, try to mangle into LITERAL_xxx.
3669: // if can't mangle, use int value as last resort
3670: StringLiteralSymbol sl = (StringLiteralSymbol) ts;
3671: String label = sl.getLabel();
3672: if (label != null) {
3673: cs = label;
3674: } else {
3675: cs = mangleLiteral(tId);
3676: if (cs == null) {
3677: cs = String.valueOf(value);
3678: }
3679: }
3680: } else {
3681: cs = tId;
3682: }
3683: }
3684: return cs;
3685: }
3686:
3687: /**Is the lookahead for this alt empty? */
3688: protected boolean lookaheadIsEmpty(Alternative alt, int maxDepth) {
3689: int depth = alt.lookaheadDepth;
3690: if (depth == GrammarAnalyzer.NONDETERMINISTIC) {
3691: depth = grammar.maxk;
3692: }
3693: for (int i = 1; i <= depth && i <= maxDepth; i++) {
3694: BitSet p = alt.cache[i].fset;
3695: if (p.degree() != 0) {
3696: return false;
3697: }
3698: }
3699: return true;
3700: }
3701:
3702: private String lookaheadString(int k) {
3703: if (grammar instanceof TreeWalkerGrammar) {
3704: return "_t.Type";
3705: }
3706: return "LA(" + k + ")";
3707: }
3708:
3709: /** Mangle a string literal into a meaningful token name. This is
3710: * only possible for literals that are all characters. The resulting
3711: * mangled literal name is literalsPrefix with the text of the literal
3712: * appended.
3713: * @return A string representing the mangled literal, or null if not possible.
3714: */
3715: private String mangleLiteral(String s) {
3716: String mangled = antlrTool.literalsPrefix;
3717: for (int i = 1; i < s.length() - 1; i++) {
3718: if (!Character.isLetter(s.charAt(i)) && s.charAt(i) != '_') {
3719: return null;
3720: }
3721: mangled += s.charAt(i);
3722: }
3723: if (antlrTool.upperCaseMangledLiterals) {
3724: mangled = mangled.toUpperCase();
3725: }
3726: return mangled;
3727: }
3728:
3729: /** Map an identifier to it's corresponding tree-node variable.
3730: * This is context-sensitive, depending on the rule and alternative
3731: * being generated
3732: * @param idParam The identifier name to map
3733: * @return The mapped id (which may be the same as the input), or null if the mapping is invalid due to duplicates
3734: */
3735: public String mapTreeId(String idParam, ActionTransInfo transInfo) {
3736: // if not in an action of a rule, nothing to map.
3737: if (currentRule == null)
3738: return idParam;
3739:
3740: boolean in_var = false;
3741: String id = idParam;
3742: if (grammar instanceof TreeWalkerGrammar) {
3743: if (!grammar.buildAST) {
3744: in_var = true;
3745: }
3746: // If the id ends with "_in", then map it to the input variable
3747: else if (id.length() > 3
3748: && id.lastIndexOf("_in") == id.length() - 3) {
3749: // Strip off the "_in"
3750: id = id.substring(0, id.length() - 3);
3751: in_var = true;
3752: }
3753: }
3754:
3755: // Check the rule labels. If id is a label, then the output
3756: // variable is label_AST, and the input variable is plain label.
3757: for (int i = 0; i < currentRule.labeledElements.size(); i++) {
3758: AlternativeElement elt = (AlternativeElement) currentRule.labeledElements
3759: .elementAt(i);
3760: if (elt.getLabel().equals(id)) {
3761: return in_var ? id : id + "_AST";
3762: }
3763: }
3764:
3765: // Failing that, check the id-to-variable map for the alternative.
3766: // If the id is in the map, then output variable is the name in the
3767: // map, and input variable is name_in
3768: String s = (String) treeVariableMap.get(id);
3769: if (s != null) {
3770: if (s == NONUNIQUE) {
3771: // There is more than one element with this id
3772: antlrTool.error("Ambiguous reference to AST element "
3773: + id + " in rule " + currentRule.getRuleName());
3774: return null;
3775: } else if (s.equals(currentRule.getRuleName())) {
3776: // a recursive call to the enclosing rule is
3777: // ambiguous with the rule itself.
3778: // if( in_var )
3779: // System.out.println("returning null (rulename)");
3780: antlrTool.error("Ambiguous reference to AST element "
3781: + id + " in rule " + currentRule.getRuleName());
3782: return null;
3783: } else {
3784: return in_var ? s + "_in" : s;
3785: }
3786: }
3787:
3788: // Failing that, check the rule name itself. Output variable
3789: // is rule_AST; input variable is rule_AST_in (treeparsers).
3790: if (id.equals(currentRule.getRuleName())) {
3791: String r = in_var ? id + "_AST_in" : id + "_AST";
3792: if (transInfo != null) {
3793: if (!in_var) {
3794: transInfo.refRuleRoot = r;
3795: }
3796: }
3797: return r;
3798: } else {
3799: // id does not map to anything -- return itself.
3800: return id;
3801: }
3802: }
3803:
3804: /** Given an element and the name of an associated AST variable,
3805: * create a mapping between the element "name" and the variable name.
3806: */
3807: private void mapTreeVariable(AlternativeElement e, String name) {
3808: // For tree elements, defer to the root
3809: if (e instanceof TreeElement) {
3810: mapTreeVariable(((TreeElement) e).root, name);
3811: return;
3812: }
3813:
3814: // Determine the name of the element, if any, for mapping purposes
3815: String elName = null;
3816:
3817: // Don't map labeled items
3818: if (e.getLabel() == null) {
3819: if (e instanceof TokenRefElement) {
3820: // use the token id
3821: elName = ((TokenRefElement) e).atomText;
3822: } else if (e instanceof RuleRefElement) {
3823: // use the rule name
3824: elName = ((RuleRefElement) e).targetRule;
3825: }
3826: }
3827: // Add the element to the tree variable map if it has a name
3828: if (elName != null) {
3829: if (treeVariableMap.get(elName) != null) {
3830: // Name is already in the map -- mark it as duplicate
3831: treeVariableMap.remove(elName);
3832: treeVariableMap.put(elName, NONUNIQUE);
3833: } else {
3834: treeVariableMap.put(elName, name);
3835: }
3836: }
3837: }
3838:
3839: /** Lexically process tree-specifiers in the action.
3840: * This will replace #id and #(...) with the appropriate
3841: * function calls and/or variables.
3842: */
3843: protected String processActionForSpecialSymbols(String actionStr,
3844: int line, RuleBlock currentRule, ActionTransInfo tInfo) {
3845: if (actionStr == null || actionStr.length() == 0)
3846: return null;
3847:
3848: // The action trans info tells us (at the moment) whether an
3849: // assignment was done to the rule's tree root.
3850: if (grammar == null)
3851: return actionStr;
3852:
3853: // see if we have anything to do...
3854: if ((grammar.buildAST && actionStr.indexOf('#') != -1)
3855: || grammar instanceof TreeWalkerGrammar
3856: || ((grammar instanceof LexerGrammar || grammar instanceof ParserGrammar) && actionStr
3857: .indexOf('$') != -1)) {
3858: // Create a lexer to read an action and return the translated version
3859: persistence.antlr.actions.csharp.ActionLexer lexer = new persistence.antlr.actions.csharp.ActionLexer(
3860: actionStr, currentRule, this , tInfo);
3861:
3862: lexer.setLineOffset(line);
3863: lexer.setFilename(grammar.getFilename());
3864: lexer.setTool(antlrTool);
3865:
3866: try {
3867: lexer.mACTION(true);
3868: actionStr = lexer.getTokenObject().getText();
3869: // System.out.println("action translated: "+actionStr);
3870: // System.out.println("trans info is "+tInfo);
3871: } catch (RecognitionException ex) {
3872: lexer.reportError(ex);
3873: return actionStr;
3874: } catch (TokenStreamException tex) {
3875: antlrTool.panic("Error reading action:" + actionStr);
3876: return actionStr;
3877: } catch (CharStreamException io) {
3878: antlrTool.panic("Error reading action:" + actionStr);
3879: return actionStr;
3880: }
3881: }
3882: return actionStr;
3883: }
3884:
3885: private void setupGrammarParameters(Grammar g) {
3886: if (g instanceof ParserGrammar || g instanceof LexerGrammar
3887: || g instanceof TreeWalkerGrammar) {
3888: /* RK: options also have to be added to Grammar.java and for options
3889: * on the file level entries have to be defined in
3890: * DefineGrammarSymbols.java and passed around via 'globals' in antlrTool.java
3891: */
3892: if (antlrTool.nameSpace != null)
3893: nameSpace = new CSharpNameSpace(antlrTool.nameSpace
3894: .getName());
3895: //genHashLines = antlrTool.genHashLines;
3896:
3897: /* let grammar level options override filelevel ones...
3898: */
3899: if (g.hasOption("namespace")) {
3900: Token t = g.getOption("namespace");
3901: if (t != null) {
3902: nameSpace = new CSharpNameSpace(t.getText());
3903: }
3904: }
3905: /*
3906: if( g.hasOption("genHashLines") ) {
3907: Token t = g.getOption("genHashLines");
3908: if( t != null ) {
3909: String val = StringUtils.stripFrontBack(t.getText(),"\"","\"");
3910: genHashLines = val.equals("true");
3911: }
3912: }
3913: */
3914: }
3915:
3916: if (g instanceof ParserGrammar) {
3917: labeledElementASTType = "AST";
3918: if (g.hasOption("ASTLabelType")) {
3919: Token tsuffix = g.getOption("ASTLabelType");
3920: if (tsuffix != null) {
3921: String suffix = StringUtils.stripFrontBack(tsuffix
3922: .getText(), "\"", "\"");
3923: if (suffix != null) {
3924: usingCustomAST = true;
3925: labeledElementASTType = suffix;
3926: }
3927: }
3928: }
3929: labeledElementType = "Token ";
3930: labeledElementInit = "null";
3931: commonExtraArgs = "";
3932: commonExtraParams = "";
3933: commonLocalVars = "";
3934: lt1Value = "LT(1)";
3935: exceptionThrown = "RecognitionException";
3936: throwNoViable = "throw new NoViableAltException(LT(1), getFilename());";
3937: } else if (g instanceof LexerGrammar) {
3938: labeledElementType = "char ";
3939: labeledElementInit = "'\\0'";
3940: commonExtraArgs = "";
3941: commonExtraParams = "bool _createToken";
3942: commonLocalVars = "int _ttype; Token _token=null; int _begin=text.Length;";
3943: lt1Value = "LA(1)";
3944: exceptionThrown = "RecognitionException";
3945: throwNoViable = "throw new NoViableAltForCharException((char)LA(1), getFilename(), getLine(), getColumn());";
3946: } else if (g instanceof TreeWalkerGrammar) {
3947: labeledElementASTType = "AST";
3948: labeledElementType = "AST";
3949: if (g.hasOption("ASTLabelType")) {
3950: Token tsuffix = g.getOption("ASTLabelType");
3951: if (tsuffix != null) {
3952: String suffix = StringUtils.stripFrontBack(tsuffix
3953: .getText(), "\"", "\"");
3954: if (suffix != null) {
3955: usingCustomAST = true;
3956: labeledElementASTType = suffix;
3957: labeledElementType = suffix;
3958: }
3959: }
3960: }
3961: if (!g.hasOption("ASTLabelType")) {
3962: g.setOption("ASTLabelType", new Token(
3963: ANTLRTokenTypes.STRING_LITERAL, "AST"));
3964: }
3965: labeledElementInit = "null";
3966: commonExtraArgs = "_t";
3967: commonExtraParams = "AST _t";
3968: commonLocalVars = "";
3969: if (usingCustomAST)
3970: lt1Value = "(_t==ASTNULL) ? null : ("
3971: + labeledElementASTType + ")_t";
3972: else
3973: lt1Value = "_t";
3974: exceptionThrown = "RecognitionException";
3975: throwNoViable = "throw new NoViableAltException(_t);";
3976: } else {
3977: antlrTool.panic("Unknown grammar type");
3978: }
3979: }
3980:
3981: /** This method exists so a subclass, namely VAJCodeGenerator,
3982: * can open the file in its own evil way. JavaCodeGenerator
3983: * simply opens a text file...
3984: */
3985: public void setupOutput(String className) throws IOException {
3986: currentOutput = antlrTool.openOutputFile(className + ".cs");
3987: }
3988:
3989: /** Helper method from Eric Smith's version of CSharpCodeGenerator.*/
3990: private static String OctalToUnicode(String str) {
3991: // only do any conversion if the string looks like "'\003'"
3992: if ((4 <= str.length()) && ('\'' == str.charAt(0))
3993: && ('\\' == str.charAt(1))
3994: && (('0' <= str.charAt(2)) && ('7' >= str.charAt(2)))
3995: && ('\'' == str.charAt(str.length() - 1))) {
3996: // convert octal representation to decimal, then to hex
3997: Integer x = Integer.valueOf(str.substring(2,
3998: str.length() - 1), 8);
3999:
4000: return "'\\x" + Integer.toHexString(x.intValue()) + "'";
4001: } else {
4002: return str;
4003: }
4004: }
4005:
4006: /** Helper method that returns the name of the interface/class/enum type for
4007: token type constants.
4008: */
4009: public String getTokenTypesClassName() {
4010: TokenManager tm = grammar.tokenManager;
4011: return new String(tm.getName() + TokenTypesFileSuffix);
4012: }
4013:
4014: private void declareSaveIndexVariableIfNeeded() {
4015: if (!bSaveIndexCreated) {
4016: println("int _saveIndex = 0;");
4017: bSaveIndexCreated = true;
4018: }
4019: }
4020: }
|