From 8635c06a169acdcebbd29bc6c615262bc5a6c73d Mon Sep 17 00:00:00 2001
From: Martin Zak <zakmart1@fit.cvut.cz>
Date: Sun, 17 Nov 2013 17:06:41 +0100
Subject: [PATCH] Grammar refactoring

---
 alib/src/grammar/Grammar.cpp                  | 28 +++++-------
 alib/src/grammar/Grammar.h                    |  6 +--
 alib/src/grammar/RightRegularGrammar.cpp      | 45 +++++++------------
 alib/src/grammar/RightRegularGrammar.h        |  4 +-
 alib/src/grammar/UnknownGrammar.cpp           | 19 +++++---
 alib/src/grammar/UnknownGrammar.h             |  4 +-
 .../grammar/{regular.xml => rightRegular.xml} | 12 +++++
 7 files changed, 58 insertions(+), 60 deletions(-)
 rename examples/grammar/{regular.xml => rightRegular.xml} (68%)

diff --git a/alib/src/grammar/Grammar.cpp b/alib/src/grammar/Grammar.cpp
index 4b02480f47..f76c90ce1c 100644
--- a/alib/src/grammar/Grammar.cpp
+++ b/alib/src/grammar/Grammar.cpp
@@ -14,24 +14,6 @@ namespace grammar {
 using namespace std;
 using namespace alphabet;
 
-bool Grammar::usesExistingSymbols(const Rule& rule) const{
-	const list<Symbol>& leftSide = rule.getLeftSide();
-	for(list<Symbol>::const_iterator left = leftSide.begin(); left != leftSide.end(); left ++) {
-		if(terminalSymbols.find(*left) == terminalSymbols.end() && nonTerminalSymbols.find(*left) == nonTerminalSymbols.end()) {
-			return false;
-		}
-	}
-
-	const list<Symbol>& rightSide = rule.getRightSide();
-	for(list<Symbol>::const_iterator right = rightSide.begin(); right != rightSide.end(); right++) {
-		if(terminalSymbols.find(*right) == terminalSymbols.end() && nonTerminalSymbols.find(*right) == nonTerminalSymbols.end()) {
-			return false;
-		}
-	}
-
-	return true;
-}
-
 Grammar::~Grammar() {
 }
 
@@ -109,6 +91,16 @@ void Grammar::setStartSymbol(const Symbol& symbol) {
 	startSymbol = symbol;
 }
 
+void Grammar::addRule(const Rule& rule) {
+	if (!isValidRule(rule)) {
+		throw GrammarException("Rule is not valid for this grammar.");
+	}
+
+	if (!rules.insert(rule).second) {
+		throw GrammarException("Rule already exists.");
+	}
+}
+
 void Grammar::toXML(ostream& out) const {
 	GrammarPrinter::toXML(*this, out);
 }
diff --git a/alib/src/grammar/Grammar.h b/alib/src/grammar/Grammar.h
index a16c91bce0..33fbe2e64f 100644
--- a/alib/src/grammar/Grammar.h
+++ b/alib/src/grammar/Grammar.h
@@ -26,7 +26,7 @@ protected:
 	set<Rule> rules;
 	Symbol startSymbol;
 
-	bool usesExistingSymbols(const Rule& rule) const;
+	virtual bool isValidRule(const Rule& rule) const = 0;
 public:
 	virtual ~Grammar();
 
@@ -38,14 +38,14 @@ public:
 	void removeNonTerminalSymbol(const Symbol& symbol);
 	const set<Symbol>& getNonTerminalSymbols() const;
 
-	virtual void addRule(const Rule& rule) = 0;
+	void addRule(const Rule& rule);
 	void removeRule(const Rule& rule);
 	const set<Rule>& getRules() const;
 
 	const Symbol& getStartSymbol() const;
 	void setStartSymbol(const Symbol& symbol);
 
-	virtual void toXML(ostream& out) const;
+	void toXML(ostream& out) const;
 };
 
 } /* namespace grammar */
diff --git a/alib/src/grammar/RightRegularGrammar.cpp b/alib/src/grammar/RightRegularGrammar.cpp
index 2f7b4c5c89..fb552d648c 100644
--- a/alib/src/grammar/RightRegularGrammar.cpp
+++ b/alib/src/grammar/RightRegularGrammar.cpp
@@ -11,18 +11,8 @@
 
 namespace grammar {
 
-void RightRegularGrammar::addRule(const Rule& rule) {
-	if (!isValidRule(rule)) {
-		throw GrammarException("Not a right regular grammar rule.");
-	}
-
-	if (!rules.insert(rule).second) {
-		throw GrammarException("Rule already exists.");
-	}
-}
-
 bool RightRegularGrammar::isValidRule(const Rule& rule) const {
-	return usesExistingSymbols(rule) && checkLeftSide(rule.getLeftSide()) && checkRightSide(rule.getRightSide());
+	return checkLeftSide(rule.getLeftSide()) && checkRightSide(rule.getRightSide());
 }
 
 bool RightRegularGrammar::checkLeftSide(const list<Symbol>& leftSide) const {
@@ -40,9 +30,7 @@ bool RightRegularGrammar::checkLeftSide(const list<Symbol>& leftSide) const {
 bool RightRegularGrammar::checkRightSide(const list<Symbol>& rightSide) const {
 	if (rightSide.size() == 0) {
 		return true;
-	}
-
-	if (rightSide.size() == 1) {
+	} else if (rightSide.size() == 1) {
 		const Symbol& symbol = rightSide.front();
 
 		//check epsilon
@@ -50,27 +38,26 @@ bool RightRegularGrammar::checkRightSide(const list<Symbol>& rightSide) const {
 			return true;
 		}
 
-		if (terminalSymbols.find(symbol) == terminalSymbols.end()
-				&& nonTerminalSymbols.find(symbol) == nonTerminalSymbols.end()) {
-			return false;
+		//check that symbol exists
+		return ((terminalSymbols.find(symbol) != terminalSymbols.end())
+				|| (nonTerminalSymbols.find(symbol) != nonTerminalSymbols.end()));
+
+	} else {
+		//check if all symbols except the last one are terminal symbols
+		for (list<Symbol>::const_iterator symbol = rightSide.begin(); symbol != --rightSide.end(); symbol++) {
+			if (terminalSymbols.find(*symbol) == terminalSymbols.end()) {
+				return false;
+			}
 		}
-		return true;
-	}
 
-	//check if all symbols except the last are terminal symbols
-	for (list<Symbol>::const_iterator symbol = rightSide.begin(); symbol != --rightSide.end(); symbol++) {
-		if (terminalSymbols.find(*symbol) == terminalSymbols.end()) {
+		//check if last symbol is nonterminal
+		const Symbol& lastSymbol = *(--rightSide.end());
+		if (nonTerminalSymbols.find(lastSymbol) == nonTerminalSymbols.end()) {
 			return false;
 		}
-	}
 
-	//check if last symbol is nonterminal
-	const Symbol& lastSymbol = *(--rightSide.end());
-	if (nonTerminalSymbols.find(lastSymbol) == nonTerminalSymbols.end()) {
-		return false;
+		return true;
 	}
-
-	return true;
 }
 
 }
diff --git a/alib/src/grammar/RightRegularGrammar.h b/alib/src/grammar/RightRegularGrammar.h
index 46a8e52eb4..deffa166ec 100644
--- a/alib/src/grammar/RightRegularGrammar.h
+++ b/alib/src/grammar/RightRegularGrammar.h
@@ -12,14 +12,12 @@
 
 namespace grammar {
 
-class RightRegularGrammar: public grammar::Grammar {
+class RightRegularGrammar: public Grammar {
 private:
 	bool checkLeftSide(const list<Symbol>& leftSide) const;
 	bool checkRightSide(const list<Symbol>& rightSide) const;
 public:
 	bool isValidRule(const Rule& rule) const;
-	void addRule(const Rule& rule);
-
 };
 
 } /* namespace grammar */
diff --git a/alib/src/grammar/UnknownGrammar.cpp b/alib/src/grammar/UnknownGrammar.cpp
index 19b02d82f8..ae89e343dc 100644
--- a/alib/src/grammar/UnknownGrammar.cpp
+++ b/alib/src/grammar/UnknownGrammar.cpp
@@ -10,14 +10,23 @@
 
 namespace grammar {
 
-void UnknownGrammar::addRule(const Rule& rule) {
-	usesExistingSymbols(rule);
+bool UnknownGrammar::isValidRule(const Rule& rule) const {
+	for (auto const & symbol : rule.getLeftSide()) {
+		if (terminalSymbols.find(symbol) == terminalSymbols.end()
+				&& nonTerminalSymbols.find(symbol) == nonTerminalSymbols.end()) {
+			return false;
+		}
+	}
 
-	if(!rules.insert(rule).second) {
-		throw GrammarException("Rule already exists.");
+	for (auto const & right : rule.getRightSide()) {
+		if (terminalSymbols.find(right) == terminalSymbols.end()
+				&& nonTerminalSymbols.find(right) == nonTerminalSymbols.end()) {
+			return false;
+		}
 	}
+
+	return true;
 }
 
 } /* namespace grammar */
 
-
diff --git a/alib/src/grammar/UnknownGrammar.h b/alib/src/grammar/UnknownGrammar.h
index a3f1829589..8f03a98ff7 100644
--- a/alib/src/grammar/UnknownGrammar.h
+++ b/alib/src/grammar/UnknownGrammar.h
@@ -13,8 +13,8 @@
 namespace grammar {
 
 class UnknownGrammar: public grammar::Grammar {
-public:
-	void addRule(const Rule& rule);
+protected:
+	bool isValidRule(const Rule& rule) const;
 };
 
 } /* namespace grammar */
diff --git a/examples/grammar/regular.xml b/examples/grammar/rightRegular.xml
similarity index 68%
rename from examples/grammar/regular.xml
rename to examples/grammar/rightRegular.xml
index 18e5614bb0..1e3f164c41 100644
--- a/examples/grammar/regular.xml
+++ b/examples/grammar/rightRegular.xml
@@ -6,6 +6,7 @@
 
 	<terminalSymbols>
 		<symbol>a</symbol>
+		<symbol>b</symbol>
 	</terminalSymbols>
 
 	<rules>
@@ -27,6 +28,17 @@
 				<symbol>a</symbol>
 			</rightSide>
 		</rule>
+		<rule>
+			<leftSide>
+				<symbol>A</symbol>
+			</leftSide>
+			<rightSide>
+				<symbol>b</symbol>
+				<symbol>b</symbol>
+				<symbol>b</symbol>
+				<symbol>A</symbol>
+			</rightSide>
+		</rule>
 	</rules>
 
 	<startSymbol>S</startSymbol>
-- 
GitLab