diff --git a/pom.xml b/pom.xml index 62622c5..cbea213 100644 --- a/pom.xml +++ b/pom.xml @@ -17,9 +17,8 @@ org.projectlombok lombok - 1.18.18 + 1.18.20 provided - true \ No newline at end of file diff --git a/src/main/java/nl/andrewlalis/grammar_tool/machine/FiniteStateMachine.java b/src/main/java/nl/andrewlalis/grammar_tool/machine/FiniteStateMachine.java new file mode 100644 index 0000000..60a6f5d --- /dev/null +++ b/src/main/java/nl/andrewlalis/grammar_tool/machine/FiniteStateMachine.java @@ -0,0 +1,63 @@ +package nl.andrewlalis.grammar_tool.machine; + +import nl.andrewlalis.grammar_tool.grammar.Symbol; + +import java.util.Objects; +import java.util.Set; + +public class FiniteStateMachine { + private final Set alphabet; + private final Set states; + private final Set finalStates; + private final State startState; + private final Set transitions; + + public FiniteStateMachine(Set alphabet, Set states, Set finalStates, State startState, Set transitions) { + this.alphabet = alphabet; + this.states = states; + this.finalStates = finalStates; + this.startState = startState; + this.transitions = transitions; + this.ensureValidElements(); + } + + private void ensureValidElements() { + if (!this.states.contains(this.startState)) { + throw new IllegalArgumentException("Start state is not an element of the whole set of states."); + } + if (!this.states.containsAll(this.finalStates)) { + throw new IllegalArgumentException("Not all final states belong to the whole set of states."); + } + if (this.finalStates.isEmpty()) { + throw new IllegalArgumentException("No final states. There must be at least one final state."); + } + for (Transition t : this.transitions) { + if (!this.states.contains(t.getStartState())) { + throw new IllegalArgumentException("Start state of transition does not belong to the whole set of states: " + t); + } + if (!this.states.contains(t.getEndState())) { + throw new IllegalArgumentException("End state of transition does not belong to the whole set of states: " + t); + } + if (!this.alphabet.contains(t.getAcceptingSymbol())) { + throw new IllegalArgumentException("Accepting symbol of transition is not in the alphabet: " + t); + } + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FiniteStateMachine that = (FiniteStateMachine) o; + return alphabet.equals(that.alphabet) && + states.equals(that.states) && + finalStates.equals(that.finalStates) && + startState.equals(that.startState) && + transitions.equals(that.transitions); + } + + @Override + public int hashCode() { + return Objects.hash(alphabet, states, finalStates, startState, transitions); + } +} diff --git a/src/main/java/nl/andrewlalis/grammar_tool/machine/State.java b/src/main/java/nl/andrewlalis/grammar_tool/machine/State.java new file mode 100644 index 0000000..eaf30bd --- /dev/null +++ b/src/main/java/nl/andrewlalis/grammar_tool/machine/State.java @@ -0,0 +1,29 @@ +package nl.andrewlalis.grammar_tool.machine; + +import java.util.Objects; + +public class State { + private final String name; + + public State(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + State state = (State) o; + return name.equals(state.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public String toString() { + return this.name; + } +} diff --git a/src/main/java/nl/andrewlalis/grammar_tool/machine/Transition.java b/src/main/java/nl/andrewlalis/grammar_tool/machine/Transition.java new file mode 100644 index 0000000..993d693 --- /dev/null +++ b/src/main/java/nl/andrewlalis/grammar_tool/machine/Transition.java @@ -0,0 +1,39 @@ +package nl.andrewlalis.grammar_tool.machine; + +import lombok.Getter; +import nl.andrewlalis.grammar_tool.grammar.Symbol; + +import java.util.Objects; + +@Getter +public class Transition { + private final State startState; + private final Symbol acceptingSymbol; + private final State endState; + + public Transition(State startState, Symbol acceptingSymbol, State endState) { + this.startState = startState; + this.acceptingSymbol = acceptingSymbol; + this.endState = endState; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Transition that = (Transition) o; + return startState.equals(that.startState) && + acceptingSymbol.equals(that.acceptingSymbol) && + endState.equals(that.endState); + } + + @Override + public int hashCode() { + return Objects.hash(startState, acceptingSymbol, endState); + } + + @Override + public String toString() { + return String.format("%s (%s) -> %s", this.startState, this.acceptingSymbol, this.endState); + } +}