From 37d302bbb3c6c24b4230ee432c84ead9aa25af69 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Mon, 30 Jun 2014 20:36:36 +0200 Subject: [PATCH] ENFA to StringParser and Composer --- alib2/src/alphabet/SymbolFromStringParser.h | 7 + .../FSM/FiniteAutomatonFromStringLexer.cpp | 85 ++++++++ .../FSM/FiniteAutomatonFromStringLexer.h | 42 ++++ .../FSM/FiniteAutomatonFromStringParser.cpp | 193 ++++++++++++++++++ .../FSM/FiniteAutomatonFromStringParser.h | 43 ++++ .../FSM/FiniteAutomatonToStringComposer.cpp | 125 ++++++++++++ .../FSM/FiniteAutomatonToStringComposer.h | 42 ++++ alib2/src/label/LabelFromStringParser.h | 7 + alib2/test-src/automaton/AutomatonTest.cpp | 27 +++ alib2/test-src/automaton/AutomatonTest.h | 2 + 10 files changed, 573 insertions(+) create mode 100644 alib2/src/automaton/FSM/FiniteAutomatonFromStringLexer.cpp create mode 100644 alib2/src/automaton/FSM/FiniteAutomatonFromStringLexer.h create mode 100644 alib2/src/automaton/FSM/FiniteAutomatonFromStringParser.cpp create mode 100644 alib2/src/automaton/FSM/FiniteAutomatonFromStringParser.h create mode 100644 alib2/src/automaton/FSM/FiniteAutomatonToStringComposer.cpp create mode 100644 alib2/src/automaton/FSM/FiniteAutomatonToStringComposer.h diff --git a/alib2/src/alphabet/SymbolFromStringParser.h b/alib2/src/alphabet/SymbolFromStringParser.h index 59050e04eb..f62d3b8fc5 100644 --- a/alib2/src/alphabet/SymbolFromStringParser.h +++ b/alib2/src/alphabet/SymbolFromStringParser.h @@ -27,6 +27,12 @@ class RegExpFromStringParser; } /* namespace regexp */ +namespace automaton { + +class FiniteAutomatonFromStringParser; + +} /* namespace automaton */ + namespace alphabet { class SymbolFromStringParser { @@ -43,6 +49,7 @@ public: Symbol parseValue(); friend class string::StringFromStringParser; friend class regexp::RegExpFromStringParser; + friend class automaton::FiniteAutomatonFromStringParser; }; } /* namespace alphabet */ diff --git a/alib2/src/automaton/FSM/FiniteAutomatonFromStringLexer.cpp b/alib2/src/automaton/FSM/FiniteAutomatonFromStringLexer.cpp new file mode 100644 index 0000000000..11a14a6360 --- /dev/null +++ b/alib2/src/automaton/FSM/FiniteAutomatonFromStringLexer.cpp @@ -0,0 +1,85 @@ +#include "FiniteAutomatonFromStringLexer.h" + +namespace automaton { + +FiniteAutomatonFromStringLexer::FiniteAutomatonFromStringLexer(std::stringstream& in) : m_In(in) { + m_Current.type = TokenType::ERROR; + m_Current.value = ""; +} + +FiniteAutomatonFromStringLexer& FiniteAutomatonFromStringLexer::next() { + char character; + m_Current.value = ""; + + std::streampos pos = m_In.tellg(); +L0: + character = m_In.get(); + if(m_In.eof()) { + m_In.seekg(pos); + m_Current.type = TokenType::TEOF; + return *this; + } else if(character == ' ' || character == '\t') { + goto L0; + } else if(character == '\n') { + m_Current.type = TokenType::NEW_LINE; + m_Current.value += character; + return *this; + } else if(character == '<') { + m_Current.type = TokenType::OUT; + m_Current.value += character; + return *this; + } else if(character == '>') { + m_Current.type = TokenType::IN; + m_Current.value += character; + return *this; + } else if(character == '|') { + m_Current.type = TokenType::SEPARATOR; + m_Current.value += character; + return *this; + } else if(character == '-') { + m_Current.type = TokenType::NONE; + m_Current.value += character; + return *this; + } else if(character == '#') { + m_Current.value += character; + goto L1; + } else if(m_In.seekg(pos), m_In >> "ENFA") { + m_Current.type = TokenType::EPSILON_NFA; + m_Current.value = "ENFA"; + return *this; + } else if(m_In.clear(), m_In >> "NFA") { + m_Current.type = TokenType::NFA; + m_Current.value = "NFA"; + return *this; + } else if(m_In.clear(), m_In >> "DFA") { + m_Current.type = TokenType::DFA; + m_Current.value = "DFA"; + return *this; + } else { + m_In.clear(); + m_In.seekg(pos); + m_Current.type = TokenType::ERROR; + return *this; + } +L1: + character = m_In.get(); + if(m_In.eof()) { + m_In.seekg(pos); + m_Current.type = TokenType::ERROR; + return *this; + } else if(character == 'E') { + m_Current.value += character; + m_Current.type = TokenType::EPSILON; + return *this; + } else { + m_In.seekg(pos); + m_Current.type = TokenType::ERROR; + return *this; + } +} + +FiniteAutomatonFromStringLexer::Token FiniteAutomatonFromStringLexer::token() { + return m_Current; +} + +} /* namespace automaton */ diff --git a/alib2/src/automaton/FSM/FiniteAutomatonFromStringLexer.h b/alib2/src/automaton/FSM/FiniteAutomatonFromStringLexer.h new file mode 100644 index 0000000000..1683ee5c15 --- /dev/null +++ b/alib2/src/automaton/FSM/FiniteAutomatonFromStringLexer.h @@ -0,0 +1,42 @@ +#ifndef FINITE_AUTOMATON_FROM_STRING_LEXER_H_ +#define FINITE_AUTOMATON_FROM_STRING_LEXER_H_ + +#include <string> +#include <sstream> +#include "../../std/istream.h" + +namespace automaton { + +class FiniteAutomatonFromStringLexer { +public: + enum class TokenType { + EPSILON_NFA, + NFA, + DFA, + OUT, + IN, + EPSILON, + SEPARATOR, + NONE, + NEW_LINE, + TEOF, + ERROR + }; + + struct Token { + TokenType type; + std::string value; + }; +private: + std::stringstream& m_In; + Token m_Current; +public: + + FiniteAutomatonFromStringLexer(std::stringstream&); + FiniteAutomatonFromStringLexer& next(); + Token token(); +}; + +} /* namepsace automaton */ + +#endif /* FINITE_AUTOMATON_FROM_STRING_LEXER_H_ */ diff --git a/alib2/src/automaton/FSM/FiniteAutomatonFromStringParser.cpp b/alib2/src/automaton/FSM/FiniteAutomatonFromStringParser.cpp new file mode 100644 index 0000000000..f2bcd8e838 --- /dev/null +++ b/alib2/src/automaton/FSM/FiniteAutomatonFromStringParser.cpp @@ -0,0 +1,193 @@ +#include "FiniteAutomatonFromStringParser.h" + +#include "../../AlibException.h" + +#include "EpsilonNFA.h" +#include "NFA.h" +#include "DFA.h" + +#include "../../label/Label.h" +#include "../../label/IntegerLabel.h" + +namespace automaton { + +FiniteAutomatonFromStringParser::FiniteAutomatonFromStringParser(std::stringstream& input) : m_FiniteAutomatonLexer(input), m_SymbolParser(input), m_LabelParser(input) { + +} + +Automaton FiniteAutomatonFromStringParser::parse() { + return parse(std::set<FEATURES>({FEATURES::EPSILON_NFA, FEATURES::NFA, FEATURES::DFA})); +} + +Automaton FiniteAutomatonFromStringParser::parse(const std::set<FEATURES>& features) { + FiniteAutomatonFromStringLexer::Token token = m_FiniteAutomatonLexer.token(); + if(token.type == FiniteAutomatonFromStringLexer::TokenType::EPSILON_NFA) { + if(!features.count(FEATURES::EPSILON_NFA)) throw alib::AlibException(); + return Automaton(parseEpsilonNFA()); + } else if(token.type == FiniteAutomatonFromStringLexer::TokenType::NFA) { + if(!features.count(FEATURES::NFA)) throw alib::AlibException(); + return Automaton(parseNFA()); + } else if(token.type == FiniteAutomatonFromStringLexer::TokenType::DFA) { + if(!features.count(FEATURES::DFA)) throw alib::AlibException(); + return Automaton(parseDFA()); + } else { + throw alib::AlibException(); + } +} + +Automaton FiniteAutomatonFromStringParser::parseValue() { + first(); + Automaton res = parse(); + + FiniteAutomatonFromStringLexer::Token token = m_FiniteAutomatonLexer.token(); + if(token.type == FiniteAutomatonFromStringLexer::TokenType::TEOF) { + return std::move(res); + } else { + throw alib::AlibException(); + } +} + +bool FiniteAutomatonFromStringParser::first() { + FiniteAutomatonFromStringLexer::Token token = m_FiniteAutomatonLexer.next().token(); + if(token.type == FiniteAutomatonFromStringLexer::TokenType::EPSILON_NFA || token.type == FiniteAutomatonFromStringLexer::TokenType::NFA || token.type == FiniteAutomatonFromStringLexer::TokenType::DFA) { + return true; + } else { + return false; + } +} + +bool FiniteAutomatonFromStringParser::next() { + FiniteAutomatonFromStringLexer::Token token = m_FiniteAutomatonLexer.next().token(); + if(token.type == FiniteAutomatonFromStringLexer::TokenType::EPSILON_NFA || token.type == FiniteAutomatonFromStringLexer::TokenType::NFA || token.type == FiniteAutomatonFromStringLexer::TokenType::DFA || token.type == FiniteAutomatonFromStringLexer::TokenType::OUT || token.type == FiniteAutomatonFromStringLexer::TokenType::IN || token.type == FiniteAutomatonFromStringLexer::TokenType::EPSILON || token.type == FiniteAutomatonFromStringLexer::TokenType::SEPARATOR || token.type == FiniteAutomatonFromStringLexer::TokenType::NONE || token.type == FiniteAutomatonFromStringLexer::TokenType::NEW_LINE) { + return true; + } else { + return false; + } +} + +Automaton* FiniteAutomatonFromStringParser::parsePointer() { + if(first()) { + return new Automaton(parse()); + } else { + return NULL; + } +} + +EpsilonNFA FiniteAutomatonFromStringParser::parseEpsilonNFA() { + EpsilonNFA res; + + FiniteAutomatonFromStringLexer::Token token = m_FiniteAutomatonLexer.token(); + if(token.type != FiniteAutomatonFromStringLexer::TokenType::EPSILON_NFA) { + throw alib::AlibException(); + } + std::vector<std::variant<string::Epsilon, alphabet::Symbol> > symbols; + + next() || m_SymbolParser.first() || m_SymbolParser.m_LabelParser.first(); + token = m_FiniteAutomatonLexer.token(); + while(token.type != FiniteAutomatonFromStringLexer::TokenType::NEW_LINE) { + if(token.type == FiniteAutomatonFromStringLexer::TokenType::ERROR) { + alphabet::Symbol symbol = m_SymbolParser.parse(); + res.addInputSymbol(symbol); + + std::variant<string::Epsilon, alphabet::Symbol> symbolVariant; + symbolVariant.set<alphabet::Symbol>(symbol); + symbols.push_back(symbolVariant); + } else if(token.type == FiniteAutomatonFromStringLexer::TokenType::EPSILON) { + symbols.push_back(std::variant<string::Epsilon, alphabet::Symbol>()); + } + + next() || m_SymbolParser.first() || m_SymbolParser.m_LabelParser.first(); + token = m_FiniteAutomatonLexer.token(); + } + + token = m_FiniteAutomatonLexer.token(); + if(token.type != FiniteAutomatonFromStringLexer::TokenType::NEW_LINE) throw alib::AlibException(); + + next() || m_LabelParser.first(); + parseEpsilonNFATransition(res, symbols); + token = m_FiniteAutomatonLexer.token(); + + while(token.type == FiniteAutomatonFromStringLexer::TokenType::NEW_LINE) { + next() || m_LabelParser.first(); + token = m_FiniteAutomatonLexer.token(); + if(token.type == FiniteAutomatonFromStringLexer::TokenType::TEOF) break; + + parseEpsilonNFATransition(res, symbols); + token = m_FiniteAutomatonLexer.token(); + } + + return res; +} + +NFA FiniteAutomatonFromStringParser::parseNFA() { + NFA res; + + return res; +} + +DFA FiniteAutomatonFromStringParser::parseDFA() { + DFA res(State(label::Label(label::IntegerLabel(0))));; + + return res; +} + +void FiniteAutomatonFromStringParser::parseEpsilonNFATransition(EpsilonNFA& res, const std::vector<std::variant<string::Epsilon, alphabet::Symbol> >& symbols) { + bool initial = false; + bool final = false; + + FiniteAutomatonFromStringLexer::Token token = m_FiniteAutomatonLexer.token(); + if(token.type == FiniteAutomatonFromStringLexer::TokenType::IN) { + initial = true; + next() || m_LabelParser.first(); + token = m_FiniteAutomatonLexer.token(); + + if(token.type == FiniteAutomatonFromStringLexer::TokenType::OUT) { + final = true; + next() || m_LabelParser.first(); + } + } else if(token.type == FiniteAutomatonFromStringLexer::TokenType::OUT) { + final = true; + next() || m_LabelParser.first(); + token = m_FiniteAutomatonLexer.token(); + + if(token.type == FiniteAutomatonFromStringLexer::TokenType::IN) { + initial = true; + next() || m_LabelParser.first(); + } + } + + State from(m_LabelParser.parse()); + res.addState(from); + if(initial) res.addInitialState(from); + if(final) res.addFinalState(from); + + next() || m_LabelParser.first(); + + std::vector<std::variant<string::Epsilon, alphabet::Symbol>>::const_iterator iter = symbols.begin(); + do { + if(iter == symbols.end()) throw alib::AlibException(); + + token = m_FiniteAutomatonLexer.token(); + if(token.type != FiniteAutomatonFromStringLexer::TokenType::NONE) { + + do { + State to(m_LabelParser.parse()); + res.addState(to); + res.addTransition(from, *iter, to); + + next() || m_LabelParser.first(); + token = m_FiniteAutomatonLexer.token(); + if(token.type != FiniteAutomatonFromStringLexer::TokenType::SEPARATOR) break; + + next() || m_LabelParser.first(); + } while(true); + } else { + next() || m_LabelParser.first(); + token = m_FiniteAutomatonLexer.token(); + } + iter++; + } while(token.type != FiniteAutomatonFromStringLexer::TokenType::NEW_LINE); + if(iter != symbols.end()) throw alib::AlibException(); +} + +} /* namespace automaton */ diff --git a/alib2/src/automaton/FSM/FiniteAutomatonFromStringParser.h b/alib2/src/automaton/FSM/FiniteAutomatonFromStringParser.h new file mode 100644 index 0000000000..9b35c28dd7 --- /dev/null +++ b/alib2/src/automaton/FSM/FiniteAutomatonFromStringParser.h @@ -0,0 +1,43 @@ +#ifndef FINITE_AUTOMATON_FROM_STRING_PARSER_H_ +#define FINITE_AUTOMATON_FROM_STRING_PARSER_H_ + +#include "FiniteAutomatonFromStringLexer.h" +#include "../../alphabet/SymbolFromStringParser.h" +#include "../../label/LabelFromStringParser.h" + +#include "../Automaton.h" +#include "../AutomatonFeatures.h" + +#include "../../std/variant.hpp" + +#include "../../string/Epsilon.h" + +namespace automaton { + +class FiniteAutomatonFromStringParser { + FiniteAutomatonFromStringLexer m_FiniteAutomatonLexer; + alphabet::SymbolFromStringParser m_SymbolParser; + label::LabelFromStringParser m_LabelParser; + + Automaton parse(); + Automaton parse(const std::set<FEATURES>& features); + bool next(); + + EpsilonNFA parseEpsilonNFA(); + NFA parseNFA(); + DFA parseDFA(); + void parseEpsilonNFATransition(EpsilonNFA& res, const std::vector<std::variant<string::Epsilon, alphabet::Symbol> >& symbols); + void parseNFATransition(NFA& res, const std::vector<alphabet::Symbol> symbols); + void parseDFATransition(DFA& res, const std::vector<alphabet::Symbol> symbols); +public: + FiniteAutomatonFromStringParser(std::stringstream& input); + + Automaton parseValue(); + bool first(); + Automaton* parsePointer(); + +}; + +} /* namespace automaton */ + +#endif /* FINITE_AUTOMATON_FROM_STRING_PARSER_H_ */ diff --git a/alib2/src/automaton/FSM/FiniteAutomatonToStringComposer.cpp b/alib2/src/automaton/FSM/FiniteAutomatonToStringComposer.cpp new file mode 100644 index 0000000000..c024932d7a --- /dev/null +++ b/alib2/src/automaton/FSM/FiniteAutomatonToStringComposer.cpp @@ -0,0 +1,125 @@ +#include "FiniteAutomatonToStringComposer.h" +#include "../../AlibException.h" + +#include "../../alphabet/SymbolToStringComposer.h" +#include "../../label/LabelToStringComposer.h" + +namespace automaton { + +void FiniteAutomatonToStringComposer::composeTransitionsFromState(std::stringstream& out, const EpsilonNFA& automaton, const State& from) const { + std::map<std::pair<State, alphabet::Symbol>, std::set<State> > symbolTransitionsFromState = automaton.getSymbolTransitionsFromState(from); + + for(const alphabet::Symbol& inputSymbol : automaton.getInputAlphabet()) { + const std::map<std::pair<State, alphabet::Symbol>, std::set<State> >::iterator toStates = symbolTransitionsFromState.find(std::make_pair(from, inputSymbol)); + if(toStates == symbolTransitionsFromState.end() || toStates->second.size() == 0) { + out << " -"; + } else { + bool sign = false; + for(const State& to : toStates->second) { + label::LabelToStringComposer composer; + out << (sign ? "|" : " ") << composer.compose(to.getName()); + sign = true; + } + } + } + + std::map<State, std::set<State> > epsilonTransitionsFromState = automaton.getEpsilonTransitionsFromState(from); + if(epsilonTransitionsFromState.size() == 0 || epsilonTransitionsFromState.begin()->second.size() == 0) { + out << " -"; + } else { + bool sign = false; + for(const State& to : epsilonTransitionsFromState.begin()->second) { + label::LabelToStringComposer composer; + out << (sign ? "|" : " ") << composer.compose(to.getName()); + sign = true; + } + } +} + +std::string FiniteAutomatonToStringComposer::compose(const DFA& automaton) const { + std::stringstream out; + + + return out.str(); +} + +std::string FiniteAutomatonToStringComposer::compose(const NFA& automaton) const { + std::stringstream out; + + + return out.str(); +} + +std::string FiniteAutomatonToStringComposer::compose(const EpsilonNFA& automaton) const { + std::stringstream out; + + out << "ENFA"; + for(auto iterSymbol = automaton.getInputAlphabet().begin(); iterSymbol != automaton.getInputAlphabet().end(); iterSymbol++) { + alphabet::SymbolToStringComposer composer; + out << " " << composer.compose(*iterSymbol); + } + + out << " #E"; + out << std::endl; + + for(auto iterState = automaton.getStates().begin(); iterState != automaton.getStates().end(); iterState++) { + if(automaton.getInitialStates().find(*iterState) != automaton.getInitialStates().end()) { + out << ">"; + } + if(automaton.getFinalStates().find(*iterState) != automaton.getFinalStates().end()) { + out << "<"; + } + label::LabelToStringComposer composer; + out << composer.compose(iterState->getName()); + + composeTransitionsFromState(out, automaton, *iterState); + + out << std::endl; + } + + return out.str(); +} + +std::string FiniteAutomatonToStringComposer::compose(const Automaton& automaton) const { + std::stringstream out; + automaton.getAutomaton().Accept((void*) &out, *this); + return out.str(); +} + +void FiniteAutomatonToStringComposer::Visit(void* data, const Automaton& automaton) const { + *((std::stringstream*) data) << this->compose(automaton); +} + +void FiniteAutomatonToStringComposer::Visit(void*, const UnknownAutomaton&) const { + throw alib::AlibException(); +} + +void FiniteAutomatonToStringComposer::Visit(void* data, const EpsilonNFA& automaton) const { + *((std::stringstream*) data) << this->compose(automaton); +} + +void FiniteAutomatonToStringComposer::Visit(void* data, const NFA& automaton) const { + *((std::stringstream*) data) << this->compose(automaton); +} + +void FiniteAutomatonToStringComposer::Visit(void* data, const DFA& automaton) const { + *((std::stringstream*) data) << this->compose(automaton); +} + +void FiniteAutomatonToStringComposer::Visit(void*, const ExtendedNFA&) const { + throw alib::AlibException(); +} + +void FiniteAutomatonToStringComposer::Visit(void*, const CompactNFA&) const { + throw alib::AlibException(); +} + +void FiniteAutomatonToStringComposer::Visit(void*, const PDA&) const { + throw alib::AlibException(); +} + +void FiniteAutomatonToStringComposer::Visit(void*, const OneTapeDTM&) const { + throw alib::AlibException(); +} + +} /* namespace automaton */ diff --git a/alib2/src/automaton/FSM/FiniteAutomatonToStringComposer.h b/alib2/src/automaton/FSM/FiniteAutomatonToStringComposer.h new file mode 100644 index 0000000000..aa5ef2872b --- /dev/null +++ b/alib2/src/automaton/FSM/FiniteAutomatonToStringComposer.h @@ -0,0 +1,42 @@ +#ifndef AUTOMATON_PRINTER_H_ +#define AUTOMATON_PRINTER_H_ + +#include <sstream> +#include "../Automaton.h" +#include "DFA.h" +#include "NFA.h" +#include "EpsilonNFA.h" + +namespace automaton { + +class FiniteAutomatonToStringComposer : public AutomatonBase::const_visitor_type { + void Visit(void*, const Automaton& automaton) const; + void Visit(void*, const UnknownAutomaton& automaton) const; + void Visit(void*, const EpsilonNFA& automaton) const; + void Visit(void*, const NFA& automaton) const; + void Visit(void*, const DFA& automaton) const; + void Visit(void*, const ExtendedNFA& automaton) const; + void Visit(void*, const CompactNFA& automaton) const; + void Visit(void*, const PDA& automaton) const; + void Visit(void*, const OneTapeDTM& automaton) const; + + void composeTransitionsFromState(std::stringstream& out, const EpsilonNFA& automaton, const State& from) const; + +public: + /** + * Prints XML representation of UnknownAutomaton to the output stream. + * @param automaton automaton to print + * @return list of xml tokens representing the automaton + */ + std::string compose(const AutomatonBase& automaton) const; + + std::string compose(const Automaton& automaton) const; + + std::string compose(const DFA& automaton) const; + std::string compose(const NFA& automaton) const; + std::string compose(const EpsilonNFA& automaton) const; +}; + +} /* namespace automaton */ + +#endif /* AUTOMATON_PRINTER_H_ */ diff --git a/alib2/src/label/LabelFromStringParser.h b/alib2/src/label/LabelFromStringParser.h index 4cb0787acc..8ba1cf79c1 100644 --- a/alib2/src/label/LabelFromStringParser.h +++ b/alib2/src/label/LabelFromStringParser.h @@ -33,6 +33,12 @@ class StringFromStringParser; } /* namespace string */ +namespace automaton { + +class FiniteAutomatonFromStringParser; + +} /* namespace automaton */ + namespace label { class LabelFromStringParser { @@ -48,6 +54,7 @@ public: friend class alphabet::SymbolFromStringParser; friend class regexp::RegExpFromStringParser; friend class string::StringFromStringParser; + friend class automaton::FiniteAutomatonFromStringParser; }; } /* namespace label */ diff --git a/alib2/test-src/automaton/AutomatonTest.cpp b/alib2/test-src/automaton/AutomatonTest.cpp index 301afd6563..11c938d218 100644 --- a/alib2/test-src/automaton/AutomatonTest.cpp +++ b/alib2/test-src/automaton/AutomatonTest.cpp @@ -17,6 +17,9 @@ #include "label/Label.h" #include "alphabet/LabeledSymbol.h" +#include "automaton/FSM/FiniteAutomatonFromStringParser.h" +#include "automaton/FSM/FiniteAutomatonToStringComposer.h" + #define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y)) CPPUNIT_TEST_SUITE_REGISTRATION( AutomatonTest ); @@ -85,3 +88,27 @@ void AutomatonTest::testDFAParser() { } } +void AutomatonTest::FSMStringParserTest() { + std::string input = "ENFA a b c d #E\n" + ">0 3|4 5 1|3|4 - 2\n" + "1 2 - - - -\n" + "2 3 - - - -\n" + "3 - - 4 - -\n" + "4 - 5 - - 5\n" + "<5 - - - - 3\n"; + std::stringstream inputs(input); + + automaton::FiniteAutomatonFromStringParser parser(inputs); + automaton::Automaton automaton = parser.parseValue(); + + automaton::FiniteAutomatonToStringComposer composer; + std::string output = composer.compose(automaton); + std::stringstream outputs(output); + + CPPUNIT_ASSERT( input == output ); + + automaton::FiniteAutomatonFromStringParser parser2(outputs); + automaton::Automaton automaton2 = parser2.parseValue(); + + CPPUNIT_ASSERT( automaton == automaton2 ); +} diff --git a/alib2/test-src/automaton/AutomatonTest.h b/alib2/test-src/automaton/AutomatonTest.h index 261c2901bb..3984de6d8c 100644 --- a/alib2/test-src/automaton/AutomatonTest.h +++ b/alib2/test-src/automaton/AutomatonTest.h @@ -8,6 +8,7 @@ class AutomatonTest : public CppUnit::TestFixture CPPUNIT_TEST_SUITE( AutomatonTest ); CPPUNIT_TEST( testXMLParser ); CPPUNIT_TEST( testDFAParser ); + CPPUNIT_TEST( FSMStringParserTest ); CPPUNIT_TEST_SUITE_END(); public: @@ -16,6 +17,7 @@ public: void testXMLParser(); void testDFAParser(); + void FSMStringParserTest(); }; #endif // AUTOMATON_TEST_H_ -- GitLab