1

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

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

1 回答 1

1

你的动作是一个 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);

在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_]
    );
}

在Coliru现场观看

于 2017-08-17T22:22:50.730 回答