From bf8c9ecd108530961787908ba37340c917d10600 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Wed, 19 Sep 2018 13:13:51 +0200 Subject: [PATCH] template grammar ToAutomaton algorithm --- alib2algo/src/grammar/convert/ToAutomaton.cpp | 116 +----------------- alib2algo/src/grammar/convert/ToAutomaton.h | 104 +++++++++++++++- .../grammar/convert/GrammarCFGtoPDATest.cpp | 64 +++++----- 3 files changed, 133 insertions(+), 151 deletions(-) diff --git a/alib2algo/src/grammar/convert/ToAutomaton.cpp b/alib2algo/src/grammar/convert/ToAutomaton.cpp index 84a1a70abe..80de0d939f 100644 --- a/alib2algo/src/grammar/convert/ToAutomaton.cpp +++ b/alib2algo/src/grammar/convert/ToAutomaton.cpp @@ -5,128 +5,16 @@ * Author: Tomas Pecka */ #include "ToAutomaton.h" - -#include <common/createUnique.hpp> - -#include <label/InitialStateLabel.h> -#include <label/FinalStateLabel.h> #include <registration/AlgoRegistration.hpp> namespace grammar { namespace convert { -automaton::NFA < > ToAutomaton::convert(const grammar::LeftRG < > & grammar) { - ext::map<DefaultSymbolType, DefaultStateType> stateMap; - ext::set<DefaultStateType> states; - - // step 2 - for(const auto& symbol : grammar.getNonterminalAlphabet()) { - DefaultStateType state ( symbol ); - states.insert(state); - stateMap.insert(std::make_pair(symbol, state)); - } - - // step 1, 4 - DefaultStateType q0 = common::createUnique(label::InitialStateLabel::instance < DefaultStateType > ( ), states); - states.insert(q0); - automaton::NFA < > automaton(q0); - automaton.setInputAlphabet(grammar.getTerminalAlphabet()); - automaton.setStates(states); - - // step 3 - for(const auto& rule : grammar.getRules()) { - const DefaultSymbolType& lhs = rule.first; - for(const auto& ruleRHS : rule.second) { - if(ruleRHS.is<ext::pair<DefaultSymbolType, DefaultSymbolType>>()) { // if B->Ca => \delta(C,a)=B - const ext::pair<DefaultSymbolType, DefaultSymbolType>& rhs = ruleRHS.get<ext::pair<DefaultSymbolType, DefaultSymbolType>>(); - automaton.addTransition(stateMap.find(rhs.first)->second, rhs.second, stateMap.find(lhs)->second); - } - else { // if B->a => \delta(StartState,a)=B - const DefaultSymbolType& rhs = ruleRHS.get<DefaultSymbolType>(); - automaton.addTransition(q0, rhs, stateMap.find(lhs)->second); - } - } - } - - // step 5 - automaton.addFinalState(stateMap.find(grammar.getInitialSymbol())->second); - if(grammar.getGeneratesEpsilon()) - automaton.addFinalState(q0); - - return automaton; -} - -automaton::NFA < > ToAutomaton::convert(const grammar::RightRG < > & grammar) { - ext::map<DefaultSymbolType, DefaultStateType> stateMap; - ext::set<DefaultStateType> states; - - // step2 - for(const auto& symbol : grammar.getNonterminalAlphabet()) { - DefaultStateType state( symbol ); - states.insert(state); - stateMap.insert(std::make_pair(symbol, state)); - } - - // step 1, 4 - DefaultStateType AState = common::createUnique(label::FinalStateLabel::instance < DefaultStateType > ( ), states); - states.insert(AState); - automaton::NFA < > automaton(stateMap.find(grammar.getInitialSymbol())->second); - automaton.setStates(states); - - automaton.setInputAlphabet(grammar.getTerminalAlphabet()); - - // step 3 - for(const auto& rule : grammar.getRules()) { - const DefaultSymbolType& lhs = rule.first; - for(const auto& ruleRHS : rule.second) { - if(ruleRHS.is<ext::pair<DefaultSymbolType, DefaultSymbolType>>()) { // if B->aC => \delta(B,a)=C - const ext::pair<DefaultSymbolType, DefaultSymbolType>& rhs = ruleRHS.get<ext::pair<DefaultSymbolType, DefaultSymbolType>>(); - automaton.addTransition(stateMap.find(lhs)->second, rhs.first, stateMap.find(rhs.second)->second); - } - else { // if B->a => \delta(B,a)=AState - const DefaultSymbolType& rhs = ruleRHS.get<DefaultSymbolType>(); - automaton.addTransition(stateMap.find(lhs)->second, rhs, AState); - } - } - } - - // step 5 - automaton.addFinalState(AState); - if(grammar.getGeneratesEpsilon()) - automaton.addFinalState(automaton.getInitialState()); - - return automaton; -} - -template <class T> -automaton::NPDA < > ToAutomaton::convert(const T& grammar) { - automaton::NPDA < > automaton(label::InitialStateLabel::instance < DefaultStateType > ( ), grammar.getInitialSymbol()); - - automaton.setInputAlphabet(grammar.getTerminalAlphabet()); - - automaton.setPushdownStoreAlphabet(grammar.getNonterminalAlphabet()); - for(const DefaultSymbolType& symbol : grammar.getTerminalAlphabet()) - automaton.addPushdownStoreSymbol(symbol); - - for(const std::pair<const DefaultSymbolType, ext::set<ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>>>& kv : grammar.getRules()) - for(const ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>& rhs : kv.second) { - ext::vector < DefaultSymbolType > tmp; - for ( const ext::variant < DefaultSymbolType, DefaultSymbolType > & symbol : rhs ) - tmp.push_back ( symbol.get < DefaultSymbolType > ( ) ); - automaton.addTransition(automaton.getInitialState(), ext::vector<DefaultSymbolType>{kv.first}, automaton.getInitialState(), tmp); - } - - for(const DefaultSymbolType& symbol : grammar.getTerminalAlphabet()) - automaton.addTransition(automaton.getInitialState(), symbol, ext::vector<DefaultSymbolType>{symbol}, automaton.getInitialState(), ext::vector<DefaultSymbolType>{}); - - return automaton; -} - auto ToAutomatonLeftRG = registration::AbstractRegister < ToAutomaton, automaton::NFA < >, const grammar::LeftRG < > & > ( ToAutomaton::convert ); auto ToAutomatonRightRG = registration::AbstractRegister < ToAutomaton, automaton::NFA < >, const grammar::RightRG < > & > ( ToAutomaton::convert ); -auto ToAutomatonCFG = registration::AbstractRegister < ToAutomaton, automaton::NPDA < >, const grammar::CFG < > & > ( ToAutomaton::convert ); -auto ToAutomatonEpsilonFreeCFG = registration::AbstractRegister < ToAutomaton, automaton::NPDA < >, const grammar::EpsilonFreeCFG < > & > ( ToAutomaton::convert ); +auto ToAutomatonCFG = registration::AbstractRegister < ToAutomaton, automaton::NPDA < DefaultSymbolType, DefaultEpsilonType, ext::variant < DefaultSymbolType, DefaultSymbolType >, unsigned >, const grammar::CFG < > & > ( ToAutomaton::convert ); +auto ToAutomatonEpsilonFreeCFG = registration::AbstractRegister < ToAutomaton, automaton::NPDA < DefaultSymbolType, DefaultEpsilonType, ext::variant < DefaultSymbolType, DefaultSymbolType >, unsigned >, const grammar::EpsilonFreeCFG < > & > ( ToAutomaton::convert ); } /* namespace convert */ diff --git a/alib2algo/src/grammar/convert/ToAutomaton.h b/alib2algo/src/grammar/convert/ToAutomaton.h index 541b154f79..ee9c818337 100644 --- a/alib2algo/src/grammar/convert/ToAutomaton.h +++ b/alib2algo/src/grammar/convert/ToAutomaton.h @@ -8,6 +8,7 @@ #ifndef _GRAMMAR_TO_AUTOMATON_H_ #define _GRAMMAR_TO_AUTOMATON_H_ +#include <grammar/Grammar.h> #include <grammar/Regular/LeftRG.h> #include <grammar/Regular/RightRG.h> #include <grammar/ContextFree/CFG.h> @@ -16,6 +17,11 @@ #include <automaton/FSM/NFA.h> #include <automaton/PDA/NPDA.h> +#include <common/createUnique.hpp> + +#include <label/InitialStateLabel.h> +#include <label/FinalStateLabel.h> + namespace grammar { namespace convert { @@ -31,13 +37,103 @@ public: * @param grammar Regular grammar to convert. * @return FSM equivalent to source grammar. */ - static automaton::NFA < > convert(const grammar::LeftRG < > & grammar); - static automaton::NFA < > convert(const grammar::RightRG < > & grammar); + template < class TerminalSymbolType, class NonterminalSymbolType > + static automaton::NFA < TerminalSymbolType, NonterminalSymbolType > convert(const grammar::LeftRG < TerminalSymbolType, NonterminalSymbolType > & grammar); + template < class TerminalSymbolType, class NonterminalSymbolType > + static automaton::NFA < TerminalSymbolType, NonterminalSymbolType > convert(const grammar::RightRG < TerminalSymbolType, NonterminalSymbolType > & grammar); - template <class T> - static automaton::NPDA < > convert(const T& grammar); + template < class T, class TerminalSymbolType = typename grammar::TerminalSymbolTypeOfGrammar < T >, class NonterminalSymbolType = typename grammar::NonterminalSymbolTypeOfGrammar < T > > + static automaton::NPDA < TerminalSymbolType, DefaultEpsilonType, ext::variant < TerminalSymbolType, NonterminalSymbolType >, unsigned > convert ( const T & grammar ); }; +template < class TerminalSymbolType, class NonterminalSymbolType > +automaton::NFA < TerminalSymbolType, NonterminalSymbolType > ToAutomaton::convert(const grammar::LeftRG < TerminalSymbolType, NonterminalSymbolType > & grammar) { + // step 1, 4 + NonterminalSymbolType q0 = common::createUnique ( label::InitialStateLabel::instance < NonterminalSymbolType > ( ), grammar.getNonterminalAlphabet ( ) ); + automaton::NFA < TerminalSymbolType, NonterminalSymbolType > automaton ( q0 ); + automaton.setInputAlphabet(grammar.getTerminalAlphabet()); + for ( const NonterminalSymbolType & nonterminal : grammar.getNonterminalAlphabet ( ) ) + automaton.addState ( nonterminal ); + + // step 3 + for(const auto& rule : grammar.getRules()) { + const NonterminalSymbolType& lhs = rule.first; + for(const auto& ruleRHS : rule.second) { + if ( ruleRHS.template is < ext::pair < NonterminalSymbolType, TerminalSymbolType > > ( ) ) { // if B->Ca => \delta(C,a)=B + const ext::pair < NonterminalSymbolType, TerminalSymbolType > & rhs = ruleRHS.template get < ext::pair < NonterminalSymbolType, TerminalSymbolType > > ( ); + automaton.addTransition(rhs.first, rhs.second, lhs); + } + else { // if B->a => \delta(StartState,a)=B + const TerminalSymbolType& rhs = ruleRHS.template get < TerminalSymbolType > ( ); + automaton.addTransition(q0, rhs, lhs); + } + } + } + + // step 5 + automaton.addFinalState(grammar.getInitialSymbol()); + if(grammar.getGeneratesEpsilon()) + automaton.addFinalState(q0); + + return automaton; +} + +template < class TerminalSymbolType, class NonterminalSymbolType > +automaton::NFA < TerminalSymbolType, NonterminalSymbolType > ToAutomaton::convert(const grammar::RightRG < TerminalSymbolType, NonterminalSymbolType > & grammar) { + // step 1, 4 + NonterminalSymbolType AState = common::createUnique(label::FinalStateLabel::instance < NonterminalSymbolType > ( ), grammar.getNonterminalAlphabet ( ) ); + automaton::NFA < > automaton(grammar.getInitialSymbol()); + for ( const NonterminalSymbolType & nonterminal : grammar.getNonterminalAlphabet ( ) ) + automaton.addState ( nonterminal ); + automaton.addState(AState); + + automaton.setInputAlphabet(grammar.getTerminalAlphabet()); + + // step 3 + for(const auto& rule : grammar.getRules()) { + const NonterminalSymbolType& lhs = rule.first; + for(const auto& ruleRHS : rule.second) { + if ( ruleRHS.template is < ext::pair < TerminalSymbolType, NonterminalSymbolType > > ( ) ) { // if B->aC => \delta(B,a)=C + const ext::pair < TerminalSymbolType, NonterminalSymbolType > & rhs = ruleRHS.template get < ext::pair < TerminalSymbolType, NonterminalSymbolType > > ( ); + automaton.addTransition(lhs, rhs.first, rhs.second); + } + else { // if B->a => \delta(B,a)=AState + const TerminalSymbolType& rhs = ruleRHS.template get < TerminalSymbolType > ( ); + automaton.addTransition(lhs, rhs, AState); + } + } + } + + // step 5 + automaton.addFinalState(AState); + if(grammar.getGeneratesEpsilon()) + automaton.addFinalState(automaton.getInitialState()); + + return automaton; +} + +template < class T, class TerminalSymbolType, class NonterminalSymbolType > +automaton::NPDA < TerminalSymbolType, DefaultEpsilonType, ext::variant < TerminalSymbolType, NonterminalSymbolType >, unsigned > ToAutomaton::convert ( const T & grammar ) { + automaton::NPDA < TerminalSymbolType, DefaultEpsilonType, ext::variant < TerminalSymbolType, NonterminalSymbolType >, unsigned > automaton ( label::InitialStateLabel::instance < unsigned > ( ), grammar.getInitialSymbol()); + + automaton.setInputAlphabet(grammar.getTerminalAlphabet()); + + for ( const NonterminalSymbolType & nonterminal : grammar.getNonterminalAlphabet ( ) ) + automaton.addPushdownStoreSymbol ( nonterminal ); + for ( const TerminalSymbolType & terminal : grammar.getTerminalAlphabet ( ) ) + automaton.addPushdownStoreSymbol ( terminal ); + + for(const std::pair<const NonterminalSymbolType, ext::set<ext::vector<ext::variant<TerminalSymbolType,NonterminalSymbolType>>>>& kv : grammar.getRules()) + for ( const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & rhs : kv.second ) { + automaton.addTransition ( automaton.getInitialState ( ), ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { kv.first }, automaton.getInitialState ( ), rhs ); + } + + for(const TerminalSymbolType & symbol : grammar.getTerminalAlphabet()) + automaton.addTransition ( automaton.getInitialState ( ), symbol, ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { symbol }, automaton.getInitialState ( ), ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > { } ); + + return automaton; +} + } /* namespace convert */ } /* namespace grammar */ diff --git a/alib2algo/test-src/grammar/convert/GrammarCFGtoPDATest.cpp b/alib2algo/test-src/grammar/convert/GrammarCFGtoPDATest.cpp index f2aab8b5f5..cb6b6bcaa1 100644 --- a/alib2algo/test-src/grammar/convert/GrammarCFGtoPDATest.cpp +++ b/alib2algo/test-src/grammar/convert/GrammarCFGtoPDATest.cpp @@ -23,43 +23,41 @@ void GrammarCFGtoPDATest::tearDown() { void GrammarCFGtoPDATest::testTopDown() { { - DefaultSymbolType nE = DefaultSymbolType('E'); - DefaultSymbolType nT = DefaultSymbolType('T'); - DefaultSymbolType nF = DefaultSymbolType('F'); - - DefaultSymbolType tP = DefaultSymbolType('+'); - DefaultSymbolType tS = DefaultSymbolType('*'); - DefaultSymbolType tL = DefaultSymbolType('('); - DefaultSymbolType tR = DefaultSymbolType(')'); - DefaultSymbolType tA = DefaultSymbolType('a'); - - grammar::CFG < > grammar(nE); - grammar.setTerminalAlphabet(ext::set<DefaultSymbolType>{tP, tS, tL, tR, tA}); - grammar.setNonterminalAlphabet(ext::set<DefaultSymbolType>{nE, nT, nF}); - grammar.addRule(nE, ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>{nE, tP, nT}); - grammar.addRule(nE, ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>{nT}); - grammar.addRule(nT, ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>{nT, tS, nF}); - grammar.addRule(nT, ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>{nF}); - grammar.addRule(nF, ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>{tL, nE, tR}); - grammar.addRule(nF, ext::vector<ext::variant<DefaultSymbolType,DefaultSymbolType>>{tA}); + std::string nE = "E"; + std::string nT = "T"; + std::string nF = "F"; + + char tP = '+'; + char tS = '*'; + char tL = '('; + char tR = ')'; + char tA = 'a'; + + grammar::CFG < char, std::string > grammar(nE); + grammar.setTerminalAlphabet ( ext::set < char > { tP, tS, tL, tR, tA } ); + grammar.setNonterminalAlphabet ( ext::set < std::string > { nE, nT, nF } ); + grammar.addRule ( nE, ext::vector < ext::variant < char, std::string > > { nE, tP, nT } ); + grammar.addRule ( nE, ext::vector < ext::variant < char, std::string > > { nT } ); + grammar.addRule ( nT, ext::vector < ext::variant < char, std::string > > { nT, tS, nF } ); + grammar.addRule ( nT, ext::vector < ext::variant < char, std::string > > { nF } ); + grammar.addRule ( nF, ext::vector < ext::variant < char, std::string > > { tL, nE, tR } ); + grammar.addRule ( nF, ext::vector < ext::variant < char, std::string > > { tA } ); + unsigned q = label::InitialStateLabel::instance < unsigned > ( ); - DefaultStateType q = label::InitialStateLabel::instance < DefaultStateType > ( ); + automaton::NPDA < char, DefaultEpsilonType, ext::variant < char, std::string >, unsigned > pda ( q, nE ); + pda.setInputAlphabet ( ext::set < char > { tP, tS, tL, tR, tA } ); + pda.setPushdownStoreAlphabet ( ext::set < ext::variant < char, std::string > > { tP, tS, tL, tR, tA, nE, nT, nF } ); - automaton::NPDA < > pda(q, nE); - pda.setStates(ext::set<DefaultStateType>{q}); - pda.setInputAlphabet(ext::set<DefaultSymbolType>{tP, tS, tL, tR, tA}); - pda.setPushdownStoreAlphabet(ext::set<DefaultSymbolType>{tP, tS, tL, tR, tA, nE, nT, nF}); + pda.addTransition ( q, ext::vector < ext::variant < char, std::string > > { nE }, q, ext::vector < ext::variant < char, std::string > > { nE, tP, nT } ); + pda.addTransition ( q, ext::vector < ext::variant < char, std::string > > { nE }, q, ext::vector < ext::variant < char, std::string > > { nT } ); + pda.addTransition ( q, ext::vector < ext::variant < char, std::string > > { nT }, q, ext::vector < ext::variant < char, std::string > > { nT, tS, nF } ); + pda.addTransition ( q, ext::vector < ext::variant < char, std::string > > { nT }, q, ext::vector < ext::variant < char, std::string > > { nF } ); + pda.addTransition ( q, ext::vector < ext::variant < char, std::string > > { nF }, q, ext::vector < ext::variant < char, std::string > > { tL, nE, tR } ); + pda.addTransition ( q, ext::vector < ext::variant < char, std::string > > { nF }, q, ext::vector < ext::variant < char, std::string > > { tA } ); - pda.addTransition(q, ext::vector<DefaultSymbolType>{nE}, q, ext::vector<DefaultSymbolType>{nE, tP, nT}); - pda.addTransition(q, ext::vector<DefaultSymbolType>{nE}, q, ext::vector<DefaultSymbolType>{nT}); - pda.addTransition(q, ext::vector<DefaultSymbolType>{nT}, q, ext::vector<DefaultSymbolType>{nT, tS, nF}); - pda.addTransition(q, ext::vector<DefaultSymbolType>{nT}, q, ext::vector<DefaultSymbolType>{nF}); - pda.addTransition(q, ext::vector<DefaultSymbolType>{nF}, q, ext::vector<DefaultSymbolType>{tL, nE, tR}); - pda.addTransition(q, ext::vector<DefaultSymbolType>{nF}, q, ext::vector<DefaultSymbolType>{tA}); - - for(const auto& symbol: pda.getInputAlphabet()) - pda.addTransition(q, symbol, ext::vector<DefaultSymbolType>{symbol}, q, ext::vector<DefaultSymbolType>{}); + for ( char symbol : pda.getInputAlphabet ( ) ) + pda.addTransition ( q, symbol, ext::vector<ext::variant < char, std::string >>{symbol}, q, ext::vector<ext::variant < char, std::string >>{}); CPPUNIT_ASSERT(pda == grammar::convert::ToAutomaton::convert(grammar)); } -- GitLab