4

我用 boost::spirit::qi::rule 写了一些语法来解析互联网数据包。语法类似于:

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

为了提高性能,用户可能希望在运行时跳过一些规则,例如忽略“response”、“status”、“query”而只尝试匹配请求,因此规则将变为:

start = (request ) >> lit("\r\n"); 

可以这样做吗?例如,是否有像“disable()”这样的函数来禁用规则“响应”、“状态”和“查询”?

4

2 回答 2

6

最自然的方法是在更受限制的情况下使用不同的解析器。

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

  • 您可能应该做一个手写解析器(通常,Spirit 的自动属性处理并不总是最佳的)或
  • 考虑静态优化扫描(如 Boost Xpressive 或 Spirit Lex)
  • 你可能做错了什么(如果你有一个次优的语法,你可以有很多回溯会破坏性能 - 就像退化的正则表达式(https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS))

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

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

就像迈克提到的那样,这也用于纳比亚莱克技巧,尽管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

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

与上面非常相似,您可以将“子规则”作为继承属性传递。我不确定我是否会推荐这个,因为我在过去的示例中看到了未定义的行为,请参见例如

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

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

于 2013-11-09T22:22:17.500 回答
1

是的,这可以通过使用qi::symbols解析器来实现。可以在运行时更改使用的符号,因此您可以更改行为。要使用这个解析器来获取完整的规则,有一个小技巧,称为 nabialek 技巧http://boost-spirit.com/home/articles/qi-example/nabialek-trick/

基本上它展示了如何在符号解析器中挂钩完整的规则。

于 2013-11-08T12:05:30.960 回答