From bc250a225f172d3102d46801452f7d08865e3e73 Mon Sep 17 00:00:00 2001 From: Tomas Pecka <tomas.pecka@fit.cvut.cz> Date: Tue, 5 Nov 2019 21:33:59 +0100 Subject: [PATCH] Algo: CFG alternation/concatenation/iteration (#171) --- .../grammar/transform/GrammarAlternation.cpp | 23 ++++++ .../grammar/transform/GrammarAlternation.h | 82 +++++++++++++++++++ .../transform/GrammarConcatenation.cpp | 23 ++++++ .../grammar/transform/GrammarConcatenation.h | 76 +++++++++++++++++ .../grammar/transform/GrammarIteration.cpp | 21 +++++ .../src/grammar/transform/GrammarIteration.h | 68 +++++++++++++++ .../transform/GrammarTransformCommon.h | 55 +++++++++++++ .../transform/GrammarAlternationTest.cpp | 56 +++++++++++++ .../transform/GrammarConcatenationTest.cpp | 55 +++++++++++++ .../transform/GrammarIterationTest.cpp | 39 +++++++++ 10 files changed, 498 insertions(+) create mode 100644 alib2algo/src/grammar/transform/GrammarAlternation.cpp create mode 100644 alib2algo/src/grammar/transform/GrammarAlternation.h create mode 100644 alib2algo/src/grammar/transform/GrammarConcatenation.cpp create mode 100644 alib2algo/src/grammar/transform/GrammarConcatenation.h create mode 100644 alib2algo/src/grammar/transform/GrammarIteration.cpp create mode 100644 alib2algo/src/grammar/transform/GrammarIteration.h create mode 100644 alib2algo/src/grammar/transform/GrammarTransformCommon.h create mode 100644 alib2algo/test-src/grammar/transform/GrammarAlternationTest.cpp create mode 100644 alib2algo/test-src/grammar/transform/GrammarConcatenationTest.cpp create mode 100644 alib2algo/test-src/grammar/transform/GrammarIterationTest.cpp diff --git a/alib2algo/src/grammar/transform/GrammarAlternation.cpp b/alib2algo/src/grammar/transform/GrammarAlternation.cpp new file mode 100644 index 0000000000..66e6d2649e --- /dev/null +++ b/alib2algo/src/grammar/transform/GrammarAlternation.cpp @@ -0,0 +1,23 @@ +/* + * GrammarAlternation.cpp + * + * Created on: 05. 11. 2019 + * Author: Tomas Pecka + */ + +#include "GrammarAlternation.h" +#include <registration/AlgoRegistration.hpp> + +namespace { + +auto GrammarAlternationCFG = registration::AbstractRegister < grammar::transform::GrammarAlternation, + grammar::CFG < DefaultSymbolType, ext::pair < DefaultSymbolType, unsigned > >, + const grammar::CFG < DefaultSymbolType, DefaultSymbolType > &, + const grammar::CFG < DefaultSymbolType, DefaultSymbolType > & > ( grammar::transform::GrammarAlternation::alternation, "first", "second" ).setDocumentation ( +"Alternates two context-free grammars.\n\ +\n\ +@param first First grammar (G1)\n\ +@param second Second grammar (G2)\n\ +@return context-free grammar G where L(G) = L(G1) \\cup L(G2)" ); + +} /* namespace */ diff --git a/alib2algo/src/grammar/transform/GrammarAlternation.h b/alib2algo/src/grammar/transform/GrammarAlternation.h new file mode 100644 index 0000000000..5f3aca18dd --- /dev/null +++ b/alib2algo/src/grammar/transform/GrammarAlternation.h @@ -0,0 +1,82 @@ +/* + * GrammarAlternation.h + * + * This file is part of Algorithms library toolkit. + * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz) + + * Algorithms library toolkit is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * Algorithms library toolkit is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>. + * + * Created on: 05. 11. 2019 + * Author: Tomas Pecka + */ + +#ifndef GRAMMAR_ALTERNATION_H_ +#define GRAMMAR_ALTERNATION_H_ + +#include "GrammarTransformCommon.h" + +#include <grammar/ContextFree/CFG.h> +#include <common/createUnique.hpp> + +#include <label/InitialStateLabel.h> + +namespace grammar::transform { + +/** + * Alternation of two grammars. + * For two regular grammars G1 and G2, we create a regular grammar such that L(G) = L(G1) \cup L(G2). + * For CFG and CFG/RG we create a context free grammar such that L(G) = L(G1) \cup L(G2). + * Source: + */ +class GrammarAlternation { +public: + /** + * Alternates two grammars. + * @tparam TerminalSymbolType Type for terminal symbols. + * @tparam NonterminalSymbolType Type for nonterminal symbols. + * @param first First grammar (G1) + * @param second Second grammar (G2) + * @return CFG grammar for alternation of two CFG or RightRG for alternation of two RightRG. + */ + template < class TerminalSymbolType, class NonterminalSymbolType > + static grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > alternation ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & first, const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & second ); + +private: + template < class TerminalSymbolType, class NonterminalSymbolType > + static void addRulesRenameNonterminals ( grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > & grammar, const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & g, const unsigned id ); +}; + + +template < class TerminalSymbolType, class NonterminalSymbolType > +grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > GrammarAlternation::alternation ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & first, const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & second ) { + ext::pair < NonterminalSymbolType, unsigned > S = ext::make_pair ( common::createUnique ( label::InitialStateLabel::instance < NonterminalSymbolType > ( ), first.getNonterminalAlphabet ( ), second.getNonterminalAlphabet ( ) ), 0 ); + grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > res ( S ); + + res.setTerminalAlphabet ( first.getTerminalAlphabet ( ) + second.getTerminalAlphabet ( ) ); + + copyNonterminalsRename ( res, first, 1 ); + copyNonterminalsRename ( res, first, 2 ); + + copyRulesRenameNonterminals ( res, first, 1 ); + copyRulesRenameNonterminals ( res, second, 2 ); + + res.addRule ( S, { ext::make_pair ( first.getInitialSymbol ( ), 1 ) } ); + res.addRule ( S, { ext::make_pair ( second.getInitialSymbol ( ), 2 ) } ); + + return res; +} + +} /* namespace grammar::transform */ + +#endif /* GRAMMAR_ALTERNATION_H_ */ diff --git a/alib2algo/src/grammar/transform/GrammarConcatenation.cpp b/alib2algo/src/grammar/transform/GrammarConcatenation.cpp new file mode 100644 index 0000000000..0e57a5a61c --- /dev/null +++ b/alib2algo/src/grammar/transform/GrammarConcatenation.cpp @@ -0,0 +1,23 @@ +/* + * GrammarConcatenation.cpp + * + * Created on: 05. 11. 2019 + * Author: Tomas Pecka + */ + +#include "GrammarConcatenation.h" +#include <registration/AlgoRegistration.hpp> + +namespace { + +auto GrammarConcatenationCFG = registration::AbstractRegister < grammar::transform::GrammarConcatenation, + grammar::CFG < DefaultSymbolType, ext::pair < DefaultSymbolType, unsigned > >, + const grammar::CFG < > &, + const grammar::CFG < > & > ( grammar::transform::GrammarConcatenation::concatenation, "first", "second" ).setDocumentation ( +"Concatenates two context-free grammars.\n\ +\n\ +@param first First grammar (G1)\n\ +@param second Second grammar (G2)\n\ +@return context-free grammar G where L(G) = L(G1).L(G2)" ); + +} /* namespace */ diff --git a/alib2algo/src/grammar/transform/GrammarConcatenation.h b/alib2algo/src/grammar/transform/GrammarConcatenation.h new file mode 100644 index 0000000000..193cd8d068 --- /dev/null +++ b/alib2algo/src/grammar/transform/GrammarConcatenation.h @@ -0,0 +1,76 @@ +/* + * GrammarConcatenation.h + * + * This file is part of Algorithms library toolkit. + * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz) + + * Algorithms library toolkit is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * Algorithms library toolkit is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>. + * + * Created on: 05. 11. 2019 + * Author: Tomas Pecka + */ + +#ifndef GRAMMAR_CONCATENATION_H_ +#define GRAMMAR_CONCATENATION_H_ + +#include "GrammarTransformCommon.h" + +#include <grammar/ContextFree/CFG.h> +#include <common/createUnique.hpp> + +#include <label/InitialStateLabel.h> + +namespace grammar::transform { + +/** + * Concatenation of two grammars. + * For two regular grammars G1 and G2, we create a regular grammar such that L(G) = L(G1).L(G2). + * For CFG and CFG/RG we create a context free grammar such that L(G) = L(G1).(G2). + * Source: + */ +class GrammarConcatenation { +public: + /** + * Concatenates two grammars. + * @tparam TerminalSymbolType Type for terminal symbols. + * @tparam NonterminalSymbolType Type for nonterminal symbols. + * @param first First grammar (G1) + * @param second Second grammar (G2) + * @return CFG grammar for concatenation of two CFG or RightRG for concatenation of two RightRG. + */ + template < class TerminalSymbolType, class NonterminalSymbolType > + static grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > concatenation ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & first, const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & second ); +}; + +template < class TerminalSymbolType, class NonterminalSymbolType > +grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > GrammarConcatenation::concatenation ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & first, const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & second ) { + ext::pair < NonterminalSymbolType, unsigned > S = ext::make_pair ( common::createUnique ( label::InitialStateLabel::instance < NonterminalSymbolType > ( ), first.getNonterminalAlphabet ( ), second.getNonterminalAlphabet ( ) ), 0 ); + grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > res ( S ); + + res.setTerminalAlphabet ( first.getTerminalAlphabet ( ) + second.getTerminalAlphabet ( ) ); + + copyNonterminalsRename ( res, first, 1 ); + copyNonterminalsRename ( res, first, 2 ); + + copyRulesRenameNonterminals ( res, first, 1 ); + copyRulesRenameNonterminals ( res, second, 2 ); + + res.addRule ( S, { ext::make_pair ( first.getInitialSymbol ( ), 1 ), ext::make_pair ( second.getInitialSymbol ( ), 2 ) } ); + + return res; +} + +} /* namespace grammar::transform */ + +#endif /* GRAMMAR_CONCATENATION_H_ */ diff --git a/alib2algo/src/grammar/transform/GrammarIteration.cpp b/alib2algo/src/grammar/transform/GrammarIteration.cpp new file mode 100644 index 0000000000..72ba20b3c6 --- /dev/null +++ b/alib2algo/src/grammar/transform/GrammarIteration.cpp @@ -0,0 +1,21 @@ +/* + * GrammarIteration.cpp + * + * Created on: 05. 11. 2019 + * Author: Tomas Pecka + */ + +#include "GrammarIteration.h" +#include <registration/AlgoRegistration.hpp> + +namespace { + +auto GrammarIterationCFG = registration::AbstractRegister < grammar::transform::GrammarIteration, + grammar::CFG < >, + const grammar::CFG < > & > ( grammar::transform::GrammarIteration::iteration, "first" ).setDocumentation ( +"Iterates a context-free grammars.\n\ +\n\ +@param grammar CFG grammar (G1)\n\ +@return context-free grammar G where L(G) = L(G1)*" ); + +} /* namespace */ diff --git a/alib2algo/src/grammar/transform/GrammarIteration.h b/alib2algo/src/grammar/transform/GrammarIteration.h new file mode 100644 index 0000000000..4c5fd15cbc --- /dev/null +++ b/alib2algo/src/grammar/transform/GrammarIteration.h @@ -0,0 +1,68 @@ +/* + * GrammarIteration.h + * + * This file is part of Algorithms library toolkit. + * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz) + + * Algorithms library toolkit is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * Algorithms library toolkit is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>. + * + * Created on: 05. 11. 2019 + * Author: Tomas Pecka + */ + +#ifndef GRAMMAR_ITERATION_H_ +#define GRAMMAR_ITERATION_H_ + +#include <grammar/ContextFree/CFG.h> +#include <common/createUnique.hpp> + +#include <label/InitialStateLabel.h> + +namespace grammar::transform { + +/** + * Iteration of two grammars. + * For two regular grammars G1 and G2, we create a regular grammar such that L(G) = L(G1) \cup L(G2). + * For CFG and CFG/RG we create a context free grammar such that L(G) = L(G1) \cup L(G2). + * Source: + */ +class GrammarIteration { +public: + /** + * Iterates a grammar. + * @tparam TerminalSymbolType Type for terminal symbols. + * @tparam NonterminalSymbolType Type for nonterminal symbols. + * @param grammar grammar + * @return CFG grammar for iteartion of a CFG grammar + */ + template < class TerminalSymbolType, class NonterminalSymbolType > + static grammar::CFG < TerminalSymbolType, NonterminalSymbolType > iteration ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & grammar ); +}; + +template < class TerminalSymbolType, class NonterminalSymbolType > +grammar::CFG < TerminalSymbolType, NonterminalSymbolType > GrammarIteration::iteration ( const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & grammar ) { + NonterminalSymbolType S = common::createUnique ( label::InitialStateLabel::instance < NonterminalSymbolType > ( ), grammar.getNonterminalAlphabet ( ) ); + grammar::CFG < TerminalSymbolType, NonterminalSymbolType > res = grammar; + + res.addNonterminalSymbol ( S ); + res.setInitialSymbol ( S ); + res.addRule ( S, { } ); + res.addRule ( S, { grammar.getInitialSymbol ( ), S } ); + + return res; +} + +} /* namespace grammar::transform */ + +#endif /* GRAMMAR_ITERATION_H_ */ diff --git a/alib2algo/src/grammar/transform/GrammarTransformCommon.h b/alib2algo/src/grammar/transform/GrammarTransformCommon.h new file mode 100644 index 0000000000..164480250e --- /dev/null +++ b/alib2algo/src/grammar/transform/GrammarTransformCommon.h @@ -0,0 +1,55 @@ +/* + * GrammarTransformCommon.h + * + * This file is part of Algorithms library toolkit. + * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz) + + * Algorithms library toolkit is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * Algorithms library toolkit is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>. + * + * Created on: 05. 11. 2019 + * Author: Tomas Pecka + */ + +#include <grammar/ContextFree/CFG.h> + +#ifndef GRAMMAR_TRANSFORM_COMMON_H_ +#define GRAMMAR_TRANSFORM_COMMON_H_ + +template < class TerminalSymbolType, class NonterminalSymbolType > +void copyNonterminalsRename ( grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > & dst, const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & src, const unsigned suffix ) { + for ( const NonterminalSymbolType & symb : src.getNonterminalAlphabet ( ) ) + dst.addNonterminalSymbol ( ext::make_pair ( symb, suffix ) ); +} + +template < class TerminalSymbolType, class NonterminalSymbolType > +void copyRulesRenameNonterminals ( grammar::CFG < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > & dst, const grammar::CFG < TerminalSymbolType, NonterminalSymbolType > & src, const unsigned suffix ) { + for ( const std::pair < const NonterminalSymbolType, ext::set < ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > > > & kv : src.getRules ( ) ) { + const NonterminalSymbolType & lhs = kv.first; + + for ( const ext::vector < ext::variant < TerminalSymbolType, NonterminalSymbolType > > & rhs : kv.second ) { + ext::vector < ext::variant < TerminalSymbolType, ext::pair < NonterminalSymbolType, unsigned > > > newRhs; + + for ( const ext::variant < TerminalSymbolType, NonterminalSymbolType > & symb : rhs ) { + if ( symb.template is < TerminalSymbolType > ( ) && src.getTerminalAlphabet ( ).count ( symb.template get < TerminalSymbolType > ( ) ) ) + newRhs.push_back ( symb.template get < TerminalSymbolType > ( ) ); + else + newRhs.push_back ( ext::make_pair ( symb.template get < NonterminalSymbolType > ( ), suffix ) ); + } + + dst.addRule ( ext::make_pair ( lhs, suffix ), newRhs ); + } + } +} + +#endif /* GRAMMAR_TRANSFORM_COMMON_H_ */ diff --git a/alib2algo/test-src/grammar/transform/GrammarAlternationTest.cpp b/alib2algo/test-src/grammar/transform/GrammarAlternationTest.cpp new file mode 100644 index 0000000000..0f95a059e5 --- /dev/null +++ b/alib2algo/test-src/grammar/transform/GrammarAlternationTest.cpp @@ -0,0 +1,56 @@ +#include <catch2/catch.hpp> +#include <common/createUnique.hpp> + +#include "grammar/ContextFree/CFG.h" +#include "grammar/transform/GrammarAlternation.h" + +TEST_CASE ( "Grammar Alternation", "[unit][algo][grammar][transform]" ) { + SECTION ( "Test CFG" ) { + { + ext::pair < DefaultSymbolType, unsigned > S1 = ext::make_pair ( DefaultSymbolType ( "S" ), 1 ); + ext::pair < DefaultSymbolType, unsigned > A1 = ext::make_pair ( DefaultSymbolType ( "A" ), 1 ); + ext::pair < DefaultSymbolType, unsigned > S2 = ext::make_pair ( DefaultSymbolType ( "S" ), 2 ); + ext::pair < DefaultSymbolType, unsigned > A2 = ext::make_pair ( DefaultSymbolType ( "A" ), 2 ); + DefaultSymbolType S = DefaultSymbolType ( "S" ); + DefaultSymbolType A = DefaultSymbolType ( "A" ); + + DefaultSymbolType a = DefaultSymbolType ( 'a' ); + DefaultSymbolType b = DefaultSymbolType ( 'b' ); + + grammar::CFG < DefaultSymbolType, DefaultSymbolType > grammar1 ( { S, A }, { a, b }, S ); + grammar::CFG < DefaultSymbolType, DefaultSymbolType > grammar2 ( { S, A }, { a, b }, S ); + + ext::pair < DefaultSymbolType, unsigned > S0 = ext::make_pair ( common::createUnique ( label::InitialStateLabel::instance < DefaultSymbolType > ( ), grammar1.getNonterminalAlphabet ( ), grammar2.getNonterminalAlphabet ( ) ), 0 ); + grammar::CFG < DefaultSymbolType, ext::pair < DefaultSymbolType, unsigned > > grammar3 ( { S0, S1, A1, S2, A2 }, { a, b }, S0 ); + + grammar1.addRule ( S, { } ); + grammar1.addRule ( S, { a, A } ); + grammar1.addRule ( S, { a, S } ); + grammar1.addRule ( A, { a, A } ); + grammar1.addRule ( A, { } ); + + grammar2.addRule ( S, { } ); + grammar2.addRule ( S, { a, A } ); + grammar2.addRule ( S, { a, S } ); + grammar2.addRule ( A, { a, A } ); + grammar2.addRule ( A, { } ); + + grammar3.addRule ( S0, { S1 } ); + grammar3.addRule ( S0, { S2 } ); + + grammar3.addRule ( S1, { } ); + grammar3.addRule ( S1, { a, A1 } ); + grammar3.addRule ( S1, { a, S1 } ); + grammar3.addRule ( A1, { a, A1 } ); + grammar3.addRule ( A1, { } ); + + grammar3.addRule ( S2, { } ); + grammar3.addRule ( S2, { a, A2 } ); + grammar3.addRule ( S2, { a, S2 } ); + grammar3.addRule ( A2, { a, A2 } ); + grammar3.addRule ( A2, { } ); + + CHECK ( grammar3 == grammar::transform::GrammarAlternation::alternation ( grammar1, grammar2 ) ); + } + } +} diff --git a/alib2algo/test-src/grammar/transform/GrammarConcatenationTest.cpp b/alib2algo/test-src/grammar/transform/GrammarConcatenationTest.cpp new file mode 100644 index 0000000000..efb220771f --- /dev/null +++ b/alib2algo/test-src/grammar/transform/GrammarConcatenationTest.cpp @@ -0,0 +1,55 @@ +#include <catch2/catch.hpp> +#include <common/createUnique.hpp> + +#include "grammar/ContextFree/CFG.h" +#include "grammar/transform/GrammarConcatenation.h" + +TEST_CASE ( "Grammar Concatenation", "[unit][algo][grammar][transform]" ) { + SECTION ( "Test CFG" ) { + { + ext::pair < DefaultSymbolType, unsigned > S1 = ext::make_pair ( DefaultSymbolType ( "S" ), 1 ); + ext::pair < DefaultSymbolType, unsigned > A1 = ext::make_pair ( DefaultSymbolType ( "A" ), 1 ); + ext::pair < DefaultSymbolType, unsigned > S2 = ext::make_pair ( DefaultSymbolType ( "S" ), 2 ); + ext::pair < DefaultSymbolType, unsigned > A2 = ext::make_pair ( DefaultSymbolType ( "A" ), 2 ); + DefaultSymbolType S = DefaultSymbolType ( "S" ); + DefaultSymbolType A = DefaultSymbolType ( "A" ); + + DefaultSymbolType a = DefaultSymbolType ( 'a' ); + DefaultSymbolType b = DefaultSymbolType ( 'b' ); + + grammar::CFG < DefaultSymbolType, DefaultSymbolType > grammar1 ( { S, A }, { a, b }, S ); + grammar::CFG < DefaultSymbolType, DefaultSymbolType > grammar2 ( { S, A }, { a, b }, S ); + + ext::pair < DefaultSymbolType, unsigned > S0 = ext::make_pair ( common::createUnique ( label::InitialStateLabel::instance < DefaultSymbolType > ( ), grammar1.getNonterminalAlphabet ( ), grammar2.getNonterminalAlphabet ( ) ), 0 ); + grammar::CFG < DefaultSymbolType, ext::pair < DefaultSymbolType, unsigned > > grammar3 ( { S0, S1, A1, S2, A2 }, { a, b }, S0 ); + + grammar1.addRule ( S, { } ); + grammar1.addRule ( S, { a, A } ); + grammar1.addRule ( S, { a, S } ); + grammar1.addRule ( A, { a, A } ); + grammar1.addRule ( A, { } ); + + grammar2.addRule ( S, { } ); + grammar2.addRule ( S, { a, A } ); + grammar2.addRule ( S, { a, S } ); + grammar2.addRule ( A, { a, A } ); + grammar2.addRule ( A, { } ); + + grammar3.addRule ( S0, { S1, S2 } ); + + grammar3.addRule ( S1, { } ); + grammar3.addRule ( S1, { a, A1 } ); + grammar3.addRule ( S1, { a, S1 } ); + grammar3.addRule ( A1, { a, A1 } ); + grammar3.addRule ( A1, { } ); + + grammar3.addRule ( S2, { } ); + grammar3.addRule ( S2, { a, A2 } ); + grammar3.addRule ( S2, { a, S2 } ); + grammar3.addRule ( A2, { a, A2 } ); + grammar3.addRule ( A2, { } ); + + CHECK ( grammar3 == grammar::transform::GrammarConcatenation::concatenation ( grammar1, grammar2 ) ); + } + } +} diff --git a/alib2algo/test-src/grammar/transform/GrammarIterationTest.cpp b/alib2algo/test-src/grammar/transform/GrammarIterationTest.cpp new file mode 100644 index 0000000000..b96852f02b --- /dev/null +++ b/alib2algo/test-src/grammar/transform/GrammarIterationTest.cpp @@ -0,0 +1,39 @@ +#include <catch2/catch.hpp> +#include <common/createUnique.hpp> + +#include "grammar/ContextFree/CFG.h" +#include "grammar/transform/GrammarIteration.h" + +TEST_CASE ( "Grammar Iteration", "[unit][algo][grammar][transform]" ) { + SECTION ( "Test CFG" ) { + { + DefaultSymbolType S = DefaultSymbolType ( "S" ); + DefaultSymbolType A = DefaultSymbolType ( "A" ); + + DefaultSymbolType a = DefaultSymbolType ( 'a' ); + DefaultSymbolType b = DefaultSymbolType ( 'b' ); + + grammar::CFG < DefaultSymbolType, DefaultSymbolType > grammar1 ( { S, A }, { a, b }, S ); + + DefaultSymbolType S0 = common::createUnique ( label::InitialStateLabel::instance < DefaultSymbolType > ( ), grammar1.getNonterminalAlphabet ( ) ); + grammar::CFG < DefaultSymbolType, DefaultSymbolType > grammar3 ( { S0, S, A }, { a, b }, S0 ); + + grammar1.addRule ( S, { } ); + grammar1.addRule ( S, { a, A } ); + grammar1.addRule ( S, { a, S } ); + grammar1.addRule ( A, { a, A } ); + grammar1.addRule ( A, { } ); + + grammar3.addRule ( S0, { } ); + grammar3.addRule ( S0, { S, S0 } ); + + grammar3.addRule ( S, { } ); + grammar3.addRule ( S, { a, A } ); + grammar3.addRule ( S, { a, S } ); + grammar3.addRule ( A, { a, A } ); + grammar3.addRule ( A, { } ); + + CHECK ( grammar3 == grammar::transform::GrammarIteration::iteration ( grammar1 ) ); + } + } +} -- GitLab