From 45297d73da7ae0cd77b76f5806a8f6675767952d Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Wed, 14 May 2014 10:05:46 +0200
Subject: [PATCH] allow epsilon as input or output in unknown trans

---
 .../src/automaton/AutomatonFromXMLParser.cpp  | 51 +++++++++++++------
 alib2/src/automaton/AutomatonFromXMLParser.h  |  5 +-
 .../src/automaton/AutomatonToXMLComposer.cpp  | 15 +++++-
 alib2/src/automaton/AutomatonToXMLComposer.h  |  1 +
 alib2/src/automaton/UnknownTransition.cpp     | 31 ++++++-----
 alib2/src/automaton/UnknownTransition.h       | 16 +++---
 alib2/src/std/variant.hpp                     | 34 +++++++++++++
 alib2/src/string/Epsilon.cpp                  |  5 ++
 alib2/src/string/Epsilon.h                    |  2 +
 9 files changed, 120 insertions(+), 40 deletions(-)

diff --git a/alib2/src/automaton/AutomatonFromXMLParser.cpp b/alib2/src/automaton/AutomatonFromXMLParser.cpp
index 1909162229..e5bbbf96f3 100644
--- a/alib2/src/automaton/AutomatonFromXMLParser.cpp
+++ b/alib2/src/automaton/AutomatonFromXMLParser.cpp
@@ -57,7 +57,7 @@ void AutomatonFromXMLParser::parseStates(std::list<sax::Token> &input, UnknownAu
 void AutomatonFromXMLParser::parseInputAlphabet(std::list<sax::Token> &input, UnknownAutomaton& automaton) {
 	popToken(input, sax::Token::START_ELEMENT, "inputAlphabet");
 	while (isToken(input, sax::Token::START_ELEMENT, "symbol")) {
-		automaton.addInputSymbol(parseSymbol(input, "symbol"));
+		automaton.addInputSymbol(parseSymbol(input));
 	}
 	popToken(input, sax::Token::END_ELEMENT, "inputAlphabet");
 }
@@ -81,7 +81,7 @@ void AutomatonFromXMLParser::parseFinalStates(std::list<sax::Token> &input, Unkn
 void AutomatonFromXMLParser::parseStackAlphabet(std::list<sax::Token> &input, UnknownAutomaton& automaton) {
 	popToken(input, sax::Token::START_ELEMENT, "stackAlphabet");
 	while (isToken(input, sax::Token::START_ELEMENT, "symbol")) {
-		automaton.addStackSymbol(parseSymbol(input, "symbol"));
+		automaton.addStackSymbol(parseSymbol(input));
 	}
 	popToken(input, sax::Token::END_ELEMENT, "stackAlphabet");
 }
@@ -89,7 +89,7 @@ void AutomatonFromXMLParser::parseStackAlphabet(std::list<sax::Token> &input, Un
 void AutomatonFromXMLParser::parseStartSymbols(std::list<sax::Token> &input, UnknownAutomaton& automaton) {
 	popToken(input, sax::Token::START_ELEMENT, "startSymbols");
 	while (isToken(input, sax::Token::START_ELEMENT, "symbol")) {
-		automaton.addInitialSymbol(parseSymbol(input, "symbol"));
+		automaton.addInitialSymbol(parseSymbol(input));
 	}
 	popToken(input, sax::Token::END_ELEMENT, "startSymbols");
 }
@@ -97,14 +97,14 @@ void AutomatonFromXMLParser::parseStartSymbols(std::list<sax::Token> &input, Unk
 void AutomatonFromXMLParser::parseTapeAlphabet(std::list<sax::Token>& input, UnknownAutomaton& automaton) {
 	popToken(input, sax::Token::START_ELEMENT, "tapeAlphabet");
 	while (isToken(input, sax::Token::START_ELEMENT, "symbol")) {
-		automaton.addTapeSymbol(parseSymbol(input, "symbol"));
+		automaton.addTapeSymbol(parseSymbol(input));
 	}
 	popToken(input, sax::Token::END_ELEMENT, "tapeAlphabet");
 }
 
 void AutomatonFromXMLParser::parseBlankSymbol(std::list<sax::Token>& input, UnknownAutomaton& automaton) {
 	popToken(input, sax::Token::START_ELEMENT, "blankSymbol");
-	automaton.setBlankSymbol(parseSymbol(input, "symbol"));
+	automaton.setBlankSymbol(parseSymbol(input));
 	popToken(input, sax::Token::END_ELEMENT, "blankSymbol");
 }
 
@@ -119,7 +119,7 @@ void AutomatonFromXMLParser::parseTransitions(std::list<sax::Token> &input, Unkn
 void AutomatonFromXMLParser::parsePop(std::list<sax::Token>& input, UnknownTransition& transition) {
 	popToken(input, sax::Token::START_ELEMENT, "pop");
 	while (isToken(input, sax::Token::START_ELEMENT, "symbol")) {
-		transition.addPop(parseSymbol(input, "symbol"));
+		transition.addPop(parseSymbol(input));
 	}
 	popToken(input, sax::Token::END_ELEMENT, "pop");
 }
@@ -127,7 +127,7 @@ void AutomatonFromXMLParser::parsePop(std::list<sax::Token>& input, UnknownTrans
 void AutomatonFromXMLParser::parsePush(std::list<sax::Token>& input, UnknownTransition& transition) {
 	popToken(input, sax::Token::START_ELEMENT, "push");
 	while (isToken(input, sax::Token::START_ELEMENT, "symbol")) {
-		transition.addPush(parseSymbol(input, "symbol"));
+		transition.addPush(parseSymbol(input));
 	}
 	popToken(input, sax::Token::END_ELEMENT, "push");
 }
@@ -140,23 +140,42 @@ State AutomatonFromXMLParser::parseState(std::list<sax::Token> &input, std::stri
 	return state;
 }
 
-alphabet::Symbol AutomatonFromXMLParser::parseSymbol(std::list<sax::Token>& input, std::string tagName) {
-	popToken(input, sax::Token::START_ELEMENT, tagName);
-
+alphabet::Symbol AutomatonFromXMLParser::parseSymbol(std::list<sax::Token>& input) {
 	alphabet::Symbol result("");
-	if (isTokenType(input, sax::Token::CHARACTER)) {
+	if (isToken(input, sax::Token::START_ELEMENT, "symbol")) {
+		popToken(input, sax::Token::START_ELEMENT, "symbol");
 		result = alphabet::Symbol(popTokenData(input, sax::Token::CHARACTER));
+		popToken(input, sax::Token::END_ELEMENT, "symbol");
+	} else if (isToken(input, sax::Token::START_ELEMENT, "blank")) {
+		result = alphabet::Blank();
+		input.pop_front();
+		popToken(input, sax::Token::END_ELEMENT,"blank");
+	} else {
+		throw sax::ParserException(sax::Token("", sax::Token::CHARACTER), input.front());
+	}
+	return result;
+}
+
+std::variant<string::Epsilon, alphabet::Symbol> AutomatonFromXMLParser::parseInput(std::list<sax::Token>& input, std::string tagName) {
+	popToken(input, sax::Token::START_ELEMENT, tagName);
+
+	std::variant<string::Epsilon, alphabet::Symbol> result;
+	if (isToken(input, sax::Token::START_ELEMENT, "symbol")) {
+		popToken(input, sax::Token::START_ELEMENT, "symbol");
+		result.set<alphabet::Symbol>(alphabet::Symbol(popTokenData(input, sax::Token::CHARACTER)));
+		popToken(input, sax::Token::END_ELEMENT, "symbol");
 	} else if(isToken(input, sax::Token::START_ELEMENT, "epsilon")) {
-		result = alphabet::Symbol(""); //TODO predelat na opravdovy epsilon
+		result.set<string::Epsilon>(string::Epsilon());
 		input.pop_front();
-		popToken(input, sax::Token::END_ELEMENT,"epsilon");
+		popToken(input, sax::Token::END_ELEMENT, "epsilon");
 	} else if (isToken(input, sax::Token::START_ELEMENT, "blank")) {
-		result = alphabet::Blank();
+		result.set<alphabet::Symbol>(alphabet::Blank());
 		input.pop_front();
 		popToken(input, sax::Token::END_ELEMENT,"blank");
 	} else {
 		throw sax::ParserException(sax::Token("", sax::Token::CHARACTER), input.front());
 	}
+	
 	popToken(input, sax::Token::END_ELEMENT, tagName);
 	return result;
 }
@@ -190,7 +209,7 @@ UnknownTransition AutomatonFromXMLParser::parseTransition(std::list<sax::Token>&
 		if (isToken(input, sax::Token::START_ELEMENT, "from")) {
 			transition.setFrom(parseState(input, "from"));
 		} else if (isToken(input, sax::Token::START_ELEMENT, "input")) {
-			transition.setInput(parseSymbol(input, "input"));
+			transition.setInput(parseInput(input, "input"));
 		} else if (isToken(input, sax::Token::START_ELEMENT, "to")) {
 			transition.setTo(parseState(input, "to"));
 		} else if (isToken(input, sax::Token::START_ELEMENT, "pop")) {
@@ -198,7 +217,7 @@ UnknownTransition AutomatonFromXMLParser::parseTransition(std::list<sax::Token>&
 		} else if (isToken(input, sax::Token::START_ELEMENT, "push")) {
 			parsePush(input, transition);
 		} else if (isToken(input, sax::Token::START_ELEMENT, "output")) {
-			transition.setOutput(parseSymbol(input, "output"));
+			transition.setOutput(parseInput(input, "output"));
 		} else if (isToken(input, sax::Token::START_ELEMENT, "shift")) {
 			transition.setShift(parseShift(input));
 		} else {
diff --git a/alib2/src/automaton/AutomatonFromXMLParser.h b/alib2/src/automaton/AutomatonFromXMLParser.h
index 3072505554..4196cdcfeb 100644
--- a/alib2/src/automaton/AutomatonFromXMLParser.h
+++ b/alib2/src/automaton/AutomatonFromXMLParser.h
@@ -13,7 +13,9 @@
 
 #include <list>
 #include <set>
+#include "../std/variant.hpp"
 #include "../sax/Token.h"
+#include "../string/Epsilon.h"
 
 namespace automaton {
 
@@ -37,7 +39,8 @@ protected:
 
 	UnknownTransition parseTransition(std::list<sax::Token>& input);
 	State parseState(std::list<sax::Token> &input, std::string tagName);
-	alphabet::Symbol parseSymbol(std::list<sax::Token> &input, std::string tagName);
+	std::variant<string::Epsilon, alphabet::Symbol> parseInput(std::list<sax::Token> &input, std::string tagName);
+	alphabet::Symbol parseSymbol(std::list<sax::Token> &input);
 	Shift parseShift(std::list<sax::Token> &input);
 
 public:
diff --git a/alib2/src/automaton/AutomatonToXMLComposer.cpp b/alib2/src/automaton/AutomatonToXMLComposer.cpp
index 32ded991df..8e05cfa173 100644
--- a/alib2/src/automaton/AutomatonToXMLComposer.cpp
+++ b/alib2/src/automaton/AutomatonToXMLComposer.cpp
@@ -43,7 +43,7 @@ void AutomatonToXMLComposer::printUnknownTransitions(std::list<sax::Token>& out,
 		}
 
 		if(transition.hasInput()) {
-			printSymbol(out, transition.getInput(), "input");
+			printInput(out, transition.getInput(), "input");
 		}
 		
 		if(transition.hasTo()) {
@@ -58,7 +58,7 @@ void AutomatonToXMLComposer::printUnknownTransitions(std::list<sax::Token>& out,
 		}
 
 		if (transition.hasOutput()) {
-			printSymbol(out, transition.getOutput(), "output");
+			printInput(out, transition.getOutput(), "output");
 		}
 
 		if (transition.getShift() != Shift::NOT_SET) {
@@ -77,6 +77,17 @@ void AutomatonToXMLComposer::printState(std::list<sax::Token>& out, const State&
 	out.push_back(sax::Token(tagName, sax::Token::END_ELEMENT));
 }
 
+void AutomatonToXMLComposer::printInput(std::list<sax::Token>& out, const std::variant<string::Epsilon, alphabet::Symbol>& symbol, std::string tagName) {
+	out.push_back(sax::Token(tagName, sax::Token::START_ELEMENT));
+	if(symbol.is<string::Epsilon>()) {
+		out.push_back(sax::Token("epsilon", sax::Token::START_ELEMENT));
+		out.push_back(sax::Token("epsilon", sax::Token::END_ELEMENT));
+	} else {
+		out.push_back(sax::Token(symbol.get<alphabet::Symbol>().getSymbol(), sax::Token::CHARACTER));
+	}
+	out.push_back(sax::Token(tagName, sax::Token::END_ELEMENT));
+}
+
 void AutomatonToXMLComposer::printSymbol(std::list<sax::Token>& out, const alphabet::Symbol& symbol, std::string tagName) {
 	out.push_back(sax::Token(tagName, sax::Token::START_ELEMENT));
 	out.push_back(sax::Token(symbol.getSymbol(), sax::Token::CHARACTER));
diff --git a/alib2/src/automaton/AutomatonToXMLComposer.h b/alib2/src/automaton/AutomatonToXMLComposer.h
index 6403c4bd00..7bda0daf6d 100644
--- a/alib2/src/automaton/AutomatonToXMLComposer.h
+++ b/alib2/src/automaton/AutomatonToXMLComposer.h
@@ -27,6 +27,7 @@ protected:
 
 	static void printState(std::list<sax::Token>&, const State& state, std::string tagName);
 	static void printSymbol(std::list<sax::Token>&, const alphabet::Symbol& symbol, std::string tagName);
+	static void printInput(std::list<sax::Token>&, const std::variant<string::Epsilon, alphabet::Symbol>&, std::string);
 	static void printShift(std::list<sax::Token>&, const Shift& shift, std::string tagName);
 
 public:
diff --git a/alib2/src/automaton/UnknownTransition.cpp b/alib2/src/automaton/UnknownTransition.cpp
index 9b3f63d2fb..89e9f0ecce 100644
--- a/alib2/src/automaton/UnknownTransition.cpp
+++ b/alib2/src/automaton/UnknownTransition.cpp
@@ -14,8 +14,8 @@ UnknownTransition::UnknownTransition() : from(NULL), to(NULL), input(NULL), outp
 
 }
 
-UnknownTransition::UnknownTransition(const State& from, const State& to, const std::vector<alphabet::Symbol>& pop, const std::vector<alphabet::Symbol>& push, const alphabet::Symbol& input, const alphabet::Symbol& output, Shift shift) :
-		from(new State(from)), to(new State(to)), pop(pop), push(push), input(new alphabet::Symbol(input)), output(new alphabet::Symbol(output)), shift(shift) {
+UnknownTransition::UnknownTransition(const State& from, const State& to, const std::vector<alphabet::Symbol>& pop, const std::vector<alphabet::Symbol>& push, const std::variant<string::Epsilon, alphabet::Symbol>& input, const std::variant<string::Epsilon, alphabet::Symbol>& output, Shift shift) :
+		from(new State(from)), to(new State(to)), pop(pop), push(push), input(new std::variant<string::Epsilon, alphabet::Symbol>(input)), output(new std::variant<string::Epsilon, alphabet::Symbol>(output)), shift(shift) {
 
 }
 
@@ -83,9 +83,9 @@ void UnknownTransition::addPush(const alphabet::Symbol& symbol) {
 	push.push_back(symbol);
 }
 
-void UnknownTransition::setOutput(const alphabet::Symbol& symbol) {
+void UnknownTransition::setOutput(const std::variant<string::Epsilon, alphabet::Symbol>& symbol) {
 	delete output;
-	output = new alphabet::Symbol(symbol);
+	output = new std::variant<string::Epsilon, alphabet::Symbol>(symbol);
 }
 
 bool UnknownTransition::hasOutput() const {
@@ -97,13 +97,13 @@ void UnknownTransition::clearOutput() {
 	output = NULL;
 }
 
-const alphabet::Symbol& UnknownTransition::getOutput() const {
+const std::variant<string::Epsilon, alphabet::Symbol>& UnknownTransition::getOutput() const {
 	return *output;
 }
 
-void UnknownTransition::setInput(const alphabet::Symbol& symbol) {
+void UnknownTransition::setInput(const std::variant<string::Epsilon, alphabet::Symbol>& symbol) {
 	delete input;
-	input = new alphabet::Symbol(symbol);
+	input = new std::variant<string::Epsilon, alphabet::Symbol>(symbol);
 }
 
 bool UnknownTransition::hasInput() const {
@@ -115,7 +115,7 @@ void UnknownTransition::clearInput() {
 	input = NULL;
 }
 
-const alphabet::Symbol& UnknownTransition::getInput() const {
+const std::variant<string::Epsilon, alphabet::Symbol>& UnknownTransition::getInput() const {
 	return *input;
 }
 
@@ -168,12 +168,15 @@ bool UnknownTransition::operator !=(const UnknownTransition& other) const {
 }
 
 std::ostream& operator<<(std::ostream& out, const UnknownTransition& transition) {
-	out << "(UnknownTransition"
-		<< " from = " << ((transition.from == NULL) ? (std::string) "NULL" : *transition.from)
-		<< " input = " << ((transition.input == NULL) ? (std::string) "NULL" : *transition.input)
-		<< " to = " << ((transition.to == NULL) ? (std::string) "NULL" : *transition.to)
-		<< " output = " << ((transition.output == NULL) ? (std::string) "NULL" : *transition.output)
-		<< " pop = " << transition.pop
+	out << "(UnknownTransition" << " from = ";
+	if(transition.from == NULL) out << "NULL"; else out << *transition.from;
+	out << " input = ";
+	if(transition.input == NULL) out << "NULL"; else out << *transition.input;
+	out << " to = ";
+	if(transition.to == NULL) out << "NULL"; else out << *transition.to;
+	out << " output = ";
+	if(transition.output == NULL) out << "NULL"; else out << *transition.output;
+	out << " pop = " << transition.pop
 		<< " push = " << transition.push
 		<< " shift = " << SHIFT_NAMES[transition.shift]
 		<< ")";
diff --git a/alib2/src/automaton/UnknownTransition.h b/alib2/src/automaton/UnknownTransition.h
index f04b34d269..96822cb57c 100644
--- a/alib2/src/automaton/UnknownTransition.h
+++ b/alib2/src/automaton/UnknownTransition.h
@@ -13,6 +13,8 @@
 #include "State.h"
 #include "../alphabet/Symbol.h"
 #include "Shift.h"
+#include "../std/variant.hpp"
+#include "../string/Epsilon.h"
 
 namespace automaton {
 
@@ -27,15 +29,15 @@ protected:
 	std::vector<alphabet::Symbol> pop;
 	std::vector<alphabet::Symbol> push;
 
-	alphabet::Symbol* input;
-	alphabet::Symbol* output;
+	std::variant<string::Epsilon, alphabet::Symbol>* input;
+	std::variant<string::Epsilon, alphabet::Symbol>* output;
 
 	Shift shift;
 
 public:
 	UnknownTransition();
 	
-	UnknownTransition(const State& from, const State& to, const std::vector<alphabet::Symbol>& pop, const std::vector<alphabet::Symbol>& push, const alphabet::Symbol& input, const alphabet::Symbol& output, Shift shift);
+	UnknownTransition(const State& from, const State& to, const std::vector<alphabet::Symbol>& pop, const std::vector<alphabet::Symbol>& push, const std::variant<string::Epsilon, alphabet::Symbol>& input, const std::variant<string::Epsilon, alphabet::Symbol>& output, Shift shift);
 	~UnknownTransition();
 
 	/**
@@ -113,13 +115,13 @@ public:
 	/**
 	 * @return the output symbol of the transition
 	 */
-	const alphabet::Symbol& getInput() const;
+	const std::variant<string::Epsilon, alphabet::Symbol>& getInput() const;
 
 	/**
 	 * Sets the output Symbol of the transition.
 	 * @param symbol Symbol to set
 	 */
-	void setInput(const alphabet::Symbol& symbol);
+	void setInput(const std::variant<string::Epsilon, alphabet::Symbol>& symbol);
 
 	/**
 	 * @return true if the input symbol is set
@@ -134,13 +136,13 @@ public:
 	/**
 	 * @return the output symbol of the transition
 	 */
-	const alphabet::Symbol& getOutput() const;
+	const std::variant<string::Epsilon, alphabet::Symbol>& getOutput() const;
 
 	/**
 	 * Sets the output Symbol of the transition.
 	 * @param symbol Symbol to set
 	 */
-	void setOutput(const alphabet::Symbol& symbol);
+	void setOutput(const std::variant<string::Epsilon, alphabet::Symbol>& symbol);
 
 	/**
 	 * @return true if the output symbol is set
diff --git a/alib2/src/std/variant.hpp b/alib2/src/std/variant.hpp
index 396e628e6f..784db111c4 100644
--- a/alib2/src/std/variant.hpp
+++ b/alib2/src/std/variant.hpp
@@ -70,6 +70,14 @@ struct variant_helper<F, Ts...> {
 			return variant_helper<Ts...>::compareEq(this_t, this_v, other_t, other_v);
 	}
 
+	inline static void print(ostream& out, const size_t id, const void* data) {
+		if (id == typeid(F).hash_code())
+			out << *reinterpret_cast<const F*>(data);
+		else
+			variant_helper<Ts...>::print(out, id, data);
+	}
+
+
 	inline static bool compareLess(size_t this_t, const void * this_v, size_t other_t, const void * other_v)
 	{
 		if (this_t == typeid(F).hash_code() && other_t != typeid(F).hash_code()) return true;
@@ -88,6 +96,7 @@ inline static void destroy(size_t id, void * data) { }
 inline static bool move(size_t old_t, void * old_v, void * new_v) { return false; }
 inline static void copy(size_t old_t, const void * old_v, void * new_v) { }
 inline static bool compareEq(size_t this_t, const void * this_v, size_t other_t, const void * other_v) { return true; }
+inline static void print(ostream& out, const size_t id, const void* data) {}
 inline static bool compareLess(size_t this_t, const void * this_v, size_t other_t, const void * other_v) { return false; }
 };
 
@@ -137,11 +146,31 @@ public:
 		return helper_t::compareEq(type_id, &data, other.type_id, &other.data);
 	}
 
+	bool operator!= (const variant<F, Ts...>& other) const
+	{
+		return !(*this == other);
+	}
+
 	bool operator< (const variant<F, Ts...>& other) const
 	{
 		return helper_t::compareLess(type_id, &data, other.type_id, &other.data);
 	}
 
+	bool operator> (const variant<F, Ts...>& other) const
+	{
+		return other < *this;
+	}
+
+	bool operator<= (const variant<F, Ts...>& other) const
+	{
+		return !(*this > other);
+	}
+
+	bool operator>= (const variant<F, Ts...>& other) const
+	{
+		return !(*this < other);
+	}
+
 	template<typename T>
 	bool is() const {
 		return (type_id == typeid(T).hash_code());
@@ -192,6 +221,11 @@ public:
 	~variant() {
 		helper_t::destroy(type_id, &data);
 	}
+
+	friend std::ostream& operator <<(std::ostream& out, const variant<F, Ts...>& obj) {
+		helper_t::print(out, obj.type_id, &obj.data);
+		return out;
+	}
 };
 
 } /* namespace std */
diff --git a/alib2/src/string/Epsilon.cpp b/alib2/src/string/Epsilon.cpp
index d758e43730..77a92db4af 100644
--- a/alib2/src/string/Epsilon.cpp
+++ b/alib2/src/string/Epsilon.cpp
@@ -25,6 +25,11 @@ bool Epsilon::operator!=(const Epsilon& other) const {
   return false;
 }
 
+std::ostream& operator<<(std::ostream& out, const Epsilon& eps) {
+	out << (const String&) eps;
+	return out;
+}
+
 Epsilon Epsilon::EPSILON = Epsilon();
 
 } /* namespace string */
diff --git a/alib2/src/string/Epsilon.h b/alib2/src/string/Epsilon.h
index 6eb628e13a..18b4e9f796 100644
--- a/alib2/src/string/Epsilon.h
+++ b/alib2/src/string/Epsilon.h
@@ -32,6 +32,8 @@ public:
 	bool operator==(const Epsilon& other) const;
 	
 	bool operator!=(const Epsilon& other) const;
+
+	friend std::ostream& operator<<(std::ostream& out, const Epsilon& eps);
 	
 	static Epsilon EPSILON;
 };
-- 
GitLab