diff --git a/alib2algo/src/grammar/parsing/First.cpp b/alib2algo/src/grammar/parsing/First.cpp index fc00d75ead0c6d8251a4931b5b2bf1079f139e5f..61d290a23546da8484e27fcdc6216b91ec806834 100644 --- a/alib2algo/src/grammar/parsing/First.cpp +++ b/alib2algo/src/grammar/parsing/First.cpp @@ -6,54 +6,48 @@ */ #include "First.h" -#include <algorithm> -#include <string/Epsilon.h> -#include <iterator> -#include "setunion.h" +#include <grammar/ContextFree/CFG.h> +#include <grammar/ContextFree/EpsilonFreeCFG.h> +#include <grammar/ContextFree/CNF.h> +#include <grammar/ContextFree/GNF.h> +#include <grammar/ContextFree/LG.h> +#include <grammar/Regular/LeftLG.h> +#include <grammar/Regular/LeftRG.h> +#include <grammar/Regular/RightLG.h> +#include <grammar/Regular/RightRG.h> +#include <exception/AlibException.h> namespace grammar { namespace parsing { -template<class T> -std::set<std::variant<alphabet::Symbol, string::Epsilon>> First::firstSeq(const T& grammar, const std::vector<alphabet::Symbol>& rhs, std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> firstNt) -{ +std::set<std::variant<alphabet::Symbol, string::Epsilon>> First::first(const std::set<alphabet::Symbol>& terminals, const std::set<alphabet::Symbol>& nonterminals, const std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& firstOfNonterminal, const std::vector<alphabet::Symbol>& rhs) { // 1. FIRST(\varepsilon) = { \varepsilon } - if(rhs.empty()) return {string::Epsilon::EPSILON}; + if(rhs.size() == 0) + return {string::Epsilon::EPSILON}; // 2. FIRST(a) = { a } forall a \in T - else if(grammar.getTerminalAlphabet().find(rhs[0]) != grammar.getTerminalAlphabet().end()) + else if(terminals.count(rhs[0])) return {rhs[0]}; - // 3. FIRST(A) = first(A) forall A \in N - else if(rhs.size() == 1 && grammar.getNonterminalAlphabet().find(rhs[0]) != grammar.getNonterminalAlphabet().end()) - return firstNt[rhs[0]]; - // 4. FIRST(A \alpha) = first(A) if A \in N and \varepsilon \notin first(A) - else if(grammar.getNonterminalAlphabet().find(rhs[0]) != grammar.getNonterminalAlphabet().end() && firstNt[rhs[0]].find(string::Epsilon::EPSILON) == firstNt[rhs[0]].end()) - return firstNt[rhs[0]]; + else if(nonterminals.count(rhs[0]) && !firstOfNonterminal.find(rhs[0])->second.count(string::Epsilon::EPSILON)) + return firstOfNonterminal.find(rhs[0])->second; // 5. FIRST(A \alpha) = (first(A) - \varepsilon) \cup FIRST(\alpha) if A \in N and \varepsilon \in first(A) - else if(grammar.getNonterminalAlphabet().find(rhs[0]) != grammar.getNonterminalAlphabet().end() && firstNt[rhs[0]].find(string::Epsilon::EPSILON) != firstNt[rhs[0]].end()) - { - std::set<std::variant<alphabet::Symbol, string::Epsilon>> fiA = firstNt[rhs[0]]; - - auto it = fiA.find(string::Epsilon::EPSILON); - if(it != fiA.end()) fiA.erase(it); + else if(nonterminals.count(rhs[0]) && firstOfNonterminal.find(rhs[0])->second.count(string::Epsilon::EPSILON)) { + std::set<std::variant<alphabet::Symbol, string::Epsilon>> res = firstOfNonterminal.find(rhs[0])->second; + res.erase(string::Epsilon::EPSILON); - std::vector<alphabet::Symbol> alpha = rhs; - alpha.erase(alpha.begin()); - std::set<std::variant<alphabet::Symbol, string::Epsilon>> FIA = firstSeq(grammar, alpha, firstNt); - - return setunion(fiA, FIA); - } - throw exception::AlibException("Unhandled case in First.cpp"); + std::set<std::variant<alphabet::Symbol, string::Epsilon>> next = first(terminals, nonterminals, firstOfNonterminal, std::vector<alphabet::Symbol>(rhs.begin() + 1, rhs.end())); + res.insert(next.begin(), next.end()); + return res; + } else + throw exception::AlibException("Cant be reached"); } -template<class T> -std::set<std::variant<alphabet::Symbol, string::Epsilon>> First::first(const T& grammar, const std::vector<alphabet::Symbol>& rhs) -{ +std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> First::first(const std::set<alphabet::Symbol>& terminals, const std::set<alphabet::Symbol>& nonterminals, const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rules) { /* * * 1. foreach A \in N: first(A) = \emptyset @@ -62,134 +56,79 @@ std::set<std::variant<alphabet::Symbol, string::Epsilon>> First::first(const T& * 3. repeat step 2 if at least one set first(A) has changed * */ + std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> firstOfNonterminal1; + for(const alphabet::Symbol& nonterminal : nonterminals) + firstOfNonterminal1[nonterminal]; - // (N u T)* -> T* - // rhs -> first(rhs) - std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> firstNt; - for(const alphabet::Symbol& nt : grammar.getNonterminalAlphabet()) - firstNt.insert(std::make_pair(nt, std::set<std::variant<alphabet::Symbol, string::Epsilon>>{})); - - bool changed; - do - { - changed = false; - - for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : grammar.getRawRules()) - { - const alphabet::Symbol& lhs = rule.first; - for(const std::vector<alphabet::Symbol>& rhs : rule.second) - { - std::set<std::variant<alphabet::Symbol, string::Epsilon>> oldFirst; - - oldFirst = firstNt[lhs]; - firstNt[lhs] = setunion(firstNt[lhs], firstSeq(grammar, rhs, firstNt)); - if(firstNt[lhs] != oldFirst) - changed = true; + std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> firstOfNonterminal2 = firstOfNonterminal1; + + do { + for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : rules) { + for(const std::vector<alphabet::Symbol>& rhs : rule.second) { + std::set<std::variant<alphabet::Symbol, string::Epsilon>> newFirst = first(terminals, nonterminals, firstOfNonterminal1, rhs); + firstOfNonterminal2[rule.first].insert(newFirst.begin(), newFirst.end()); } } - } - while(changed); - - /* - std::map<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> res; - for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : grammar.getRawRules()) - for(const std::vector<alphabet::Symbol>& rhs : rule.second) - res[rhs] = firstSeq(grammar, rhs, firstNt); - return res; - */ - - return firstSeq(grammar, rhs, firstNt); -} - -template<> -std::set<std::variant<alphabet::Symbol, string::Epsilon>> First::first(const grammar::Grammar& grammar, const std::vector<alphabet::Symbol>& rhs) { - std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> data; - data.first = rhs; - grammar.getData().Accept((void*) &data, First::FIRST); - return data.second; -} - -void First::Visit(void* data, const grammar::LeftLG& grammar) const { - std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); - - out.second = this->first(grammar, out.first); -} - -void First::Visit(void* data, const grammar::LeftRG& grammar) const { - std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); - out.second = this->first(grammar, out.first); -} - -void First::Visit(void* data, const grammar::RightLG& grammar) const { - std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); - - out.second = this->first(grammar, out.first); -} - -void First::Visit(void* data, const grammar::RightRG& grammar) const { - std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); + if(firstOfNonterminal1 == firstOfNonterminal2) break; - out.second = this->first(grammar, out.first); -} + firstOfNonterminal1 = std::move(firstOfNonterminal2); + firstOfNonterminal2.clear(); -void First::Visit(void* data, const grammar::LG& grammar) const { - std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); + } while(true); - out.second = this->first(grammar, out.first); + return firstOfNonterminal1; } -void First::Visit(void* data, const grammar::CFG& grammar) const { - std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); - - out.second = this->first(grammar, out.first); -} - -void First::Visit(void* data, const grammar::EpsilonFreeCFG& grammar) const { - std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); - - out.second = this->first(grammar, out.first); -} +template<class T> +std::map<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> First::first( const T & grammar ) { + std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> firstNt = first(grammar.getTerminalAlphabet(), grammar.getNonterminalAlphabet(), grammar.getRawRules()); -void First::Visit(void* data, const grammar::CNF& grammar) const { - std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); + std::map<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> res; + for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : grammar.getRawRules()) { + for(const std::vector<alphabet::Symbol>& rhs : rule.second) { + res.insert(make_pair(rhs, first(grammar.getTerminalAlphabet(), grammar.getNonterminalAlphabet(), firstNt, rhs))); + } + } - out.second = this->first(grammar, out.first); + return res; } -void First::Visit(void* data, const grammar::GNF& grammar) const { - std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); +template<class T> +std::set<std::variant<alphabet::Symbol, string::Epsilon>> First::first(const T& grammar, const std::vector<alphabet::Symbol>& rhs) { + std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> firstNt = first(grammar.getTerminalAlphabet(), grammar.getNonterminalAlphabet(), grammar.getRawRules()); - out.second = this->first(grammar, out.first); + return first(grammar.getTerminalAlphabet(), grammar.getNonterminalAlphabet(), firstNt, rhs); } -void First::Visit(void*, const grammar::CSG&) const { - throw exception::AlibException("Unsupported grammar type CSG"); -} +auto FirstCFG = FirstBase1::RegistratorWrapper<FirstResult1, grammar::CFG>(First::getInstance1(), First::first); +auto FirstEpsilonFreeCFG = FirstBase1::RegistratorWrapper<FirstResult1, grammar::EpsilonFreeCFG>(First::getInstance1(), First::first); +auto FirstGNF = FirstBase1::RegistratorWrapper<FirstResult1, grammar::GNF>(First::getInstance1(), First::first); +auto FirstCNF = FirstBase1::RegistratorWrapper<FirstResult1, grammar::CNF>(First::getInstance1(), First::first); +auto FirstLG = FirstBase1::RegistratorWrapper<FirstResult1, grammar::LG>(First::getInstance1(), First::first); +auto FirstLeftLG = FirstBase1::RegistratorWrapper<FirstResult1, grammar::LeftLG>(First::getInstance1(), First::first); +auto FirstLeftRG = FirstBase1::RegistratorWrapper<FirstResult1, grammar::LeftRG>(First::getInstance1(), First::first); +auto FirstRightLG = FirstBase1::RegistratorWrapper<FirstResult1, grammar::RightLG>(First::getInstance1(), First::first); +auto FirstRightRG = FirstBase1::RegistratorWrapper<FirstResult1, grammar::RightRG>(First::getInstance1(), First::first); -void First::Visit(void*, const grammar::NonContractingGrammar&) const { - throw exception::AlibException("Unsupported grammar type NonConctractingGrammar"); +std::map<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> First::first(const grammar::Grammar& grammar) { + return getInstance1().dispatch(grammar.getData()); } -void First::Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar&) const { - throw exception::AlibException("Unsupported grammar type ContextPreservingUnrestrictedGrammar"); -} +auto FirstCFG2 = FirstBase2::RegistratorWrapper<FirstResult2, grammar::CFG>(First::getInstance2(), First::first); +auto FirstEpsilonFreeCFG2 = FirstBase2::RegistratorWrapper<FirstResult2, grammar::EpsilonFreeCFG>(First::getInstance2(), First::first); +auto FirstGNF2 = FirstBase2::RegistratorWrapper<FirstResult2, grammar::GNF>(First::getInstance2(), First::first); +auto FirstCNF2 = FirstBase2::RegistratorWrapper<FirstResult2, grammar::CNF>(First::getInstance2(), First::first); +auto FirstLG2 = FirstBase2::RegistratorWrapper<FirstResult2, grammar::LG>(First::getInstance2(), First::first); +auto FirstLeftLG2 = FirstBase2::RegistratorWrapper<FirstResult2, grammar::LeftLG>(First::getInstance2(), First::first); +auto FirstLeftRG2 = FirstBase2::RegistratorWrapper<FirstResult2, grammar::LeftRG>(First::getInstance2(), First::first); +auto FirstRightLG2 = FirstBase2::RegistratorWrapper<FirstResult2, grammar::RightLG>(First::getInstance2(), First::first); +auto FirstRightRG2 = FirstBase2::RegistratorWrapper<FirstResult2, grammar::RightRG>(First::getInstance2(), First::first); -void First::Visit(void*, const grammar::UnrestrictedGrammar&) const { - throw exception::AlibException("Unsupported grammar type UnrestrictedGrammar"); +std::set<std::variant<alphabet::Symbol, string::Epsilon>> First::first(const grammar::Grammar& grammar, const std::vector<alphabet::Symbol>& rhs) { + return getInstance2().dispatch(grammar.getData(), rhs); } -const First First::FIRST; - } /* namespace parsing */ } /* namespace grammar */ diff --git a/alib2algo/src/grammar/parsing/First.h b/alib2algo/src/grammar/parsing/First.h index 958a0a99a41d2f863f68547d03b5ab9c61fd3904..c01373e1a2dad0240bd3e2424cd92155c0e55f6c 100644 --- a/alib2algo/src/grammar/parsing/First.h +++ b/alib2algo/src/grammar/parsing/First.h @@ -2,56 +2,58 @@ * First.h * * Created on: 9. 6. 2015 - * Author: Tomas Pecka + * Author: Tomas Pecka, Jan Travnicek */ #ifndef FIRST_H_ #define FIRST_H_ +#include <common/multipleDispatch.hpp> #include <grammar/Grammar.h> - -#include <grammar/ContextFree/CFG.h> -#include <grammar/ContextFree/EpsilonFreeCFG.h> -#include <grammar/ContextFree/CNF.h> -#include <grammar/ContextFree/GNF.h> -#include <grammar/ContextFree/LG.h> -#include <grammar/Regular/LeftLG.h> -#include <grammar/Regular/LeftRG.h> -#include <grammar/Regular/RightLG.h> -#include <grammar/Regular/RightRG.h> -#include <exception/AlibException.h> +#include <alphabet/Symbol.h> +#include <string/Epsilon.h> +#include <vector> +#include <set> +#include <variant> namespace grammar { namespace parsing { -class First : public grammar::VisitableGrammarBase::const_visitor_type { +typedef std::map<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> FirstResult1; +typedef std::SingleDispatch<FirstResult1, grammar::GrammarBase> FirstBase1; -public: - First() {} +typedef std::set<std::variant<alphabet::Symbol, string::Epsilon>> FirstResult2; +typedef std::SingleDispatchLastStaticParam<FirstResult2, grammar::GrammarBase, const std::vector<alphabet::Symbol>&> FirstBase2; + +class First : public FirstBase1, public FirstBase2 { + static std::set<std::variant<alphabet::Symbol, string::Epsilon>> first(const std::set<alphabet::Symbol>& terminals, const std::set<alphabet::Symbol>& nonterminals, const std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& firstOfNonterminal, const std::vector<alphabet::Symbol>& rhs); + + static std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> first(const std::set<alphabet::Symbol>& terminals, const std::set<alphabet::Symbol>& nonterminals, const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rules); + + static First& getInstance() { + static First res; + return res; + } +public: template<class T> - static std::set<std::variant<alphabet::Symbol, string::Epsilon>> first(const T& grammar, const std::vector<alphabet::Symbol>& rhs); + static FirstResult1 first( const T & grammar ); -private: template<class T> - static std::set<std::variant<alphabet::Symbol, string::Epsilon>> firstSeq(const T& grammar, const std::vector<alphabet::Symbol>& rhs, std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> firstNt); - - void Visit(void*, const grammar::LeftLG& grammar) const; - void Visit(void*, const grammar::LeftRG& grammar) const; - void Visit(void*, const grammar::RightLG& grammar) const; - void Visit(void*, const grammar::RightRG& grammar) const; - void Visit(void*, const grammar::LG& grammar) const; - void Visit(void*, const grammar::CFG& grammar) const; - void Visit(void*, const grammar::EpsilonFreeCFG& grammar) const; - void Visit(void*, const grammar::CNF& grammar) const; - void Visit(void*, const grammar::GNF& grammar) const; - void Visit(void*, const grammar::CSG& grammar) const; - void Visit(void*, const grammar::NonContractingGrammar& grammar) const; - void Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar& grammar) const; - void Visit(void*, const grammar::UnrestrictedGrammar& grammar) const; - - static const First FIRST; + static FirstResult2 first(const T& grammar, const std::vector<alphabet::Symbol>& rhs); + + static FirstResult1 first(const grammar::Grammar& grammar); + + static FirstResult2 first(const grammar::Grammar& grammar, const std::vector<alphabet::Symbol>& rhs); + + static FirstBase1& getInstance1() { + return getInstance(); + } + + static FirstBase2& getInstance2() { + return getInstance(); + } }; } /* namespace parsing */ diff --git a/alib2algo/src/grammar/parsing/Follow.cpp b/alib2algo/src/grammar/parsing/Follow.cpp index afd058b5f75ce537697ad97c7dec4bf9dd5550ff..dfc2ec98a83025619e1f9ea44009f6ce67457f4c 100644 --- a/alib2algo/src/grammar/parsing/Follow.cpp +++ b/alib2algo/src/grammar/parsing/Follow.cpp @@ -11,16 +11,47 @@ #include <string/Epsilon.h> #include <iterator> -#include "setunion.h" +#include <grammar/ContextFree/CFG.h> +#include <grammar/ContextFree/EpsilonFreeCFG.h> +#include <grammar/ContextFree/CNF.h> +#include <grammar/ContextFree/GNF.h> +#include <grammar/ContextFree/LG.h> +#include <grammar/Regular/LeftLG.h> +#include <grammar/Regular/LeftRG.h> +#include <grammar/Regular/RightLG.h> +#include <grammar/Regular/RightRG.h> +#include <exception/AlibException.h> namespace grammar { namespace parsing { template<class T> -std::set<std::variant<alphabet::Symbol, string::Epsilon>> Follow::follow(const T& grammar, const alphabet::Symbol& nt) -{ - if(grammar.getNonterminalAlphabet().find(nt) == grammar.getNonterminalAlphabet().end()) +void Follow::follow(const T& grammar, std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& followSet) { + for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : grammar.getRawRules()) { + const alphabet::Symbol& X = rule.first; + for(const std::vector<alphabet::Symbol>& rhs : rule.second) { + // every nt in rhs is Y + for(std::vector<alphabet::Symbol>::const_iterator it = rhs.begin(); it != rhs.end(); it++) { + const alphabet::Symbol& Y = *it; + if(!grammar.getNonterminalAlphabet().count(Y)) continue; + + std::set<std::variant<alphabet::Symbol, string::Epsilon>> firstBeta = First::first(grammar, std::vector<alphabet::Symbol>(std::next(it), rhs.end())); + + if(firstBeta.count(string::Epsilon::EPSILON)) { + firstBeta.erase(string::Epsilon::EPSILON); + followSet[Y].insert(followSet[X].begin(), followSet[X].end()); + } + + followSet[Y].insert(firstBeta.begin(), firstBeta.end()); + } + } + } +} + +template<class T> +std::set<std::variant<alphabet::Symbol, string::Epsilon>> Follow::follow(const T& grammar, const alphabet::Symbol& nt) { + if(!grammar.getNonterminalAlphabet().count(nt)) throw exception::AlibException("Follow: Given symbol is not nonterminal."); /* @@ -34,144 +65,40 @@ std::set<std::variant<alphabet::Symbol, string::Epsilon>> Follow::follow(const T * 3. goto 2 if any follow set was changed in prev step. */ - std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> followSet; + std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> followSet1; for(const alphabet::Symbol& symb : grammar.getNonterminalAlphabet()) - followSet[symb] = {}; - - followSet[grammar.getInitialSymbol()] = {string::Epsilon::EPSILON}; - - bool changed; - do - { - changed = false; - - for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : grammar.getRawRules()) - { - const alphabet::Symbol& X = rule.first; - for(const std::vector<alphabet::Symbol>& rhs : rule.second) - { - // every nt in rhs is Y - for(std::vector<alphabet::Symbol>::const_iterator it = rhs.begin(); it != rhs.end(); it++) - { - const alphabet::Symbol& Y = *it; - - if(grammar.getNonterminalAlphabet().find(Y) == grammar.getNonterminalAlphabet().end()) - continue; - - std::vector<alphabet::Symbol> beta(std::next(it), rhs.end()); - std::set<std::variant<alphabet::Symbol, string::Epsilon>> oldFollow, firstBeta = First::first(grammar, beta); - - auto epsIt = firstBeta.find(string::Epsilon::EPSILON); - if(epsIt != firstBeta.end()) - { - firstBeta.erase(epsIt); - - oldFollow = followSet[Y]; - followSet[Y] = setunion(followSet[Y], followSet[X]); - if(oldFollow != followSet[Y]) changed = true; - } - - oldFollow = followSet[Y]; - followSet[Y] = setunion(followSet[Y], firstBeta); - if(oldFollow != followSet[Y]) changed = true; - } - } - } - } - while(changed); - - return followSet[nt]; -} - -template<> -std::set<std::variant<alphabet::Symbol, string::Epsilon>> Follow::follow(const grammar::Grammar& grammar, const alphabet::Symbol& nt) { - std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> data(nt, {}); - grammar.getData().Accept((void*) &data, Follow::FOLLOW); - return data.second; -} - -void Follow::Visit(void* data, const grammar::LeftLG& grammar) const { - std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); - - out.second = this->follow(grammar, out.first); -} - -void Follow::Visit(void* data, const grammar::LeftRG& grammar) const { - std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); - - out.second = this->follow(grammar, out.first); -} - -void Follow::Visit(void* data, const grammar::RightLG& grammar) const { - std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); - - out.second = this->follow(grammar, out.first); -} - -void Follow::Visit(void* data, const grammar::RightRG& grammar) const { - std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); - - out.second = this->follow(grammar, out.first); -} - -void Follow::Visit(void* data, const grammar::LG& grammar) const { - std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); - - out.second = this->follow(grammar, out.first); -} - -void Follow::Visit(void* data, const grammar::CFG& grammar) const { - std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); + followSet1[symb]; - out.second = this->follow(grammar, out.first); -} - -void Follow::Visit(void* data, const grammar::EpsilonFreeCFG& grammar) const { - std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); + followSet1[grammar.getInitialSymbol()] = {string::Epsilon::EPSILON}; - out.second = this->follow(grammar, out.first); -} + std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> followSet2 = followSet1; -void Follow::Visit(void* data, const grammar::CNF& grammar) const { - std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); + do { + follow(grammar, followSet2); - out.second = this->follow(grammar, out.first); -} + if(followSet1 == followSet2) break; -void Follow::Visit(void* data, const grammar::GNF& grammar) const { - std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& out = - *((std::pair<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>*) data); + followSet1 = followSet2; + } while(true); - out.second = this->follow(grammar, out.first); + return followSet1[nt]; } -void Follow::Visit(void*, const grammar::CSG&) const { - throw exception::AlibException("Unsupported grammar type CSG"); -} +auto FollowCFG = Follow::RegistratorWrapper<std::set<std::variant<alphabet::Symbol, string::Epsilon>>, grammar::CFG>(Follow::getInstance(), Follow::follow); +auto FollowEpsilonFreeCFG = Follow::RegistratorWrapper<std::set<std::variant<alphabet::Symbol, string::Epsilon>>, grammar::EpsilonFreeCFG>(Follow::getInstance(), Follow::follow); +auto FollowGNF = Follow::RegistratorWrapper<std::set<std::variant<alphabet::Symbol, string::Epsilon>>, grammar::GNF>(Follow::getInstance(), Follow::follow); +auto FollowCNF = Follow::RegistratorWrapper<std::set<std::variant<alphabet::Symbol, string::Epsilon>>, grammar::CNF>(Follow::getInstance(), Follow::follow); +auto FollowLG = Follow::RegistratorWrapper<std::set<std::variant<alphabet::Symbol, string::Epsilon>>, grammar::LG>(Follow::getInstance(), Follow::follow); +auto FollowLeftLG = Follow::RegistratorWrapper<std::set<std::variant<alphabet::Symbol, string::Epsilon>>, grammar::LeftLG>(Follow::getInstance(), Follow::follow); +auto FollowLeftRG = Follow::RegistratorWrapper<std::set<std::variant<alphabet::Symbol, string::Epsilon>>, grammar::LeftRG>(Follow::getInstance(), Follow::follow); +auto FollowRightLG = Follow::RegistratorWrapper<std::set<std::variant<alphabet::Symbol, string::Epsilon>>, grammar::RightLG>(Follow::getInstance(), Follow::follow); +auto FollowRightRG = Follow::RegistratorWrapper<std::set<std::variant<alphabet::Symbol, string::Epsilon>>, grammar::RightRG>(Follow::getInstance(), Follow::follow); -void Follow::Visit(void*, const grammar::NonContractingGrammar&) const { - throw exception::AlibException("Unsupported grammar type NonConctractingGrammar"); -} - -void Follow::Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar&) const { - throw exception::AlibException("Unsupported grammar type ContextPreservingUnrestrictedGrammar"); -} - -void Follow::Visit(void*, const grammar::UnrestrictedGrammar&) const { - throw exception::AlibException("Unsupported grammar type UnrestrictedGrammar"); +std::set<std::variant<alphabet::Symbol, string::Epsilon>> Follow::follow(const grammar::Grammar& grammar, const alphabet::Symbol& nt) { + return getInstance().dispatch(grammar.getData(), nt); } -const Follow Follow::FOLLOW; - } /* namespace parsing */ } /* namespace grammar */ diff --git a/alib2algo/src/grammar/parsing/Follow.h b/alib2algo/src/grammar/parsing/Follow.h index 3d1e4b40bbbe91ba19c0a20e495cc23f616286e3..e5d6a0800ac05864e3e6affb8873d6558f96536e 100644 --- a/alib2algo/src/grammar/parsing/Follow.h +++ b/alib2algo/src/grammar/parsing/Follow.h @@ -8,47 +8,32 @@ #ifndef FOLLOW_H_ #define FOLLOW_H_ +#include <common/multipleDispatch.hpp> #include <grammar/Grammar.h> - -#include <grammar/ContextFree/CFG.h> -#include <grammar/ContextFree/EpsilonFreeCFG.h> -#include <grammar/ContextFree/CNF.h> -#include <grammar/ContextFree/GNF.h> -#include <grammar/ContextFree/LG.h> -#include <grammar/Regular/LeftLG.h> -#include <grammar/Regular/LeftRG.h> -#include <grammar/Regular/RightLG.h> -#include <grammar/Regular/RightRG.h> -#include <exception/AlibException.h> +#include <alphabet/Symbol.h> +#include <string/Epsilon.h> +#include <vector> +#include <set> +#include <variant> namespace grammar { namespace parsing { -class Follow : public grammar::VisitableGrammarBase::const_visitor_type { +class Follow : public std::SingleDispatchLastStaticParam<std::set<std::variant<alphabet::Symbol, string::Epsilon>>, grammar::GrammarBase, const alphabet::Symbol&> { + template<class T> + static void follow(const T& grammar, std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>>& followSet); public: - Follow() {} + static std::set<std::variant<alphabet::Symbol, string::Epsilon>> follow(const grammar::Grammar& grammar, const alphabet::Symbol& nt); template<class T> static std::set<std::variant<alphabet::Symbol, string::Epsilon>> follow(const T& grammar, const alphabet::Symbol& nt); -private: - void Visit(void*, const grammar::LeftLG& grammar) const; - void Visit(void*, const grammar::LeftRG& grammar) const; - void Visit(void*, const grammar::RightLG& grammar) const; - void Visit(void*, const grammar::RightRG& grammar) const; - void Visit(void*, const grammar::LG& grammar) const; - void Visit(void*, const grammar::CFG& grammar) const; - void Visit(void*, const grammar::EpsilonFreeCFG& grammar) const; - void Visit(void*, const grammar::CNF& grammar) const; - void Visit(void*, const grammar::GNF& grammar) const; - void Visit(void*, const grammar::CSG& grammar) const; - void Visit(void*, const grammar::NonContractingGrammar& grammar) const; - void Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar& grammar) const; - void Visit(void*, const grammar::UnrestrictedGrammar& grammar) const; - - static const Follow FOLLOW; + static Follow& getInstance() { + static Follow res; + return res; + } }; } /* namespace parsing */ diff --git a/alib2algo/src/grammar/parsing/setunion.h b/alib2algo/src/grammar/parsing/setunion.h deleted file mode 100644 index c69b35061aec537a9cd2a9bbc2362162c826ca27..0000000000000000000000000000000000000000 --- a/alib2algo/src/grammar/parsing/setunion.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __SETUNION_H__ -#define __SETUNION_H__ - -namespace grammar { - -namespace parsing { - -template<class T> -std::set<T> setunion(const std::set<T>& a, const std::set<T>& b) -{ - std::set<T> res; - std::set_union(a.begin(), a.end(), b.begin(), b.end(), std::inserter(res, res.begin())); - return res; -} - -} /* namespace parsing */ - -} /* namespace grammar */ - -#endif /* __SETUNION_H__ */ diff --git a/alib2algo/test-src/grammar/parsing/FirstTest.cpp b/alib2algo/test-src/grammar/parsing/FirstTest.cpp index ad3f5fbf29cf79c6acdb6c9b3384735ebc47dd8b..f80149c9b369182390d49ab893510e6ccca10a76 100644 --- a/alib2algo/test-src/grammar/parsing/FirstTest.cpp +++ b/alib2algo/test-src/grammar/parsing/FirstTest.cpp @@ -2,6 +2,7 @@ #include "grammar/parsing/First.h" #include "string/Epsilon.h" +#include "grammar/ContextFree/CFG.h" CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( FirstTest, "grammar" ); CPPUNIT_TEST_SUITE_REGISTRATION( FirstTest ); @@ -142,3 +143,52 @@ void FirstTest::testFirst() { } } +void FirstTest::testFirst2() { + alphabet::Symbol A = alphabet::symbolFrom('A'); + alphabet::Symbol c = alphabet::symbolFrom('c'); + alphabet::Symbol d = alphabet::symbolFrom('d'); + + grammar::CFG grammar(A); + grammar.setTerminalAlphabet({c, d}); + grammar.setNonterminalAlphabet({{A}}); + grammar.setInitialSymbol(A); + + grammar.addRule(A, std::vector<alphabet::Symbol>{ A, c }); + grammar.addRule(A, std::vector<alphabet::Symbol>{ d }); + + std::map<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> res = {{{d}, {d}}, {{A, c}, {d}}}; + CPPUNIT_ASSERT(res == grammar::parsing::First::first(grammar)); +} + +void FirstTest::testFirst3() { + alphabet::Symbol S = alphabet::symbolFrom('S'); + alphabet::Symbol A = alphabet::symbolFrom('A'); + alphabet::Symbol B = alphabet::symbolFrom('B'); + alphabet::Symbol a = alphabet::symbolFrom('a'); + alphabet::Symbol b = alphabet::symbolFrom('b'); + alphabet::Symbol c = alphabet::symbolFrom('c'); + alphabet::Symbol d = alphabet::symbolFrom('d'); + alphabet::Symbol f = alphabet::symbolFrom('f'); + + grammar::CFG grammar(S); + grammar.setTerminalAlphabet({a, b, c, d, f}); + grammar.setNonterminalAlphabet({{S, A, B}}); + grammar.setInitialSymbol(S); + + grammar.addRule(S, std::vector<alphabet::Symbol>{ A, a }); + grammar.addRule(S, std::vector<alphabet::Symbol>{ b, S }); + grammar.addRule(A, std::vector<alphabet::Symbol>{ c, A, d }); + grammar.addRule(A, std::vector<alphabet::Symbol>{ B }); + grammar.addRule(B, std::vector<alphabet::Symbol>{ f, S }); + grammar.addRule(B, std::vector<alphabet::Symbol>{ }); + + std::map<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> res = { + {{A, a}, {c, f, a}}, + {{b, S}, {b}}, + {{c, A, d}, {c}}, + {{B}, {f, string::Epsilon::EPSILON}}, + {{f, S}, {f}}, + {{}, {string::Epsilon::EPSILON}}}; + CPPUNIT_ASSERT(res == grammar::parsing::First::first(grammar)); +} + diff --git a/alib2algo/test-src/grammar/parsing/FirstTest.h b/alib2algo/test-src/grammar/parsing/FirstTest.h index 5bb36cef0f8b7bf193d35c799568ab92e6961eba..46c90bab689a5a8a9728fc00d2c7883fb6097b22 100644 --- a/alib2algo/test-src/grammar/parsing/FirstTest.h +++ b/alib2algo/test-src/grammar/parsing/FirstTest.h @@ -7,6 +7,8 @@ class FirstTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( FirstTest ); CPPUNIT_TEST( testFirst ); + CPPUNIT_TEST( testFirst2 ); + CPPUNIT_TEST( testFirst3 ); CPPUNIT_TEST_SUITE_END(); public: @@ -14,6 +16,8 @@ public: void tearDown(); void testFirst(); + void testFirst2(); + void testFirst3(); }; #endif /* FIRST_TEST_H_ */ diff --git a/alib2algo/test-src/grammar/parsing/FollowTest.cpp b/alib2algo/test-src/grammar/parsing/FollowTest.cpp index fb2c2eb95045f99581a042ab4fa70ef458fc6214..2a2d17f044795572b071109dce98089b57c028db 100644 --- a/alib2algo/test-src/grammar/parsing/FollowTest.cpp +++ b/alib2algo/test-src/grammar/parsing/FollowTest.cpp @@ -2,6 +2,7 @@ #include "grammar/parsing/Follow.h" #include "string/Epsilon.h" +#include "grammar/ContextFree/CFG.h" CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( FollowTest, "grammar" ); CPPUNIT_TEST_SUITE_REGISTRATION( FollowTest );