буст феникс не ссылается на предыдущий матч

я пытаюсь проанализировать поток символов и выполнить поиск по второму проанализированному символу, чтобы получить количество повторов, необходимое для третьего символа. Переменная objSize, однако, не получает правильной ссылки при повторении, и полный анализ завершается неудачно. Если я назначу 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;
}

1

Решение

Твои действия лямбда

[&](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);

Печать Жить на Колиру

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

Видеть это Жить на Колиру

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]