use of org.antlr.v4.tool.LeftRecursiveRule in project antlr4 by antlr.
the class LeftRecursiveRuleTransformer method translateLeftRecursiveRules.
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)) {
boolean fitsPattern = translateLeftRecursiveRule(ast, (LeftRecursiveRule) r, language);
if (fitsPattern) {
leftRecursiveRuleNames.add(r.name);
} else {
// better given an error that non-conforming left-recursion exists
tool.errMgr.grammarError(ErrorType.NONCONFORMING_LR_RULE, g.fileName, ((GrammarAST) r.ast.getChild(0)).token, r.name);
}
}
}
}
// update all refs to recursive rules to have [0] argument
for (GrammarAST r : ast.getNodesWithType(ANTLRParser.RULE_REF)) {
// must be rule def
if (r.getParent().getType() == ANTLRParser.RULE)
continue;
// already has arg; must be in rewritten rule
if (((GrammarASTWithOptions) r).getOptionString(PRECEDENCE_OPTION_NAME) != null)
continue;
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"));
}
}
}
use of org.antlr.v4.tool.LeftRecursiveRule in project antlr4 by antlr.
the class LeftRecursiveRuleTransformer method translateLeftRecursiveRule.
/**
* 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) {
// didn't match; oh well
isLeftRec = false;
}
if (!isLeftRec)
return false;
// replace old rule's AST; first create text of altered rule
GrammarAST RULES = (GrammarAST) ast.getFirstChildWithType(ANTLRParser.RULES);
String newRuleText = leftRecursiveRuleWalker.getArtificialOpPrecRule();
// System.out.println("created: "+newRuleText);
// now parse within the context of the grammar that originally created
// the AST we are transforming. This could be an imported grammar so
// we cannot just reference this.g because the role might come from
// the imported grammar and not the root grammar (this.g)
RuleAST t = parseArtificialRule(prevRuleAST.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.prefixAndOtherAlts);
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);
r.args.type = AttributeDict.DictType.ARG;
r.args.ast = arg;
// todo: isn't this Rule or something?
arg.resolver = r.alt[1];
}
// 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;
}
use of org.antlr.v4.tool.LeftRecursiveRule in project antlr4 by antlr.
the class LeftRecursiveRuleTransformer method setAltASTPointers.
/**
* <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);
// (* BLOCK ...)
BlockAST opsBlk = (BlockAST) mainAlt.getChild(1).getChild(0);
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());
}
}
use of org.antlr.v4.tool.LeftRecursiveRule in project antlr4 by antlr.
the class OutputModelController method buildRuleFunction.
/**
* Create RuleFunction per rule and update sempreds,actions of parser
* output object with stuff found in r.
*/
public void buildRuleFunction(Parser parser, Rule r) {
RuleFunction function = rule(r);
parser.funcs.add(function);
pushCurrentRule(function);
function.fillNamedActions(delegate, r);
if (r instanceof LeftRecursiveRule) {
buildLeftRecursiveRuleFunction((LeftRecursiveRule) r, (LeftRecursiveRuleFunction) function);
} else {
buildNormalRuleFunction(r, function);
}
Grammar g = getGrammar();
for (ActionAST a : r.actions) {
if (a instanceof PredAST) {
PredAST p = (PredAST) a;
RuleSempredFunction rsf = parser.sempredFuncs.get(r);
if (rsf == null) {
rsf = new RuleSempredFunction(delegate, r, function.ctxType);
parser.sempredFuncs.put(r, rsf);
}
rsf.actions.put(g.sempreds.get(p), new Action(delegate, p));
}
}
popCurrentRule();
}
Aggregations