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