Compiler Construction/State.java
From Wikibooks, open books for an open world
// State.java /* Copyright 2005 Takuya Murata This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ import java.util.*; import java.io.*; public final class State { public static interface Delta { public void move (int input, Collection<State> result); } public static final Delta nil = new Delta () { public void move (int input, Collection<State> result) { } }; public static final int EMPTY = -2, BEGIN_INPUT = -1, EOF = -1, ACCEPT = 0; public String label; // for the debugging purpose. private Delta delta = nil; public State () { this.label = super.toString ().replaceAll ("^.+@", "@"); } private State (String label, int i) { this.label = label + super.toString ().replaceAll ("^.+@", "@"); } public State (String label) { this.label = label; } public void setTransition (final int entry, final State dest) { final Delta prev = delta; delta = new Delta () { public void move (int input, Collection<State> result) { if (entry == input) result.add (dest); prev.move (input, result); } }; } public void setTransition (final String inputs, final State dest) { final Delta prev = delta; delta = new Delta () { public void move (int input, Collection<State> result) { if (inputs.contains (input)) result.add (dest); prev.move (input, result); } }; } public void setTransition (final Delta d) { final Delta prev = delta; delta = new Delta () { public void move (int input, Collection<State> result) { d.move (input, result); prev.move (input, result); } }; } public static final State[] toArray (Collection<State> col) { return col.toArray (new State[col.size ()]); } public static Set<State> closure (Collection<State> t) { Set<State> ret = new HashSet<State> (t); for (;;) { Collection<State> u = new ArrayList<State> (); for (State s : t) { Delta d = s.delta; d.move (State.EMPTY, ret); d.move (State.EMPTY, u); } if (u.isEmpty ()) break; else t = u; } return ret; } public static Set<State> move (Set<State> t, int input) { assert BEGIN_INPUT <= input && input < 256; Set<State> ret = new HashSet<State> (); for (State s : closure (t)) s.delta.move (input, ret); return ret; } public State[] move (int input) { return toArray (move (Collections.singleton (this), input)); } // A set of states reachable from this state without shifting an input. public State[] closure () { return toArray (closure (Collections.singleton (this))); } public State[] move (CharSequence string) { Set<State> ret = Collections.singleton (this); for (int i = 0; i < string.length (); i++) ret = move (ret, string.charAt (i)); return toArray (ret); } private static class SingleItemSet<T> extends AbstractList<T> implements Set<T> { private T item = null; public int size () { return (item != null) ? 1 : 0; } public T get (int i) { return item; } public T set (int i, T item) { T ret = this.item; assert 0 <= i && i < size (); this.item = item; return ret; } public void add (int i, T item) { assert i == 0; this.item = item; } public T remove (int i) { return set (i, null); } public T first () { return item; } } public State moveDFA (int input) { if (input == EMPTY) return this; SingleItemSet<State> t = new SingleItemSet<State> (); delta.move (input, t); if (!t.isEmpty ()) return t.first (); else return null; } public State moveDFA (CharSequence string) { State s = this; for (int i = 0; i < string.length (); i++) { s = s.moveDFA (string.charAt (i)); if (s == null) return null; } return s; } private static State createState (Set<State> t, Map<Set<State>, State> table) { State existing = table.get (t); if (existing != null) return existing; // We now need to make a new state for this states set. State q = new State ("q" + table.size ()); table.put (t, q); for (int i = BEGIN_INPUT; i < 256; i++) { assert i != EMPTY : i; Set<State> u = move (t, i); if (!u.isEmpty ()) q.setTransition (i, createState (u, table)); } return q; } public State toDFA () { Map<Set<State>, State> table = new HashMap<Set<State>, State> (); return createState (Collections.singleton (this), table); } private void prettyPrint (StringBuffer buf, Collection<State> marked) { if (marked.contains (this)) return; marked.add (this); buf.append (label + "["); boolean notfirst = false; for (int i = BEGIN_INPUT; i < 256; i++) { Set<State> t = move (Collections.singleton (this), i); if (!t.isEmpty ()) { if (notfirst) buf.append (", "); if (i == EMPTY) buf.append ("@e"); else if (i == ACCEPT) buf.append ("@acc"); else buf.append ((char) i); buf.append (":" + t); notfirst = true; } } buf.append ("]\n"); for (int i = BEGIN_INPUT; i < 256; i++) { Set<State> t = move (Collections.singleton (this), i); for (State s : t) s.prettyPrint (buf, marked); } } public String outputString () { Set<State> marked = new HashSet<State> (); StringBuffer buf = new StringBuffer (); this.prettyPrint (buf, marked); return buf.toString (); } public String toString () { return label; } // Create states and transitions for a string sequence public static final State[] stringSequence (CharSequence string) { int len = string.length (); State q[] = new State[len + 1]; // need s[len] for (int i = 0; i <= len; i++) q[i] = new State ("q" + i, 0); for (int i = 0; i < len; i++) q[i].setTransition (string.charAt (i), q[i + 1]); return new State[] { q[0], q[len] }; } public static final State[] stringSequenceIgnoreCase (CharSequence string) { int len = string.length (); State q[] = new State[len + 1]; // need s[len] for (int i = 0; i <= len; i++) q[i] = new State ("q" + i, 0); for (int i = 0; i < len; i++) { char lower = Character.toLowerCase (string.charAt (i)), upper = Character.toUpperCase (lower); q[i].setTransition (lower, q[i + 1]); q[i].setTransition (upper, q[i + 1]); } return new State[] { q[0], q[len] }; } }
This page may need to be