diff --git a/alib2algo/src/grammar/simplify/LeftRecursionRemover.cpp b/alib2algo/src/grammar/simplify/LeftRecursionRemover.cpp new file mode 100644 index 0000000000000000000000000000000000000000..996f203d03bfdbc45b5dc9a9814db4a2d4e25975 --- /dev/null +++ b/alib2algo/src/grammar/simplify/LeftRecursionRemover.cpp @@ -0,0 +1,214 @@ +/* + * LeftRecursionRemover.cpp + * + * Created on: 24. 11. 2014 + * Author: Jan Travnicek + */ + +#include "LeftRecursionRemover.h" + +#include "../convert/ToGrammarRightRG.h" +#include "std/vector.hpp" + +namespace grammar { + +namespace simplify { + +grammar::EpsilonFreeCFG directLeftRecursionRemoveAsOrder(const grammar::EpsilonFreeCFG& origGrammar) { + grammar::EpsilonFreeCFG res(origGrammar.getInitialSymbol()); + res.setNonterminalAlphabet(origGrammar.getNonterminalAlphabet()); + res.setTerminalAlphabet(origGrammar.getTerminalAlphabet()); + res.setGeneratesEpsilon(origGrammar.getGeneratesEpsilon()); + + for(const auto& nonterminal : origGrammar.getNonterminalAlphabet()) { + if(origGrammar.getRules().find(nonterminal) == origGrammar.getRules().end()) continue; + + if(std::any_of(origGrammar.getRules().find(nonterminal)->second.begin(), origGrammar.getRules().find(nonterminal)->second.end(), [&](const std::vector<alphabet::Symbol>& singleRHS) { + return singleRHS[0] == nonterminal; // is there a direct left recursion? + } ) && std::all_of(origGrammar.getRules().find(nonterminal)->second.begin(), origGrammar.getRules().find(nonterminal)->second.end(), [&](const std::vector<alphabet::Symbol>& singleRHS) { + return origGrammar.getTerminalAlphabet().count(singleRHS[0]) || singleRHS[0] >= nonterminal; // only remove left recursion when all nonterminals are bigger than the left hand side + })) { + alphabet::Symbol primed = alphabet::createUniqueSymbol(nonterminal, res.getTerminalAlphabet(), res.getNonterminalAlphabet()); + res.addNonterminalSymbol(primed); + for(const std::vector<alphabet::Symbol>& singleRHS : origGrammar.getRules().find(nonterminal)->second) { // do the removal + if(singleRHS[0] == nonterminal) { // A -> A alpha + std::vector<alphabet::Symbol> tmpRHS(singleRHS.begin() + 1, singleRHS.end()); + + res.addRule(primed, tmpRHS); // A' -> alpha + + tmpRHS.push_back(primed); + res.addRule(primed, tmpRHS); // A' -> alpha A' + } else { // a -> beta + std::vector<alphabet::Symbol> tmpRHS(singleRHS); + + res.addRule(nonterminal, tmpRHS); // A -> beta + + tmpRHS.push_back(primed); + res.addRule(nonterminal, tmpRHS); // A -> beta A' + } + } + } else { + for(const std::vector<alphabet::Symbol>& singleRHS : origGrammar.getRules().find(nonterminal)->second) { + res.addRule(nonterminal, singleRHS); + } + } + } + return res; +} + +grammar::EpsilonFreeCFG assignAsOrder(const grammar::EpsilonFreeCFG& origGrammar, unsigned i, const std::set<alphabet::Symbol>& origNonterminals) { + grammar::EpsilonFreeCFG res(origGrammar.getInitialSymbol()); + res.setNonterminalAlphabet(origGrammar.getNonterminalAlphabet()); + res.setTerminalAlphabet(origGrammar.getTerminalAlphabet()); + res.setGeneratesEpsilon(origGrammar.getGeneratesEpsilon()); + + for(const alphabet::Symbol& lhs : origGrammar.getNonterminalAlphabet()) { + if(i > 0) { + if(origGrammar.getRules().find(lhs) == origGrammar.getRules().end()) continue; + for(const std::vector<alphabet::Symbol>& rule : origGrammar.getRules().find(lhs)->second) { + res.addRule(lhs, rule); + } + + i--; + continue; // substitue only in i-th up to n-th nonterminals + } + if(origGrammar.getRules().find(lhs) == origGrammar.getRules().end()) continue; + if(!origNonterminals.count(lhs)) { // do not subsitute in nonoriginal nonterminals + for(const std::vector<alphabet::Symbol>& rule : origGrammar.getRules().find(lhs)->second) { + res.addRule(lhs, rule); + } + continue; + } + + const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule = *origGrammar.getRules().find(lhs); + + for(const std::vector<alphabet::Symbol>& singleRHS : rule.second) { + if(res.getTerminalAlphabet().count(singleRHS[0])) { //do not substitute terminals + res.addRule(lhs, singleRHS); + continue; + } + const alphabet::Symbol& secondLHS = singleRHS[0]; + if(secondLHS >= lhs) { // substitute only by 0th up to i-th nonterminals right hand sides + res.addRule(lhs, singleRHS); + continue; + } + if(origGrammar.getRules().find(secondLHS) == origGrammar.getRules().end()) { //is there any right hand side to substitue with? + res.addRule(lhs, singleRHS); + continue; + } + + for(const std::vector<alphabet::Symbol>& secondSingleRHS : origGrammar.getRules().find(secondLHS)->second) { // do the substitution + std::vector<alphabet::Symbol> newRHS(secondSingleRHS); + newRHS.insert(newRHS.end(), singleRHS.begin() + 1, singleRHS.end()); + res.addRule(lhs, newRHS); + } + } + } + return res; +} + +grammar::EpsilonFreeCFG LeftRecursionRemover::remove(const grammar::EpsilonFreeCFG& origGrammar) { + grammar::EpsilonFreeCFG step = origGrammar; + unsigned i = 0; + while(i < origGrammar.getNonterminalAlphabet().size()) { + grammar::EpsilonFreeCFG nextStep = assignAsOrder(directLeftRecursionRemoveAsOrder(step), i, origGrammar.getNonterminalAlphabet()); + + if(step == nextStep) break; + step = std::move(nextStep); + i++; + }; + + return step; +} + +grammar::GNF LeftRecursionRemover::remove(const grammar::GNF& origGrammar) { + return origGrammar; +} + +grammar::RightRG LeftRecursionRemover::remove(const grammar::RightRG& origGrammar) { + return origGrammar; +} + +grammar::RightLG LeftRecursionRemover::remove(const grammar::RightLG& origGrammar) { + return origGrammar; +} + +grammar::RightRG LeftRecursionRemover::remove(const grammar::LeftRG& origGrammar) { + return convert::ToGrammarRightRG::convert(origGrammar); +} + +grammar::RightLG LeftRecursionRemover::remove(const grammar::LeftLG& origGrammar) { + // TODO +} + +grammar::Grammar LeftRecursionRemover::remove(const grammar::Grammar& grammar) { + grammar::Grammar* out = NULL; + grammar.getData().Accept((void*) &out, LeftRecursionRemover::LEFT_RECURSION_REMOVER); + grammar::Grammar res = std::move(*out); + delete out; + return res; +} + +void LeftRecursionRemover::Visit(void* data, const grammar::LeftLG& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->remove(grammar))); +} + +void LeftRecursionRemover::Visit(void* data, const grammar::LeftRG& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->remove(grammar))); +} + +void LeftRecursionRemover::Visit(void* data, const grammar::RightLG& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->remove(grammar))); +} + +void LeftRecursionRemover::Visit(void* data, const grammar::RightRG& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->remove(grammar))); +} + +void LeftRecursionRemover::Visit(void*, const grammar::LG&) const { + throw exception::AlibException("Unsupported grammar type LG"); +} + +void LeftRecursionRemover::Visit(void*, const grammar::CFG&) const { + throw exception::AlibException("Unsupported grammar type CFG"); +} + +void LeftRecursionRemover::Visit(void* data, const grammar::EpsilonFreeCFG& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->remove(grammar))); +} + +void LeftRecursionRemover::Visit(void*, const grammar::CNF&) const { + throw exception::AlibException("Unsupported grammar type CNF"); +} + +void LeftRecursionRemover::Visit(void* data, const grammar::GNF& grammar) const { + grammar::Grammar* & out = *((grammar::Grammar**) data); + out = new Grammar(std::move(this->remove(grammar))); +} + +void LeftRecursionRemover::Visit(void*, const grammar::CSG&) const { + throw exception::AlibException("Unsupported grammar type CSG"); +} + +void LeftRecursionRemover::Visit(void*, const grammar::NonContractingGrammar&) const { + throw exception::AlibException("Unsupported grammar type NonConctractingGrammar"); +} + +void LeftRecursionRemover::Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar&) const { + throw exception::AlibException("Unsupported grammar type ContextPreservingUnrestrictedGrammar"); +} + +void LeftRecursionRemover::Visit(void*, const grammar::UnrestrictedGrammar&) const { + throw exception::AlibException("Unsupported grammar type UnrestrictedGrammar"); +} + +const LeftRecursionRemover LeftRecursionRemover::LEFT_RECURSION_REMOVER; + +} /* namespace simplify */ + +} /* namespace grammar */ diff --git a/alib2algo/src/grammar/simplify/LeftRecursionRemover.h b/alib2algo/src/grammar/simplify/LeftRecursionRemover.h new file mode 100644 index 0000000000000000000000000000000000000000..d6a08689c7b3085e3bb2c7b76ef586b7adcda488 --- /dev/null +++ b/alib2algo/src/grammar/simplify/LeftRecursionRemover.h @@ -0,0 +1,63 @@ +/* + * LeftRecursionRemover.h + * + * Created on: 24. 11. 2014 + * Author: Jan Travnicek + */ + +#ifndef LEFT_RECURSION_REMOVER_H_ +#define LEFT_RECURSION_REMOVER_H_ + +#include <map> +#include <algorithm> + +#include <grammar/Grammar.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 simplify { + +class LeftRecursionRemover : public grammar::VisitableGrammarBase::const_visitor_type { +public: + static grammar::Grammar remove( const grammar::Grammar & grammar ); + + static grammar::EpsilonFreeCFG remove( const grammar::EpsilonFreeCFG & grammar ); + static grammar::GNF remove( const grammar::GNF & grammar ); + static grammar::RightRG remove( const grammar::RightRG & grammar ); + static grammar::RightLG remove( const grammar::RightLG & grammar ); + static grammar::RightRG remove( const grammar::LeftRG & grammar ); + static grammar::RightLG remove( const grammar::LeftLG & grammar ); +private: + void Visit(void*, const grammar::LeftLG& grammar) const; + void Visit(void*, const grammar::LeftRG& grammar) const; + void Visit(void*, const grammar::RightLG& grammar) const; + void Visit(void*, const grammar::RightRG& grammar) const; + void Visit(void*, const grammar::LG& grammar) const; + void Visit(void*, const grammar::CFG& grammar) const; + void Visit(void*, const grammar::EpsilonFreeCFG& grammar) const; + void Visit(void*, const grammar::CNF& grammar) const; + void Visit(void*, const grammar::GNF& grammar) const; + void Visit(void*, const grammar::CSG& grammar) const; + void Visit(void*, const grammar::NonContractingGrammar& grammar) const; + void Visit(void*, const grammar::ContextPreservingUnrestrictedGrammar& grammar) const; + void Visit(void*, const grammar::UnrestrictedGrammar& grammar) const; + + static const LeftRecursionRemover LEFT_RECURSION_REMOVER; +}; + +} /* namespace simplify */ + +} /* namespace grammar */ + +#endif /* LEFT_RECURSION_REMOVER_H_ */ diff --git a/alib2algo/test-src/grammar/simplify/GrammarLeftRecursionRemoverTest.cpp b/alib2algo/test-src/grammar/simplify/GrammarLeftRecursionRemoverTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c935e86f1aee1e46d7bd812d60b898b94d143281 --- /dev/null +++ b/alib2algo/test-src/grammar/simplify/GrammarLeftRecursionRemoverTest.cpp @@ -0,0 +1,186 @@ +#include "GrammarLeftRecursionRemoverTest.h" + +#include "grammar/simplify/LeftRecursionRemover.h" + +#include "grammar/ContextFree/CFG.h" +#include "grammar/ContextFree/EpsilonFreeCFG.h" + +#include <factory/StringDataFactory.hpp> + +#define CPPUNIT_IMPLY(x, y) CPPUNIT_ASSERT(!(x) || (y)) + +CPPUNIT_TEST_SUITE_REGISTRATION( GrammarLeftRecursionRemoverTest ); + +void GrammarLeftRecursionRemoverTest::setUp() { +} + +void GrammarLeftRecursionRemoverTest::tearDown() { +} + +void GrammarLeftRecursionRemoverTest::testRemoveEpsilonRules1() { + alphabet::Symbol S = alphabet::symbolFrom("S"); + alphabet::Symbol A = alphabet::symbolFrom("A"); + alphabet::Symbol B = alphabet::symbolFrom("B"); + alphabet::Symbol C = alphabet::symbolFrom("C"); + alphabet::Symbol D = alphabet::symbolFrom("D"); + + alphabet::Symbol a = alphabet::symbolFrom('a'); + alphabet::Symbol b = alphabet::symbolFrom('b'); + + grammar::EpsilonFreeCFG grammar1(S); + grammar1.setNonterminalAlphabet({S, A, B, C, D}); + grammar1.setTerminalAlphabet({a, b}); + + grammar::EpsilonFreeCFG grammar2 = grammar::simplify::LeftRecursionRemover::remove(grammar1); + + grammar::EpsilonFreeCFG grammar3(S); + grammar3.setNonterminalAlphabet({S, A, B, C, D}); + grammar3.setTerminalAlphabet({a, b}); + + CPPUNIT_ASSERT(grammar2 == grammar3); +} + +void GrammarLeftRecursionRemoverTest::testRemoveEpsilonRules2() { + alphabet::Symbol S = alphabet::symbolFrom("S"); + alphabet::Symbol A = alphabet::symbolFrom("A"); + alphabet::Symbol B = alphabet::symbolFrom("B"); + alphabet::Symbol C = alphabet::symbolFrom("C"); + alphabet::Symbol D = alphabet::symbolFrom("D"); + + alphabet::Symbol a = alphabet::symbolFrom('a'); + alphabet::Symbol b = alphabet::symbolFrom('b'); + alphabet::Symbol c = alphabet::symbolFrom('c'); + + grammar::EpsilonFreeCFG grammar1(S); + grammar1.setNonterminalAlphabet({S, A, B, C, D}); + grammar1.setTerminalAlphabet({a, b, c}); + grammar1.addRule(S, {A}); + grammar1.addRule(A, {A, a}); + grammar1.addRule(A, {A, b}); + grammar1.addRule(A, {c}); + + alphabet::Symbol Aprimed = createUniqueSymbol(A, grammar1.getTerminalAlphabet(), grammar1.getNonterminalAlphabet()); + + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar1)) << std::endl; + + grammar::EpsilonFreeCFG grammar2 = grammar::simplify::LeftRecursionRemover::remove(grammar1); + + grammar::EpsilonFreeCFG grammar3(S); + grammar3.setNonterminalAlphabet({S, A, Aprimed, B, C, D}); + grammar3.setTerminalAlphabet({a, b, c}); + grammar3.addRule(S, {c, Aprimed}); + grammar3.addRule(S, {c}); + grammar3.addRule(A, {c, Aprimed}); + grammar3.addRule(A, {c}); + grammar3.addRule(Aprimed, {a, Aprimed}); + grammar3.addRule(Aprimed, {a}); + grammar3.addRule(Aprimed, {b, Aprimed}); + grammar3.addRule(Aprimed, {b}); + + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar2)) << std::endl; + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar3)) << std::endl; + + CPPUNIT_ASSERT(grammar2 == grammar3); +} + +void GrammarLeftRecursionRemoverTest::testRemoveEpsilonRules3() { + alphabet::Symbol S = alphabet::symbolFrom("S"); + alphabet::Symbol A = alphabet::symbolFrom("A"); + alphabet::Symbol B = alphabet::symbolFrom("B"); + alphabet::Symbol C = alphabet::symbolFrom("C"); + + alphabet::Symbol a = alphabet::symbolFrom('a'); + alphabet::Symbol b = alphabet::symbolFrom('b'); + alphabet::Symbol c = alphabet::symbolFrom('c'); + + grammar::EpsilonFreeCFG grammar1(S); + grammar1.setNonterminalAlphabet({S, A, B, C}); + grammar1.setTerminalAlphabet({a, b, c}); + grammar1.addRule(S, {A}); + grammar1.addRule(A, {B, a}); + grammar1.addRule(B, {A, b}); + grammar1.addRule(A, {c}); + + alphabet::Symbol Bprimed = createUniqueSymbol(B, grammar1.getTerminalAlphabet(), grammar1.getNonterminalAlphabet()); + + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar1)) << std::endl; + + grammar::EpsilonFreeCFG grammar2 = grammar::simplify::LeftRecursionRemover::remove(grammar1); + + grammar::EpsilonFreeCFG grammar3(S); + grammar3.setNonterminalAlphabet({S, A, B, Bprimed, C}); + grammar3.setTerminalAlphabet({a, b, c}); + grammar3.addRule(S, {c}); + grammar3.addRule(S, {c, b, Bprimed, a}); + grammar3.addRule(S, {c, b, a}); + grammar3.addRule(A, {B, a}); + grammar3.addRule(A, {c}); + grammar3.addRule(B, {c, b}); + grammar3.addRule(B, {c, b, Bprimed}); + grammar3.addRule(Bprimed, {a, b, Bprimed}); + grammar3.addRule(Bprimed, {a, b}); + + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar2)) << std::endl; + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar3)) << std::endl; + + CPPUNIT_ASSERT(grammar2 == grammar3); +} + +void GrammarLeftRecursionRemoverTest::testRemoveEpsilonRules4() { + alphabet::Symbol A = alphabet::symbolFrom("A"); + alphabet::Symbol B = alphabet::symbolFrom("B"); + alphabet::Symbol C = alphabet::symbolFrom("C"); + + alphabet::Symbol a = alphabet::symbolFrom('a'); + alphabet::Symbol b = alphabet::symbolFrom('b'); + + grammar::EpsilonFreeCFG grammar1(A); + grammar1.setNonterminalAlphabet({A, B, C}); + grammar1.setTerminalAlphabet({a, b}); + grammar1.addRule(A, {B, C}); + grammar1.addRule(A, {a}); + grammar1.addRule(B, {C, A}); + grammar1.addRule(B, {A, b}); + grammar1.addRule(C, {A, B}); + grammar1.addRule(C, {C, C}); + grammar1.addRule(C, {a}); + + alphabet::Symbol Bprimed = createUniqueSymbol(B, grammar1.getTerminalAlphabet(), grammar1.getNonterminalAlphabet()); + alphabet::Symbol Cprimed = createUniqueSymbol(C, grammar1.getTerminalAlphabet(), grammar1.getNonterminalAlphabet()); + + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar1)) << std::endl; + + grammar::EpsilonFreeCFG grammar2 = grammar::simplify::LeftRecursionRemover::remove(grammar1); + + grammar::EpsilonFreeCFG grammar3(A); + grammar3.setNonterminalAlphabet({A, B, Bprimed, C, Cprimed}); + grammar3.setTerminalAlphabet({a, b}); + grammar3.addRule(A, {B, C}); + grammar3.addRule(A, {a}); + grammar3.addRule(B, {C, A}); + grammar3.addRule(B, {a, b}); + grammar3.addRule(B, {C, A, Bprimed}); + grammar3.addRule(B, {a, b, Bprimed}); + grammar3.addRule(Bprimed, {C, b, Bprimed}); + grammar3.addRule(Bprimed, {C, b}); + grammar3.addRule(C, {a, b, C, B}); + grammar3.addRule(C, {a, b, Bprimed, C, B}); + grammar3.addRule(C, {a, B}); + grammar3.addRule(C, {a}); + grammar3.addRule(C, {a, b, C, B, Cprimed}); + grammar3.addRule(C, {a, b, Bprimed, C, B, Cprimed}); + grammar3.addRule(C, {a, B, Cprimed}); + grammar3.addRule(C, {a, Cprimed}); + grammar3.addRule(Cprimed, {A, C, B, Cprimed}); + grammar3.addRule(Cprimed, {A, Bprimed, C, B, Cprimed}); + grammar3.addRule(Cprimed, {C, Cprimed}); + grammar3.addRule(Cprimed, {A, C, B}); + grammar3.addRule(Cprimed, {A, Bprimed, C, B}); + grammar3.addRule(Cprimed, {C}); + + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar2)) << std::endl; + std::cout << alib::StringDataFactory::toString<grammar::Grammar>(grammar::Grammar(grammar3)) << std::endl; + + CPPUNIT_ASSERT(grammar2 == grammar3); +} + diff --git a/alib2algo/test-src/grammar/simplify/GrammarLeftRecursionRemoverTest.h b/alib2algo/test-src/grammar/simplify/GrammarLeftRecursionRemoverTest.h new file mode 100644 index 0000000000000000000000000000000000000000..2988cb8f4b182fa865fffff9619e268fd1d52f0b --- /dev/null +++ b/alib2algo/test-src/grammar/simplify/GrammarLeftRecursionRemoverTest.h @@ -0,0 +1,25 @@ +#ifndef GRAMMAR_EPSILON_REMOVER_TEST_H_ +#define GRAMMAR_EPSILON_REMOVER_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class GrammarLeftRecursionRemoverTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( GrammarLeftRecursionRemoverTest ); + CPPUNIT_TEST( testRemoveEpsilonRules1 ); + CPPUNIT_TEST( testRemoveEpsilonRules2 ); + CPPUNIT_TEST( testRemoveEpsilonRules3 ); + CPPUNIT_TEST( testRemoveEpsilonRules4 ); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp(); + void tearDown(); + + void testRemoveEpsilonRules1(); + void testRemoveEpsilonRules2(); + void testRemoveEpsilonRules3(); + void testRemoveEpsilonRules4(); +}; + +#endif /* GRAMMAR_EPSILON_REMOVER_TEST_H_ */ diff --git a/alib2data/src/alphabet/Symbol.h b/alib2data/src/alphabet/Symbol.h index eac937b86e8c54ad0ce80592c2aa92192fbc2a98..6b7883c14ba2f92a477cd0c5fadbce7c389f4577 100644 --- a/alib2data/src/alphabet/Symbol.h +++ b/alib2data/src/alphabet/Symbol.h @@ -30,7 +30,7 @@ typedef alib::wrapper<SymbolBase> Symbol; * @throws AutomatonException if symbol could not be created * @return created symbol */ -alphabet::Symbol createUniqueSymbol(const alphabet::Symbol& base, const std::set<alphabet::Symbol>& Terminals, const std::set<alphabet::Symbol>& nonterminals); +alphabet::Symbol createUniqueSymbol(const alphabet::Symbol& base, const std::set<alphabet::Symbol>& terminals, const std::set<alphabet::Symbol>& nonterminals); alphabet::Symbol symbolFrom(int number); alphabet::Symbol symbolFrom(char character); diff --git a/alib2data/src/common/base.hpp b/alib2data/src/common/base.hpp index 4e13245d96d180d5972a8473a9832b9074916b0a..e6e86ab01dd4baa57cb66d66b6dabb2579aaf24e 100644 --- a/alib2data/src/common/base.hpp +++ b/alib2data/src/common/base.hpp @@ -88,10 +88,18 @@ public: return this->compare(other) < 0; } + bool operator<=(const T& other) const { + return this->compare(other) <= 0; + } + bool operator>(const T& other) const { return this->compare(other) > 0; } + bool operator>=(const T& other) const { + return this->compare(other) >= 0; + } + virtual int compare(const T& other) const = 0; friend std::ostream& operator<<(std::ostream& os, const T& instance) {