Search code examples
c++boostboost-spiritboost-spirit-qi

spirit real_parser ".e"


I am trying to parse real numbers using real_parser and the following ureal_policies:

template <typename T>
struct number_real_policies : qi::ureal_policies<T>
{
    static bool const expect_dot = true;

    template <typename Iterator, typename Attribute>
    static bool
    parse_nan(Iterator& first, Iterator const& last, Attribute& attr) {
        return false;
    }

    template <typename Iterator, typename Attribute>
    static bool
    parse_inf(Iterator& first, Iterator const& last, Attribute& attr) {
        return false;
    }
};

It seems to perfectly parse all variations of the real number format I need but I noticed that the following string is accepted as well: ".12345.e12".

Is it normal that two dots are accepted in the fractional part (it only works with the second dot before E/e, and E/e has to be present)?

Thanks in advance


Solution

  • As @llonesmiz correctly pointed out in my test application, it works exactly as designed:

    Live On Coliru

    It looks like you forget to check the parser exit code?

    #include <boost/spirit/include/qi.hpp>
    #include <boost/spirit/include/karma.hpp>
    
    namespace qi    = boost::spirit::qi;
    namespace karma = boost::spirit::karma;
    
    typedef std::vector<double> attr_t;
    
    template <typename T>
    struct number_real_policies : qi::ureal_policies<T>
    {
        static bool const expect_dot = true;
    
        template <typename Iterator, typename Attribute>
        static bool
        parse_nan(Iterator& first, Iterator const& last, Attribute& attr) {
            return false;
        }
    
        template <typename Iterator, typename Attribute>
        static bool
        parse_inf(Iterator& first, Iterator const& last, Attribute& attr) {
            return false;
        }
    };
    
    template <typename It, typename Skipper = qi::space_type>
        struct parser : qi::grammar<It, attr_t(), Skipper>
    {
        parser() : parser::base_type(start)
        {
            using namespace qi;
    
            start %= *mydouble_;
            BOOST_SPIRIT_DEBUG_NODE(start);
        }
    
      private:
        qi::rule<It, attr_t(), Skipper> start;
        qi::real_parser<double, number_real_policies<double> > mydouble_;
    };
    
    bool doParse(const std::string& input)
    {
        typedef std::string::const_iterator It;
        auto f(begin(input)), l(end(input));
    
        parser<It, qi::space_type> p;
        attr_t data;
    
        try
        {
            bool ok = qi::phrase_parse(f,l,p,qi::space,data);
            if (ok)   
            {
                std::cout << "parse success\n";
                std::cout << "data: " << 
                    karma::format_delimited(karma::columns(3) [*karma::auto_], ' ', data) << "\n";
            }
            else      std::cerr << "parse failed: '" << std::string(f,l) << "'\n";
    
            if (f!=l) std::cerr << "trailing unparsed: '" << std::string(f,l) << "'\n";
            return ok;
        } catch(const qi::expectation_failure<It>& e)
        {
            std::string frag(e.first, e.last);
            std::cerr << e.what() << "'" << frag << "'\n";
        }
    
        return false;
    }
    
    int main()
    {
    
        bool ok = doParse(
                "0.    2.    .3    \n  "
                "0.e7  2.e7  .3e7  \n"
                "0.e-7 2.e-7 .3e-7 \n"
                // shouldn't accept:
                //"0..e7\n"
                "0.3.e7\n"
                );
        return ok? 0 : 255;
    }
    

    Output:

    parse success
    data: 0.0 2.0 0.3 
    0.0 2.0e07 3.0e06 
    0.0 2.0e-07 3.0e-08 
    0.3 
    
    trailing unparsed: '.e7
    '