diff --git a/tool/playground/T.g b/tool/playground/T.g index eebbe9ddd1..9949f8074f 100644 --- a/tool/playground/T.g +++ b/tool/playground/T.g @@ -1,6 +1,8 @@ grammar T; -s : f f EOF; -f : | x; -x : 'a' 'b'; +s : e ';' ; +e : e '*' e + | ID + | INT + ; INT : '0'..'9'+; WS : (' '|'\n') {skip();} ; diff --git a/tool/resources/org/antlr/v4/tool/templates/LeftRecursiveRules.stg b/tool/resources/org/antlr/v4/tool/templates/LeftRecursiveRules.stg index 9ac580e884..7c0bcddc2e 100644 --- a/tool/resources/org/antlr/v4/tool/templates/LeftRecursiveRules.stg +++ b/tool/resources/org/antlr/v4/tool/templates/LeftRecursiveRules.stg @@ -37,7 +37,7 @@ recRule(ruleName, precArgDef, argName, primaryAlts, opAlts, setResultAction, userRetvals, leftRecursiveRuleRefLabels) ::= << [] returns [] - : ( }; separator="\n | "> + : ( {} }; separator="\n | "> ) ( )* diff --git a/tool/test/org/antlr/v4/test/TestLeftRecursion.java b/tool/test/org/antlr/v4/test/TestLeftRecursion.java index f5b8400f92..205f737c89 100644 --- a/tool/test/org/antlr/v4/test/TestLeftRecursion.java +++ b/tool/test/org/antlr/v4/test/TestLeftRecursion.java @@ -276,6 +276,59 @@ public class TestLeftRecursion extends BaseTest { runTests(grammar, tests, "s"); } + @Test + public void testAmbigLR() throws Exception { + String grammar = + "// START: g\n" + + "grammar Expr;\n" + + "// END: g\n" + + "\n" + + "// START:stat\n" + + "prog: stat ;\n" + + "\n" + + "stat: expr NEWLINE -> printExpr\n" + + " | ID '=' expr NEWLINE -> assign\n" + + " | NEWLINE -> blank\n" + + " ;\n" + + "// END:stat\n" + + "\n" + + "// START:expr\n" + + "expr: expr ('*'|'/') expr -> MulDiv\n" + + " | expr ('+'|'-') expr -> AddSub\n" + + " | INT -> int\n" + + " | ID -> id\n" + + " | '(' expr ')' -> parens\n" + + " ;\n" + + "// END:expr\n" + + "\n" + + "// show marginal cost of adding a clear/wipe command for memory\n" + + "\n" + + "// START:tokens\n" + + "MUL : '*' ; // assigns token name to '*' used above in grammar\n" + + "DIV : '/' ;\n" + + "ADD : '+' ;\n" + + "SUB : '-' ;\n" + + "ID : [a-zA-Z]+ ; // match identifiers\n" + + "INT : [0-9]+ ; // match integers\n" + + "NEWLINE:'\\r'? '\\n' ; // return newlines to parser (is end-statement signal)\n" + + "WS : [ \\t]+ -> skip ; // toss out whitespace\n" + + "// END:tokens\n"; + String result = execParser("Expr.g4", grammar, "ExprParser", "ExprLexer", "prog", "1\n", true); + assertNull(stderrDuringParse); + + result = execParser("Expr.g4", grammar, "ExprParser", "ExprLexer", "prog", "a = 5\n", true); + assertNull(stderrDuringParse); + + result = execParser("Expr.g4", grammar, "ExprParser", "ExprLexer", "prog", "b = 6\n", true); + assertNull(stderrDuringParse); + + result = execParser("Expr.g4", grammar, "ExprParser", "ExprLexer", "prog", "a+b*2\n", true); + assertNull(stderrDuringParse); + + result = execParser("Expr.g4", grammar, "ExprParser", "ExprLexer", "prog", "(1+2)*3\n", true); + assertNull(stderrDuringParse); + } + public void runTests(String grammar, String[] tests, String startRule) { rawGenerateAndBuildRecognizer("T.g", grammar, "TParser", "TLexer"); writeRecognizerAndCompile("TParser",