diff --git a/alib2algo/src/grammar/parsing/First.cpp b/alib2algo/src/grammar/parsing/First.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc00d75ead0c6d8251a4931b5b2bf1079f139e5f --- /dev/null +++ b/alib2algo/src/grammar/parsing/First.cpp @@ -0,0 +1,195 @@ +/* + * First.cpp + * + * Created on: 9. 6. 2015 + * Author: Tomas Pecka + */ + +#include "First.h" +#include <algorithm> +#include <string/Epsilon.h> +#include <iterator> + +#include "setunion.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) +{ + // 1. FIRST(\varepsilon) = { \varepsilon } + if(rhs.empty()) return {string::Epsilon::EPSILON}; + + // 2. FIRST(a) = { a } forall a \in T + else if(grammar.getTerminalAlphabet().find(rhs[0]) != grammar.getTerminalAlphabet().end()) + 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]]; + + // 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); + + 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"); +} + +template<class T> +std::set<std::variant<alphabet::Symbol, string::Epsilon>> First::first(const T& grammar, const std::vector<alphabet::Symbol>& rhs) +{ + /* + * + * 1. foreach A \in N: first(A) = \emptyset + * 2. foreach A \rightarrow \alpha: + * first(A) = first(A) \cup FIRST(\alpha) + * 3. repeat step 2 if at least one set first(A) has changed + * + */ + + // (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; + } + } + } + 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); + + out.second = this->first(grammar, out.first); +} + +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); + + out.second = this->first(grammar, out.first); +} + +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); +} + +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); + + out.second = this->first(grammar, out.first); +} + +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); + + out.second = this->first(grammar, out.first); +} + +void First::Visit(void*, const grammar::CSG&) const { + throw exception::AlibException("Unsupported grammar type CSG"); +} + +void First::Visit(void*, const grammar::NonContractingGrammar&) const { + throw exception::AlibException("Unsupported grammar type NonConctractingGrammar"); +} + +void First::Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar&) const { + throw exception::AlibException("Unsupported grammar type ContextPreservingUnrestrictedGrammar"); +} + +void First::Visit(void*, const grammar::UnrestrictedGrammar&) const { + throw exception::AlibException("Unsupported grammar type UnrestrictedGrammar"); +} + +const First First::FIRST; + +} /* namespace parsing */ + +} /* namespace grammar */ diff --git a/alib2algo/src/grammar/parsing/First.h b/alib2algo/src/grammar/parsing/First.h new file mode 100644 index 0000000000000000000000000000000000000000..958a0a99a41d2f863f68547d03b5ab9c61fd3904 --- /dev/null +++ b/alib2algo/src/grammar/parsing/First.h @@ -0,0 +1,61 @@ +/* + * First.h + * + * Created on: 9. 6. 2015 + * Author: Tomas Pecka + */ + +#ifndef FIRST_H_ +#define FIRST_H_ + +#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> + +namespace grammar { + +namespace parsing { + +class First : public grammar::VisitableGrammarBase::const_visitor_type { + +public: + First() {} + + template<class T> + static std::set<std::variant<alphabet::Symbol, string::Epsilon>> first(const T& grammar, const std::vector<alphabet::Symbol>& rhs); + +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; +}; + +} /* namespace parsing */ + +} /* namespace grammar */ + +#endif /* FIRST_H_ */ diff --git a/alib2algo/src/grammar/parsing/Follow.cpp b/alib2algo/src/grammar/parsing/Follow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..afd058b5f75ce537697ad97c7dec4bf9dd5550ff --- /dev/null +++ b/alib2algo/src/grammar/parsing/Follow.cpp @@ -0,0 +1,177 @@ +/* + * Follow.cpp + * + * Created on: 9. 6. 2015 + * Author: Tomas Pecka + */ + +#include "Follow.h" +#include "First.h" +#include <algorithm> +#include <string/Epsilon.h> +#include <iterator> + +#include "setunion.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()) + throw exception::AlibException("Follow: Given symbol is not nonterminal."); + + /* + * 1. Follow(S) = { \varepsilon } + * Follow(A) = {} forall A \in N, A \neq S + * 2. Forall p \in P: + * if p == X -> \alpha Y \beta + * Follow(Y) = Follow(Y) \cup (First(\beta) \setminus { \varepsilon}) + * if p == X -> \alpha Y \beta \wedge \varepsilon \in First(\beta) + * Follow(Y) = Follow(Y) \cup Follow(X) + * 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; + + 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); + + 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); + + out.second = this->follow(grammar, out.first); +} + +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); + + out.second = this->follow(grammar, out.first); +} + +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); + + out.second = this->follow(grammar, out.first); +} + +void Follow::Visit(void*, const grammar::CSG&) const { + throw exception::AlibException("Unsupported grammar type CSG"); +} + +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"); +} + +const Follow Follow::FOLLOW; + +} /* namespace parsing */ + +} /* namespace grammar */ diff --git a/alib2algo/src/grammar/parsing/Follow.h b/alib2algo/src/grammar/parsing/Follow.h new file mode 100644 index 0000000000000000000000000000000000000000..3d1e4b40bbbe91ba19c0a20e495cc23f616286e3 --- /dev/null +++ b/alib2algo/src/grammar/parsing/Follow.h @@ -0,0 +1,58 @@ +/* + * Follow.h + * + * Created on: 9. 6. 2015 + * Author: Tomas Pecka + */ + +#ifndef FOLLOW_H_ +#define FOLLOW_H_ + +#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> + +namespace grammar { + +namespace parsing { + +class Follow : public grammar::VisitableGrammarBase::const_visitor_type { + +public: + Follow() {} + + 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; +}; + +} /* namespace parsing */ + +} /* namespace grammar */ + +#endif /* FOLLOW_H_ */ diff --git a/alib2algo/src/grammar/parsing/setunion.h b/alib2algo/src/grammar/parsing/setunion.h new file mode 100644 index 0000000000000000000000000000000000000000..c69b35061aec537a9cd2a9bbc2362162c826ca27 --- /dev/null +++ b/alib2algo/src/grammar/parsing/setunion.h @@ -0,0 +1,20 @@ +#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 new file mode 100644 index 0000000000000000000000000000000000000000..ad3f5fbf29cf79c6acdb6c9b3384735ebc47dd8b --- /dev/null +++ b/alib2algo/test-src/grammar/parsing/FirstTest.cpp @@ -0,0 +1,144 @@ +#include "FirstTest.h" + +#include "grammar/parsing/First.h" +#include "string/Epsilon.h" + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( FirstTest, "grammar" ); +CPPUNIT_TEST_SUITE_REGISTRATION( FirstTest ); + +void FirstTest::setUp() { +} + +void FirstTest::tearDown() { +} + +void FirstTest::testFirst() { + { + alphabet::Symbol nE = alphabet::symbolFrom('E'); + alphabet::Symbol nT = alphabet::symbolFrom('T'); + alphabet::Symbol nF = alphabet::symbolFrom('F'); + + alphabet::Symbol tP = alphabet::symbolFrom('+'); + alphabet::Symbol tS = alphabet::symbolFrom('*'); + alphabet::Symbol tL = alphabet::symbolFrom('('); + alphabet::Symbol tR = alphabet::symbolFrom(')'); + alphabet::Symbol tA = alphabet::symbolFrom('a'); + + grammar::CFG grammar(nE); + grammar.setTerminalAlphabet(std::set<alphabet::Symbol>{tP, tS, tL, tR, tA}); + grammar.setNonterminalAlphabet(std::set<alphabet::Symbol>{nE, nT, nF}); + + std::vector<alphabet::Symbol> rhsE1({nE, tP, nT}); + std::vector<alphabet::Symbol> rhsE2({nT}); + std::vector<alphabet::Symbol> rhsT1({nT, tS, nF}); + std::vector<alphabet::Symbol> rhsT2({nF}); + std::vector<alphabet::Symbol> rhsF1({tA}); + std::vector<alphabet::Symbol> rhsF2({tL, nE, tR}); + + grammar.addRule(nE, rhsE1); + grammar.addRule(nE, rhsE2); + grammar.addRule(nT, rhsT1); + grammar.addRule(nT, rhsT2); + grammar.addRule(nF, rhsF1); + grammar.addRule(nF, rhsF2); + + // -------------------------------------------------- + std::map<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> first; + + first[rhsE1] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tA, tL}; + first[rhsE2] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tA, tL}; + first[rhsT1] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tA, tL}; + first[rhsT2] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tA, tL}; + first[rhsF1] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tA}; + first[rhsF2] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tL}; + + // -------------------------------------------------- + + std::map<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> firstAlgo; + + for(const auto& rule : grammar.getRawRules()) + for(const auto& rhs : rule.second) + firstAlgo[rhs] = grammar::parsing::First::first(grammar, rhs); + + CPPUNIT_ASSERT(first == firstAlgo); + } + + { + alphabet::Symbol nS = alphabet::symbolFrom('S'); + alphabet::Symbol nA = alphabet::symbolFrom('A'); + alphabet::Symbol nB = alphabet::symbolFrom('B'); + alphabet::Symbol nC = alphabet::symbolFrom('C'); + alphabet::Symbol nD = alphabet::symbolFrom('D'); + alphabet::Symbol nE = alphabet::symbolFrom('E'); + alphabet::Symbol nF = alphabet::symbolFrom('F'); + + alphabet::Symbol tA = alphabet::symbolFrom('a'); + alphabet::Symbol tB = alphabet::symbolFrom('b'); + alphabet::Symbol tC = alphabet::symbolFrom('c'); + alphabet::Symbol tD = alphabet::symbolFrom('d'); + alphabet::Symbol tE = alphabet::symbolFrom('e'); + + grammar::CFG grammar(nS); + grammar.setTerminalAlphabet(std::set<alphabet::Symbol>{tA, tB, tC, tD, tE}); + grammar.setNonterminalAlphabet(std::set<alphabet::Symbol>{nS, nA, nB, nC, nD, nE, nF}); + + std::vector<alphabet::Symbol> rhsS1({nB, tD, nS}); + std::vector<alphabet::Symbol> rhsS2({tD, tD, nC}); + std::vector<alphabet::Symbol> rhsS3({tC, nA}); + std::vector<alphabet::Symbol> rhsA1({tA, tE, nE}); + std::vector<alphabet::Symbol> rhsA2({tB, tB, nE}); + std::vector<alphabet::Symbol> rhsB1({tA, nF}); + std::vector<alphabet::Symbol> rhsB2({tB, tB, nD}); + std::vector<alphabet::Symbol> rhsC1({tA, nB, tD}); + std::vector<alphabet::Symbol> rhsC2({tE, nA}); + std::vector<alphabet::Symbol> rhsD1({tC, tA, nF}); + std::vector<alphabet::Symbol> rhsE1({tC, tA, tE, nE}); + std::vector<alphabet::Symbol> rhsE2({}); + std::vector<alphabet::Symbol> rhsF1({tE, nD}); + std::vector<alphabet::Symbol> rhsF2({}); + + grammar.addRule(nS, rhsS1); + grammar.addRule(nS, rhsS2); + grammar.addRule(nS, rhsS3); + grammar.addRule(nA, rhsA1); + grammar.addRule(nA, rhsA2); + grammar.addRule(nB, rhsB1); + grammar.addRule(nB, rhsB2); + grammar.addRule(nC, rhsC1); + grammar.addRule(nC, rhsC2); + grammar.addRule(nD, rhsD1); + grammar.addRule(nE, rhsE1); + grammar.addRule(nE, rhsE2); + grammar.addRule(nF, rhsF1); + grammar.addRule(nF, rhsF2); + + // -------------------------------------------------- + std::map<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> first; + + first[rhsS1] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tA, tB}; + first[rhsS2] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tD}; + first[rhsS3] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tC}; + first[rhsA1] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tA}; + first[rhsA2] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tB}; + first[rhsB1] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tA}; + first[rhsB2] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tB}; + first[rhsC1] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tA}; + first[rhsC2] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tE}; + first[rhsD1] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tC}; + first[rhsE1] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tC}; + first[rhsE2] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{string::Epsilon::EPSILON}; + first[rhsF1] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tE}; + first[rhsF2] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{string::Epsilon::EPSILON}; + + // -------------------------------------------------- + + std::map<std::vector<alphabet::Symbol>, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> firstAlgo; + + for(const auto& rule : grammar.getRawRules()) + for(const auto& rhs : rule.second) + firstAlgo[rhs] = grammar::parsing::First::first(grammar, rhs); + + CPPUNIT_ASSERT(first == firstAlgo); + } +} + diff --git a/alib2algo/test-src/grammar/parsing/FirstTest.h b/alib2algo/test-src/grammar/parsing/FirstTest.h new file mode 100644 index 0000000000000000000000000000000000000000..5bb36cef0f8b7bf193d35c799568ab92e6961eba --- /dev/null +++ b/alib2algo/test-src/grammar/parsing/FirstTest.h @@ -0,0 +1,19 @@ +#ifndef FIRST_TEST_H_ +#define FIRST_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class FirstTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( FirstTest ); + CPPUNIT_TEST( testFirst ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testFirst(); +}; + +#endif /* FIRST_TEST_H_ */ diff --git a/alib2algo/test-src/grammar/parsing/FollowTest.cpp b/alib2algo/test-src/grammar/parsing/FollowTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb2c2eb95045f99581a042ab4fa70ef458fc6214 --- /dev/null +++ b/alib2algo/test-src/grammar/parsing/FollowTest.cpp @@ -0,0 +1,137 @@ +#include "FollowTest.h" + +#include "grammar/parsing/Follow.h" +#include "string/Epsilon.h" + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( FollowTest, "grammar" ); +CPPUNIT_TEST_SUITE_REGISTRATION( FollowTest ); + +void FollowTest::setUp() { +} + +void FollowTest::tearDown() { +} + +void FollowTest::testFollow() { + { + alphabet::Symbol nE = alphabet::symbolFrom('E'); + alphabet::Symbol nT = alphabet::symbolFrom('T'); + alphabet::Symbol nF = alphabet::symbolFrom('F'); + + alphabet::Symbol tP = alphabet::symbolFrom('+'); + alphabet::Symbol tS = alphabet::symbolFrom('*'); + alphabet::Symbol tL = alphabet::symbolFrom('('); + alphabet::Symbol tR = alphabet::symbolFrom(')'); + alphabet::Symbol tA = alphabet::symbolFrom('a'); + + grammar::CFG grammar(nE); + grammar.setTerminalAlphabet(std::set<alphabet::Symbol>{tP, tS, tL, tR, tA}); + grammar.setNonterminalAlphabet(std::set<alphabet::Symbol>{nE, nT, nF}); + + std::vector<alphabet::Symbol> rhsE1({nE, tP, nT}); + std::vector<alphabet::Symbol> rhsE2({nT}); + std::vector<alphabet::Symbol> rhsT1({nT, tS, nF}); + std::vector<alphabet::Symbol> rhsT2({nF}); + std::vector<alphabet::Symbol> rhsF1({tA}); + std::vector<alphabet::Symbol> rhsF2({tL, nE, tR}); + + grammar.addRule(nE, rhsE1); + grammar.addRule(nE, rhsE2); + grammar.addRule(nT, rhsT1); + grammar.addRule(nT, rhsT2); + grammar.addRule(nF, rhsF1); + grammar.addRule(nF, rhsF2); + + // -------------------------------------------------- + std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> follow; + + follow[nE] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{string::Epsilon::EPSILON, tP, tR}; + follow[nT] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{string::Epsilon::EPSILON, tP, tR, tS}; + follow[nF] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{string::Epsilon::EPSILON, tP, tR, tS}; + + // -------------------------------------------------- + + std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> followAlgo; + + for(const auto& nt : grammar.getNonterminalAlphabet()) + followAlgo[nt] = grammar::parsing::Follow::follow(grammar, nt); + + // std::cout << follow << std::endl; + // std::cout << followAlgo << std::endl; + CPPUNIT_ASSERT(follow == followAlgo); + } + + { + alphabet::Symbol nS = alphabet::symbolFrom('S'); + alphabet::Symbol nA = alphabet::symbolFrom('A'); + alphabet::Symbol nB = alphabet::symbolFrom('B'); + alphabet::Symbol nC = alphabet::symbolFrom('C'); + alphabet::Symbol nD = alphabet::symbolFrom('D'); + alphabet::Symbol nE = alphabet::symbolFrom('E'); + alphabet::Symbol nF = alphabet::symbolFrom('F'); + + alphabet::Symbol tA = alphabet::symbolFrom('a'); + alphabet::Symbol tB = alphabet::symbolFrom('b'); + alphabet::Symbol tC = alphabet::symbolFrom('c'); + alphabet::Symbol tD = alphabet::symbolFrom('d'); + alphabet::Symbol tE = alphabet::symbolFrom('e'); + + grammar::CFG grammar(nS); + grammar.setTerminalAlphabet(std::set<alphabet::Symbol>{tA, tB, tC, tD, tE}); + grammar.setNonterminalAlphabet(std::set<alphabet::Symbol>{nS, nA, nB, nC, nD, nE, nF}); + + std::vector<alphabet::Symbol> rhsS1({nB, tD, nS}); + std::vector<alphabet::Symbol> rhsS2({tD, tD, nC}); + std::vector<alphabet::Symbol> rhsS3({tC, nA}); + std::vector<alphabet::Symbol> rhsA1({tA, tE, nE}); + std::vector<alphabet::Symbol> rhsA2({tB, tB, nE}); + std::vector<alphabet::Symbol> rhsB1({tA, nF}); + std::vector<alphabet::Symbol> rhsB2({tB, tB, nD}); + std::vector<alphabet::Symbol> rhsC1({tA, nB, tD}); + std::vector<alphabet::Symbol> rhsC2({tE, nA}); + std::vector<alphabet::Symbol> rhsD1({tC, tA, nF}); + std::vector<alphabet::Symbol> rhsE1({tC, tA, tE, nE}); + std::vector<alphabet::Symbol> rhsE2({}); + std::vector<alphabet::Symbol> rhsF1({tE, nD}); + std::vector<alphabet::Symbol> rhsF2({}); + + grammar.addRule(nS, rhsS1); + grammar.addRule(nS, rhsS2); + grammar.addRule(nS, rhsS3); + grammar.addRule(nA, rhsA1); + grammar.addRule(nA, rhsA2); + grammar.addRule(nB, rhsB1); + grammar.addRule(nB, rhsB2); + grammar.addRule(nC, rhsC1); + grammar.addRule(nC, rhsC2); + grammar.addRule(nD, rhsD1); + grammar.addRule(nE, rhsE1); + grammar.addRule(nE, rhsE2); + grammar.addRule(nF, rhsF1); + grammar.addRule(nF, rhsF2); + + // -------------------------------------------------- + std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> follow; + + follow[nS] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{string::Epsilon::EPSILON}; + follow[nA] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{string::Epsilon::EPSILON}; + follow[nB] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tD}; + follow[nC] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{string::Epsilon::EPSILON}; + follow[nD] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tD}; + follow[nE] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{string::Epsilon::EPSILON}; + follow[nF] = std::set<std::variant<alphabet::Symbol, string::Epsilon>>{tD}; + + // -------------------------------------------------- + + std::map<alphabet::Symbol, std::set<std::variant<alphabet::Symbol, string::Epsilon>>> followAlgo; + + for(const auto& nt : grammar.getNonterminalAlphabet()) + followAlgo[nt] = grammar::parsing::Follow::follow(grammar, nt); + + // std::cout << follow << std::endl; + // std::cout << followAlgo << std::endl; + CPPUNIT_ASSERT(follow == followAlgo); + + } +} + diff --git a/alib2algo/test-src/grammar/parsing/FollowTest.h b/alib2algo/test-src/grammar/parsing/FollowTest.h new file mode 100644 index 0000000000000000000000000000000000000000..aa992d4afae4a9a7a75ab0c5f367373887830804 --- /dev/null +++ b/alib2algo/test-src/grammar/parsing/FollowTest.h @@ -0,0 +1,19 @@ +#ifndef FOLLOW_TEST_H_ +#define FOLLOW_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class FollowTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( FollowTest ); + CPPUNIT_TEST( testFollow ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testFollow(); +}; + +#endif /* FOLLOW_TEST_H_ */