/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This file is part of SableCC. *
* See the file "LICENSE" for copyright information and the *
* terms and conditions for copying, distribution and *
* modification of SableCC. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package org.sablecc.sablecc;
import java.util.Hashtable;
import java.util.Vector;
@SuppressWarnings({"rawtypes", "unchecked"})
public class DFA {
public DFA(NFA nfa) {
this.nfa = nfa;
construct();
optimize();
}
public NFA nfa;
public final Vector states = new Vector(0);
public final Hashtable finder = new Hashtable(1);
private void optimize() {
Vector transitions = new Vector(0);
for (int i = 0; i < states.size(); i++) {
DFA.State state = (DFA.State) states.elementAt(i);
transitions.addElement(new Vector(0));
for (int j = 0; j < state.transitions.size(); j++) {
int max = 0;
int st = -1;
for (int k = 0; k < i; k++) {
int match = match(i, j, k);
if (match > max) {
max = match;
st = k;
}
}
if (max < 2) {
((Vector) transitions.elementAt(i)).addElement(
state.transitions.elementAt(j));
} else {
DFA.Transition transition1 =
(DFA.Transition) state.transitions.elementAt(j);
DFA.Transition transition2 =
(DFA.Transition) state.transitions.elementAt(j + max - 1);
DFA.Transition transition =
new DFA.Transition(
new CharSet.Interval(
transition1.interval().start,
transition2.interval().end),
-2 - st);
((Vector) transitions.elementAt(i)).addElement(transition);
j += max - 1;
}
}
}
for (int i = 0; i < states.size(); i++) {
DFA.State state = (DFA.State) states.elementAt(i);
state.transitions = (Vector) transitions.elementAt(i);
}
}
private int match(int st1, int tr, int st2) {
DFA.State state1 = (DFA.State) states.elementAt(st1);
DFA.State state2 = (DFA.State) states.elementAt(st2);
DFA.Transition first =
(DFA.Transition) state1.transitions.elementAt(tr);
int j = -1;
for (int i = 0; i < state2.transitions.size(); i++) {
DFA.Transition transition =
(DFA.Transition) state2.transitions.elementAt(i);
if (transition.match(first)) {
j = i;
break;
}
}
if (j == -1) {
return 0;
}
int max = 0;
int i = tr;
while ((i < state1.transitions.size()) &&
(j < state2.transitions.size())) {
DFA.Transition transition1 =
(DFA.Transition) state1.transitions.elementAt(i);
DFA.Transition transition2 =
(DFA.Transition) state2.transitions.elementAt(j);
if (!transition1.match(transition2)) {
return max;
}
max++;
i++;
j++;
}
return max;
}
private void construct() {
computeEClosures();
IntSet initial = new IntSet();
initial.or(eclosure(0));
State state = new State(initial);
states.addElement(state);
finder.put(state.nfaStates, new Integer(0));
int i = -1;
while (++i < states.size()) {
System.out.print(".");
state = (State) states.elementAt(i);
CharSet.Interval interval = new CharSet.Interval((char) 0, (char) 0xffff);
do {
IntSet destination = new IntSet();
interval.end = (char) 0xffff;
boolean modified = false;
int[] elements = state.nfaStates.elements();
for (int k = 0; k < elements.length; k++) {
int j = elements[k];
if ((nfa.states[j].transitions[0] != null) &&
(nfa.states[j].transitions[0].chars != null)) {
CharSet.Interval overlap =
nfa.states[j].transitions[0].chars.findOverlap(interval);
if (overlap != null) {
if (overlap.start > interval.start) {
interval.end = (char) (overlap.start - 1);
} else {
destination.set(nfa.states[j].transitions[0].destination);
modified = true;
if (overlap.end < interval.end) {
interval.end = overlap.end;
}
}
}
}
if ((nfa.states[j].transitions[1] != null) &&
(nfa.states[j].transitions[1].chars != null)) {
CharSet.Interval overlap =
nfa.states[j].transitions[1].chars.findOverlap(interval);
if (overlap != null) {
if (overlap.start > interval.start) {
interval.end = (char) (overlap.start - 1);
} else {
destination.set(nfa.states[j].transitions[1].destination);
if (overlap.end < interval.end) {
interval.end = overlap.end;
}
}
}
}
}
if (modified) {
destination = eclosure(destination);
Integer dest = (Integer) finder.get(destination);
if (dest != null) {
state.transitions.addElement(
new Transition((CharSet.Interval) interval.clone(), dest.intValue()));
} else {
State s = new State(destination);
states.addElement(s);
finder.put(s.nfaStates, new Integer(states.size() - 1));
state.transitions.addElement(
new Transition((CharSet.Interval) interval.clone(), states.size() - 1));
}
}
interval.start = (char) (interval.end + 1);
}
while (interval.end != (char) 0xffff);
// System.out.println(state);
}
// System.out.println(this);
}
private IntSet[] eclosures;
private void computeEClosures() {
eclosures = new IntSet[nfa.states.length];
for (int i = 0; i < nfa.states.length; i++) {
System.out.print(".");
IntSet set
= new IntSet();
eclosure(i, set
);
eclosures[i] = set
;
}
System.out.println();
}
private IntSet eclosure(int state) {
return eclosures[state];
}
private void eclosure(int state, IntSet nfaStates) {
if (eclosures[state] != null) {
nfaStates.or(eclosures[state]);
return;
}
nfaStates.set(state);
if ((nfa.states[state].transitions[0] != null) &&
(nfa.states[state].transitions[0].chars == null) &&
(!nfaStates.get(nfa.states[state].transitions[0].destination)))
{
eclosure(nfa.states[state].transitions[0].destination, nfaStates);
}
if ((nfa.states[state].transitions[1] != null) &&
(nfa.states[state].transitions[1].chars == null) &&
(!nfaStates.get(nfa.states[state].transitions[1].destination)))
{
eclosure(nfa.states[state].transitions[1].destination, nfaStates);
}
}
private IntSet eclosure(IntSet nfaStates) {
IntSet result = new IntSet();
int[] elements = nfaStates.elements();
for (int j = 0; j < elements.length; j++) {
int i = elements[j];
result.or(eclosure(i));
}
return result;
}
@Override
public String toString() {
StringBuffer result = new StringBuffer();
for (int i = 0; i < states.size(); i++) {
result.append(i + ": " + states.elementAt(i) +
System.getProperty("line.separator"));
}
return result.toString();
}
public static class State {
public State(IntSet nfaStates) {
this.nfaStates = nfaStates;
}
public IntSet nfaStates = new IntSet();
public Vector transitions = new Vector(0);
public int accept;
@Override
public String toString() {
StringBuffer result = new StringBuffer();
/* for(int i = 0; i < nfaStates.size(); i++)
{
if(nfaStates.get(i))
{
if(nfa.states[i].accept != null)
{
result.append("(" + nfa.states[i].accept + ")");
}
}
}*/
for (int i = 0; i < transitions.size(); i++) {
result.append(transitions.elementAt(i) + ",");
}
return result /*+ " " + nfaStates*/ + "";
}
}
public static class Transition {
private char start;
private char end;
public int destination;
public Transition(CharSet.Interval interval, int destination) {
this.start = interval.start;
this.end = interval.end;
this.destination = destination;
}
public CharSet.Interval interval() {
return new CharSet.Interval(start, end);
}
public Transition(Transition transition) {
start = transition.start;
end = transition.end;
destination = transition.destination;
}
@Override
public String toString() {
return destination + ":[" + interval() + "]";
}
public boolean match(Transition transition) {
return (start == transition.start) &&
(end == transition.end) &&
(destination == transition.destination);
}
}
}