blob: 61e189152a8ca65571d4ca3698020d17493c6e7f [file] [log] [blame]
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 ToolSTGroupFile(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 &rarr; ? 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 (Map.Entry<Integer, String> entry : opPrecRuleAlts.entrySet()) {
int alt = entry.getKey();
String altText = entry.getValue();
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 +
'}';
}
}