package pl.edu.amu.wmi.daut.base;
import java.util.List;
/**
*
* @author tomekd
*
* Klasa odpowiedzialna za zbudowanie poprawnego automatu, po pobraniu
* informacji z metody toString() wykonanej na wybranym automacie.
*
*/
public class MakeAutomatonFromString {
private static final int TRANSITION_PARTS = 3;
private static final int LABEL_LENGHT = 4;
private static final int FINAL_STR_INDEX = 3;
private static final int MINIMUM_TABLE_SIZE = 5;
private String[] codeTable;
private List<State> stateList;
private int transitionPoiner, initialPointer;
private AutomatonSpecification automaton;
/**
* Konstruktor przyjmujący za argumenty automat (powinien być pusty!) i
* strumień znaków, który pochodzi z metody toString() automatu.
* @param emptyAutomaton pusty automat, na którym chcemy zbudować wybrany automat
* @param description opis automatu w formie, jaką zwraca metoda toString()
*/
public MakeAutomatonFromString(AutomatonSpecification emptyAutomaton, String description) {
automaton = emptyAutomaton;
codeTable = description.split("\\s+");
stateList = automaton.allStates();
}
private boolean isCorrectStateName(String name) {
if (name.length() < 2)
return false;
if (!name.startsWith("q"))
return false;
try {
Integer.decode(name.substring(1));
} catch (NumberFormatException exp) {
return false;
}
return true;
}
private boolean isCorrectLabel(String name) {
if (name.equals("-epsilon->"))
return true;
if (name.equals("-ANY->"))
return true;
if (name.startsWith("-[") && name.endsWith("]->"))
return true;
if (!(name.length() == LABEL_LENGHT))
return false;
if (!name.startsWith("-"))
return false;
if (!name.endsWith("->"))
return false;
return true;
}
private void checkStates() throws StructureException {
for (int i = 2; i < codeTable.length; ++i) {
if (!isCorrectStateName(codeTable[i])) {
if (!codeTable[i].equals("-Transitions:")) {
throw new StructureException();
} else {
transitionPoiner = i;
break;
}
}
}
}
private void checkTransitions() throws StructureException {
for (int i = transitionPoiner + 1; i < codeTable.length; i += TRANSITION_PARTS) {
if (codeTable[i].equals("-Initial")) {
initialPointer = i;
break;
} else {
if (!isCorrectStateName(codeTable[i]))
throw new StructureException();
if (!isCorrectLabel(codeTable[i + 1]))
throw new StructureException();
if (!isCorrectStateName(codeTable[i + 2]))
throw new StructureException();
}
}
}
private void isCorrectSpecialState() throws StructureException {
if (!codeTable[initialPointer + 1].equals("state:"))
throw new StructureException();
if (!isCorrectStateName(codeTable[initialPointer + 2]))
throw new StructureException();
if (!codeTable[initialPointer + FINAL_STR_INDEX]
.equals("-Final"))
throw new StructureException();
if (!codeTable[initialPointer + FINAL_STR_INDEX + 1]
.equals("states:"))
throw new StructureException();
for (int it = initialPointer + FINAL_STR_INDEX + 2; it < codeTable.length; ++it) {
if (!isCorrectStateName(codeTable[it]))
throw new StructureException();
}
}
private void isCorrectInitialWords() throws StructureException {
if (codeTable.length < MINIMUM_TABLE_SIZE)
throw new StructureException();
if (!codeTable[0].equals("Automaton:"))
throw new StructureException();
if (!codeTable[1].equals("-States:"))
throw new StructureException();
}
/**
* Sprawdza czy podany ciag znaków jest poprawny; jeżeli tak
* to dodaje stany i przejścia zgodnie z danym opisem automatu.
* @throws StructureException zwracany, gdy podany ciąg znaków jest niepoprawny.
*/
public void make() throws StructureException {
isCorrectInitialWords();
checkStates();
checkTransitions();
isCorrectSpecialState();
constructGraph();
}
private int getIndex(String stateName) {
String indexStr = stateName.substring(1);
return Integer.decode(indexStr);
}
private TransitionLabel getLabel(String name) throws StructureException {
if (name.length() == LABEL_LENGHT)
return new CharTransitionLabel(name.charAt(1));
if (name.equals("-epsilon->"))
return new EpsilonTransitionLabel();
if (name.startsWith("-[") && name.endsWith("]->"))
return new ComplementCharClassTransitionLabel(name
.substring(2, name.length() - 2));
if (name.equals("-ANY->"))
return new AnyTransitionLabel();
throw new StructureException();
}
private void constructGraph() throws StructureException {
for (int i = 0; i < transitionPoiner - 2; ++i)
automaton.addState();
automaton.markAsInitial(stateList
.get(getIndex(codeTable[initialPointer + 2])));
for (int i = initialPointer + FINAL_STR_INDEX + 2; i < codeTable.length; ++i) {
automaton.markAsFinal(stateList.get(getIndex(codeTable[i])));
}
for (int i = transitionPoiner + 1; i < initialPointer; i += TRANSITION_PARTS) {
automaton.addTransition(stateList.get(getIndex(codeTable[i])),
stateList.get(getIndex(codeTable[i + 2])),
getLabel(codeTable[i + 1]));
}
}
}