制约了现有Boost.Spirit real_parser(有策略) [英] Constraining the existing Boost.Spirit real_parser (with a policy)

查看:160
本文介绍了制约了现有Boost.Spirit real_parser(有策略)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要解析浮动,但不允许NaN值,所以我产生从默认策略继承和政策,创建一个 real_parser 与它:

  //使用boost ::精神::齐:: {real_parser,real_policies,
// phrase_parse,double_,char_};模板< typename的T>
结构no_nan_policy:real_policies< T>
{
    模板< typename的我,类型名A>
    静态布尔
    parse_nan(I和;,我常数和放大器,A安培;){
          返回false;
    }
};real_parser<双,no_nan_policy<双> > no_nan;//然后我可以使用no_nan解析,如下面的语法
布尔OK = phrase_parse(第一,最后,
   no_nan [REF(VALA)= _1]>>烧焦_(@)GT;> double_ [REF(B)= _1]
空间);

但现在我的要确保以 no_nan 解析字符串的总长度不超过4,即1.23或0.123,甚至2.e6或INF就行了,3.2323不是,也不是男。我不能这样做,在政策,这看起来分离左侧的圆点/右的 parse_n / parse_frac_n 部分如果无法通信( ...干净的),他们将不得不因为的长度是相关的。

的想法,然后是扩展 real_parser (在升压/精神的/ home /气/数字/ real.hpp )和包裹解析 - 但这类没有方法。旁边的 real_parser any_real_parser 结构而确实的有解析,但是这两种结构似乎并没有任何明显的方式进行交互。

有没有一种方法可以轻松地注入我自己的解析(),做一些pre-检查,然后调用的真正的解析(返回的boost ::精神::齐:: any_real_parser< T,RealPolicy> ::解析(...)),然后坚持给定的政策?写一个新的解析器将是一个不得已的方法,但我希望有一个更好的办法。

(使用Boost 1.55,即精神2.5.2,用C ++ 11)


解决方案

  

看来我那么近,即只是为了double_解析器的一些变化,我会做。这可能会是一个很多比增加一个新的语法,因为所有其他解析是这样做的方式更容易维护。 - 身背<一个href=\"http://stackoverflow.com/questions/30375750/extending-the-existing-boost-spirit-real-parser-with-a-policy-plus-a-wrapped-par#comment48844034_30375750\">7小时前


更易于维护将不会再写分析器都没有。

您基本上要解析一个浮点数(精神已经得到了你覆盖的),但后来应用一些验证。我会做验证在语义动作:

 原料[double_ [_val = _1] [_pass = isnan _(_ VAL)及!&安培; PX ::大小(_1)&LT; = 4]

这就是它。

说明

解剖:


  • double_ [_val = _1] 解析一个双并将其分配给暴露的属性作为usual¹

  • 原料[解析] 匹配封闭的 解析器 公开原料来源迭代器区间为属性

  • [_pass = isnan _(_ VAL)及!&安培; PX ::大小(_1)&LT; = 4] - 部分业务

    这个语义动作附加到原料[] 解析器。因此,


    • _1 现指已解析的原始迭代器范围双_

    • _val 已经包含了的成功匹配的夹生的价值双_

    • _pass 是,我们可以设置为false精神环境标志,使解析失败。


现在唯一剩下的事情就是将其结合在一起。让我们的延迟版本 :: isnan

 的boost ::凤::功能&LT; decltype(安培; :: isnan)GT; isnan _(安培; :: isnan);

我们是好去。

测试程序

<大骨节病> 住在Coliru

 的#include&LT;升压/精神/有/ qi.hpp&GT;
#包括LT&;升压/精神/有/ phoenix.hpp&GT;
#包括LT&;&CMATH GT;
#包括LT&;&iostream的GT;诠释的main()
{
    使用它=标准::字符串::为const_iterator;    汽车my_fpnumber = [] {// TODO封装在一个语法结构
        使用空间boost ::精神::补气;
        使用boost ::凤凰::大小;        静态的boost ::凤::功能&LT; decltype(安培; :: isnan)GT; isnan _(安培; :: isnan);        返回规则&LT;它,双()&GT; (
                原料[double_ [_val = _1]] [_pass = isnan _(_ VAL)及!&放大器;大小(_1)&LT; = 4]
            );
    }();    对于(标准::字符串常量小号:{1.23,0.123,2.e6,INF,3.2323,楠})
    {
        它F = s.begin(),L = s.end();        双重效果;
        如果(解析(F,L,my_fpnumber,结果))
            性病::法院LT&;&LT; 解析成功:&LT;&LT;小号所述&;&下; ' - &gt;中与所述;&下;结果&LT;&LT; \\ n;
        其他
            性病::法院LT&;&LT; 解析拒绝:'&LT;&LT;小号所述&;&下; '在'&LT;&LT;标准::字符串(F,L)LT;&LT; '\\ n;
    }
}

打印

 解析成功:'1.23' - &GT; 1.23
解析成功:0.123 - &GT; 0.123
解析成功:2.e6' - &GT; 2E + 06
解析成功:INF - &GT; INF
解析拒绝:3.2323在3.2323
解析拒绝:'南'的'南'


¹的分配必须要因为我们使用语义动作,并明确在这里完成他们通常燮preSS自动属性传播

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

// 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 to ensure that the overall length of the string parsed with no_nan does not exceed 4, i.e. "1.23" or ".123" or even "2.e6" or "inf" is ok, "3.2323" is not, nor is "nan". I can not do that in the parse_n/parse_frac_n section of the policy, which separately looks left/right of the dot and can not communicate (...cleanly), which they would have to since the overall length is relevant.

The idea then was to extend real_parser (in boost/spirit/home/qi/numeric/real.hpp) and wrap the parse method -- but this class has no methods. Next to real_parser is the any_real_parser struct which does have parse, but these two structs do not seem to interact in any obvious way.

Is there a way to easily inject my own parse(), do some pre-checks, and then call the real parse (return boost::spirit::qi::any_real_parser<T, RealPolicy>::parse(...)) which then adheres to the given policies? Writing a new parser would be a last-resort method, but I hope there is a better way.

(Using Boost 1.55, i.e. Spirit 2.5.2, with C++11)

解决方案

It seems I am so close, i.e. just a few changes to the double_ parser and I'd be done. This would probably be a lot more maintainable than adding a new grammar, since all the other parsing is done that way. – toting 7 hours ago

Even more maintainable would be to not write another parser at all.

You basically want to parse a floating point numbers (Spirit has got you covered) but apply some validations afterward. I'd do the validations in a semantic action:

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

That's it.

Explanations

Anatomy:

  • double_ [_val = _1] parses a double and assigns it to the exposed attribute as usual¹
  • raw [ parser ] matches the enclosed parser but exposes the raw source iterator range as an attribute
  • [ _pass = !isnan_(_val) && px::size(_1)<=4 ] - the business part!

    This semantic action attaches to the raw[] parser. Hence

    • _1 now refers to the raw iterator range that already parsed the double_
    • _val already contains the "cooked" value of a successful match of double_
    • _pass is a Spirit context flag that we can set to false to make parsing fail.

Now the only thing left is to tie it all together. Let's make a deferred version of ::isnan:

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

We're good to go.

Test Program

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

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'


¹ The assignment has to be done explicitly here because we use semantic actions and they normally suppress automatic attribute propagation

这篇关于制约了现有Boost.Spirit real_parser(有策略)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆