public RuleAST parseArtificialRule(final Grammar g, String ruleText) { ANTLRLexer lexer = new ANTLRLexer(new ANTLRStringStream(ruleText)); GrammarASTAdaptor adaptor = new GrammarASTAdaptor(lexer.getCharStream()); CommonTokenStream tokens = new CommonTokenStream(lexer); lexer.tokens = tokens; ToolANTLRParser p = new ToolANTLRParser(tokens, tool); p.setTreeAdaptor(adaptor); try { ParserRuleReturnScope r = p.rule(); RuleAST tree = (RuleAST) r.getTree(); GrammarTransformPipeline.setGrammarPtr(g, tree); GrammarTransformPipeline.augmentTokensWithOriginalPosition(g, tree); return tree; } catch (Exception e) { tool.errMgr.toolError( ErrorType.INTERNAL_ERROR, "error parsing rule created during left-recursion detection: " + ruleText, e); } return null; }
/** 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; }