From f47e73a5e9807d32f23a45e4af50599b0f24cbc9 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Sat, 12 Jul 2014 20:12:34 +0200 Subject: [PATCH] CFG and EpsilonFreeCFG --- alib2/src/grammar/ContextFree/CFG.cpp | 100 ++++++++++++++ alib2/src/grammar/ContextFree/CFG.h | 51 ++++++++ .../grammar/ContextFree/EpsilonFreeCFG.cpp | 123 ++++++++++++++++++ .../src/grammar/ContextFree/EpsilonFreeCFG.h | 51 ++++++++ alib2/src/grammar/ContextSensitive/CSG.h | 2 +- .../ContextSensitive/NonContractingGrammar.h | 2 +- alib2/src/grammar/GrammarToXMLComposer.h | 4 +- .../ContextPreservingUnrestrictedGrammar.h | 2 +- 8 files changed, 330 insertions(+), 5 deletions(-) create mode 100644 alib2/src/grammar/ContextFree/CFG.cpp create mode 100644 alib2/src/grammar/ContextFree/CFG.h create mode 100644 alib2/src/grammar/ContextFree/EpsilonFreeCFG.cpp create mode 100644 alib2/src/grammar/ContextFree/EpsilonFreeCFG.h diff --git a/alib2/src/grammar/ContextFree/CFG.cpp b/alib2/src/grammar/ContextFree/CFG.cpp new file mode 100644 index 0000000000..92a7bff275 --- /dev/null +++ b/alib2/src/grammar/ContextFree/CFG.cpp @@ -0,0 +1,100 @@ +/* + * CFG.cpp + * + * Created on: Nov 17, 2013 + * Author: Jan Travnicek + */ + +#include "CFG.h" +#include "../../std/map.hpp" +#include "../GrammarException.h" +#include <algorithm> + +#include "../../alphabet/Symbol.h" + +namespace grammar { + +CFG::CFG(const alphabet::Symbol& initialSymbol) : TerminalNonterminalAlphabetInitialSymbol(initialSymbol), generatesEpsilon(false) { + +} + +CFG::CFG(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* CFG::clone() const { + return new CFG(*this); +} + +GrammarBase* CFG::plunder() && { + return new CFG(std::move(*this)); +} + +bool CFG::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 CFG::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 CFG::addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(!nonterminalAlphabet.count(leftHandSide)) + throw GrammarException("Rule must rewrite nonterminal symbol"); + + for(const alphabet::Symbol& symbol : rightHandSide) + if(terminalAlphabet.find(symbol) == terminalAlphabet.end() && nonterminalAlphabet.find(symbol) == nonterminalAlphabet.end()) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is not neither terminal nor nonterminal symbol"); + + return rules[leftHandSide].insert(rightHandSide).second; +} + +const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> CFG::getRules() const { + return rules; +} + +bool CFG::removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + return rules[leftHandSide].erase(rightHandSide); +} + +bool CFG::operator==(const GrammarBase& other) const { + return other == *this; +} + +bool CFG::operator==(const CFG& other) const { + return this->nonterminalAlphabet == other.nonterminalAlphabet && this->terminalAlphabet == other.terminalAlphabet && this->initialSymbol == other.initialSymbol && this->rules == other.rules; +} + +void CFG::operator>>(std::ostream& out) const { + out << "(CFG" + << "nonterminalAlphabet = " << nonterminalAlphabet + << "terminalAlphabet = " << terminalAlphabet + << "initialSymbol = " << initialSymbol + << "rules = " << rules + << ")"; +} + +} /* namespace grammar */ diff --git a/alib2/src/grammar/ContextFree/CFG.h b/alib2/src/grammar/ContextFree/CFG.h new file mode 100644 index 0000000000..0ddc621ed1 --- /dev/null +++ b/alib2/src/grammar/ContextFree/CFG.h @@ -0,0 +1,51 @@ +/* + * CFG.h + * + * Created on: Nov 17, 2013 + * Author: Jan Travnicek + */ + +#ifndef CFG_H_ +#define CFG_H_ + +#include "../GrammarBase.h" +#include <map> +#include "../common/TerminalNonterminalAlphabetInitialSymbol.h" + +namespace grammar { + +/** + * Context free grammar. Type 2 in Chomsky hierarchy. Produces context free language. + */ +class CFG : public std::element<CFG, GrammarBase>, public TerminalNonterminalAlphabetInitialSymbol { + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> rules; + bool generatesEpsilon; +public: + CFG(const alphabet::Symbol& initialSymbol); + + CFG(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 CFG& other) const; + + virtual void operator>>(std::ostream& os) const; +}; + +} /* namespace grammar */ + +#endif /* CFG_H_ */ diff --git a/alib2/src/grammar/ContextFree/EpsilonFreeCFG.cpp b/alib2/src/grammar/ContextFree/EpsilonFreeCFG.cpp new file mode 100644 index 0000000000..cccf6eca7c --- /dev/null +++ b/alib2/src/grammar/ContextFree/EpsilonFreeCFG.cpp @@ -0,0 +1,123 @@ +/* + * EpsilonFreeCFG.cpp + * + * Created on: Nov 17, 2013 + * Author: Jan Travnicek + */ + +#include "EpsilonFreeCFG.h" +#include "../../std/map.hpp" +#include "../GrammarException.h" +#include <algorithm> + +#include "../../alphabet/Symbol.h" + +namespace grammar { + +EpsilonFreeCFG::EpsilonFreeCFG(const alphabet::Symbol& initialSymbol) : TerminalNonterminalAlphabetInitialSymbol(initialSymbol), generatesEpsilon(false) { + +} + +EpsilonFreeCFG::EpsilonFreeCFG(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* EpsilonFreeCFG::clone() const { + return new EpsilonFreeCFG(*this); +} + +GrammarBase* EpsilonFreeCFG::plunder() && { + return new EpsilonFreeCFG(std::move(*this)); +} + +bool EpsilonFreeCFG::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 EpsilonFreeCFG::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 EpsilonFreeCFG::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(!nonterminalAlphabet.count(leftHandSide)) + throw GrammarException("Rule must rewrite nonterminal symbol"); + + for(const alphabet::Symbol& symbol : rightHandSide) { + if(terminalAlphabet.find(symbol) == terminalAlphabet.end() && nonterminalAlphabet.find(symbol) == nonterminalAlphabet.end()) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is not neither terminal nor nonterminal symbol"); + if(generatesEpsilon && symbol == initialSymbol) + throw GrammarException("Initial symbol is already allowed to be rewritten to epsilon"); + } + + return rules[leftHandSide].insert(rightHandSide).second; + } +} + +const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> EpsilonFreeCFG::getRules() const { + return rules; +} + +bool EpsilonFreeCFG::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 EpsilonFreeCFG::operator==(const GrammarBase& other) const { + return other == *this; +} + +bool EpsilonFreeCFG::operator==(const EpsilonFreeCFG& other) const { + return this->nonterminalAlphabet == other.nonterminalAlphabet && this->terminalAlphabet == other.terminalAlphabet && this->initialSymbol == other.initialSymbol && this->rules == other.rules; +} + +void EpsilonFreeCFG::operator>>(std::ostream& out) const { + out << "(EpsilonFreeCFG" + << "nonterminalAlphabet = " << nonterminalAlphabet + << "terminalAlphabet = " << terminalAlphabet + << "initialSymbol = " << initialSymbol + << "rules = " << rules + << ")"; +} + +} /* namespace grammar */ diff --git a/alib2/src/grammar/ContextFree/EpsilonFreeCFG.h b/alib2/src/grammar/ContextFree/EpsilonFreeCFG.h new file mode 100644 index 0000000000..1af9c54463 --- /dev/null +++ b/alib2/src/grammar/ContextFree/EpsilonFreeCFG.h @@ -0,0 +1,51 @@ +/* + * EpsilonFreeCFG.h + * + * Created on: Nov 17, 2013 + * Author: Jan Travnicek + */ + +#ifndef EPSILON_FREE_CFG_H_ +#define EPSILON_FREE_CFG_H_ + +#include "../GrammarBase.h" +#include <map> +#include "../common/TerminalNonterminalAlphabetInitialSymbol.h" + +namespace grammar { + +/** + * Epsilon free context free grammar. Type 2 in Chomsky hierarchy. Produces context free languages. + */ +class EpsilonFreeCFG : public std::element<EpsilonFreeCFG, GrammarBase>, public TerminalNonterminalAlphabetInitialSymbol { + std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> rules; + bool generatesEpsilon; +public: + EpsilonFreeCFG(const alphabet::Symbol& initialSymbol); + + EpsilonFreeCFG(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 EpsilonFreeCFG& other) const; + + virtual void operator>>(std::ostream& os) const; +}; + +} /* namespace grammar */ + +#endif /* EPSILON_FREE_CFG_H_ */ diff --git a/alib2/src/grammar/ContextSensitive/CSG.h b/alib2/src/grammar/ContextSensitive/CSG.h index 1617f7ed77..88f3f3ed98 100644 --- a/alib2/src/grammar/ContextSensitive/CSG.h +++ b/alib2/src/grammar/ContextSensitive/CSG.h @@ -15,7 +15,7 @@ namespace grammar { /** - * UnrestrictedGrammar grammar. Type 0 in Chomsky hierarchy. Produces recursively enumerable language. + * Context sensitive grammar. Type 1 in Chomsky hierarchy. Produces context sensitive language. */ class CSG : public std::element<CSG, GrammarBase>, public TerminalNonterminalAlphabetInitialSymbol { std::map<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>> rules; diff --git a/alib2/src/grammar/ContextSensitive/NonContractingGrammar.h b/alib2/src/grammar/ContextSensitive/NonContractingGrammar.h index 7cf45360ae..9ecb4ef3b7 100644 --- a/alib2/src/grammar/ContextSensitive/NonContractingGrammar.h +++ b/alib2/src/grammar/ContextSensitive/NonContractingGrammar.h @@ -15,7 +15,7 @@ namespace grammar { /** - * Unrestricted grammar. Type 0 in Chomsky hierarchy. Produces recursively enumerable language. + * Non contracting grammar. Type 1 in Chomsky hierarchy. Produces context sensitive language. */ class NonContractingGrammar : public std::element<NonContractingGrammar, GrammarBase>, public TerminalNonterminalAlphabetInitialSymbol { std::map<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>> rules; diff --git a/alib2/src/grammar/GrammarToXMLComposer.h b/alib2/src/grammar/GrammarToXMLComposer.h index 3c03188448..f582b91864 100644 --- a/alib2/src/grammar/GrammarToXMLComposer.h +++ b/alib2/src/grammar/GrammarToXMLComposer.h @@ -17,8 +17,8 @@ class LeftRG; class RightLG; class RightRG; class LG; -class CFG; -class EpsilonFreeCFG; +#include "ContextFree/CFG.h" +#include "ContextFree/EpsilonFreeCFG.h" class CNF; class GNF; #include "ContextSensitive/CSG.h" diff --git a/alib2/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.h b/alib2/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.h index 1317aacf62..c95593ad65 100644 --- a/alib2/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.h +++ b/alib2/src/grammar/Unrestricted/ContextPreservingUnrestrictedGrammar.h @@ -15,7 +15,7 @@ namespace grammar { /** - * UnrestrictedGrammar grammar. Type 0 in Chomsky hierarchy. Produces recursively enumerable language. + * Context preserving unrestricted grammar. Type 0 in Chomsky hierarchy. Produces recursively enumerable language. */ class ContextPreservingUnrestrictedGrammar : public std::element<ContextPreservingUnrestrictedGrammar, GrammarBase>, public TerminalNonterminalAlphabetInitialSymbol { std::map<std::vector<alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>> rules; -- GitLab