public void translateLeftRecursiveRules() { String language = g.getOptionString("language"); // translate all recursive rules List<String> leftRecursiveRuleNames = new ArrayList<String>(); for (Rule r : rules) { if (!Grammar.isTokenName(r.name)) { if (LeftRecursiveRuleAnalyzer.hasImmediateRecursiveRuleRefs(r.ast, r.name)) { g.originalTokenStream = g.tokenStream; boolean fitsPattern = translateLeftRecursiveRule(ast, (LeftRecursiveRule) r, language); if (fitsPattern) leftRecursiveRuleNames.add(r.name); } } } // update all refs to recursive rules to have [0] argument for (GrammarAST r : ast.getNodesWithType(ANTLRParser.RULE_REF)) { if (r.getParent().getType() == ANTLRParser.RULE) continue; // must be rule def if (((GrammarASTWithOptions) r).getOptionString(PRECEDENCE_OPTION_NAME) != null) continue; // already has arg; must be in rewritten rule if (leftRecursiveRuleNames.contains(r.getText())) { // found ref to recursive rule not already rewritten with arg ((GrammarASTWithOptions) r) .setOption( PRECEDENCE_OPTION_NAME, (GrammarAST) new GrammarASTAdaptor().create(ANTLRParser.INT, "0")); } } }
/** Return true if successful */ public boolean translateLeftRecursiveRule( GrammarRootAST ast, LeftRecursiveRule r, String language) { // tool.log("grammar", ruleAST.toStringTree()); GrammarAST prevRuleAST = r.ast; String ruleName = prevRuleAST.getChild(0).getText(); LeftRecursiveRuleAnalyzer leftRecursiveRuleWalker = new LeftRecursiveRuleAnalyzer(prevRuleAST, tool, ruleName, language); boolean isLeftRec; try { // System.out.println("TESTING ---------------\n"+ // leftRecursiveRuleWalker.text(ruleAST)); isLeftRec = leftRecursiveRuleWalker.rec_rule(); } catch (RecognitionException re) { isLeftRec = false; // didn't match; oh well } if (!isLeftRec) return false; // replace old rule's AST GrammarAST RULES = (GrammarAST) ast.getFirstChildWithType(ANTLRParser.RULES); String newRuleText = leftRecursiveRuleWalker.getArtificialOpPrecRule(); // System.out.println("created: "+newRuleText); RuleAST t = parseArtificialRule(g, newRuleText); // reuse the name token from the original AST since it refers to the proper source location in // the original grammar ((GrammarAST) t.getChild(0)).token = ((GrammarAST) prevRuleAST.getChild(0)).getToken(); // update grammar AST and set rule's AST. RULES.setChild(prevRuleAST.getChildIndex(), t); r.ast = t; // Reduce sets in newly created rule tree GrammarTransformPipeline transform = new GrammarTransformPipeline(g, g.tool); transform.reduceBlocksToSets(r.ast); transform.expandParameterizedLoops(r.ast); // Rerun semantic checks on the new rule RuleCollector ruleCollector = new RuleCollector(g); ruleCollector.visit(t, "rule"); BasicSemanticChecks basics = new BasicSemanticChecks(g, ruleCollector); // disable the assoc element option checks because they are already // handled for the pre-transformed rule. basics.checkAssocElementOption = false; basics.visit(t, "rule"); // track recursive alt info for codegen r.recPrimaryAlts = new ArrayList<LeftRecursiveRuleAltInfo>(); r.recPrimaryAlts.addAll(leftRecursiveRuleWalker.prefixAlts); r.recPrimaryAlts.addAll(leftRecursiveRuleWalker.otherAlts); if (r.recPrimaryAlts.isEmpty()) { tool.errMgr.grammarError( ErrorType.NO_NON_LR_ALTS, g.fileName, ((GrammarAST) r.ast.getChild(0)).getToken(), r.name); } r.recOpAlts = new OrderedHashMap<Integer, LeftRecursiveRuleAltInfo>(); r.recOpAlts.putAll(leftRecursiveRuleWalker.binaryAlts); r.recOpAlts.putAll(leftRecursiveRuleWalker.ternaryAlts); r.recOpAlts.putAll(leftRecursiveRuleWalker.suffixAlts); // walk alt info records and set their altAST to point to appropriate ALT subtree // from freshly created AST setAltASTPointers(r, t); // update Rule to just one alt and add prec alt ActionAST arg = (ActionAST) r.ast.getFirstChildWithType(ANTLRParser.ARG_ACTION); if (arg != null) { r.args = ScopeParser.parseTypedArgList(arg, arg.getText(), g.tool.errMgr); r.args.type = AttributeDict.DictType.ARG; r.args.ast = arg; arg.resolver = r.alt[1]; // todo: isn't this Rule or something? } // define labels on recursive rule refs we delete; they don't point to nodes of course // these are so $label in action translation works for (Pair<GrammarAST, String> pair : leftRecursiveRuleWalker.leftRecursiveRuleRefLabels) { GrammarAST labelNode = pair.a; GrammarAST labelOpNode = (GrammarAST) labelNode.getParent(); GrammarAST elementNode = (GrammarAST) labelOpNode.getChild(1); LabelElementPair lp = new LabelElementPair(g, labelNode, elementNode, labelOpNode.getType()); r.alt[1].labelDefs.map(labelNode.getText(), lp); } // copy to rule from walker r.leftRecursiveRuleRefLabels = leftRecursiveRuleWalker.leftRecursiveRuleRefLabels; tool.log("grammar", "added: " + t.toStringTree()); return true; }