Merge pull request #873 from parrt/fix-nonconforming-lr-rules

Check for nonconforming left-recursive rules.
This commit is contained in:
Terence Parr 2015-05-19 14:45:00 -07:00
commit f491a1a84f
5 changed files with 75 additions and 6 deletions

View File

@ -93,7 +93,12 @@ public class LeftRecursiveRuleTransformer {
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);
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);
}
}
}
}

View File

@ -79,6 +79,7 @@ package org.antlr.v4.parse;
import org.antlr.v4.Tool;
import org.antlr.v4.tool.*;
import org.antlr.v4.tool.ast.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
}
@ -105,8 +106,12 @@ public void visit(GrammarAST t, String ruleName) {
Method m = getClass().getMethod(ruleName);
m.invoke(this);
}
catch (Exception e) {
catch (Throwable e) {
ErrorManager errMgr = getErrorManager();
if ( e instanceof InvocationTargetException ) {
e = e.getCause();
}
//e.printStackTrace(System.err);
if ( errMgr==null ) {
System.err.println("can't find rule "+ruleName+
" or tree structure error: "+t.toStringTree()

View File

@ -85,14 +85,15 @@ public class SemanticPipeline {
BasicSemanticChecks basics = new BasicSemanticChecks(g, ruleCollector);
basics.process();
// don't continue if we get errors in this basic check
//if ( false ) return;
// TRANSFORM LEFT-RECURSIVE RULES
int prevErrors = g.tool.errMgr.getNumErrors();
LeftRecursiveRuleTransformer lrtrans =
new LeftRecursiveRuleTransformer(g.ast, ruleCollector.rules.values(), g);
lrtrans.translateLeftRecursiveRules();
// don't continue if we got errors during left-recursion elimination
if ( g.tool.errMgr.getNumErrors()>prevErrors ) return;
// STORE RULES IN GRAMMAR
for (Rule r : ruleCollector.rules.values()) {
g.defineRule(r);

View File

@ -956,6 +956,8 @@ public enum ErrorType {
*/
CHANNELS_BLOCK_IN_COMBINED_GRAMMAR(164, "custom channels are not supported in combined grammars", ErrorSeverity.ERROR),
NONCONFORMING_LR_RULE(165, "rule <arg> is left recursive but doesn't conform to a pattern ANTLR can handle", ErrorSeverity.ERROR),
/*
* Backward incompatibility errors
*/

View File

@ -34,7 +34,7 @@ import org.antlr.v4.tool.ErrorType;
import org.junit.Test;
/** */
public class TestLeftRecursion extends BaseTest {
public class TestLeftRecursionToolIssues extends BaseTest {
protected boolean debug = false;
@Test public void testCheckForNonLeftRecursiveRule() throws Exception {
@ -64,4 +64,60 @@ public class TestLeftRecursion extends BaseTest {
testErrors(new String[] { grammar, expected }, false);
}
/** Reproduces https://github.com/antlr/antlr4/issues/855 */
@Test public void testLeftRecursiveRuleRefWithArg() throws Exception {
String grammar =
"grammar T;\n" +
"statement\n" +
"locals[Scope scope]\n" +
" : expressionA[$scope] ';'\n" +
" ;\n" +
"expressionA[Scope scope]\n" +
" : atom[$scope]\n" +
" | expressionA[$scope] '[' expressionA[$scope] ']'\n" +
" ;\n" +
"atom[Scope scope]\n" +
" : 'dummy'\n" +
" ;\n";
String expected =
"error(" + ErrorType.NONCONFORMING_LR_RULE.code + "): T.g4:6:0: rule expressionA is left recursive but doesn't conform to a pattern ANTLR can handle\n";
testErrors(new String[]{grammar, expected}, false);
}
/** Reproduces https://github.com/antlr/antlr4/issues/855 */
@Test public void testLeftRecursiveRuleRefWithArg2() throws Exception {
String grammar =
"grammar T;\n" +
"a[int i] : 'x'\n" +
" | a[3] 'y'\n" +
" ;";
String expected =
"error(" + ErrorType.NONCONFORMING_LR_RULE.code + "): T.g4:2:0: rule a is left recursive but doesn't conform to a pattern ANTLR can handle\n";
testErrors(new String[]{grammar, expected}, false);
}
/** Reproduces https://github.com/antlr/antlr4/issues/855 */
@Test public void testLeftRecursiveRuleRefWithArg3() throws Exception {
String grammar =
"grammar T;\n" +
"a : 'x'\n" +
" | a[3] 'y'\n" +
" ;";
String expected =
"error(" + ErrorType.NONCONFORMING_LR_RULE.code + "): T.g4:2:0: rule a is left recursive but doesn't conform to a pattern ANTLR can handle\n";
testErrors(new String[]{grammar, expected}, false);
}
/** Reproduces https://github.com/antlr/antlr4/issues/822 */
@Test public void testIsolatedLeftRecursiveRuleRef() throws Exception {
String grammar =
"grammar T;\n" +
"a : a | b ;\n" +
"b : 'B' ;\n";
String expected =
"error(" + ErrorType.NONCONFORMING_LR_RULE.code + "): T.g4:2:0: rule a is left recursive but doesn't conform to a pattern ANTLR can handle\n";
testErrors(new String[]{grammar, expected}, false);
}
}