Scaling in boost::spirit's assign_a
-
06-07-2019 - |
Question
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
Solution
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.
OTHER TIPS
With Spirit.Qi you can use [ref(buffer.speed) = _1 * 100]