package de.unisiegen.gtitool.core.machines;
import java.util.ArrayList;
import java.util.TreeSet;
import javax.swing.JTable;
import javax.swing.event.EventListenerList;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import de.unisiegen.gtitool.core.entities.Alphabet;
import de.unisiegen.gtitool.core.entities.DefaultStack;
import de.unisiegen.gtitool.core.entities.DefaultState;
import de.unisiegen.gtitool.core.entities.DefaultStateSet;
import de.unisiegen.gtitool.core.entities.DefaultSymbol;
import de.unisiegen.gtitool.core.entities.DefaultTransition;
import de.unisiegen.gtitool.core.entities.DefaultWord;
import de.unisiegen.gtitool.core.entities.Stack;
import de.unisiegen.gtitool.core.entities.State;
import de.unisiegen.gtitool.core.entities.StateSet;
import de.unisiegen.gtitool.core.entities.Symbol;
import de.unisiegen.gtitool.core.entities.Transition;
import de.unisiegen.gtitool.core.entities.Word;
import de.unisiegen.gtitool.core.entities.Transition.TransitionType;
import de.unisiegen.gtitool.core.entities.listener.AlphabetChangedListener;
import de.unisiegen.gtitool.core.entities.listener.ModifyStatusChangedListener;
import de.unisiegen.gtitool.core.entities.listener.StateChangedListener;
import de.unisiegen.gtitool.core.entities.listener.TransitionChangedListener;
import de.unisiegen.gtitool.core.exceptions.machine.MachineAllSymbolsException;
import de.unisiegen.gtitool.core.exceptions.machine.MachineEpsilonTransitionException;
import de.unisiegen.gtitool.core.exceptions.machine.MachineException;
import de.unisiegen.gtitool.core.exceptions.machine.MachineStateFinalException;
import de.unisiegen.gtitool.core.exceptions.machine.MachineStateNameException;
import de.unisiegen.gtitool.core.exceptions.machine.MachineStateNotReachableException;
import de.unisiegen.gtitool.core.exceptions.machine.MachineStateStartException;
import de.unisiegen.gtitool.core.exceptions.machine.MachineSymbolOnlyOneTimeException;
import de.unisiegen.gtitool.core.exceptions.machine.MachineTransitionStackOperationsException;
import de.unisiegen.gtitool.core.exceptions.machine.MachineValidationException;
import de.unisiegen.gtitool.core.exceptions.state.StateException;
import de.unisiegen.gtitool.core.exceptions.stateset.StateSetException;
import de.unisiegen.gtitool.core.exceptions.transition.TransitionSymbolNotInAlphabetException;
import de.unisiegen.gtitool.core.exceptions.transition.TransitionSymbolOnlyOneTimeException;
import de.unisiegen.gtitool.core.exceptions.word.WordFinishedException;
import de.unisiegen.gtitool.core.exceptions.word.WordResetedException;
import de.unisiegen.gtitool.core.i18n.Messages;
import de.unisiegen.gtitool.core.machines.dfa.DefaultDFA;
import de.unisiegen.gtitool.core.machines.enfa.DefaultENFA;
import de.unisiegen.gtitool.core.machines.listener.MachineChangedListener;
import de.unisiegen.gtitool.core.machines.nfa.DefaultNFA;
import de.unisiegen.gtitool.core.machines.pda.DefaultPDA;
import de.unisiegen.gtitool.core.parser.style.PrettyPrintable;
import de.unisiegen.gtitool.core.parser.style.PrettyString;
import de.unisiegen.gtitool.core.parser.style.PrettyToken;
import de.unisiegen.gtitool.core.parser.style.Style;
import de.unisiegen.gtitool.core.parser.style.renderer.PrettyStringTableCellRenderer;
import de.unisiegen.gtitool.core.parser.style.renderer.PrettyStringTableHeaderCellRenderer;
import de.unisiegen.gtitool.core.storage.Modifyable;
import de.unisiegen.gtitool.core.storage.exceptions.StoreException;
import de.unisiegen.gtitool.core.util.ObjectPair;
import de.unisiegen.gtitool.core.util.ObjectTriple;
import de.unisiegen.gtitool.core.util.Util;
import de.unisiegen.gtitool.logger.Logger;
/**
* The abstract class for all machines.
*
* @author Christian Fehler
* @version $Id$
*/
public abstract class AbstractMachine implements Machine
{
/**
* The serial version uid.
*/
private static final long serialVersionUID = -7657607466102471211L;
/**
* The {@link Logger} for this class.
*/
private static final Logger logger = Logger
.getLogger ( AbstractMachine.class );
/**
* Returns the {@link Machine} with the given {@link Machine} type.
*
* @param machineType The {@link Machine} type.
* @param alphabet The {@link Alphabet}.
* @param pushDownAlphabet The push down {@link Alphabet} of this
* {@link Transition}.
* @param usePushDownAlphabet The use push down {@link Alphabet}.
* @return The {@link Machine} with the given {@link Machine} type.
* @throws StoreException If the {@link Machine} type is unknown.
*/
public static final Machine createMachine ( String machineType,
Alphabet alphabet, Alphabet pushDownAlphabet, boolean usePushDownAlphabet )
throws StoreException
{
if ( machineType.equals ( ( "DFA" ) ) ) //$NON-NLS-1$
{
return new DefaultDFA ( alphabet, pushDownAlphabet, usePushDownAlphabet );
}
if ( machineType.equals ( ( "NFA" ) ) ) //$NON-NLS-1$
{
return new DefaultNFA ( alphabet, pushDownAlphabet, usePushDownAlphabet );
}
if ( machineType.equals ( ( "ENFA" ) ) ) //$NON-NLS-1$
{
return new DefaultENFA ( alphabet, pushDownAlphabet, usePushDownAlphabet );
}
if ( machineType.equals ( ( "PDA" ) ) ) //$NON-NLS-1$
{
return new DefaultPDA ( alphabet, pushDownAlphabet, usePushDownAlphabet );
}
throw new StoreException ( Messages
.getString ( "StoreException.WrongMachineType" ) ); //$NON-NLS-1$
}
/**
* The {@link Alphabet} of this {@link AbstractMachine}.
*/
private Alphabet alphabet;
/**
* The push down {@link Alphabet} of this {@link AbstractMachine}.
*/
private Alphabet pushDownAlphabet;
/**
* The use push down {@link Alphabet} of this {@link AbstractMachine}.
*/
private boolean usePushDownAlphabet;
/**
* The initial use push down {@link Alphabet} of this {@link AbstractMachine}.
*/
private boolean initialUsePushDownAlphabet;
/**
* The current {@link State} id.
*/
private int currentStateId = State.ID_NOT_DEFINED;
/**
* The current {@link Transition} id.
*/
private int currentTransitionId = Transition.ID_NOT_DEFINED;
/**
* The history of this {@link AbstractMachine}.
*/
private ArrayList < HistoryItem > history;
/**
* The list of the {@link State}s.
*/
private ArrayList < State > stateList;
/**
* The initial list of the {@link State}s.
*/
private ArrayList < State > initialStateList;
/**
* The list of the {@link Transition}.
*/
private ArrayList < Transition > transitionList;
/**
* The list of the {@link Transition}.
*/
private ArrayList < Transition > initialTransitionList;
/**
* The current {@link Word}.
*/
private Word word = null;
/**
* The current {@link Stack}.
*/
private Stack stack = null;
/**
* The validation element list.
*/
private ArrayList < ValidationElement > validationElementList;
/**
* List of listeners
*/
private EventListenerList listenerList = new EventListenerList ();
/**
* The {@link AlphabetChangedListener}.
*/
private AlphabetChangedListener alphabetChangedListener;
/**
* The {@link TransitionChangedListener}.
*/
private TransitionChangedListener transitionChangedListener;
/**
* The {@link StateChangedListener}.
*/
private StateChangedListener stateChangedListener;
/**
* The {@link ModifyStatusChangedListener}.
*/
private ModifyStatusChangedListener modifyStatusChangedListener;
/**
* The list of cached values which is needed because of the {@link Transition}
* highlighting.
*/
private ArrayList < ObjectTriple < Integer, Integer, Object >> cachedValueList;
/**
* Allocates a new {@link AbstractMachine}.
*
* @param alphabet The {@link Alphabet} of this {@link AbstractMachine}.
* @param pushDownAlphabet The push down {@link Alphabet} of this
* {@link AbstractMachine}.
* @param usePushDownAlphabet The use push down {@link Alphabet}.
* @param validationElements The validation elements which indicates which
* validation elements should be checked during a validation.
*/
public AbstractMachine ( Alphabet alphabet, Alphabet pushDownAlphabet,
boolean usePushDownAlphabet, ValidationElement ... validationElements )
{
// alphabet
if ( alphabet == null )
{
throw new NullPointerException ( "alphabet is null" ); //$NON-NLS-1$
}
this.alphabet = alphabet;
// push down alphabet
if ( pushDownAlphabet == null )
{
throw new NullPointerException ( "push down alphabet is null" ); //$NON-NLS-1$
}
this.pushDownAlphabet = pushDownAlphabet;
// use push down alphabet
this.usePushDownAlphabet = usePushDownAlphabet;
// validation elements
if ( validationElements == null )
{
throw new NullPointerException ( "validation elements is null" ); //$NON-NLS-1$
}
this.validationElementList = new ArrayList < ValidationElement > ();
for ( ValidationElement current : validationElements )
{
this.validationElementList.add ( current );
}
// state list
this.stateList = new ArrayList < State > ();
this.initialStateList = new ArrayList < State > ();
// transition list
this.transitionList = new ArrayList < Transition > ();
this.initialTransitionList = new ArrayList < Transition > ();
// stack
this.stack = new DefaultStack ();
// history
this.history = new ArrayList < HistoryItem > ();
// cached value list
this.cachedValueList = new ArrayList < ObjectTriple < Integer, Integer, Object >> ();
// alphabet changed listener
this.alphabetChangedListener = new AlphabetChangedListener ()
{
public void alphabetChanged (
@SuppressWarnings ( "unused" ) Alphabet newAlphabet )
{
fireTableStructureChanged ();
}
};
this.alphabet.addAlphabetChangedListener ( this.alphabetChangedListener );
// transition changed listener
this.transitionChangedListener = new TransitionChangedListener ()
{
public void transitionChanged (
@SuppressWarnings ( "unused" ) Transition newTransition )
{
fireTableDataChanged ();
}
};
// state changed listener
this.stateChangedListener = new StateChangedListener ()
{
public void stateChanged ( boolean nameChanged,
@SuppressWarnings ( "unused" ) boolean startChanged,
@SuppressWarnings ( "unused" ) boolean loopTransitionChanged )
{
if ( nameChanged )
{
fireTableDataChanged ();
}
}
};
// modify status changed listener
this.modifyStatusChangedListener = new ModifyStatusChangedListener ()
{
public void modifyStatusChanged ( boolean modified )
{
fireModifyStatusChanged ( modified );
}
};
this.alphabet
.addModifyStatusChangedListener ( this.modifyStatusChangedListener );
this.pushDownAlphabet
.addModifyStatusChangedListener ( this.modifyStatusChangedListener );
// reset modify
resetModify ();
}
/**
* {@inheritDoc}
*
* @see Machine#addMachineChangedListener(MachineChangedListener)
*/
public final void addMachineChangedListener ( MachineChangedListener listener )
{
this.listenerList.add ( MachineChangedListener.class, listener );
}
/**
* {@inheritDoc}
*
* @see Machine#addModifyStatusChangedListener(ModifyStatusChangedListener)
*/
public final void addModifyStatusChangedListener (
ModifyStatusChangedListener listener )
{
this.listenerList.add ( ModifyStatusChangedListener.class, listener );
}
/**
* {@inheritDoc}
*
* @see Machine#addState(Iterable)
*/
public final void addState ( Iterable < State > states )
{
if ( states == null )
{
throw new NullPointerException ( "states is null" ); //$NON-NLS-1$
}
if ( !states.iterator ().hasNext () )
{
throw new IllegalArgumentException ( "states is empty" ); //$NON-NLS-1$
}
for ( State current : states )
{
addState ( current );
}
}
/**
* {@inheritDoc}
*
* @see Machine#addState(State)
*/
public final void addState ( State state )
{
if ( state == null )
{
throw new NullPointerException ( "state is null" ); //$NON-NLS-1$
}
if ( ( state.isIdDefined () ) && ( this.stateList.contains ( state ) ) )
{
throw new IllegalArgumentException ( "state is already added" ); //$NON-NLS-1$
}
// Set the state alphabet if it is not set already.
if ( state.getAlphabet () == null )
{
state.setAlphabet ( this.alphabet );
}
if ( !this.alphabet.equals ( state.getAlphabet () ) )
{
throw new IllegalArgumentException ( "not the same alphabet" ); //$NON-NLS-1$
}
// Set the state push down alphabet if it is not set already.
if ( state.getPushDownAlphabet () == null )
{
state.setPushDownAlphabet ( this.pushDownAlphabet );
}
if ( !this.pushDownAlphabet.equals ( state.getPushDownAlphabet () ) )
{
throw new IllegalArgumentException ( "not the same push down alphabet" ); //$NON-NLS-1$
}
if ( state.getId () == State.ID_NOT_DEFINED )
{
state.setId ( ++this.currentStateId );
}
else
{
if ( state.getId () > this.currentStateId )
{
this.currentStateId = state.getId ();
}
}
this.stateList.add ( state );
link ( state );
fireTableDataChanged ();
state.addStateChangedListener ( this.stateChangedListener );
state.addModifyStatusChangedListener ( this.modifyStatusChangedListener );
fireModifyStatusChanged ( true );
}
/**
* {@inheritDoc}
*
* @see Machine#addState(State[])
*/
public final void addState ( State ... states )
{
if ( states == null )
{
throw new NullPointerException ( "states is null" ); //$NON-NLS-1$
}
if ( states.length == 0 )
{
throw new IllegalArgumentException ( "states is empty" ); //$NON-NLS-1$
}
for ( State current : states )
{
addState ( current );
}
}
/**
* {@inheritDoc}
*
* @see TableModel#addTableModelListener(TableModelListener)
*/
public final void addTableModelListener ( TableModelListener listener )
{
this.listenerList.add ( TableModelListener.class, listener );
}
/**
* {@inheritDoc}
*
* @see Machine#addTransition(Iterable)
*/
public final void addTransition ( Iterable < Transition > transitions )
{
if ( transitions == null )
{
throw new NullPointerException ( "transitions is null" ); //$NON-NLS-1$
}
if ( !transitions.iterator ().hasNext () )
{
throw new IllegalArgumentException ( "transitions is empty" ); //$NON-NLS-1$
}
for ( Transition current : transitions )
{
addTransition ( current );
}
}
/**
* {@inheritDoc}
*
* @see Machine#addTransition(Transition)
*/
public final void addTransition ( Transition transition )
{
if ( transition == null )
{
throw new NullPointerException ( "transition is null" ); //$NON-NLS-1$
}
if ( ( transition.isIdDefined () )
&& ( this.transitionList.contains ( transition ) ) )
{
throw new IllegalArgumentException ( "transition is already added" ); //$NON-NLS-1$
}
// Set the transition alphabet if it is not set already.
if ( transition.getAlphabet () == null )
{
transition.setAlphabet ( this.alphabet );
}
if ( !this.alphabet.equals ( transition.getAlphabet () ) )
{
throw new IllegalArgumentException ( "not the same alphabet" ); //$NON-NLS-1$
}
// Set the transition push down alphabet if it is not set already.
if ( transition.getPushDownAlphabet () == null )
{
transition.setPushDownAlphabet ( this.pushDownAlphabet );
}
if ( !this.pushDownAlphabet.equals ( transition.getPushDownAlphabet () ) )
{
throw new IllegalArgumentException ( "not the same push down alphabet" ); //$NON-NLS-1$
}
if ( transition.getId () == Transition.ID_NOT_DEFINED )
{
transition.setId ( ++this.currentTransitionId );
}
else
{
if ( transition.getId () > this.currentTransitionId )
{
this.currentTransitionId = transition.getId ();
}
}
this.transitionList.add ( transition );
link ( transition );
fireTableDataChanged ();
transition.addTransitionChangedListener ( this.transitionChangedListener );
transition
.addModifyStatusChangedListener ( this.modifyStatusChangedListener );
fireModifyStatusChanged ( true );
}
/**
* {@inheritDoc}
*
* @see Machine#addTransition(Transition[])
*/
public final void addTransition ( Transition ... transitions )
{
if ( transitions == null )
{
throw new NullPointerException ( "transitions is null" ); //$NON-NLS-1$
}
if ( transitions.length == 0 )
{
throw new IllegalArgumentException ( "transitions is empty" ); //$NON-NLS-1$
}
for ( Transition current : transitions )
{
addTransition ( current );
}
}
/**
* Checks if there is a {@link State}, which {@link Transition}s do not
* contain all {@link Symbol}s.
*
* @return The list of {@link MachineException}.
*/
private final ArrayList < MachineException > checkAllSymbols ()
{
ArrayList < MachineException > machineExceptionList = new ArrayList < MachineException > ();
for ( State currentState : this.getState () )
{
TreeSet < Symbol > currentSymbolSet = new TreeSet < Symbol > ();
for ( Transition currentTransition : currentState.getTransitionBegin () )
{
currentSymbolSet.addAll ( currentTransition.getSymbol () );
}
TreeSet < Symbol > notUsedSymbolSet = new TreeSet < Symbol > ();
for ( Symbol currentSymbol : this.alphabet )
{
// the symbols must be cloned
notUsedSymbolSet.add ( new DefaultSymbol ( currentSymbol.getName () ) );
}
for ( Symbol currentSymbol : currentSymbolSet )
{
notUsedSymbolSet.remove ( currentSymbol );
}
if ( notUsedSymbolSet.size () > 0 )
{
machineExceptionList.add ( new MachineAllSymbolsException (
currentState, notUsedSymbolSet ) );
}
}
return machineExceptionList;
}
/**
* Checks if there is a {@link Transition} without a {@link Symbol}.
*
* @return The list of {@link MachineException}.
*/
private final ArrayList < MachineException > checkEpsilonTransition ()
{
ArrayList < MachineException > machineExceptionList = new ArrayList < MachineException > ();
for ( Transition currentTransition : this.getTransition () )
{
if ( currentTransition.getTransitionType ().equals (
TransitionType.EPSILON_ONLY )
|| currentTransition.getTransitionType ().equals (
TransitionType.EPSILON_SYMBOL ) )
{
machineExceptionList.add ( new MachineEpsilonTransitionException (
currentTransition ) );
}
}
return machineExceptionList;
}
/**
* Checks if there is no final state defined.
*
* @return The list of {@link MachineException}.
*/
private final ArrayList < MachineException > checkFinalState ()
{
ArrayList < MachineException > machineExceptionList = new ArrayList < MachineException > ();
boolean found = false;
loop : for ( State currentState : this.stateList )
{
if ( currentState.isFinalState () )
{
found = true;
break loop;
}
}
if ( !found )
{
machineExceptionList.add ( new MachineStateFinalException () );
}
return machineExceptionList;
}
/**
* Checks if there is more than one start state defined.
*
* @return The list of {@link MachineException}.
*/
private final ArrayList < MachineException > checkMoreThanOneStartState ()
{
ArrayList < MachineException > machineExceptionList = new ArrayList < MachineException > ();
ArrayList < State > startStateList = new ArrayList < State > ();
for ( State current : this.stateList )
{
if ( current.isStartState () )
{
startStateList.add ( current );
}
}
if ( startStateList.size () >= 2 )
{
machineExceptionList.add ( new MachineStateStartException (
startStateList ) );
}
return machineExceptionList;
}
/**
* Checks if there is no start state defined.
*
* @return The list of {@link MachineException}.
*/
private final ArrayList < MachineException > checkNoStartState ()
{
ArrayList < MachineException > machineExceptionList = new ArrayList < MachineException > ();
ArrayList < State > startStateList = new ArrayList < State > ();
for ( State current : this.getState () )
{
if ( current.isStartState () )
{
startStateList.add ( current );
}
}
if ( startStateList.size () == 0 )
{
machineExceptionList.add ( new MachineStateStartException (
startStateList ) );
}
return machineExceptionList;
}
/**
* Checks if there are {@link State}s with the same name.
*
* @return The list of {@link MachineException}.
*/
private final ArrayList < MachineException > checkStateName ()
{
ArrayList < MachineException > machineExceptionList = new ArrayList < MachineException > ();
ArrayList < State > duplicatedListAll = new ArrayList < State > ();
firstLoop : for ( int i = 0 ; i < this.getState ().size () ; i++ )
{
if ( duplicatedListAll.contains ( this.getState ().get ( i ) ) )
{
continue firstLoop;
}
ArrayList < State > duplicatedListOne = new ArrayList < State > ();
for ( int j = i + 1 ; j < this.getState ().size () ; j++ )
{
if ( this.getState ().get ( i ).getName ().equals (
this.getState ().get ( j ).getName () ) )
{
duplicatedListOne.add ( this.getState ().get ( j ) );
}
}
if ( duplicatedListOne.size () > 0 )
{
duplicatedListOne.add ( this.getState ().get ( i ) );
for ( State current : duplicatedListOne )
{
duplicatedListAll.add ( current );
}
machineExceptionList.add ( new MachineStateNameException (
duplicatedListOne ) );
}
}
return machineExceptionList;
}
/**
* Checks if there is a {@link State} which is not reachable.
*
* @return The list of {@link MachineException}.
*/
private final ArrayList < MachineException > checkStateNotReachable ()
{
ArrayList < MachineException > machineExceptionList = new ArrayList < MachineException > ();
for ( State current : getNotReachableStates () )
{
machineExceptionList.add ( new MachineStateNotReachableException (
current ) );
}
return machineExceptionList;
}
/**
* Checks if there is a {@link State} with {@link Transition}s with the same
* {@link Symbol}.
*
* @return The list of {@link MachineException}.
*/
private final ArrayList < MachineException > checkSymbolOnlyOneTime ()
{
ArrayList < MachineException > machineExceptionList = new ArrayList < MachineException > ();
for ( State currentState : this.getState () )
{
for ( Symbol currentSymbol : this.alphabet )
{
ArrayList < Transition > transitions = new ArrayList < Transition > ();
ArrayList < Symbol > symbols = new ArrayList < Symbol > ();
for ( Transition currentTransition : currentState.getTransitionBegin () )
{
if ( currentTransition.contains ( currentSymbol ) )
{
transitions.add ( currentTransition );
for ( Symbol addSymbol : currentTransition.getSymbol () )
{
if ( addSymbol.equals ( currentSymbol ) )
{
symbols.add ( addSymbol );
}
}
}
}
if ( transitions.size () > 1 )
{
machineExceptionList.add ( new MachineSymbolOnlyOneTimeException (
currentState, symbols, transitions ) );
}
}
}
return machineExceptionList;
}
/**
* Checks if there is a {@link Transition} with {@link Stack} operations.
*
* @return The list of {@link MachineException}.
*/
private final ArrayList < MachineException > checkTransitionStackOperation ()
{
ArrayList < MachineException > machineExceptionList = new ArrayList < MachineException > ();
for ( Transition currentTransition : this.getTransition () )
{
if ( ( currentTransition.getPushDownWordRead ().size () > 0 )
|| ( currentTransition.getPushDownWordWrite ().size () > 0 ) )
{
machineExceptionList
.add ( new MachineTransitionStackOperationsException (
currentTransition ) );
}
}
return machineExceptionList;
}
/**
* Clears the active {@link State}s.
*/
private final void clearActiveState ()
{
for ( State current : this.stateList )
{
current.setActive ( false );
}
}
/**
* Clears the active {@link Symbol}s.
*/
private final void clearActiveSymbol ()
{
for ( Transition currentTransition : this.transitionList )
{
for ( Symbol currentSymbol : currentTransition )
{
currentSymbol.setActive ( false );
}
}
}
/**
* Clears the active {@link Transition}s.
*/
private final void clearActiveTransition ()
{
for ( Transition current : this.transitionList )
{
current.setActive ( false );
}
}
/**
* Clears the history of this {@link AbstractMachine}.
*/
private final void clearHistory ()
{
this.history.clear ();
}
/**
* {@inheritDoc}
*
* @see Machine#clearSelectedTransition()
*/
public final void clearSelectedTransition ()
{
// transition
for ( Transition current : this.transitionList )
{
current.setSelected ( false );
}
// find the columns
for ( int i = 0 ; i < getColumnCount () ; i++ )
{
for ( int j = 0 ; j < getRowCount () ; j++ )
{
Object value = getValueAt ( j, i );
if ( value instanceof State )
{
State state = ( State ) value;
state.setSelected ( false );
}
else if ( value instanceof StateSet )
{
StateSet stateSet = ( StateSet ) value;
for ( State currentState : stateSet )
{
currentState.setSelected ( false );
}
}
else
{
throw new RuntimeException ( "not supported table value class: " //$NON-NLS-1$
+ value.getClass ().getSimpleName () );
}
}
}
}
/**
* Returns the cloned current {@link Stack}.
*
* @return The cloned current {@link Stack}.
*/
private final Stack cloneCurrentStack ()
{
ArrayList < Symbol > oldStackSymbolList = this.stack.peak ( this.stack
.size () );
Stack result = new DefaultStack ();
for ( int i = oldStackSymbolList.size () - 1 ; i >= 0 ; i-- )
{
result.push ( oldStackSymbolList.get ( i ) );
}
return result;
}
/**
* Let the listeners know that the editing is startet.
*/
private final void fireMachineChangedStartEditing ()
{
logger.debug ( "fireMachineChangedStartEditing", "start editing" ); //$NON-NLS-1$ //$NON-NLS-2$
MachineChangedListener [] listeners = this.listenerList
.getListeners ( MachineChangedListener.class );
for ( MachineChangedListener current : listeners )
{
current.startEditing ();
}
}
/**
* Let the listeners know that the editing is stopped.
*/
private final void fireMachineChangedStopEditing ()
{
logger.debug ( "fireMachineChangedStopEditing", "stop editing" ); //$NON-NLS-1$ //$NON-NLS-2$
MachineChangedListener [] listeners = this.listenerList
.getListeners ( MachineChangedListener.class );
for ( MachineChangedListener current : listeners )
{
current.stopEditing ();
}
}
/**
* Let the listeners know that {@link Symbol}s were added to the
* {@link Transition}.
*
* @param transition The modified {@link Transition}.
* @param addedSymbols The added {@link Symbol}s.
*/
private final void fireMachineChangedSymbolAdded ( Transition transition,
ArrayList < Symbol > addedSymbols )
{
logger.debug ( "fireMachineChangedSymbolAdded", "symbol added: " //$NON-NLS-1$ //$NON-NLS-2$
+ addedSymbols + " to " + transition ); //$NON-NLS-1$
MachineChangedListener [] listeners = this.listenerList
.getListeners ( MachineChangedListener.class );
for ( MachineChangedListener current : listeners )
{
current.symbolAdded ( transition, addedSymbols );
}
}
/**
* Let the listeners know that {@link Symbol}s were removed from the
* {@link Transition}.
*
* @param transition The modified {@link Transition}.
* @param removedSymbols The removed {@link Symbol}s.
*/
private final void fireMachineChangedSymbolRemoved ( Transition transition,
ArrayList < Symbol > removedSymbols )
{
logger.debug ( "fireMachineChangedSymbolRemoved", "symbol removed: " //$NON-NLS-1$ //$NON-NLS-2$
+ removedSymbols + " from " + transition ); //$NON-NLS-1$
MachineChangedListener [] listeners = this.listenerList
.getListeners ( MachineChangedListener.class );
for ( MachineChangedListener current : listeners )
{
current.symbolRemoved ( transition, removedSymbols );
}
}
/**
* Let the listeners know that a new {@link Transition} is added.
*
* @param newTransition The {@link Transition} to add.
*/
private final void fireMachineChangedTransitionAdded (
Transition newTransition )
{
logger.debug ( "fireMachineChangedTransitionAdded", "transition added: " //$NON-NLS-1$//$NON-NLS-2$
+ newTransition );
MachineChangedListener [] listeners = this.listenerList
.getListeners ( MachineChangedListener.class );
for ( MachineChangedListener current : listeners )
{
current.transitionAdded ( newTransition );
}
}
/**
* Let the listeners know that the {@link Transition} is removed.
*
* @param transition The {@link Transition} to remove.
*/
private final void fireMachineChangedTransitionRemoved ( Transition transition )
{
logger.debug ( "fireMachineChangedTransitionRemoved", //$NON-NLS-1$
"transition removed: " + transition ); //$NON-NLS-1$
MachineChangedListener [] listeners = this.listenerList
.getListeners ( MachineChangedListener.class );
for ( MachineChangedListener current : listeners )
{
current.transitionRemoved ( transition );
}
}
/**
* Let the listeners know that the modify status has changed.
*
* @param forceModify True if the modify is forced, otherwise false.
*/
protected final void fireModifyStatusChanged ( boolean forceModify )
{
ModifyStatusChangedListener [] listeners = this.listenerList
.getListeners ( ModifyStatusChangedListener.class );
if ( forceModify )
{
for ( ModifyStatusChangedListener current : listeners )
{
current.modifyStatusChanged ( true );
}
}
else
{
boolean newModifyStatus = isModified ();
for ( ModifyStatusChangedListener current : listeners )
{
current.modifyStatusChanged ( newModifyStatus );
}
}
}
/**
* Forwards the given notification event to all {@link TableModelListener}s
* that registered themselves as listeners for this table model.
*
* @param event The event to be forwarded
* @see #addTableModelListener
* @see TableModelEvent
* @see EventListenerList
*/
private final void fireTableChanged ( TableModelEvent event )
{
TableModelListener [] listeners = this.listenerList
.getListeners ( TableModelListener.class );
for ( TableModelListener current : listeners )
{
current.tableChanged ( event );
}
}
/**
* Notifies all listeners that all cell values in the table's rows may have
* changed. The number of rows may also have changed and the {@link JTable}
* should redraw the table from scratch. The structure of the table (as in the
* order of the columns) is assumed to be the same.
*
* @see TableModelEvent
* @see EventListenerList
* @see JTable#tableChanged(TableModelEvent)
*/
protected final void fireTableDataChanged ()
{
fireTableChanged ( new TableModelEvent ( this ) );
}
/**
* Notifies all listeners that the table's structure has changed.
*
* @see TableModelEvent
* @see EventListenerList
*/
protected final void fireTableStructureChanged ()
{
fireTableChanged ( new TableModelEvent ( this, TableModelEvent.HEADER_ROW ) );
}
/**
* {@inheritDoc}
*
* @see Machine#getAcceptedWords(int)
*/
public final ArrayList < Word > getAcceptedWords ( int maxLength )
{
ArrayList < Word > result = new ArrayList < Word > ();
ArrayList < Word > words = new ArrayList < Word > ();
ArrayList < Word > tmpWords = new ArrayList < Word > ();
int length = 0;
while ( length <= maxLength )
{
if ( length == 0 )
{
Word newWord = new DefaultWord ();
words.add ( newWord );
if ( isWordAccepted ( newWord ) )
{
result.add ( newWord );
}
}
else
{
tmpWords.clear ();
for ( Word currentWord : words )
{
for ( Symbol currentSymbol : this.alphabet )
{
Word newWord = new DefaultWord ( currentWord );
newWord.add ( currentSymbol );
tmpWords.add ( newWord );
if ( isWordAccepted ( newWord ) )
{
result.add ( newWord );
}
}
}
words.clear ();
words.addAll ( tmpWords );
}
length++ ;
}
return result;
}
/**
* {@inheritDoc}
*
* @see Machine#getAlphabet()
*/
public final Alphabet getAlphabet ()
{
return this.alphabet;
}
/**
* {@inheritDoc}
*
* @see TableModel#getColumnClass(int)
*/
public final Class < ? > getColumnClass (
@SuppressWarnings ( "unused" ) int columnIndex )
{
return PrettyPrintable.class;
}
/**
* {@inheritDoc}
*
* @see TableModel#getColumnCount()
*/
public final int getColumnCount ()
{
return SPECIAL_COLUMN_COUNT + this.alphabet.size ();
}
/**
* {@inheritDoc}
*
* @see TableModel#getColumnName(int)
*/
public final String getColumnName ( int columnIndex )
{
if ( columnIndex == STATE_COLUMN )
{
return ""; //$NON-NLS-1$
}
if ( columnIndex == EPSILON_COLUMN )
{
return "\u03B5"; //$NON-NLS-1$
}
return this.alphabet.get ( columnIndex - SPECIAL_COLUMN_COUNT ).toString ();
}
/**
* {@inheritDoc}
*
* @see Machine#getMachineType()
*/
public abstract MachineType getMachineType ();
/**
* {@inheritDoc}
*
* @see Machine#getNextStateName()
*/
public final String getNextStateName ()
{
int result = -1;
for ( State current : this.stateList )
{
if ( current.getId () > result )
{
result = current.getId ();
}
}
result++ ;
return "z" + result; //$NON-NLS-1$
}
/**
* {@inheritDoc}
*
* @see Machine#getNotReachableStates()
*/
public final ArrayList < State > getNotReachableStates ()
{
ArrayList < State > reachable = getReachableStates ();
ArrayList < State > notReachable = new ArrayList < State > ();
notReachable.addAll ( this.stateList );
for ( State current : reachable )
{
notReachable.remove ( current );
}
return notReachable;
}
/**
* {@inheritDoc}
*
* @see Machine#getNotRemoveableSymbolsFromAlphabet()
*/
public final TreeSet < Symbol > getNotRemoveableSymbolsFromAlphabet ()
{
TreeSet < Symbol > notRemoveableSymbols = new TreeSet < Symbol > ();
for ( Transition currentTransition : this.transitionList )
{
for ( Symbol currentSymbol : currentTransition )
{
if ( !currentSymbol.isEpsilon () )
{
notRemoveableSymbols.add ( currentSymbol );
}
}
}
return notRemoveableSymbols;
}
/**
* {@inheritDoc}
*
* @see Machine#getNotRemoveableSymbolsFromPushDownAlphabet()
*/
public final TreeSet < Symbol > getNotRemoveableSymbolsFromPushDownAlphabet ()
{
TreeSet < Symbol > notRemoveableSymbols = new TreeSet < Symbol > ();
for ( Transition current : this.transitionList )
{
for ( Symbol currentSymbol : current.getPushDownWordRead () )
{
notRemoveableSymbols.add ( currentSymbol );
}
for ( Symbol currentSymbol : current.getPushDownWordWrite () )
{
notRemoveableSymbols.add ( currentSymbol );
}
}
return notRemoveableSymbols;
}
/**
* {@inheritDoc}
*
* @see Machine#getPossibleTransitions()
*/
public final ArrayList < Transition > getPossibleTransitions ()
{
ArrayList < Transition > result = new ArrayList < Transition > ();
ArrayList < State > activeStateList = new ArrayList < State > ();
for ( State current : this.stateList )
{
if ( current.isActive () )
{
activeStateList.add ( current );
}
}
for ( State currentState : activeStateList )
{
transitionLoop : for ( Transition currentTransition : currentState
.getTransitionBegin () )
{
// epsilon
if ( currentTransition.getTransitionType ().equals (
TransitionType.EPSILON_ONLY )
|| currentTransition.getTransitionType ().equals (
TransitionType.EPSILON_SYMBOL ) )
{
Word readWord = currentTransition.getPushDownWordRead ();
ArrayList < Symbol > stackSymbols = this.stack.peak ( readWord
.size () );
// the read word must match
if ( readWord.size () != stackSymbols.size () )
{
continue transitionLoop;
}
for ( int i = 0 ; i < readWord.size () ; i++ )
{
if ( !readWord.get ( i ).equals ( stackSymbols.get ( i ) ) )
{
continue transitionLoop;
}
}
result.add ( currentTransition );
}
// no epsilon
else
{
Symbol symbol;
try
{
symbol = this.word.nextSymbol ();
this.word.previousSymbol ();
}
catch ( WordFinishedException exc )
{
continue transitionLoop;
}
catch ( WordResetedException exc )
{
continue transitionLoop;
}
Word readWord = currentTransition.getPushDownWordRead ();
ArrayList < Symbol > stackSymbols = this.stack.peak ( readWord
.size () );
// the read word must match
if ( readWord.size () != stackSymbols.size () )
{
continue transitionLoop;
}
for ( int i = 0 ; i < readWord.size () ; i++ )
{
if ( !readWord.get ( i ).equals ( stackSymbols.get ( i ) ) )
{
continue transitionLoop;
}
}
if ( currentTransition.contains ( symbol ) )
{
result.add ( currentTransition );
}
}
}
}
return result;
}
/**
* {@inheritDoc}
*
* @see Machine#getPushDownAlphabet()
*/
public final Alphabet getPushDownAlphabet ()
{
return this.pushDownAlphabet;
}
/**
* {@inheritDoc}
*
* @see Machine#getReachableStates()
*/
public final ArrayList < State > getReachableStates ()
{
ArrayList < State > reachable = new ArrayList < State > ();
ArrayList < State > todoList = new ArrayList < State > ();
for ( State current : this.stateList )
{
if ( current.isStartState () )
{
todoList.add ( current );
}
}
while ( todoList.size () > 0 )
{
State currentState = todoList.remove ( 0 );
reachable.add ( currentState );
for ( Transition currentTransition : currentState.getTransitionBegin () )
{
State endState = currentTransition.getStateEnd ();
if ( !todoList.contains ( endState ) && !reachable.contains ( endState ) )
{
todoList.add ( endState );
}
}
}
return reachable;
}
/**
* {@inheritDoc}
*
* @see Machine#getReadedSymbols()
*/
public final ArrayList < Symbol > getReadedSymbols ()
throws WordFinishedException, WordResetedException
{
return this.word.getReadedSymbols ();
}
/**
* {@inheritDoc}
*
* @see TableModel#getRowCount()
*/
public final int getRowCount ()
{
return this.stateList.size ();
}
/**
* {@inheritDoc}
*
* @see Machine#getStack()
*/
public final Stack getStack ()
{
return this.stack;
}
/**
* {@inheritDoc}
*
* @see Machine#getState()
*/
public final ArrayList < State > getState ()
{
return this.stateList;
}
/**
* {@inheritDoc}
*
* @see Machine#getState(int)
*/
public final State getState ( int index )
{
return this.stateList.get ( index );
}
/**
* {@inheritDoc}
*
* @see Machine#getTableColumnModel()
*/
public final TableColumnModel getTableColumnModel ()
{
DefaultTableColumnModel columnModel = new DefaultTableColumnModel ();
TableColumn stateColumn = new TableColumn ( STATE_COLUMN );
stateColumn.setHeaderValue ( new PrettyString ( new PrettyToken ( "", //$NON-NLS-1$
Style.NONE ) ) );
stateColumn.setHeaderRenderer ( new PrettyStringTableHeaderCellRenderer () );
stateColumn.setCellRenderer ( new PrettyStringTableCellRenderer () );
columnModel.addColumn ( stateColumn );
TableColumn epsilonColumn = new TableColumn ( EPSILON_COLUMN );
epsilonColumn.setHeaderValue ( new PrettyString ( new PrettyToken (
"\u03B5", Style.SYMBOL ) ) ); //$NON-NLS-1$
epsilonColumn
.setHeaderRenderer ( new PrettyStringTableHeaderCellRenderer () );
epsilonColumn.setCellRenderer ( new PrettyStringTableCellRenderer () );
columnModel.addColumn ( epsilonColumn );
for ( int i = 0 ; i < this.alphabet.size () ; i++ )
{
TableColumn symbolColumn = new TableColumn ( i + SPECIAL_COLUMN_COUNT );
symbolColumn.setHeaderValue ( this.alphabet.get ( i ) );
symbolColumn
.setHeaderRenderer ( new PrettyStringTableHeaderCellRenderer () );
symbolColumn.setCellRenderer ( new PrettyStringTableCellRenderer () );
columnModel.addColumn ( symbolColumn );
}
return columnModel;
}
/**
* {@inheritDoc}
*
* @see Machine#getTransition()
*/
public final ArrayList < Transition > getTransition ()
{
return this.transitionList;
}
/**
* {@inheritDoc}
*
* @see Machine#getTransition(int)
*/
public final Transition getTransition ( int index )
{
return this.transitionList.get ( index );
}
/**
* {@inheritDoc}
*
* @see TableModel#getValueAt(int, int)
*/
public final Object getValueAt ( int rowIndex, int columnIndex )
{
// State column
if ( columnIndex == STATE_COLUMN )
{
for ( int i = 0 ; i < this.cachedValueList.size () ; i++ )
{
ObjectTriple < Integer, Integer, Object > cache = this.cachedValueList
.get ( i );
int cachedRowIndex = cache.getFirst ().intValue ();
int cachedColumnIndex = cache.getSecond ().intValue ();
if ( ( rowIndex == cachedRowIndex )
&& ( columnIndex == cachedColumnIndex ) )
{
State cachedState = ( State ) cache.getThird ();
try
{
cachedState.setName ( this.stateList.get ( rowIndex ).getName () );
}
catch ( StateException exc )
{
exc.printStackTrace ();
System.exit ( 1 );
}
return cache.getThird ();
}
}
State newState = null;
try
{
newState = new DefaultState ( this.stateList.get ( rowIndex )
.getName () );
newState.setId ( this.stateList.get ( rowIndex ).getId () );
}
catch ( StateException exc )
{
exc.printStackTrace ();
System.exit ( 1 );
}
this.cachedValueList.add ( new ObjectTriple < Integer, Integer, Object > (
new Integer ( rowIndex ), new Integer ( columnIndex ), newState ) );
return this.stateList.get ( rowIndex );
}
StateSet stateEndList = new DefaultStateSet ();
State currentState = this.stateList.get ( rowIndex );
// epsilon column
if ( columnIndex == EPSILON_COLUMN )
{
for ( Transition currentTransition : currentState.getTransitionBegin () )
{
if ( currentTransition.getTransitionType ().equals (
TransitionType.EPSILON_ONLY )
|| currentTransition.getTransitionType ().equals (
TransitionType.EPSILON_SYMBOL ) )
{
try
{
stateEndList.add ( currentTransition.getStateEnd () );
}
catch ( StateSetException exc )
{
exc.printStackTrace ();
System.exit ( 1 );
}
}
}
}
// normal columns
else
{
Symbol currentSymbol = this.alphabet.get ( columnIndex
- SPECIAL_COLUMN_COUNT );
for ( Transition currentTransition : currentState.getTransitionBegin () )
{
if ( currentTransition.contains ( currentSymbol ) )
{
try
{
stateEndList.add ( currentTransition.getStateEnd () );
}
catch ( StateSetException exc )
{
exc.printStackTrace ();
System.exit ( 1 );
}
}
}
}
for ( int i = 0 ; i < this.cachedValueList.size () ; i++ )
{
ObjectTriple < Integer, Integer, Object > cache = this.cachedValueList
.get ( i );
int cachedRowIndex = cache.getFirst ().intValue ();
int cachedColumnIndex = cache.getSecond ().intValue ();
if ( ( rowIndex == cachedRowIndex )
&& ( columnIndex == cachedColumnIndex ) )
{
StateSet cachedStateSet = ( StateSet ) cache.getThird ();
if ( cachedStateSet.size () != stateEndList.size () )
{
this.cachedValueList.remove ( i );
break;
}
for ( int j = 0 ; j < stateEndList.size () ; j++ )
{
try
{
cachedStateSet.get ( j ).setName (
stateEndList.get ( j ).getName () );
}
catch ( StateException exc )
{
exc.printStackTrace ();
System.exit ( 1 );
}
}
return cache.getThird ();
}
}
StateSet newStateEndList = new DefaultStateSet ();
for ( State current : stateEndList )
{
try
{
State newState = new DefaultState ( current.getName () );
newState.setId ( current.getId () );
newStateEndList.add ( newState );
}
catch ( StateSetException exc )
{
exc.printStackTrace ();
System.exit ( 1 );
}
catch ( StateException exc )
{
exc.printStackTrace ();
System.exit ( 1 );
}
}
this.cachedValueList
.add ( new ObjectTriple < Integer, Integer, Object > ( new Integer (
rowIndex ), new Integer ( columnIndex ), newStateEndList ) );
return newStateEndList;
}
/**
* {@inheritDoc}
*
* @see Machine#getWord()
*/
public final Word getWord ()
{
return this.word;
}
/**
* {@inheritDoc}
*
* @see TableModel#isCellEditable(int, int)
*/
public final boolean isCellEditable (
@SuppressWarnings ( "unused" ) int rowIndex, int columnIndex )
{
return columnIndex > 0;
}
/**
* {@inheritDoc}
*
* @see Machine#isEveryStateUnique()
*/
public final boolean isEveryStateUnique ()
{
for ( int i = 0 ; i < this.stateList.size () ; i++ )
{
for ( int j = i + 1 ; j < this.stateList.size () ; j++ )
{
if ( this.stateList.get ( i ).getName ().equals (
this.stateList.get ( j ).getName () ) )
{
return false;
}
}
}
return true;
}
/**
* {@inheritDoc}
*
* @see Modifyable#isModified()
*/
public final boolean isModified ()
{
if ( this.stateList.size () != this.initialStateList.size () )
{
return true;
}
if ( this.transitionList.size () != this.initialTransitionList.size () )
{
return true;
}
boolean found;
for ( int i = 0 ; i < this.stateList.size () ; i++ )
{
found = false;
for ( int j = 0 ; j < this.initialStateList.size () ; j++ )
{
if ( this.stateList.get ( i ) == this.initialStateList.get ( j ) )
{
found = true;
break;
}
}
if ( !found )
{
return true;
}
}
for ( int i = 0 ; i < this.transitionList.size () ; i++ )
{
found = false;
for ( int j = 0 ; j < this.initialTransitionList.size () ; j++ )
{
if ( this.transitionList.get ( i ) == this.initialTransitionList
.get ( j ) )
{
found = true;
break;
}
}
if ( !found )
{
return true;
}
}
if ( this.alphabet.isModified () )
{
return true;
}
if ( this.pushDownAlphabet.isModified () )
{
return true;
}
if ( this.usePushDownAlphabet != this.initialUsePushDownAlphabet )
{
return true;
}
for ( State current : this.stateList )
{
if ( current.isModified () )
{
return true;
}
}
for ( Transition current : this.transitionList )
{
if ( current.isModified () )
{
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*
* @see Machine#isNextSymbolAvailable()
*/
public final boolean isNextSymbolAvailable ()
{
if ( this.word == null )
{
return false;
}
// special case for the pda navigation
if ( getMachineType ().equals ( MachineType.PDA )
&& ( getPossibleTransitions ().size () > 0 ) )
{
return true;
}
// the exception is thrown if the word is finished
try
{
nextSymbol ();
}
catch ( Exception exc )
{
previousSymbol ();
return false;
}
// save the new active states
ArrayList < State > newActiveStates = new ArrayList < State > ();
for ( State current : this.stateList )
{
if ( current.isActive () )
{
newActiveStates.add ( current );
}
}
if ( newActiveStates.size () == 0 )
{
previousSymbol ();
return false;
}
previousSymbol ();
return true;
}
/**
* {@inheritDoc}
*
* @see Machine#isPreviousSymbolAvailable()
*/
public final boolean isPreviousSymbolAvailable ()
{
if ( this.word == null )
{
return false;
}
return !this.history.isEmpty ();
}
/**
* {@inheritDoc}
*
* @see Machine#isUsePushDownAlphabet()
*/
public final boolean isUsePushDownAlphabet ()
{
return this.usePushDownAlphabet;
}
/**
* {@inheritDoc}
*
* @see Machine#isUserInputNeeded()
*/
public final boolean isUserInputNeeded ()
{
if ( getMachineType ().equals ( MachineType.PDA ) )
{
return getPossibleTransitions ().size () >= 2;
}
return false;
}
/**
*{@inheritDoc}
*
* @see Machine#isWordAccepted()
*/
public final boolean isWordAccepted ()
{
if ( this.stack.size () > 0 )
{
return false;
}
for ( State current : this.stateList )
{
if ( current.isActive () && current.isFinalState () )
{
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*
* @see Machine#isWordAccepted(Word)
*/
public final boolean isWordAccepted ( Word testWord )
{
testWord.start ();
ArrayList < State > activeStates = new ArrayList < State > ( this.stateList
.size () );
ArrayList < State > tmpActiveStates = new ArrayList < State > (
this.stateList.size () );
// start states
for ( State current : this.stateList )
{
if ( current.isStartState () )
{
activeStates.addAll ( Util.getClosure ( current ) );
}
}
try
{
while ( !testWord.isFinished () )
{
tmpActiveStates.clear ();
Symbol symbol = testWord.nextSymbol ();
for ( State currentState : activeStates )
{
for ( Transition currentTransition : currentState
.getTransitionBegin () )
{
if ( currentTransition.contains ( symbol ) )
{
if ( !tmpActiveStates.contains ( currentState ) )
{
tmpActiveStates.add ( currentTransition.getStateEnd () );
break;
}
}
}
}
activeStates.clear ();
activeStates.addAll ( Util.getClosure ( tmpActiveStates ) );
}
}
catch ( WordFinishedException exc )
{
exc.printStackTrace ();
System.exit ( 1 );
return false;
}
for ( State current : activeStates )
{
if ( current.isFinalState () )
{
return true;
}
}
return false;
}
/**
* Links the {@link Transition}s with the given {@link State}.
*
* @param state The {@link State} to which the {@link Transition}s should be
* linked.
*/
private final void link ( State state )
{
for ( Transition current : this.transitionList )
{
// State begin
if ( current.getStateBegin () == null )
{
if ( current.getStateBeginId () == state.getId () )
{
current.setStateBegin ( state );
state.addTransitionBegin ( current );
}
}
else if ( current.getStateBegin ().equals ( state ) )
{
state.addTransitionBegin ( current );
}
// State end
if ( current.getStateEnd () == null )
{
if ( current.getStateEndId () == state.getId () )
{
current.setStateEnd ( state );
state.addTransitionEnd ( current );
}
}
else if ( current.getStateEnd ().equals ( state ) )
{
state.addTransitionEnd ( current );
}
}
}
/**
* Links the given {@link Transition} with the {@link State}s.
*
* @param transition The {@link Transition} to link with the {@link State}s.
*/
private final void link ( Transition transition )
{
for ( State currentState : this.stateList )
{
// State begin
if ( transition.getStateBegin () == null )
{
if ( transition.getStateBeginId () == currentState.getId () )
{
transition.setStateBegin ( currentState );
currentState.addTransitionBegin ( transition );
}
}
else if ( transition.getStateBegin ().equals ( currentState ) )
{
currentState.addTransitionBegin ( transition );
}
// State end
if ( transition.getStateEnd () == null )
{
if ( transition.getStateEndId () == currentState.getId () )
{
transition.setStateEnd ( currentState );
currentState.addTransitionEnd ( transition );
}
}
else if ( transition.getStateEnd ().equals ( currentState ) )
{
currentState.addTransitionEnd ( transition );
}
}
}
/**
* {@inheritDoc}
*
* @see Machine#nextSymbol()
*/
public final void nextSymbol ()
{
ArrayList < State > activeStateList = new ArrayList < State > ();
for ( State current : this.stateList )
{
if ( current.isActive () )
{
activeStateList.add ( current );
}
}
if ( activeStateList.size () == 0 )
{
throw new RuntimeException ( "active state set is empty" ); //$NON-NLS-1$
}
TreeSet < State > oldActiveStateSet = new TreeSet < State > ();
TreeSet < Transition > oldActiveTransitionSet = new TreeSet < Transition > ();
ArrayList < Symbol > oldActiveSymbolList = new ArrayList < Symbol > ();
Stack oldStack = cloneCurrentStack ();
for ( State current : this.stateList )
{
if ( current.isActive () )
{
oldActiveStateSet.add ( current );
}
}
for ( Transition current : this.transitionList )
{
if ( current.isActive () )
{
oldActiveTransitionSet.add ( current );
for ( Symbol currentSymbol : current )
{
if ( currentSymbol.isActive () )
{
oldActiveSymbolList.add ( currentSymbol );
}
}
}
}
HistoryItem historyItem = new HistoryItem ( oldActiveStateSet,
oldActiveTransitionSet, oldActiveSymbolList, oldStack, false );
this.history.add ( historyItem );
clearActiveState ();
clearActiveTransition ();
clearActiveSymbol ();
// check for epsilon transitions
boolean epsilonTransitionFound = false;
stateLoop : for ( State activeState : oldActiveStateSet )
{
transitionLoop : for ( Transition current : activeState
.getTransitionBegin () )
{
if ( ( current.getTransitionType ().equals (
TransitionType.EPSILON_ONLY ) || current.getTransitionType ()
.equals ( TransitionType.EPSILON_SYMBOL ) )
// special case for the pda
&& ( ( !oldActiveStateSet.contains ( current.getStateEnd () ) ) || getMachineType ()
.equals ( MachineType.PDA ) ) )
{
Word readWord = current.getPushDownWordRead ();
ArrayList < Symbol > stackSymbols = this.stack.peak ( readWord
.size () );
// the read word must match
if ( readWord.size () != stackSymbols.size () )
{
continue transitionLoop;
}
for ( int i = 0 ; i < readWord.size () ; i++ )
{
if ( !readWord.get ( i ).equals ( stackSymbols.get ( i ) ) )
{
continue transitionLoop;
}
}
epsilonTransitionFound = true;
break stateLoop;
}
}
}
// epsilon transition found
if ( epsilonTransitionFound )
{
for ( State currentState : oldActiveStateSet )
{
// add the old state if not a pda
if ( !getMachineType ().equals ( MachineType.PDA ) )
{
currentState.setActive ( true );
}
transitionLoop : for ( Transition currentTransition : currentState
.getTransitionBegin () )
{
if ( ( currentTransition.getTransitionType ().equals (
TransitionType.EPSILON_ONLY ) || currentTransition
.getTransitionType ().equals ( TransitionType.EPSILON_SYMBOL ) )
&& ( !oldActiveStateSet.contains ( currentTransition
.getStateEnd () ) ) )
{
Word readWord = currentTransition.getPushDownWordRead ();
ArrayList < Symbol > stackSymbols = this.stack.peak ( readWord
.size () );
// the read word must match
if ( readWord.size () != stackSymbols.size () )
{
continue transitionLoop;
}
for ( int i = 0 ; i < readWord.size () ; i++ )
{
if ( !readWord.get ( i ).equals ( stackSymbols.get ( i ) ) )
{
continue transitionLoop;
}
}
// add the state begin if not a pda
if ( !getMachineType ().equals ( MachineType.PDA ) )
{
currentTransition.getStateBegin ().setActive ( true );
}
currentTransition.setActive ( true );
currentTransition.getStateEnd ().setActive ( true );
for ( Symbol currentSymbol : currentTransition )
{
if ( currentSymbol.isEpsilon () )
{
currentSymbol.setActive ( true );
break;
}
}
replaceStack ( readWord.size (), currentTransition
.getPushDownWordWrite () );
}
}
}
}
// no epsilon transition found
else
{
Symbol symbol;
try
{
symbol = this.word.nextSymbol ();
historyItem.setNextWordStep ( true );
}
catch ( WordFinishedException exc )
{
throw new RuntimeException ( exc.getMessage () );
}
for ( State currentState : oldActiveStateSet )
{
transitionLoop : for ( Transition currentTransition : currentState
.getTransitionBegin () )
{
Word readWord = currentTransition.getPushDownWordRead ();
ArrayList < Symbol > stackSymbols = this.stack.peak ( readWord
.size () );
// the read word must match
if ( readWord.size () != stackSymbols.size () )
{
continue transitionLoop;
}
for ( int i = 0 ; i < readWord.size () ; i++ )
{
if ( !readWord.get ( i ).equals ( stackSymbols.get ( i ) ) )
{
continue transitionLoop;
}
}
if ( currentTransition.contains ( symbol ) )
{
currentTransition.setActive ( true );
currentTransition.getStateEnd ().setActive ( true );
for ( Symbol currentSymbol : currentTransition )
{
if ( !currentSymbol.isEpsilon ()
&& currentSymbol.getName ().equals ( symbol.getName () ) )
{
currentSymbol.setActive ( true );
break;
}
}
replaceStack ( readWord.size (), currentTransition
.getPushDownWordWrite () );
}
}
}
}
}
/**
* {@inheritDoc}
*
* @see Machine#nextSymbol(Transition)
*/
public void nextSymbol ( Transition transition )
{
ArrayList < State > activeStateList = new ArrayList < State > ();
for ( State current : this.stateList )
{
if ( current.isActive () )
{
activeStateList.add ( current );
}
}
if ( activeStateList.size () == 0 )
{
throw new RuntimeException ( "active state set is empty" ); //$NON-NLS-1$
}
TreeSet < State > oldActiveStateSet = new TreeSet < State > ();
TreeSet < Transition > oldActiveTransitionSet = new TreeSet < Transition > ();
ArrayList < Symbol > oldActiveSymbolList = new ArrayList < Symbol > ();
Stack oldStack = cloneCurrentStack ();
for ( State current : this.stateList )
{
if ( current.isActive () )
{
oldActiveStateSet.add ( current );
}
}
for ( Transition current : this.transitionList )
{
if ( current.isActive () )
{
oldActiveTransitionSet.add ( current );
for ( Symbol currentSymbol : current )
{
if ( currentSymbol.isActive () )
{
oldActiveSymbolList.add ( currentSymbol );
}
}
}
}
HistoryItem historyItem = new HistoryItem ( oldActiveStateSet,
oldActiveTransitionSet, oldActiveSymbolList, oldStack, false );
this.history.add ( historyItem );
clearActiveState ();
clearActiveTransition ();
clearActiveSymbol ();
// epsilon
if ( transition.getTransitionType ().equals ( TransitionType.EPSILON_ONLY )
|| transition.getTransitionType ().equals (
TransitionType.EPSILON_SYMBOL ) )
{
Word readWord = transition.getPushDownWordRead ();
transition.getStateBegin ().setActive ( true );
transition.setActive ( true );
transition.getStateEnd ().setActive ( true );
for ( Symbol currentSymbol : transition )
{
if ( currentSymbol.isEpsilon () )
{
currentSymbol.setActive ( true );
break;
}
}
replaceStack ( readWord.size (), transition.getPushDownWordWrite () );
}
// no epsilon
else
{
Word readWord = transition.getPushDownWordRead ();
transition.setActive ( true );
transition.getStateEnd ().setActive ( true );
replaceStack ( readWord.size (), transition.getPushDownWordWrite () );
}
}
/**
* {@inheritDoc}
*
* @see Machine#previousSymbol()
*/
public final void previousSymbol ()
{
if ( this.history.size () == 0 )
{
throw new RuntimeException ( "history is empty" ); //$NON-NLS-1$
}
clearActiveState ();
clearActiveTransition ();
clearActiveSymbol ();
this.stack.clear ();
HistoryItem historyItem = this.history.remove ( this.history.size () - 1 );
ArrayList < Symbol > historyStackSymbolList = historyItem.getStack ().peak (
historyItem.getStack ().size () );
for ( int i = historyStackSymbolList.size () - 1 ; i >= 0 ; i-- )
{
this.stack.push ( historyStackSymbolList.get ( i ) );
}
for ( State current : historyItem.getStateSet () )
{
current.setActive ( true );
}
for ( Transition current : historyItem.getTransitionSet () )
{
current.setActive ( true );
}
for ( Symbol current : historyItem.getSymbolSet () )
{
current.setActive ( true );
}
if ( historyItem.isNextWordStep () )
{
try
{
this.word.previousSymbol ();
}
catch ( WordResetedException exc )
{
exc.printStackTrace ();
System.exit ( 1 );
return;
}
}
}
/**
* {@inheritDoc}
*
* @see Machine#removeMachineChangedListener(MachineChangedListener)
*/
public final void removeMachineChangedListener (
MachineChangedListener listener )
{
this.listenerList.add ( MachineChangedListener.class, listener );
}
/**
* {@inheritDoc}
*
* @see Machine#removeModifyStatusChangedListener(ModifyStatusChangedListener)
*/
public final void removeModifyStatusChangedListener (
ModifyStatusChangedListener listener )
{
this.listenerList.remove ( ModifyStatusChangedListener.class, listener );
}
/**
* {@inheritDoc}
*
* @see Machine#removeState(java.lang.Iterable)
*/
public final void removeState ( Iterable < State > states )
{
if ( states == null )
{
throw new NullPointerException ( "states is null" ); //$NON-NLS-1$
}
if ( !states.iterator ().hasNext () )
{
throw new IllegalArgumentException ( "states is empty" ); //$NON-NLS-1$
}
for ( State current : states )
{
removeState ( current );
}
}
/**
* {@inheritDoc}
*
* @see Machine#removeState(State)
*/
public final void removeState ( State state )
{
this.stateList.remove ( state );
for ( Transition current : state.getTransitionBegin () )
{
removeTransition ( current );
}
for ( Transition current : state.getTransitionEnd () )
{
removeTransition ( current );
}
fireTableDataChanged ();
state.removeStateChangedListener ( this.stateChangedListener );
state.removeModifyStatusChangedListener ( this.modifyStatusChangedListener );
fireModifyStatusChanged ( false );
}
/**
* {@inheritDoc}
*
* @see Machine#removeState(State[])
*/
public final void removeState ( State ... states )
{
if ( states == null )
{
throw new NullPointerException ( "states is null" ); //$NON-NLS-1$
}
if ( states.length == 0 )
{
throw new IllegalArgumentException ( "states is empty" ); //$NON-NLS-1$
}
for ( State current : states )
{
removeState ( current );
}
}
/**
* {@inheritDoc}
*
* @see Machine#removeSymbol(Symbol)
*/
public final void removeSymbol ( Symbol symbol )
{
this.alphabet.remove ( symbol );
}
/**
* {@inheritDoc}
*
* @see TableModel#removeTableModelListener(TableModelListener)
*/
public final void removeTableModelListener ( TableModelListener listener )
{
this.listenerList.remove ( TableModelListener.class, listener );
}
/**
* {@inheritDoc}
*
* @see Machine#removeTransition(java.lang.Iterable)
*/
public final void removeTransition ( Iterable < Transition > transitions )
{
if ( transitions == null )
{
throw new NullPointerException ( "transitions is null" ); //$NON-NLS-1$
}
if ( !transitions.iterator ().hasNext () )
{
throw new IllegalArgumentException ( "transitions is empty" ); //$NON-NLS-1$
}
for ( Transition current : transitions )
{
removeTransition ( current );
}
}
/**
* {@inheritDoc}
*
* @see Machine#removeTransition(Transition)
*/
public final void removeTransition ( Transition transition )
{
this.transitionList.remove ( transition );
for ( State current : this.stateList )
{
if ( current.getTransitionBegin ().contains ( transition ) )
{
current.removeTransitionBegin ( transition );
}
if ( current.getTransitionEnd ().contains ( transition ) )
{
current.removeTransitionEnd ( transition );
}
}
fireTableDataChanged ();
transition
.removeTransitionChangedListener ( this.transitionChangedListener );
transition
.removeModifyStatusChangedListener ( this.modifyStatusChangedListener );
fireModifyStatusChanged ( false );
}
/**
* {@inheritDoc}
*
* @see Machine#removeTransition(Transition[])
*/
public final void removeTransition ( Transition ... transitions )
{
if ( transitions == null )
{
throw new NullPointerException ( "transitions is null" ); //$NON-NLS-1$
}
if ( transitions.length == 0 )
{
throw new IllegalArgumentException ( "transitions is empty" ); //$NON-NLS-1$
}
for ( Transition current : transitions )
{
removeTransition ( current );
}
}
/**
* Replaces the first size members of the {@link Stack} with the given
* {@link Word}.
*
* @param size The number of {@link Symbol}s to replace.
* @param replacement The replacement.
*/
private final void replaceStack ( int size, Word replacement )
{
for ( int i = 0 ; i < size ; i++ )
{
this.stack.pop ();
}
for ( int i = replacement.size () - 1 ; i >= 0 ; i-- )
{
this.stack.push ( replacement.get ( i ) );
}
}
/**
* {@inheritDoc}
*
* @see Modifyable#resetModify()
*/
public final void resetModify ()
{
this.initialStateList.clear ();
this.initialStateList.addAll ( this.stateList );
this.initialTransitionList.clear ();
this.initialTransitionList.addAll ( this.transitionList );
this.alphabet.resetModify ();
this.pushDownAlphabet.resetModify ();
this.initialUsePushDownAlphabet = this.usePushDownAlphabet;
for ( State current : this.stateList )
{
current.resetModify ();
}
for ( Transition current : this.transitionList )
{
current.resetModify ();
}
}
/**
* {@inheritDoc}
*
* @see Machine#setSelectedState(State)
*/
public final void setSelectedState ( State state )
{
// reset
clearSelectedTransition ();
// find the row
int row = -1;
for ( int i = 0 ; i < this.stateList.size () ; i++ )
{
if ( this.stateList.get ( i ).equals ( state ) )
{
row = i;
break;
}
}
State chachedState = ( State ) getValueAt ( row, STATE_COLUMN );
chachedState.setSelected ( true );
}
/**
* {@inheritDoc}
*
* @see Machine#setSelectedTransition(ArrayList)
*/
public final void setSelectedTransition (
ArrayList < Transition > transitionList )
{
// reset
clearSelectedTransition ();
// transition
for ( Transition current : transitionList )
{
current.setSelected ( true );
}
for ( Transition current : transitionList )
{
// find the row
int row = -1;
for ( int i = 0 ; i < this.stateList.size () ; i++ )
{
if ( this.stateList.get ( i ).equals ( current.getStateBegin () ) )
{
row = i;
break;
}
}
if ( current.getTransitionType ().equals ( TransitionType.EPSILON_ONLY ) )
{
StateSet stateSet = ( StateSet ) getValueAt ( row, EPSILON_COLUMN );
for ( State currentState : stateSet )
{
if ( currentState.equals ( current.getStateEnd () ) )
{
currentState.setSelected ( true );
}
}
}
else if ( current.getTransitionType ().equals (
TransitionType.EPSILON_SYMBOL ) )
{
StateSet stateSet = ( StateSet ) getValueAt ( row, EPSILON_COLUMN );
for ( State currentState : stateSet )
{
if ( currentState.equals ( current.getStateEnd () ) )
{
currentState.setSelected ( true );
}
}
// find the columns
for ( int i = 0 ; i < this.alphabet.size () ; i++ )
{
for ( int j = 0 ; j < current.size () ; j++ )
{
if ( this.alphabet.get ( i ).equals ( current.getSymbol ( j ) ) )
{
int column = i + SPECIAL_COLUMN_COUNT;
stateSet = ( StateSet ) getValueAt ( row, column );
for ( State currentState : stateSet )
{
if ( currentState.equals ( current.getStateEnd () ) )
{
currentState.setSelected ( true );
}
}
}
}
}
}
else if ( current.getTransitionType ().equals ( TransitionType.SYMBOL ) )
{
// find the columns
for ( int i = 0 ; i < this.alphabet.size () ; i++ )
{
for ( int j = 0 ; j < current.size () ; j++ )
{
if ( this.alphabet.get ( i ).equals ( current.getSymbol ( j ) ) )
{
int column = i + SPECIAL_COLUMN_COUNT;
StateSet stateSet = ( StateSet ) getValueAt ( row, column );
for ( State currentState : stateSet )
{
if ( currentState.equals ( current.getStateEnd () ) )
{
currentState.setSelected ( true );
}
}
}
}
}
}
else
{
throw new RuntimeException ( "unsupported transition type" ); //$NON-NLS-1$
}
}
}
/**
* {@inheritDoc}
*
* @see Machine#setUsePushDownAlphabet(boolean)
*/
public final void setUsePushDownAlphabet ( boolean usePushDownAlphabet )
{
this.usePushDownAlphabet = usePushDownAlphabet;
fireModifyStatusChanged ( false );
}
/**
* {@inheritDoc}
*
* @see TableModel#setValueAt(Object, int, int)
*/
public final void setValueAt ( Object value, int rowIndex, int columnIndex )
{
// State column
if ( columnIndex == STATE_COLUMN )
{
throw new IllegalArgumentException (
"the state column should not be editable" ); //$NON-NLS-1$
}
if ( value == null )
{
logger.debug ( "setValueAt", "value is null" ); //$NON-NLS-1$ //$NON-NLS-2$
return;
}
State stateBegin = this.stateList.get ( rowIndex );
StateSet stateSetNew = ( StateSet ) value;
StateSet stateSetOld = ( StateSet ) getValueAt ( rowIndex, columnIndex );
logger.debug ( "setValueAt", "state begin: " + stateBegin.getName () ); //$NON-NLS-1$ //$NON-NLS-2$
logger.debug ( "setValueAt", "state set old: " + stateSetOld.toString () ); //$NON-NLS-1$ //$NON-NLS-2$
logger.debug ( "setValueAt", "state set new: " + stateSetNew.toString () ); //$NON-NLS-1$//$NON-NLS-2$
ArrayList < State > stateAdd = new ArrayList < State > ();
ArrayList < State > stateRemove = new ArrayList < State > ();
for ( State currentNew : stateSetNew )
{
boolean found = false;
for ( State currentOld : stateSetOld )
{
if ( currentNew.getName ().equals ( currentOld.getName () ) )
{
found = true;
break;
}
}
if ( !found )
{
for ( State stateMember : this.stateList )
{
if ( stateMember.getName ().equals ( currentNew.getName () ) )
{
stateAdd.add ( stateMember );
break;
}
}
}
}
for ( State currentOld : stateSetOld )
{
boolean found = false;
for ( State currentNew : stateSetNew )
{
if ( currentOld.getName ().equals ( currentNew.getName () ) )
{
found = true;
break;
}
}
if ( !found )
{
for ( State stateMember : this.stateList )
{
if ( stateMember.getName ().equals ( currentOld.getName () ) )
{
stateRemove.add ( stateMember );
break;
}
}
}
}
logger.debug ( "setValueAt", "state add: " + stateAdd ); //$NON-NLS-1$ //$NON-NLS-2$
logger.debug ( "setValueAt", "state remove: " + stateRemove ); //$NON-NLS-1$ //$NON-NLS-2$
ArrayList < Transition > transitionAdd = new ArrayList < Transition > ();
ArrayList < Transition > transitionRemove = new ArrayList < Transition > ();
ArrayList < ObjectPair < Transition, Symbol >> symbolsAdd = new ArrayList < ObjectPair < Transition, Symbol >> ();
ArrayList < ObjectPair < Transition, Symbol >> symbolsRemove = new ArrayList < ObjectPair < Transition, Symbol >> ();
// Add the transitions
for ( State currentState : stateAdd )
{
try
{
// Epsilon transition
if ( columnIndex == EPSILON_COLUMN )
{
logger.debug ( "setValueAt", "add transition: epsilon" ); //$NON-NLS-1$ //$NON-NLS-2$
Transition foundTransition = null;
loopTransition : for ( Transition currentTransition : this.transitionList )
{
if ( ( ! ( currentTransition.getTransitionType ().equals (
TransitionType.EPSILON_ONLY ) || currentTransition
.getTransitionType ().equals ( TransitionType.EPSILON_SYMBOL ) ) )
&& currentTransition.getStateBegin ().getName ().equals (
stateBegin.getName () )
&& currentTransition.getStateEnd ().getName ().equals (
currentState.getName () ) )
{
foundTransition = currentTransition;
break loopTransition;
}
}
if ( foundTransition == null )
{
Transition newTransition = new DefaultTransition ( this.alphabet,
this.pushDownAlphabet, new DefaultWord (), new DefaultWord (),
stateBegin, currentState );
newTransition.add ( new DefaultSymbol () );
transitionAdd.add ( newTransition );
}
else
{
symbolsAdd.add ( new ObjectPair < Transition, Symbol > (
foundTransition, new DefaultSymbol () ) );
}
}
// No epsilon transition
else
{
Transition foundTransition = null;
loopTransition : for ( Transition currentTransition : this.transitionList )
{
if ( currentTransition.getStateBegin ().getName ().equals (
stateBegin.getName () )
&& currentTransition.getStateEnd ().getName ().equals (
currentState.getName () ) )
{
foundTransition = currentTransition;
break loopTransition;
}
}
if ( foundTransition == null )
{
logger.debug ( "setValueAt", //$NON-NLS-1$
"add transition: no epsilon: transition not found" ); //$NON-NLS-1$
Transition newTransition = new DefaultTransition ( this.alphabet,
this.pushDownAlphabet, new DefaultWord (), new DefaultWord (),
stateBegin, currentState, this.alphabet.get ( columnIndex
- SPECIAL_COLUMN_COUNT ) );
transitionAdd.add ( newTransition );
}
else
{
logger.debug ( "setValueAt", //$NON-NLS-1$
"add transition: no epsilon: transition found" ); //$NON-NLS-1$
symbolsAdd.add ( new ObjectPair < Transition, Symbol > (
foundTransition, this.alphabet.get ( columnIndex
- SPECIAL_COLUMN_COUNT ) ) );
}
}
}
catch ( TransitionSymbolNotInAlphabetException exc )
{
exc.printStackTrace ();
System.exit ( 1 );
}
catch ( TransitionSymbolOnlyOneTimeException exc )
{
exc.printStackTrace ();
System.exit ( 1 );
}
}
// Remove the transitions and symbols
for ( State currentState : stateRemove )
{
for ( Transition currentTransition : this.transitionList )
{
if ( currentTransition.getStateBegin ().getName ().equals (
stateBegin.getName () )
&& currentTransition.getStateEnd ().getName ().equals (
currentState.getName () ) )
{
// Epsilon transition
if ( ( columnIndex == EPSILON_COLUMN )
&& currentTransition.getTransitionType ().equals (
TransitionType.EPSILON_ONLY ) )
{
logger.debug ( "setValueAt", "remove transition: epsilon" ); //$NON-NLS-1$ //$NON-NLS-2$
transitionRemove.add ( currentTransition );
}
else if ( ( columnIndex == EPSILON_COLUMN )
&& currentTransition.getTransitionType ().equals (
TransitionType.EPSILON_SYMBOL ) )
{
logger.debug (
"setValueAt", "remove transition: only epsilon symbol" ); //$NON-NLS-1$ //$NON-NLS-2$
for ( Symbol epsilonSymbol : currentTransition )
{
if ( epsilonSymbol.isEpsilon () )
{
symbolsRemove.add ( new ObjectPair < Transition, Symbol > (
currentTransition, epsilonSymbol ) );
break;
}
}
}
// No epsilon transition
else if ( columnIndex > EPSILON_COLUMN )
{
Symbol symbolColumn = this.alphabet.get ( columnIndex
- SPECIAL_COLUMN_COUNT );
Symbol symbolRemove = null;
loopSymbol : for ( Symbol currentSymbol : currentTransition
.getSymbol () )
{
if ( currentSymbol.equals ( symbolColumn ) )
{
symbolRemove = currentSymbol;
break loopSymbol;
}
}
if ( symbolRemove != null )
{
// The last symbol is removed
if ( currentTransition.size () == 1 )
{
logger.debug ( "setValueAt", //$NON-NLS-1$
"remove transition: no epsilon: remove transition" ); //$NON-NLS-1$
transitionRemove.add ( currentTransition );
}
// Only one symbol is removed
else
{
logger.debug ( "setValueAt", //$NON-NLS-1$
"remove transition: no epsilon: remove symbol" ); //$NON-NLS-1$
symbolsRemove.add ( new ObjectPair < Transition, Symbol > (
currentTransition, symbolRemove ) );
}
}
else
{
logger.debug ( "setValueAt", //$NON-NLS-1$
"remove transition: no epsilon: nothing found" ); //$NON-NLS-1$
}
}
else
{
logger.debug ( "setValueAt", //$NON-NLS-1$
"remove transition: epsilon column: no epsilon transition" ); //$NON-NLS-1$
}
}
}
}
if ( ( transitionAdd.size () > 0 ) || ( transitionRemove.size () > 0 )
|| ( symbolsAdd.size () > 0 ) || ( symbolsRemove.size () > 0 ) )
{
fireMachineChangedStartEditing ();
for ( Transition current : transitionAdd )
{
addTransition ( current );
fireMachineChangedTransitionAdded ( current );
}
for ( Transition current : transitionRemove )
{
removeTransition ( current );
fireMachineChangedTransitionRemoved ( current );
}
for ( ObjectPair < Transition, Symbol > current : symbolsAdd )
{
try
{
current.getFirst ().add ( current.getSecond () );
}
catch ( TransitionSymbolNotInAlphabetException exc )
{
exc.printStackTrace ();
System.exit ( 1 );
}
catch ( TransitionSymbolOnlyOneTimeException exc )
{
exc.printStackTrace ();
System.exit ( 1 );
}
ArrayList < Symbol > symbolList = new ArrayList < Symbol > ();
symbolList.add ( current.getSecond () );
fireMachineChangedSymbolAdded ( current.getFirst (), symbolList );
}
for ( ObjectPair < Transition, Symbol > current : symbolsRemove )
{
current.getFirst ().remove ( current.getSecond () );
ArrayList < Symbol > symbolList = new ArrayList < Symbol > ();
symbolList.add ( current.getSecond () );
fireMachineChangedSymbolRemoved ( current.getFirst (), symbolList );
}
fireMachineChangedStopEditing ();
}
}
/**
* {@inheritDoc}
*
* @see Machine#start(Word)
*/
public final void start ( Word startWord )
{
// Word
if ( startWord == null )
{
throw new NullPointerException ( "word is null" ); //$NON-NLS-1$
}
this.word = startWord;
this.word.start ();
this.stack.clear ();
clearHistory ();
for ( State current : this.stateList )
{
if ( current.isStartState () )
{
current.setActive ( true );
}
}
}
/**
* {@inheritDoc}
*
* @see Machine#stop
*/
public final void stop ()
{
this.word = null;
clearActiveState ();
clearActiveTransition ();
clearActiveSymbol ();
this.stack.clear ();
clearHistory ();
}
/**
* {@inheritDoc}
*
* @see Machine#validate()
*/
public final void validate () throws MachineValidationException
{
ArrayList < MachineException > machineExceptionList = new ArrayList < MachineException > ();
if ( this.validationElementList.contains ( ValidationElement.ALL_SYMBOLS ) )
{
machineExceptionList.addAll ( checkAllSymbols () );
}
if ( this.validationElementList
.contains ( ValidationElement.EPSILON_TRANSITION ) )
{
machineExceptionList.addAll ( checkEpsilonTransition () );
}
if ( this.validationElementList
.contains ( ValidationElement.TRANSITION_STACK_OPERATION ) )
{
machineExceptionList.addAll ( checkTransitionStackOperation () );
}
if ( this.validationElementList.contains ( ValidationElement.FINAL_STATE ) )
{
machineExceptionList.addAll ( checkFinalState () );
}
if ( this.validationElementList
.contains ( ValidationElement.MORE_THAN_ONE_START_STATE ) )
{
machineExceptionList.addAll ( checkMoreThanOneStartState () );
}
if ( this.validationElementList
.contains ( ValidationElement.NO_START_STATE ) )
{
machineExceptionList.addAll ( checkNoStartState () );
}
if ( this.validationElementList.contains ( ValidationElement.STATE_NAME ) )
{
machineExceptionList.addAll ( checkStateName () );
}
if ( this.validationElementList
.contains ( ValidationElement.STATE_NOT_REACHABLE ) )
{
machineExceptionList.addAll ( checkStateNotReachable () );
}
if ( this.validationElementList
.contains ( ValidationElement.SYMBOL_ONLY_ONE_TIME ) )
{
machineExceptionList.addAll ( checkSymbolOnlyOneTime () );
}
// Throw the exception if a warning or an error has occurred.
if ( machineExceptionList.size () > 0 )
{
throw new MachineValidationException ( machineExceptionList );
}
}
}