diff --git a/alib2/src/grammar/GrammarToXMLComposer.h b/alib2/src/grammar/GrammarToXMLComposer.h index 4cf67898b5c0a447ccd83153df17769ef22bf491..5cb9860203bae5feeea1327af91c2719f958622e 100644 --- a/alib2/src/grammar/GrammarToXMLComposer.h +++ b/alib2/src/grammar/GrammarToXMLComposer.h @@ -13,9 +13,9 @@ #include "Grammar.h" #include "UnknownGrammar.h" #include "Regular/LeftLG.h" -class LeftRG; +#include "Regular/LeftRG.h" #include "Regular/RightLG.h" -class RightRG; +#include "Regular/RightRG.h" #include "ContextFree/LG.h" #include "ContextFree/CFG.h" #include "ContextFree/EpsilonFreeCFG.h" diff --git a/alib2/src/grammar/Regular/LeftRG.cpp b/alib2/src/grammar/Regular/LeftRG.cpp new file mode 100644 index 0000000000000000000000000000000000000000..210f4d46736515bb3897d4382e3e10a13223a17d --- /dev/null +++ b/alib2/src/grammar/Regular/LeftRG.cpp @@ -0,0 +1,132 @@ +/* + * LeftRG.cpp + * + * Created on: Nov 17, 2013 + * Author: Jan Travnicek + */ + +#include "LeftRG.h" +#include "../../std/map.hpp" +#include "../GrammarException.h" +#include <algorithm> + +#include "../../alphabet/Symbol.h" + +namespace grammar { + +LeftRG::LeftRG(const alphabet::Symbol& initialSymbol) : TerminalNonterminalAlphabetInitialSymbol(initialSymbol), generatesEpsilon(false) { + +} + +LeftRG::LeftRG(const std::set<alphabet::Symbol>& nonterminalAlphabet, const std::set<alphabet::Symbol>& terminalAlphabet, const alphabet::Symbol& initialSymbol) : TerminalNonterminalAlphabetInitialSymbol(initialSymbol), generatesEpsilon(false) { + setNonterminalAlphabet(nonterminalAlphabet); + setTerminalAlphabet(terminalAlphabet); +} + +GrammarBase* LeftRG::clone() const { + return new LeftRG(*this); +} + +GrammarBase* LeftRG::plunder() && { + return new LeftRG(std::move(*this)); +} + +bool LeftRG::removeTerminalSymbol(const alphabet::Symbol& symbol) { + for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : rules) { + if(rule.first == symbol) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + + for(const std::vector<alphabet::Symbol>& rhs : rule.second) + if(std::find(rhs.begin(), rhs.end(), symbol) != rhs.end()) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + } + + return terminalAlphabet.erase(symbol); +} + +bool LeftRG::removeNonterminalSymbol(const alphabet::Symbol& symbol) { + for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : rules) { + if(rule.first == symbol) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + + for(const std::vector<alphabet::Symbol>& rhs : rule.second) + if(std::find(rhs.begin(), rhs.end(), symbol) != rhs.end()) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + } + + if(initialSymbol == symbol) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is initial symbol."); + + + return nonterminalAlphabet.erase(symbol); +} + +bool LeftRG::addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + int rSize = rightHandSide.size(); + + if(leftHandSide == initialSymbol && rSize == 0) { + for(const auto& rule : rules) { + for(const auto& ruleRHS : rule.second) { + if(any_of(ruleRHS.begin(), ruleRHS.end(), [&](const alphabet::Symbol& symbol) { return initialSymbol == symbol; })) { + throw GrammarException("Initial symbol " + (std::string) initialSymbol + "used on right hand side of already existing rule"); + } + } + } + + generatesEpsilon = true; + return rules[leftHandSide].insert(rightHandSide).second; + } else if(rSize == 1) { + if(!nonterminalAlphabet.count(leftHandSide)) + throw GrammarException("Rule must rewrite nonterminal symbol"); + + if(!terminalAlphabet.count(rightHandSide[0])) + throw GrammarException("Rule must rewrite to terminal symbol"); + + return rules[leftHandSide].insert(rightHandSide).second; + } else if(rSize == 2) { + if(!nonterminalAlphabet.count(leftHandSide)) + throw GrammarException("Rule must rewrite nonterminal symbol"); + + if(!nonterminalAlphabet.count(rightHandSide[0])) + throw GrammarException("Rule must rewrite to nonterminal symbol followed by terminal symbol"); + + if(!terminalAlphabet.count(rightHandSide[1])) + throw GrammarException("Rule must rewrite to nonterminal symbol followed by terminal symbol"); + + return rules[leftHandSide].insert(rightHandSide).second; + } else { + throw GrammarException("Invalid size of right hand side of the rule"); + } +} + +const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> LeftRG::getRules() const { + return rules; +} + +bool LeftRG::removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + int rSize = rightHandSide.size(); + + if(leftHandSide == initialSymbol && rSize == 0) { + generatesEpsilon = false; + } + return rules[leftHandSide].erase(rightHandSide); +} + +bool LeftRG::operator==(const GrammarBase& other) const { + return other == *this; +} + +bool LeftRG::operator==(const LeftRG& other) const { + return this->nonterminalAlphabet == other.nonterminalAlphabet && this->terminalAlphabet == other.terminalAlphabet && this->initialSymbol == other.initialSymbol && this->rules == other.rules; +} + +void LeftRG::operator>>(std::ostream& out) const { + out << "(LeftRG" + << "nonterminalAlphabet = " << nonterminalAlphabet + << "terminalAlphabet = " << terminalAlphabet + << "initialSymbol = " << initialSymbol + << "rules = " << rules + << ")"; +} + +} /* namespace grammar */ diff --git a/alib2/src/grammar/Regular/LeftRG.h b/alib2/src/grammar/Regular/LeftRG.h new file mode 100644 index 0000000000000000000000000000000000000000..1a1591d5ea1cd4e85c3c2b20d35f33f286029219 --- /dev/null +++ b/alib2/src/grammar/Regular/LeftRG.h @@ -0,0 +1,51 @@ +/* + * LeftRG.h + * + * Created on: Nov 17, 2013 + * Author: Jan Travnicek + */ + +#ifndef LEFT_RG_H_ +#define LEFT_RG_H_ + +#include "../GrammarBase.h" +#include <map> +#include "../common/TerminalNonterminalAlphabetInitialSymbol.h" + +namespace grammar { + +/** + * Context free grammar in chomsky normal form. Type 2 in Chomsky hierarchy. Produces context free languages. + */ +class LeftRG : public std::element<LeftRG, GrammarBase>, public TerminalNonterminalAlphabetInitialSymbol { + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> rules; + bool generatesEpsilon; +public: + LeftRG(const alphabet::Symbol& initialSymbol); + + LeftRG(const std::set<alphabet::Symbol>& nonTerminalSymbols, const std::set<alphabet::Symbol>& terminalSymbols, const alphabet::Symbol& initialSymbol); + + virtual GrammarBase* clone() const; + + virtual GrammarBase* plunder() &&; + + bool addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + + const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRules() const; + + bool removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + + bool removeTerminalSymbol(const alphabet::Symbol& symbol); + + bool removeNonterminalSymbol(const alphabet::Symbol& symbol); + + virtual bool operator==(const GrammarBase& other) const; + + virtual bool operator==(const LeftRG& other) const; + + virtual void operator>>(std::ostream& os) const; +}; + +} /* namespace grammar */ + +#endif /* LEFT_RG_H_ */ diff --git a/alib2/src/grammar/Regular/RightRG.cpp b/alib2/src/grammar/Regular/RightRG.cpp new file mode 100644 index 0000000000000000000000000000000000000000..825039e19f774107bc1f973c8d167437196e8747 --- /dev/null +++ b/alib2/src/grammar/Regular/RightRG.cpp @@ -0,0 +1,132 @@ +/* + * RightRG.cpp + * + * Created on: Nov 17, 2013 + * Author: Jan Travnicek + */ + +#include "RightRG.h" +#include "../../std/map.hpp" +#include "../GrammarException.h" +#include <algorithm> + +#include "../../alphabet/Symbol.h" + +namespace grammar { + +RightRG::RightRG(const alphabet::Symbol& initialSymbol) : TerminalNonterminalAlphabetInitialSymbol(initialSymbol), generatesEpsilon(false) { + +} + +RightRG::RightRG(const std::set<alphabet::Symbol>& nonterminalAlphabet, const std::set<alphabet::Symbol>& terminalAlphabet, const alphabet::Symbol& initialSymbol) : TerminalNonterminalAlphabetInitialSymbol(initialSymbol), generatesEpsilon(false) { + setNonterminalAlphabet(nonterminalAlphabet); + setTerminalAlphabet(terminalAlphabet); +} + +GrammarBase* RightRG::clone() const { + return new RightRG(*this); +} + +GrammarBase* RightRG::plunder() && { + return new RightRG(std::move(*this)); +} + +bool RightRG::removeTerminalSymbol(const alphabet::Symbol& symbol) { + for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : rules) { + if(rule.first == symbol) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + + for(const std::vector<alphabet::Symbol>& rhs : rule.second) + if(std::find(rhs.begin(), rhs.end(), symbol) != rhs.end()) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + } + + return terminalAlphabet.erase(symbol); +} + +bool RightRG::removeNonterminalSymbol(const alphabet::Symbol& symbol) { + for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : rules) { + if(rule.first == symbol) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + + for(const std::vector<alphabet::Symbol>& rhs : rule.second) + if(std::find(rhs.begin(), rhs.end(), symbol) != rhs.end()) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + } + + if(initialSymbol == symbol) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is initial symbol."); + + + return nonterminalAlphabet.erase(symbol); +} + +bool RightRG::addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + int rSize = rightHandSide.size(); + + if(leftHandSide == initialSymbol && rSize == 0) { + for(const auto& rule : rules) { + for(const auto& ruleRHS : rule.second) { + if(any_of(ruleRHS.begin(), ruleRHS.end(), [&](const alphabet::Symbol& symbol) { return initialSymbol == symbol; })) { + throw GrammarException("Initial symbol " + (std::string) initialSymbol + "used on right hand side of already existing rule"); + } + } + } + + generatesEpsilon = true; + return rules[leftHandSide].insert(rightHandSide).second; + } else if(rSize == 1) { + if(!nonterminalAlphabet.count(leftHandSide)) + throw GrammarException("Rule must rewrite nonterminal symbol"); + + if(!terminalAlphabet.count(rightHandSide[0])) + throw GrammarException("Rule must rewrite to terminal symbol"); + + return rules[leftHandSide].insert(rightHandSide).second; + } else if(rSize == 2) { + if(!nonterminalAlphabet.count(leftHandSide)) + throw GrammarException("Rule must rewrite nonterminal symbol"); + + if(!terminalAlphabet.count(rightHandSide[0])) + throw GrammarException("Rule must rewrite to terminal symbol followed by nonterminal symbol"); + + if(!nonterminalAlphabet.count(rightHandSide[1])) + throw GrammarException("Rule must rewrite to terminal symbol followed by nonterminal symbol"); + + return rules[leftHandSide].insert(rightHandSide).second; + } else { + throw GrammarException("Invalid size of right hand side of the rule"); + } +} + +const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> RightRG::getRules() const { + return rules; +} + +bool RightRG::removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + int rSize = rightHandSide.size(); + + if(leftHandSide == initialSymbol && rSize == 0) { + generatesEpsilon = false; + } + return rules[leftHandSide].erase(rightHandSide); +} + +bool RightRG::operator==(const GrammarBase& other) const { + return other == *this; +} + +bool RightRG::operator==(const RightRG& other) const { + return this->nonterminalAlphabet == other.nonterminalAlphabet && this->terminalAlphabet == other.terminalAlphabet && this->initialSymbol == other.initialSymbol && this->rules == other.rules; +} + +void RightRG::operator>>(std::ostream& out) const { + out << "(RightRG" + << "nonterminalAlphabet = " << nonterminalAlphabet + << "terminalAlphabet = " << terminalAlphabet + << "initialSymbol = " << initialSymbol + << "rules = " << rules + << ")"; +} + +} /* namespace grammar */ diff --git a/alib2/src/grammar/Regular/RightRG.h b/alib2/src/grammar/Regular/RightRG.h new file mode 100644 index 0000000000000000000000000000000000000000..73648b49fb4402f71bf1b5c2a1e8c116642bac70 --- /dev/null +++ b/alib2/src/grammar/Regular/RightRG.h @@ -0,0 +1,51 @@ +/* + * RightRG.h + * + * Created on: Nov 17, 2013 + * Author: Jan Travnicek + */ + +#ifndef RIGHT_RG_H_ +#define RIGHT_RG_H_ + +#include "../GrammarBase.h" +#include <map> +#include "../common/TerminalNonterminalAlphabetInitialSymbol.h" + +namespace grammar { + +/** + * Context free grammar in chomsky normal form. Type 2 in Chomsky hierarchy. Produces context free languages. + */ +class RightRG : public std::element<RightRG, GrammarBase>, public TerminalNonterminalAlphabetInitialSymbol { + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> rules; + bool generatesEpsilon; +public: + RightRG(const alphabet::Symbol& initialSymbol); + + RightRG(const std::set<alphabet::Symbol>& nonTerminalSymbols, const std::set<alphabet::Symbol>& terminalSymbols, const alphabet::Symbol& initialSymbol); + + virtual GrammarBase* clone() const; + + virtual GrammarBase* plunder() &&; + + bool addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + + const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRules() const; + + bool removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + + bool removeTerminalSymbol(const alphabet::Symbol& symbol); + + bool removeNonterminalSymbol(const alphabet::Symbol& symbol); + + virtual bool operator==(const GrammarBase& other) const; + + virtual bool operator==(const RightRG& other) const; + + virtual void operator>>(std::ostream& os) const; +}; + +} /* namespace grammar */ + +#endif /* RIGHT_RG_H_ */