views:

83

answers:

1

I am writing a Boost Spirit grammar to parse text into a vector of these structs:

struct Pair
{
    double a;
    double b;
};

BOOST_FUSION_ADAPT_STRUCT(
    Pair,
    (double, a)
    (double, a)
)

This grammar has a rule like this:

qi::rule<Iterator, Pair()> pairSequence;

However, the actual grammar of pairSequence is this:

double_ % separator

I want this grammar to produce a Pair with a equal to the double and b equal to some constant. I want to do something like this:

pairSequence = double_[_val = Pair(_1, DEFAULT_B)] % separator;

The above does not compile, of course. I tried adding a constructor to Pair, but I still get compile errors (no matching function for call to 'Pair::Pair(const boost::phoenix::actor >&, double)').

+2  A: 

First of all, the signature of pairSequence needs to be:

qi::rule<Iterator, std::vector<Pair>()> pairSequence; 

as the list operator exposes a std::vector<Pair> as its attribute.

All functions called from inside a semantic action have to be 'lazy', so you need to utilize phoenix:

namespace phx = boost::phoenix;

pairSequence = 
    double_[
        phx::push_back(_val, 
            phx::construct<Pair>(_1, phx::val(DEFAULT_B))
        )
    ] % separator
; 

Another possibility would be to add a (non-explicit) constructor to Pair:

struct Pair         
{         
    Pair(double a) : a(a), b(DEFAULT_B) {}

    double a;         
    double b;         
};         

which allows to simplify the grammar:

pairSequence = double_ % separator; 

and completely relies on Spirit's built-in attribute propagation rules.

BTW, for any of this to work, you don't need to adapt Pair as a Fusion sequence.

hkaiser
Ah yes, I missed the vector<Pair> construct.
AJM