diff --git a/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.cpp b/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.cpp index cccf6eca7c41401d9c55417e794bf497fb7a062a..d0facd7c198874b447527027449e146c680b2879 100644 --- a/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.cpp +++ b/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.cpp @@ -64,17 +64,8 @@ bool EpsilonFreeCFG::removeNonterminalSymbol(const alphabet::Symbol& symbol) { bool EpsilonFreeCFG::addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { int rSize = rightHandSide.size(); - if(leftHandSide == initialSymbol && rSize == 0) { - for(const auto& rule : rules) { - for(const auto& ruleRHS : rule.second) { - if(any_of(ruleRHS.begin(), ruleRHS.end(), [&](const alphabet::Symbol& symbol) { return initialSymbol == symbol; })) { - throw GrammarException("Initial symbol " + (std::string) initialSymbol + "used on right hand side of already existing rule"); - } - } - } - - generatesEpsilon = true; - return rules[leftHandSide].insert(rightHandSide).second; + if(rSize == 0) { + throw GrammarException("Epsilon rule is not allowed"); } else { if(!nonterminalAlphabet.count(leftHandSide)) throw GrammarException("Rule must rewrite nonterminal symbol"); @@ -82,8 +73,6 @@ bool EpsilonFreeCFG::addRule(const alphabet::Symbol& leftHandSide, const std::ve for(const alphabet::Symbol& symbol : rightHandSide) { if(terminalAlphabet.find(symbol) == terminalAlphabet.end() && nonterminalAlphabet.find(symbol) == nonterminalAlphabet.end()) throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is not neither terminal nor nonterminal symbol"); - if(generatesEpsilon && symbol == initialSymbol) - throw GrammarException("Initial symbol is already allowed to be rewritten to epsilon"); } return rules[leftHandSide].insert(rightHandSide).second; @@ -95,20 +84,23 @@ const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> Epsilo } bool EpsilonFreeCFG::removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { - int rSize = rightHandSide.size(); - - if(leftHandSide == initialSymbol && rSize == 0) { - generatesEpsilon = false; - } return rules[leftHandSide].erase(rightHandSide); } +void EpsilonFreeCFG::setGeneratesEpsilon(bool genEps) { + generatesEpsilon = genEps; +} + +bool EpsilonFreeCFG::getGeneratesEpsilon() const { + return generatesEpsilon; +} + bool EpsilonFreeCFG::operator==(const GrammarBase& other) const { return other == *this; } bool EpsilonFreeCFG::operator==(const EpsilonFreeCFG& other) const { - return this->nonterminalAlphabet == other.nonterminalAlphabet && this->terminalAlphabet == other.terminalAlphabet && this->initialSymbol == other.initialSymbol && this->rules == other.rules; + return this->nonterminalAlphabet == other.nonterminalAlphabet && this->terminalAlphabet == other.terminalAlphabet && this->initialSymbol == other.initialSymbol && this->rules == other.rules && this->generatesEpsilon == other.generatesEpsilon; } void EpsilonFreeCFG::operator>>(std::ostream& out) const { @@ -117,6 +109,7 @@ void EpsilonFreeCFG::operator>>(std::ostream& out) const { << "terminalAlphabet = " << terminalAlphabet << "initialSymbol = " << initialSymbol << "rules = " << rules + << "generatesEpsilon = " << generatesEpsilon << ")"; } diff --git a/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.h b/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.h index 44d31bd50dd2cf20463586823d26521f2972f529..149d0c65ed7304a0d262513289e712d2d07ee07f 100644 --- a/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.h +++ b/alib2data/src/grammar/ContextFree/EpsilonFreeCFG.h @@ -40,6 +40,9 @@ public: bool removeNonterminalSymbol(const alphabet::Symbol& symbol); + void setGeneratesEpsilon(bool genEps); + bool getGeneratesEpsilon() const; + virtual bool operator==(const GrammarBase& other) const; virtual bool operator==(const EpsilonFreeCFG& other) const; diff --git a/alib2data/src/grammar/GrammarFromXMLParser.cpp b/alib2data/src/grammar/GrammarFromXMLParser.cpp index ede304e5002ccf09a7a80fef9db42eeaef051fda..72727df7e7af493794aa93efc071d9c42648a9a1 100644 --- a/alib2data/src/grammar/GrammarFromXMLParser.cpp +++ b/alib2data/src/grammar/GrammarFromXMLParser.cpp @@ -211,6 +211,9 @@ EpsilonFreeCFG GrammarFromXMLParser::parseEpsilonFreeCFG(std::list<sax::Token>& parseRules(input, grammar); + bool generatesEpsilon = parseGeneratesEpsilon(input); + grammar.setGeneratesEpsilon(generatesEpsilon); + popToken(input, sax::Token::TokenType::END_ELEMENT, "EpsilonFreeCFG"); return grammar; } diff --git a/alib2data/src/grammar/GrammarToXMLComposer.cpp b/alib2data/src/grammar/GrammarToXMLComposer.cpp index e87ff418fbc5c681d614160eee512889123c2010..a012f95cf991a1cbcf0bd2a1ef46ddeed19f8f16 100644 --- a/alib2data/src/grammar/GrammarToXMLComposer.cpp +++ b/alib2data/src/grammar/GrammarToXMLComposer.cpp @@ -126,6 +126,7 @@ std::list<sax::Token> GrammarToXMLComposer::compose(const EpsilonFreeCFG& gramma composeTerminalAlphabet(out, grammar.getTerminalAlphabet()); composeInitialSymbol(out, grammar.getInitialSymbol()); composeRules(out, grammar); + composeGeneratesEpsilon(out, grammar.getGeneratesEpsilon()); out.push_back(sax::Token("EpsilonFreeCFG", sax::Token::TokenType::END_ELEMENT)); return out; diff --git a/alib2data/test-src/grammar/GrammarTest.cpp b/alib2data/test-src/grammar/GrammarTest.cpp index d3dbb5fc62203c14d778a42fd33f5cfb1f466b81..bf3bffea275fc5e6fa27fe93cc01ae484660fd8c 100644 --- a/alib2data/test-src/grammar/GrammarTest.cpp +++ b/alib2data/test-src/grammar/GrammarTest.cpp @@ -170,6 +170,36 @@ void GrammarTest::testContextFreeParser() { grammar::GrammarFromXMLParser parser; grammar::LG grammar2 = parser.parseLG(tokens2); + CPPUNIT_ASSERT( grammar == grammar2 ); + } + } + { + grammar::EpsilonFreeCFG grammar(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(1))))); + + grammar.addNonterminalSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(1))))); + grammar.addNonterminalSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(2))))); + grammar.addNonterminalSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(3))))); + grammar.addTerminalSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("a"))))); + grammar.addTerminalSymbol(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("b"))))); + grammar.setGeneratesEpsilon(true); + + grammar.addRule(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(1)))), std::vector<alphabet::Symbol> {alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("a")))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(2))))}); + grammar.addRule(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(2)))), std::vector<alphabet::Symbol> {alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("b")))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(3))))}); + grammar.addRule(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(1)))), std::vector<alphabet::Symbol> {alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(3))))}); + grammar.addRule(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(1)))), std::vector<alphabet::Symbol> {alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("a")))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("a")))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("a")))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(2))))}); + + CPPUNIT_ASSERT( grammar == grammar ); + { + grammar::GrammarToXMLComposer composer; + std::list<sax::Token> tokens = composer.compose(grammar); + std::string tmp; + sax::SaxComposeInterface::printMemory(tmp, tokens); + + std::list<sax::Token> tokens2; + sax::SaxParseInterface::parseMemory(tmp, tokens2); + grammar::GrammarFromXMLParser parser; + grammar::EpsilonFreeCFG grammar2 = parser.parseEpsilonFreeCFG(tokens2); + CPPUNIT_ASSERT( grammar == grammar2 ); } }