From b5d471e9812d0b0c9c1f2886f7a4b0a9e85bfc12 Mon Sep 17 00:00:00 2001
From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz>
Date: Tue, 20 Oct 2015 20:27:42 +0200
Subject: [PATCH] add algorithm to compute LL1ParseTable

---
 .../src/grammar/parsing/LL1ParseTable.cpp     | 68 ++++++++++++++++
 alib2algo/src/grammar/parsing/LL1ParseTable.h | 43 ++++++++++
 .../grammar/parsing/LL1ParseTable.cpp         | 81 +++++++++++++++++++
 .../test-src/grammar/parsing/LL1ParseTable.h  | 19 +++++
 4 files changed, 211 insertions(+)
 create mode 100644 alib2algo/src/grammar/parsing/LL1ParseTable.cpp
 create mode 100644 alib2algo/src/grammar/parsing/LL1ParseTable.h
 create mode 100644 alib2algo/test-src/grammar/parsing/LL1ParseTable.cpp
 create mode 100644 alib2algo/test-src/grammar/parsing/LL1ParseTable.h

diff --git a/alib2algo/src/grammar/parsing/LL1ParseTable.cpp b/alib2algo/src/grammar/parsing/LL1ParseTable.cpp
new file mode 100644
index 0000000000..a11ec54cc8
--- /dev/null
+++ b/alib2algo/src/grammar/parsing/LL1ParseTable.cpp
@@ -0,0 +1,68 @@
+/*
+ * LL1ParseTable.cpp
+ *
+ *  Created on: 9. 6. 2015
+ *	  Author: Tomas Pecka
+ */
+
+#include "LL1ParseTable.h"
+#include "First.h"
+#include "Follow.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 {
+
+template < class T >
+std::map < std::pair < std::variant< alphabet::Symbol, string::Epsilon>, alphabet::Symbol >, std::set < std::vector < alphabet::Symbol > > > LL1ParseTable::parseTable ( const T & grammar ) {
+	std::map < std::pair < std::variant< alphabet::Symbol, string::Epsilon>, alphabet::Symbol >, std::set < std::vector < alphabet::Symbol > > > res;
+
+	std::map < std::vector < alphabet::Symbol >, std::set < std::variant < alphabet::Symbol, string::Epsilon > > > first = First::first(grammar);
+	std::map < alphabet::Symbol, std::set < std::variant < alphabet::Symbol, string::Epsilon > > > follow = Follow::follow(grammar);
+
+	for(const std::pair<alphabet::Symbol, std::set< std::vector<alphabet::Symbol>>>& transition : grammar.getRawRules()) {
+		const alphabet::Symbol& lhs = transition.first;
+		for(const std::vector<alphabet::Symbol>& rhs : transition.second) {
+			for(const std::variant<alphabet::Symbol, string::Epsilon>& firstElem : first[rhs]) {
+				if(firstElem.is<string::Epsilon>()) continue;
+
+				res[std::make_pair(firstElem, lhs)].insert(rhs);
+			}
+
+			if(first[rhs].count(string::Epsilon::EPSILON)) for(const std::variant<alphabet::Symbol, string::Epsilon>& followElem : follow[lhs]) {
+				res[std::make_pair(followElem, lhs)].insert(rhs);
+			}
+		}
+	}
+
+	return res;
+}
+
+auto LL1ParseTableCFG = LL1ParseTable::RegistratorWrapper < std::map<std::pair<std::variant<alphabet::Symbol, string::Epsilon>, alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>>, grammar::CFG > ( LL1ParseTable::getInstance ( ), LL1ParseTable::parseTable );
+auto LL1ParseTableEpsilonFreeCFG = LL1ParseTable::RegistratorWrapper < std::map<std::pair<std::variant<alphabet::Symbol, string::Epsilon>, alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>>, grammar::EpsilonFreeCFG > ( LL1ParseTable::getInstance ( ), LL1ParseTable::parseTable );
+auto LL1ParseTableGNF = LL1ParseTable::RegistratorWrapper < std::map<std::pair<std::variant<alphabet::Symbol, string::Epsilon>, alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>>, grammar::GNF > ( LL1ParseTable::getInstance ( ), LL1ParseTable::parseTable );
+auto LL1ParseTableCNF = LL1ParseTable::RegistratorWrapper < std::map<std::pair<std::variant<alphabet::Symbol, string::Epsilon>, alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>>, grammar::CNF > ( LL1ParseTable::getInstance ( ), LL1ParseTable::parseTable );
+auto LL1ParseTableLG  = LL1ParseTable::RegistratorWrapper < std::map<std::pair<std::variant<alphabet::Symbol, string::Epsilon>, alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>>, grammar::LG > ( LL1ParseTable::getInstance ( ), LL1ParseTable::parseTable );
+auto LL1ParseTableLeftLG  = LL1ParseTable::RegistratorWrapper < std::map<std::pair<std::variant<alphabet::Symbol, string::Epsilon>, alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>>, grammar::LeftLG > ( LL1ParseTable::getInstance ( ), LL1ParseTable::parseTable );
+auto LL1ParseTableLeftRG  = LL1ParseTable::RegistratorWrapper < std::map<std::pair<std::variant<alphabet::Symbol, string::Epsilon>, alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>>, grammar::LeftRG > ( LL1ParseTable::getInstance ( ), LL1ParseTable::parseTable );
+auto LL1ParseTableRightLG = LL1ParseTable::RegistratorWrapper < std::map<std::pair<std::variant<alphabet::Symbol, string::Epsilon>, alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>>, grammar::RightLG > ( LL1ParseTable::getInstance ( ), LL1ParseTable::parseTable );
+auto LL1ParseTableRightRG = LL1ParseTable::RegistratorWrapper < std::map<std::pair<std::variant<alphabet::Symbol, string::Epsilon>, alphabet::Symbol>, std::set<std::vector<alphabet::Symbol>>>, grammar::RightRG > ( LL1ParseTable::getInstance ( ), LL1ParseTable::parseTable );
+
+std::map < std::pair < std::variant< alphabet::Symbol, string::Epsilon>, alphabet::Symbol >, std::set < std::vector < alphabet::Symbol > > > LL1ParseTable::parseTable ( const grammar::Grammar & grammar ) {
+	return getInstance ( ).dispatch ( grammar.getData ( ) );
+}
+
+} /* namespace parsing */
+
+} /* namespace grammar */
diff --git a/alib2algo/src/grammar/parsing/LL1ParseTable.h b/alib2algo/src/grammar/parsing/LL1ParseTable.h
new file mode 100644
index 0000000000..bc373c03bf
--- /dev/null
+++ b/alib2algo/src/grammar/parsing/LL1ParseTable.h
@@ -0,0 +1,43 @@
+/*
+ * LL1ParseTable.h
+ *
+ *  Created on: 9. 6. 2015
+ *	  Author: Jan Travnicek
+ */
+
+#ifndef LL_1_PARSE_TABLE_H_
+#define LL_1_PARSE_TABLE_H_
+
+#include <common/multipleDispatch.hpp>
+#include <grammar/Grammar.h>
+#include <alphabet/Symbol.h>
+#include <string/Epsilon.h>
+#include <vector>
+#include <variant>
+#include <set>
+#include <map>
+
+namespace grammar {
+
+namespace parsing {
+
+class LL1ParseTable : public std::SingleDispatch < std::map < std::pair < std::variant< alphabet::Symbol, string::Epsilon>, alphabet::Symbol >, std::set < std::vector < alphabet::Symbol > > >, grammar::GrammarBase > {
+public:
+	template < class T >
+	static std::map < std::pair < std::variant< alphabet::Symbol, string::Epsilon>, alphabet::Symbol >, std::set < std::vector < alphabet::Symbol > > > parseTable ( const T & grammar );
+
+	static std::map < std::pair < std::variant< alphabet::Symbol, string::Epsilon>, alphabet::Symbol >, std::set < std::vector < alphabet::Symbol > > > parseTable ( const grammar::Grammar & grammar );
+
+	static LL1ParseTable & getInstance ( ) {
+		static LL1ParseTable res;
+
+		return res;
+	}
+
+};
+
+} /* namespace parsing */
+
+} /* namespace grammar */
+
+#endif /* LL_1_PARSE_TABLE_H_ */
diff --git a/alib2algo/test-src/grammar/parsing/LL1ParseTable.cpp b/alib2algo/test-src/grammar/parsing/LL1ParseTable.cpp
new file mode 100644
index 0000000000..fa877870d2
--- /dev/null
+++ b/alib2algo/test-src/grammar/parsing/LL1ParseTable.cpp
@@ -0,0 +1,81 @@
+#include "LL1ParseTable.h"
+
+#include "grammar/parsing/LL1ParseTable.h"
+#include "string/Epsilon.h"
+#include "grammar/ContextFree/CFG.h"
+
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION ( LL1ParseTable, "grammar" );
+CPPUNIT_TEST_SUITE_REGISTRATION ( LL1ParseTable );
+
+void LL1ParseTable::setUp ( ) {
+}
+
+void LL1ParseTable::tearDown ( ) {
+}
+
+void LL1ParseTable::testLL1Table ( ) {
+	{
+		alphabet::Symbol nE = alphabet::symbolFrom ( 'E' );
+		alphabet::Symbol nEp = alphabet::symbolFrom ( "E'" );
+		alphabet::Symbol nT = alphabet::symbolFrom ( 'T' );
+		alphabet::Symbol nTp = 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, nEp, nT, nTp, nF } );
+
+		std::vector < alphabet::Symbol > rhsE1 ( { nT, nEp } );
+		std::vector < alphabet::Symbol > rhsEp1 ( { tP, nT, nEp } );
+		std::vector < alphabet::Symbol > rhsEp2 ( { } );
+		std::vector < alphabet::Symbol > rhsT1 ( { nF, nTp } );
+		std::vector < alphabet::Symbol > rhsTp1 ( { tS, nF, nTp } );
+		std::vector < alphabet::Symbol > rhsTp2 ( { } );
+		std::vector < alphabet::Symbol > rhsF1 ( { tA } );
+		std::vector < alphabet::Symbol > rhsF2 ( { tL, nE, tR } );
+
+		grammar.addRule ( nE, rhsE1 );
+		grammar.addRule ( nEp, rhsEp1 );
+		grammar.addRule ( nEp, rhsEp2 );
+		grammar.addRule ( nT, rhsT1 );
+		grammar.addRule ( nTp, rhsTp1 );
+		grammar.addRule ( nTp, rhsTp2 );
+		grammar.addRule ( nF, rhsF1 );
+		grammar.addRule ( nF, rhsF2 );
+
+		 // --------------------------------------------------
+		std::map < std::pair < std::variant< alphabet::Symbol, string::Epsilon>, alphabet::Symbol >, std::set < std::vector < alphabet::Symbol > > > parseTable;
+
+		parseTable[std::make_pair(tA, nE)].insert( rhsE1 );
+		parseTable[std::make_pair(tL, nE)].insert( rhsE1 );
+
+		parseTable[std::make_pair(tP, nEp)].insert( rhsEp1 );
+		parseTable[std::make_pair(tR, nEp)].insert( rhsEp2 );
+		parseTable[std::make_pair(string::Epsilon::EPSILON, nEp)].insert( rhsEp2 );
+
+		parseTable[std::make_pair(tA, nT)].insert( rhsT1 );
+		parseTable[std::make_pair(tL, nT)].insert( rhsT1 );
+
+		parseTable[std::make_pair(tS, nTp)].insert( rhsTp1 );
+		parseTable[std::make_pair(tP, nTp)].insert( rhsTp2 );
+		parseTable[std::make_pair(tR, nTp)].insert( rhsTp2 );
+		parseTable[std::make_pair(string::Epsilon::EPSILON, nTp)].insert( rhsTp2 );
+
+		parseTable[std::make_pair(tA, nF)].insert( rhsF1 );
+		parseTable[std::make_pair(tL, nF)].insert( rhsF2 );
+
+		// --------------------------------------------------
+
+		std::map < std::pair < std::variant< alphabet::Symbol, string::Epsilon>, alphabet::Symbol >, std::set < std::vector < alphabet::Symbol > > > parseTableAlgo = grammar::parsing::LL1ParseTable::parseTable ( grammar );
+
+		std::cout << parseTable << std::endl;
+		std::cout << parseTableAlgo << std::endl;
+		CPPUNIT_ASSERT ( parseTable == parseTableAlgo );
+	}
+}
diff --git a/alib2algo/test-src/grammar/parsing/LL1ParseTable.h b/alib2algo/test-src/grammar/parsing/LL1ParseTable.h
new file mode 100644
index 0000000000..b98431743f
--- /dev/null
+++ b/alib2algo/test-src/grammar/parsing/LL1ParseTable.h
@@ -0,0 +1,19 @@
+#ifndef LL_1_PARSER_TABLE_H_
+#define LL_1_PARSER_TABLE_H_
+
+#include <cppunit/extensions/HelperMacros.h>
+
+class LL1ParseTable : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE( LL1ParseTable );
+  CPPUNIT_TEST( testLL1Table );
+  CPPUNIT_TEST_SUITE_END();
+
+public:
+  void setUp();
+  void tearDown();
+
+  void testLL1Table();
+};
+
+#endif /* LL_1_PARSER_TABLE_H_ */
-- 
GitLab