foo
This commit is contained in:
parent
0df4411ea7
commit
90187039f0
|
@ -37,6 +37,7 @@ import org.antlr.v4.runtime.tree.ParseTree;
|
|||
import org.antlr.v4.runtime.tree.ParseTreeListener;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
import org.antlr.v4.runtime.tree.TerminalNodeImpl;
|
||||
import org.antlr.v4.runtime.tree.pattern.RuleTagToken;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -96,8 +97,17 @@ public class ParserRuleContext extends RuleContext {
|
|||
|
||||
public Token start, stop;
|
||||
|
||||
/** Used when parsing <expr> tags in patterns. If non-null, then this
|
||||
* node is not just expr but <expr> to match any expr rule subtree.
|
||||
*
|
||||
* // found a <expr> tag in pattern. Just consume it and store in
|
||||
// rule node to indicate it matches entire subtree. A bit ugly
|
||||
// but better than replacing rule node with diff kind of object
|
||||
*/
|
||||
public RuleTagToken patternRuleTag;
|
||||
|
||||
/**
|
||||
* The exception which forced this rule to return. If the rule successfully
|
||||
* The exception that forced this rule to return. If the rule successfully
|
||||
* completed, this is {@code null}.
|
||||
*/
|
||||
public RecognitionException exception;
|
||||
|
|
|
@ -33,6 +33,7 @@ package org.antlr.v4.runtime.tree.pattern;
|
|||
import org.antlr.v4.runtime.DefaultErrorStrategy;
|
||||
import org.antlr.v4.runtime.InputMismatchException;
|
||||
import org.antlr.v4.runtime.Parser;
|
||||
import org.antlr.v4.runtime.ParserRuleContext;
|
||||
import org.antlr.v4.runtime.RecognitionException;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
|
||||
|
@ -70,9 +71,15 @@ public class ParseTreePatternErrorStrategy extends DefaultErrorStrategy {
|
|||
@Override
|
||||
public void recover(Parser recognizer, RecognitionException e) {
|
||||
if (e.getOffendingToken() instanceof RuleTagToken) {
|
||||
recognizer.consume(); // match <tag> as if it matches rule, continue
|
||||
// leaves <expr> as (expr <expr>) tree; can shrink later. this
|
||||
// is simplest mechanism to get <expr> into tree.
|
||||
ParserRuleContext ctx = recognizer.getContext();
|
||||
// found a <expr> tag in pattern. Just consume it and store in
|
||||
// rule node to indicate it matches entire subtree. A bit ugly
|
||||
// but better than replacing rule node with diff kind of object
|
||||
Token o = recognizer.getCurrentToken();
|
||||
ctx.patternRuleTag = (RuleTagToken)o;
|
||||
if (o.getType() != Token.EOF) {
|
||||
recognizer.getInputStream().consume();
|
||||
}
|
||||
}
|
||||
else {
|
||||
super.recover(recognizer, e);
|
||||
|
|
|
@ -144,11 +144,11 @@ public class ParseTreePatternMatcher {
|
|||
}
|
||||
return m;
|
||||
}
|
||||
if ( tree instanceof RuleNode && patternTree instanceof RuleNode ) {
|
||||
RuleNode r1 = (RuleNode)tree;
|
||||
RuleNode r2 = (RuleNode)patternTree;
|
||||
if ( tree instanceof ParserRuleContext && patternTree instanceof ParserRuleContext ) {
|
||||
ParserRuleContext r1 = (ParserRuleContext)tree;
|
||||
ParserRuleContext r2 = (ParserRuleContext)patternTree;
|
||||
// (expr ...) and <expr>
|
||||
if ( r2 instanceof RuleSubtreeNode ) {
|
||||
if ( r2.patternRuleTag!=null ) {
|
||||
ParseTreeMatch m = null;
|
||||
if ( r1.getRuleContext().getRuleIndex() == r2.getRuleContext().getRuleIndex() ) {
|
||||
m = new ParseTreeMatch(tree, pattern);
|
||||
|
@ -184,48 +184,28 @@ public class ParseTreePatternMatcher {
|
|||
parser.setErrorHandler(new ParseTreePatternErrorStrategy());
|
||||
ParseTree tree = null;
|
||||
try {
|
||||
Method startRule = parserClass.getMethod(patternRuleName);
|
||||
tree = (ParserRuleContext)startRule.invoke(parser, (Object[])null);
|
||||
Method startRule = null;
|
||||
Object[] args = null;
|
||||
try {
|
||||
startRule = parserClass.getMethod(patternRuleName);
|
||||
}
|
||||
catch (NoSuchMethodException nsme) {
|
||||
// try with int _p arg for recursive func
|
||||
startRule = parserClass.getMethod(patternRuleName, int.class);
|
||||
args = new Integer[] {0};
|
||||
}
|
||||
tree = (ParseTree)startRule.invoke(parser, args);
|
||||
System.out.println("pattern tree = "+tree.toStringTree(parser));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CannotInvokeStartRule(e);
|
||||
}
|
||||
|
||||
shrinkRuleTagSubtreesToSingleNode(tree);
|
||||
System.out.println("after optimize pattern tree = " + tree.toStringTree(parser));
|
||||
|
||||
return new ParseTreePattern(patternRuleName, pattern, tree);
|
||||
}
|
||||
|
||||
// replace (expr <expr>) where <expr> is a TerminalNode with RuleTagToken
|
||||
// symbol to a single RuleSubtreeNode for <expr>
|
||||
protected void shrinkRuleTagSubtreesToSingleNode(ParseTree t) {
|
||||
if ( t instanceof RuleNode ) {
|
||||
RuleNode r = (RuleNode)t;
|
||||
if ( r.getChildCount()==1 && r.getChild(0) instanceof TerminalNode ) {
|
||||
TerminalNode c = (TerminalNode)r.getChild(0);
|
||||
if ( c.getSymbol() instanceof RuleTagToken ) {
|
||||
System.out.println("rule tag subtree "+t.toStringTree(parser));
|
||||
ParserRuleContext parent = (ParserRuleContext)r.getParent();
|
||||
int i = parent.children.indexOf(r);
|
||||
if ( i==-1 ) {
|
||||
System.out.printf("eh?-------------------");
|
||||
}
|
||||
RuleSubtreeNode sub = new RuleSubtreeNode((ParserRuleContext)r.getRuleContext());
|
||||
parent.children.set(i, sub);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( t instanceof RuleNode) {
|
||||
RuleNode r = (RuleNode)t;
|
||||
int n = r.getChildCount();
|
||||
for (int i = 0; i<n; i++) {
|
||||
shrinkRuleTagSubtreesToSingleNode(r.getChild(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<? extends Token> tokenize(String pattern) {
|
||||
lazyInit();
|
||||
// make maps for quick look up
|
||||
|
|
|
@ -524,8 +524,17 @@ public abstract class BaseTest {
|
|||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
Parser parser = pctor.newInstance(tokens);
|
||||
|
||||
Method startRule = parserClass.getMethod(startRuleName);
|
||||
ParseTree result = (ParseTree)startRule.invoke(parser, (Object[])null);
|
||||
Method startRule = null;
|
||||
Object[] args = null;
|
||||
try {
|
||||
startRule = parserClass.getMethod(startRuleName);
|
||||
}
|
||||
catch (NoSuchMethodException nsme) {
|
||||
// try with int _p arg for recursive func
|
||||
startRule = parserClass.getMethod(startRuleName, int.class);
|
||||
args = new Integer[] {0};
|
||||
}
|
||||
ParseTree result = (ParseTree)startRule.invoke(parser, args);
|
||||
System.out.println("parse tree = "+result.toStringTree(parser));
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -160,6 +160,27 @@ public class TestParseTreeMatcher extends BaseTest {
|
|||
checkPatternMatch("X5.g4", grammar, "s", input, pattern, "X5Parser", "X5Lexer");
|
||||
}
|
||||
|
||||
@Test public void testLRecursiveExpr() throws Exception {
|
||||
String grammar =
|
||||
"grammar X6;\n" +
|
||||
"s : expr ';'\n" +
|
||||
//" | 'return' expr ';'\n" +
|
||||
" ;\n" +
|
||||
"expr: expr '.' ID\n" +
|
||||
" | expr '*' expr\n" +
|
||||
" | expr '=' expr\n" +
|
||||
" | ID\n" +
|
||||
" | INT\n" +
|
||||
" ;\n" +
|
||||
"ID : [a-z]+ ;\n" +
|
||||
"INT : [0-9]+ ;\n" +
|
||||
"WS : [ \\r\\n\\t]+ -> skip ;\n";
|
||||
|
||||
String input = "3*4*5";
|
||||
String pattern = "<expr> * <expr> * <expr>";
|
||||
checkPatternMatch("X6.g4", grammar, "expr", input, pattern, "X6Parser", "X6Lexer");
|
||||
}
|
||||
|
||||
public void checkPatternMatch(String grammarName, String grammar, String startRule,
|
||||
String input, String pattern,
|
||||
String parserName, String lexerName)
|
||||
|
|
Loading…
Reference in New Issue