views:

296

answers:

2

Hey folks!

I am diving into boost::spirit in order to parse a ASCII-based protocoll. I mananged to extract values from the line using rules like this:

rule<> Speed = uint_parser<unsigned int,10,3,3>()[assign_a(buffer.speed)];

I also succeed to connect these rules in a meaningful manner. What is missing for a perfect day is the following: The data values are integers that need to be transformed to floating point values using a fixed conversion factor (usually powers of 10).

What I do right now is just appying these scalings factors after parsing. However I would really apprechiate to include the scaling factor just inside the rule definition for the field. I imagine something like this:

rule<> Speed = uint_parser<unsigned int,10,3,3>()[assign_a(buffer.speed,100)];

Any suggestions?

Thanks in advance Arne

A: 

One way to do this is to use Boost.Phoenix. Include these headers:

#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_object.hpp> // For static_cast_
#include <boost/spirit/include/phoenix_operator.hpp> // For multiplication

and then use something like:

using namespace boost::phoenix;
using namespace boost::phoenix::arg_names;

rule<> Speed = uint_parser<unsigned int,10,3,3>()[
    ref(buffer.speed) = static_cast_<double>(arg1) * 100
];

Although, I find phoenix a bit tricky to use and generally just write my own action:

struct assign_scaled
{
    double& result;
    double scale;

    assign_with_scale(double& r, double scale) : result(r), scale(scale) {}

    void operator()(unsigned int x) const
    {
        result = static_cast<double>(x) * scale;
    }
};

And use it like this:

    rule<> Speed = uint_parser<unsigned int,10,3,3>()[assign_scaled(buffer.speed, 100)];

This may be more verbose, but I find it easier to maintain.

Daniel James
Thanks a lot. The second approach is what I will try tonight. -Arne
Arne
A: 

With Spirit.Qi you can use [ref(buffer.speed) = _1 * 100]

Tronic