forked from jasder/antlr
Improved accuracy of implicit label analysis within alternatives
This commit is contained in:
parent
1b08a014d2
commit
751b063cae
|
@ -29,6 +29,9 @@
|
|||
|
||||
package org.antlr.v4.codegen.model;
|
||||
|
||||
import org.antlr.runtime.RecognitionException;
|
||||
import org.antlr.runtime.tree.CommonTreeNodeStream;
|
||||
import org.antlr.runtime.tree.TreeNodeStream;
|
||||
import org.antlr.v4.codegen.OutputModelFactory;
|
||||
import org.antlr.v4.codegen.model.decl.AltLabelStructDecl;
|
||||
import org.antlr.v4.codegen.model.decl.ContextRuleGetterDecl;
|
||||
|
@ -40,27 +43,32 @@ import org.antlr.v4.codegen.model.decl.ContextTokenListIndexedGetterDecl;
|
|||
import org.antlr.v4.codegen.model.decl.Decl;
|
||||
import org.antlr.v4.codegen.model.decl.StructDecl;
|
||||
import org.antlr.v4.misc.FrequencySet;
|
||||
import org.antlr.v4.misc.MutableInt;
|
||||
import org.antlr.v4.misc.Utils;
|
||||
import org.antlr.v4.parse.GrammarASTAdaptor;
|
||||
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.tool.Attribute;
|
||||
import org.antlr.v4.tool.ErrorType;
|
||||
import org.antlr.v4.tool.Rule;
|
||||
import org.antlr.v4.tool.ast.ActionAST;
|
||||
import org.antlr.v4.tool.ast.AltAST;
|
||||
import org.antlr.v4.tool.ast.GrammarAST;
|
||||
import org.antlr.v4.tool.ast.TerminalAST;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.antlr.v4.parse.ANTLRParser.CLOSURE;
|
||||
import static org.antlr.v4.parse.ANTLRParser.POSITIVE_CLOSURE;
|
||||
import static org.antlr.v4.parse.ANTLRParser.RULE_REF;
|
||||
import static org.antlr.v4.parse.ANTLRParser.TOKEN_REF;
|
||||
|
||||
|
@ -181,19 +189,9 @@ public class RuleFunction extends OutputModelObject {
|
|||
FrequencySet<String> altFreq = getElementFrequenciesForAlt(ast);
|
||||
for (GrammarAST t : refs) {
|
||||
String refLabelName = t.getText();
|
||||
if (needsList.contains(refLabelName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( altFreq.count(t.getText())>1 ) {
|
||||
if ( altFreq.count(refLabelName)>1 ) {
|
||||
needsList.add(refLabelName);
|
||||
}
|
||||
else {
|
||||
boolean inLoop = t.hasAncestor(CLOSURE) || t.hasAncestor(POSITIVE_CLOSURE);
|
||||
if (inLoop) {
|
||||
needsList.add(refLabelName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<Decl> decls = new HashSet<Decl>();
|
||||
|
@ -209,14 +207,19 @@ public class RuleFunction extends OutputModelObject {
|
|||
|
||||
/** Given list of X and r refs in alt, compute how many of each there are */
|
||||
protected FrequencySet<String> getElementFrequenciesForAlt(AltAST ast) {
|
||||
IntervalSet reftypes = new IntervalSet(RULE_REF, TOKEN_REF);
|
||||
List<GrammarAST> refs = ast.getNodesWithType(reftypes);
|
||||
FrequencySet<String> altFreq = new FrequencySet<String>();
|
||||
for (GrammarAST t : refs) {
|
||||
String refLabelName = t.getText();
|
||||
altFreq.add(refLabelName);
|
||||
try {
|
||||
ElementFrequenciesVisitor visitor = new ElementFrequenciesVisitor(new CommonTreeNodeStream(new GrammarASTAdaptor(), ast));
|
||||
visitor.outerAlternative();
|
||||
if (visitor.frequencies.size() != 1) {
|
||||
factory.getGrammar().tool.errMgr.toolError(ErrorType.INTERNAL_ERROR);
|
||||
return new FrequencySet<String>();
|
||||
}
|
||||
|
||||
return visitor.frequencies.peek();
|
||||
} catch (RecognitionException ex) {
|
||||
factory.getGrammar().tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, ex);
|
||||
return new FrequencySet<String>();
|
||||
}
|
||||
return altFreq;
|
||||
}
|
||||
|
||||
/** Get list of decls for token/rule refs.
|
||||
|
@ -231,14 +234,10 @@ public class RuleFunction extends OutputModelObject {
|
|||
TOKEN_REF);
|
||||
List<GrammarAST> refs = altAST.getNodesWithType(reftypes);
|
||||
Set<Decl> decls = new HashSet<Decl>();
|
||||
FrequencySet<String> freq = new FrequencySet<String>();
|
||||
for (GrammarAST t : refs) freq.add(t.getText());
|
||||
FrequencySet<String> freq = getElementFrequenciesForAlt(altAST);
|
||||
for (GrammarAST t : refs) {
|
||||
String refLabelName = t.getText();
|
||||
boolean inLoop = t.hasAncestor(CLOSURE) || t.hasAncestor(POSITIVE_CLOSURE);
|
||||
boolean multipleRefs = freq.count(refLabelName)>1;
|
||||
boolean needList = inLoop || multipleRefs;
|
||||
// System.out.println(altAST.toStringTree()+" "+t+" inLoop? "+inLoop);
|
||||
boolean needList = freq.count(refLabelName)>1;
|
||||
List<Decl> d = getDeclForAltElement(t, refLabelName, needList);
|
||||
decls.addAll(d);
|
||||
}
|
||||
|
@ -293,4 +292,129 @@ public class RuleFunction extends OutputModelObject {
|
|||
}
|
||||
ruleCtx.addDecl(d); // stick in overall rule's ctx
|
||||
}
|
||||
|
||||
protected static class ElementFrequenciesVisitor extends GrammarTreeVisitor {
|
||||
final Deque<FrequencySet<String>> frequencies;
|
||||
|
||||
public ElementFrequenciesVisitor(TreeNodeStream input) {
|
||||
super(input);
|
||||
frequencies = new ArrayDeque<FrequencySet<String>>();
|
||||
frequencies.push(new FrequencySet<String>());
|
||||
}
|
||||
|
||||
/*
|
||||
* Common
|
||||
*/
|
||||
|
||||
protected static FrequencySet<String> combineMax(FrequencySet<String> a, FrequencySet<String> b) {
|
||||
FrequencySet<String> result = combineAndClip(a, b, 1);
|
||||
for (Map.Entry<String, MutableInt> entry : a.entrySet()) {
|
||||
result.get(entry.getKey()).v = entry.getValue().v;
|
||||
}
|
||||
|
||||
for (Map.Entry<String, MutableInt> entry : a.entrySet()) {
|
||||
MutableInt slot = result.get(entry.getKey());
|
||||
slot.v = Math.max(slot.v, entry.getValue().v);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected static FrequencySet<String> combineAndClip(FrequencySet<String> a, FrequencySet<String> b, int clip) {
|
||||
FrequencySet<String> result = new FrequencySet<String>();
|
||||
for (Map.Entry<String, MutableInt> entry : a.entrySet()) {
|
||||
for (int i = 0; i < entry.getValue().v; i++) {
|
||||
result.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, MutableInt> entry : b.entrySet()) {
|
||||
for (int i = 0; i < entry.getValue().v; i++) {
|
||||
result.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, MutableInt> entry : result.entrySet()) {
|
||||
entry.getValue().v = Math.min(entry.getValue().v, clip);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tokenRef(TerminalAST ref) {
|
||||
frequencies.peek().add(ref.getText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ruleRef(GrammarAST ref, ActionAST arg) {
|
||||
frequencies.peek().add(ref.getText());
|
||||
}
|
||||
|
||||
/*
|
||||
* Parser rules
|
||||
*/
|
||||
|
||||
@Override
|
||||
protected void enterAlternative(AltAST tree) {
|
||||
frequencies.push(new FrequencySet<String>());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exitAlternative(AltAST tree) {
|
||||
frequencies.push(combineMax(frequencies.pop(), frequencies.pop()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enterElement(GrammarAST tree) {
|
||||
frequencies.push(new FrequencySet<String>());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exitElement(GrammarAST tree) {
|
||||
frequencies.push(combineAndClip(frequencies.pop(), frequencies.pop(), 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exitSubrule(GrammarAST tree) {
|
||||
if (tree.getType() == CLOSURE || tree.getType() == POSITIVE_CLOSURE) {
|
||||
for (Map.Entry<String, MutableInt> entry : frequencies.peek().entrySet()) {
|
||||
entry.getValue().v = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Lexer rules
|
||||
*/
|
||||
|
||||
@Override
|
||||
protected void enterLexerAlternative(GrammarAST tree) {
|
||||
frequencies.push(new FrequencySet<String>());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exitLexerAlternative(GrammarAST tree) {
|
||||
frequencies.push(combineMax(frequencies.pop(), frequencies.pop()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enterLexerElement(GrammarAST tree) {
|
||||
frequencies.push(new FrequencySet<String>());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exitLexerElement(GrammarAST tree) {
|
||||
frequencies.push(combineAndClip(frequencies.pop(), frequencies.pop(), 2));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exitLexerSubrule(GrammarAST tree) {
|
||||
if (tree.getType() == CLOSURE || tree.getType() == POSITIVE_CLOSURE) {
|
||||
for (Map.Entry<String, MutableInt> entry : frequencies.peek().entrySet()) {
|
||||
entry.getValue().v = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue