forked from jasder/antlr
DFA adaptive edge map optimization
This commit is contained in:
parent
f5f3861cb7
commit
bcfca2009e
|
@ -44,7 +44,7 @@ public abstract class ATNSimulator {
|
|||
public final ATN atn;
|
||||
|
||||
static {
|
||||
ERROR = new DFAState(new ATNConfigSet());
|
||||
ERROR = new DFAState(new ATNConfigSet(), 0, 0);
|
||||
ERROR.stateNumber = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
|
|
|
@ -217,8 +217,8 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
}
|
||||
|
||||
// if no edge, pop over to ATN interpreter, update DFA and return
|
||||
if ( s.edges == null || t >= s.edges.length || t <= CharStream.EOF ||
|
||||
s.edges[t] == null )
|
||||
DFAState target = s.getTarget(t);
|
||||
if ( target == null )
|
||||
{
|
||||
try {
|
||||
ATN_failover++;
|
||||
|
@ -229,9 +229,10 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
break loop; // dead end; no where to go, fall back on prev
|
||||
}
|
||||
}
|
||||
else if ( target == ERROR ) {
|
||||
break;
|
||||
}
|
||||
|
||||
DFAState target = s.edges[t];
|
||||
if ( target == ERROR ) break;
|
||||
s = target;
|
||||
|
||||
if ( s.isAcceptState ) {
|
||||
|
@ -593,16 +594,9 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
}
|
||||
|
||||
protected void addDFAEdge(@NotNull DFAState p, int t, @NotNull DFAState q) {
|
||||
if (t < 0 || t > MAX_DFA_EDGE) return; // Only track edges within the DFA bounds
|
||||
if ( p.edges==null ) {
|
||||
// make room for tokens 1..n and -1 masquerading as index 0
|
||||
p.edges = new DFAState[MAX_DFA_EDGE+1]; // TODO: make adaptive
|
||||
if ( p!=null ) {
|
||||
p.setTarget(t, q);
|
||||
}
|
||||
// if ( t==Token.EOF ) {
|
||||
// System.out.println("state "+p+" has EOF edge");
|
||||
// t = 0;
|
||||
// }
|
||||
p.edges[t] = q; // connect
|
||||
}
|
||||
|
||||
/** Add a new DFA state if there isn't one with this set of
|
||||
|
@ -629,7 +623,7 @@ public class LexerATNSimulator extends ATNSimulator {
|
|||
*/
|
||||
@Nullable
|
||||
protected DFAState addDFAState(@NotNull ATNConfigSet configs) {
|
||||
DFAState proposed = new DFAState(configs);
|
||||
DFAState proposed = new DFAState(configs, 0, MAX_DFA_EDGE);
|
||||
DFAState existing = dfa[mode].states.get(proposed);
|
||||
if ( existing!=null ) return existing;
|
||||
|
||||
|
|
|
@ -365,7 +365,8 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
break;
|
||||
}
|
||||
// if no edge, pop over to ATN interpreter, update DFA and return
|
||||
if ( s.edges == null || t >= s.edges.length || t < -1 || s.edges[t+1] == null ) {
|
||||
DFAState target = s.getTarget(t);
|
||||
if ( target == null ) {
|
||||
if ( dfa_debug && t>=0 ) System.out.println("no edge for "+parser.getTokenNames()[t]);
|
||||
int alt = -1;
|
||||
if ( dfa_debug ) {
|
||||
|
@ -379,10 +380,10 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
// same alt; e.g., s0-A->:s1=>2-B->:s2=>2
|
||||
// TODO: This next stuff kills edge, but extra states remain. :(
|
||||
if ( s.isAcceptState && alt!=-1 ) {
|
||||
DFAState d = s.edges[input.LA(1)+1];
|
||||
DFAState d = s.getTarget(input.LA(1));
|
||||
if ( d.isAcceptState && d.prediction==s.prediction ) {
|
||||
// we can carve it out.
|
||||
s.edges[input.LA(1)+1] = ERROR; // IGNORE really not error
|
||||
s.setTarget(input.LA(1), ERROR); // IGNORE really not error
|
||||
}
|
||||
}
|
||||
if ( dfa_debug ) {
|
||||
|
@ -399,8 +400,7 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
throw nvae;
|
||||
}
|
||||
}
|
||||
DFAState target = s.edges[t+1];
|
||||
if ( target == ERROR ) {
|
||||
else if ( target == ERROR ) {
|
||||
throw noViableAlt(input, outerContext, s.configset, startIndex);
|
||||
}
|
||||
s = target;
|
||||
|
@ -1290,17 +1290,15 @@ public class ParserATNSimulator<Symbol> extends ATNSimulator {
|
|||
}
|
||||
|
||||
protected void addDFAEdge(@Nullable DFAState p, int t, @Nullable DFAState q) {
|
||||
if ( p==null || t < -1 || q == null ) return;
|
||||
if ( p.edges==null ) {
|
||||
p.edges = new DFAState[atn.maxTokenType+1+1]; // TODO: make adaptive
|
||||
if ( p!=null ) {
|
||||
p.setTarget(t, q);
|
||||
}
|
||||
p.edges[t+1] = q; // connect
|
||||
}
|
||||
|
||||
/** See comment on LexerInterpreter.addDFAState. */
|
||||
@Nullable
|
||||
protected DFAState addDFAState(@NotNull DFA dfa, @NotNull ATNConfigSet configs) {
|
||||
DFAState proposed = new DFAState(configs);
|
||||
DFAState proposed = new DFAState(configs, -1, atn.maxTokenType);
|
||||
DFAState existing = dfa.states.get(proposed);
|
||||
if ( existing!=null ) return existing;
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* [The "BSD license"]
|
||||
* Copyright (c) 2012 Sam Harwell
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.antlr.v4.runtime.dfa;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sam Harwell
|
||||
*/
|
||||
public abstract class AbstractEdgeMap<T> implements EdgeMap<T> {
|
||||
|
||||
protected final int minIndex;
|
||||
protected final int maxIndex;
|
||||
|
||||
public AbstractEdgeMap(int minIndex, int maxIndex) {
|
||||
this.minIndex = minIndex;
|
||||
this.maxIndex = maxIndex;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* [The "BSD license"]
|
||||
* Copyright (c) 2012 Sam Harwell
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.antlr.v4.runtime.dfa;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author sam
|
||||
*/
|
||||
public class ArrayEdgeMap<T> extends AbstractEdgeMap<T> {
|
||||
|
||||
private final T[] arrayData;
|
||||
private int size;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ArrayEdgeMap(int minIndex, int maxIndex) {
|
||||
super(minIndex, maxIndex);
|
||||
arrayData = (T[])new Object[maxIndex - minIndex + 1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(int key) {
|
||||
return get(key) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(int key) {
|
||||
if (key < minIndex || key > maxIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return arrayData[key - minIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayEdgeMap<T> put(int key, T value) {
|
||||
if (key >= minIndex && key <= maxIndex) {
|
||||
T existing = arrayData[key - minIndex];
|
||||
arrayData[key - minIndex] = value;
|
||||
if (existing == null && value != null) {
|
||||
size++;
|
||||
} else if (existing != null && value == null) {
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayEdgeMap<T> remove(int key) {
|
||||
return put(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayEdgeMap<T> putAll(EdgeMap<? extends T> m) {
|
||||
if (m instanceof ArrayEdgeMap<?>) {
|
||||
ArrayEdgeMap<? extends T> other = (ArrayEdgeMap<? extends T>)m;
|
||||
int minOverlap = Math.max(minIndex, other.minIndex);
|
||||
int maxOverlap = Math.min(maxIndex, other.maxIndex);
|
||||
if (minOverlap > maxIndex || maxOverlap < minIndex) {
|
||||
int removed = 0;
|
||||
for (int i = minOverlap - this.minIndex; i <= maxOverlap - this.minIndex; i++) {
|
||||
if (arrayData[i] != null) {
|
||||
removed++;
|
||||
}
|
||||
}
|
||||
|
||||
int added = 0;
|
||||
for (int i = minOverlap - other.minIndex; i <= maxOverlap - other.minIndex; i++) {
|
||||
if (other.arrayData[i] != null) {
|
||||
added++;
|
||||
}
|
||||
}
|
||||
|
||||
System.arraycopy(other.arrayData, minOverlap - other.minIndex, this.arrayData, minOverlap - this.minIndex, maxOverlap - minOverlap + 1);
|
||||
size = size + added - removed;
|
||||
}
|
||||
|
||||
return this;
|
||||
} else if (m instanceof SingletonEdgeMap<?>) {
|
||||
SingletonEdgeMap<? extends T> other = (SingletonEdgeMap<? extends T>)m;
|
||||
return put(other.getKey(), other.getValue());
|
||||
} else if (m instanceof SparseEdgeMap<?>) {
|
||||
SparseEdgeMap<? extends T> other = (SparseEdgeMap<? extends T>)m;
|
||||
int[] keys = other.getKeys();
|
||||
List<? extends T> values = other.getValues();
|
||||
ArrayEdgeMap<T> result = this;
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
result = result.put(keys[i], values.get(i));
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
throw new UnsupportedOperationException(String.format("EdgeMap of type %s is supported yet.", m.getClass().getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayEdgeMap<T> clear() {
|
||||
Arrays.fill(arrayData, null);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, T> toMap() {
|
||||
if (isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<Integer, T> result = new HashMap<Integer, T>();
|
||||
for (int i = 0; i < arrayData.length; i++) {
|
||||
if (arrayData[i] == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result.put(i + minIndex, arrayData[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -53,13 +53,12 @@ public class DFASerializer {
|
|||
Map<DFAState,DFAState> states = dfa.states;
|
||||
if ( states!=null ) {
|
||||
for (DFAState s : states.values()) {
|
||||
int n = 0;
|
||||
if ( s.edges!=null ) n = s.edges.length;
|
||||
for (int i=0; i<n; i++) {
|
||||
DFAState t = s.edges[i];
|
||||
Map<Integer, DFAState> edges = s.getEdgeMap();
|
||||
for (Map.Entry<Integer, DFAState> entry : edges.entrySet()) {
|
||||
DFAState t = entry.getValue();
|
||||
if ( t!=null && t.stateNumber != Integer.MAX_VALUE ) {
|
||||
buf.append(getStateString(s));
|
||||
String label = getEdgeLabel(i);
|
||||
String label = getEdgeLabel(entry.getKey());
|
||||
buf.append("-"+label+"->"+ getStateString(t)+'\n');
|
||||
}
|
||||
}
|
||||
|
@ -72,9 +71,9 @@ public class DFASerializer {
|
|||
|
||||
protected String getEdgeLabel(int i) {
|
||||
String label;
|
||||
if ( i==0 ) return "EOF";
|
||||
if ( tokenNames!=null ) label = tokenNames[i-1];
|
||||
else label = String.valueOf(i-1);
|
||||
if ( i==-1 ) return "EOF";
|
||||
if ( tokenNames!=null ) label = tokenNames[i];
|
||||
else label = String.valueOf(i);
|
||||
return label;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,8 +34,10 @@ import org.antlr.v4.runtime.atn.ATNConfigSet;
|
|||
import org.antlr.v4.runtime.atn.SemanticContext;
|
||||
import org.antlr.v4.runtime.misc.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/** A DFA state represents a set of possible ATN configurations.
|
||||
|
@ -74,7 +76,9 @@ public class DFAState {
|
|||
|
||||
/** edges[symbol] points to target of symbol */
|
||||
@Nullable
|
||||
public DFAState[] edges;
|
||||
private EdgeMap<DFAState> edges;
|
||||
private final int minSymbol;
|
||||
private final int maxSymbol;
|
||||
|
||||
public boolean isAcceptState = false;
|
||||
|
||||
|
@ -135,11 +139,35 @@ public class DFAState {
|
|||
}
|
||||
}
|
||||
|
||||
public DFAState() { }
|
||||
public DFAState(ATNConfigSet configs, int minSymbol, int maxSymbol) {
|
||||
this.configset = configs;
|
||||
this.minSymbol = minSymbol;
|
||||
this.maxSymbol = maxSymbol;
|
||||
}
|
||||
|
||||
public DFAState(int stateNumber) { this.stateNumber = stateNumber; }
|
||||
public DFAState getTarget(int symbol) {
|
||||
if (edges == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public DFAState(ATNConfigSet configs) { this.configset = configs; }
|
||||
return edges.get(symbol);
|
||||
}
|
||||
|
||||
public void setTarget(int symbol, DFAState target) {
|
||||
if (edges == null) {
|
||||
edges = new SingletonEdgeMap<DFAState>(minSymbol, maxSymbol);
|
||||
}
|
||||
|
||||
edges = edges.put(symbol, target);
|
||||
}
|
||||
|
||||
public Map<Integer, DFAState> getEdgeMap() {
|
||||
if (edges == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
return edges.toMap();
|
||||
}
|
||||
|
||||
/** Get the set of all alts mentioned by all ATN configurations in this
|
||||
* DFA state.
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* [The "BSD license"]
|
||||
* Copyright (c) 2012 Sam Harwell
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.antlr.v4.runtime.dfa;
|
||||
|
||||
//import java.util.Collection;
|
||||
|
||||
import java.util.Map;
|
||||
import org.antlr.v4.runtime.misc.NotNull;
|
||||
import org.antlr.v4.runtime.misc.Nullable;
|
||||
|
||||
//import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sam Harwell
|
||||
*/
|
||||
public interface EdgeMap<T> {
|
||||
|
||||
int size();
|
||||
|
||||
boolean isEmpty();
|
||||
|
||||
boolean containsKey(int key);
|
||||
|
||||
// boolean containsValue(T value);
|
||||
|
||||
@Nullable
|
||||
T get(int key);
|
||||
|
||||
@NotNull
|
||||
EdgeMap<T> put(int key, @Nullable T value);
|
||||
|
||||
@NotNull
|
||||
EdgeMap<T> remove(int key);
|
||||
|
||||
@NotNull
|
||||
EdgeMap<T> putAll(@NotNull EdgeMap<? extends T> m);
|
||||
|
||||
@NotNull
|
||||
EdgeMap<T> clear();
|
||||
|
||||
@NotNull
|
||||
Map<Integer, T> toMap();
|
||||
|
||||
// Set<Integer> keySet();
|
||||
//
|
||||
// Collection<T> values();
|
||||
//
|
||||
// Set<Entry<Integer, DFAState>> entrySet();
|
||||
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* [The "BSD license"]
|
||||
* Copyright (c) 2012 Sam Harwell
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.antlr.v4.runtime.dfa;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sam Harwell
|
||||
*/
|
||||
public class SingletonEdgeMap<T> extends AbstractEdgeMap<T> {
|
||||
|
||||
private int key;
|
||||
private T value;
|
||||
|
||||
public SingletonEdgeMap(int minIndex, int maxIndex) {
|
||||
super(minIndex, maxIndex);
|
||||
}
|
||||
|
||||
public SingletonEdgeMap(int minIndex, int maxIndex, int key, T value) {
|
||||
super(minIndex, maxIndex);
|
||||
if (key >= minIndex && key <= maxIndex) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return value != null ? 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return value == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(int key) {
|
||||
return key == this.key && value != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(int key) {
|
||||
if (key == this.key) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EdgeMap<T> put(int key, T value) {
|
||||
if (key < minIndex || key > maxIndex) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (key == this.key || this.value == null) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
return this;
|
||||
} else if (value != null) {
|
||||
EdgeMap<T> result = new SparseEdgeMap<T>(minIndex, maxIndex);
|
||||
result = result.put(this.key, this.value);
|
||||
result = result.put(key, value);
|
||||
return result;
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingletonEdgeMap<T> remove(int key) {
|
||||
if (key == this.key) {
|
||||
this.value = null;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EdgeMap<T> putAll(EdgeMap<? extends T> m) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SingletonEdgeMap<T> clear() {
|
||||
this.value = null;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, T> toMap() {
|
||||
if (isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
return Collections.singletonMap(key, value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* [The "BSD license"]
|
||||
* Copyright (c) 2012 Sam Harwell
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.antlr.v4.runtime.dfa;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sam Harwell
|
||||
*/
|
||||
public class SparseEdgeMap<T> extends AbstractEdgeMap<T> {
|
||||
private static final int DEFAULT_MAX_SIZE = 5;
|
||||
|
||||
private final int[] keys;
|
||||
private final List<T> values;
|
||||
|
||||
public SparseEdgeMap(int minIndex, int maxIndex) {
|
||||
this(minIndex, maxIndex, DEFAULT_MAX_SIZE);
|
||||
}
|
||||
|
||||
public SparseEdgeMap(int minIndex, int maxIndex, int maxSparseSize) {
|
||||
super(minIndex, maxIndex);
|
||||
this.keys = new int[maxSparseSize];
|
||||
this.values = new ArrayList<T>(maxSparseSize);
|
||||
}
|
||||
|
||||
public int[] getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
public List<T> getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
public int getMaxSparseSize() {
|
||||
return keys.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return values.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return values.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(int key) {
|
||||
return get(key) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(int key) {
|
||||
int index = Arrays.binarySearch(keys, 0, size(), key);
|
||||
if (index < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return values.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EdgeMap<T> put(int key, T value) {
|
||||
if (key < minIndex || key > maxIndex) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (value == null) {
|
||||
return remove(key);
|
||||
}
|
||||
|
||||
int index = Arrays.binarySearch(keys, 0, size(), key);
|
||||
if (index >= 0) {
|
||||
// replace existing entry
|
||||
values.set(index, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
assert index < 0 && value != null;
|
||||
if (size() < getMaxSparseSize()) {
|
||||
// stay sparse and add new entry
|
||||
int insertIndex = -index - 1;
|
||||
System.arraycopy(keys, insertIndex, keys, insertIndex + 1, keys.length - insertIndex - 1);
|
||||
keys[insertIndex] = key;
|
||||
values.add(insertIndex, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
assert size() == getMaxSparseSize();
|
||||
ArrayEdgeMap<T> arrayMap = new ArrayEdgeMap<T>(minIndex, maxIndex);
|
||||
arrayMap = arrayMap.putAll(this);
|
||||
arrayMap.put(key, value);
|
||||
return arrayMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SparseEdgeMap<T> remove(int key) {
|
||||
int index = Arrays.binarySearch(keys, 0, size(), key);
|
||||
if (index >= 0) {
|
||||
System.arraycopy(keys, index + 1, keys, index, size() - index - 1);
|
||||
values.remove(index);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EdgeMap<T> putAll(EdgeMap<? extends T> m) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SparseEdgeMap<T> clear() {
|
||||
values.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, T> toMap() {
|
||||
if (isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<Integer, T> result = new LinkedHashMap<Integer, T>();
|
||||
for (int i = 0; i < size(); i++) {
|
||||
result.put(keys[i], values.get(i));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
|
@ -84,22 +84,21 @@ public class DOTGenerator {
|
|||
}
|
||||
|
||||
for (DFAState d : dfa.states.keySet()) {
|
||||
if ( d.edges!=null ) {
|
||||
for (int i = 0; i < d.edges.length; i++) {
|
||||
DFAState target = d.edges[i];
|
||||
if ( target==null) continue;
|
||||
if ( target.stateNumber == Integer.MAX_VALUE ) continue;
|
||||
int ttype = i-1; // we shift up for EOF as -1 for parser
|
||||
String label = String.valueOf(ttype);
|
||||
if ( isLexer ) label = "'"+getEdgeLabel(String.valueOf((char) i))+"'";
|
||||
else if ( grammar!=null ) label = grammar.getTokenDisplayName(ttype);
|
||||
ST st = stlib.getInstanceOf("edge");
|
||||
st.add("label", label);
|
||||
st.add("src", "s"+d.stateNumber);
|
||||
st.add("target", "s"+target.stateNumber);
|
||||
st.add("arrowhead", arrowhead);
|
||||
dot.add("edges", st);
|
||||
}
|
||||
Map<Integer, DFAState> edges = d.getEdgeMap();
|
||||
for (Map.Entry<Integer, DFAState> entry : edges.entrySet()) {
|
||||
DFAState target = entry.getValue();
|
||||
if ( target==null) continue;
|
||||
if ( target.stateNumber == Integer.MAX_VALUE ) continue;
|
||||
int ttype = entry.getKey();
|
||||
String label = String.valueOf(ttype);
|
||||
if ( isLexer ) label = "'"+getEdgeLabel(String.valueOf((char)ttype))+"'";
|
||||
else if ( grammar!=null ) label = grammar.getTokenDisplayName(ttype);
|
||||
ST st = stlib.getInstanceOf("edge");
|
||||
st.add("label", label);
|
||||
st.add("src", "s"+d.stateNumber);
|
||||
st.add("target", "s"+target.stateNumber);
|
||||
st.add("arrowhead", arrowhead);
|
||||
dot.add("edges", st);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue