2013-07-08 4 views
4

Дело в том, что я сделал грамматику, которая была полезной для задачи, но теперь задача изменилась, и мне нужно определить новые правила.Как я могу увеличить грамматику повышения духа

Но я не хотел бы изменить грамматику у меня уже есть, вместо того, что я бы хотел создать новую грамматику, которая использует существующую грамматику у меня есть без кода дублирования, поэтому мне просто нужно определить новый правила, которые мне нужны. Я пытался что-то , как это, но не работает:

struct New_grammar : Old_grammar<Iterator, Skipper>  
{ 
    New_grammar() : New_grammar::base_type(Command_list) 
    { 
     Command_list %= qi::eps >> + Commands; 
     Comandos %= oneoldCommand | NewCommand; 
     NewCommand = ("NewCommand" >> stmt)[qi::_val = phoenix::new_<NewCom>(qi::_1)]; 
    } 
    // this is a new rule I need: 
    qi::rule<Iterator, Commands*(), qi::locals<std::string>, Skipper> NewCommand; 
}; 

основном Old_grammar это грамматика у меня уже есть, и я просто хочу, чтобы добавить новое правило, что нужно в New_grammar, а также быть в состоянии использовать правила и grammars У меня уже есть Old_gramar.

+1

Вездесущее присутствие 'this ->' делает этот код очень трудным для чтения. Его следует удалить. –

ответ

8

Я не затруднял бы вопросы путем наследования. Состав часто более чем достаточно, и он не будет путать интерфейс пар-ци.

Я составил небольшой рисунок того, как может быть выполнена грамматика управления версиями. Предположим, старая грамматика:

template <typename It, typename Skipper> 
struct OldGrammar : qi::grammar<It, Skipper, std::string()> 
{ 
    OldGrammar() : OldGrammar::base_type(mainrule) 
    { 
     using namespace qi; 
     rule1 = int_(1); // expect version 1 
     rule2 = *char_; // hopefully some interesting grammar 
     mainrule = omit [ "version" > rule1 ] >> rule2; 
    } 
    private: 
    qi::rule<It, Skipper, std::string()> mainrule; 
    qi::rule<It, Skipper, int()>   rule1; 
    qi::rule<It, Skipper, std::string()> rule2; 
}; 

Как вы можете видеть, это было весьма ограниченным, требуя от версии, чтобы быть точно 1. Тем не менее, будущее произошло, и новая версия грамматики была изобретена. Теперь я хотел бы добавить

friend struct NewGrammar<It, Skipper>; 

к старой грамматике и идти о реализации новой грамматики, которая любезно возвращается к старой грамматике, если это необходимо:

template <typename It, typename Skipper> 
struct NewGrammar : qi::grammar<It, Skipper, std::string()> 
{ 
    NewGrammar() : NewGrammar::base_type(mainrule) 
    { 
     using namespace qi; 
     new_rule1 = int_(2); // support version 2 now 
     new_start = omit [ "version" >> new_rule1 ] >> old.rule2; // note, no expectation point 

     mainrule = new_start 
       | old.mainrule; // or fall back to version 1 grammar 
    } 
    private: 
    OldGrammar<It, Skipper> old; 
    qi::rule<It, Skipper, std::string()> new_start, mainrule; 
    qi::rule<It, Skipper, int()>   new_rule1; 
}; 

(I гавань» т пытались заставить его работать с наследованием, хотя, по всей вероятности, она также должна работать)

Давайте протестируем этот ребенок:.

template <template <typename It,typename Skipper> class Grammar> 
bool test(std::string const& input) 
{ 
    auto f(input.begin()), l(input.end()); 
    static const Grammar<std::string::const_iterator, qi::space_type> p; 
    try { 
     return qi::phrase_parse(f,l,p,qi::space) && (f == l); // require full input consumed 
    } 
    catch(...) { return false; } // qi::expectation_failure<> 
} 

int main() 
{ 
    assert(true == test<OldGrammar>("version 1 woot")); 
    assert(false == test<OldGrammar>("version 2 nope")); 

    assert(true == test<NewGrammar>("version 1 woot")); 
    assert(true == test<NewGrammar>("version 2 woot as well")); 
} 

Все тесты проходят, очевидно: see it live on Coliru Надеюсь, что это помогает!


Ну, штопка. Колиру слишком медленно, чтобы скомпилировать это сегодня. Итак, вот полная тестовая программа:

#define BOOST_SPIRIT_DEBUG 
#include <boost/spirit/include/qi.hpp> 

namespace qi = boost::spirit::qi; 

template <typename It, typename Skipper> 
struct NewGrammar; // forward declare for friend declaration 

template <typename It, typename Skipper> 
struct OldGrammar : qi::grammar<It, Skipper, std::string()> 
{ 
    friend struct NewGrammar<It, Skipper>; // NOTE 

    OldGrammar() : OldGrammar::base_type(mainrule) 
    { 
     using namespace qi; 
     rule1 = int_(1); // expect version 1 
     rule2 = *char_; // hopefully some interesting grammar 
     mainrule = omit [ "version" > rule1 ] >> rule2; 

     BOOST_SPIRIT_DEBUG_NODE(mainrule); 
     BOOST_SPIRIT_DEBUG_NODE(rule1); 
     BOOST_SPIRIT_DEBUG_NODE(rule2); 
    } 
    private: 
    qi::rule<It, Skipper, std::string()> mainrule; 
    qi::rule<It, Skipper, int()>   rule1; 
    qi::rule<It, Skipper, std::string()> rule2; 
}; 

template <typename It, typename Skipper> 
struct NewGrammar : qi::grammar<It, Skipper, std::string()> 
{ 
    NewGrammar() : NewGrammar::base_type(mainrule) 
    { 
     using namespace qi; 
     new_rule1 = int_(2); // support version 2 now 
     new_start = omit [ "version" >> new_rule1 ] >> old.rule2; // note, no expectation point 

     mainrule = new_start 
       | old.mainrule; // or fall back to version 1 grammar 

     BOOST_SPIRIT_DEBUG_NODE(new_start); 
     BOOST_SPIRIT_DEBUG_NODE(mainrule); 
     BOOST_SPIRIT_DEBUG_NODE(new_rule1); 
    } 
    private: 
    OldGrammar<It, Skipper> old; 
    qi::rule<It, Skipper, std::string()> new_start, mainrule; 
    qi::rule<It, Skipper, int()>   new_rule1; 
}; 

template <template <typename It,typename Skipper> class Grammar> 
bool test(std::string const& input) 
{ 
    auto f(input.begin()), l(input.end()); 
    static const Grammar<std::string::const_iterator, qi::space_type> p; 
    try { 
     return qi::phrase_parse(f,l,p,qi::space) && (f == l); // require full input consumed 
    } 
    catch(...) { return false; } // qi::expectation_failure<> 
} 

int main() 
{ 
    assert(true == test<OldGrammar>("version 1 woot")); 
    assert(false == test<OldGrammar>("version 2 nope")); 

    assert(true == test<NewGrammar>("version 1 woot")); 
    assert(true == test<NewGrammar>("version 2 woot as well")); 
} 
+0

Спасибо! этот подход работал для меня. – user2562470

Смежные вопросы