/*
* JFLAP - Formal Languages and Automata Package
*
*
* Susan H. Rodger
* Computer Science Department
* Duke University
* August 27, 2009
* Copyright (c) 2002-2009
* All rights reserved.
* JFLAP is open source software. Please see the LICENSE for terms.
*
*/
package automata.fsa;
import grammar.Production;
import grammar.reg.RegularGrammar;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import automata.Automaton;
import automata.State;
import automata.Transition;
/**
* The FSA to regular grammar converter can be used to convert a finite state
* automaton into an equivalent regular grammar. The fsa and grammar will be
* equivalent in that they will accept exactly the same language. In order to
* use this converter you must first call initializeConverter to map the states
* in the fsa to variables in the regular grammar. Then you can perform the
* conversion simply by calling convertToRegularGrammar, or you can perform the
* conversion step by step by repeatedly calling getProductionForTransition for
* every transition in the automaton and adding the returned productions to the
* grammar. If you do this for every Transition in the fsa, you will have an
* equivalent regular grammar.
*
* @see grammar.reg.RegularGrammar
*
* @author Ryan Cavalcante
*/
public class FSAToRegularGrammarConverter {
/**
* Creates an instance of FSAToRegularGrammarConverter
*/
public FSAToRegularGrammarConverter() {
}
/**
* Maps the states in automaton
to the variables in the
* grammar the converter will produce.
*
* @param automaton
* the automaton.
*/
public void initializeConverter(Automaton automaton) {
MAP = new HashMap();
State[] states = automaton.getStates();
State initialState = automaton.getInitialState();
// Do the variables.
VARIABLE = new LinkedList();
for (char c = 'A'; c <= 'Z'; c++)
VARIABLE.add("" + c);
// Map the initial state to S.
if (initialState != null) {
VARIABLE.remove(START_VARIABLE);
MAP.put(initialState, START_VARIABLE);
}
// Assign variables to the other states.
List stateList = new ArrayList(Arrays.asList(states));
stateList.remove(initialState);
Collections.sort(stateList, new Comparator() {
public int compare(Object o1, Object o2) {
return ((State) o1).getID() - ((State) o2).getID();
}
public boolean equals(Object o) {
return false;
}
});
Iterator it = stateList.iterator();
while (it.hasNext()) {
State state = (State) it.next();
MAP.put(state, VARIABLE.removeFirst());
}
}
/**
* Returns a production object that is equivalent to transition
.
*
* @param transition
* the transition.
* @return a produciton object that is equivalent to transition
.
*/
public Production getProductionForTransition(Transition transition) {
FSATransition trans = (FSATransition) transition;
State toState = trans.getToState();
State fromState = trans.getFromState();
String label = trans.getLabel();
String lhs = (String) MAP.get(fromState);
String rhs = label.concat((String) MAP.get(toState));
Production production = new Production(lhs, rhs);
return production;
}
/**
* Returns a lambda production on the variable mapped to state
* in map
.
*
* @param automaton
* the automaton that state
is in.
* @param state
* the state to make the lambda production for.
* @return a lambda production on the variable mapped to state
* in MAP
.
*/
public Production getLambdaProductionForFinalState(Automaton automaton,
State state) {
/** Check if state is a final state. */
if (!automaton.isFinalState(state)) {
System.err.println(state + " IS NOT A FINAL STATE");
return null;
}
String llhs = (String) MAP.get(state);
String lrhs = LAMBDA;
Production lprod = new Production(llhs, lrhs);
return lprod;
}
/**
* Returns a RegularGrammar object that represents a grammar equivalent to
* automaton
.
*
* @param automaton
* the automaton.
* @return a regular grammar equivalent to automaton
*/
public RegularGrammar convertToRegularGrammar(Automaton automaton) {
/** check if automaton is fsa. */
if (!(automaton instanceof FiniteStateAutomaton)) {
System.err.println("ATTEMPTING TO CONVERT NON FSA TO "
+ "REGULAR GRAMMAR");
return null;
}
RegularGrammar grammar = new RegularGrammar();
/** map states in automaton to variables in grammar. */
initializeConverter(automaton);
/**
* go through all transitions in automaton, creating production for
* each.
*/
Transition[] transitions = automaton.getTransitions();
for (int k = 0; k < transitions.length; k++) {
Production production = getProductionForTransition(transitions[k]);
grammar.addProduction(production);
}
/**
* for all final states in automaton, add lambda production.
*/
State[] finalStates = automaton.getFinalStates();
for (int j = 0; j < finalStates.length; j++) {
Production lprod = getLambdaProductionForFinalState(automaton,
finalStates[j]);
grammar.addProduction(lprod);
}
return grammar;
}
/**
* Returns the variable in the grammar corresponding to the state.
*
* @param state
* the state to get the variable for
* @return the variable in the grammar corresponding to the state, or null
* if there is no variable corresponding to this state
*/
public String variableForState(State state) {
return (String) MAP.get(state);
}
/** The map of states in the fsa to variables in the grammar. */
protected HashMap MAP;
/** The start variable. */
protected static final String START_VARIABLE = "S";
/** The string for lambda. */
protected static final String LAMBDA = "";
/** The list of unclaimed variable symbols. */
protected LinkedList VARIABLE;
}