PageRenderTime 70ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/antlr-2.7.5/antlr/CSharpCodeGenerator.java

https://github.com/boo/boo-lang
Java | 4095 lines | 2862 code | 382 blank | 851 comment | 718 complexity | 03034d4690f63bfcd828da84b77dde68 MD5 | raw file
Possible License(s): GPL-2.0
  1. package antlr;
  2. /* ANTLR Translator Generator
  3. * Project led by Terence Parr at http://www.jGuru.com
  4. * Software rights: http://www.antlr.org/license.html
  5. *
  6. * $Id:$
  7. */
  8. //
  9. // ANTLR C# Code Generator by Micheal Jordan
  10. // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com
  11. // Anthony Oguntimehin
  12. //
  13. // With many thanks to Eric V. Smith from the ANTLR list.
  14. //
  15. // HISTORY:
  16. //
  17. // 17-May-2002 kunle Fixed bug in OctalToUnicode() - was processing non-Octal escape sequences
  18. // Also added namespace support based on Cpp version.
  19. // 07-Jun-2002 kunle Added Scott Ellis's _saveIndex creation optimizations
  20. // 09-Sep-2002 richardN Richard Ney's bug-fix for literals table construction.
  21. // [ Hashtable ctor needed instance of hash code provider not it's class name. ]
  22. // 17-Sep-2002 kunle & Added all Token ID definitions as data member of every Lexer/Parser/TreeParser
  23. // AOg [ A by-product of problem-solving phase of the hetero-AST changes below
  24. // but, it breaks nothing and restores "normal" ANTLR codegen behaviour. ]
  25. // 19-Oct-2002 kunle & Completed the work required to support heterogenous ASTs (many changes)
  26. // AOg &
  27. // michealj
  28. // 14-Nov-2002 michealj Added "initializeASTFactory()" to support flexible ASTFactory initialization.
  29. // [ Thanks to Ric Klaren - for suggesting it and implementing it for Cpp. ]
  30. // 18-Nov-2002 kunle Added fix to make xx_tokenSet_xx names CLS compliant.
  31. // 01-Dec-2002 richardN Patch to reduce "unreachable code" warnings
  32. // 01-Dec-2002 richardN Fix to generate correct TreeParser token-type classnames.
  33. // 12-Jan-2003 kunle & Generated Lexers, Parsers and TreeParsers now support ANTLR's tracing option.
  34. // michealj
  35. // 12-Jan-2003 kunle Fixed issue where initializeASTFactory() was generated when "buildAST=false"
  36. // 14-Jan-2003 AOg initializeASTFactory(AST factory) method was modifying the Parser's "astFactory"
  37. // member rather than it's own "factory" parameter. Fixed.
  38. // 18-Jan-2003 kunle & Fixed reported issues with ASTFactory create() calls for hetero ASTs
  39. // michealj - code generated for LEXER token with hetero-AST option specified does not compile
  40. // - code generated for imaginary tokens with hetero-AST option specified uses
  41. // default AST type
  42. // - code generated for per-TokenRef hetero-AST option specified does not compile
  43. // 18-Jan-2003 kunle initializeASTFactory(AST) method is now a static public member
  44. // 18-May-2003 kunle Changes to address outstanding reported issues::
  45. // - Fixed reported issues with support for case-sensitive literals
  46. // - antlr.SemanticException now imported for all Lexers.
  47. // [ This exception is thrown on predicate failure. ]
  48. // 12-Jan-2004 kunle Added fix for reported issue with un-compileable generated lexers
  49. //
  50. //
  51. import java.util.Enumeration;
  52. import java.util.Hashtable;
  53. import java.util.StringTokenizer;
  54. import antlr.collections.impl.BitSet;
  55. import antlr.collections.impl.Vector;
  56. import java.io.PrintWriter; //SAS: changed for proper text file io
  57. import java.io.IOException;
  58. import java.io.FileWriter;
  59. /** Generates MyParser.cs, MyLexer.cs and MyParserTokenTypes.cs */
  60. public class CSharpCodeGenerator extends CodeGenerator {
  61. // non-zero if inside syntactic predicate generation
  62. protected int syntacticPredLevel = 0;
  63. // Are we generating ASTs (for parsers and tree parsers) right now?
  64. protected boolean genAST = false;
  65. // Are we saving the text consumed (for lexers) right now?
  66. protected boolean saveText = false;
  67. // Grammar parameters set up to handle different grammar classes.
  68. // These are used to get instanceof tests out of code generation
  69. boolean usingCustomAST = false;
  70. String labeledElementType;
  71. String labeledElementASTType;
  72. String labeledElementInit;
  73. String commonExtraArgs;
  74. String commonExtraParams;
  75. String commonLocalVars;
  76. String lt1Value;
  77. String exceptionThrown;
  78. String throwNoViable;
  79. // Tracks the rule being generated. Used for mapTreeId
  80. RuleBlock currentRule;
  81. // Tracks the rule or labeled subrule being generated. Used for AST generation.
  82. String currentASTResult;
  83. /** Mapping between the ids used in the current alt, and the
  84. * names of variables used to represent their AST values.
  85. */
  86. Hashtable treeVariableMap = new Hashtable();
  87. /** Used to keep track of which AST variables have been defined in a rule
  88. * (except for the #rule_name and #rule_name_in var's
  89. */
  90. Hashtable declaredASTVariables = new Hashtable();
  91. /* Count of unnamed generated variables */
  92. int astVarNumber = 1;
  93. /** Special value used to mark duplicate in treeVariableMap */
  94. protected static final String NONUNIQUE = new String();
  95. public static final int caseSizeThreshold = 127; // ascii is max
  96. private Vector semPreds;
  97. // Used to keep track of which (heterogeneous AST types are used)
  98. // which need to be set in the ASTFactory of the generated parser
  99. private java.util.Vector astTypes;
  100. private static CSharpNameSpace nameSpace = null;
  101. // _saveIndex creation optimization -- don't create it unless we need to use it
  102. int saveIndexCreateLevel;
  103. int blockNestingLevel;
  104. /** Create a CSharp code-generator using the given Grammar.
  105. * The caller must still call setTool, setBehavior, and setAnalyzer
  106. * before generating code.
  107. */
  108. public CSharpCodeGenerator() {
  109. super();
  110. charFormatter = new CSharpCharFormatter();
  111. }
  112. /** Adds a semantic predicate string to the sem pred vector
  113. These strings will be used to build an array of sem pred names
  114. when building a debugging parser. This method should only be
  115. called when the debug option is specified
  116. */
  117. protected int addSemPred(String predicate) {
  118. semPreds.appendElement(predicate);
  119. return semPreds.size()-1;
  120. }
  121. public void exitIfError()
  122. {
  123. if (antlrTool.hasError())
  124. {
  125. antlrTool.fatalError("Exiting due to errors.");
  126. }
  127. }
  128. /**Generate the parser, lexer, treeparser, and token types in CSharp */
  129. public void gen() {
  130. // Do the code generation
  131. try {
  132. // Loop over all grammars
  133. Enumeration grammarIter = behavior.grammars.elements();
  134. while (grammarIter.hasMoreElements()) {
  135. Grammar g = (Grammar)grammarIter.nextElement();
  136. // Connect all the components to each other
  137. g.setGrammarAnalyzer(analyzer);
  138. g.setCodeGenerator(this);
  139. analyzer.setGrammar(g);
  140. // To get right overloading behavior across heterogeneous grammars
  141. setupGrammarParameters(g);
  142. g.generate();
  143. exitIfError();
  144. }
  145. // Loop over all token managers (some of which are lexers)
  146. Enumeration tmIter = behavior.tokenManagers.elements();
  147. while (tmIter.hasMoreElements()) {
  148. TokenManager tm = (TokenManager)tmIter.nextElement();
  149. if (!tm.isReadOnly()) {
  150. // Write the token manager tokens as CSharp
  151. // this must appear before genTokenInterchange so that
  152. // labels are set on string literals
  153. genTokenTypes(tm);
  154. // Write the token manager tokens as plain text
  155. genTokenInterchange(tm);
  156. }
  157. exitIfError();
  158. }
  159. }
  160. catch (IOException e) {
  161. antlrTool.reportException(e, null);
  162. }
  163. }
  164. /** Generate code for the given grammar element.
  165. * @param blk The {...} action to generate
  166. */
  167. public void gen(ActionElement action) {
  168. if ( DEBUG_CODE_GENERATOR ) System.out.println("genAction("+action+")");
  169. if ( action.isSemPred ) {
  170. genSemPred(action.actionText, action.line);
  171. }
  172. else {
  173. if ( grammar.hasSyntacticPredicate ) {
  174. println("if (0==inputState.guessing)");
  175. println("{");
  176. tabs++;
  177. }
  178. ActionTransInfo tInfo = new ActionTransInfo();
  179. String actionStr = processActionForSpecialSymbols(action.actionText,
  180. action.getLine(),
  181. currentRule, tInfo);
  182. if ( tInfo.refRuleRoot!=null ) {
  183. // Somebody referenced "#rule", make sure translated var is valid
  184. // assignment to #rule is left as a ref also, meaning that assignments
  185. // with no other refs like "#rule = foo();" still forces this code to be
  186. // generated (unnecessarily).
  187. println(tInfo.refRuleRoot + " = ("+labeledElementASTType+")currentAST.root;");
  188. }
  189. // dump the translated action
  190. printAction(actionStr);
  191. if ( tInfo.assignToRoot ) {
  192. // Somebody did a "#rule=", reset internal currentAST.root
  193. println("currentAST.root = "+tInfo.refRuleRoot+";");
  194. // reset the child pointer too to be last sibling in sibling list
  195. println("if ( (null != "+tInfo.refRuleRoot+") && (null != "+tInfo.refRuleRoot+".getFirstChild()) )");
  196. tabs++;
  197. println("currentAST.child = "+tInfo.refRuleRoot+".getFirstChild();");
  198. tabs--;
  199. println("else");
  200. tabs++;
  201. println("currentAST.child = "+tInfo.refRuleRoot+";");
  202. tabs--;
  203. println("currentAST.advanceChildToEnd();");
  204. }
  205. if ( grammar.hasSyntacticPredicate ) {
  206. tabs--;
  207. println("}");
  208. }
  209. }
  210. }
  211. /** Generate code for the given grammar element.
  212. * @param blk The "x|y|z|..." block to generate
  213. */
  214. public void gen(AlternativeBlock blk) {
  215. if ( DEBUG_CODE_GENERATOR ) System.out.println("gen("+blk+")");
  216. println("{");
  217. tabs++;
  218. genBlockPreamble(blk);
  219. genBlockInitAction(blk);
  220. // Tell AST generation to build subrule result
  221. String saveCurrentASTResult = currentASTResult;
  222. if (blk.getLabel() != null) {
  223. currentASTResult = blk.getLabel();
  224. }
  225. boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
  226. CSharpBlockFinishingInfo howToFinish = genCommonBlock(blk, true);
  227. genBlockFinish(howToFinish, throwNoViable);
  228. tabs--;
  229. println("}");
  230. // Restore previous AST generation
  231. currentASTResult = saveCurrentASTResult;
  232. }
  233. /** Generate code for the given grammar element.
  234. * @param blk The block-end element to generate. Block-end
  235. * elements are synthesized by the grammar parser to represent
  236. * the end of a block.
  237. */
  238. public void gen(BlockEndElement end) {
  239. if ( DEBUG_CODE_GENERATOR ) System.out.println("genRuleEnd("+end+")");
  240. }
  241. /** Generate code for the given grammar element.
  242. * @param blk The character literal reference to generate
  243. */
  244. public void gen(CharLiteralElement atom) {
  245. if ( DEBUG_CODE_GENERATOR ) System.out.println("genChar("+atom+")");
  246. if ( atom.getLabel()!=null ) {
  247. println(atom.getLabel() + " = " + lt1Value + ";");
  248. }
  249. boolean oldsaveText = saveText;
  250. saveText = saveText && atom.getAutoGenType()==GrammarElement.AUTO_GEN_NONE;
  251. genMatch(atom);
  252. saveText = oldsaveText;
  253. }
  254. /** Generate code for the given grammar element.
  255. * @param blk The character-range reference to generate
  256. */
  257. public void gen(CharRangeElement r) {
  258. if ( r.getLabel()!=null && syntacticPredLevel == 0) {
  259. println(r.getLabel() + " = " + lt1Value + ";");
  260. }
  261. boolean flag = ( grammar instanceof LexerGrammar &&
  262. (!saveText || (r.getAutoGenType() == GrammarElement.AUTO_GEN_BANG)) );
  263. if (flag)
  264. println("_saveIndex = text.Length;");
  265. println("matchRange("+OctalToUnicode(r.beginText)+","+OctalToUnicode(r.endText)+");");
  266. if (flag)
  267. println("text.Length = _saveIndex;");
  268. }
  269. /** Generate the lexer CSharp file */
  270. public void gen(LexerGrammar g) throws IOException {
  271. // If debugging, create a new sempred vector for this grammar
  272. if (g.debuggingOutput)
  273. semPreds = new Vector();
  274. setGrammar(g);
  275. if (!(grammar instanceof LexerGrammar)) {
  276. antlrTool.panic("Internal error generating lexer");
  277. }
  278. genBody(g);
  279. }
  280. /** Generate code for the given grammar element.
  281. * @param blk The (...)+ block to generate
  282. */
  283. public void gen(OneOrMoreBlock blk) {
  284. if ( DEBUG_CODE_GENERATOR ) System.out.println("gen+("+blk+")");
  285. String label;
  286. String cnt;
  287. println("{ // ( ... )+");
  288. tabs++;
  289. blockNestingLevel++;
  290. genBlockPreamble(blk);
  291. if ( blk.getLabel() != null ) {
  292. cnt = "_cnt_"+blk.getLabel();
  293. }
  294. else {
  295. cnt = "_cnt" + blk.ID;
  296. }
  297. println("int "+cnt+"=0;");
  298. if ( blk.getLabel() != null ) {
  299. label = blk.getLabel();
  300. }
  301. else {
  302. label = "_loop" + blk.ID;
  303. }
  304. println("for (;;)");
  305. println("{");
  306. tabs++;
  307. blockNestingLevel++;
  308. // generate the init action for ()+ ()* inside the loop
  309. // this allows us to do usefull EOF checking...
  310. genBlockInitAction(blk);
  311. // Tell AST generation to build subrule result
  312. String saveCurrentASTResult = currentASTResult;
  313. if (blk.getLabel() != null) {
  314. currentASTResult = blk.getLabel();
  315. }
  316. boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
  317. // generate exit test if greedy set to false
  318. // and an alt is ambiguous with exit branch
  319. // or when lookahead derived purely from end-of-file
  320. // Lookahead analysis stops when end-of-file is hit,
  321. // returning set {epsilon}. Since {epsilon} is not
  322. // ambig with any real tokens, no error is reported
  323. // by deterministic() routines and we have to check
  324. // for the case where the lookahead depth didn't get
  325. // set to NONDETERMINISTIC (this only happens when the
  326. // FOLLOW contains real atoms + epsilon).
  327. boolean generateNonGreedyExitPath = false;
  328. int nonGreedyExitDepth = grammar.maxk;
  329. if ( !blk.greedy &&
  330. blk.exitLookaheadDepth<=grammar.maxk &&
  331. blk.exitCache[blk.exitLookaheadDepth].containsEpsilon() )
  332. {
  333. generateNonGreedyExitPath = true;
  334. nonGreedyExitDepth = blk.exitLookaheadDepth;
  335. }
  336. else if ( !blk.greedy &&
  337. blk.exitLookaheadDepth==LLkGrammarAnalyzer.NONDETERMINISTIC )
  338. {
  339. generateNonGreedyExitPath = true;
  340. }
  341. // generate exit test if greedy set to false
  342. // and an alt is ambiguous with exit branch
  343. if ( generateNonGreedyExitPath ) {
  344. if ( DEBUG_CODE_GENERATOR ) {
  345. System.out.println("nongreedy (...)+ loop; exit depth is "+
  346. blk.exitLookaheadDepth);
  347. }
  348. String predictExit =
  349. getLookaheadTestExpression(blk.exitCache,
  350. nonGreedyExitDepth);
  351. println("// nongreedy exit test");
  352. println("if (("+cnt+" >= 1) && "+predictExit+") goto "+label+"_breakloop;");
  353. }
  354. CSharpBlockFinishingInfo howToFinish = genCommonBlock(blk, false);
  355. genBlockFinish(
  356. howToFinish,
  357. "if ("+cnt+" >= 1) { goto "+label+"_breakloop; } else { " + throwNoViable + "; }"
  358. );
  359. println(cnt+"++;");
  360. tabs--;
  361. if (blockNestingLevel-- == saveIndexCreateLevel)
  362. saveIndexCreateLevel = 0;
  363. println("}");
  364. _print(label + "_breakloop:");
  365. println(";");
  366. tabs--;
  367. if (blockNestingLevel-- == saveIndexCreateLevel)
  368. saveIndexCreateLevel = 0;
  369. println("} // ( ... )+");
  370. // Restore previous AST generation
  371. currentASTResult = saveCurrentASTResult;
  372. }
  373. /** Generate the parser CSharp file */
  374. public void gen(ParserGrammar g) throws IOException {
  375. // if debugging, set up a new vector to keep track of sempred
  376. // strings for this grammar
  377. if (g.debuggingOutput)
  378. semPreds = new Vector();
  379. setGrammar(g);
  380. if (!(grammar instanceof ParserGrammar)) {
  381. antlrTool.panic("Internal error generating parser");
  382. }
  383. genBody(g);
  384. }
  385. /** Generate code for the given grammar element.
  386. * @param blk The rule-reference to generate
  387. */
  388. public void gen(RuleRefElement rr)
  389. {
  390. if ( DEBUG_CODE_GENERATOR ) System.out.println("genRR("+rr+")");
  391. RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
  392. if (rs == null || !rs.isDefined())
  393. {
  394. // Is this redundant???
  395. antlrTool.error("Rule '" + rr.targetRule + "' is not defined", grammar.getFilename(), rr.getLine(), rr.getColumn());
  396. return;
  397. }
  398. if (!(rs instanceof RuleSymbol))
  399. {
  400. // Is this redundant???
  401. antlrTool.error("'" + rr.targetRule + "' does not name a grammar rule", grammar.getFilename(), rr.getLine(), rr.getColumn());
  402. return;
  403. }
  404. genErrorTryForElement(rr);
  405. // AST value for labeled rule refs in tree walker.
  406. // This is not AST construction; it is just the input tree node value.
  407. if ( grammar instanceof TreeWalkerGrammar &&
  408. rr.getLabel() != null &&
  409. syntacticPredLevel == 0 )
  410. {
  411. println(rr.getLabel() + " = _t==ASTNULL ? null : "+lt1Value+";");
  412. }
  413. // if in lexer and ! on rule ref or alt or rule, save buffer index to kill later
  414. if (grammar instanceof LexerGrammar && (!saveText || rr.getAutoGenType() == GrammarElement.AUTO_GEN_BANG))
  415. {
  416. declareSaveIndexVariableIfNeeded();
  417. println("_saveIndex = text.Length;");
  418. }
  419. // Process return value assignment if any
  420. printTabs();
  421. if (rr.idAssign != null)
  422. {
  423. // Warn if the rule has no return type
  424. if (rs.block.returnAction == null)
  425. {
  426. antlrTool.warning("Rule '" + rr.targetRule + "' has no return type", grammar.getFilename(), rr.getLine(), rr.getColumn());
  427. }
  428. _print(rr.idAssign + "=");
  429. } else {
  430. // Warn about return value if any, but not inside syntactic predicate
  431. if ( !(grammar instanceof LexerGrammar) && syntacticPredLevel == 0 && rs.block.returnAction != null)
  432. {
  433. antlrTool.warning("Rule '" + rr.targetRule + "' returns a value", grammar.getFilename(), rr.getLine(), rr.getColumn());
  434. }
  435. }
  436. // Call the rule
  437. GenRuleInvocation(rr);
  438. // if in lexer and ! on element or alt or rule, save buffer index to kill later
  439. if ( grammar instanceof LexerGrammar && (!saveText||rr.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
  440. declareSaveIndexVariableIfNeeded();
  441. println("text.Length = _saveIndex;");
  442. }
  443. // if not in a syntactic predicate
  444. if (syntacticPredLevel == 0)
  445. {
  446. boolean doNoGuessTest = (
  447. grammar.hasSyntacticPredicate &&
  448. (
  449. grammar.buildAST && rr.getLabel() != null ||
  450. (genAST && rr.getAutoGenType() == GrammarElement.AUTO_GEN_NONE)
  451. )
  452. );
  453. if (doNoGuessTest) {
  454. println("if (0 == inputState.guessing)");
  455. println("{");
  456. tabs++;
  457. }
  458. if (grammar.buildAST && rr.getLabel() != null)
  459. {
  460. // always gen variable for rule return on labeled rules
  461. println(rr.getLabel() + "_AST = ("+labeledElementASTType+")returnAST;");
  462. }
  463. if (genAST)
  464. {
  465. switch (rr.getAutoGenType())
  466. {
  467. case GrammarElement.AUTO_GEN_NONE:
  468. if( usingCustomAST )
  469. println("astFactory.addASTChild(currentAST, (AST)returnAST);");
  470. else
  471. println("astFactory.addASTChild(currentAST, returnAST);");
  472. break;
  473. case GrammarElement.AUTO_GEN_CARET:
  474. antlrTool.error("Internal: encountered ^ after rule reference");
  475. break;
  476. default:
  477. break;
  478. }
  479. }
  480. // if a lexer and labeled, Token label defined at rule level, just set it here
  481. if ( grammar instanceof LexerGrammar && rr.getLabel() != null )
  482. {
  483. println(rr.getLabel()+" = returnToken_;");
  484. }
  485. if (doNoGuessTest)
  486. {
  487. tabs--;
  488. println("}");
  489. }
  490. }
  491. genErrorCatchForElement(rr);
  492. }
  493. /** Generate code for the given grammar element.
  494. * @param blk The string-literal reference to generate
  495. */
  496. public void gen(StringLiteralElement atom) {
  497. if ( DEBUG_CODE_GENERATOR ) System.out.println("genString("+atom+")");
  498. // Variable declarations for labeled elements
  499. if (atom.getLabel()!=null && syntacticPredLevel == 0) {
  500. println(atom.getLabel() + " = " + lt1Value + ";");
  501. }
  502. // AST
  503. genElementAST(atom);
  504. // is there a bang on the literal?
  505. boolean oldsaveText = saveText;
  506. saveText = saveText && atom.getAutoGenType()==GrammarElement.AUTO_GEN_NONE;
  507. // matching
  508. genMatch(atom);
  509. saveText = oldsaveText;
  510. // tack on tree cursor motion if doing a tree walker
  511. if (grammar instanceof TreeWalkerGrammar) {
  512. println("_t = _t.getNextSibling();");
  513. }
  514. }
  515. /** Generate code for the given grammar element.
  516. * @param blk The token-range reference to generate
  517. */
  518. public void gen(TokenRangeElement r) {
  519. genErrorTryForElement(r);
  520. if ( r.getLabel()!=null && syntacticPredLevel == 0) {
  521. println(r.getLabel() + " = " + lt1Value + ";");
  522. }
  523. // AST
  524. genElementAST(r);
  525. // match
  526. println("matchRange("+OctalToUnicode(r.beginText)+","+OctalToUnicode(r.endText)+");");
  527. genErrorCatchForElement(r);
  528. }
  529. /** Generate code for the given grammar element.
  530. * @param blk The token-reference to generate
  531. */
  532. public void gen(TokenRefElement atom) {
  533. if ( DEBUG_CODE_GENERATOR ) System.out.println("genTokenRef("+atom+")");
  534. if ( grammar instanceof LexerGrammar ) {
  535. antlrTool.panic("Token reference found in lexer");
  536. }
  537. genErrorTryForElement(atom);
  538. // Assign Token value to token label variable
  539. if ( atom.getLabel()!=null && syntacticPredLevel == 0) {
  540. println(atom.getLabel() + " = " + lt1Value + ";");
  541. }
  542. // AST
  543. genElementAST(atom);
  544. // matching
  545. genMatch(atom);
  546. genErrorCatchForElement(atom);
  547. // tack on tree cursor motion if doing a tree walker
  548. if (grammar instanceof TreeWalkerGrammar) {
  549. println("_t = _t.getNextSibling();");
  550. }
  551. }
  552. public void gen(TreeElement t) {
  553. // save AST cursor
  554. println("AST __t" + t.ID + " = _t;");
  555. // If there is a label on the root, then assign that to the variable
  556. if (t.root.getLabel() != null) {
  557. println(t.root.getLabel() + " = (ASTNULL == _t) ? null : ("+labeledElementASTType +")_t;");
  558. }
  559. // check for invalid modifiers ! and ^ on tree element roots
  560. if ( t.root.getAutoGenType() == GrammarElement.AUTO_GEN_BANG ) {
  561. antlrTool.error("Suffixing a root node with '!' is not implemented",
  562. grammar.getFilename(), t.getLine(), t.getColumn());
  563. t.root.setAutoGenType(GrammarElement.AUTO_GEN_NONE);
  564. }
  565. if ( t.root.getAutoGenType() == GrammarElement.AUTO_GEN_CARET ) {
  566. antlrTool.warning("Suffixing a root node with '^' is redundant; already a root",
  567. grammar.getFilename(), t.getLine(), t.getColumn());
  568. t.root.setAutoGenType(GrammarElement.AUTO_GEN_NONE);
  569. }
  570. // Generate AST variables
  571. genElementAST(t.root);
  572. if (grammar.buildAST) {
  573. // Save the AST construction state
  574. println("ASTPair __currentAST" + t.ID + " = currentAST.copy();");
  575. // Make the next item added a child of the TreeElement root
  576. println("currentAST.root = currentAST.child;");
  577. println("currentAST.child = null;");
  578. }
  579. // match root
  580. if ( t.root instanceof WildcardElement ) {
  581. println("if (null == _t) throw new MismatchedTokenException();");
  582. }
  583. else {
  584. genMatch(t.root);
  585. }
  586. // move to list of children
  587. println("_t = _t.getFirstChild();");
  588. // walk list of children, generating code for each
  589. for (int i=0; i<t.getAlternatives().size(); i++) {
  590. Alternative a = t.getAlternativeAt(i);
  591. AlternativeElement e = a.head;
  592. while ( e != null ) {
  593. e.generate();
  594. e = e.next;
  595. }
  596. }
  597. if (grammar.buildAST) {
  598. // restore the AST construction state to that just after the
  599. // tree root was added
  600. println("ASTPair.PutInstance(currentAST);");
  601. println("currentAST = __currentAST" + t.ID + ";");
  602. }
  603. // restore AST cursor
  604. println("_t = __t" + t.ID + ";");
  605. // move cursor to sibling of tree just parsed
  606. println("_t = _t.getNextSibling();");
  607. }
  608. /** Generate the tree-parser CSharp file */
  609. public void gen(TreeWalkerGrammar g) throws IOException {
  610. // SAS: debugging stuff removed for now...
  611. setGrammar(g);
  612. if (!(grammar instanceof TreeWalkerGrammar)) {
  613. antlrTool.panic("Internal error generating tree-walker");
  614. }
  615. genBody(g);
  616. }
  617. /** Generate code for the given grammar element.
  618. * @param wc The wildcard element to generate
  619. */
  620. public void gen(WildcardElement wc) {
  621. // Variable assignment for labeled elements
  622. if (wc.getLabel()!=null && syntacticPredLevel == 0) {
  623. println(wc.getLabel() + " = " + lt1Value + ";");
  624. }
  625. // AST
  626. genElementAST(wc);
  627. // Match anything but EOF
  628. if (grammar instanceof TreeWalkerGrammar) {
  629. println("if (null == _t) throw new MismatchedTokenException();");
  630. }
  631. else if (grammar instanceof LexerGrammar) {
  632. if ( grammar instanceof LexerGrammar &&
  633. (!saveText||wc.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
  634. declareSaveIndexVariableIfNeeded();
  635. println("_saveIndex = text.Length;");
  636. }
  637. println("matchNot(EOF/*_CHAR*/);");
  638. if ( grammar instanceof LexerGrammar &&
  639. (!saveText||wc.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
  640. declareSaveIndexVariableIfNeeded();
  641. println("text.Length = _saveIndex;"); // kill text atom put in buffer
  642. }
  643. }
  644. else {
  645. println("matchNot(" + getValueString(Token.EOF_TYPE) + ");");
  646. }
  647. // tack on tree cursor motion if doing a tree walker
  648. if (grammar instanceof TreeWalkerGrammar) {
  649. println("_t = _t.getNextSibling();");
  650. }
  651. }
  652. /** Generate code for the given grammar element.
  653. * @param blk The (...)* block to generate
  654. */
  655. public void gen(ZeroOrMoreBlock blk) {
  656. if ( DEBUG_CODE_GENERATOR ) System.out.println("gen*("+blk+")");
  657. println("{ // ( ... )*");
  658. tabs++;
  659. blockNestingLevel++;
  660. genBlockPreamble(blk);
  661. String label;
  662. if ( blk.getLabel() != null ) {
  663. label = blk.getLabel();
  664. }
  665. else {
  666. label = "_loop" + blk.ID;
  667. }
  668. println("for (;;)");
  669. println("{");
  670. tabs++;
  671. blockNestingLevel++;
  672. // generate the init action for ()+ ()* inside the loop
  673. // this allows us to do usefull EOF checking...
  674. genBlockInitAction(blk);
  675. // Tell AST generation to build subrule result
  676. String saveCurrentASTResult = currentASTResult;
  677. if (blk.getLabel() != null) {
  678. currentASTResult = blk.getLabel();
  679. }
  680. boolean ok = grammar.theLLkAnalyzer.deterministic(blk);
  681. // generate exit test if greedy set to false
  682. // and an alt is ambiguous with exit branch
  683. // or when lookahead derived purely from end-of-file
  684. // Lookahead analysis stops when end-of-file is hit,
  685. // returning set {epsilon}. Since {epsilon} is not
  686. // ambig with any real tokens, no error is reported
  687. // by deterministic() routines and we have to check
  688. // for the case where the lookahead depth didn't get
  689. // set to NONDETERMINISTIC (this only happens when the
  690. // FOLLOW contains real atoms + epsilon).
  691. boolean generateNonGreedyExitPath = false;
  692. int nonGreedyExitDepth = grammar.maxk;
  693. if ( !blk.greedy &&
  694. blk.exitLookaheadDepth<=grammar.maxk &&
  695. blk.exitCache[blk.exitLookaheadDepth].containsEpsilon() )
  696. {
  697. generateNonGreedyExitPath = true;
  698. nonGreedyExitDepth = blk.exitLookaheadDepth;
  699. }
  700. else if ( !blk.greedy &&
  701. blk.exitLookaheadDepth==LLkGrammarAnalyzer.NONDETERMINISTIC )
  702. {
  703. generateNonGreedyExitPath = true;
  704. }
  705. if ( generateNonGreedyExitPath ) {
  706. if ( DEBUG_CODE_GENERATOR ) {
  707. System.out.println("nongreedy (...)* loop; exit depth is "+
  708. blk.exitLookaheadDepth);
  709. }
  710. String predictExit =
  711. getLookaheadTestExpression(blk.exitCache,
  712. nonGreedyExitDepth);
  713. println("// nongreedy exit test");
  714. println("if ("+predictExit+") goto "+label+"_breakloop;");
  715. }
  716. CSharpBlockFinishingInfo howToFinish = genCommonBlock(blk, false);
  717. genBlockFinish(howToFinish, "goto " + label + "_breakloop;");
  718. tabs--;
  719. if (blockNestingLevel-- == saveIndexCreateLevel)
  720. saveIndexCreateLevel = 0;
  721. println("}");
  722. _print(label+"_breakloop:");
  723. println(";");
  724. tabs--;
  725. if (blockNestingLevel-- == saveIndexCreateLevel)
  726. saveIndexCreateLevel = 0;
  727. println("} // ( ... )*");
  728. // Restore previous AST generation
  729. currentASTResult = saveCurrentASTResult;
  730. }
  731. /** Generate an alternative.
  732. * @param alt The alternative to generate
  733. * @param blk The block to which the alternative belongs
  734. */
  735. protected void genAlt(Alternative alt, AlternativeBlock blk)
  736. {
  737. // Save the AST generation state, and set it to that of the alt
  738. boolean savegenAST = genAST;
  739. genAST = genAST && alt.getAutoGen();
  740. boolean oldsaveTest = saveText;
  741. saveText = saveText && alt.getAutoGen();
  742. // Reset the variable name map for the alternative
  743. Hashtable saveMap = treeVariableMap;
  744. treeVariableMap = new Hashtable();
  745. // Generate try block around the alt for error handling
  746. if (alt.exceptionSpec != null) {
  747. println("try // for error handling");
  748. println("{");
  749. tabs++;
  750. }
  751. AlternativeElement elem = alt.head;
  752. while ( !(elem instanceof BlockEndElement) ) {
  753. elem.generate(); // alt can begin with anything. Ask target to gen.
  754. elem = elem.next;
  755. }
  756. if ( genAST)
  757. {
  758. if (blk instanceof RuleBlock)
  759. {
  760. // Set the AST return value for the rule
  761. RuleBlock rblk = (RuleBlock)blk;
  762. if( usingCustomAST )
  763. {
  764. println(rblk.getRuleName() + "_AST = ("+labeledElementASTType+")currentAST.root;");
  765. }
  766. else
  767. {
  768. println(rblk.getRuleName() + "_AST = currentAST.root;");
  769. }
  770. }
  771. else if (blk.getLabel() != null) {
  772. // ### future: also set AST value for labeled subrules.
  773. // println(blk.getLabel() + "_AST = ("+labeledElementASTType+")currentAST.root;");
  774. antlrTool.warning("Labeled subrules not yet supported", grammar.getFilename(), blk.getLine(), blk.getColumn());
  775. }
  776. }
  777. if (alt.exceptionSpec != null)
  778. {
  779. // close try block
  780. tabs--;
  781. println("}");
  782. genErrorHandler(alt.exceptionSpec);
  783. }
  784. genAST = savegenAST;
  785. saveText = oldsaveTest;
  786. treeVariableMap = saveMap;
  787. }
  788. /** Generate all the bitsets to be used in the parser or lexer
  789. * Generate the raw bitset data like "long _tokenSet1_data[] = {...};"
  790. * and the BitSet object declarations like "BitSet _tokenSet1 = new BitSet(_tokenSet1_data);"
  791. * Note that most languages do not support object initialization inside a
  792. * class definition, so other code-generators may have to separate the
  793. * bitset declarations from the initializations (e.g., put the initializations
  794. * in the generated constructor instead).
  795. * @param bitsetList The list of bitsets to generate.
  796. * @param maxVocabulary Ensure that each generated bitset can contain at least this value.
  797. */
  798. protected void genBitsets( Vector bitsetList, int maxVocabulary ) {
  799. println("");
  800. for (int i = 0; i < bitsetList.size(); i++)
  801. {
  802. BitSet p = (BitSet)bitsetList.elementAt(i);
  803. // Ensure that generated BitSet is large enough for vocabulary
  804. p.growToInclude(maxVocabulary);
  805. genBitSet(p, i);
  806. }
  807. }
  808. /** Do something simple like:
  809. * private static final long[] mk_tokenSet_0() {
  810. * long[] data = { -2305839160922996736L, 63L, 16777216L, 0L, 0L, 0L };
  811. * return data;
  812. * }
  813. * public static final BitSet _tokenSet_0 = new BitSet(mk_tokenSet_0());
  814. *
  815. * Or, for large bitsets, optimize init so ranges are collapsed into loops.
  816. * This is most useful for lexers using unicode.
  817. */
  818. private void genBitSet(BitSet p, int id) {
  819. // initialization data
  820. println("private static long[] mk_" + getBitsetName(id) + "()");
  821. println("{");
  822. tabs++;
  823. int n = p.lengthInLongWords();
  824. if ( n<BITSET_OPTIMIZE_INIT_THRESHOLD ) {
  825. println("long[] data = { " + p.toStringOfWords() + "};");
  826. }
  827. else {
  828. // will init manually, allocate space then set values
  829. println("long[] data = new long["+n+"];");
  830. long[] elems = p.toPackedArray();
  831. for (int i = 0; i < elems.length;) {
  832. if ( (i+1)==elems.length || elems[i]!=elems[i+1] ) {
  833. // last number or no run of numbers, just dump assignment
  834. println("data["+i+"]="+elems[i]+"L;");
  835. i++;
  836. }
  837. else
  838. {
  839. // scan to find end of run
  840. int j;
  841. for (j = i + 1; j < elems.length && elems[j]==elems[i]; j++)
  842. {
  843. ;
  844. }
  845. // j-1 is last member of run
  846. println("for (int i = "+i+"; i<="+(j-1)+"; i++) { data[i]="+
  847. elems[i]+"L; }");
  848. i = j;
  849. }
  850. }
  851. }
  852. println("return data;");
  853. tabs--;
  854. println("}");
  855. // BitSet object
  856. println("public static readonly BitSet " + getBitsetName(id) + " = new BitSet(" +
  857. "mk_" + getBitsetName(id) + "()" + ");");
  858. }
  859. /** Given the index of a bitset in the bitset list, generate a unique name.
  860. * Specific code-generators may want to override this
  861. * if the language does not allow '_' or numerals in identifiers.
  862. * @param index The index of the bitset in the bitset list.
  863. */
  864. protected String getBitsetName(int index) {
  865. return "tokenSet_" + index + "_";
  866. }
  867. /** Generate the finish of a block, using a combination of the info
  868. * returned from genCommonBlock() and the action to perform when
  869. * no alts were taken
  870. * @param howToFinish The return of genCommonBlock()
  871. * @param noViableAction What to generate when no alt is taken
  872. */
  873. private void genBlockFinish(CSharpBlockFinishingInfo howToFinish, String noViableAction)
  874. {
  875. if (howToFinish.needAnErrorClause &&
  876. (howToFinish.generatedAnIf || howToFinish.generatedSwitch))
  877. {
  878. if ( howToFinish.generatedAnIf ) {
  879. println("else");
  880. println("{");
  881. }
  882. else {
  883. println("{");
  884. }
  885. tabs++;
  886. println(noViableAction);
  887. tabs--;
  888. println("}");
  889. }
  890. if ( howToFinish.postscript!=null ) {
  891. if (howToFinish.needAnErrorClause && howToFinish.generatedSwitch &&
  892. !howToFinish.generatedAnIf && noViableAction != null)
  893. {
  894. // Check to make sure that noViableAction is only a throw statement
  895. if (noViableAction.indexOf("throw") == 0 || noViableAction.indexOf("goto") == 0) {
  896. // Remove the break statement since it isn't reachable with a throw exception
  897. int endOfBreak = howToFinish.postscript.indexOf("break;") + 6;
  898. String newPostScript = howToFinish.postscript.substring(endOfBreak);
  899. println(newPostScript);
  900. }
  901. else {
  902. println(howToFinish.postscript);
  903. }
  904. }
  905. else {
  906. println(howToFinish.postscript);
  907. }
  908. }
  909. }
  910. /** Generate the init action for a block, which may be a RuleBlock or a
  911. * plain AlternativeBLock.
  912. * @blk The block for which the preamble is to be generated.
  913. */
  914. protected void genBlockInitAction(AlternativeBlock blk)
  915. {
  916. // dump out init action
  917. if (blk.initAction != null) {
  918. printAction(processActionForSpecialSymbols(blk.initAction, blk.getLine(), currentRule, null));
  919. }
  920. }
  921. /** Generate the header for a block, which may be a RuleBlock or a
  922. * plain AlternativeBLock. This generates any variable declarations
  923. * and syntactic-predicate-testing variables.
  924. * @blk The block for which the preamble is to be generated.
  925. */
  926. protected void genBlockPreamble(AlternativeBlock blk) {
  927. // define labels for rule blocks.
  928. if ( blk instanceof RuleBlock ) {
  929. RuleBlock rblk = (RuleBlock)blk;
  930. if ( rblk.labeledElements!=null ) {
  931. for (int i=0; i<rblk.labeledElements.size(); i++) {
  932. AlternativeElement a = (AlternativeElement)rblk.labeledElements.elementAt(i);
  933. //System.out.println("looking at labeled element: "+a);
  934. //Variables for labeled rule refs and
  935. //subrules are different than variables for
  936. //grammar atoms. This test is a little tricky
  937. //because we want to get all rule refs and ebnf,
  938. //but not rule blocks or syntactic predicates
  939. if (
  940. a instanceof RuleRefElement ||
  941. a instanceof AlternativeBlock &&
  942. !(a instanceof RuleBlock) &&
  943. !(a instanceof SynPredBlock)
  944. ) {
  945. if (
  946. !(a instanceof RuleRefElement) &&
  947. ((AlternativeBlock)a).not &&
  948. analyzer.subruleCanBeInverted(((AlternativeBlock)a), grammar instanceof LexerGrammar)
  949. ) {
  950. // Special case for inverted subrules that
  951. // will be inlined. Treat these like
  952. // token or char literal references
  953. println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
  954. if (grammar.buildAST) {
  955. genASTDeclaration(a);
  956. }
  957. }
  958. else {
  959. if (grammar.buildAST) {
  960. // Always gen AST variables for
  961. // labeled elements, even if the
  962. // element itself is marked with !
  963. genASTDeclaration(a);
  964. }
  965. if ( grammar instanceof LexerGrammar ) {
  966. println("IToken "+a.getLabel()+" = null;");
  967. }
  968. if (grammar instanceof TreeWalkerGrammar) {
  969. // always generate rule-ref variables
  970. // for tree walker
  971. println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
  972. }
  973. }
  974. }
  975. else {
  976. // It is a token or literal reference. Generate the
  977. // correct variable type for this grammar
  978. println(labeledElementType + " " + a.getLabel() + " = " + labeledElementInit + ";");
  979. // In addition, generate *_AST variables if building ASTs
  980. if (grammar.buildAST) {
  981. //println(labeledElementASTType+" " + a.getLabel() + "_AST = null;");
  982. if (a instanceof GrammarAtom &&
  983. ((GrammarAtom)a).getASTNodeType()!=null ) {
  984. GrammarAtom ga = (GrammarAtom)a;
  985. genASTDeclaration(a, ga.getASTNodeType());
  986. }
  987. else {
  988. genASTDeclaration(a);
  989. }
  990. }
  991. }
  992. }
  993. }
  994. }
  995. }
  996. public void genBody(LexerGrammar g) throws IOException
  997. {
  998. // SAS: moved output creation to method so a subclass can change
  999. // how the output is generated (for VAJ interface)
  1000. setupOutput(grammar.getClassName());
  1001. genAST = false; // no way to gen trees.
  1002. saveText = true; // save consumed characters.
  1003. tabs=0;
  1004. // Generate header common to all CSharp output files
  1005. genHeader();
  1006. // Do not use printAction because we assume tabs==0
  1007. println(behavior.getHeaderAction(""));
  1008. // Generate the CSharp namespace declaration (if specified)
  1009. if (nameSpace != null)
  1010. nameSpace.emitDeclarations(currentOutput);
  1011. tabs++;
  1012. // Generate header specific to lexer CSharp file
  1013. println("// Generate header specific to lexer CSharp file");
  1014. println("using System;");
  1015. println("using Stream = System.IO.Stream;");
  1016. println("using TextReader = System.IO.TextReader;");
  1017. println("using Hashtable = System.Collections.Hashtable;");
  1018. println("using Comparer = System.Collections.Comparer;");
  1019. if ( !(g.caseSensitiveLiterals) )
  1020. {
  1021. println("using CaseInsensitiveHashCodeProvider = System.Collections.CaseInsensitiveHashCodeProvider;");
  1022. println("using CaseInsensitiveComparer = System.Collections.CaseInsensitiveComparer;");
  1023. }
  1024. println("");
  1025. println("using TokenStreamException = antlr.TokenStreamException;");
  1026. println("using TokenStreamIOException = antlr.TokenStreamIOException;");
  1027. println("using TokenStreamRecognitionException = antlr.TokenStreamRecognitionException;");
  1028. println("using CharStreamException = antlr.CharStreamException;");
  1029. println("using CharStreamIOException = antlr.CharStreamIOException;");
  1030. println("using ANTLRException = antlr.ANTLRException;");
  1031. println("using CharScanner = antlr.CharScanner;");
  1032. println("using InputBuffer = antlr.InputBuffer;");
  1033. println("using ByteBuffer = antlr.ByteBuffer;");
  1034. println("using CharBuffer = antlr.CharBuffer;");
  1035. println("using Token = antlr.Token;");
  1036. println("using IToken = antlr.IToken;");
  1037. println("using CommonToken = antlr.CommonToken;");
  1038. println("using SemanticException = antlr.SemanticException;");
  1039. println("using RecognitionException = antlr.RecognitionException;");
  1040. println("using NoViableAltForCharException = antlr.NoViableAltForCharException;");
  1041. println("using MismatchedCharException = antlr.MismatchedCharException;");
  1042. println("using TokenStream = antlr.TokenStream;");
  1043. println("using LexerSharedInputState = antlr.LexerSharedInputState;");
  1044. println("using BitSet = antlr.collections.impl.BitSet;");
  1045. // Generate user-defined lexer file preamble
  1046. println(grammar.preambleAction.getText());
  1047. // Generate lexer class definition
  1048. String sup=null;
  1049. if ( grammar.superClass!=null ) {
  1050. sup = grammar.superClass;
  1051. }
  1052. else {
  1053. sup = "antlr." + grammar.getSuperClass();
  1054. }
  1055. // print javadoc comment if any
  1056. if ( grammar.comment!=null )
  1057. {
  1058. _println(grammar.comment);
  1059. }
  1060. Token tprefix = (Token)grammar.options.get("classHeaderPrefix");
  1061. if (tprefix == null) {
  1062. print("public ");
  1063. }
  1064. else {
  1065. String p = StringUtils.stripFrontBack(tprefix.getText(), "\"", "\"");
  1066. if (p == null) {
  1067. print("public ");
  1068. }
  1069. else {
  1070. print(p+" ");
  1071. }
  1072. }
  1073. print("class " + grammar.getClassName() + " : "+sup);
  1074. println(", TokenStream");
  1075. Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
  1076. if ( tsuffix != null )
  1077. {
  1078. String suffix = StringUtils.stripFrontBack(tsuffix.getText(),"\"","\"");
  1079. if ( suffix != null )
  1080. {
  1081. print(", "+suffix); // must be an interface name for CSharp
  1082. }
  1083. }
  1084. println(" {");
  1085. tabs++;
  1086. // Generate 'const' definitions for Token IDs
  1087. genTokenDefinitions(grammar.tokenManager);
  1088. // Generate user-defined lexer class members
  1089. print(
  1090. processActionForSpecialSymbols(grammar.classMemberAction.getText(), grammar.classMemberAction.getLine(), currentRule, null)
  1091. );
  1092. //
  1093. // Generate the constructor from InputStream, which in turn
  1094. // calls the ByteBuffer constructor
  1095. //
  1096. println("public " + grammar.getClassName() + "(Stream ins) : this(new ByteBuffer(ins))");
  1097. println("{");
  1098. println("}");
  1099. println("");
  1100. //
  1101. // Generate the constructor from Reader, which in turn
  1102. // calls the CharBuffer constructor
  1103. //
  1104. println("public " + grammar.getClassName() + "(TextReader r) : this(new CharBuffer(r))");
  1105. println("{");
  1106. println("}");
  1107. println("");
  1108. print("public " + grammar.getClassName() + "(InputBuffer ib)");
  1109. // if debugging, wrap the input buffer in a debugger
  1110. if (grammar.debuggingOutput)
  1111. println(" : this(new LexerSharedInputState(new antlr.debug.DebuggingInputBuffer(ib)))");
  1112. else
  1113. println(" : this(new LexerSharedInputState(ib))");
  1114. println("{");
  1115. println("}");
  1116. println("");
  1117. //
  1118. // Generate the constructor from InputBuffer (char or byte)
  1119. //
  1120. println("public " + grammar.getClassName() + "(LexerSharedInputState state) : base(state)");
  1121. println("{");
  1122. tabs++;
  1123. println("initialize();");
  1124. tabs--;
  1125. println("}");
  1126. // Generate the initialize function
  1127. println("private void initialize()");
  1128. println("{");
  1129. tabs++;
  1130. // if debugging, set up array variables and call user-overridable
  1131. // debugging setup method
  1132. if ( grammar.debuggingOutput ) {
  1133. println("ruleNames = _ruleNames;");
  1134. println("semPredNames = _semPredNames;");
  1135. println("setupDebugging();");
  1136. }
  1137. // Generate the setting of various generated options.
  1138. // These need to be before the literals since ANTLRHashString depends on
  1139. // the casesensitive stuff.
  1140. println("caseSensitiveLiterals = " + g.caseSensitiveLiterals + ";");
  1141. println("setCaseSensitive(" + g.caseSensitive + ");");
  1142. // Generate the initialization of a hashtable
  1143. // containing the string literals used in the lexer
  1144. // The literals variable itself is in CharScanner
  1145. if (g.caseSensitiveLiterals)
  1146. println("literals = new Hashtable(100, (float) 0.4, null, Comparer.Default);");
  1147. else
  1148. println("literals = new Hashtable(100, (float) 0.4, CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);");
  1149. Enumeration keys = grammar.tokenManager.getTokenSymbolKeys();
  1150. while ( keys.hasMoreElements() ) {
  1151. String key = (String)keys.nextElement();
  1152. if ( key.charAt(0) != '"' ) {
  1153. continue;
  1154. }
  1155. TokenSymbol sym = grammar.tokenManager.getTokenSymbol(key);
  1156. if ( sym instanceof StringLiteralSymbol ) {
  1157. StringLiteralSymbol s = (StringLiteralSymbol)sym;
  1158. println("literals.Add(" + s.getId() + ", " + s.getTokenType() + ");");
  1159. }
  1160. }
  1161. Enumeration ids;
  1162. tabs--;
  1163. println("}");
  1164. // generate the rule name array for debugging
  1165. if (grammar.debuggingOutput) {
  1166. println("private static readonly string[] _ruleNames = new string[] {");
  1167. ids = grammar.rules.elements();
  1168. int ruleNum=0;
  1169. while ( ids.hasMoreElements() ) {
  1170. GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
  1171. if ( sym instanceof RuleSymbol)
  1172. println(" \""+((RuleSymbol)sym).getId()+"\",");
  1173. }
  1174. println("};");
  1175. }
  1176. // Generate nextToken() rule.
  1177. // nextToken() is a synthetic lexer rule that is the implicit OR of all
  1178. // user-defined lexer rules.
  1179. genNextToken();
  1180. // Generate code for each rule in the lexer
  1181. ids = grammar.rules.elements();
  1182. int ruleNum=0;
  1183. while ( ids.hasMoreElements() ) {
  1184. RuleSymbol sym = (RuleSymbol) ids.nextElement();
  1185. // Don't generate the synthetic rules
  1186. if (!sym.getId().equals("mnextToken")) {
  1187. genRule(sym, false, ruleNum++, grammar.tokenManager);
  1188. }
  1189. exitIfError();
  1190. }
  1191. // Generate the semantic predicate map for debugging
  1192. if (grammar.debuggingOutput)
  1193. genSemPredMap();
  1194. // Generate the bitsets used throughout the lexer
  1195. genBitsets(bitsetsUsed, ((LexerGrammar)grammar).charVocabulary.size());
  1196. println("");
  1197. tabs--;
  1198. println("}");
  1199. tabs--;
  1200. // Generate the CSharp namespace closures (if required)
  1201. if (nameSpace != null)
  1202. nameSpace.emitClosures(currentOutput);
  1203. // Close the lexer output stream
  1204. currentOutput.close();
  1205. currentOutput = null;
  1206. }
  1207. public void genInitFactory( Grammar g ) {
  1208. if( g.buildAST )
  1209. {
  1210. // Generate the method to initialize an ASTFactory when we're
  1211. // building AST's
  1212. println("static public void initializeASTFactory( ASTFactory factory )");
  1213. println("{");
  1214. tabs++;
  1215. println("factory.setMaxNodeType("+g.tokenManager.maxTokenType()+");");
  1216. // Walk the token vocabulary and generate code to register every TokenID->ASTNodeType
  1217. // mapping specified in the tokens {...} section with the ASTFactory.
  1218. Vector v = g.tokenManager.getVocabulary();
  1219. for (int i = 0; i < v.size(); i++) {
  1220. String s = (String)v.elementAt(i);
  1221. if (s != null) {
  1222. TokenSymbol ts = g.tokenManager.getTokenSymbol(s);
  1223. if (ts != null && ts.getASTNodeType() != null) {
  1224. println("factory.setTokenTypeASTNodeType(" + s + ", \"" + ts.getASTNodeType() + "\");");
  1225. }
  1226. }
  1227. }
  1228. tabs--;
  1229. println("}");
  1230. }
  1231. }
  1232. public void genBody(ParserGrammar g) throws IOException
  1233. {
  1234. // Open the output stream for the parser and set the currentOutput
  1235. // SAS: moved file setup so subclass could do it (for VAJ interface)
  1236. setupOutput(grammar.getClassName());
  1237. genAST = grammar.buildAST;
  1238. tabs = 0;
  1239. // Generate the header common to all output files.
  1240. genHeader();
  1241. // Do not use printAction because we assume tabs==0
  1242. println(behavior.getHeaderAction(""));
  1243. // Generate the CSharp namespace declaration (if specified)
  1244. if (nameSpace != null)
  1245. nameSpace.emitDeclarations(currentOutput);
  1246. tabs++;
  1247. // Generate header for the parser
  1248. println("// Generate the header common to all output files.");
  1249. println("using System;");
  1250. println("");
  1251. println("using TokenBuffer = antlr.TokenBuffer;");
  1252. println("using TokenStreamException = antlr.TokenStreamException;");
  1253. println("using TokenStreamIOException = antlr.TokenStreamIOException;");
  1254. println("using ANTLRException = antlr.ANTLRException;");
  1255. String qualifiedClassName = grammar.getSuperClass();
  1256. String[] unqualifiedClassName = split(qualifiedClassName, ".");
  1257. println("using " + unqualifiedClassName[unqualifiedClassName.length-1] + " = antlr." + qualifiedClassName + ";");
  1258. println("using Token = antlr.Token;");
  1259. println("using IToken = antlr.IToken;");
  1260. println("using TokenStream = antlr.TokenStream;");
  1261. println("using RecognitionException = antlr.RecognitionException;");
  1262. println("using NoViableAltException = antlr.NoViableAltException;");
  1263. println("using MismatchedTokenException = antlr.MismatchedTokenException;");
  1264. println("using SemanticException = antlr.SemanticException;");
  1265. println("using ParserSharedInputState = antlr.ParserSharedInputState;");
  1266. println("using BitSet = antlr.collections.impl.BitSet;");
  1267. if ( genAST ) {
  1268. println("using AST = antlr.collections.AST;");
  1269. println("using ASTPair = antlr.ASTPair;");
  1270. println("using ASTFactory = antlr.ASTFactory;");
  1271. println("using ASTArray = antlr.collections.impl.ASTArray;");
  1272. }
  1273. // Output the user-defined parser preamble
  1274. println(grammar.preambleAction.getText());
  1275. // Generate parser class definition
  1276. String sup=null;
  1277. if ( grammar.superClass != null )
  1278. sup = grammar.superClass;
  1279. else
  1280. sup = "antlr." + grammar.getSuperClass();
  1281. // print javadoc comment if any
  1282. if ( grammar.comment!=null ) {
  1283. _println(grammar.comment);
  1284. }
  1285. Token tprefix = (Token)grammar.options.get("classHeaderPrefix");
  1286. if (tprefix == null) {
  1287. print("public ");
  1288. }
  1289. else {
  1290. String p = StringUtils.stripFrontBack(tprefix.getText(), "\"", "\"");
  1291. if (p == null) {
  1292. print("public ");
  1293. }
  1294. else {
  1295. print(p+" ");
  1296. }
  1297. }
  1298. println("class " + grammar.getClassName() + " : "+sup);
  1299. Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
  1300. if ( tsuffix != null ) {
  1301. String suffix = StringUtils.stripFrontBack(tsuffix.getText(),"\"","\"");
  1302. if ( suffix != null )
  1303. print(" , "+suffix); // must be an interface name for CSharp
  1304. }
  1305. println("{");
  1306. tabs++;
  1307. // Generate 'const' definitions for Token IDs
  1308. genTokenDefinitions(grammar.tokenManager);
  1309. // set up an array of all the rule names so the debugger can
  1310. // keep track of them only by number -- less to store in tree...
  1311. if (grammar.debuggingOutput) {
  1312. println("private static readonly string[] _ruleNames = new string[] {");
  1313. tabs++;
  1314. Enumeration ids = grammar.rules.elements();
  1315. int ruleNum=0;
  1316. while ( ids.hasMoreElements() ) {
  1317. GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
  1318. if ( sym instanceof RuleSymbol)
  1319. println(" \""+((RuleSymbol)sym).getId()+"\",");
  1320. }
  1321. tabs--;
  1322. println("};");
  1323. }
  1324. // Generate user-defined parser class members
  1325. print(
  1326. processActionForSpecialSymbols(grammar.classMemberAction.getText(), grammar.classMemberAction.getLine(), currentRule, null)
  1327. );
  1328. // Generate parser class constructor from TokenBuffer
  1329. println("");
  1330. println("protected void initialize()");
  1331. println("{");
  1332. tabs++;
  1333. println("tokenNames = tokenNames_;");
  1334. if( grammar.buildAST )
  1335. println("initializeFactory();");
  1336. // if debugging, set up arrays and call the user-overridable
  1337. // debugging setup method
  1338. if ( grammar.debuggingOutput ) {
  1339. println("ruleNames = _ruleNames;");
  1340. println("semPredNames = _semPredNames;");
  1341. println("setupDebugging(tokenBuf);");
  1342. }
  1343. tabs--;
  1344. println("}");
  1345. println("");
  1346. println("");
  1347. println("protected " + grammar.getClassName() + "(TokenBuffer tokenBuf, int k) : base(tokenBuf, k)");
  1348. println("{");
  1349. tabs++;
  1350. println("initialize();");
  1351. tabs--;
  1352. println("}");
  1353. println("");
  1354. println("public " + grammar.getClassName() + "(TokenBuffer tokenBuf) : this(tokenBuf," + grammar.maxk + ")");
  1355. println("{");
  1356. println("}");
  1357. println("");
  1358. // Generate parser class constructor from TokenStream
  1359. println("protected " + grammar.getClassName()+"(TokenStream lexer, int k) : base(lexer,k)");
  1360. println("{");
  1361. tabs++;
  1362. println("initialize();");
  1363. tabs--;
  1364. println("}");
  1365. println("");
  1366. println("public " + grammar.getClassName()+"(TokenStream lexer) : this(lexer," + grammar.maxk + ")");
  1367. println("{");
  1368. println("}");
  1369. println("");
  1370. println("public " + grammar.getClassName()+"(ParserSharedInputState state) : base(state," + grammar.maxk + ")");
  1371. println("{");
  1372. tabs++;
  1373. println("initialize();");
  1374. tabs--;
  1375. println("}");
  1376. println("");
  1377. astTypes = new java.util.Vector(100);
  1378. // Generate code for each rule in the grammar
  1379. Enumeration ids = grammar.rules.elements();
  1380. int ruleNum=0;
  1381. while ( ids.hasMoreElements() ) {
  1382. GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
  1383. if ( sym instanceof RuleSymbol) {
  1384. RuleSymbol rs = (RuleSymbol)sym;
  1385. genRule(rs, rs.references.size()==0, ruleNum++, grammar.tokenManager);
  1386. }
  1387. exitIfError();
  1388. }
  1389. if ( usingCustomAST )
  1390. {
  1391. // when we are using a custom AST, overload Parser.getAST() to return the
  1392. // custom AST type
  1393. println("public new " + labeledElementASTType + " getAST()");
  1394. println("{");
  1395. tabs++;
  1396. println("return (" + labeledElementASTType + ") returnAST;");
  1397. tabs--;
  1398. println("}");
  1399. println("");
  1400. }
  1401. // Generate the method that initializes the ASTFactory when we're
  1402. // building AST's
  1403. println("private void initializeFactory()");
  1404. println("{");
  1405. tabs++;
  1406. if( grammar.buildAST ) {
  1407. println("if (astFactory == null)");
  1408. println("{");
  1409. tabs++;
  1410. if( usingCustomAST )
  1411. {
  1412. println("astFactory = new ASTFactory(\"" + labeledElementASTType + "\");");
  1413. }
  1414. else
  1415. println("astFactory = new ASTFactory();");
  1416. tabs--;
  1417. println("}");
  1418. println("initializeASTFactory( astFactory );");
  1419. }
  1420. tabs--;
  1421. println("}");
  1422. genInitFactory( g );
  1423. // Generate the token names
  1424. genTokenStrings();
  1425. // Generate the bitsets used throughout the grammar
  1426. genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType());
  1427. // Generate the semantic predicate map for debugging
  1428. if (grammar.debuggingOutput)
  1429. genSemPredMap();
  1430. // Close class definition
  1431. println("");
  1432. tabs--;
  1433. println("}");
  1434. tabs--;
  1435. // Generate the CSharp namespace closures (if required)
  1436. if (nameSpace != null)
  1437. nameSpace.emitClosures(currentOutput);
  1438. // Close the parser output stream
  1439. currentOutput.close();
  1440. currentOutput = null;
  1441. }
  1442. public void genBody(TreeWalkerGrammar g) throws IOException
  1443. {
  1444. // Open the output stream for the parser and set the currentOutput
  1445. // SAS: move file open to method so subclass can override it
  1446. // (mainly for VAJ interface)
  1447. setupOutput(grammar.getClassName());
  1448. genAST = grammar.buildAST;
  1449. tabs = 0;
  1450. // Generate the header common to all output files.
  1451. genHeader();
  1452. // Do not use printAction because we assume tabs==0
  1453. println(behavior.getHeaderAction(""));
  1454. // Generate the CSharp namespace declaration (if specified)
  1455. if (nameSpace != null)
  1456. nameSpace.emitDeclarations(currentOutput);
  1457. tabs++;
  1458. // Generate header specific to the tree-parser CSharp file
  1459. println("// Generate header specific to the tree-parser CSharp file");
  1460. println("using System;");
  1461. println("");
  1462. println("using " + grammar.getSuperClass() + " = antlr." + grammar.getSuperClass() + ";");
  1463. println("using Token = antlr.Token;");
  1464. println("using IToken = antlr.IToken;");
  1465. println("using AST = antlr.collections.AST;");
  1466. println("using RecognitionException = antlr.RecognitionException;");
  1467. println("using ANTLRException = antlr.ANTLRException;");
  1468. println("using NoViableAltException = antlr.NoViableAltException;");
  1469. println("using MismatchedTokenException = antlr.MismatchedTokenException;");
  1470. println("using SemanticException = antlr.SemanticException;");
  1471. println("using BitSet = antlr.collections.impl.BitSet;");
  1472. println("using ASTPair = antlr.ASTPair;");
  1473. println("using ASTFactory = antlr.ASTFactory;");
  1474. println("using ASTArray = antlr.collections.impl.ASTArray;");
  1475. // Output the user-defined parser premamble
  1476. println(grammar.preambleAction.getText());
  1477. // Generate parser class definition
  1478. String sup=null;
  1479. if ( grammar.superClass!=null ) {
  1480. sup = grammar.superClass;
  1481. }
  1482. else {
  1483. sup = "antlr." + grammar.getSuperClass();
  1484. }
  1485. println("");
  1486. // print javadoc comment if any
  1487. if ( grammar.comment!=null ) {
  1488. _println(grammar.comment);
  1489. }
  1490. Token tprefix = (Token)grammar.options.get("classHeaderPrefix");
  1491. if (tprefix == null) {
  1492. print("public ");
  1493. }
  1494. else {
  1495. String p = StringUtils.stripFrontBack(tprefix.getText(), "\"", "\"");
  1496. if (p == null) {
  1497. print("public ");
  1498. }
  1499. else {
  1500. print(p+" ");
  1501. }
  1502. }
  1503. println("class " + grammar.getClassName() + " : "+sup);
  1504. Token tsuffix = (Token)grammar.options.get("classHeaderSuffix");
  1505. if ( tsuffix != null ) {
  1506. String suffix = StringUtils.stripFrontBack(tsuffix.getText(),"\"","\"");
  1507. if ( suffix != null ) {
  1508. print(" , "+suffix); // must be an interface name for CSharp
  1509. }
  1510. }
  1511. println("{");
  1512. tabs++;
  1513. // Generate 'const' definitions for Token IDs
  1514. genTokenDefinitions(grammar.tokenManager);
  1515. // Generate user-defined parser class members
  1516. print(
  1517. processActionForSpecialSymbols(grammar.classMemberAction.getText(), grammar.classMemberAction.getLine(), currentRule, null)
  1518. );
  1519. // Generate default parser class constructor
  1520. println("public " + grammar.getClassName() + "()");
  1521. println("{");
  1522. tabs++;
  1523. println("tokenNames = tokenNames_;");
  1524. tabs--;
  1525. println("}");
  1526. println("");
  1527. astTypes = new java.util.Vector();
  1528. // Generate code for each rule in the grammar
  1529. Enumeration ids = grammar.rules.elements();
  1530. int ruleNum=0;
  1531. String ruleNameInits = "";
  1532. while ( ids.hasMoreElements() ) {
  1533. GrammarSymbol sym = (GrammarSymbol) ids.nextElement();
  1534. if ( sym instanceof RuleSymbol) {
  1535. RuleSymbol rs = (RuleSymbol)sym;
  1536. genRule(rs, rs.references.size()==0, ruleNum++, grammar.tokenManager);
  1537. }
  1538. exitIfError();
  1539. }
  1540. if ( usingCustomAST )
  1541. {
  1542. // when we are using a custom ast override Parser.getAST to return the
  1543. // custom AST type
  1544. println("public new " + labeledElementASTType + " getAST()");
  1545. println("{");
  1546. tabs++;
  1547. println("return (" + labeledElementASTType + ") returnAST;");
  1548. tabs--;
  1549. println("}");
  1550. println("");
  1551. }
  1552. // Generate the ASTFactory initialization function
  1553. genInitFactory( grammar );
  1554. // Generate the token names
  1555. genTokenStrings();
  1556. // Generate the bitsets used throughout the grammar
  1557. genBitsets(bitsetsUsed, grammar.tokenManager.maxTokenType());
  1558. // Close class definition
  1559. tabs--;
  1560. println("}");
  1561. println("");
  1562. tabs--;
  1563. // Generate the CSharp namespace closures (if required)
  1564. if (nameSpace != null)
  1565. nameSpace.emitClosures(currentOutput);
  1566. // Close the parser output stream
  1567. currentOutput.close();
  1568. currentOutput = null;
  1569. }
  1570. /** Generate a series of case statements that implement a BitSet test.
  1571. * @param p The Bitset for which cases are to be generated
  1572. */
  1573. protected void genCases(BitSet p) {
  1574. if ( DEBUG_CODE_GENERATOR ) System.out.println("genCases("+p+")");
  1575. int[] elems;
  1576. elems = p.toArray();
  1577. // Wrap cases four-per-line for lexer, one-per-line for parser
  1578. int wrap = (grammar instanceof LexerGrammar) ? 4 : 1;
  1579. int j=1;
  1580. boolean startOfLine = true;
  1581. for (int i = 0; i < elems.length; i++) {
  1582. if (j==1) {
  1583. print("");
  1584. } else {
  1585. _print(" ");
  1586. }
  1587. _print("case " + getValueString(elems[i]) + ":");
  1588. if (j==wrap) {
  1589. _println("");
  1590. startOfLine = true;
  1591. j=1;
  1592. }
  1593. else {
  1594. j++;
  1595. startOfLine = false;
  1596. }
  1597. }
  1598. if (!startOfLine) {
  1599. _println("");
  1600. }
  1601. }
  1602. /**Generate common code for a block of alternatives; return a
  1603. * postscript that needs to be generated at the end of the
  1604. * block. Other routines may append else-clauses and such for
  1605. * error checking before the postfix is generated. If the
  1606. * grammar is a lexer, then generate alternatives in an order
  1607. * where alternatives requiring deeper lookahead are generated
  1608. * first, and EOF in the lookahead set reduces the depth of
  1609. * the lookahead. @param blk The block to generate @param
  1610. * noTestForSingle If true, then it does not generate a test
  1611. * for a single alternative.
  1612. */
  1613. public CSharpBlockFinishingInfo genCommonBlock(AlternativeBlock blk,
  1614. boolean noTestForSingle)
  1615. {
  1616. int nIF=0;
  1617. boolean createdLL1Switch = false;
  1618. int closingBracesOfIFSequence = 0;
  1619. CSharpBlockFinishingInfo finishingInfo = new CSharpBlockFinishingInfo();
  1620. if ( DEBUG_CODE_GENERATOR ) System.out.println("genCommonBlock("+blk+")");
  1621. // Save the AST generation state, and set it to that of the block
  1622. boolean savegenAST = genAST;
  1623. genAST = genAST && blk.getAutoGen();
  1624. boolean oldsaveTest = saveText;
  1625. saveText = saveText && blk.getAutoGen();
  1626. // Is this block inverted? If so, generate special-case code
  1627. if ( blk.not &&
  1628. analyzer.subruleCanBeInverted(blk, grammar instanceof LexerGrammar) )
  1629. {
  1630. if ( DEBUG_CODE_GENERATOR ) System.out.println("special case: ~(subrule)");
  1631. Lookahead p = analyzer.look(1, blk);
  1632. // Variable assignment for labeled elements
  1633. if (blk.getLabel() != null && syntacticPredLevel == 0) {
  1634. println(blk.getLabel() + " = " + lt1Value + ";");
  1635. }
  1636. // AST
  1637. genElementAST(blk);
  1638. String astArgs="";
  1639. if (grammar instanceof TreeWalkerGrammar) {
  1640. if ( usingCustomAST )
  1641. astArgs = "(AST)_t,";
  1642. else
  1643. astArgs = "_t,";
  1644. }
  1645. // match the bitset for the alternative
  1646. println("match(" + astArgs + getBitsetName(markBitsetForGen(p.fset)) + ");");
  1647. // tack on tree cursor motion if doing a tree walker
  1648. if (grammar instanceof TreeWalkerGrammar)
  1649. {
  1650. println("_t = _t.getNextSibling();");
  1651. }
  1652. return finishingInfo;
  1653. }
  1654. // Special handling for single alt
  1655. if (blk.getAlternatives().size() == 1)
  1656. {
  1657. Alternative alt = blk.getAlternativeAt(0);
  1658. // Generate a warning if there is a synPred for single alt.
  1659. if (alt.synPred != null)
  1660. {
  1661. antlrTool.warning(
  1662. "Syntactic predicate superfluous for single alternative",
  1663. grammar.getFilename(),
  1664. blk.getAlternativeAt(0).synPred.getLine(),
  1665. blk.getAlternativeAt(0).synPred.getColumn()
  1666. );
  1667. }
  1668. if (noTestForSingle)
  1669. {
  1670. if (alt.semPred != null)
  1671. {
  1672. // Generate validating predicate
  1673. genSemPred(alt.semPred, blk.line);
  1674. }
  1675. genAlt(alt, blk);
  1676. return finishingInfo;
  1677. }
  1678. }
  1679. // count number of simple LL(1) cases; only do switch for
  1680. // many LL(1) cases (no preds, no end of token refs)
  1681. // We don't care about exit paths for (...)*, (...)+
  1682. // because we don't explicitly have a test for them
  1683. // as an alt in the loop.
  1684. //
  1685. // Also, we now count how many unicode lookahead sets
  1686. // there are--they must be moved to DEFAULT or ELSE
  1687. // clause.
  1688. int nLL1 = 0;
  1689. for (int i=0; i<blk.getAlternatives().size(); i++)
  1690. {
  1691. Alternative a = blk.getAlternativeAt(i);
  1692. if ( suitableForCaseExpression(a) ) {
  1693. nLL1++;
  1694. }
  1695. }
  1696. // do LL(1) cases
  1697. if ( nLL1 >= makeSwitchThreshold)
  1698. {
  1699. // Determine the name of the item to be compared
  1700. String testExpr = lookaheadString(1);
  1701. createdLL1Switch = true;
  1702. // when parsing trees, convert null to valid tree node with NULL lookahead
  1703. if ( grammar instanceof TreeWalkerGrammar )
  1704. {
  1705. println("if (null == _t)");
  1706. tabs++;
  1707. println("_t = ASTNULL;");
  1708. tabs--;
  1709. }
  1710. println("switch ( " + testExpr+" )");
  1711. println("{");
  1712. //tabs++;
  1713. // update block nesting level as it affects creation of _saveIndex OK?
  1714. blockNestingLevel++;
  1715. for (int i=0; i<blk.alternatives.size(); i++)
  1716. {
  1717. Alternative alt = blk.getAlternativeAt(i);
  1718. // ignore any non-LL(1) alts, predicated alts,
  1719. // or end-of-token alts for case expressions
  1720. if ( !suitableForCaseExpression(alt) )
  1721. {
  1722. continue;
  1723. }
  1724. Lookahead p = alt.cache[1];
  1725. if (p.fset.degree() == 0 && !p.containsEpsilon())
  1726. {
  1727. antlrTool.warning("Alternate omitted due to empty prediction set",
  1728. grammar.getFilename(),
  1729. alt.head.getLine(), alt.head.getColumn());
  1730. }
  1731. else
  1732. {
  1733. genCases(p.fset);
  1734. println("{");
  1735. tabs++;
  1736. blockNestingLevel++;
  1737. genAlt(alt, blk);
  1738. println("break;");
  1739. if (blockNestingLevel-- == saveIndexCreateLevel)
  1740. saveIndexCreateLevel = 0;
  1741. tabs--;
  1742. println("}");
  1743. }
  1744. }
  1745. println("default:");
  1746. tabs++;
  1747. }
  1748. // do non-LL(1) and nondeterministic cases This is tricky in
  1749. // the lexer, because of cases like: STAR : '*' ; ASSIGN_STAR
  1750. // : "*="; Since nextToken is generated without a loop, then
  1751. // the STAR will have end-of-token as it's lookahead set for
  1752. // LA(2). So, we must generate the alternatives containing
  1753. // trailing end-of-token in their lookahead sets *after* the
  1754. // alternatives without end-of-token. This implements the
  1755. // usual lexer convention that longer matches come before
  1756. // shorter ones, e.g. "*=" matches ASSIGN_STAR not STAR
  1757. //
  1758. // For non-lexer grammars, this does not sort the alternates
  1759. // by depth Note that alts whose lookahead is purely
  1760. // end-of-token at k=1 end up as default or else clauses.
  1761. int startDepth = (grammar instanceof LexerGrammar) ? grammar.maxk : 0;
  1762. for (int altDepth = startDepth; altDepth >= 0; altDepth--) {
  1763. if ( DEBUG_CODE_GENERATOR ) System.out.println("checking depth "+altDepth);
  1764. for (int i=0; i<blk.alternatives.size(); i++) {
  1765. Alternative alt = blk.getAlternativeAt(i);
  1766. if ( DEBUG_CODE_GENERATOR ) System.out.println("genAlt: "+i);
  1767. // if we made a switch above, ignore what we already took care
  1768. // of. Specifically, LL(1) alts with no preds
  1769. // that do not have end-of-token in their prediction set
  1770. // and that are not giant unicode sets.
  1771. if ( createdLL1Switch && suitableForCaseExpression(alt) )
  1772. {
  1773. if ( DEBUG_CODE_GENERATOR ) System.out.println("ignoring alt because it was in the switch");
  1774. continue;
  1775. }
  1776. String e;
  1777. boolean unpredicted = false;
  1778. if (grammar instanceof LexerGrammar) {
  1779. // Calculate the "effective depth" of the alt,
  1780. // which is the max depth at which
  1781. // cache[depth]!=end-of-token
  1782. int effectiveDepth = alt.lookaheadDepth;
  1783. if (effectiveDepth == GrammarAnalyzer.NONDETERMINISTIC)
  1784. {
  1785. // use maximum lookahead
  1786. effectiveDepth = grammar.maxk;
  1787. }
  1788. while ( effectiveDepth >= 1 &&
  1789. alt.cache[effectiveDepth].containsEpsilon() )
  1790. {
  1791. effectiveDepth--;
  1792. }
  1793. // Ignore alts whose effective depth is other than
  1794. // the ones we are generating for this iteration.
  1795. if (effectiveDepth != altDepth)
  1796. {
  1797. if ( DEBUG_CODE_GENERATOR )
  1798. System.out.println("ignoring alt because effectiveDepth!=altDepth;"+effectiveDepth+"!="+altDepth);
  1799. continue;
  1800. }
  1801. unpredicted = lookaheadIsEmpty(alt, effectiveDepth);
  1802. e = getLookaheadTestExpression(alt, effectiveDepth);
  1803. }
  1804. else
  1805. {
  1806. unpredicted = lookaheadIsEmpty(alt, grammar.maxk);
  1807. e = getLookaheadTestExpression(alt, grammar.maxk);
  1808. }
  1809. // Was it a big unicode range that forced unsuitability
  1810. // for a case expression?
  1811. if (alt.cache[1].fset.degree() > caseSizeThreshold &&
  1812. suitableForCaseExpression(alt))
  1813. {
  1814. if ( nIF==0 )
  1815. {
  1816. println("if " + e);
  1817. println("{");
  1818. }
  1819. else {
  1820. println("else if " + e);
  1821. println("{");
  1822. }
  1823. }
  1824. else if (unpredicted &&
  1825. alt.semPred==null &&
  1826. alt.synPred==null)
  1827. {
  1828. // The alt has empty prediction set and no
  1829. // predicate to help out. if we have not
  1830. // generated a previous if, just put {...} around
  1831. // the end-of-token clause
  1832. if ( nIF==0 ) {
  1833. println("{");
  1834. }
  1835. else {
  1836. println("else {");
  1837. }
  1838. finishingInfo.needAnErrorClause = false;
  1839. }
  1840. else
  1841. {
  1842. // check for sem and syn preds
  1843. // Add any semantic predicate expression to the lookahead test
  1844. if ( alt.semPred != null ) {
  1845. // if debugging, wrap the evaluation of the predicate in a method
  1846. //
  1847. // translate $ and # references
  1848. ActionTransInfo tInfo = new ActionTransInfo();
  1849. String actionStr = processActionForSpecialSymbols(alt.semPred,
  1850. blk.line,
  1851. currentRule,
  1852. tInfo);
  1853. // ignore translation info...we don't need to
  1854. // do anything with it. call that will inform
  1855. // SemanticPredicateListeners of the result
  1856. if (((grammar instanceof ParserGrammar) || (grammar instanceof LexerGrammar)) &&
  1857. grammar.debuggingOutput) {
  1858. e = "("+e+"&& fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEventArgs.PREDICTING,"+ //FIXME
  1859. addSemPred(charFormatter.escapeString(actionStr))+","+actionStr+"))";
  1860. }
  1861. else {
  1862. e = "("+e+"&&("+actionStr +"))";
  1863. }
  1864. }
  1865. // Generate any syntactic predicates
  1866. if ( nIF>0 ) {
  1867. if ( alt.synPred != null ) {
  1868. println("else {");
  1869. tabs++;
  1870. blockNestingLevel++;
  1871. genSynPred( alt.synPred, e );
  1872. closingBracesOfIFSequence++;
  1873. }
  1874. else {
  1875. println("else if " + e + " {");
  1876. }
  1877. }
  1878. else {
  1879. if ( alt.synPred != null ) {
  1880. genSynPred( alt.synPred, e );
  1881. }
  1882. else {
  1883. // when parsing trees, convert null to valid tree node
  1884. // with NULL lookahead.
  1885. if ( grammar instanceof TreeWalkerGrammar ) {
  1886. println("if (_t == null)");
  1887. tabs++;
  1888. println("_t = ASTNULL;");
  1889. tabs--;
  1890. }
  1891. println("if " + e);
  1892. println("{");
  1893. }
  1894. }
  1895. }
  1896. blockNestingLevel++;
  1897. nIF++;
  1898. tabs++;
  1899. genAlt(alt, blk);
  1900. tabs--;
  1901. if (blockNestingLevel-- == saveIndexCreateLevel)
  1902. saveIndexCreateLevel = 0;
  1903. println("}");
  1904. }
  1905. }
  1906. String ps = "";
  1907. for (int i=1; i<=closingBracesOfIFSequence; i++) {
  1908. ps+="}";
  1909. if (blockNestingLevel-- == saveIndexCreateLevel)
  1910. saveIndexCreateLevel = 0;
  1911. }
  1912. // Restore the AST generation state
  1913. genAST = savegenAST;
  1914. // restore save text state
  1915. saveText=oldsaveTest;
  1916. // Return the finishing info.
  1917. if ( createdLL1Switch ) {
  1918. tabs--;
  1919. finishingInfo.postscript = ps+"break; }";
  1920. if (blockNestingLevel-- == saveIndexCreateLevel)
  1921. saveIndexCreateLevel = 0;
  1922. finishingInfo.generatedSwitch = true;
  1923. finishingInfo.generatedAnIf = nIF>0;
  1924. //return new CSharpBlockFinishingInfo(ps+"}",true,nIF>0); // close up switch statement
  1925. }
  1926. else {
  1927. finishingInfo.postscript = ps;
  1928. finishingInfo.generatedSwitch = false;
  1929. finishingInfo.generatedAnIf = nIF>0;
  1930. // return new CSharpBlockFinishingInfo(ps, false,nIF>0);
  1931. }
  1932. return finishingInfo;
  1933. }
  1934. private static boolean suitableForCaseExpression(Alternative a) {
  1935. return a.lookaheadDepth == 1 &&
  1936. a.semPred == null &&
  1937. !a.cache[1].containsEpsilon() &&
  1938. a.cache[1].fset.degree()<=caseSizeThreshold;
  1939. }
  1940. /** Generate code to link an element reference into the AST */
  1941. private void genElementAST(AlternativeElement el) {
  1942. // handle case where you're not building trees, but are in tree walker.
  1943. // Just need to get labels set up.
  1944. if ( grammar instanceof TreeWalkerGrammar && !grammar.buildAST )
  1945. {
  1946. String elementRef;
  1947. String astName;
  1948. // Generate names and declarations of the AST variable(s)
  1949. if (el.getLabel() == null)
  1950. {
  1951. elementRef = lt1Value;
  1952. // Generate AST variables for unlabeled stuff
  1953. astName = "tmp" + astVarNumber + "_AST";
  1954. astVarNumber++;
  1955. // Map the generated AST variable in the alternate
  1956. mapTreeVariable(el, astName);
  1957. // Generate an "input" AST variable also
  1958. println(labeledElementASTType+" "+astName+"_in = "+elementRef+";");
  1959. }
  1960. return;
  1961. }
  1962. if (grammar.buildAST && syntacticPredLevel == 0)
  1963. {
  1964. boolean needASTDecl =
  1965. (genAST &&
  1966. (el.getLabel() != null || (el.getAutoGenType() != GrammarElement.AUTO_GEN_BANG)));
  1967. // RK: if we have a grammar element always generate the decl
  1968. // since some guy can access it from an action and we can't
  1969. // peek ahead (well not without making a mess).
  1970. // I'd prefer taking this out.
  1971. if (el.getAutoGenType() != GrammarElement.AUTO_GEN_BANG &&
  1972. (el instanceof TokenRefElement))
  1973. needASTDecl = true;
  1974. boolean doNoGuessTest = (grammar.hasSyntacticPredicate && needASTDecl);
  1975. String elementRef;
  1976. String astNameBase;
  1977. // Generate names and declarations of the AST variable(s)
  1978. if (el.getLabel() != null)
  1979. {
  1980. // if the element is labeled use that name...
  1981. elementRef = el.getLabel();
  1982. astNameBase = el.getLabel();
  1983. }
  1984. else
  1985. {
  1986. // else generate a temporary name...
  1987. elementRef = lt1Value;
  1988. // Generate AST variables for unlabeled stuff
  1989. astNameBase = "tmp" + astVarNumber;
  1990. astVarNumber++;
  1991. }
  1992. // Generate the declaration if required.
  1993. if (needASTDecl)
  1994. {
  1995. // Generate the declaration
  1996. if ( el instanceof GrammarAtom )
  1997. {
  1998. GrammarAtom ga = (GrammarAtom)el;
  1999. if ( ga.getASTNodeType()!=null )
  2000. {
  2001. genASTDeclaration(el, astNameBase, ga.getASTNodeType());
  2002. //println(ga.getASTNodeType()+" " + astName+" = null;");
  2003. }
  2004. else
  2005. {
  2006. genASTDeclaration(el, astNameBase, labeledElementASTType);
  2007. //println(labeledElementASTType+" " + astName + " = null;");
  2008. }
  2009. }
  2010. else
  2011. {
  2012. genASTDeclaration(el, astNameBase, labeledElementASTType);
  2013. //println(labeledElementASTType+" " + astName + " = null;");
  2014. }
  2015. }
  2016. // for convenience..
  2017. String astName = astNameBase + "_AST";
  2018. // Map the generated AST variable in the alternate
  2019. mapTreeVariable(el, astName);
  2020. if (grammar instanceof TreeWalkerGrammar)
  2021. {
  2022. // Generate an "input" AST variable also
  2023. println(labeledElementASTType+" " + astName + "_in = null;");
  2024. }
  2025. // Enclose actions with !guessing
  2026. if (doNoGuessTest) {
  2027. //println("if (0 == inputState.guessing)");
  2028. //println("{");
  2029. //tabs++;
  2030. }
  2031. // if something has a label assume it will be used
  2032. // so we must initialize the RefAST
  2033. if (el.getLabel() != null)
  2034. {
  2035. if ( el instanceof GrammarAtom )
  2036. {
  2037. println(astName + " = "+ getASTCreateString((GrammarAtom)el, elementRef) + ";");
  2038. }
  2039. else
  2040. {
  2041. println(astName + " = "+ getASTCreateString(elementRef) + ";");
  2042. }
  2043. }
  2044. // if it has no label but a declaration exists initialize it.
  2045. if (el.getLabel() == null && needASTDecl)
  2046. {
  2047. elementRef = lt1Value;
  2048. if ( el instanceof GrammarAtom )
  2049. {
  2050. println(astName + " = "+ getASTCreateString((GrammarAtom)el, elementRef) + ";");
  2051. }
  2052. else
  2053. {
  2054. println(astName + " = "+ getASTCreateString(elementRef) + ";");
  2055. }
  2056. // Map the generated AST variable in the alternate
  2057. if (grammar instanceof TreeWalkerGrammar)
  2058. {
  2059. // set "input" AST variable also
  2060. println(astName + "_in = " + elementRef + ";");
  2061. }
  2062. }
  2063. if (genAST)
  2064. {
  2065. switch (el.getAutoGenType())
  2066. {
  2067. case GrammarElement.AUTO_GEN_NONE:
  2068. if ( usingCustomAST ||
  2069. ( (el instanceof GrammarAtom) &&
  2070. (((GrammarAtom)el).getASTNodeType() != null) ) )
  2071. println("astFactory.addASTChild(currentAST, (AST)" + astName + ");");
  2072. else
  2073. println("astFactory.addASTChild(currentAST, " + astName + ");");
  2074. break;
  2075. case GrammarElement.AUTO_GEN_CARET:
  2076. if ( usingCustomAST ||
  2077. ( (el instanceof GrammarAtom) &&
  2078. (((GrammarAtom)el).getASTNodeType() != null) ) )
  2079. println("astFactory.makeASTRoot(currentAST, (AST)" + astName + ");");
  2080. else
  2081. println("astFactory.makeASTRoot(currentAST, " + astName + ");");
  2082. break;
  2083. default:
  2084. break;
  2085. }
  2086. }
  2087. if (doNoGuessTest)
  2088. {
  2089. //tabs--;
  2090. //println("}");
  2091. }
  2092. }
  2093. }
  2094. /** Close the try block and generate catch phrases
  2095. * if the element has a labeled handler in the rule
  2096. */
  2097. private void genErrorCatchForElement(AlternativeElement el) {
  2098. if (el.getLabel() == null) return;
  2099. String r = el.enclosingRuleName;
  2100. if ( grammar instanceof LexerGrammar ) {
  2101. r = CodeGenerator.encodeLexerRuleName(el.enclosingRuleName);
  2102. }
  2103. RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r);
  2104. if (rs == null) {
  2105. antlrTool.panic("Enclosing rule not found!");
  2106. }
  2107. ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
  2108. if (ex != null) {
  2109. tabs--;
  2110. println("}");
  2111. genErrorHandler(ex);
  2112. }
  2113. }
  2114. /** Generate the catch phrases for a user-specified error handler */
  2115. private void genErrorHandler(ExceptionSpec ex)
  2116. {
  2117. // Each ExceptionHandler in the ExceptionSpec is a separate catch
  2118. for (int i = 0; i < ex.handlers.size(); i++)
  2119. {
  2120. ExceptionHandler handler = (ExceptionHandler)ex.handlers.elementAt(i);
  2121. // Generate catch phrase
  2122. println("catch (" + handler.exceptionTypeAndName.getText() + ")");
  2123. println("{");
  2124. tabs++;
  2125. if (grammar.hasSyntacticPredicate) {
  2126. println("if (0 == inputState.guessing)");
  2127. println("{");
  2128. tabs++;
  2129. }
  2130. // When not guessing, execute user handler action
  2131. ActionTransInfo tInfo = new ActionTransInfo();
  2132. printAction(processActionForSpecialSymbols(handler.action.getText(),
  2133. handler.action.getLine(), currentRule, tInfo));
  2134. if (grammar.hasSyntacticPredicate)
  2135. {
  2136. tabs--;
  2137. println("}");
  2138. println("else");
  2139. println("{");
  2140. tabs++;
  2141. // When guessing, rethrow exception
  2142. //println("throw " + extractIdOfAction(handler.exceptionTypeAndName) + ";");
  2143. println("throw;");
  2144. tabs--;
  2145. println("}");
  2146. }
  2147. // Close catch phrase
  2148. tabs--;
  2149. println("}");
  2150. }
  2151. }
  2152. /** Generate a try { opening if the element has a labeled handler in the rule */
  2153. private void genErrorTryForElement(AlternativeElement el) {
  2154. if (el.getLabel() == null) return;
  2155. String r = el.enclosingRuleName;
  2156. if ( grammar instanceof LexerGrammar ) {
  2157. r = CodeGenerator.encodeLexerRuleName(el.enclosingRuleName);
  2158. }
  2159. RuleSymbol rs = (RuleSymbol)grammar.getSymbol(r);
  2160. if (rs == null) {
  2161. antlrTool.panic("Enclosing rule not found!");
  2162. }
  2163. ExceptionSpec ex = rs.block.findExceptionSpec(el.getLabel());
  2164. if (ex != null) {
  2165. println("try // for error handling");
  2166. println("{");
  2167. tabs++;
  2168. }
  2169. }
  2170. protected void genASTDeclaration(AlternativeElement el)
  2171. {
  2172. genASTDeclaration(el, labeledElementASTType);
  2173. }
  2174. protected void genASTDeclaration(AlternativeElement el, String node_type)
  2175. {
  2176. genASTDeclaration(el, el.getLabel(), node_type);
  2177. }
  2178. protected void genASTDeclaration(AlternativeElement el, String var_name, String node_type)
  2179. {
  2180. // already declared?
  2181. if (declaredASTVariables.contains(el))
  2182. return;
  2183. // emit code
  2184. //String s = StringUtils.stripFrontBack(node_type, "\"", "\"");
  2185. //println(s + " " + var_name + "_AST = null;");
  2186. println(node_type + " " + var_name + "_AST = null;");
  2187. // mark as declared
  2188. declaredASTVariables.put(el,el);
  2189. }
  2190. /** Generate a header that is common to all CSharp files */
  2191. protected void genHeader()
  2192. {
  2193. println("// $ANTLR "+Tool.version+": "+
  2194. "\"" + antlrTool.fileMinusPath(antlrTool.grammarFile) + "\"" +
  2195. " -> "+
  2196. "\""+grammar.getClassName()+".cs\"$");
  2197. }
  2198. private void genLiteralsTest() {
  2199. println("_ttype = testLiteralsTable(_ttype);");
  2200. }
  2201. private void genLiteralsTestForPartialToken() {
  2202. println("_ttype = testLiteralsTable(text.ToString(_begin, text.Length-_begin), _ttype);");
  2203. }
  2204. protected void genMatch(BitSet b) {
  2205. }
  2206. protected void genMatch(GrammarAtom atom) {
  2207. if ( atom instanceof StringLiteralElement ) {
  2208. if ( grammar instanceof LexerGrammar ) {
  2209. genMatchUsingAtomText(atom);
  2210. }
  2211. else {
  2212. genMatchUsingAtomTokenType(atom);
  2213. }
  2214. }
  2215. else if ( atom instanceof CharLiteralElement ) {
  2216. if ( grammar instanceof LexerGrammar ) {
  2217. genMatchUsingAtomText(atom);
  2218. }
  2219. else {
  2220. antlrTool.error("cannot ref character literals in grammar: "+atom);
  2221. }
  2222. }
  2223. else if ( atom instanceof TokenRefElement ) {
  2224. genMatchUsingAtomText(atom);
  2225. } else if (atom instanceof WildcardElement) {
  2226. gen((WildcardElement)atom);
  2227. }
  2228. }
  2229. protected void genMatchUsingAtomText(GrammarAtom atom) {
  2230. // match() for trees needs the _t cursor
  2231. String astArgs="";
  2232. if (grammar instanceof TreeWalkerGrammar) {
  2233. if ( usingCustomAST )
  2234. astArgs="(AST)_t,";
  2235. else
  2236. astArgs="_t,";
  2237. }
  2238. // if in lexer and ! on element, save buffer index to kill later
  2239. if ( grammar instanceof LexerGrammar && (!saveText||atom.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
  2240. declareSaveIndexVariableIfNeeded();
  2241. println("_saveIndex = text.Length;");
  2242. }
  2243. print(atom.not ? "matchNot(" : "match(");
  2244. _print(astArgs);
  2245. // print out what to match
  2246. if (atom.atomText.equals("EOF")) {
  2247. // horrible hack to handle EOF case
  2248. _print("Token.EOF_TYPE");
  2249. }
  2250. else {
  2251. _print(atom.atomText);
  2252. }
  2253. _println(");");
  2254. if ( grammar instanceof LexerGrammar && (!saveText||atom.getAutoGenType()==GrammarElement.AUTO_GEN_BANG) ) {
  2255. declareSaveIndexVariableIfNeeded();
  2256. println("text.Length = _saveIndex;"); // kill text atom put in buffer
  2257. }
  2258. }
  2259. protected void genMatchUsingAtomTokenType(GrammarAtom atom) {
  2260. // match() for trees needs the _t cursor
  2261. String astArgs="";
  2262. if (grammar instanceof TreeWalkerGrammar) {
  2263. if( usingCustomAST )
  2264. astArgs="(AST)_t,";
  2265. else
  2266. astArgs="_t,";
  2267. }
  2268. // If the literal can be mangled, generate the symbolic constant instead
  2269. String mangledName = null;
  2270. String s = astArgs + getValueString(atom.getType());
  2271. // matching
  2272. println( (atom.not ? "matchNot(" : "match(") + s + ");");
  2273. }
  2274. /** Generate the nextToken() rule. nextToken() is a synthetic
  2275. * lexer rule that is the implicit OR of all user-defined
  2276. * lexer rules.
  2277. */
  2278. public void genNextToken() {
  2279. // Are there any public rules? If not, then just generate a
  2280. // fake nextToken().
  2281. boolean hasPublicRules = false;
  2282. for (int i = 0; i < grammar.rules.size(); i++) {
  2283. RuleSymbol rs = (RuleSymbol)grammar.rules.elementAt(i);
  2284. if ( rs.isDefined() && rs.access.equals("public") ) {
  2285. hasPublicRules = true;
  2286. break;
  2287. }
  2288. }
  2289. if (!hasPublicRules) {
  2290. println("");
  2291. println("override public IToken nextToken()\t\t\t//throws TokenStreamException");
  2292. println("{");
  2293. tabs++;
  2294. println("try");
  2295. println("{");
  2296. tabs++;
  2297. println("uponEOF();");
  2298. tabs--;
  2299. println("}");
  2300. println("catch(CharStreamIOException csioe)");
  2301. println("{");
  2302. tabs++;
  2303. println("throw new TokenStreamIOException(csioe.io);");
  2304. tabs--;
  2305. println("}");
  2306. println("catch(CharStreamException cse)");
  2307. println("{");
  2308. tabs++;
  2309. println("throw new TokenStreamException(cse.Message);");
  2310. tabs--;
  2311. println("}");
  2312. println("return new CommonToken(Token.EOF_TYPE, \"\");");
  2313. tabs--;
  2314. println("}");
  2315. println("");
  2316. return;
  2317. }
  2318. // Create the synthesized nextToken() rule
  2319. RuleBlock nextTokenBlk = MakeGrammar.createNextTokenRule(grammar, grammar.rules, "nextToken");
  2320. // Define the nextToken rule symbol
  2321. RuleSymbol nextTokenRs = new RuleSymbol("mnextToken");
  2322. nextTokenRs.setDefined();
  2323. nextTokenRs.setBlock(nextTokenBlk);
  2324. nextTokenRs.access = "private";
  2325. grammar.define(nextTokenRs);
  2326. // Analyze the nextToken rule
  2327. boolean ok = grammar.theLLkAnalyzer.deterministic(nextTokenBlk);
  2328. // Generate the next token rule
  2329. String filterRule=null;
  2330. if ( ((LexerGrammar)grammar).filterMode ) {
  2331. filterRule = ((LexerGrammar)grammar).filterRule;
  2332. }
  2333. println("");
  2334. println("override public IToken nextToken()\t\t\t//throws TokenStreamException");
  2335. println("{");
  2336. tabs++;
  2337. // delay creation of _saveIndex until we need it OK?
  2338. blockNestingLevel = 1;
  2339. saveIndexCreateLevel = 0;
  2340. println("IToken theRetToken = null;");
  2341. _println("tryAgain:");
  2342. println("for (;;)");
  2343. println("{");
  2344. tabs++;
  2345. println("IToken _token = null;");
  2346. println("int _ttype = Token.INVALID_TYPE;");
  2347. if ( ((LexerGrammar)grammar).filterMode ) {
  2348. println("setCommitToPath(false);");
  2349. if ( filterRule!=null ) {
  2350. // Here's a good place to ensure that the filter rule actually exists
  2351. if (!grammar.isDefined(CodeGenerator.encodeLexerRuleName(filterRule))) {
  2352. grammar.antlrTool.error("Filter rule " + filterRule + " does not exist in this lexer");
  2353. }
  2354. else {
  2355. RuleSymbol rs = (RuleSymbol)grammar.getSymbol(CodeGenerator.encodeLexerRuleName(filterRule));
  2356. if ( !rs.isDefined() ) {
  2357. grammar.antlrTool.error("Filter rule " + filterRule + " does not exist in this lexer");
  2358. }
  2359. else if ( rs.access.equals("public") ) {
  2360. grammar.antlrTool.error("Filter rule " + filterRule + " must be protected");
  2361. }
  2362. }
  2363. println("int _m;");
  2364. println("_m = mark();");
  2365. }
  2366. }
  2367. println("resetText();");
  2368. println("try // for char stream error handling");
  2369. println("{");
  2370. tabs++;
  2371. // Generate try around whole thing to trap scanner errors
  2372. println("try // for lexical error handling");
  2373. println("{");
  2374. tabs++;
  2375. // Test for public lexical rules with empty paths
  2376. for (int i=0; i<nextTokenBlk.getAlternatives().size(); i++) {
  2377. Alternative a = nextTokenBlk.getAlternativeAt(i);
  2378. if ( a.cache[1].containsEpsilon() ) {
  2379. //String r = a.head.toString();
  2380. RuleRefElement rr = (RuleRefElement)a.head;
  2381. String r = CodeGenerator.decodeLexerRuleName(rr.targetRule);
  2382. antlrTool.warning("public lexical rule "+r+" is optional (can match \"nothing\")");
  2383. }
  2384. }
  2385. // Generate the block
  2386. String newline = System.getProperty("line.separator");
  2387. CSharpBlockFinishingInfo howToFinish = genCommonBlock(nextTokenBlk, false);
  2388. String errFinish = "if (cached_LA1==EOF_CHAR) { uponEOF(); returnToken_ = makeToken(Token.EOF_TYPE); }";
  2389. errFinish += newline+"\t\t\t\t";
  2390. if ( ((LexerGrammar)grammar).filterMode ) {
  2391. if ( filterRule==null ) {
  2392. //kunle: errFinish += "else { consume(); continue tryAgain; }";
  2393. errFinish += "\t\t\t\telse";
  2394. errFinish += "\t\t\t\t{";
  2395. errFinish += "\t\t\t\t\tconsume();";
  2396. errFinish += "\t\t\t\t\tgoto tryAgain;";
  2397. errFinish += "\t\t\t\t}";
  2398. }
  2399. else {
  2400. errFinish += "\t\t\t\t\telse"+newline+
  2401. "\t\t\t\t\t{"+newline+
  2402. "\t\t\t\t\tcommit();"+newline+
  2403. "\t\t\t\t\ttry {m"+filterRule+"(false);}"+newline+
  2404. "\t\t\t\t\tcatch(RecognitionException e)"+newline+
  2405. "\t\t\t\t\t{"+newline+
  2406. "\t\t\t\t\t // catastrophic failure"+newline+
  2407. "\t\t\t\t\t reportError(e);"+newline+
  2408. "\t\t\t\t\t consume();"+newline+
  2409. "\t\t\t\t\t}"+newline+
  2410. "\t\t\t\t\tgoto tryAgain;"+newline+
  2411. "\t\t\t\t}";
  2412. }
  2413. }
  2414. else {
  2415. errFinish += "else {"+throwNoViable+"}";
  2416. }
  2417. genBlockFinish(howToFinish, errFinish);
  2418. // at this point a valid token has been matched, undo "mark" that was done
  2419. if ( ((LexerGrammar)grammar).filterMode && filterRule!=null ) {
  2420. println("commit();");
  2421. }
  2422. // Generate literals test if desired
  2423. // make sure _ttype is set first; note returnToken_ must be
  2424. // non-null as the rule was required to create it.
  2425. println("if ( null==returnToken_ ) goto tryAgain; // found SKIP token");
  2426. println("_ttype = returnToken_.Type;");
  2427. if ( ((LexerGrammar)grammar).getTestLiterals()) {
  2428. genLiteralsTest();
  2429. }
  2430. // return token created by rule reference in switch
  2431. println("returnToken_.Type = _ttype;");
  2432. println("return returnToken_;");
  2433. // Close try block
  2434. tabs--;
  2435. println("}");
  2436. println("catch (RecognitionException e) {");
  2437. tabs++;
  2438. if ( ((LexerGrammar)grammar).filterMode ) {
  2439. if ( filterRule==null ) {
  2440. println("if (!getCommitToPath())");
  2441. println("{");
  2442. tabs++;
  2443. println("consume();");
  2444. println("goto tryAgain;");
  2445. tabs--;
  2446. println("}");
  2447. }
  2448. else {
  2449. println("if (!getCommitToPath())");
  2450. println("{");
  2451. tabs++;
  2452. println("rewind(_m);");
  2453. println("resetText();");
  2454. println("try {m"+filterRule+"(false);}");
  2455. println("catch(RecognitionException ee) {");
  2456. println(" // horrendous failure: error in filter rule");
  2457. println(" reportError(ee);");
  2458. println(" consume();");
  2459. println("}");
  2460. //println("goto tryAgain;");
  2461. tabs--;
  2462. println("}");
  2463. println("else");
  2464. }
  2465. }
  2466. if ( nextTokenBlk.getDefaultErrorHandler() ) {
  2467. println("{");
  2468. tabs++;
  2469. println("reportError(e);");
  2470. println("consume();");
  2471. tabs--;
  2472. println("}");
  2473. }
  2474. else {
  2475. // pass on to invoking routine
  2476. tabs++;
  2477. println("throw new TokenStreamRecognitionException(e);");
  2478. tabs--;
  2479. }
  2480. tabs--;
  2481. println("}");
  2482. // close CharStreamException try
  2483. tabs--;
  2484. println("}");
  2485. println("catch (CharStreamException cse) {");
  2486. println(" if ( cse is CharStreamIOException ) {");
  2487. println(" throw new TokenStreamIOException(((CharStreamIOException)cse).io);");
  2488. println(" }");
  2489. println(" else {");
  2490. println(" throw new TokenStreamException(cse.Message);");
  2491. println(" }");
  2492. println("}");
  2493. // close for-loop
  2494. tabs--;
  2495. println("}");
  2496. // close method nextToken
  2497. tabs--;
  2498. println("}");
  2499. println("");
  2500. }
  2501. /** Gen a named rule block.
  2502. * ASTs are generated for each element of an alternative unless
  2503. * the rule or the alternative have a '!' modifier.
  2504. *
  2505. * If an alternative defeats the default tree construction, it
  2506. * must set <rule>_AST to the root of the returned AST.
  2507. *
  2508. * Each alternative that does automatic tree construction, builds
  2509. * up root and child list pointers in an ASTPair structure.
  2510. *
  2511. * A rule finishes by setting the returnAST variable from the
  2512. * ASTPair.
  2513. *
  2514. * @param rule The name of the rule to generate
  2515. * @param startSymbol true if the rule is a start symbol (i.e., not referenced elsewhere)
  2516. */
  2517. public void genRule(RuleSymbol s, boolean startSymbol, int ruleNum, TokenManager tm) {
  2518. tabs=1;
  2519. if ( DEBUG_CODE_GENERATOR ) System.out.println("genRule("+ s.getId() +")");
  2520. if ( !s.isDefined() ) {
  2521. antlrTool.error("undefined rule: "+ s.getId());
  2522. return;
  2523. }
  2524. // Generate rule return type, name, arguments
  2525. RuleBlock rblk = s.getBlock();
  2526. currentRule = rblk;
  2527. currentASTResult = s.getId();
  2528. // clear list of declared ast variables..
  2529. declaredASTVariables.clear();
  2530. // Save the AST generation state, and set it to that of the rule
  2531. boolean savegenAST = genAST;
  2532. genAST = genAST && rblk.getAutoGen();
  2533. // boolean oldsaveTest = saveText;
  2534. saveText = rblk.getAutoGen();
  2535. // print javadoc comment if any
  2536. if ( s.comment!=null ) {
  2537. _println(s.comment);
  2538. }
  2539. // Gen method access and final qualifier
  2540. //print(s.access + " final ");
  2541. print(s.access + " ");
  2542. // Gen method return type (note lexer return action set at rule creation)
  2543. if (rblk.returnAction != null)
  2544. {
  2545. // Has specified return value
  2546. _print(extractTypeOfAction(rblk.returnAction, rblk.getLine(), rblk.getColumn()) + " ");
  2547. } else {
  2548. // No specified return value
  2549. _print("void ");
  2550. }
  2551. // Gen method name
  2552. _print(s.getId() + "(");
  2553. // Additional rule parameters common to all rules for this grammar
  2554. _print(commonExtraParams);
  2555. if (commonExtraParams.length() != 0 && rblk.argAction != null ) {
  2556. _print(",");
  2557. }
  2558. // Gen arguments
  2559. if (rblk.argAction != null)
  2560. {
  2561. // Has specified arguments
  2562. _println("");
  2563. tabs++;
  2564. println(rblk.argAction);
  2565. tabs--;
  2566. print(")");
  2567. }
  2568. else {
  2569. // No specified arguments
  2570. _print(")");
  2571. }
  2572. // Gen throws clause and open curly
  2573. _print(" //throws " + exceptionThrown);
  2574. if ( grammar instanceof ParserGrammar ) {
  2575. _print(", TokenStreamException");
  2576. }
  2577. else if ( grammar instanceof LexerGrammar ) {
  2578. _print(", CharStreamException, TokenStreamException");
  2579. }
  2580. // Add user-defined exceptions unless lexer (for now)
  2581. if ( rblk.throwsSpec!=null ) {
  2582. if ( grammar instanceof LexerGrammar ) {
  2583. antlrTool.error("user-defined throws spec not allowed (yet) for lexer rule "+rblk.ruleName);
  2584. }
  2585. else {
  2586. _print(", "+rblk.throwsSpec);
  2587. }
  2588. }
  2589. _println("");
  2590. _println("{");
  2591. tabs++;
  2592. // Convert return action to variable declaration
  2593. if (rblk.returnAction != null)
  2594. println(rblk.returnAction + ";");
  2595. // print out definitions needed by rules for various grammar types
  2596. println(commonLocalVars);
  2597. if (grammar.traceRules) {
  2598. if ( grammar instanceof TreeWalkerGrammar ) {
  2599. if ( usingCustomAST )
  2600. println("traceIn(\""+ s.getId() +"\",(AST)_t);");
  2601. else
  2602. println("traceIn(\""+ s.getId() +"\",_t);");
  2603. }
  2604. else {
  2605. println("traceIn(\""+ s.getId() +"\");");
  2606. }
  2607. }
  2608. if ( grammar instanceof LexerGrammar ) {
  2609. // lexer rule default return value is the rule's token name
  2610. // This is a horrible hack to support the built-in EOF lexer rule.
  2611. if (s.getId().equals("mEOF"))
  2612. println("_ttype = Token.EOF_TYPE;");
  2613. else
  2614. println("_ttype = " + s.getId().substring(1)+";");
  2615. // delay creation of _saveIndex until we need it OK?
  2616. blockNestingLevel = 1;
  2617. saveIndexCreateLevel = 0;
  2618. /*
  2619. println("boolean old_saveConsumedInput=saveConsumedInput;");
  2620. if ( !rblk.getAutoGen() ) { // turn off "save input" if ! on rule
  2621. println("saveConsumedInput=false;");
  2622. }
  2623. */
  2624. }
  2625. // if debugging, write code to mark entry to the rule
  2626. if ( grammar.debuggingOutput)
  2627. if (grammar instanceof ParserGrammar)
  2628. println("fireEnterRule(" + ruleNum + ",0);");
  2629. else if (grammar instanceof LexerGrammar)
  2630. println("fireEnterRule(" + ruleNum + ",_ttype);");
  2631. // Generate trace code if desired
  2632. if ( grammar.debuggingOutput || grammar.traceRules) {
  2633. println("try { // debugging");
  2634. tabs++;
  2635. }
  2636. // Initialize AST variables
  2637. if (grammar instanceof TreeWalkerGrammar) {
  2638. // "Input" value for rule
  2639. println(labeledElementASTType+" " + s.getId() + "_AST_in = ("+labeledElementASTType+")_t;");
  2640. }
  2641. if (grammar.buildAST) {
  2642. // Parser member used to pass AST returns from rule invocations
  2643. println("returnAST = null;");
  2644. // Tracks AST construction
  2645. // println("ASTPair currentAST = (inputState.guessing==0) ? new ASTPair() : null;");
  2646. println("ASTPair currentAST = ASTPair.GetInstance();");
  2647. // User-settable return value for rule.
  2648. println(labeledElementASTType+" " + s.getId() + "_AST = null;");
  2649. }
  2650. genBlockPreamble(rblk);
  2651. genBlockInitAction(rblk);
  2652. println("");
  2653. // Search for an unlabeled exception specification attached to the rule
  2654. ExceptionSpec unlabeledUserSpec = rblk.findExceptionSpec("");
  2655. // Generate try block around the entire rule for error handling
  2656. if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler() ) {
  2657. println("try { // for error handling");
  2658. tabs++;
  2659. }
  2660. // Generate the alternatives
  2661. if ( rblk.alternatives.size()==1 )
  2662. {
  2663. // One alternative -- use simple form
  2664. Alternative alt = rblk.getAlternativeAt(0);
  2665. String pred = alt.semPred;
  2666. if ( pred!=null )
  2667. genSemPred(pred, currentRule.line);
  2668. if (alt.synPred != null) {
  2669. antlrTool.warning(
  2670. "Syntactic predicate ignored for single alternative",
  2671. grammar.getFilename(), alt.synPred.getLine(), alt.synPred.getColumn()
  2672. );
  2673. }
  2674. genAlt(alt, rblk);
  2675. }
  2676. else
  2677. {
  2678. // Multiple alternatives -- generate complex form
  2679. boolean ok = grammar.theLLkAnalyzer.deterministic(rblk);
  2680. CSharpBlockFinishingInfo howToFinish = genCommonBlock(rblk, false);
  2681. genBlockFinish(howToFinish, throwNoViable);
  2682. }
  2683. // Generate catch phrase for error handling
  2684. if (unlabeledUserSpec != null || rblk.getDefaultErrorHandler() ) {
  2685. // Close the try block
  2686. tabs--;
  2687. println("}");
  2688. }
  2689. // Generate user-defined or default catch phrases
  2690. if (unlabeledUserSpec != null)
  2691. {
  2692. genErrorHandler(unlabeledUserSpec);
  2693. }
  2694. else if (rblk.getDefaultErrorHandler())
  2695. {
  2696. // Generate default catch phrase
  2697. println("catch (" + exceptionThrown + " ex)");
  2698. println("{");
  2699. tabs++;
  2700. // Generate code to handle error if not guessing
  2701. if (grammar.hasSyntacticPredicate) {
  2702. println("if (0 == inputState.guessing)");
  2703. println("{");
  2704. tabs++;
  2705. }
  2706. println("reportError(ex);");
  2707. if ( !(grammar instanceof TreeWalkerGrammar) )
  2708. {
  2709. // Generate code to consume until token in k==1 follow set
  2710. Lookahead follow = grammar.theLLkAnalyzer.FOLLOW(1, rblk.endNode);
  2711. String followSetName = getBitsetName(markBitsetForGen(follow.fset));
  2712. println("recover(ex," + followSetName + ");");
  2713. }
  2714. else
  2715. {
  2716. // Just consume one token
  2717. println("if (null != _t)");
  2718. println("{");
  2719. tabs++;
  2720. println("_t = _t.getNextSibling();");
  2721. tabs--;
  2722. println("}");
  2723. }
  2724. if (grammar.hasSyntacticPredicate)
  2725. {
  2726. tabs--;
  2727. // When guessing, rethrow exception
  2728. println("}");
  2729. println("else");
  2730. println("{");
  2731. tabs++;
  2732. println("throw ex;");
  2733. tabs--;
  2734. println("}");
  2735. }
  2736. // Close catch phrase
  2737. tabs--;
  2738. println("}");
  2739. }
  2740. // Squirrel away the AST "return" value
  2741. if (grammar.buildAST) {
  2742. println("returnAST = " + s.getId() + "_AST;");
  2743. }
  2744. // Set return tree value for tree walkers
  2745. if ( grammar instanceof TreeWalkerGrammar ) {
  2746. println("retTree_ = _t;");
  2747. }
  2748. // Generate literals test for lexer rules so marked
  2749. if (rblk.getTestLiterals()) {
  2750. if ( s.access.equals("protected") ) {
  2751. genLiteralsTestForPartialToken();
  2752. }
  2753. else {
  2754. genLiteralsTest();
  2755. }
  2756. }
  2757. // if doing a lexer rule, dump code to create token if necessary
  2758. if ( grammar instanceof LexerGrammar ) {
  2759. println("if (_createToken && (null == _token) && (_ttype != Token.SKIP))");
  2760. println("{");
  2761. tabs++;
  2762. println("_token = makeToken(_ttype);");
  2763. println("_token.setText(text.ToString(_begin, text.Length-_begin));");
  2764. tabs--;
  2765. println("}");
  2766. println("returnToken_ = _token;");
  2767. }
  2768. // Gen the return statement if there is one (lexer has hard-wired return action)
  2769. if (rblk.returnAction != null) {
  2770. println("return " + extractIdOfAction(rblk.returnAction, rblk.getLine(), rblk.getColumn()) + ";");
  2771. }
  2772. if ( grammar.debuggingOutput || grammar.traceRules) {
  2773. println("ASTPair.PutInstance(currentAST);");
  2774. tabs--;
  2775. println("}");
  2776. println("finally");
  2777. println("{ // debugging");
  2778. tabs++;
  2779. // If debugging, generate calls to mark exit of rule
  2780. if ( grammar.debuggingOutput)
  2781. if (grammar instanceof ParserGrammar)
  2782. println("fireExitRule(" + ruleNum + ",0);");
  2783. else if (grammar instanceof LexerGrammar)
  2784. println("fireExitRule(" + ruleNum + ",_ttype);");
  2785. if (grammar.traceRules) {
  2786. if ( grammar instanceof TreeWalkerGrammar ) {
  2787. println("traceOut(\""+ s.getId() +"\",_t);");
  2788. }
  2789. else {
  2790. println("traceOut(\""+ s.getId() +"\");");
  2791. }
  2792. }
  2793. tabs--;
  2794. println("}");
  2795. }
  2796. // Release the ASTPair instance (if we're not in trace or debug mode)
  2797. if (grammar.buildAST && !(grammar.debuggingOutput || grammar.traceRules)) {
  2798. println("ASTPair.PutInstance(currentAST);");
  2799. }
  2800. tabs--;
  2801. println("}");
  2802. println("");
  2803. // Restore the AST generation state
  2804. genAST = savegenAST;
  2805. // restore char save state
  2806. // saveText = oldsaveTest;
  2807. }
  2808. private void GenRuleInvocation(RuleRefElement rr) {
  2809. // dump rule name
  2810. _print(rr.targetRule + "(");
  2811. // lexers must tell rule if it should set returnToken_
  2812. if ( grammar instanceof LexerGrammar ) {
  2813. // if labeled, could access Token, so tell rule to create
  2814. if ( rr.getLabel() != null ) {
  2815. _print("true");
  2816. }
  2817. else {
  2818. _print("false");
  2819. }
  2820. if (commonExtraArgs.length() != 0 || rr.args!=null ) {
  2821. _print(",");
  2822. }
  2823. }
  2824. // Extra arguments common to all rules for this grammar
  2825. _print(commonExtraArgs);
  2826. if (commonExtraArgs.length() != 0 && rr.args!=null ) {
  2827. _print(",");
  2828. }
  2829. // Process arguments to method, if any
  2830. RuleSymbol rs = (RuleSymbol)grammar.getSymbol(rr.targetRule);
  2831. if (rr.args != null)
  2832. {
  2833. // When not guessing, execute user arg action
  2834. ActionTransInfo tInfo = new ActionTransInfo();
  2835. String args = processActionForSpecialSymbols(rr.args, 0, currentRule, tInfo);
  2836. if ( tInfo.assignToRoot || tInfo.refRuleRoot!=null )
  2837. {
  2838. antlrTool.error("Arguments of rule reference '" + rr.targetRule + "' cannot set or ref #" +
  2839. currentRule.getRuleName(), grammar.getFilename(), rr.getLine(), rr.getColumn());
  2840. }
  2841. _print(args);
  2842. // Warn if the rule accepts no arguments
  2843. if (rs.block.argAction == null)
  2844. {
  2845. antlrTool.warning("Rule '" + rr.targetRule + "' accepts no arguments", grammar.getFilename(), rr.getLine(), rr.getColumn());
  2846. }
  2847. }
  2848. else
  2849. {
  2850. // For C++, no warning if rule has parameters, because there may be default
  2851. // values for all of the parameters
  2852. if (rs.block.argAction != null)
  2853. {
  2854. antlrTool.warning("Missing parameters on reference to rule " + rr.targetRule, grammar.getFilename(), rr.getLine(), rr.getColumn());
  2855. }
  2856. }
  2857. _println(");");
  2858. // move down to the first child while parsing
  2859. if ( grammar instanceof TreeWalkerGrammar ) {
  2860. println("_t = retTree_;");
  2861. }
  2862. }
  2863. protected void genSemPred(String pred, int line) {
  2864. // translate $ and # references
  2865. ActionTransInfo tInfo = new ActionTransInfo();
  2866. pred = processActionForSpecialSymbols(pred, line, currentRule, tInfo);
  2867. // ignore translation info...we don't need to do anything with it.
  2868. String escapedPred = charFormatter.escapeString(pred);
  2869. // if debugging, wrap the semantic predicate evaluation in a method
  2870. // that can tell SemanticPredicateListeners the result
  2871. if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) || (grammar instanceof LexerGrammar)))
  2872. pred = "fireSemanticPredicateEvaluated(antlr.debug.SemanticPredicateEvent.VALIDATING,"
  2873. + addSemPred(escapedPred) + "," + pred + ")";
  2874. println("if (!(" + pred + "))");
  2875. println(" throw new SemanticException(\"" + escapedPred + "\");");
  2876. }
  2877. /** Write an array of Strings which are the semantic predicate
  2878. * expressions. The debugger will reference them by number only
  2879. */
  2880. protected void genSemPredMap() {
  2881. Enumeration e = semPreds.elements();
  2882. println("private string[] _semPredNames = {");
  2883. tabs++;
  2884. while(e.hasMoreElements())
  2885. println("\""+e.nextElement()+"\",");
  2886. tabs--;
  2887. println("};");
  2888. }
  2889. protected void genSynPred(SynPredBlock blk, String lookaheadExpr) {
  2890. if ( DEBUG_CODE_GENERATOR ) System.out.println("gen=>("+blk+")");
  2891. // Dump synpred result variable
  2892. println("bool synPredMatched" + blk.ID + " = false;");
  2893. // Gen normal lookahead test
  2894. println("if (" + lookaheadExpr + ")");
  2895. println("{");
  2896. tabs++;
  2897. // Save input state
  2898. if ( grammar instanceof TreeWalkerGrammar ) {
  2899. println("AST __t" + blk.ID + " = _t;");
  2900. }
  2901. else {
  2902. println("int _m" + blk.ID + " = mark();");
  2903. }
  2904. // Once inside the try, assume synpred works unless exception caught
  2905. println("synPredMatched" + blk.ID + " = true;");
  2906. println("inputState.guessing++;");
  2907. // if debugging, tell listeners that a synpred has started
  2908. if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) ||
  2909. (grammar instanceof LexerGrammar))) {
  2910. println("fireSyntacticPredicateStarted();");
  2911. }
  2912. syntacticPredLevel++;
  2913. println("try {");
  2914. tabs++;
  2915. gen((AlternativeBlock)blk); // gen code to test predicate
  2916. tabs--;
  2917. //println("System.out.println(\"pred "+blk+" succeeded\");");
  2918. println("}");
  2919. //kunle: lose a few warnings cheaply
  2920. // println("catch (" + exceptionThrown + " pe)");
  2921. println("catch (" + exceptionThrown + ")");
  2922. println("{");
  2923. tabs++;
  2924. println("synPredMatched"+blk.ID+" = false;");
  2925. //println("System.out.println(\"pred "+blk+" failed\");");
  2926. tabs--;
  2927. println("}");
  2928. // Restore input state
  2929. if ( grammar instanceof TreeWalkerGrammar ) {
  2930. println("_t = __t"+blk.ID+";");
  2931. }
  2932. else {
  2933. println("rewind(_m"+blk.ID+");");
  2934. }
  2935. println("inputState.guessing--;");
  2936. // if debugging, tell listeners how the synpred turned out
  2937. if (grammar.debuggingOutput && ((grammar instanceof ParserGrammar) ||
  2938. (grammar instanceof LexerGrammar))) {
  2939. println("if (synPredMatched" + blk.ID +")");
  2940. println(" fireSyntacticPredicateSucceeded();");
  2941. println("else");
  2942. println(" fireSyntacticPredicateFailed();");
  2943. }
  2944. syntacticPredLevel--;
  2945. tabs--;
  2946. // Close lookahead test
  2947. println("}");
  2948. // Test synred result
  2949. println("if ( synPredMatched"+blk.ID+" )");
  2950. println("{");
  2951. }
  2952. /** Generate a static array containing the names of the tokens,
  2953. * indexed by the token type values. This static array is used
  2954. * to format error messages so that the token identifers or literal
  2955. * strings are displayed instead of the token numbers.
  2956. *
  2957. * If a lexical rule has a paraphrase, use it rather than the
  2958. * token label.
  2959. */
  2960. public void genTokenStrings() {
  2961. // Generate a string for each token. This creates a static
  2962. // array of Strings indexed by token type.
  2963. println("");
  2964. println("public static readonly string[] tokenNames_ = new string[] {");
  2965. tabs++;
  2966. // Walk the token vocabulary and generate a Vector of strings
  2967. // from the tokens.
  2968. Vector v = grammar.tokenManager.getVocabulary();
  2969. for (int i = 0; i < v.size(); i++)
  2970. {
  2971. String s = (String)v.elementAt(i);
  2972. if (s == null)
  2973. {
  2974. s = "<"+String.valueOf(i)+">";
  2975. }
  2976. if ( !s.startsWith("\"") && !s.startsWith("<") ) {
  2977. TokenSymbol ts = (TokenSymbol)grammar.tokenManager.getTokenSymbol(s);
  2978. if ( ts!=null && ts.getParaphrase()!=null ) {
  2979. s = StringUtils.stripFrontBack(ts.getParaphrase(), "\"", "\"");
  2980. }
  2981. }
  2982. else if (s.startsWith("\"")) {
  2983. s = StringUtils.stripFrontBack(s, "\"", "\"");
  2984. }
  2985. print(charFormatter.literalString(s));
  2986. if (i != v.size()-1) {
  2987. _print(",");
  2988. }
  2989. _println("");
  2990. }
  2991. // Close the string array initailizer
  2992. tabs--;
  2993. println("};");
  2994. }
  2995. /** Generate the token types CSharp file */
  2996. protected void genTokenTypes(TokenManager tm) throws IOException {
  2997. // Open the token output CSharp file and set the currentOutput stream
  2998. // SAS: file open was moved to a method so a subclass can override
  2999. // This was mainly for the VAJ interface
  3000. setupOutput(tm.getName() + TokenTypesFileSuffix);
  3001. tabs = 0;
  3002. // Generate the header common to all CSharp files
  3003. genHeader();
  3004. // Do not use printAction because we assume tabs==0
  3005. println(behavior.getHeaderAction(""));
  3006. // Generate the CSharp namespace declaration (if specified)
  3007. if (nameSpace != null)
  3008. nameSpace.emitDeclarations(currentOutput);
  3009. tabs++;
  3010. // Encapsulate the definitions in a class. This has to be done as a class because
  3011. // they are all constants and CSharp inteface types cannot contain constants.
  3012. println("public class " + tm.getName() + TokenTypesFileSuffix);
  3013. //println("public class " + getTokenTypesClassName());
  3014. println("{");
  3015. tabs++;
  3016. genTokenDefinitions(tm);
  3017. // Close the interface
  3018. tabs--;
  3019. println("}");
  3020. tabs--;
  3021. // Generate the CSharp namespace closures (if required)
  3022. if (nameSpace != null)
  3023. nameSpace.emitClosures(currentOutput);
  3024. // Close the tokens output file
  3025. currentOutput.close();
  3026. currentOutput = null;
  3027. exitIfError();
  3028. }
  3029. protected void genTokenDefinitions(TokenManager tm) throws IOException {
  3030. // Generate a definition for each token type
  3031. Vector v = tm.getVocabulary();
  3032. // Do special tokens manually
  3033. println("public const int EOF = " + Token.EOF_TYPE + ";");
  3034. println("public const int NULL_TREE_LOOKAHEAD = " + Token.NULL_TREE_LOOKAHEAD + ";");
  3035. for (int i = Token.MIN_USER_TYPE; i < v.size(); i++) {
  3036. String s = (String)v.elementAt(i);
  3037. if (s != null) {
  3038. if ( s.startsWith("\"") ) {
  3039. // a string literal
  3040. StringLiteralSymbol sl = (StringLiteralSymbol)tm.getTokenSymbol(s);
  3041. if ( sl==null ) {
  3042. antlrTool.panic("String literal " + s + " not in symbol table");
  3043. }
  3044. else if ( sl.label != null ) {
  3045. println("public const int " + sl.label + " = " + i + ";");
  3046. }
  3047. else {
  3048. String mangledName = mangleLiteral(s);
  3049. if (mangledName != null) {
  3050. // We were able to create a meaningful mangled token name
  3051. println("public const int " + mangledName + " = " + i + ";");
  3052. // if no label specified, make the label equal to the mangled name
  3053. sl.label = mangledName;
  3054. }
  3055. else {
  3056. println("// " + s + " = " + i);
  3057. }
  3058. }
  3059. }
  3060. else if ( !s.startsWith("<") ) {
  3061. println("public const int " + s + " = " + i + ";");
  3062. }
  3063. }
  3064. }
  3065. println("");
  3066. }
  3067. /** Process a string for an simple expression for use in xx/action.g
  3068. * it is used to cast simple tokens/references to the right type for
  3069. * the generated language. Basically called for every element in
  3070. * the vector to getASTCreateString(vector V)
  3071. * @param str A String.
  3072. */
  3073. public String processStringForASTConstructor( String str )
  3074. {
  3075. /*
  3076. System.out.println("processStringForASTConstructor: str = "+str+
  3077. ", custom = "+(new Boolean(usingCustomAST)).toString()+
  3078. ", tree = "+(new Boolean((grammar instanceof TreeWalkerGrammar))).toString()+
  3079. ", parser = "+(new Boolean((grammar instanceof ParserGrammar))).toString()+
  3080. ", notDefined = "+(new Boolean((!(grammar.tokenManager.tokenDefined(str))))).toString()
  3081. );
  3082. */
  3083. if( usingCustomAST &&
  3084. ( (grammar instanceof TreeWalkerGrammar) ||
  3085. (grammar instanceof ParserGrammar) ) &&
  3086. !(grammar.tokenManager.tokenDefined(str)) )
  3087. {
  3088. //System.out.println("processStringForASTConstructor: "+str+" with cast");
  3089. return "(AST)"+str;
  3090. }
  3091. else
  3092. {
  3093. //System.out.println("processStringForASTConstructor: "+str);
  3094. return str;
  3095. }
  3096. }
  3097. /** Get a string for an expression to generate creation of an AST subtree.
  3098. * @param v A Vector of String, where each element is an expression
  3099. * in the target language yielding an AST node.
  3100. */
  3101. public String getASTCreateString(Vector v) {
  3102. if (v.size() == 0) {
  3103. return "";
  3104. }
  3105. StringBuffer buf = new StringBuffer();
  3106. buf.append("("+labeledElementASTType+
  3107. ") astFactory.make(");
  3108. buf.append(v.elementAt(0));
  3109. for (int i = 1; i < v.size(); i++) {
  3110. buf.append(", " + v.elementAt(i));
  3111. }
  3112. buf.append(")");
  3113. return buf.toString();
  3114. }
  3115. /** Get a string for an expression to generate creating of an AST node
  3116. * @param atom The grammar node for which you are creating the node
  3117. * @param str The arguments to the AST constructor
  3118. */
  3119. public String getASTCreateString(GrammarAtom atom, String astCtorArgs) {
  3120. String astCreateString = "astFactory.create(" + astCtorArgs + ")";
  3121. if (atom == null)
  3122. return getASTCreateString(astCtorArgs);
  3123. else {
  3124. if ( atom.getASTNodeType() != null ) {
  3125. // this Atom was instantiated from a Token that had an "AST" option - associating
  3126. // it with a specific heterogeneous AST type - applied to either:
  3127. // 1) it's underlying TokenSymbol (in the "tokens {} section" or,
  3128. // 2) a particular token reference in the grammar
  3129. //
  3130. // For option (1), we simply generate a cast to hetero-AST type
  3131. // For option (2), we generate a call to factory.create(Token, ASTNodeType) and cast it too
  3132. TokenSymbol ts = grammar.tokenManager.getTokenSymbol(atom.getText());
  3133. if ( (ts == null) || (ts.getASTNodeType() != atom.getASTNodeType()) )
  3134. astCreateString = "(" + atom.getASTNodeType() + ") astFactory.create(" + astCtorArgs + ", \"" + atom.getASTNodeType() + "\")";
  3135. else if ( (ts != null) && (ts.getASTNodeType() != null) )
  3136. astCreateString = "(" + ts.getASTNodeType() + ") " + astCreateString;
  3137. }
  3138. else if ( usingCustomAST )
  3139. astCreateString = "(" + labeledElementASTType + ") " + astCreateString;
  3140. }
  3141. return astCreateString;
  3142. }
  3143. /** Returns a string expression that creates an AST node using the specified
  3144. * AST constructor argument string.
  3145. * Parses the first (possibly only) argument in the supplied AST ctor argument
  3146. * string to obtain the token type -- ctorID.
  3147. *
  3148. * IF the token type is a valid token symbol AND
  3149. * it has an associated AST node type AND
  3150. * this is not a #[ID, "T", "ASTType"] constructor
  3151. * THEN
  3152. * generate a call to factory.create(ID, Text, token.ASTNodeType())
  3153. *
  3154. * #[ID, "T", "ASTType"] constructors are mapped to astFactory.create(ID, "T", "ASTType")
  3155. *
  3156. * The supported AST constructor forms are:
  3157. * #[ID]
  3158. * #[ID, "text"]
  3159. * #[ID, "text", ASTclassname] -- introduced in 2.7.2
  3160. *
  3161. * @param astCtorArgs The arguments to the AST constructor
  3162. */
  3163. public String getASTCreateString(String astCtorArgs) {
  3164. // kunle: 19-Aug-2002
  3165. // This AST creation string is almost certainly[*1] a manual tree construction request.
  3166. // From the manual [I couldn't read ALL of the code ;-)], this can only be one of:
  3167. // 1) #[ID] -- 'astCtorArgs' contains: 'ID' (without quotes) or,
  3168. // 2) #[ID, "T"] -- 'astCtorArgs' contains: 'ID, "Text"' (without single quotes) or,
  3169. // kunle: 08-Dec-2002 - 2.7.2a6
  3170. // 3) #[ID, "T", "ASTTypeName"] -- 'astCtorArgs' contains: 'ID, "T", "ASTTypeName"' (without single quotes)
  3171. //
  3172. // [*1] In my tests, 'atom' was '== null' only for manual tree construction requests
  3173. if ( astCtorArgs==null ) {
  3174. astCtorArgs = "";
  3175. }
  3176. String astCreateString = "astFactory.create(" + astCtorArgs + ")";
  3177. String ctorID = astCtorArgs;
  3178. String ctorText = null;
  3179. int commaIndex;
  3180. boolean ctorIncludesCustomType = false; // Is this a #[ID, "t", "ASTType"] constructor?
  3181. commaIndex = astCtorArgs.indexOf(',');
  3182. if ( commaIndex != -1 ) {
  3183. ctorID = astCtorArgs.substring(0, commaIndex); // the 'ID' portion of #[ID, "Text"]
  3184. ctorText = astCtorArgs.substring(commaIndex+1, astCtorArgs.length()); // the 'Text' portion of #[ID, "Text"]
  3185. commaIndex = ctorText.indexOf(',');
  3186. if (commaIndex != -1 ) {
  3187. // This is an AST creation of the form: #[ID, "Text", "ASTTypename"]
  3188. // Support for this was introduced with 2.7.2a6
  3189. // create default type or (since 2.7.2) 3rd arg is classname
  3190. ctorIncludesCustomType = true;
  3191. }
  3192. }
  3193. TokenSymbol ts = grammar.tokenManager.getTokenSymbol(ctorID);
  3194. if ( (null != ts) && (null != ts.getASTNodeType()) )
  3195. astCreateString = "(" + ts.getASTNodeType() + ") " + astCreateString;
  3196. else if ( usingCustomAST )
  3197. astCreateString = "(" + labeledElementASTType + ") " + astCreateString;
  3198. return astCreateString;
  3199. }
  3200. protected String getLookaheadTestExpression(Lookahead[] look, int k) {
  3201. StringBuffer e = new StringBuffer(100);
  3202. boolean first = true;
  3203. e.append("(");
  3204. for (int i = 1; i <= k; i++) {
  3205. BitSet p = look[i].fset;
  3206. if (!first) {
  3207. e.append(") && (");
  3208. }
  3209. first = false;
  3210. // Syn preds can yield <end-of-syn-pred> (epsilon) lookahead.
  3211. // There is no way to predict what that token would be. Just
  3212. // allow anything instead.
  3213. if (look[i].containsEpsilon()) {
  3214. e.append("true");
  3215. } else {
  3216. e.append(getLookaheadTestTerm(i, p));
  3217. }
  3218. }
  3219. e.append(")");
  3220. return e.toString();
  3221. }
  3222. /**Generate a lookahead test expression for an alternate. This
  3223. * will be a series of tests joined by '&&' and enclosed by '()',
  3224. * the number of such tests being determined by the depth of the lookahead.
  3225. */
  3226. protected String getLookaheadTestExpression(Alternative alt, int maxDepth) {
  3227. int depth = alt.lookaheadDepth;
  3228. if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) {
  3229. // if the decision is nondeterministic, do the best we can: LL(k)
  3230. // any predicates that are around will be generated later.
  3231. depth = grammar.maxk;
  3232. }
  3233. if ( maxDepth==0 ) {
  3234. // empty lookahead can result from alt with sem pred
  3235. // that can see end of token. E.g., A : {pred}? ('a')? ;
  3236. return "( true )";
  3237. }
  3238. return "(" + getLookaheadTestExpression(alt.cache,depth) + ")";
  3239. }
  3240. /**Generate a depth==1 lookahead test expression given the BitSet.
  3241. * This may be one of:
  3242. * 1) a series of 'x==X||' tests
  3243. * 2) a range test using >= && <= where possible,
  3244. * 3) a bitset membership test for complex comparisons
  3245. * @param k The lookahead level
  3246. * @param p The lookahead set for level k
  3247. */
  3248. protected String getLookaheadTestTerm(int k, BitSet p) {
  3249. // Determine the name of the item to be compared
  3250. String ts = lookaheadString(k);
  3251. // Generate a range expression if possible
  3252. int[] elems = p.toArray();
  3253. if (elementsAreRange(elems)) {
  3254. return getRangeExpression(k, elems);
  3255. }
  3256. // Generate a bitset membership test if possible
  3257. StringBuffer e;
  3258. int degree = p.degree();
  3259. if ( degree == 0 ) {
  3260. return "true";
  3261. }
  3262. if (degree >= bitsetTestThreshold) {
  3263. int bitsetIdx = markBitsetForGen(p);
  3264. return getBitsetName(bitsetIdx) + ".member(" + ts + ")";
  3265. }
  3266. // Otherwise, generate the long-winded series of "x==X||" tests
  3267. e = new StringBuffer();
  3268. for (int i = 0; i < elems.length; i++) {
  3269. // Get the compared-to item (token or character value)
  3270. String cs = getValueString(elems[i]);
  3271. // Generate the element comparison
  3272. if ( i>0 ) e.append("||");
  3273. e.append(ts);
  3274. e.append("==");
  3275. e.append(cs);
  3276. }
  3277. return e.toString();
  3278. }
  3279. /** Return an expression for testing a contiguous renage of elements
  3280. * @param k The lookahead level
  3281. * @param elems The elements representing the set, usually from BitSet.toArray().
  3282. * @return String containing test expression.
  3283. */
  3284. public String getRangeExpression(int k, int[] elems) {
  3285. if (!elementsAreRange(elems)) {
  3286. antlrTool.panic("getRangeExpression called with non-range");
  3287. }
  3288. int begin = elems[0];
  3289. int end = elems[elems.length-1];
  3290. return
  3291. "(" + lookaheadString(k) + " >= " + getValueString(begin) + " && " +
  3292. lookaheadString(k) + " <= " + getValueString(end) + ")";
  3293. }
  3294. /** getValueString: get a string representation of a token or char value
  3295. * @param value The token or char value
  3296. */
  3297. private String getValueString(int value) {
  3298. String cs;
  3299. if ( grammar instanceof LexerGrammar ) {
  3300. cs = charFormatter.literalChar(value);
  3301. }
  3302. else
  3303. {
  3304. TokenSymbol ts = grammar.tokenManager.getTokenSymbolAt(value);
  3305. if ( ts == null ) {
  3306. return ""+value; // return token type as string
  3307. // antlrTool.panic("vocabulary for token type " + value + " is null");
  3308. }
  3309. String tId = ts.getId();
  3310. if ( ts instanceof StringLiteralSymbol ) {
  3311. // if string literal, use predefined label if any
  3312. // if no predefined, try to mangle into LITERAL_xxx.
  3313. // if can't mangle, use int value as last resort
  3314. StringLiteralSymbol sl = (StringLiteralSymbol)ts;
  3315. String label = sl.getLabel();
  3316. if ( label!=null ) {
  3317. cs = label;
  3318. }
  3319. else {
  3320. cs = mangleLiteral(tId);
  3321. if (cs == null) {
  3322. cs = String.valueOf(value);
  3323. }
  3324. }
  3325. }
  3326. else {
  3327. cs = tId;
  3328. }
  3329. }
  3330. return cs;
  3331. }
  3332. /**Is the lookahead for this alt empty? */
  3333. protected boolean lookaheadIsEmpty(Alternative alt, int maxDepth) {
  3334. int depth = alt.lookaheadDepth;
  3335. if ( depth == GrammarAnalyzer.NONDETERMINISTIC ) {
  3336. depth = grammar.maxk;
  3337. }
  3338. for (int i=1; i<=depth && i<=maxDepth; i++) {
  3339. BitSet p = alt.cache[i].fset;
  3340. if (p.degree() != 0) {
  3341. return false;
  3342. }
  3343. }
  3344. return true;
  3345. }
  3346. private String lookaheadString(int k) {
  3347. if (grammar instanceof TreeWalkerGrammar) {
  3348. return "_t.Type";
  3349. }
  3350. if (grammar instanceof LexerGrammar) {
  3351. if (k == 1) {
  3352. return "cached_LA1";
  3353. }
  3354. if (k == 2) {
  3355. return "cached_LA2";
  3356. }
  3357. }
  3358. return "LA(" + k + ")";
  3359. }
  3360. /** Mangle a string literal into a meaningful token name. This is
  3361. * only possible for literals that are all characters. The resulting
  3362. * mangled literal name is literalsPrefix with the text of the literal
  3363. * appended.
  3364. * @return A string representing the mangled literal, or null if not possible.
  3365. */
  3366. private String mangleLiteral(String s) {
  3367. String mangled = antlrTool.literalsPrefix;
  3368. for (int i = 1; i < s.length()-1; i++) {
  3369. if (!Character.isLetter(s.charAt(i)) &&
  3370. s.charAt(i) != '_') {
  3371. return null;
  3372. }
  3373. mangled += s.charAt(i);
  3374. }
  3375. if ( antlrTool.upperCaseMangledLiterals ) {
  3376. mangled = mangled.toUpperCase();
  3377. }
  3378. return mangled;
  3379. }
  3380. /** Map an identifier to it's corresponding tree-node variable.
  3381. * This is context-sensitive, depending on the rule and alternative
  3382. * being generated
  3383. * @param idParam The identifier name to map
  3384. * @return The mapped id (which may be the same as the input), or null if the mapping is invalid due to duplicates
  3385. */
  3386. public String mapTreeId(String idParam, ActionTransInfo transInfo) {
  3387. // if not in an action of a rule, nothing to map.
  3388. if ( currentRule==null ) return idParam;
  3389. boolean in_var = false;
  3390. String id = idParam;
  3391. if (grammar instanceof TreeWalkerGrammar)
  3392. {
  3393. if ( !grammar.buildAST )
  3394. {
  3395. in_var = true;
  3396. }
  3397. // If the id ends with "_in", then map it to the input variable
  3398. else if (id.length() > 3 && id.lastIndexOf("_in") == id.length()-3)
  3399. {
  3400. // Strip off the "_in"
  3401. id = id.substring(0, id.length()-3);
  3402. in_var = true;
  3403. }
  3404. }
  3405. // Check the rule labels. If id is a label, then the output
  3406. // variable is label_AST, and the input variable is plain label.
  3407. for (int i = 0; i < currentRule.labeledElements.size(); i++)
  3408. {
  3409. AlternativeElement elt = (AlternativeElement)currentRule.labeledElements.elementAt(i);
  3410. if (elt.getLabel().equals(id))
  3411. {
  3412. return in_var ? id : id + "_AST";
  3413. }
  3414. }
  3415. // Failing that, check the id-to-variable map for the alternative.
  3416. // If the id is in the map, then output variable is the name in the
  3417. // map, and input variable is name_in
  3418. String s = (String)treeVariableMap.get(id);
  3419. if (s != null)
  3420. {
  3421. if (s == NONUNIQUE)
  3422. {
  3423. // There is more than one element with this id
  3424. antlrTool.error("Ambiguous reference to AST element "+id+
  3425. " in rule "+currentRule.getRuleName());
  3426. return null;
  3427. }
  3428. else if (s.equals(currentRule.getRuleName()))
  3429. {
  3430. // a recursive call to the enclosing rule is
  3431. // ambiguous with the rule itself.
  3432. // if( in_var )
  3433. // System.out.println("returning null (rulename)");
  3434. antlrTool.error("Ambiguous reference to AST element "+id+
  3435. " in rule "+currentRule.getRuleName());
  3436. return null;
  3437. }
  3438. else
  3439. {
  3440. return in_var ? s + "_in" : s;
  3441. }
  3442. }
  3443. // Failing that, check the rule name itself. Output variable
  3444. // is rule_AST; input variable is rule_AST_in (treeparsers).
  3445. if( id.equals(currentRule.getRuleName()) )
  3446. {
  3447. String r = in_var ? id + "_AST_in" : id + "_AST";
  3448. if ( transInfo!=null ) {
  3449. if ( !in_var ) {
  3450. transInfo.refRuleRoot = r;
  3451. }
  3452. }
  3453. return r;
  3454. }
  3455. else
  3456. {
  3457. // id does not map to anything -- return itself.
  3458. return id;
  3459. }
  3460. }
  3461. /** Given an element and the name of an associated AST variable,
  3462. * create a mapping between the element "name" and the variable name.
  3463. */
  3464. private void mapTreeVariable(AlternativeElement e, String name)
  3465. {
  3466. // For tree elements, defer to the root
  3467. if (e instanceof TreeElement) {
  3468. mapTreeVariable( ((TreeElement)e).root, name);
  3469. return;
  3470. }
  3471. // Determine the name of the element, if any, for mapping purposes
  3472. String elName = null;
  3473. // Don't map labeled items
  3474. if (e.getLabel() == null) {
  3475. if (e instanceof TokenRefElement) {
  3476. // use the token id
  3477. elName = ((TokenRefElement)e).atomText;
  3478. }
  3479. else if (e instanceof RuleRefElement) {
  3480. // use the rule name
  3481. elName = ((RuleRefElement)e).targetRule;
  3482. }
  3483. }
  3484. // Add the element to the tree variable map if it has a name
  3485. if (elName != null) {
  3486. if (treeVariableMap.get(elName) != null) {
  3487. // Name is already in the map -- mark it as duplicate
  3488. treeVariableMap.remove(elName);
  3489. treeVariableMap.put(elName, NONUNIQUE);
  3490. }
  3491. else {
  3492. treeVariableMap.put(elName, name);
  3493. }
  3494. }
  3495. }
  3496. /** Lexically process tree-specifiers in the action.
  3497. * This will replace #id and #(...) with the appropriate
  3498. * function calls and/or variables.
  3499. */
  3500. protected String processActionForSpecialSymbols(String actionStr,
  3501. int line,
  3502. RuleBlock currentRule,
  3503. ActionTransInfo tInfo)
  3504. {
  3505. if ( actionStr==null || actionStr.length()==0 )
  3506. return null;
  3507. // The action trans info tells us (at the moment) whether an
  3508. // assignment was done to the rule's tree root.
  3509. if (grammar==null)
  3510. return actionStr;
  3511. // see if we have anything to do...
  3512. if ((grammar.buildAST && actionStr.indexOf('#') != -1) ||
  3513. grammar instanceof TreeWalkerGrammar ||
  3514. ((grammar instanceof LexerGrammar ||
  3515. grammar instanceof ParserGrammar)
  3516. && actionStr.indexOf('$') != -1) )
  3517. {
  3518. // Create a lexer to read an action and return the translated version
  3519. antlr.actions.csharp.ActionLexer lexer = new antlr.actions.csharp.ActionLexer(actionStr, currentRule, this, tInfo);
  3520. lexer.setLineOffset(line);
  3521. lexer.setFilename(grammar.getFilename());
  3522. lexer.setTool(antlrTool);
  3523. try {
  3524. lexer.mACTION(true);
  3525. actionStr = lexer.getTokenObject().getText();
  3526. // System.out.println("action translated: "+actionStr);
  3527. // System.out.println("trans info is "+tInfo);
  3528. }
  3529. catch (RecognitionException ex) {
  3530. lexer.reportError(ex);
  3531. return actionStr;
  3532. }
  3533. catch (TokenStreamException tex) {
  3534. antlrTool.panic("Error reading action:"+actionStr);
  3535. return actionStr;
  3536. }
  3537. catch (CharStreamException io) {
  3538. antlrTool.panic("Error reading action:"+actionStr);
  3539. return actionStr;
  3540. }
  3541. }
  3542. return actionStr;
  3543. }
  3544. private void setupGrammarParameters(Grammar g) {
  3545. if (g instanceof ParserGrammar ||
  3546. g instanceof LexerGrammar ||
  3547. g instanceof TreeWalkerGrammar
  3548. )
  3549. {
  3550. /* RK: options also have to be added to Grammar.java and for options
  3551. * on the file level entries have to be defined in
  3552. * DefineGrammarSymbols.java and passed around via 'globals' in antlrTool.java
  3553. */
  3554. if( antlrTool.nameSpace != null )
  3555. nameSpace = new CSharpNameSpace( antlrTool.nameSpace.getName() );
  3556. //genHashLines = antlrTool.genHashLines;
  3557. /* let grammar level options override filelevel ones...
  3558. */
  3559. if( g.hasOption("namespace") ) {
  3560. Token t = g.getOption("namespace");
  3561. if( t != null ) {
  3562. nameSpace = new CSharpNameSpace(t.getText());
  3563. }
  3564. }
  3565. /*
  3566. if( g.hasOption("genHashLines") ) {
  3567. Token t = g.getOption("genHashLines");
  3568. if( t != null ) {
  3569. String val = StringUtils.stripFrontBack(t.getText(),"\"","\"");
  3570. genHashLines = val.equals("true");
  3571. }
  3572. }
  3573. */
  3574. }
  3575. if (g instanceof ParserGrammar) {
  3576. labeledElementASTType = "AST";
  3577. if ( g.hasOption("ASTLabelType") ) {
  3578. Token tsuffix = g.getOption("ASTLabelType");
  3579. if ( tsuffix != null ) {
  3580. String suffix = StringUtils.stripFrontBack(tsuffix.getText(), "\"", "\"");
  3581. if ( suffix != null ) {
  3582. usingCustomAST = true;
  3583. labeledElementASTType = suffix;
  3584. }
  3585. }
  3586. }
  3587. labeledElementType = "IToken ";
  3588. labeledElementInit = "null";
  3589. commonExtraArgs = "";
  3590. commonExtraParams = "";
  3591. commonLocalVars = "";
  3592. lt1Value = "LT(1)";
  3593. exceptionThrown = "RecognitionException";
  3594. throwNoViable = "throw new NoViableAltException(LT(1), getFilename());";
  3595. }
  3596. else if (g instanceof LexerGrammar) {
  3597. labeledElementType = "char ";
  3598. labeledElementInit = "'\\0'";
  3599. commonExtraArgs = "";
  3600. commonExtraParams = "bool _createToken";
  3601. commonLocalVars = "int _ttype; IToken _token=null; int _begin=text.Length;";
  3602. lt1Value = "cached_LA1";
  3603. exceptionThrown = "RecognitionException";
  3604. throwNoViable = "throw new NoViableAltForCharException(cached_LA1, getFilename(), getLine(), getColumn());";
  3605. }
  3606. else if (g instanceof TreeWalkerGrammar) {
  3607. labeledElementASTType = "AST";
  3608. labeledElementType = "AST";
  3609. if ( g.hasOption("ASTLabelType") ) {
  3610. Token tsuffix = g.getOption("ASTLabelType");
  3611. if ( tsuffix != null ) {
  3612. String suffix = StringUtils.stripFrontBack(tsuffix.getText(), "\"", "\"");
  3613. if ( suffix != null ) {
  3614. usingCustomAST = true;
  3615. labeledElementASTType = suffix;
  3616. labeledElementType = suffix;
  3617. }
  3618. }
  3619. }
  3620. if ( !g.hasOption("ASTLabelType") ) {
  3621. g.setOption("ASTLabelType", new Token(ANTLRTokenTypes.STRING_LITERAL,"AST"));
  3622. }
  3623. labeledElementInit = "null";
  3624. commonExtraArgs = "_t";
  3625. commonExtraParams = "AST _t";
  3626. commonLocalVars = "";
  3627. if (usingCustomAST)
  3628. lt1Value = "(_t==ASTNULL) ? null : (" + labeledElementASTType + ")_t";
  3629. else
  3630. lt1Value = "_t";
  3631. exceptionThrown = "RecognitionException";
  3632. throwNoViable = "throw new NoViableAltException(_t);";
  3633. }
  3634. else {
  3635. antlrTool.panic("Unknown grammar type");
  3636. }
  3637. }
  3638. /** This method exists so a subclass, namely VAJCodeGenerator,
  3639. * can open the file in its own evil way. JavaCodeGenerator
  3640. * simply opens a text file...
  3641. */
  3642. public void setupOutput(String className) throws IOException
  3643. {
  3644. currentOutput = antlrTool.openOutputFile(className + ".cs");
  3645. }
  3646. /** Helper method from Eric Smith's version of CSharpCodeGenerator.*/
  3647. private static String OctalToUnicode(String str)
  3648. {
  3649. // only do any conversion if the string looks like "'\003'"
  3650. if ( (4 <= str.length()) &&
  3651. ('\'' == str.charAt(0)) &&
  3652. ('\\' == str.charAt(1)) &&
  3653. (('0' <= str.charAt(2)) && ('7' >= str.charAt(2))) &&
  3654. ('\'' == str.charAt(str.length()-1)) )
  3655. {
  3656. // convert octal representation to decimal, then to hex
  3657. Integer x = Integer.valueOf(str.substring(2, str.length()-1), 8);
  3658. return "'\\x" + Integer.toHexString(x.intValue()) + "'";
  3659. }
  3660. else {
  3661. return str;
  3662. }
  3663. }
  3664. /** Helper method that returns the name of the interface/class/enum type for
  3665. token type constants.
  3666. */
  3667. public String getTokenTypesClassName()
  3668. {
  3669. TokenManager tm = grammar.tokenManager;
  3670. return new String(tm.getName() + TokenTypesFileSuffix);
  3671. }
  3672. private void declareSaveIndexVariableIfNeeded()
  3673. {
  3674. if (saveIndexCreateLevel == 0)
  3675. {
  3676. println("int _saveIndex = 0;");
  3677. saveIndexCreateLevel = blockNestingLevel;
  3678. }
  3679. }
  3680. public String[] split(String str, String sep)
  3681. {
  3682. StringTokenizer st = new StringTokenizer(str, sep);
  3683. int count = st.countTokens();
  3684. String[] values = new String[count];
  3685. int i = 0;
  3686. while(st.hasMoreTokens())
  3687. {
  3688. values[i] = st.nextToken();
  3689. i++;
  3690. }
  3691. return values;
  3692. }
  3693. }