use of org.antlr.v4.tool.LeftRecursiveRule in project antlr4 by antlr.
the class ParserATNFactory method createRuleStartAndStopATNStates.
/** Define all the rule begin/end ATNStates to solve forward reference
* issues.
*/
void createRuleStartAndStopATNStates() {
atn.ruleToStartState = new RuleStartState[g.rules.size()];
atn.ruleToStopState = new RuleStopState[g.rules.size()];
for (Rule r : g.rules.values()) {
RuleStartState start = newState(RuleStartState.class, r.ast);
RuleStopState stop = newState(RuleStopState.class, r.ast);
start.stopState = stop;
start.isLeftRecursiveRule = r instanceof LeftRecursiveRule;
start.setRuleIndex(r.index);
stop.setRuleIndex(r.index);
atn.ruleToStartState[r.index] = start;
atn.ruleToStopState[r.index] = stop;
}
}
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 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 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 RuleCollector method discoverRule.
@Override
public void discoverRule(RuleAST rule, GrammarAST ID, List<GrammarAST> modifiers, ActionAST arg, ActionAST returns, GrammarAST thrws, GrammarAST options, ActionAST locals, List<GrammarAST> actions, GrammarAST block) {
int numAlts = block.getChildCount();
Rule r;
if (LeftRecursiveRuleAnalyzer.hasImmediateRecursiveRuleRefs(rule, ID.getText())) {
r = new LeftRecursiveRule(g, ID.getText(), rule);
} else {
r = new Rule(g, ID.getText(), rule, numAlts);
}
rules.put(r.name, r);
if (arg != null) {
r.args = ScopeParser.parseTypedArgList(arg, arg.getText(), g);
r.args.type = AttributeDict.DictType.ARG;
r.args.ast = arg;
arg.resolver = r.alt[currentOuterAltNumber];
}
if (returns != null) {
r.retvals = ScopeParser.parseTypedArgList(returns, returns.getText(), g);
r.retvals.type = AttributeDict.DictType.RET;
r.retvals.ast = returns;
}
if (locals != null) {
r.locals = ScopeParser.parseTypedArgList(locals, locals.getText(), g);
r.locals.type = AttributeDict.DictType.LOCAL;
r.locals.ast = locals;
}
for (GrammarAST a : actions) {
// a = ^(AT ID ACTION)
ActionAST action = (ActionAST) a.getChild(1);
r.namedActions.put(a.getChild(0).getText(), action);
action.resolver = r;
}
}
Aggregations