/** * Copyright (c) 2011 Ubimet * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) **/ #include "endian.hpp" #include "float.hpp" #include #include namespace boost { namespace spirit { #define BOOST_SPIRIT_ENABLE_BINARY(name) \ template<> \ struct use_terminal: mpl::true_ {}; \ \ template \ struct use_terminal > >: is_floating_point {}; \ \ template<> \ struct use_lazy_terminal: mpl::true_ {}; \ \ /***/ BOOST_SPIRIT_ENABLE_BINARY(bin_float) BOOST_SPIRIT_ENABLE_BINARY(big_bin_float) BOOST_SPIRIT_ENABLE_BINARY(little_bin_float) BOOST_SPIRIT_ENABLE_BINARY(bin_double) BOOST_SPIRIT_ENABLE_BINARY(big_bin_double) BOOST_SPIRIT_ENABLE_BINARY(little_bin_double) #undef BOOST_SPIRIT_ENABLE_BINARY }} namespace boost { namespace spirit { namespace qi { namespace detail { template struct floating_point { BOOST_SPIRIT_ASSERT_MSG(bits == 32 || bits == 64, not_supported_binary_size, ()); }; template<> struct floating_point<32> { typedef float type; }; template<> struct floating_point<64> { typedef double type; }; } template struct bin_float_parser: primitive_parser > { template struct attribute { typedef typename detail::floating_point::type type; }; template bool parse(Iterator& first, Iterator const& last, Context&, Skipper const& skipper, Attribute& attr) const { boost::spirit::qi::skip_over(first, last, skipper); typename attribute::type attr_; endian bytes(attr_); Iterator it = first; for (unsigned int i = 0; i < sizeof(attr_); ++i) { if(it == last) return false; *bytes.current = *it; ++it; bytes.next(); } first = it; boost::spirit::traits::assign_to(attr_, attr); return true; } template info what(Context&) const { return info("bin_float"); } }; template struct bin_float_lit_parser: primitive_parser > { template struct attribute { typedef unused_type type; }; bin_float_lit_parser(Float n) : n(n) {} template bool parse(Iterator& first, Iterator const& last, Context& /*context*/, Skipper const& skipper, Attribute& attr) const { qi::skip_over(first, last, skipper); typename detail::floating_point::type attr_; attr_ = n; endian bytes(attr_); Iterator it = first; for (unsigned int i = 0; i < sizeof(attr_); ++i) { if(it == last) { return false; } if(*bytes.current != static_cast(*it)) { return false; } ++it; bytes.next(); } first = it; spirit::traits::assign_to(attr_, attr); return true; } template info what(Context& /*context*/) const { return info("bin_float"); } Float n; }; }}} namespace boost { namespace spirit { namespace qi { template struct make_floating_point_parser { typedef bin_float_parser result_type; result_type operator()(unused_type, unused_type) const { return result_type(); } }; template struct make_floating_point_lit_parser { typedef bin_float_lit_parser result_type; template result_type operator()(Terminal const& term, unused_type) const { return result_type(fusion::at_c<0>(term.args)); } }; #define BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(name, endian, bits) \ template \ struct make_primitive \ : make_floating_point_parser< ::detail::endianness::endian, bits> {}; \ \ template \ struct make_primitive< \ terminal_ex >, Modifiers> \ : make_floating_point_lit_parser {}; \ \ /***/ BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(bin_float, native, 32) BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_bin_float, big, 32) BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_bin_float, little, 32) BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(bin_double, native, 64) BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(big_bin_double, big, 64) BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE(little_bin_double, little, 64) #undef BOOST_SPIRIT_MAKE_BINARY_PRIMITIVE }}}