diff --git a/aconversions/src/aconversion/ConversionHandler.cpp b/aconversions/src/aconversion/ConversionHandler.cpp index b986415b818799a41e91479dabe17302be4b6fc4..b18f150a4adaafc5cc2217087d6742cec7a15846 100644 --- a/aconversions/src/aconversion/ConversionHandler.cpp +++ b/aconversions/src/aconversion/ConversionHandler.cpp @@ -171,6 +171,14 @@ void ConversionHandler::convertRegExp( ostream & out ) conv->convert( ).toXML( out ); delete conv; } + else if ( m_algorithm == GLUSHKOV_RRG ) + { + AbstractREtoRRGConverter* conv; + + conv = new GlushkovRRG( regexp ); + conv->convert( ).toXML( out ); + delete conv; + } } } @@ -247,6 +255,7 @@ ConversionHandler::TAlgorithm ConversionHandler::parseAlgorithmFromString( const /* RE to RG */ if( algorithm == "brzozowskirrg") return BRZOZOWSKI_RRG; + if( algorithm == "glushkovrrg") return GLUSHKOV_RRG; /* RG to FA */ if( algorithm == "rg" ) return RG_FA; @@ -262,7 +271,7 @@ ConversionHandler::TAlgorithm ConversionHandler::getDefaultAlgorithm( void ) con if( m_source == FINITE_AUTOMATA && m_target == REGULAR_EXPRESSION ) return STATE_ELIMINATION; if( m_source == FINITE_AUTOMATA && m_target == REGULAR_GRAMMAR ) return FA_RRG; if( m_source == REGULAR_EXPRESSION && m_target == FINITE_AUTOMATA ) return GLUSHKOV; - if( m_source == REGULAR_EXPRESSION && m_target == REGULAR_GRAMMAR ) return BRZOZOWSKI_RRG; + if( m_source == REGULAR_EXPRESSION && m_target == REGULAR_GRAMMAR ) return GLUSHKOV_RRG; if( m_source == REGULAR_GRAMMAR && m_target == FINITE_AUTOMATA ) return RG_FA; if( m_source == REGULAR_GRAMMAR && m_target == REGULAR_EXPRESSION ) return BRZOZOWSKI_ALGEBRAIC; if( m_source == REGULAR_GRAMMAR && m_target == REGULAR_GRAMMAR ) return LRG_RRG; @@ -288,7 +297,7 @@ bool ConversionHandler::checkAlgorithm( void ) const return ( m_target == FINITE_AUTOMATA && ( m_algorithm == BRZOZOWSKI_DERIVATION || m_algorithm == GLUSHKOV || m_algorithm == THOMPSON ) ) || ( m_target == REGULAR_GRAMMAR && - ( m_algorithm == BRZOZOWSKI_RRG) ); + ( m_algorithm == BRZOZOWSKI_RRG || m_algorithm == GLUSHKOV_RRG ) ); /* RG to FA */ /* RG to RE */ diff --git a/aconversions/src/aconversion/ConversionHandler.h b/aconversions/src/aconversion/ConversionHandler.h index a5e27368a7c974519773cc6e02a23fe06e4a1322..28f911930a29df642ce9e36823cdbe89aff6ec5f 100644 --- a/aconversions/src/aconversion/ConversionHandler.h +++ b/aconversions/src/aconversion/ConversionHandler.h @@ -31,6 +31,7 @@ #include "../re2rg/re2rrg/BrzozowskiDerivationRRG.h" #include "../lrg2rrg/LeftToRightRegularGrammar.h" #include "../rrg2lrg/RightToLeftRegularGrammar.h" +#include "../re2rg/re2rrg/GlushkovRRG.h" namespace conversions { @@ -57,6 +58,7 @@ public: /* RE to RG */ BRZOZOWSKI_RRG, + GLUSHKOV_RRG, /* RG to FA */ RG_FA, diff --git a/aconversions/src/include/macros.h b/aconversions/src/include/macros.h index 6af4fc212f7e28f294a4dfcaf99723651ab5b250..735e2299484b0c9ff8d72ec4e4910c95c740d83e 100644 --- a/aconversions/src/include/macros.h +++ b/aconversions/src/include/macros.h @@ -9,7 +9,7 @@ namespace conversions { #define isInSet(x,set) ( (set).find((x)) != (set).end() ) -#define isInList(x,list) ( find((list).begin(), (list).end(), (x)) ) +#define isInList(x,list) ( find((list).begin(), (list).end(), (x)) != (list).end() ) #define isKeyInMap(key,map) ( (map).find((key)) != (map).end() ) } /* namespace conversions */ diff --git a/aconversions/src/re2rg/re2rrg/AbstractREtoRRGConverter.h b/aconversions/src/re2rg/re2rrg/AbstractREtoRRGConverter.h index d31f20ace0ef6e1dca845e263ef93f36f3027886..7e313f513502f32d98056a4306b5eb9ed1ddee83 100644 --- a/aconversions/src/re2rg/re2rrg/AbstractREtoRRGConverter.h +++ b/aconversions/src/re2rg/re2rrg/AbstractREtoRRGConverter.h @@ -11,6 +11,7 @@ #include <regexp/RegExp.h> #include <grammar/Regular/RightRegularGrammar.h> +#include "../../include/macros.h" #include "../AbstractREtoRGConverter.h" namespace conversions diff --git a/aconversions/src/re2rg/re2rrg/GlushkovRRG.cpp b/aconversions/src/re2rg/re2rrg/GlushkovRRG.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0fb53d9938b96d3f23ed1d0aedf8b88ad686ab67 --- /dev/null +++ b/aconversions/src/re2rg/re2rrg/GlushkovRRG.cpp @@ -0,0 +1,148 @@ +/* + * GlushkovRRG.cpp + * + * Created on: 11. 1. 2014 + * Author: tomas + */ + +#include "GlushkovRRG.h" + +using namespace alib; +using namespace alphabet; +using namespace grammar; +using namespace regexp; +using namespace std; + +namespace conversions +{ + +GlushkovRRG::GlushkovRRG( const RegExp & re ) : AbstractREtoRRGConverter( re ) +{ + +} + +GlushkovRRG::~GlushkovRRG( void ) +{ + +} + +RightRegularGrammar GlushkovRRG::convert( void ) +{ + // step 1 + initNumberSymbols( ); + + for( const auto & symbol : RegExpAlphabet::getSymbols( m_re ) ) + m_grammar.addTerminalSymbol( symbol.getSymbol( ) ); + + // steps 2, 3, 4 + constructBeginSymbolSet( ); + constructEndSymbolSet( ); + constructNeighbourSymbolSet( ); + // \e in q0 check is in step 7 + + // step 5 + Symbol S = m_grammar.createUniqueNonTerminalSymbol( "S" ); + m_grammar.setStartSymbol( S ); + + //for( const auto & kv : m_numberedSymbols ) + //m_grammar.createUniqueNonTerminalSymbol( kv.second.m_nonTerminal ); + + // step 6 + for( const auto & ns : m_beginSymbolSet ) + { + list<Symbol> leftSide = { S }; + list<Symbol> rightSide = { ns.m_alphabetSymbol, ns.m_nonTerminal }; + m_grammar.addRule( Rule( leftSide, rightSide ) ); + } + + for( const auto & ns : m_neighbourSymbolSet ) + { + const NumberedSymbol & first = m_numberedSymbols.find( ns.m_first )->second; + const NumberedSymbol & second = m_numberedSymbols.find( ns.m_second )->second; + + list<Symbol> leftSide = { first.m_nonTerminal }; + list<Symbol> rightSide = { second.m_alphabetSymbol, second.m_nonTerminal }; + + m_grammar.addRule( Rule( leftSide, rightSide ) ); + } + + // step 7 + for( const auto & ns : m_endSymbolSet ) + { + /* + * for all rules where ns.m_nonTerminal is on rightSide: + * add Rule: leftSide -> ns.m_alphabetSymbol + * unless it already exists + */ + + for( const auto & rule : m_grammar.getRules( ) ) + { + if( isInList( ns.m_nonTerminal, rule.getRightSide( ) ) ) + { + list<Symbol> leftSide = rule.getLeftSide( ); + list<Symbol> rightSide = { ns.m_alphabetSymbol }; + Rule r( leftSide, rightSide ); + if( ! isInSet( r, m_grammar.getRules( ) ) ) + m_grammar.addRule( r ); + } + } + } + + if( m_re.containsEmptyString( ) ) + { + list<Symbol> leftSide = { S }; + list<Symbol> rightSide = { }; + m_grammar.addRule( Rule( leftSide, rightSide ) ); + } + + return m_grammar; +} + +void GlushkovRRG::initNumberSymbols( void ) +{ + int id = 1; + + for( const auto & symb : RegExpAlphabet::getSymbolsListInOrder( m_re ) ) + m_numberedSymbols.insert( pair<const RegExpSymbol*, NumberedSymbol>( symb, NumberedSymbol( symb, m_grammar, id ++ ) ) ); +} + +// ---------------------------------------------------------------------------- + +void GlushkovRRG::constructBeginSymbolSet( void ) +{ + for( const auto & s : GlushkovTraversal::getLeftmostSymbolsInTree( m_re ) ) + m_beginSymbolSet.insert( m_numberedSymbols.find( s )->second ); +} + +void GlushkovRRG::constructEndSymbolSet( void ) +{ + for( const auto & s : GlushkovTraversal::getRightmostSymbolsInTree( m_re ) ) + m_endSymbolSet.insert( m_numberedSymbols.find( s )->second ); +} + +void GlushkovRRG::constructNeighbourSymbolSet( void ) +{ + for( const auto & n : GlushkovTraversal::getNeighbours( m_re ) ) + m_neighbourSymbolSet.insert( n ); +} + +// ---------------------------------------------------------------------------- + +bool GlushkovRRG::NumberedSymbol::operator<( const NumberedSymbol & x ) const +{ + return m_i < x.m_i; +} + +GlushkovRRG::NumberedSymbol::NumberedSymbol( const RegExpSymbol * symbol, grammar::RightRegularGrammar & g, int i ) : + m_i( i ), + m_alphabetSymbol( symbol->getSymbol( ) ), + m_nonTerminal( g.createUniqueNonTerminalSymbol( "[" + m_alphabetSymbol.getSymbol( ) + "], id " + to_string( m_i ), false ) ) +{ + +} + +// ---------------------------------------------------------------------------- + + + +} /* namespace conversions */ diff --git a/aconversions/src/re2rg/re2rrg/GlushkovRRG.h b/aconversions/src/re2rg/re2rrg/GlushkovRRG.h new file mode 100644 index 0000000000000000000000000000000000000000..82c4ba6ed16fc6c0ac321373592221c9cc9b85c7 --- /dev/null +++ b/aconversions/src/re2rg/re2rrg/GlushkovRRG.h @@ -0,0 +1,55 @@ +/* + * GlushkovRRG.h + * + * Created on: 11. 1. 2014 + * Author: tomas + */ + +#ifndef GLUSHKOVRRG_H_ +#define GLUSHKOVRRG_H_ + +#include <map> + +#include <grammar/Regular/RightRegularGrammar.h> +#include <regexp/RegExp.h> + +#include "../../shared/GlushkovTraversal.h" +#include "AbstractREtoRRGConverter.h" + +#include "RegExpAlphabet.h" + +namespace conversions +{ + +class GlushkovRRG : public AbstractREtoRRGConverter +{ +public: + GlushkovRRG( const regexp::RegExp & re ); + ~GlushkovRRG( void ); + grammar::RightRegularGrammar convert( void ); + +private: + struct NumberedSymbol + { + const int m_i; + const alphabet::Symbol m_alphabetSymbol; + const alphabet::Symbol m_nonTerminal; + + NumberedSymbol( const regexp::RegExpSymbol * symb, grammar::RightRegularGrammar & rrg, int i ); + bool operator<( const NumberedSymbol & x ) const; + }; + + void initNumberSymbols( void ); + void constructBeginSymbolSet( void ); + void constructEndSymbolSet( void ); + void constructNeighbourSymbolSet( void ); + + std::map<const regexp::RegExpElement*, NumberedSymbol> m_numberedSymbols; + std::set<NumberedSymbol> m_beginSymbolSet, m_endSymbolSet; + std::set<GlushkovTraversal::Neighbours> m_neighbourSymbolSet; + +}; + +} /* namespace conversions */ + +#endif /* GLUSHKOVRRG_H_ */ diff --git a/aconversions/src/shared/GlushkovTraversal.cpp b/aconversions/src/shared/GlushkovTraversal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d9971752cada83c5685145485295664aadf4d65d --- /dev/null +++ b/aconversions/src/shared/GlushkovTraversal.cpp @@ -0,0 +1,296 @@ +/* + * GlushkovTraversal.cpp + * + * Created on: 13. 3. 2014 + * Author: tomas + */ + +#include "GlushkovTraversal.h" + +using namespace alib; +using namespace regexp; +using namespace std; + +namespace conversions +{ + +set<const RegExpSymbol*> GlushkovTraversal::getLeftmostSymbolsInTree( const RegExp & re ) +{ + return getLeftmostSymbolsInTree( re.getRegExp( ) ); + +} +set<const RegExpSymbol*> GlushkovTraversal::getRightmostSymbolsInTree( const RegExp & re ) +{ + return getRightmostSymbolsInTree( re.getRegExp( ) ); +} + +set<GlushkovTraversal::Neighbours> GlushkovTraversal::getNeighbours( const RegExp & re ) +{ + return getNeighbours( re.getRegExp( ) ); +} + +// ----------------------------------------------------------------------------- + +GlushkovTraversal::Neighbours::Neighbours( const RegExpSymbol * first, const RegExpSymbol * second ) : + m_first( first ), + m_second( second ) +{ + +} + +bool GlushkovTraversal::Neighbours::operator<( const Neighbours & x ) const +{ + if( m_first != x.m_first ) + return m_first < x.m_first; + else + return m_second < x.m_second; +} + +// ----------------------------------------------------------------------------- + +set<const RegExpSymbol*> GlushkovTraversal::getLeftmostSymbolsInTree( const RegExpElement * node ) +{ + const Alternation* alternation = dynamic_cast<const Alternation*>( node ); + const Concatenation* concatenation = dynamic_cast<const Concatenation*>( node ); + const Iteration* iteration = dynamic_cast<const Iteration*>( node ); + const RegExpSymbol* symbol = dynamic_cast<const RegExpSymbol*>( node ); + const RegExpEmpty* empty = dynamic_cast<const RegExpEmpty*>( node ); + const RegExpEpsilon* eps = dynamic_cast<const RegExpEpsilon*>( node ); + + if( symbol ) + return getLeftmostSymbolsInTree( symbol ); + else if( alternation ) + return getLeftmostSymbolsInTree( alternation ); + else if( concatenation ) + return getLeftmostSymbolsInTree( concatenation ); + else if( iteration ) + return getLeftmostSymbolsInTree( iteration ); + else if( eps ) + return getLeftmostSymbolsInTree( eps ); + else if( empty ) + return getLeftmostSymbolsInTree( empty ); + + throw AlibException( "GlushkovTraversal::getLeftmostSymbolsInTree - invalid RegExpElement node" ); +} + +set<const RegExpSymbol*> GlushkovTraversal::getLeftmostSymbolsInTree( const Alternation * node ) +{ + set<const RegExpSymbol*> ret; + + for( const auto & e : node->getElements( ) ) + { + const set<const RegExpSymbol*> tmp = getLeftmostSymbolsInTree( e ); + ret.insert( tmp.begin( ), tmp.end( ) ); + } + + return ret; +} + +set<const RegExpSymbol*> GlushkovTraversal::getLeftmostSymbolsInTree( const Concatenation * node ) +{ + set<const RegExpSymbol*> ret; + + for( const auto & e : node->getElements( ) ) + { + set<const RegExpSymbol*> tmp = getLeftmostSymbolsInTree( e ); + ret.insert( tmp.begin( ), tmp.end( ) ); + + if( ! e->containsEmptyString( ) ) // If this subtree can be epsilon, then we need to add next subtree also + break; + } + + return ret; +} + +set<const RegExpSymbol*> GlushkovTraversal::getLeftmostSymbolsInTree( const Iteration * node ) +{ + return getLeftmostSymbolsInTree( node->getElement( ) ); +} + +set<const RegExpSymbol*> GlushkovTraversal::getLeftmostSymbolsInTree( const RegExpSymbol * node ) +{ + return set<const RegExpSymbol*> { node }; +} + +set<const RegExpSymbol*> GlushkovTraversal::getLeftmostSymbolsInTree( const RegExpEpsilon * node ) +{ + return set<const RegExpSymbol*>( ); +} + +set<const RegExpSymbol*> GlushkovTraversal::getLeftmostSymbolsInTree( const RegExpEmpty * node ) +{ + return set<const RegExpSymbol*>( ); +} +// ---------------------------------------------------------------------------- + +set<const RegExpSymbol*> GlushkovTraversal::getRightmostSymbolsInTree( const RegExpElement * node ) +{ + const Alternation* alternation = dynamic_cast<const Alternation*>( node ); + const Concatenation* concatenation = dynamic_cast<const Concatenation*>( node ); + const Iteration* iteration = dynamic_cast<const Iteration*>( node ); + const RegExpSymbol* symbol = dynamic_cast<const RegExpSymbol*>( node ); + const RegExpEmpty* empty = dynamic_cast<const RegExpEmpty*>( node ); + const RegExpEpsilon* eps = dynamic_cast<const RegExpEpsilon*>( node ); + + if( symbol ) + return getRightmostSymbolsInTree( symbol ); + else if( alternation ) + return getRightmostSymbolsInTree( alternation ); + else if( concatenation ) + return getRightmostSymbolsInTree( concatenation ); + else if( iteration ) + return getRightmostSymbolsInTree( iteration ); + else if( eps ) + return getRightmostSymbolsInTree( eps ); + else if( empty ) + return getRightmostSymbolsInTree( empty ); + + throw AlibException( "GlushkovTraversal::getRightmostSymbolsInTree - invalid RegExpElement node" ); +} + +set<const RegExpSymbol*> GlushkovTraversal::getRightmostSymbolsInTree( const Alternation * node ) +{ + set<const RegExpSymbol*> ret; + + for( const auto & e : node->getElements( ) ) + { + set<const RegExpSymbol*> tmp = getRightmostSymbolsInTree( e ); + ret.insert( tmp.begin( ), tmp.end( ) ); + } + + return ret; +} + +set<const RegExpSymbol*> GlushkovTraversal::getRightmostSymbolsInTree( const Concatenation * node ) +{ + set<const RegExpSymbol*> ret; + + for( auto it = node->getElements( ).rbegin( ); it != node->getElements( ).rend( ) ; it ++ ) + { + set<const RegExpSymbol*> tmp = getRightmostSymbolsInTree( *it ); + ret.insert( tmp.begin( ), tmp.end( ) ); + + if( ! ( * it )->containsEmptyString( ) ) + break; + } + + return ret; +} + +set<const RegExpSymbol*> GlushkovTraversal::getRightmostSymbolsInTree( const Iteration * node ) +{ + return getRightmostSymbolsInTree( node->getElement( ) ); +} + +set<const RegExpSymbol*> GlushkovTraversal::getRightmostSymbolsInTree( const RegExpSymbol * node ) +{ + return set<const RegExpSymbol*> { node }; +} + +set<const RegExpSymbol*> GlushkovTraversal::getRightmostSymbolsInTree( const RegExpEpsilon * node ) +{ + return set<const RegExpSymbol*>( ); +} + +set<const RegExpSymbol*> GlushkovTraversal::getRightmostSymbolsInTree( const RegExpEmpty * node ) +{ + return set<const RegExpSymbol*>( ); +} + +// ---------------------------------------------------------------------------- + +set<GlushkovTraversal::Neighbours> GlushkovTraversal::getNeighbours( const RegExpElement * node ) +{ + const Alternation* alternation = dynamic_cast<const Alternation*>( node ); + const Concatenation* concatenation = dynamic_cast<const Concatenation*>( node ); + const Iteration* iteration = dynamic_cast<const Iteration*>( node ); + const RegExpSymbol* symbol = dynamic_cast<const RegExpSymbol*>( node ); + const RegExpEmpty* empty = dynamic_cast<const RegExpEmpty*>( node ); + const RegExpEpsilon* eps = dynamic_cast<const RegExpEpsilon*>( node ); + + if( symbol ) + return getNeighbours( symbol ); + else if( alternation ) + return getNeighbours( alternation ); + else if( concatenation ) + return getNeighbours( concatenation ); + else if( iteration ) + return getNeighbours( iteration ); + else if( eps ) + return getNeighbours( eps ); + else if( empty ) + return getNeighbours( empty ); + + throw AlibException( "GlushkovTraversal::getNeighbours - unknown RegExpElement* " ); +} + +set<GlushkovTraversal::Neighbours> GlushkovTraversal::getNeighbours( const Alternation * node ) +{ + set<Neighbours> n; + for( const auto & e : node->getElements( ) ) + { + set<Neighbours> tmp = getNeighbours( e ); + n.insert( tmp.begin( ), tmp.end( ) ); + } + + return n; +} + +set<GlushkovTraversal::Neighbours> GlushkovTraversal::getNeighbours( const Concatenation * node ) +{ + set<Neighbours> n; + for( const auto & e : node->getElements( ) ) + { + set<Neighbours> tmp = getNeighbours( e ); + n.insert( tmp.begin( ), tmp.end( ) ); + } + + for( auto e = node->getElements( ).begin( ); e != node->getElements( ).end( ); e ++ ) + { + auto f = e; + if( f == node->getElements( ).end( ) ) + continue; + + for( f++ ; f != node->getElements( ).end( ); f ++ ) + { + for( const auto & x : getRightmostSymbolsInTree( * e ) ) + for( const auto & y : getLeftmostSymbolsInTree( * f ) ) + n.insert( Neighbours( x, y ) ); + + if( ! ( * f )->containsEmptyString( ) ) + break; + } + } + + return n; +} + +set<GlushkovTraversal::Neighbours> GlushkovTraversal::getNeighbours( const Iteration * node ) +{ + set<Neighbours> n; + set<Neighbours> tmp = getNeighbours( node->getElement( ) ); + n.insert( tmp.begin( ), tmp.end( ) ); + + for( const auto & x : getRightmostSymbolsInTree( node->getElement( ) ) ) + for( const auto & y : getLeftmostSymbolsInTree( node->getElement( ) ) ) + n.insert( Neighbours( x, y ) ); + + return n; +} + +set<GlushkovTraversal::Neighbours> GlushkovTraversal::getNeighbours( const RegExpSymbol * node ) +{ + return set<Neighbours>( ); +} + +set<GlushkovTraversal::Neighbours> GlushkovTraversal::getNeighbours( const RegExpEpsilon * node ) +{ + return set<Neighbours>( ); +} + +set<GlushkovTraversal::Neighbours> GlushkovTraversal::getNeighbours( const RegExpEmpty * node ) +{ + return set<Neighbours>( ); +} + +} /* namespace conversions */ diff --git a/aconversions/src/shared/GlushkovTraversal.h b/aconversions/src/shared/GlushkovTraversal.h new file mode 100644 index 0000000000000000000000000000000000000000..cf2ff3d4a1cdaee0384fe8e17291f7ac0d68910f --- /dev/null +++ b/aconversions/src/shared/GlushkovTraversal.h @@ -0,0 +1,70 @@ +/* + * GlushkovTraversal.h + * + * Created on: 13. 3. 2014 + * Author: tomas + */ + +#ifndef GLUSHKOVTRAVERSAL_H_ +#define GLUSHKOVTRAVERSAL_H_ + +#include <set> + +#include <regexp/RegExp.h> +#include <regexp/RegExpElement.h> +#include <regexp/Alternation.h> +#include <regexp/Concatenation.h> +#include <regexp/Iteration.h> +#include <regexp/RegExpSymbol.h> +#include <regexp/RegExpEmpty.h> +#include <regexp/RegExpEpsilon.h> + +#include <AlibException.h> + +namespace conversions +{ + +class GlushkovTraversal +{ +public: + struct Neighbours + { + const regexp::RegExpSymbol * m_first, * m_second; + + Neighbours( const regexp::RegExpSymbol * first, const regexp::RegExpSymbol * second ); + bool operator<( const Neighbours & x ) const; + }; + + static std::set<const regexp::RegExpSymbol*> getLeftmostSymbolsInTree( const regexp::RegExp & re ); + static std::set<const regexp::RegExpSymbol*> getRightmostSymbolsInTree( const regexp::RegExp & re ); + static std::set<Neighbours> getNeighbours( const regexp::RegExp & re ); + +private: + static std::set<const regexp::RegExpSymbol*> getLeftmostSymbolsInTree( const regexp::RegExpElement * node ); + static std::set<const regexp::RegExpSymbol*> getLeftmostSymbolsInTree( const regexp::Alternation * node ); + static std::set<const regexp::RegExpSymbol*> getLeftmostSymbolsInTree( const regexp::Concatenation * node ); + static std::set<const regexp::RegExpSymbol*> getLeftmostSymbolsInTree( const regexp::Iteration * node ); + static std::set<const regexp::RegExpSymbol*> getLeftmostSymbolsInTree( const regexp::RegExpSymbol * node ); + static std::set<const regexp::RegExpSymbol*> getLeftmostSymbolsInTree( const regexp::RegExpEmpty * node ); + static std::set<const regexp::RegExpSymbol*> getLeftmostSymbolsInTree( const regexp::RegExpEpsilon * node ); + + static std::set<const regexp::RegExpSymbol*> getRightmostSymbolsInTree( const regexp::RegExpElement * node ); + static std::set<const regexp::RegExpSymbol*> getRightmostSymbolsInTree( const regexp::Alternation * node ); + static std::set<const regexp::RegExpSymbol*> getRightmostSymbolsInTree( const regexp::Concatenation * node ); + static std::set<const regexp::RegExpSymbol*> getRightmostSymbolsInTree( const regexp::Iteration * node ); + static std::set<const regexp::RegExpSymbol*> getRightmostSymbolsInTree( const regexp::RegExpSymbol * node ); + static std::set<const regexp::RegExpSymbol*> getRightmostSymbolsInTree( const regexp::RegExpEmpty * node ); + static std::set<const regexp::RegExpSymbol*> getRightmostSymbolsInTree( const regexp::RegExpEpsilon * node ); + + static std::set<Neighbours> getNeighbours( const regexp::RegExpElement * node ); + static std::set<Neighbours> getNeighbours( const regexp::Alternation * node ); + static std::set<Neighbours> getNeighbours( const regexp::Concatenation * node ); + static std::set<Neighbours> getNeighbours( const regexp::Iteration * node ); + static std::set<Neighbours> getNeighbours( const regexp::RegExpSymbol * node ); + static std::set<Neighbours> getNeighbours( const regexp::RegExpEmpty * node ); + static std::set<Neighbours> getNeighbours( const regexp::RegExpEpsilon * node ); +}; + +} /* namespace conversions */ + +#endif /* GLUSHKOVTRAVERSAL_H_ */