use of org.antlr.v4.tool.ast.RuleAST in project antlr4 by antlr.
the class LeftRecursiveRuleTransformer method parseArtificialRule.
public RuleAST parseArtificialRule(final Grammar g, String ruleText) {
ANTLRLexer lexer = new ANTLRLexer(new ANTLRStringStream(ruleText));
GrammarASTAdaptor adaptor = new GrammarASTAdaptor(lexer.getCharStream());
CommonTokenStream tokens = new CommonTokenStream(lexer);
lexer.tokens = tokens;
ToolANTLRParser p = new ToolANTLRParser(tokens, tool);
p.setTreeAdaptor(adaptor);
Token ruleStart = null;
try {
ParserRuleReturnScope r = p.rule();
RuleAST tree = (RuleAST) r.getTree();
ruleStart = (Token) r.getStart();
GrammarTransformPipeline.setGrammarPtr(g, tree);
GrammarTransformPipeline.augmentTokensWithOriginalPosition(g, tree);
return tree;
} catch (Exception e) {
tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, e, ruleStart, "error parsing rule created during left-recursion detection: " + ruleText);
}
return null;
}
use of org.antlr.v4.tool.ast.RuleAST in project antlr4 by antlr.
the class TestATNConstruction method testAplusSingleAltHasPlusASTPointingAtLoopBackState.
@Test
public void testAplusSingleAltHasPlusASTPointingAtLoopBackState() throws Exception {
Grammar g = new Grammar("parser grammar P;\n" + // (RULE a (BLOCK (ALT (+ (BLOCK (ALT A))))))
"s : a B ;\n" + "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());
}
use of org.antlr.v4.tool.ast.RuleAST 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.ast.RuleAST 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.ast.RuleAST in project antlr4 by antlr.
the class Tool method checkForRuleIssues.
/**
* Important enough to avoid multiple definitions that we do very early,
* right after AST construction. Also check for undefined rules in
* parser/lexer to avoid exceptions later. Return true if we find multiple
* definitions of the same rule or a reference to an undefined rule or
* parser rule ref in lexer rule.
*/
public boolean checkForRuleIssues(final Grammar g) {
// check for redefined rules
GrammarAST RULES = (GrammarAST) g.ast.getFirstChildWithType(ANTLRParser.RULES);
List<GrammarAST> rules = new ArrayList<GrammarAST>(RULES.getAllChildrenWithType(ANTLRParser.RULE));
for (GrammarAST mode : g.ast.getAllChildrenWithType(ANTLRParser.MODE)) {
rules.addAll(mode.getAllChildrenWithType(ANTLRParser.RULE));
}
boolean redefinition = false;
final Map<String, RuleAST> ruleToAST = new HashMap<String, RuleAST>();
for (GrammarAST r : rules) {
RuleAST ruleAST = (RuleAST) r;
GrammarAST ID = (GrammarAST) ruleAST.getChild(0);
String ruleName = ID.getText();
RuleAST prev = ruleToAST.get(ruleName);
if (prev != null) {
GrammarAST prevChild = (GrammarAST) prev.getChild(0);
g.tool.errMgr.grammarError(ErrorType.RULE_REDEFINITION, g.fileName, ID.getToken(), ruleName, prevChild.getToken().getLine());
redefinition = true;
continue;
}
ruleToAST.put(ruleName, ruleAST);
}
// check for undefined rules
class UndefChecker extends GrammarTreeVisitor {
public boolean badref = false;
@Override
public void tokenRef(TerminalAST ref) {
if ("EOF".equals(ref.getText())) {
// this is a special predefined reference
return;
}
if (g.isLexer())
ruleRef(ref, null);
}
@Override
public void ruleRef(GrammarAST ref, ActionAST arg) {
RuleAST ruleAST = ruleToAST.get(ref.getText());
String fileName = ref.getToken().getInputStream().getSourceName();
if (Character.isUpperCase(currentRuleName.charAt(0)) && Character.isLowerCase(ref.getText().charAt(0))) {
badref = true;
errMgr.grammarError(ErrorType.PARSER_RULE_REF_IN_LEXER_RULE, fileName, ref.getToken(), ref.getText(), currentRuleName);
} else if (ruleAST == null) {
badref = true;
errMgr.grammarError(ErrorType.UNDEFINED_RULE_REF, fileName, ref.token, ref.getText());
}
}
@Override
public ErrorManager getErrorManager() {
return errMgr;
}
}
UndefChecker chk = new UndefChecker();
chk.visitGrammar(g.ast);
return redefinition || chk.badref;
}
Aggregations