повышение духа ци числовой разбор целых и плавающих точек - PullRequest
5 голосов
/ 27 июня 2010

Я пытаюсь понять следующий результат. Код теста:

#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!
};

мотивация здесь в том, что я хочу, чтобы числа '12345' соответствовали целым числам, а НИКОГДА не использовались как числа с плавающей запятой. «12345.34» будет соответствовать double_ и никогда не int_, но обратный случай неверен; «12345» соответствует как целым числам (int_), так и плавающей точке (double_). Я попытался double_ - int_, и он успешно не соответствует «12345». Однако я надеялся, что последний контрольный пример «12345.34» будет положительно соответствовать double_ - int_, но результат, который я получаю, не соответствует.

Почему это так, и как мне получить синтаксический анализатор, который соответствует только целым числам, а другой - только плавающие точки (как в c, 5.0 будет интерпретироваться как плавающая точка)

Ответы [ 2 ]

14 голосов
/ 27 июня 2010

Для вашего конкретного примера, я думаю, что это на самом деле описано в документации Boost Spirit в разделе RealPolicies Специализация. Чтобы вам было проще, я вынул быстрый «настоящий» парсер, который анализирует только реальные числа, а не целые числа (или, по крайней мере, он работал с вашими упрощенными примерами):

template <typename T>
struct strict_real_policies : qi::real_policies<T>
{
    static bool const expect_dot = true;
};

qi::real_parser< double, strict_real_policies<double> > real;

И вы можете использовать это так же, как любой другой парсер (например, int_ и double_). Возможно, вам придется добавить:

#include <boost/spirit/include/qi_numeric.hpp>

Чтобы получить его для компиляции.

4 голосов
/ 27 июня 2010

Проблема с double-not-int qi::double_ - qi::int_ заключается в том, что отдельный парсер не должен совпадать со всем вводом для успешного совпадения.Для "+12345.34" qi :: double_ делает успешное совпадение для всего, а qi :: int делает успешное совпадение для "+12345", так что qi::double_ - qi::int_ не совпадает.Для оператора разности подумайте о применении каждого синтаксического анализатора отдельно и о том, существует ли для каждого из них действительное совпадение даже для первой части ввода.

Вы можете получить желаемое поведение, потребовав некоторую границу после qi:: int_.То, что следует, когда qi :: int_ соответствует первой части с плавающей точкой, является допустимым с плавающей точкой (например, qi :: int_ для "+12345.34" соответствует "+12345", оставляя ".34" следующим в потоке).Следовательно, вы можете сделать отрицательный взгляд вперед для числа с плавающей запятой:

int_rule %= qi::int_ >> !qi::double_;

double_rule %= qi::double_ - int_rule; 

или

double_rule %= qi::double_ - (qi::int_ >> !qi::double_); 

!qi::double также верно для пробелов и эои, поэтому я думаю, что это должно быть довольнообщие для стандартного формата.Это не будет работать для научной нотации.

...