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