Skip to content
Snippets Groups Projects
Commit bf8c9ecd authored by Jan Trávníček's avatar Jan Trávníček
Browse files

template grammar ToAutomaton algorithm

parent 68e1fc38
No related branches found
No related tags found
No related merge requests found
......@@ -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 */
 
......
......@@ -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 */
......
......@@ -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));
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment