/*
 * ToAutomatonThompson.h
 *
 *  Created on: 11. 1. 2014
 *	  Author: Tomas Pecka
 */

#ifndef TO_AUTOMATON_THOMPSON_H_
#define TO_AUTOMATON_THOMPSON_H_

#include <regexp/formal/FormalRegExp.h>
#include <regexp/formal/FormalRegExpElement.h>
#include <regexp/unbounded/UnboundedRegExp.h>
#include <regexp/unbounded/UnboundedRegExpElement.h>
#include <automaton/FSM/EpsilonNFA.h>

namespace regexp {

namespace convert {

/**
 * Converts regular expression to finite automaton using Thompson's Construction Algorithm (TCA).
 * Sources:
 *  Hopcroft, section 3.2.3
 *  http://www.eecis.udel.edu/~cavazos/cisc672/lectures/Lecture-04.pdf
 *  http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.21.7450&rep=rep1&type=ps
 *  Melichar 2.112
 */
class ToAutomatonThompson {
public:
	/**
	 * Implements conversion of regular expressions to finite automata usign Thompson's method of incremental construction.
	 *
	 * \tparam SymbolType the type of symbols in the regular expression
	 *
	 * \param regexp the regexp to convert
	 *
	 * \return finite automaton accepting the language described by the original regular expression
	 */
	static automaton::EpsilonNFA < > convert(const regexp::FormalRegExp < > & regexp);

	/**
	 * \overload
	 */
	static automaton::EpsilonNFA < > convert(const regexp::UnboundedRegExp < > & regexp);

	class Unbounded {
	public:
		static void visit(const regexp::UnboundedRegExpAlternation < DefaultSymbolType > & alternation, automaton::EpsilonNFA < > & automaton , int & nextState, const DefaultStateType * & headArg, const DefaultStateType * & tailArg);
		static void visit(const regexp::UnboundedRegExpConcatenation < DefaultSymbolType > & concatenation, automaton::EpsilonNFA < > & automaton , int & nextState, const DefaultStateType * & headArg, const DefaultStateType * & tailArg);
		static void visit(const regexp::UnboundedRegExpIteration < DefaultSymbolType > & iteration, automaton::EpsilonNFA < > & automaton , int & nextState, const DefaultStateType * & headArg, const DefaultStateType * & tailArg);
		static void visit(const regexp::UnboundedRegExpSymbol < DefaultSymbolType > & symbol, automaton::EpsilonNFA < > & automaton , int & nextState, const DefaultStateType * & headArg, const DefaultStateType * & tailArg);
		static void visit(const regexp::UnboundedRegExpEpsilon < DefaultSymbolType > & epsilon, automaton::EpsilonNFA < > & automaton , int & nextState, const DefaultStateType * & headArg, const DefaultStateType * & tailArg);
		static void visit(const regexp::UnboundedRegExpEmpty < DefaultSymbolType > & empty, automaton::EpsilonNFA < > & automaton , int & nextState, const DefaultStateType * & headArg, const DefaultStateType * & tailArg);
	};

	class Formal {
	public:
		static void visit(const regexp::FormalRegExpAlternation < DefaultSymbolType > & alternation, automaton::EpsilonNFA < > & automaton , int & nextState, const DefaultStateType * & headArg, const DefaultStateType * & tailArg);
		static void visit(const regexp::FormalRegExpConcatenation < DefaultSymbolType > & concatenation, automaton::EpsilonNFA < > & automaton , int & nextState, const DefaultStateType * & headArg, const DefaultStateType * & tailArg);
		static void visit(const regexp::FormalRegExpIteration < DefaultSymbolType > & iteration, automaton::EpsilonNFA < > & automaton , int & nextState, const DefaultStateType * & headArg, const DefaultStateType * & tailArg);
		static void visit(const regexp::FormalRegExpSymbol < DefaultSymbolType > & symbol, automaton::EpsilonNFA < > & automaton , int & nextState, const DefaultStateType * & headArg, const DefaultStateType * & tailArg);
		static void visit(const regexp::FormalRegExpEpsilon < DefaultSymbolType > & epsilon, automaton::EpsilonNFA < > & automaton , int & nextState, const DefaultStateType * & headArg, const DefaultStateType * & tailArg);
		static void visit(const regexp::FormalRegExpEmpty < DefaultSymbolType > & empty, automaton::EpsilonNFA < > & automaton , int & nextState, const DefaultStateType * & headArg, const DefaultStateType * & tailArg);
	};

};

} /* namespace convert */

} /* namespace regexp */

#endif /* TO_AUTOMATON_THOMPSON_H_ */
