Boost logo

Boost Users :

Subject: [Boost-users] Using Boost.Spirit with Boost.Units
From: Vitaly Budovski (vbudovski+news_at_[hidden])
Date: 2010-09-21 03:57:05


Hi,

I need to be able to construct expressions from a collection of basic
units and prefixes. The expression is provided as a string and thus
needs to be parsed first. I have been able to achieve without too much
trouble. What I am having trouble with is constructing the
appropriated expressions using the Boost.Units library. I'm still very
new to these two boost libraries so any pointers on how to achieve
what I'm after (is it possible?) would be very much appreciated.
Please see my code below:

-----------------------------------

#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/units/systems/si.hpp>
#include <boost/units/systems/si/prefixes.hpp>
#include <boost/units/systems/cgs.hpp>
#include <boost/units/systems/temperature/celsius.hpp>
#include <boost/variant.hpp>
#include <iostream>
#include <string>
using namespace boost::units;
using namespace boost::units::si;

// Most prefixes omitted for brevity.
struct si_prefix_symbol_: boost::spirit::qi::symbols<char, int>
{
    si_prefix_symbol_()
    {
        add
            ("k", 3)
            ("M", 6)
            ("G", 9)

            ("c", -2)
            ("m", -3)
         ;
    }

} si_prefix_symbol;

typedef boost::variant<quantity<cgs::mass>, quantity<length>,
    quantity<si::time>, quantity<absolute<si::temperature> >,
    quantity<absolute<celsius::temperature> >, double> variant_t;

struct unit_symbol_: boost::spirit::qi::symbols<char, variant_t>
{
    unit_symbol_()
    {
        add
            ("m", 1.0 * meter)
            ("g", 1.0 * cgs::gram)
            ("s", 1.0 * second)
            ("K", 1.0 * absolute<si::temperature>())
            ("C", 1.0 * absolute<celsius::temperature>())
        ;
    }

} unit_symbol;

template<class Iterator>
struct unit_expression: boost::spirit::qi::grammar<Iterator, variant_t()>
{
    unit_expression(): unit_expression::base_type(start)
    {
        using boost::spirit::int_;
        using boost::spirit::ascii::space;
        using boost::spirit::eps;
        using namespace boost::spirit::arg_names;

        start = eps[_val = 1.0] >>
            (
                (
                    (
                        unit_symbol |
                            si_prefix_symbol >> unit_symbol
                    ) >>
                    -(
                        '^' >> int_
                    )
                ) % space
            )
        ;
    }

    boost::spirit::qi::rule<Iterator, variant_t()> start;
};

int main()
{
    std::string in("kg m^-2");

    typedef std::string::const_iterator iterator_type;
    typedef unit_expression<iterator_type> unit_expression;

    iterator_type first = in.begin();
    iterator_type last = in.end();

    unit_expression unit_parser;
    variant_t result;
    bool r = parse(first, last, unit_parser, result);
    if(r && first == last)
    {
        std::cout << "success: " << result << std::endl;
    }
    else
    {
        std::cout << "parsing failed at: ";
        std::cout << std::string(first, last) << std::endl;
    }

    return 0;
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net