1

i am trying to parse a character stream and do a lookup on the second character parsed to get the number of repeats required for the third character. Variable objSize however does not get referenced correctly within repeat and full parse fails. If i assign objSize = 3 i get Full Parse Pass. Here is the code i am using. Any help much appreciated.

#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;
}
user2149346
  • 295
  • 1
  • 8
  • Note that if you want to access the data, you'll need to keep using semantic actions OR use automatic attribute propagation (see https://stackoverflow.com/questions/8259440/boost-spirit-semantic-actions-are-evil and [operator %=](http://www.boost.org/doc/libs/1_64_0/libs/spirit/doc/html/spirit/qi/reference/nonterminal/rule.html#spirit.qi.reference.nonterminal.rule.expression_semantics)) – sehe Aug 17 '17 at 22:24

1 Answers1

1

You action is a lambda:

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

That's not a Phoenix Actor. Yet you are using phx::ref inside it (that's not gonna do what you want).

One valid way to specify the action would seem:

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

Here's a cleanified way to write that:

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

Prints Live On Coliru

Parse Success
Full Parse Pass  Size:5

Drawbacks, improving it

This grammar has drawbacks: it refers to a local (objectSize) and as such has lifetime issues. Ideally the local should be part of the rule. This would, at once, make the rule reentrant.

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

Bonus:

Because getObjSize is so simple, the phx::bind seems too ugly. Why not integrate it:

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

See it Live On Coliru

sehe
  • 374,641
  • 47
  • 450
  • 633
  • this solves my problem. I have a range of broadly similar character streams to parse but this solution will hopefully get me going in the right direction. the comprehensive answer is much appreciated. – user2149346 Aug 18 '17 at 06:32
  • Welcome to SO. Please also read https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – sehe Aug 18 '17 at 15:21