i am trying to make sense of the following result. The test case code is
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/spirit/home/support/context.hpp>
#include <boost/spirit/home/phoenix.hpp>
#include <boost/foreach.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <vector>
namespace sp = boost::spirit;
namespace qi = boost::spirit::qi;
using namespace boost::spirit::ascii;
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
using phoenix::at_c;
using phoenix::push_back;
using phoenix::bind;
template <typename P>
void test_parser(
char const* input, P const& p, bool full_match = true)
{
using boost::spirit::qi::parse;
char const* f(input);
char const* l(f + strlen(f));
if (parse(f, l, p) && (!full_match || (f == l)))
std::cout << "ok" << std::endl;
else
std::cout << "fail" << std::endl;
}
int main() {
test_parser("+12345", qi::int_ ); //Ok
test_parser("+12345", qi::double_ - qi::int_ ); //failed, as expected
test_parser("+12345.34", qi::int_ ); // failed, as expected
test_parser("+12345.34", qi::double_ - qi::int_ ); //failed but it should be Ok!
};
the motivation here is that i want to match numbers '12345' as integers and NEVER as floating points. '12345.34' will match double_ and never int_ but the reciprocal case is not true; '12345' matches both integers (int_ ) and floating point (double_ ). I tried double_ - int_ and it successfully failed to match '12345'. However my hope was that the last test case '12345.34' would positively match double_ - int_, but the result i get is fail to match.
Why this is so, and how do i get a parser that only matches integers and another that only matches floating points (like in c, 5.0 would be interpreted as floating point)
The problem with the double-not-int
qi::double_ - qi::int_
is that an individual parser doesn't have to match the whole input to be a successful match. For "+12345.34", qi::double_ makes a successful match on the whole thing and qi::int makes a successful match on "+12345", so thatqi::double_ - qi::int_
is a non-match. For difference operator, think about applying each parser separately and whether there is a valid match for each for even the first part of the input.You can get the behavior you want by requiring some kind of boundary after qi::int_. What follows when an qi::int_ matches the first part of a float is a valid float (e.g. qi::int_ on "+12345.34" matches "+12345", leaving ".34" next on the stream). Therefore, you can do a negative look ahead for a float:
or
!qi::double
is also true for whitespace and eoi, so I think this should be pretty general for standard format. This won't work for scientific notation though.For your specific example, I think it's actually described in the Boost Spirit documentation under
RealPolicies
Specialization. To make things a bit easier for you, I whipped out a quick "real" parser, that only parses real numbers and not integers(or at least it worked with your simplified examples):And you can use this just like any other parser(like int_ and double_). You might have to add:
To get it to compile.