Limit existing Boost.Spirit real_parser (with policy)

I want to parse a float, but not allow NaN, so I create a policy that inherits from the default policy and creates with it real_parser:

// using boost::spirit::qi::{real_parser,real_policies,
//                           phrase_parse,double_,char_};

template <typename T>
struct no_nan_policy : real_policies<T>
{
    template <typename I, typename A>
    static bool
    parse_nan(I&, I const&, A&) {
          return false;
    }    
};

real_parser<double, no_nan_policy<double> > no_nan;

// then I can use no_nan to parse, as in the following grammar
bool ok = phrase_parse(first, last, 
   no_nan[ref(valA) = _1] >> char_('@') >> double_[ref(b) = _1],
space);

But now I also want the total length of the line being processed with help no_nannot to exceed 4, that is, "1.23" or ".123" or even "2.e6", or "inf" in order, "3.2323" is not "nan". I cannot do this in a section parse_n/ parse_frac_npolicy that looks separately to the left / right points and cannot communicate (... purely) what they should have in view of the total length.

, real_parser ( boost/spirit/home/qi/numeric/real.hpp) parse, . real_parser any_real_parser, parse, - .

(), , (return boost::spirit::qi::any_real_parser<T, RealPolicy>::parse(...)), ? , , .

( Boost 1.55, Spirit 2.5.2, ++ 11)

+2
1

, , double_, . , , , , . - toting 7

.

( ), . :

raw [ double_ [_val = _1] ] [ _pass = !isnan_(_val) && px::size(_1)<=4 ]

.

:

  • double_ [_val = _1] ¹
  • raw [ parser ] parser ,
  • [ _pass = !isnan_(_val) && px::size(_1)<=4 ] - -!

    raw[]. ,

    • _1 , double_
    • _val "" double_
    • _pass - Spirit, false, .

. ::isnan:

boost::phoenix::function<decltype(&::isnan)> isnan_(&::isnan);

.

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <cmath>
#include <iostream>

int main ()
{
    using It = std::string::const_iterator;

    auto my_fpnumber = [] { // TODO encapsulate in a grammar struct
        using namespace boost::spirit::qi;
        using boost::phoenix::size;

        static boost::phoenix::function<decltype(&::isnan)> isnan_(&::isnan);

        return rule<It, double()> (
                raw [ double_ [_val = _1] ] [ _pass = !isnan_(_val) && size(_1)<=4 ]
            );
    }();

    for (std::string const s: { "1.23", ".123", "2.e6", "inf", "3.2323", "nan" })
    {
        It f = s.begin(), l = s.end();

        double result;
        if (parse(f, l, my_fpnumber, result))
            std::cout << "Parse success:  '" << s << "' -> " << result << "\n";
        else
            std::cout << "Parse rejected: '" << s << "' at '" << std::string(f,l) << "'\n";
    }
}

Parse success:  '1.23' -> 1.23
Parse success:  '.123' -> 0.123
Parse success:  '2.e6' -> 2e+06
Parse success:  'inf' -> inf
Parse rejected: '3.2323' at '3.2323'
Parse rejected: 'nan' at 'nan'

¹ , ,

+2

Source: https://habr.com/ru/post/1663128/


All Articles