Merge branch 'left-recursive-prefix-alternatives' of git://github.com/michaelpj/antlr4 into michaelpj-left-recursive-prefix-alternatives

This commit is contained in:
parrt 2016-03-29 15:23:59 -07:00
commit f2cbc6eb7c
11 changed files with 305 additions and 11 deletions

View File

@ -59,6 +59,8 @@ TestTemplates ::= [
"MultipleAlternativesWithCommonLabel_2": [],
"MultipleAlternativesWithCommonLabel_3": [],
"MultipleAlternativesWithCommonLabel_4": [],
"PrefixAndOtherAlt_1": [],
"PrefixAndOtherAlt_2": [],
"PrefixOpWithActionAndLabel_1": [],
"PrefixOpWithActionAndLabel_2": [],
"PrefixOpWithActionAndLabel_3": [],

View File

@ -0,0 +1,24 @@
TestType() ::= "Parser"
Options ::= [
"Debug": false
]
Grammar ::= [
"T": {<grammar("T")>}
]
Rule() ::= "s"
grammar(grammarName) ::= <<
grammar <grammarName>;
s @after {<ToStringTree("$ctx"):writeln()>} : expr EOF ;
expr : literal
| op expr
| expr op expr
;
literal : '-'? Integer ;
op : '+' | '-' ;
Integer : [0-9]+ ;
WS : (' '|'\n') -> skip ;
>>

View File

@ -0,0 +1,9 @@
import "PrefixAndOtherAlt.stg"
Input() ::= "-1"
Output() ::= <<
(s (expr (literal - 1)) \<EOF>)<\n>
>>
Errors() ::= ""

View File

@ -0,0 +1,9 @@
import "PrefixAndOtherAlt.stg"
Input() ::= "-1 + -1"
Output() ::= <<
(s (expr (expr (literal - 1)) (op +) (expr (literal - 1))) \<EOF>)<\n>
>>
Errors() ::= ""

View File

@ -1801,6 +1801,50 @@ public class TestLeftRecursion extends BaseTest {
assertEquals("(prog (statement (letterA a)) (statement (letterA a)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testPrefixAndOtherAlt_1() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(223);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("s @after {Console.WriteLine($ctx.ToStringTree(this));} : expr EOF ; \n");
grammarBuilder.append("expr : literal\n");
grammarBuilder.append(" | op expr\n");
grammarBuilder.append(" | expr op expr\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("literal : '-'? Integer ;\n");
grammarBuilder.append("op : '+' | '-' ;\n");
grammarBuilder.append("Integer : [0-9]+ ;\n");
grammarBuilder.append("WS : (' '|'\\n') -> skip ;");
String grammar = grammarBuilder.toString();
String input ="-1";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", input, false);
assertEquals("(s (expr (literal - 1)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testPrefixAndOtherAlt_2() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(223);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("s @after {Console.WriteLine($ctx.ToStringTree(this));} : expr EOF ; \n");
grammarBuilder.append("expr : literal\n");
grammarBuilder.append(" | op expr\n");
grammarBuilder.append(" | expr op expr\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("literal : '-'? Integer ;\n");
grammarBuilder.append("op : '+' | '-' ;\n");
grammarBuilder.append("Integer : [0-9]+ ;\n");
grammarBuilder.append("WS : (' '|'\\n') -> skip ;");
String grammar = grammarBuilder.toString();
String input ="-1 + -1";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", input, false);
assertEquals("(s (expr (expr (literal - 1)) (op +) (expr (literal - 1))) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test

View File

@ -2007,6 +2007,58 @@ public class TestLeftRecursion extends BaseTest {
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testPrefixAndOtherAlt_1() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(224);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("s @after {System.out.println($ctx.toStringTree(this));} : expr EOF ; \n");
grammarBuilder.append("expr : literal\n");
grammarBuilder.append(" | op expr\n");
grammarBuilder.append(" | expr op expr\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("literal : '-'? Integer ;\n");
grammarBuilder.append("op : '+' | '-' ;\n");
grammarBuilder.append("Integer : [0-9]+ ;\n");
grammarBuilder.append("WS : (' '|'\\n') -> skip ;");
String grammar = grammarBuilder.toString();
String input ="-1";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", input, false);
assertEquals("(s (expr (literal - 1)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testPrefixAndOtherAlt_2() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(224);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("s @after {System.out.println($ctx.toStringTree(this));} : expr EOF ; \n");
grammarBuilder.append("expr : literal\n");
grammarBuilder.append(" | op expr\n");
grammarBuilder.append(" | expr op expr\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("literal : '-'? Integer ;\n");
grammarBuilder.append("op : '+' | '-' ;\n");
grammarBuilder.append("Integer : [0-9]+ ;\n");
grammarBuilder.append("WS : (' '|'\\n') -> skip ;");
String grammar = grammarBuilder.toString();
String input ="-1 + -1";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "s", input, false);
assertEquals("(s (expr (expr (literal - 1)) (op +) (expr (literal - 1))) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testPrefixOpWithActionAndLabel_1() throws Exception {

View File

@ -1905,6 +1905,54 @@ public class TestLeftRecursion extends BaseTest {
assertEquals("(prog (statement (letterA a)) (statement (letterA a)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testPrefixAndOtherAlt_1() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(223);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("s @after {console.log($ctx.toStringTree(null, this));} : expr EOF ; \n");
grammarBuilder.append("expr : literal\n");
grammarBuilder.append(" | op expr\n");
grammarBuilder.append(" | expr op expr\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("literal : '-'? Integer ;\n");
grammarBuilder.append("op : '+' | '-' ;\n");
grammarBuilder.append("Integer : [0-9]+ ;\n");
grammarBuilder.append("WS : (' '|'\\n') -> skip ;");
String grammar = grammarBuilder.toString();
String input ="-1";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"TListener", "TVisitor",
"s", input, false);
assertEquals("(s (expr (literal - 1)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testPrefixAndOtherAlt_2() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(223);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("s @after {console.log($ctx.toStringTree(null, this));} : expr EOF ; \n");
grammarBuilder.append("expr : literal\n");
grammarBuilder.append(" | op expr\n");
grammarBuilder.append(" | expr op expr\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("literal : '-'? Integer ;\n");
grammarBuilder.append("op : '+' | '-' ;\n");
grammarBuilder.append("Integer : [0-9]+ ;\n");
grammarBuilder.append("WS : (' '|'\\n') -> skip ;");
String grammar = grammarBuilder.toString();
String input ="-1 + -1";
String found = execParser("T.g4", grammar, "TParser", "TLexer",
"TListener", "TVisitor",
"s", input, false);
assertEquals("(s (expr (expr (literal - 1)) (op +) (expr (literal - 1))) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test

View File

@ -2058,6 +2058,60 @@ public class TestLeftRecursion extends BasePython2Test {
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testPrefixAndOtherAlt_1() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(216);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("s @after {print($ctx.toStringTree(recog=self))} : expr EOF ; \n");
grammarBuilder.append("expr : literal\n");
grammarBuilder.append(" | op expr\n");
grammarBuilder.append(" | expr op expr\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("literal : '-'? Integer ;\n");
grammarBuilder.append("op : '+' | '-' ;\n");
grammarBuilder.append("Integer : [0-9]+ ;\n");
grammarBuilder.append("WS : (' '|'\\n') -> skip ;");
String grammar = grammarBuilder.toString();
String input ="-1";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "TListener", "TVisitor", "s", input, false);
assertEquals("(s (expr (literal - 1)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testPrefixAndOtherAlt_2() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(216);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("s @after {print($ctx.toStringTree(recog=self))} : expr EOF ; \n");
grammarBuilder.append("expr : literal\n");
grammarBuilder.append(" | op expr\n");
grammarBuilder.append(" | expr op expr\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("literal : '-'? Integer ;\n");
grammarBuilder.append("op : '+' | '-' ;\n");
grammarBuilder.append("Integer : [0-9]+ ;\n");
grammarBuilder.append("WS : (' '|'\\n') -> skip ;");
String grammar = grammarBuilder.toString();
String input ="-1 + -1";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "TListener", "TVisitor", "s", input, false);
assertEquals("(s (expr (expr (literal - 1)) (op +) (expr (literal - 1))) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testPrefixOpWithActionAndLabel_1() throws Exception {

View File

@ -2058,6 +2058,60 @@ public class TestLeftRecursion extends BasePython3Test {
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testPrefixAndOtherAlt_1() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(216);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("s @after {print($ctx.toStringTree(recog=self))} : expr EOF ; \n");
grammarBuilder.append("expr : literal\n");
grammarBuilder.append(" | op expr\n");
grammarBuilder.append(" | expr op expr\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("literal : '-'? Integer ;\n");
grammarBuilder.append("op : '+' | '-' ;\n");
grammarBuilder.append("Integer : [0-9]+ ;\n");
grammarBuilder.append("WS : (' '|'\\n') -> skip ;");
String grammar = grammarBuilder.toString();
String input ="-1";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "TListener", "TVisitor", "s", input, false);
assertEquals("(s (expr (literal - 1)) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testPrefixAndOtherAlt_2() throws Exception {
mkdir(tmpdir);
StringBuilder grammarBuilder = new StringBuilder(216);
grammarBuilder.append("grammar T;\n");
grammarBuilder.append("s @after {print($ctx.toStringTree(recog=self))} : expr EOF ; \n");
grammarBuilder.append("expr : literal\n");
grammarBuilder.append(" | op expr\n");
grammarBuilder.append(" | expr op expr\n");
grammarBuilder.append(" ;\n");
grammarBuilder.append("literal : '-'? Integer ;\n");
grammarBuilder.append("op : '+' | '-' ;\n");
grammarBuilder.append("Integer : [0-9]+ ;\n");
grammarBuilder.append("WS : (' '|'\\n') -> skip ;");
String grammar = grammarBuilder.toString();
String input ="-1 + -1";
String found = execParser("T.g4", grammar, "TParser", "TLexer", "TListener", "TVisitor", "s", input, false);
assertEquals("(s (expr (expr (literal - 1)) (op +) (expr (literal - 1))) <EOF>)\n", found);
assertNull(this.stderrDuringParse);
}
/* This file and method are generated by TestGenerator, any edits will be overwritten by the next generation. */
@Test
public void testPrefixOpWithActionAndLabel_1() throws Exception {

View File

@ -30,6 +30,12 @@
package org.antlr.v4.analysis;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.antlr.runtime.CommonToken;
import org.antlr.runtime.Token;
import org.antlr.runtime.TokenStream;
@ -51,12 +57,6 @@ import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupFile;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/** Using a tree walker on the rules, determine if a rule is directly left-recursive and if it follows
* our pattern.
*/
@ -69,7 +69,6 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
public LinkedHashMap<Integer, LeftRecursiveRuleAltInfo> ternaryAlts = new LinkedHashMap<Integer, LeftRecursiveRuleAltInfo>();
public LinkedHashMap<Integer, LeftRecursiveRuleAltInfo> suffixAlts = new LinkedHashMap<Integer, LeftRecursiveRuleAltInfo>();
public List<LeftRecursiveRuleAltInfo> prefixAlts = new ArrayList<LeftRecursiveRuleAltInfo>();
public List<LeftRecursiveRuleAltInfo> otherAlts = new ArrayList<LeftRecursiveRuleAltInfo>();
/** Pointer to ID node of ^(= ID element) */
public List<Pair<GrammarAST,String>> leftRecursiveRuleRefLabels =
@ -222,7 +221,9 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
String altLabel = altTree.altLabel!=null ? altTree.altLabel.getText() : null;
LeftRecursiveRuleAltInfo a =
new LeftRecursiveRuleAltInfo(alt, altText, null, altLabel, false, originalAltTree);
otherAlts.add(a);
// We keep other alts with prefix alts since they are all added to the start of the generated rule, and
// we want to retain any prior ordering between them
prefixAlts.add(a);
// System.out.println("otherAlt " + alt + ": " + altText);
}
@ -255,7 +256,6 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
}
ruleST.add("primaryAlts", prefixAlts);
ruleST.add("primaryAlts", otherAlts);
tool.log("left-recursion", ruleST.render());
@ -440,7 +440,6 @@ public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
", ternaryAlts=" + ternaryAlts +
", suffixAlts=" + suffixAlts +
", prefixAlts=" + prefixAlts +
", otherAlts=" + otherAlts +
'}';
}
}

View File

@ -169,7 +169,6 @@ public class LeftRecursiveRuleTransformer {
// track recursive alt info for codegen
r.recPrimaryAlts = new ArrayList<LeftRecursiveRuleAltInfo>();
r.recPrimaryAlts.addAll(leftRecursiveRuleWalker.prefixAlts);
r.recPrimaryAlts.addAll(leftRecursiveRuleWalker.otherAlts);
if (r.recPrimaryAlts.isEmpty()) {
tool.errMgr.grammarError(ErrorType.NO_NON_LR_ALTS, g.fileName, ((GrammarAST)r.ast.getChild(0)).getToken(), r.name);
}