在boost :: spirit :: qi中,是否可以在运行时动态修改规则定义

Rui*_*hou 4 c++ boost boost-spirit boost-spirit-qi

我用boost :: spirit :: qi :: rule写了一些语法来解析互联网数据包.语法是这样的:

qi::rule<Iterator> start, request, response, status, query ;
start = (request | response | status | query) >> lit("\r\n");
Run Code Online (Sandbox Code Playgroud)

为了提高性能,用户可能希望跳过运行时中的一些规则,例如忽略"响应","状态","查询"并且只尝试匹配请求,因此规则将更改为:

start = (request ) >> lit("\r\n"); 
Run Code Online (Sandbox Code Playgroud)

有可能这样做吗?例如,是否有一个像"禁用()"这样的功能来禁用规则"响应","状态"和"查询"?

seh*_*ehe 6

最自然的方法是在你受限制的场合使用不同的解析器.

此外,如果性能如此重要,您甚至无法进行3或4个额外的字符比较

也就是说,这里有一些选择:

1.使用变量规则 qi::lazy

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

namespace qi    = boost::spirit::qi;
namespace phx   = boost::phoenix;

int main()
{
    typedef std::string::const_iterator It;
    qi::rule<It> 
        request  = "request",
        response = "response",
        status   = "status",
        query    = "query",
        // 
        allowed;

    static qi::rule<It> const start = qi::lazy(phx::ref(allowed)) >> qi::lit("\r\n");
    static const auto test = [](std::string const& input) { return qi::parse(begin(input), end(input), start); };

    for (int i=0; i<10; ++i)
    {
        switch(rand()%3)
        {
            case 0: allowed = request; break;
            case 1: allowed = request | response | query; break;
            case 2: allowed = request | response | status | query; break;
        }

        std::cout << "status: "    << test("status\r\n")   << "\t"
                  << "response: "  << test("response\r\n") << "\t"
                  << "request:  "  << test("request\r\n")  << "\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

就像迈克提到的那样,这也用在了Nabialek技巧中,虽然它qi::lazy是这里必不可少的成分.

这打印,例如:

status: 0   response: 1 request:  1
status: 0   response: 1 request:  1
status: 0   response: 0 request:  1
status: 0   response: 1 request:  1
status: 1   response: 1 request:  1
status: 0   response: 1 request:  1
status: 0   response: 1 request:  1
status: 0   response: 0 request:  1
status: 0   response: 0 request:  1
status: 0   response: 1 request:  1
Run Code Online (Sandbox Code Playgroud)

2.使用继承的属性 qi::lazy

与上面的内容非常类似,您可以将'subrules'作为继承属性传递.我不确定我会推荐这个,因为我在过去的例子中看到了未定义的行为,见例如

3.只需使用单独的规则

在我看来,这是最自然的:

std::function<bool(string)> test;
switch(rand()%3)
{
    case 0: test = [&](std::string const& input) { return qi::parse(begin(input), end(input), request); }; break;
    case 1: test = [&](std::string const& input) { return qi::parse(begin(input), end(input), request | response | query); }; break;
    case 2: test = [&](std::string const& input) { return qi::parse(begin(input), end(input), request | response | status | query); }; break;
}
Run Code Online (Sandbox Code Playgroud)

查看完整示例:http://coliru.stacked-crooked.com/a/603f093add6b9799