PageRenderTime 36ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/antlr-2.7.5/antlr/BooCodeGenerator.java

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