【问题标题】:in boost::spirit::qi, is it possible to dynamically modify rule definition in runtime在 boost::spirit::qi 中,是否可以在运行时动态修改规则定义
【发布时间】:2013-11-07 14:48:38
【问题描述】:

我用 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()”这样的函数来禁用规则“响应”、“状态”和“查询”?

【问题讨论】:

    标签: c++ boost boost-spirit boost-spirit-qi


    【解决方案1】:

    最自然的方法是为您的更多限制场合使用不同的解析器。

    另外,如果性能如此重要,您甚至不能多做 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";
        }
    }
    

    就像 Mike 提到的,这也用于 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
    

    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

    【讨论】:

    • 我可以再问一个问题。您似乎建议经常手动编写解析器,但这不是很难吗?回溯似乎不太简单,如何验证您是否收到所有案件?有什么见解或要读的东西吗?谢谢。
    • 手动编写解析器很少复杂,但枯燥乏味。如果语法发生变化,这尤其会受到伤害。只有当你的语法是“狂野的”(想想:c++)时,它才会变得困难。测试的方式与测试精神语法的方式完全相同。
    • 现在请注意:我建议您编写自己的解析器,并且根据您的评论建议相反。由于上述原因,我观察到这听起来像是过早的优化。 (你分析过差异吗?)
    • @MikeM 我刚刚意识到你不是这里的 OP:/ 所以我的建议是错误的。我希望你当时有这个意图。 Spirit 在语法的快速组合中大放异彩,并具有合理的性能:它针对开发人员时间进行了优化(以(泄漏)抽象为代价,最重要的是:编译复杂性)。在很多情况下,这很有意义,这就是我喜欢 Spirit 的原因。
    • 别担心,我没有误解您的评论。有时很难把学到的东西放在眼里;我的意思是,什么时候才能确保真正获得一些知识,而不仅仅是冰山一角。这就是为什么我在这里提出要求,为我把精神放在一个更大的角度。无论如何,在过去的几个月里,我从您(和 cv_and_he)的回答中学到了很多东西,谢谢。
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多