boost phoenix 没有引用之前的比赛

boost phoenix not referencing previous match

我正在尝试解析字符流并查找解析的第二个字符以获得第三个字符所需的重复次数。然而,变量 objSize 在 repeat 中没有被正确引用,并且完全解析失败。如果我分配 objSize = 3,我会得到 Full Parse Pass。这是我正在使用的代码。非常感谢任何帮助。

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <iostream>
#include <iomanip>
#include <boost/spirit/include/qi.hpp>
#include <boost/phoenix/phoenix.hpp>
#include <boost/spirit/include/qi_char.hpp>
#include <boost/spirit/include/qi_repeat.hpp>
#include <string>
#include <vector>

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

 void write_to_con (const std::vector<unsigned char> &v){
         for (int i = 0; i <v.size(); ++i)
            std::cout << std::setw(2) << std::setfill('0') << std::hex <<int(v[i]) <<" ";
            std::cout << std::endl;
    }

 int getObjSize(unsigned char t)
    {
        if(t == '\x02')
            return 3;
        else return 0;
    }

int main()
{
    std::vector<unsigned char> v = {'\x01','\x02','\x03','\x03','\x03'};
    int objSize = 0;
    auto it = v.begin();
    bool match = boost::spirit::qi::parse(it, v.end(),
            //Begin Grammar
            (
             (qi::char_('\x01'))>>(qi::char_[([&](unsigned char c){phx::ref(objSize) = getObjSize(c);})])>>(qi::repeat(phx::ref(objSize))[qi::char_])
            )
            //End Grammar
              );
    if(match){
        std::cout << "Parse Success\n";
    }
    else
        std::cout << "Parse Fail\n";

    if (it != v.end()){
        std::vector<unsigned char> ret(it, v.end());
        std::cout << "Full Parse Failed at:";
        write_to_con(ret);
    }
    else
        std::cout << "Full Parse Pass\t Size:" <<v.size() << "\n";
    return 0;
}

您的操作是一个 lambda:

[&](unsigned char c) { phx::ref(objSize) = getObjSize(c); };

那不是凤凰男演员。然而你在其中使用 phx::ref(这不会做你想要的)。

一种指定操作的有效方法如下:

qi::char_[phx::ref(objSize) = phx::bind(getObjSize, qi::_1)]

这是一种简洁的写法:

qi::rule<decltype(it)> p;
{
    using namespace qi;
    p = (
        (char_('\x01'))
     >> (char_[phx::ref(objSize) = phx::bind(getObjSize, _1)])
     >> (repeat(phx::ref(objSize))[char_])
    );
}

bool match = boost::spirit::qi::parse(it, v.end(), p);

打印 Live On Coliru

Parse Success
Full Parse Pass  Size:5

缺点,改进一下

此语法有缺点:它指的是本地 (objectSize),因此存在生命周期问题。理想情况下,当地应该成为规则的一部分。这将立即使规则可重入。

输入qi::locals<>:

qi::rule<decltype(it), qi::locals<int> > p;
{
    using namespace qi;
    _a_type objSize; // the first local placeholder

    p = (
        (char_('\x01'))
     >> (char_[objSize = phx::bind(getObjSize, _1)])
     >> (repeat(objSize)[char_])
    );
}

奖金:

因为getObjSize太简单了,phx::bind就显得太丑了。为什么不整合它:

qi::rule<decltype(it), qi::locals<int> > p;
{
    using namespace qi;
    _a_type objSize; // the first local placeholder

    struct size_f { int operator()(unsigned char t) const { return t=='\x02'?3:0; } };
    phx::function<size_f> get_size;

    p = (
        char_('\x01')
     >> char_[objSize = get_size(_1)]
     >> repeat(objSize)[char_]
    );
}

看到了Live On Coliru