c++parsingboostboost-spiritqi

Skipper does not work in boost::spirit


I use boost spirit to parse a color. That worked quite well, but after I changed the the iterator type, the skipper stopped working.

"rgb(1.0,1.0,0.5)"  // this works
" rgb(0.2,0.2,0.2)" // this fails

Here is the header:

struct ColorGrammar : public qi::grammar<StringIterator, Color(), chs::space_type>
{
//! Iterator type for this grammar
typedef StringIterator ItType;
//! Skipper type used in this grammar
typedef chs::space_type Skipper;



//! Rule to parse a number with up to 3 digits
qi::uint_parser<uint8, 10, 1, 3> number;
//! Rule to parse a hex digit
qi::uint_parser<uint8, 16, 1, 1> hexdigit;

ColorGrammar();

//! Rule for rgb(...)
qi::rule<ItType, Color(), qi::locals<float, float>, Skipper> rule_rgb;
//! Rule for rgba(...)
qi::rule<ItType, Color(), qi::locals<float, float, float>, Skipper> rule_rgba;
//! Mainrule
qi::rule<ItType, Color(), Skipper> rule_color;
};

Here is the cpp

ColorGrammar::ColorGrammar()
: ColorGrammar::base_type(rule_color, "color-grammar")
{
using namespace qi::labels;
using boost::phoenix::construct;
auto& _1 = qi::_1;


rule_rgb = '(' >> qi::float_[_a = _1] >> ',' >> qi::float_[_b = _1] >> ',' >> qi::float_[_val = phx::construct<Color>(_a, _b, _1)] >> ')';
rule_rgba = '(' >> qi::float_[_a = _1] >> ',' >> qi::float_[_b = _1] >> ',' >> qi::float_[_c = _1] >> ',' >> qi::float_[_val = phx::construct<Color>(_a, _b, _c, _1)] >> ')';
rule_color = (qi::lit("rgb") >> rule_rgb)
    | (qi::lit("rgba") >> rule_rgba);
}

And the call:

Color out;
StringIterator begin = str.cbegin();
StringIterator end = str.cend();

bool result = qi::phrase_parse(begin, end, color_, chs::space, out);

I'm sure, it is only a little misstake, but I am not able to see it. Maybe i watched too long at the source... can you see a misstake?


Solution

  • I can't see what's wrong: I've taken the effort to reconstruct your SSCCE.

    In the process, it seems I must have removed the problem. I suggest you do the same.

    Oh, and this is how I'd write this:

    In short: no more fuss.

    #include <boost/spirit/include/qi.hpp>
    #include <boost/fusion/adapted/struct.hpp>
    #include <cstdint>
    
    namespace qi  = boost::spirit::qi;
    namespace chs = boost::spirit::ascii; //qi;
    
    typedef std::string::const_iterator StringIterator;
    
    struct Color
    {
        float r,g,b,a; 
    };
    
    BOOST_FUSION_ADAPT_STRUCT(Color, (float, r)(float, g)(float, b)(float, a))
    
    template <typename ItType, typename Skipper>
    struct ColorGrammar : public qi::grammar<StringIterator, Color(), Skipper>
    {
        ColorGrammar()
            : ColorGrammar::base_type(rule_color, "color-grammar")
        {
            using namespace qi;
            rule_rgb   = lit("rgb")  >> '(' > float_ > ',' > float_ > ',' > float_ >       attr(1.0f) > ')';
            rule_rgba  = lit("rgba") >> '(' > float_ > ',' > float_ > ',' > float_ > ',' > float_     > ')';
            rule_color = rule_rgb | rule_rgba;
        }
    
      private:
        qi::uint_parser<uint8_t, 10, 1, 3> number;   // unused
        qi::uint_parser<uint8_t, 16, 1, 1> hexdigit; // unused
    
        qi::rule<ItType, Color(), Skipper> rule_rgb, rule_rgba, rule_color;
    };
    
    int main()
    {
        Color out;
        std::string str = " rgb ( 0.3 , .4 , 0.5 )";
        StringIterator begin = str.cbegin();
        StringIterator end   = str.cend();
    
        ColorGrammar<StringIterator, chs::space_type> color_;
    
        bool result = qi::phrase_parse(begin, end, color_, chs::space, out);
        std::cout << std::boolalpha << result << '\n';
        std::cout << "remains: '" << std::string(begin, end) << "'\n";
    }
    

    Live on http://liveworkspace.org/code/35htD$3