public static Map<Integer, Interval> getStateToGrammarRegionMap( GrammarRootAST ast, IntervalSet grammarTokenTypes) { Map<Integer, Interval> stateToGrammarRegionMap = new HashMap<Integer, Interval>(); if (ast == null) return stateToGrammarRegionMap; List<GrammarAST> nodes = ast.getNodesWithType(grammarTokenTypes); for (GrammarAST n : nodes) { if (n.atnState != null) { Interval tokenRegion = Interval.of(n.getTokenStartIndex(), n.getTokenStopIndex()); org.antlr.runtime.tree.Tree ruleNode = null; // RULEs, BLOCKs of transformed recursive rules point to original token interval switch (n.getType()) { case ANTLRParser.RULE: ruleNode = n; break; case ANTLRParser.BLOCK: case ANTLRParser.CLOSURE: ruleNode = n.getAncestor(ANTLRParser.RULE); break; } if (ruleNode instanceof RuleAST) { String ruleName = ((RuleAST) ruleNode).getRuleName(); Rule r = ast.g.getRule(ruleName); if (r instanceof LeftRecursiveRule) { RuleAST originalAST = ((LeftRecursiveRule) r).getOriginalAST(); tokenRegion = Interval.of(originalAST.getTokenStartIndex(), originalAST.getTokenStopIndex()); } } stateToGrammarRegionMap.put(n.atnState.stateNumber, tokenRegion); } } return stateToGrammarRegionMap; }
@Test public void testAplusSingleAltHasPlusASTPointingAtLoopBackState() throws Exception { Grammar g = new Grammar( "parser grammar P;\n" + "s : a B ;\n" + // (RULE a (BLOCK (ALT (+ (BLOCK (ALT A)))))) "a : A+;"); String expecting = "RuleStart_a_2->PlusBlockStart_8\n" + "PlusBlockStart_8->s7\n" + "s7-A->BlockEnd_9\n" + "BlockEnd_9->PlusLoopBack_10\n" + "PlusLoopBack_10->PlusBlockStart_8\n" + "PlusLoopBack_10->s11\n" + "s11->RuleStop_a_3\n" + "RuleStop_a_3->s5\n"; checkRuleATN(g, "a", expecting); // Get all AST -> ATNState relationships. Make sure loopback is covered when no loop entry // decision List<GrammarAST> ruleNodes = g.ast.getNodesWithType(ANTLRParser.RULE); RuleAST a = (RuleAST) ruleNodes.get(1); List<GrammarAST> nodesInRule = a.getNodesWithType(null); Map<GrammarAST, ATNState> covered = new LinkedHashMap<GrammarAST, ATNState>(); for (GrammarAST node : nodesInRule) { if (node.atnState != null) { covered.put(node, node.atnState); } } assertEquals("{RULE=2, BLOCK=8, +=10, BLOCK=8, A=7}", covered.toString()); }
/** * * * <pre> * (RULE e int _p (returns int v) * (BLOCK * (ALT * (BLOCK * (ALT INT {$v = $INT.int;}) * (ALT '(' (= x e) ')' {$v = $x.v;}) * (ALT ID)) * (* (BLOCK * (OPTIONS ...) * (ALT {7 >= $_p}? '*' (= b e) {$v = $a.v * $b.v;}) * (ALT {6 >= $_p}? '+' (= b e) {$v = $a.v + $b.v;}) * (ALT {3 >= $_p}? '++') (ALT {2 >= $_p}? '--')))))) * </pre> */ public void setAltASTPointers(LeftRecursiveRule r, RuleAST t) { // System.out.println("RULE: "+t.toStringTree()); BlockAST ruleBlk = (BlockAST) t.getFirstChildWithType(ANTLRParser.BLOCK); AltAST mainAlt = (AltAST) ruleBlk.getChild(0); BlockAST primaryBlk = (BlockAST) mainAlt.getChild(0); BlockAST opsBlk = (BlockAST) mainAlt.getChild(1).getChild(0); // (* BLOCK ...) for (int i = 0; i < r.recPrimaryAlts.size(); i++) { LeftRecursiveRuleAltInfo altInfo = r.recPrimaryAlts.get(i); altInfo.altAST = (AltAST) primaryBlk.getChild(i); altInfo.altAST.leftRecursiveAltInfo = altInfo; altInfo.originalAltAST.leftRecursiveAltInfo = altInfo; // altInfo.originalAltAST.parent = altInfo.altAST.parent; // System.out.println(altInfo.altAST.toStringTree()); } for (int i = 0; i < r.recOpAlts.size(); i++) { LeftRecursiveRuleAltInfo altInfo = r.recOpAlts.getElement(i); altInfo.altAST = (AltAST) opsBlk.getChild(i); altInfo.altAST.leftRecursiveAltInfo = altInfo; altInfo.originalAltAST.leftRecursiveAltInfo = altInfo; // altInfo.originalAltAST.parent = altInfo.altAST.parent; // System.out.println(altInfo.altAST.toStringTree()); } }
/** 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; }