diff options
Diffstat (limited to 'tool/src/main/java/org/antlr/tool/LeftRecursiveRuleAnalyzer.java')
-rw-r--r-- | tool/src/main/java/org/antlr/tool/LeftRecursiveRuleAnalyzer.java | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/tool/src/main/java/org/antlr/tool/LeftRecursiveRuleAnalyzer.java b/tool/src/main/java/org/antlr/tool/LeftRecursiveRuleAnalyzer.java new file mode 100644 index 0000000..fcbf7db --- /dev/null +++ b/tool/src/main/java/org/antlr/tool/LeftRecursiveRuleAnalyzer.java @@ -0,0 +1,352 @@ +package org.antlr.tool; + +import org.antlr.codegen.CodeGenerator; +import org.antlr.grammar.v3.*; +import org.antlr.runtime.Token; +import org.antlr.runtime.tree.CommonTreeNodeStream; +import org.antlr.runtime.tree.TreeNodeStream; +import org.stringtemplate.v4.*; + +import java.util.*; + +/** */ +public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker { + public static enum ASSOC { left, right }; + + public Grammar g; + public CodeGenerator generator; + public String ruleName; + Map<Integer, Integer> tokenToPrec = new HashMap<Integer, Integer>(); + public LinkedHashMap<Integer, String> binaryAlts = new LinkedHashMap<Integer, String>(); + public LinkedHashMap<Integer, String> ternaryAlts = new LinkedHashMap<Integer, String>(); + public LinkedHashMap<Integer, String> suffixAlts = new LinkedHashMap<Integer, String>(); + public List<String> prefixAlts = new ArrayList<String>(); + public List<String> otherAlts = new ArrayList<String>(); + + public GrammarAST retvals; + + public STGroup recRuleTemplates; + public String language; + + public Map<Integer, ASSOC> altAssociativity = new HashMap<Integer, ASSOC>(); + + public LeftRecursiveRuleAnalyzer(TreeNodeStream input, Grammar g, String ruleName) { + super(input); + this.g = g; + this.ruleName = ruleName; + language = (String)g.getOption("language"); + generator = new CodeGenerator(g.tool, g, language); + generator.loadTemplates(language); + loadPrecRuleTemplates(); + } + + public void loadPrecRuleTemplates() { + recRuleTemplates = + new STGroupFile(CodeGenerator.classpathTemplateRootDirectoryName+ + "/LeftRecursiveRules.stg"); + if ( !recRuleTemplates.isDefined("recRuleName") ) { + ErrorManager.error(ErrorManager.MSG_MISSING_CODE_GEN_TEMPLATES, + "PrecRules"); + return; + } + } + + @Override + public void setReturnValues(GrammarAST t) { + System.out.println(t); + retvals = t; + } + + @Override + public void setTokenPrec(GrammarAST t, int alt) { + int ttype = g.getTokenType(t.getText()); + tokenToPrec.put(ttype, alt); + ASSOC assoc = ASSOC.left; + if ( t.terminalOptions!=null ) { + String a = (String)t.terminalOptions.get("assoc"); + if ( a!=null ) { + if ( a.equals(ASSOC.right.toString()) ) { + assoc = ASSOC.right; + } + else { + ErrorManager.error(ErrorManager.MSG_ILLEGAL_OPTION_VALUE, "assoc", assoc); + } + } + } + + if ( altAssociativity.get(alt)!=null && altAssociativity.get(alt)!=assoc ) { + ErrorManager.error(ErrorManager.MSG_ALL_OPS_NEED_SAME_ASSOC, alt); + } + altAssociativity.put(alt, assoc); + + //System.out.println("op " + alt + ": " + t.getText()+", assoc="+assoc); + } + + @Override + public void binaryAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) { + altTree = GrammarAST.dupTree(altTree); + rewriteTree = GrammarAST.dupTree(rewriteTree); + + stripSynPred(altTree); + stripLeftRecursion(altTree); + + // rewrite e to be e_[rec_arg] + int nextPrec = nextPrecedence(alt); + ST refST = recRuleTemplates.getInstanceOf("recRuleRef"); + refST.add("ruleName", ruleName); + refST.add("arg", nextPrec); + altTree = replaceRuleRefs(altTree, refST.render()); + + String altText = text(altTree); + altText = altText.trim(); + altText += "{}"; // add empty alt to prevent pred hoisting + ST nameST = recRuleTemplates.getInstanceOf("recRuleName"); + nameST.add("ruleName", ruleName); + rewriteTree = replaceRuleRefs(rewriteTree, "$" + nameST.render()); + String rewriteText = text(rewriteTree); + binaryAlts.put(alt, altText + (rewriteText != null ? " " + rewriteText : "")); + //System.out.println("binaryAlt " + alt + ": " + altText + ", rewrite=" + rewriteText); + } + + /** Convert e ? e : e -> ? e : e_[nextPrec] */ + @Override + public void ternaryAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) { + altTree = GrammarAST.dupTree(altTree); + rewriteTree = GrammarAST.dupTree(rewriteTree); + + stripSynPred(altTree); + stripLeftRecursion(altTree); + + int nextPrec = nextPrecedence(alt); + ST refST = recRuleTemplates.getInstanceOf("recRuleRef"); + refST.add("ruleName", ruleName); + refST.add("arg", nextPrec); + altTree = replaceLastRuleRef(altTree, refST.render()); + + String altText = text(altTree); + altText = altText.trim(); + altText += "{}"; // add empty alt to prevent pred hoisting + ST nameST = recRuleTemplates.getInstanceOf("recRuleName"); + nameST.add("ruleName", ruleName); + rewriteTree = replaceRuleRefs(rewriteTree, "$" + nameST.render()); + String rewriteText = text(rewriteTree); + ternaryAlts.put(alt, altText + (rewriteText != null ? " " + rewriteText : "")); + //System.out.println("ternaryAlt " + alt + ": " + altText + ", rewrite=" + rewriteText); + } + + @Override + public void prefixAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) { + altTree = GrammarAST.dupTree(altTree); + rewriteTree = GrammarAST.dupTree(rewriteTree); + + stripSynPred(altTree); + + int nextPrec = precedence(alt); + // rewrite e to be e_[rec_arg] + ST refST = recRuleTemplates.getInstanceOf("recRuleRef"); + refST.add("ruleName", ruleName); + refST.add("arg", nextPrec); + altTree = replaceRuleRefs(altTree, refST.render()); + String altText = text(altTree); + altText = altText.trim(); + altText += "{}"; // add empty alt to prevent pred hoisting + + ST nameST = recRuleTemplates.getInstanceOf("recRuleName"); + nameST.add("ruleName", ruleName); + rewriteTree = replaceRuleRefs(rewriteTree, nameST.render()); + String rewriteText = text(rewriteTree); + + prefixAlts.add(altText + (rewriteText != null ? " " + rewriteText : "")); + //System.out.println("prefixAlt " + alt + ": " + altText + ", rewrite=" + rewriteText); + } + + @Override + public void suffixAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) { + altTree = GrammarAST.dupTree(altTree); + rewriteTree = GrammarAST.dupTree(rewriteTree); + stripSynPred(altTree); + stripLeftRecursion(altTree); + ST nameST = recRuleTemplates.getInstanceOf("recRuleName"); + nameST.add("ruleName", ruleName); + rewriteTree = replaceRuleRefs(rewriteTree, "$" + nameST.render()); + String rewriteText = text(rewriteTree); + String altText = text(altTree); + altText = altText.trim(); + suffixAlts.put(alt, altText + (rewriteText != null ? " " + rewriteText : "")); +// System.out.println("suffixAlt " + alt + ": " + altText + ", rewrite=" + rewriteText); + } + + @Override + public void otherAlt(GrammarAST altTree, GrammarAST rewriteTree, int alt) { + altTree = GrammarAST.dupTree(altTree); + rewriteTree = GrammarAST.dupTree(rewriteTree); + stripSynPred(altTree); + stripLeftRecursion(altTree); + String altText = text(altTree); + + String rewriteText = text(rewriteTree); + otherAlts.add(altText + (rewriteText != null ? " " + rewriteText : "")); + //System.out.println("otherAlt " + alt + ": " + altText + ", rewrite=" + rewriteText); + } + + // --------- get transformed rules ---------------- + + public String getArtificialPrecStartRule() { + ST ruleST = recRuleTemplates.getInstanceOf("recRuleStart"); + ruleST.add("ruleName", ruleName); + ruleST.add("minPrec", 0); + ruleST.add("userRetvals", retvals); + fillRetValAssignments(ruleST, "recRuleName"); + + System.out.println("start: " + ruleST); + return ruleST.render(); + } + + public String getArtificialOpPrecRule() { + ST ruleST = recRuleTemplates.getInstanceOf("recRule"); + ruleST.add("ruleName", ruleName); + ruleST.add("buildAST", grammar.buildAST()); + ST argDefST = + generator.getTemplates().getInstanceOf("recRuleDefArg"); + ruleST.add("precArgDef", argDefST); + ST ruleArgST = + generator.getTemplates().getInstanceOf("recRuleArg"); + ruleST.add("argName", ruleArgST); + ST setResultST = + generator.getTemplates().getInstanceOf("recRuleSetResultAction"); + ruleST.add("setResultAction", setResultST); + ruleST.add("userRetvals", retvals); + fillRetValAssignments(ruleST, "recPrimaryName"); + + LinkedHashMap<Integer, String> opPrecRuleAlts = new LinkedHashMap<Integer, String>(); + opPrecRuleAlts.putAll(binaryAlts); + opPrecRuleAlts.putAll(ternaryAlts); + opPrecRuleAlts.putAll(suffixAlts); + for (int alt : opPrecRuleAlts.keySet()) { + String altText = opPrecRuleAlts.get(alt); + ST altST = recRuleTemplates.getInstanceOf("recRuleAlt"); + ST predST = + generator.getTemplates().getInstanceOf("recRuleAltPredicate"); + predST.add("opPrec", precedence(alt)); + predST.add("ruleName", ruleName); + altST.add("pred", predST); + altST.add("alt", altText); + ruleST.add("alts", altST); + } + + System.out.println(ruleST); + + return ruleST.render(); + } + + public String getArtificialPrimaryRule() { + ST ruleST = recRuleTemplates.getInstanceOf("recPrimaryRule"); + ruleST.add("ruleName", ruleName); + ruleST.add("alts", prefixAlts); + ruleST.add("alts", otherAlts); + ruleST.add("userRetvals", retvals); + System.out.println(ruleST); + return ruleST.render(); + } + + public GrammarAST replaceRuleRefs(GrammarAST t, String name) { + if ( t==null ) return null; + for (GrammarAST rref : t.findAllType(RULE_REF)) { + if ( rref.getText().equals(ruleName) ) rref.setText(name); + } + return t; + } + + public static boolean hasImmediateRecursiveRuleRefs(GrammarAST t, String ruleName) { + if ( t==null ) return false; + for (GrammarAST rref : t.findAllType(RULE_REF)) { + if ( rref.getText().equals(ruleName) ) return true; + } + return false; + } + + public GrammarAST replaceLastRuleRef(GrammarAST t, String name) { + if ( t==null ) return null; + GrammarAST last = null; + for (GrammarAST rref : t.findAllType(RULE_REF)) { last = rref; } + if ( last !=null && last.getText().equals(ruleName) ) last.setText(name); + return t; + } + + public void stripSynPred(GrammarAST altAST) { + GrammarAST t = (GrammarAST)altAST.getChild(0); + if ( t.getType()==ANTLRParser.BACKTRACK_SEMPRED || + t.getType()==ANTLRParser.SYNPRED || + t.getType()==ANTLRParser.SYN_SEMPRED ) + { + altAST.deleteChild(0); // kill it + } + } + + public void stripLeftRecursion(GrammarAST altAST) { + GrammarAST rref = (GrammarAST)altAST.getChild(0); + if ( rref.getType()== ANTLRParser.RULE_REF && + rref.getText().equals(ruleName)) + { + // remove rule ref + altAST.deleteChild(0); + // reset index so it prints properly + GrammarAST newFirstChild = (GrammarAST) altAST.getChild(0); + altAST.setTokenStartIndex(newFirstChild.getTokenStartIndex()); + } + } + + public String text(GrammarAST t) { + if ( t==null ) return null; + try { + return new ANTLRTreePrinter(new CommonTreeNodeStream(t)).toString(grammar, true); + } + catch (Exception e) { + ErrorManager.error(ErrorManager.MSG_BAD_AST_STRUCTURE, e); + } + return null; + } + + public int precedence(int alt) { + return numAlts-alt+1; + } + + public int nextPrecedence(int alt) { + int p = precedence(alt); + if ( altAssociativity.get(alt)==ASSOC.left ) p++; + return p; + } + + public void fillRetValAssignments(ST ruleST, String srcName) { + if ( retvals==null ) return; + + // complicated since we must be target-independent + for (String name : getNamesFromArgAction(retvals.token)) { + ST setRetValST = + generator.getTemplates().getInstanceOf("recRuleSetReturnAction"); + ST ruleNameST = recRuleTemplates.getInstanceOf(srcName); + ruleNameST.add("ruleName", ruleName); + setRetValST.add("src", ruleNameST); + setRetValST.add("name", name); + ruleST.add("userRetvalAssignments",setRetValST); + } + } + + public Collection<String> getNamesFromArgAction(Token t) { + AttributeScope returnScope = grammar.createReturnScope("",t); + returnScope.addAttributes(t.getText(), ','); + return returnScope.attributes.keySet(); + } + + @Override + public String toString() { + return "PrecRuleOperatorCollector{" + + "binaryAlts=" + binaryAlts + + ", rec=" + tokenToPrec + + ", ternaryAlts=" + ternaryAlts + + ", suffixAlts=" + suffixAlts + + ", prefixAlts=" + prefixAlts + + ", otherAlts=" + otherAlts + + '}'; + } +} |