约束现有的 Boost.Spirit real_parser (使用策略)

2024-02-06

我想解析浮点数,但不允许 NaN 值,因此我生成一个继承默认策略的策略并创建一个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);

但是现在我also想要确保解析的字符串的总长度no_nan不超过4,即“1.23”或“.123”甚至“2.e6”或“inf”都可以,“3.2323”不行,“nan”也不行。我不能这样做parse_n/parse_frac_n策略的部分,分别看起来点的左/右并且不能通信(...干净地),自从overall长度相关。

当时的想法是延长real_parser (in boost/spirit/home/qi/numeric/real.hpp) and 包裹住parse method-- 但这个类没有方法。旁边real_parser is the any_real_parser结构体does have parse,但这两个结构似乎没有以任何明显的方式相互作用。

有没有一种方法可以轻松地注入我自己的 parse(),进行一些预检查,然后调用real parse (return boost::spirit::qi::any_real_parser<T, RealPolicy>::parse(...))然后遵守给定的政策?编写一个新的解析器将是最后的手段,但我希望有更好的方法。

(使用Boost 1.55,即Spirit 2.5.2,带有C++11)


看来我已经很接近了,即只需对 double_ 解析器进行一些更改,我就完成了。这可能比添加新语法更易于维护,因为所有其他解析都是通过这种方式完成的。 – 携带7 小时前 https://stackoverflow.com/questions/30375750/extending-the-existing-boost-spirit-real-parser-with-a-policy-plus-a-wrapped-par#comment48844034_30375750

更可维护的是根本不编写另一个解析器。

您基本上想要解析浮点数(精神已覆盖你)但随后应用一些验证。我会在语义操作中进行验证:

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

就是这样。

说明

Anatomy:

  • double_ [_val = _1]像往常一样解析一个 double 并将其分配给公开的属性
  • raw [ parser ]与随附的parser but将原始源迭代器范围公开为属性
  • [ _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 http://coliru.stacked-crooked.com/a/3d352fca049d6e8b

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

Prints

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'

1 必须在此处显式完成分配,因为我们使用语义操作,并且它们通常会抑制自动属性传播

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

约束现有的 Boost.Spirit real_parser (使用策略) 的相关文章

随机推荐