Question

I have the following boost::spirit::qi parser rule:

namespace qi = boost::spirit::qi;
qi::rule<Iterator, BroadbandCurve(), Skipper> Cmd_BBNSET;


Cmd_BBNSET = +(qi::float_ >> qi::float_) >> qi::int_ >> qi::int_ >> lit("BBNSET");

I'm trying to get it to emit the following attribute:

struct FreqLevelPair
{
    float freq;
    float dbLevel;
};
BOOST_FUSION_ADAPT_STRUCT(
    FreqLevelPair,
    (float, freq)
    (float, dbLevel)
)

struct BroadbandCurve
{
    std::vector<FreqLevelPair> freqPairs;
    int numFreqPairs; //Ignored since we can just count the number of pairs outright...
    int curveNum; //ID number
};
BOOST_FUSION_ADAPT_STRUCT(
    BroadbandCurve,
    (std::vector<FreqLevelPair>, freqPairs)
    (int, numFreqPairs)
    (int, curveNum)
)

As you can see, I'm attempting to parse one or more pairs of floats, followed by two ints, followed by the literal "BBNSET." All of this code compiles, however when I attempt to parse a valid BBNSET command of the form:

0.0 80.0 50.0 25.0 100.0 10.0 3 0 BBNSET

the parse fails. I'm unable to determine why. I've attempted wrapping the float pairs in a lexeme directive, and changing the + to a *, but no matter what I've attempted, the command still fails to parse, despite compiling without a problem.

What am I doing wrong, and will this rule emit the attribute as expected once it is parsing correctly?

Was it helpful?

Solution

Sharth was really quick to note the cause.

The solution, IMO is to use strict_real_policies

See it Live On Coliru

#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;

struct FreqLevelPair
{
    float freq;
    float dbLevel;
};

BOOST_FUSION_ADAPT_STRUCT(
    FreqLevelPair,
    (float, freq)
    (float, dbLevel)
)

struct BroadbandCurve
{
    std::vector<FreqLevelPair> freqPairs;
    int numFreqPairs; //Ignored since we can just count the number of pairs outright...
    int curveNum; //ID number
};

BOOST_FUSION_ADAPT_STRUCT(
    BroadbandCurve,
    (std::vector<FreqLevelPair>, freqPairs)
    (int, numFreqPairs)
    (int, curveNum)
)

int main()
{
    typedef std::string::const_iterator Iterator;
    typedef qi::space_type Skipper;

    qi::real_parser<double, qi::strict_real_policies<double> > strict_real_;

    qi::rule<Iterator, BroadbandCurve(), Skipper> Cmd_BBNSET;
    Cmd_BBNSET = +(strict_real_ >> strict_real_) >> qi::int_ >> qi::int_ >> qi::lit("BBNSET");

    std::string const input("0.0 80.0 50.0 25.0 100.0 10.0 3 0 BBNSET");
    auto f(input.begin()), l(input.end());
    bool ok = qi::phrase_parse(f, l, Cmd_BBNSET, qi::space);

    if (ok)
    {
        std::cout << "Parse succeeded\n";
    } else
    {
        std::cout << "Parse failed\n";
    }

    if (f!=l)
        std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}

OTHER TIPS

I suspect your issue is actually with Recursive Descent Parsers in general.

Cmd_BBNSET = +(qi::float_ >> qi::float_) >> qi::int_ >> qi::int_ >> lit("BBNSET");

Let's walk this:

0.0 80.0 50.0 25.0 100.0 10.0 3 0 BBNSET
^
Matches +(qi::float_ >> qi::float_)

0.0 80.0 50.0 25.0 100.0 10.0 3 0 BBNSET
         ^
         Matches +(qi::float_ >> qi::float_)

0.0 80.0 50.0 25.0 100.0 10.0 3 0 BBNSET
                   ^
                   Matches +(qi::float_ >> qi::float_)

0.0 80.0 50.0 25.0 100.0 10.0 3 0 BBNSET
                              ^
                          !!! Matches +(qi::float_ >> qi::float_) !!!

0.0 80.0 50.0 25.0 100.0 10.0 3 0 BBNSET
                                  ^
                                  Does not match qi::int_.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top