Merge pull request #501 from sharwell/fix-433

Fix 433
This commit is contained in:
Terence Parr 2014-03-23 11:30:00 -07:00
commit 794e4a0b7b
6 changed files with 103 additions and 57 deletions

View File

@ -30,7 +30,7 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.runtime.misc.Triple;
import org.antlr.v4.runtime.misc.Pair;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.ActionAST;
@ -38,6 +38,7 @@ import org.antlr.v4.tool.ast.AltAST;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** A model object representing a parse tree listener file.
@ -57,10 +58,10 @@ public class ListenerFile extends OutputFile {
parserName = g.getRecognizerName();
grammarName = g.name;
for (Rule r : g.rules.values()) {
List<Triple<Integer,AltAST,String>> labels = r.getAltLabels();
Map<String, List<Pair<Integer,AltAST>>> labels = r.getAltLabels();
if ( labels!=null ) {
for (Triple<Integer,AltAST,String> pair : labels) {
listenerNames.add(pair.c);
for (Map.Entry<String, List<Pair<Integer, AltAST>>> pair : labels.entrySet()) {
listenerNames.add(pair.getKey());
}
}
else {

View File

@ -51,7 +51,7 @@ import org.antlr.v4.parse.GrammarTreeVisitor;
import org.antlr.v4.runtime.atn.ATNState;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.antlr.v4.runtime.misc.OrderedHashSet;
import org.antlr.v4.runtime.misc.Triple;
import org.antlr.v4.runtime.misc.Pair;
import org.antlr.v4.tool.Attribute;
import org.antlr.v4.tool.ErrorType;
import org.antlr.v4.tool.Rule;
@ -149,17 +149,28 @@ public class RuleFunction extends OutputModelObject {
// make structs for -> labeled alts, define ctx labels for elements
altLabelCtxs = new HashMap<String,AltLabelStructDecl>();
List<Triple<Integer,AltAST,String>> labels = r.getAltLabels();
Map<String, List<Pair<Integer, AltAST>>> labels = r.getAltLabels();
if ( labels!=null ) {
for (Triple<Integer,AltAST,String> pair : labels) {
Integer altNum = pair.a;
AltAST altAST = pair.b;
String label = pair.c;
altToContext[altNum] = new AltLabelStructDecl(factory, r, altNum, label);
altLabelCtxs.put(label, altToContext[altNum]);
Set<Decl> decls = getDeclsForAltElements(altAST);
// we know which ctx to put in, so do it directly
for (Decl d : decls) altToContext[altNum].addDecl(d);
for (Map.Entry<String, List<Pair<Integer, AltAST>>> entry : labels.entrySet()) {
String label = entry.getKey();
List<AltAST> alts = new ArrayList<AltAST>();
for (Pair<Integer, AltAST> pair : entry.getValue()) {
alts.add(pair.b);
}
Set<Decl> decls = getDeclsForAllElements(alts);
for (Pair<Integer, AltAST> pair : entry.getValue()) {
Integer altNum = pair.a;
altToContext[altNum] = new AltLabelStructDecl(factory, r, altNum, label);
if (!altLabelCtxs.containsKey(label)) {
altLabelCtxs.put(label, altToContext[altNum]);
}
// we know which ctx to put in, so do it directly
for (Decl d : decls) {
altToContext[altNum].addDecl(d);
}
}
}
}
}
@ -223,28 +234,6 @@ public class RuleFunction extends OutputModelObject {
}
}
/** Get list of decls for token/rule refs.
* Single ref X becomes X() getter
* Multiple refs to X becomes List X() method, X(int i) method.
* Ref X in a loop then we get List X(), X(int i)
*
* Does not gen labels for literals like '+', 'begin', ';', ...
*/
public Set<Decl> getDeclsForAltElements(AltAST altAST) {
IntervalSet reftypes = new IntervalSet(RULE_REF,
TOKEN_REF);
List<GrammarAST> refs = altAST.getNodesWithType(reftypes);
Set<Decl> decls = new HashSet<Decl>();
FrequencySet<String> freq = getElementFrequenciesForAlt(altAST);
for (GrammarAST t : refs) {
String refLabelName = t.getText();
boolean needList = freq.count(refLabelName)>1;
List<Decl> d = getDeclForAltElement(t, refLabelName, needList);
decls.addAll(d);
}
return decls;
}
public List<Decl> getDeclForAltElement(GrammarAST t, String refLabelName, boolean needList) {
List<Decl> decls = new ArrayList<Decl>();
if ( t.getType()==RULE_REF ) {

View File

@ -30,7 +30,7 @@
package org.antlr.v4.codegen.model;
import org.antlr.v4.codegen.OutputModelFactory;
import org.antlr.v4.runtime.misc.Triple;
import org.antlr.v4.runtime.misc.Pair;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.Rule;
import org.antlr.v4.tool.ast.ActionAST;
@ -38,6 +38,7 @@ import org.antlr.v4.tool.ast.AltAST;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class VisitorFile extends OutputFile {
@ -54,10 +55,10 @@ public class VisitorFile extends OutputFile {
parserName = g.getRecognizerName();
grammarName = g.name;
for (Rule r : g.rules.values()) {
List<Triple<Integer,AltAST,String>> labels = r.getAltLabels();
Map<String, List<Pair<Integer, AltAST>>> labels = r.getAltLabels();
if ( labels!=null ) {
for (Triple<Integer,AltAST,String> pair : labels) {
visitorNames.add(pair.c);
for (Map.Entry<String, List<Pair<Integer, AltAST>>> pair : labels.entrySet()) {
visitorNames.add(pair.getKey());
}
}
else {

View File

@ -33,13 +33,14 @@ package org.antlr.v4.tool;
import org.antlr.v4.analysis.LeftRecursiveRuleAltInfo;
import org.antlr.v4.misc.OrderedHashMap;
import org.antlr.v4.runtime.misc.Pair;
import org.antlr.v4.runtime.misc.Triple;
import org.antlr.v4.tool.ast.AltAST;
import org.antlr.v4.tool.ast.GrammarAST;
import org.antlr.v4.tool.ast.RuleAST;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class LeftRecursiveRule extends Rule {
public List<LeftRecursiveRuleAltInfo> recPrimaryAlts;
@ -84,16 +85,20 @@ public class LeftRecursiveRule extends Rule {
/** Get -> labels from those alts we deleted for left-recursive rules. */
@Override
public List<Triple<Integer,AltAST,String>> getAltLabels() {
List<Triple<Integer,AltAST,String>> labels = new ArrayList<Triple<Integer,AltAST,String>>();
List<Triple<Integer,AltAST,String>> normalAltLabels = super.getAltLabels();
if ( normalAltLabels!=null ) labels.addAll(normalAltLabels);
public Map<String, List<Pair<Integer, AltAST>>> getAltLabels() {
Map<String, List<Pair<Integer, AltAST>>> labels = new HashMap<String, List<Pair<Integer, AltAST>>>();
Map<String, List<Pair<Integer, AltAST>>> normalAltLabels = super.getAltLabels();
if ( normalAltLabels!=null ) labels.putAll(normalAltLabels);
if ( recPrimaryAlts!=null ) {
for (LeftRecursiveRuleAltInfo altInfo : recPrimaryAlts) {
if (altInfo.altLabel != null) {
labels.add(new Triple<Integer, AltAST, String>(altInfo.altNum,
altInfo.originalAltAST,
altInfo.altLabel));
List<Pair<Integer, AltAST>> pairs = labels.get(altInfo.altLabel);
if (pairs == null) {
pairs = new ArrayList<Pair<Integer, AltAST>>();
labels.put(altInfo.altLabel, pairs);
}
pairs.add(new Pair<Integer, AltAST>(altInfo.altNum, altInfo.originalAltAST));
}
}
}
@ -101,9 +106,13 @@ public class LeftRecursiveRule extends Rule {
for (int i = 0; i < recOpAlts.size(); i++) {
LeftRecursiveRuleAltInfo altInfo = recOpAlts.getElement(i);
if ( altInfo.altLabel!=null ) {
labels.add(new Triple<Integer,AltAST,String>(altInfo.altNum,
altInfo.originalAltAST,
altInfo.altLabel));
List<Pair<Integer, AltAST>> pairs = labels.get(altInfo.altLabel);
if (pairs == null) {
pairs = new ArrayList<Pair<Integer, AltAST>>();
labels.put(altInfo.altLabel, pairs);
}
pairs.add(new Pair<Integer, AltAST>(altInfo.altNum, altInfo.originalAltAST));
}
}
}

View File

@ -30,7 +30,7 @@
package org.antlr.v4.tool;
import org.antlr.v4.runtime.misc.Triple;
import org.antlr.v4.runtime.misc.Pair;
import org.antlr.v4.tool.ast.ActionAST;
import org.antlr.v4.tool.ast.AltAST;
import org.antlr.v4.tool.ast.GrammarAST;
@ -205,13 +205,24 @@ public class Rule implements AttributeResolver {
return numberOfAlts;
}
/** Get -> labels. */
public List<Triple<Integer,AltAST,String>> getAltLabels() {
List<Triple<Integer,AltAST,String>> labels = new ArrayList<Triple<Integer,AltAST,String>>();
/**
* Get {@code #} labels. The keys of the map are the labels applied to outer
* alternatives of a lexer rule, and the values are collections of pairs
* (alternative number and {@link AltAST}) identifying the alternatives with
* this label. Unlabeled alternatives are not included in the result.
*/
public Map<String, List<Pair<Integer, AltAST>>> getAltLabels() {
Map<String, List<Pair<Integer, AltAST>>> labels = new HashMap<String, List<Pair<Integer, AltAST>>>();
for (int i=1; i<=numberOfAlts; i++) {
GrammarAST altLabel = alt[i].ast.altLabel;
if ( altLabel!=null ) {
labels.add(new Triple<Integer,AltAST,String>(i,alt[i].ast,altLabel.getText()));
List<Pair<Integer, AltAST>> list = labels.get(altLabel.getText());
if (list == null) {
list = new ArrayList<Pair<Integer, AltAST>>();
labels.put(altLabel.getText(), list);
}
list.add(new Pair<Integer, AltAST>(i, alt[i].ast));
}
}
if ( labels.isEmpty() ) return null;

View File

@ -339,6 +339,41 @@ public class TestLeftRecursion extends BaseTest {
runTests(grammar, tests, "s");
}
/**
* This is a regression test for antlr/antlr4#433 "Not all context accessor
* methods are generated when an alternative rule label is used for multiple
* alternatives".
* https://github.com/antlr/antlr4/issues/433
*/
@Test public void testMultipleAlternativesWithCommonLabel() throws Exception {
String grammar =
"grammar T;\n" +
"s : e {System.out.println($e.v);} ;\n" +
"\n" +
"e returns [int v]\n" +
" : e '*' e {$v = ((BinaryContext)$ctx).e(0).v * ((BinaryContext)$ctx).e(1).v;} # binary\n" +
" | e '+' e {$v = ((BinaryContext)$ctx).e(0).v + ((BinaryContext)$ctx).e(1).v;} # binary\n" +
" | INT {$v = $INT.int;} # anInt\n" +
" | '(' e ')' {$v = $e.v;} # parens\n" +
" | left=e INC {assert(((UnaryContext)$ctx).INC() != null); $v = $left.v + 1;} # unary\n" +
" | left=e DEC {assert(((UnaryContext)$ctx).DEC() != null); $v = $left.v - 1;} # unary\n" +
" | ID {$v = 3;} # anID\n" +
" ; \n" +
"\n" +
"ID : 'a'..'z'+ ;\n" +
"INT : '0'..'9'+ ;\n" +
"INC : '++' ;\n" +
"DEC : '--' ;\n" +
"WS : (' '|'\\n') -> skip ;\n";
String[] tests = {
"4", "4",
"1+2", "3",
"1+2*3", "7",
"i++*3", "12",
};
runTests(grammar, tests, "s");
}
@Test public void testPrefixOpWithActionAndLabel() throws Exception {
String grammar =
"grammar T;\n" +