繁体   English   中英

如何扩展提升精神语法

[英]How can I extend a boost spirit grammar

问题是我创建了一个对任务有用的语法,但现在任务已经改变,我需要定义新规则。

但是我不想修改我已经拥有的语法而不是我想创建一个使用现有语法而没有代码重复的新语法,所以我只需要定义我需要的新规则。 我尝试过类似的东西,但是没有用:

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添加我需要的新规则,并且还能够使用我在Old_gramar已有的规则和语法。

我不会通过继承来使问题复杂化。 组合通常绰绰有余,并且不会混淆qi解析器接口。

我已经制作了一个关于如何完成版本化语法的小草图。 假设旧语法:

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;
};

(我没有尝试过使用继承,尽管它很可能也可以工作。)

我们来试试这个宝贝:

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"));
}

显然,所有的测试都通过了: 看到它在Coliru 1 上生活希望这有帮助!


1嗯,笨蛋。 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"));
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM