diff --git a/alib2data/src/grammar/GrammarFromXMLParser.cpp b/alib2data/src/grammar/GrammarFromXMLParser.cpp index cd0e84d9635762e44358494c781cf2ba01033e18..8f57b7b443324ef9e3629d2cffdf12a3cb3ddc0e 100644 --- a/alib2data/src/grammar/GrammarFromXMLParser.cpp +++ b/alib2data/src/grammar/GrammarFromXMLParser.cpp @@ -270,7 +270,7 @@ RightRG GrammarFromXMLParser::parseRightRG(std::list<sax::Token>& input) const { } RightLG GrammarFromXMLParser::parseRightLG(std::list<sax::Token>& input) const { - popToken(input, sax::Token::TokenType::START_ELEMENT, "LeftLG"); + popToken(input, sax::Token::TokenType::START_ELEMENT, "RightLG"); std::set<alphabet::Symbol> nonterminalAlphabet = parseNonterminalAlphabet(input); std::set<alphabet::Symbol> terminalAlphabet = parseTerminalAlphabet(input); @@ -457,7 +457,7 @@ void GrammarFromXMLParser::parseRule(std::list<sax::Token>& input, RightRG& gram void GrammarFromXMLParser::parseRule(std::list<sax::Token>& input, RightLG& grammar) const { alphabet::Symbol lhs = parseRuleSingleSymbolLHS(input); std::vector<alphabet::Symbol> rhs = parseRuleRHS(input); - grammar.addRule(lhs, rhs); + grammar.addRawRule(lhs, rhs); } void GrammarFromXMLParser::parseRule(std::list<sax::Token>& input, LeftRG& grammar) const { @@ -469,14 +469,17 @@ void GrammarFromXMLParser::parseRule(std::list<sax::Token>& input, LeftRG& gramm void GrammarFromXMLParser::parseRule(std::list<sax::Token>& input, LeftLG& grammar) const { alphabet::Symbol lhs = parseRuleSingleSymbolLHS(input); std::vector<alphabet::Symbol> rhs = parseRuleRHS(input); - grammar.addRule(lhs, rhs); + grammar.addRawRule(lhs, rhs); } std::vector<alphabet::Symbol> GrammarFromXMLParser::parseRuleLHS(std::list<sax::Token>& input) const { std::vector<alphabet::Symbol> lhs; popToken(input, sax::Token::TokenType::START_ELEMENT, "lhs"); - while (isTokenType(input, sax::Token::TokenType::START_ELEMENT)) { + if(isToken(input, sax::Token::TokenType::START_ELEMENT, "epsilon")) { + input.pop_front(); + popToken(input, sax::Token::TokenType::END_ELEMENT, "epsilon"); + } else while (isTokenType(input, sax::Token::TokenType::START_ELEMENT)) { lhs.push_back(alib::FromXMLParsers::symbolParser.parse(input)); } popToken(input, sax::Token::TokenType::END_ELEMENT, "lhs"); @@ -493,7 +496,10 @@ alphabet::Symbol GrammarFromXMLParser::parseRuleSingleSymbolLHS(std::list<sax::T std::vector<alphabet::Symbol> GrammarFromXMLParser::parseRuleRHS(std::list<sax::Token>& input) const { std::vector<alphabet::Symbol> rhs; popToken(input, sax::Token::TokenType::START_ELEMENT, "rhs"); - while (isTokenType(input, sax::Token::TokenType::START_ELEMENT)) { + if(isToken(input, sax::Token::TokenType::START_ELEMENT, "epsilon")) { + input.pop_front(); + popToken(input, sax::Token::TokenType::END_ELEMENT, "epsilon"); + } else while (isTokenType(input, sax::Token::TokenType::START_ELEMENT)) { rhs.push_back(alib::FromXMLParsers::symbolParser.parse(input)); } popToken(input, sax::Token::TokenType::END_ELEMENT, "rhs"); diff --git a/alib2data/src/grammar/GrammarToXMLComposer.cpp b/alib2data/src/grammar/GrammarToXMLComposer.cpp index f76dcce81d698138106f2b3df667aef73e38ed13..d3f2e027a53224d4d39d7e6c95604d346c940b66 100644 --- a/alib2data/src/grammar/GrammarToXMLComposer.cpp +++ b/alib2data/src/grammar/GrammarToXMLComposer.cpp @@ -422,7 +422,7 @@ void GrammarToXMLComposer::composeRules(std::list<sax::Token>& out, const RightL out.push_back(sax::Token("rule", sax::Token::TokenType::START_ELEMENT)); composeRuleSingleSymbolLHS(out, rule.first); - composeRuleRHS(out, rhs); + composeRuleRightLGRHS(out, rhs); out.push_back(sax::Token("rule", sax::Token::TokenType::END_ELEMENT)); } @@ -456,7 +456,7 @@ void GrammarToXMLComposer::composeRules(std::list<sax::Token>& out, const LeftLG out.push_back(sax::Token("rule", sax::Token::TokenType::START_ELEMENT)); composeRuleSingleSymbolLHS(out, rule.first); - composeRuleRHS(out, rhs); + composeRuleLeftLGRHS(out, rhs); out.push_back(sax::Token("rule", sax::Token::TokenType::END_ELEMENT)); } @@ -516,6 +516,50 @@ void GrammarToXMLComposer::composeRuleOneOrTwoSymbolsRHS(std::list<sax::Token>& out.push_back(sax::Token("rhs", sax::Token::TokenType::END_ELEMENT)); } +void GrammarToXMLComposer::composeRuleLeftLGRHS(std::list<sax::Token>& out, const std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>>& symbols) const { + out.push_back(sax::Token("rhs", sax::Token::TokenType::START_ELEMENT)); + if(symbols.is<std::vector<alphabet::Symbol>>()) { + const std::vector<alphabet::Symbol>& rhs = symbols.get<std::vector<alphabet::Symbol>>(); + if(rhs.size() == 0) { + out.push_back(sax::Token("epsilon", sax::Token::TokenType::START_ELEMENT)); + out.push_back(sax::Token("epsilon", sax::Token::TokenType::END_ELEMENT)); + } else { + for (const auto& symbol : symbols.get<std::vector<alphabet::Symbol>>()) { + out.splice(out.end(), alib::ToXMLComposers::symbolComposer.compose(symbol)); + } + } + } else { + const std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>& rhs = symbols.get<std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>>(); + out.splice(out.end(), alib::ToXMLComposers::symbolComposer.compose(rhs.first)); + for (const auto& symbol : rhs.second) { + out.splice(out.end(), alib::ToXMLComposers::symbolComposer.compose(symbol)); + } + } + out.push_back(sax::Token("rhs", sax::Token::TokenType::END_ELEMENT)); +} + +void GrammarToXMLComposer::composeRuleRightLGRHS(std::list<sax::Token>& out, const std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>>& symbols) const { + out.push_back(sax::Token("rhs", sax::Token::TokenType::START_ELEMENT)); + if(symbols.is<std::vector<alphabet::Symbol>>()) { + const std::vector<alphabet::Symbol>& rhs = symbols.get<std::vector<alphabet::Symbol>>(); + if(rhs.size() == 0) { + out.push_back(sax::Token("epsilon", sax::Token::TokenType::START_ELEMENT)); + out.push_back(sax::Token("epsilon", sax::Token::TokenType::END_ELEMENT)); + } else { + for (const auto& symbol : symbols.get<std::vector<alphabet::Symbol>>()) { + out.splice(out.end(), alib::ToXMLComposers::symbolComposer.compose(symbol)); + } + } + } else { + const std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>& rhs = symbols.get<std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>>(); + for (const auto& symbol : rhs.first) { + out.splice(out.end(), alib::ToXMLComposers::symbolComposer.compose(symbol)); + } + out.splice(out.end(), alib::ToXMLComposers::symbolComposer.compose(rhs.second)); + } + out.push_back(sax::Token("rhs", sax::Token::TokenType::END_ELEMENT)); +} + std::list<sax::Token> GrammarToXMLComposer::compose(const Grammar& grammar) const { std::list<sax::Token> out; grammar.getGrammar().Accept((void*) &out, *this); diff --git a/alib2data/src/grammar/GrammarToXMLComposer.h b/alib2data/src/grammar/GrammarToXMLComposer.h index 1d501d8b15144085b53a5c859e7548944d1b6332..32268126b1d3b978d0eed0f223f6f3a8d710f442 100644 --- a/alib2data/src/grammar/GrammarToXMLComposer.h +++ b/alib2data/src/grammar/GrammarToXMLComposer.h @@ -73,6 +73,8 @@ class GrammarToXMLComposer : public GrammarBase::const_visitor_type { void composeRuleSingleSymbolLHS(std::list<sax::Token>& out, const alphabet::Symbol& symbol) const; void composeRuleRHS(std::list<sax::Token>& out, const std::vector<alphabet::Symbol>& symbols) const; void composeRuleOneOrTwoSymbolsRHS(std::list<sax::Token>& out, const std::variant<alphabet::Symbol, std::pair<alphabet::Symbol, alphabet::Symbol>>& symbols) const; + void composeRuleLeftLGRHS(std::list<sax::Token>& out, const std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>>& symbols) const; + void composeRuleRightLGRHS(std::list<sax::Token>& out, const std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>>& symbols) const; public: /** * Prints XML representation of UnknownGrammar to the output stream. diff --git a/alib2data/src/grammar/Regular/LeftLG.cpp b/alib2data/src/grammar/Regular/LeftLG.cpp index 7c35514090f5e8de90e0fc059ef93c91bb90e010..29db7f37bcdb2550af219ee3b00b4c433197a867 100644 --- a/alib2data/src/grammar/Regular/LeftLG.cpp +++ b/alib2data/src/grammar/Regular/LeftLG.cpp @@ -32,26 +32,39 @@ GrammarBase* LeftLG::plunder() && { } bool LeftLG::removeTerminalSymbol(const alphabet::Symbol& symbol) { - for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : rules) { + for(const std::pair<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >> >& rule : rules) { if(rule.first == symbol) throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); - for(const std::vector<alphabet::Symbol>& rhs : rule.second) - if(std::find(rhs.begin(), rhs.end(), symbol) != rhs.end()) - throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + for(const std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >& rhsTmp : rule.second) + if(rhsTmp.is<std::vector<alphabet::Symbol>>()) { + const std::vector<alphabet::Symbol>& rhs = rhsTmp.get<std::vector<alphabet::Symbol>>(); + + if(std::find(rhs.begin(), rhs.end(), symbol) != rhs.end()) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + } else { + const std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>& rhs = rhsTmp.get<std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>>(); + + if(std::find(rhs.second.begin(), rhs.second.end(), symbol) != rhs.second.end()) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + } } return terminalAlphabet.erase(symbol); } bool LeftLG::removeNonterminalSymbol(const alphabet::Symbol& symbol) { - for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : rules) { + for(const std::pair<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >> >& rule : rules) { if(rule.first == symbol) throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); - for(const std::vector<alphabet::Symbol>& rhs : rule.second) - if(std::find(rhs.begin(), rhs.end(), symbol) != rhs.end()) - throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + for(const std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >& rhsTmp : rule.second) + if(rhsTmp.is<std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>>()) { + const std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>& rhs = rhsTmp.get<std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>>(); + + if(rhs.first == symbol) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + } } if(initialSymbol == symbol) @@ -61,31 +74,71 @@ bool LeftLG::removeNonterminalSymbol(const alphabet::Symbol& symbol) { return nonterminalAlphabet.erase(symbol); } -bool LeftLG::addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { +bool LeftLG::addRule(const alphabet::Symbol& leftHandSide, const std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >& rightHandSide) { if(!nonterminalAlphabet.count(leftHandSide)) throw GrammarException("Rule must rewrite nonterminal symbol"); - std::vector<alphabet::Symbol>::const_iterator iter = rightHandSide.begin(); - if(iter == rightHandSide.end()) return rules[leftHandSide].insert(rightHandSide).second; + if(rightHandSide.is<std::vector<alphabet::Symbol>>()) { + const std::vector<alphabet::Symbol>& rhs = rightHandSide.get<std::vector<alphabet::Symbol>>(); + for(const auto & symbol : rhs ) { + if(terminalAlphabet.find(symbol) == terminalAlphabet.end()) + throw GrammarException("Symbol " + (std::string) symbol.getSymbol() + " is not a terminal symbol"); + } + + return rules[leftHandSide].insert(rightHandSide).second; + } else { + const std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>& rhs = rightHandSide.get<std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>>(); - if(nonterminalAlphabet.find(*iter) != nonterminalAlphabet.end() && terminalAlphabet.find(*iter) != terminalAlphabet.end()) throw GrammarException("Symbol " + (std::string) iter->getSymbol() + " is not a terminal nor nonterminal symbol"); - iter++; + if(nonterminalAlphabet.find(rhs.first) == nonterminalAlphabet.end()) + throw GrammarException("Symbol " + (std::string) rhs.first.getSymbol() + " is not a nonterminal symbol"); - for(; iter != rightHandSide.end() && terminalAlphabet.find(*iter) != terminalAlphabet.end(); iter++); + for(const auto & symbol : rhs.second ) { + if(terminalAlphabet.find(symbol) == terminalAlphabet.end()) + throw GrammarException("Symbol " + (std::string) symbol.getSymbol() + " is not a terminal symbol"); + } - if(iter == rightHandSide.end()) return rules[leftHandSide].insert(rightHandSide).second; + return rules[leftHandSide].insert(rightHandSide).second; + } +} + +bool LeftLG::addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> > rhs(rightHandSide); + return addRule(leftHandSide, rhs); +} - throw GrammarException("Symbol " + (std::string) iter->getSymbol() + " is not a terminal symbol"); +bool LeftLG::addRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>& rightHandSide) { + std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> > rhs(rightHandSide); + return addRule(leftHandSide, rhs); } -const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> LeftLG::getRules() const { +bool LeftLG::addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + return addRule(leftHandSide, rightHandSide); + } else if(nonterminalAlphabet.count(rightHandSide[0])) { + return addRule(leftHandSide, std::make_pair(rightHandSide[0], std::vector<alphabet::Symbol>(rightHandSide.begin() + 1, rightHandSide.end()))); + } else { + return addRule(leftHandSide, rightHandSide); + } +} + +const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >> > LeftLG::getRules() const { return rules; } -bool LeftLG::removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { +bool LeftLG::removeRule(const alphabet::Symbol& leftHandSide, const std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >& rightHandSide) { return rules[leftHandSide].erase(rightHandSide); } +bool LeftLG::removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> > rhs(rightHandSide); + return removeRule(leftHandSide, rhs); +} + +bool LeftLG::removeRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>& rightHandSide) { + std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> > rhs(rightHandSide); + return removeRule(leftHandSide, rhs); +} + bool LeftLG::operator==(const GrammarBase& other) const { return other == *this; } diff --git a/alib2data/src/grammar/Regular/LeftLG.h b/alib2data/src/grammar/Regular/LeftLG.h index 8127000f7fd1641472df4ece06d41fd134710178..b251bb09c2edb9f112aef7f67ac07bea5c55e206 100644 --- a/alib2data/src/grammar/Regular/LeftLG.h +++ b/alib2data/src/grammar/Regular/LeftLG.h @@ -11,6 +11,7 @@ #include "../GrammarBase.h" #include <map> #include <vector> +#include "../../std/variant.hpp" #include "../common/TerminalNonterminalAlphabetInitialSymbol.h" namespace grammar { @@ -19,7 +20,7 @@ namespace grammar { * Left linear grammar in chomsky normal form. Type 3 in Chomsky hierarchy. Produces regular languages. */ class LeftLG : public std::element<LeftLG, GrammarBase>, public TerminalNonterminalAlphabetInitialSymbol { - std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> rules; + std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >> > rules; public: LeftLG(const alphabet::Symbol& initialSymbol); @@ -29,11 +30,17 @@ public: virtual GrammarBase* plunder() &&; + bool addRule(const alphabet::Symbol& leftHandSide, const std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >& rightHandSide); bool addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + bool addRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>& rightHandSide); - const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRules() const; + bool addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >> > getRules() const; + + bool removeRule(const alphabet::Symbol& leftHandSide, const std::variant<std::vector<alphabet::Symbol>, std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>> >& rightHandSide); bool removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + bool removeRule(const alphabet::Symbol& leftHandSide, const std::pair<alphabet::Symbol, std::vector<alphabet::Symbol>>& rightHandSide); bool removeTerminalSymbol(const alphabet::Symbol& symbol); diff --git a/alib2data/src/grammar/Regular/RightLG.cpp b/alib2data/src/grammar/Regular/RightLG.cpp index 39a4da54ffda217c1d6dfdb2e7312786371b93b5..a124a0151a299a218c8ecc0502472f2798d4df35 100644 --- a/alib2data/src/grammar/Regular/RightLG.cpp +++ b/alib2data/src/grammar/Regular/RightLG.cpp @@ -32,26 +32,39 @@ GrammarBase* RightLG::plunder() && { } bool RightLG::removeTerminalSymbol(const alphabet::Symbol& symbol) { - for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : rules) { + for(const std::pair<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >> >& rule : rules) { if(rule.first == symbol) throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); - for(const std::vector<alphabet::Symbol>& rhs : rule.second) - if(std::find(rhs.begin(), rhs.end(), symbol) != rhs.end()) - throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + for(const std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >& rhsTmp : rule.second) + if(rhsTmp.is<std::vector<alphabet::Symbol>>()) { + const std::vector<alphabet::Symbol>& rhs = rhsTmp.get<std::vector<alphabet::Symbol>>(); + + if(std::find(rhs.begin(), rhs.end(), symbol) != rhs.end()) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + } else { + const std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>& rhs = rhsTmp.get<std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>>(); + + if(std::find(rhs.first.begin(), rhs.first.end(), symbol) != rhs.first.end()) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + } } return terminalAlphabet.erase(symbol); } bool RightLG::removeNonterminalSymbol(const alphabet::Symbol& symbol) { - for(const std::pair<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>>& rule : rules) { + for(const std::pair<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >> >& rule : rules) { if(rule.first == symbol) throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); - for(const std::vector<alphabet::Symbol>& rhs : rule.second) - if(std::find(rhs.begin(), rhs.end(), symbol) != rhs.end()) - throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + for(const std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >& rhsTmp : rule.second) + if(rhsTmp.is<std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>>()) { + const std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>& rhs = rhsTmp.get<std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>>(); + + if(rhs.second == symbol) + throw GrammarException("Symbol \"" + (std::string) symbol.getSymbol() + "\" is used in rule."); + } } if(initialSymbol == symbol) @@ -61,31 +74,71 @@ bool RightLG::removeNonterminalSymbol(const alphabet::Symbol& symbol) { return nonterminalAlphabet.erase(symbol); } -bool RightLG::addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { +bool RightLG::addRule(const alphabet::Symbol& leftHandSide, const std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >& rightHandSide) { if(!nonterminalAlphabet.count(leftHandSide)) throw GrammarException("Rule must rewrite nonterminal symbol"); - std::vector<alphabet::Symbol>::const_iterator iter = rightHandSide.begin(); - for(; iter != rightHandSide.end() && terminalAlphabet.find(*iter) != terminalAlphabet.end(); iter++); + if(rightHandSide.is<std::vector<alphabet::Symbol>>()) { + const std::vector<alphabet::Symbol>& rhs = rightHandSide.get<std::vector<alphabet::Symbol>>(); + for(const auto & symbol : rhs ) { + if(terminalAlphabet.find(symbol) == terminalAlphabet.end()) + throw GrammarException("Symbol " + (std::string) symbol.getSymbol() + " is not a terminal symbol"); + } + + return rules[leftHandSide].insert(rightHandSide).second; + } else { + const std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>& rhs = rightHandSide.get<std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>>(); - if(iter == rightHandSide.end()) return rules[leftHandSide].insert(rightHandSide).second; + if(nonterminalAlphabet.find(rhs.second) == nonterminalAlphabet.end()) + throw GrammarException("Symbol " + (std::string) rhs.second.getSymbol() + " is not a nonterminal symbol"); - if(nonterminalAlphabet.find(*iter) == nonterminalAlphabet.end()) throw GrammarException("Symbol " + (std::string) iter->getSymbol() + " is not a terminal nor nonterminal symbol"); - iter++; + for(const auto & symbol : rhs.first ) { + if(terminalAlphabet.find(symbol) == terminalAlphabet.end()) + throw GrammarException("Symbol " + (std::string) symbol.getSymbol() + " is not a terminal symbol"); + } - if(iter == rightHandSide.end()) return rules[leftHandSide].insert(rightHandSide).second; + return rules[leftHandSide].insert(rightHandSide).second; + } +} + +bool RightLG::addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> > rhs(rightHandSide); + return addRule(leftHandSide, rhs); +} - throw GrammarException("Symbol " + (std::string) iter->getSymbol() + " is not a terminal symbol"); +bool RightLG::addRule(const alphabet::Symbol& leftHandSide, const std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>& rightHandSide) { + std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> > rhs(rightHandSide); + return addRule(leftHandSide, rhs); } -const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> RightLG::getRules() const { +bool RightLG::addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + if(rightHandSide.size() == 0) { + return addRule(leftHandSide, rightHandSide); + } else if(nonterminalAlphabet.count(rightHandSide[rightHandSide.size() - 1])) { + return addRule(leftHandSide, std::make_pair(std::vector<alphabet::Symbol>(rightHandSide.begin(), rightHandSide.end() - 1), rightHandSide[rightHandSide.size() - 1])); + } else { + return addRule(leftHandSide, rightHandSide); + } +} + +const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >> > RightLG::getRules() const { return rules; } -bool RightLG::removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { +bool RightLG::removeRule(const alphabet::Symbol& leftHandSide, const std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >& rightHandSide) { return rules[leftHandSide].erase(rightHandSide); } +bool RightLG::removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide) { + std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> > rhs(rightHandSide); + return removeRule(leftHandSide, rhs); +} + +bool RightLG::removeRule(const alphabet::Symbol& leftHandSide, const std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>& rightHandSide) { + std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> > rhs(rightHandSide); + return removeRule(leftHandSide, rhs); +} + bool RightLG::operator==(const GrammarBase& other) const { return other == *this; } diff --git a/alib2data/src/grammar/Regular/RightLG.h b/alib2data/src/grammar/Regular/RightLG.h index 9cba0827f4e0d648d9fc817ba7f48288ca8b3059..3446bf5774c64cdb92fa3a2468a21ad5a231a153 100644 --- a/alib2data/src/grammar/Regular/RightLG.h +++ b/alib2data/src/grammar/Regular/RightLG.h @@ -11,6 +11,7 @@ #include "../GrammarBase.h" #include <map> #include <vector> +#include "../../std/variant.hpp" #include "../common/TerminalNonterminalAlphabetInitialSymbol.h" namespace grammar { @@ -19,7 +20,7 @@ namespace grammar { * Right linear grammar in chomsky normal form. Type 3 in Chomsky hierarchy. Produces regular languages. */ class RightLG : public std::element<RightLG, GrammarBase>, public TerminalNonterminalAlphabetInitialSymbol { - std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> rules; + std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >> > rules; public: RightLG(const alphabet::Symbol& initialSymbol); @@ -29,11 +30,17 @@ public: virtual GrammarBase* plunder() &&; + bool addRule(const alphabet::Symbol& leftHandSide, const std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >& rightHandSide); bool addRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + bool addRule(const alphabet::Symbol& leftHandSide, const std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>& rightHandSide); - const std::map<alphabet::Symbol, std::set<std::vector<alphabet::Symbol>>> getRules() const; + bool addRawRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + const std::map<alphabet::Symbol, std::set<std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >> > getRules() const; + + bool removeRule(const alphabet::Symbol& leftHandSide, const std::variant<std::vector<alphabet::Symbol>, std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol> >& rightHandSide); bool removeRule(const alphabet::Symbol& leftHandSide, const std::vector<alphabet::Symbol>& rightHandSide); + bool removeRule(const alphabet::Symbol& leftHandSide, const std::pair<std::vector<alphabet::Symbol>, alphabet::Symbol>& rightHandSide); bool removeTerminalSymbol(const alphabet::Symbol& symbol); diff --git a/alib2data/test-src/grammar/GrammarTest.cpp b/alib2data/test-src/grammar/GrammarTest.cpp index b150fe8d5231f0f71ad44c8b85fe4e238e8425bd..f85be638281b646409769195947a3b0119bdf83f 100644 --- a/alib2data/test-src/grammar/GrammarTest.cpp +++ b/alib2data/test-src/grammar/GrammarTest.cpp @@ -84,19 +84,20 @@ void GrammarTest::testUnrestrictedParser() { } void GrammarTest::testRegularParser() { - grammar::RightRG grammar(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(1))))); + { + grammar::RightRG 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.addRule(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(1)))), std::make_pair(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::make_pair(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("b")))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(3)))))); + 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"))))); - CPPUNIT_ASSERT( grammar == grammar ); - { + grammar.addRule(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(1)))), std::make_pair(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::make_pair(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::StringLabel("b")))), alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(3)))))); + + CPPUNIT_ASSERT( grammar == grammar ); + { grammar::GrammarToXMLComposer composer; std::list<sax::Token> tokens = composer.compose(grammar); std::string tmp; @@ -108,5 +109,36 @@ void GrammarTest::testRegularParser() { grammar::RightRG grammar2 = parser.parseRightRG(tokens2); CPPUNIT_ASSERT( grammar == grammar2 ); + } + } + + { + grammar::RightLG 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.addRule(alphabet::Symbol(alphabet::LabeledSymbol(label::Label(label::IntegerLabel(1)))), std::make_pair(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::make_pair(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::make_pair(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::make_pair(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::RightLG grammar2 = parser.parseRightLG(tokens2); + + CPPUNIT_ASSERT( grammar == grammar2 ); + } } }