Boost.Spirit.Qi - Bounds checking against primitive data types

会有一股神秘感。 提交于 2019-12-24 04:59:10

问题


I need to check that the value of a parsed qi::uint_ is less than 256.


I stumbled across an SO post outlining the following syntax to run checks after a primitive type has been parsed (qi::double_ in this example).

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

Here, raw[...] returns an iterator to the parsed qi::double_ value, and the final semantic action is used to "test" the resulting value.


Extrapolating from the previous example, I assumed I could check bounds using a similar approach.

raw [ uint_ [_val = _1] ] [ _pass = _val<=256 ]

Unfortunately, I get the following error.

boost.spirit.qi.bounds.cpp:51:105: error: invalid operands to binary expression ('const boost::spirit::_val_type'
  (aka 'const actor<attribute<0> >') and 'int')
    if (qi::parse(str.begin(), str.end(), qi::raw[qi::uint_[qi::_val = qi::_1]][qi::_pass = qi::_val<=256]).full)
                                                                                            ~~~~~~~~^ ~~~

The documentation and examples are great for basic parsers, but it begins to taper off with more advanced topics; such as this.

How can I convert or extract the unsigned integer value from qi::_val to test against 256?


回答1:


You have missed the fact that raw[] exposes an iterator range. The other answer used that because the "extra" constraint was referring to the input length (in characters).

You don't need that, so you'd rather use something direct like:

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;

int main ()
{
    using It = std::string::const_iterator;
    qi::rule<It, double()> r
        = qi::double_ [ qi::_pass = (qi::_1 < 256.0), qi::_val = qi::_1 ];

    for (std::string const s: { "1.23", ".123", "2.e6", "inf", "-inf", "3.2323", "nan" })
    {
        It f = s.begin(), l = s.end();

        double result;
        if (parse(f, l, r, result))
             std::cout << "accepted: '" << s << "' -> " << result;
        else std::cout << "rejected: '" << s << "'";

        if (f!=l)
             std::cout << " (remaining: '" << std::string(f,l) << "')\n";
        else std::cout << "\n";
    }
}

Prints

accepted: '1.23' -> 1.23
accepted: '.123' -> 0.123
rejected: '2.e6' (remaining: '2.e6')
rejected: 'inf' (remaining: 'inf')
accepted: '-inf' -> -inf
accepted: '3.2323' -> 3.2323
rejected: 'nan' (remaining: 'nan')

Notes:

  1. the [action1, action2] is the Phoenix way of supplying multiple statements (in this case would be very similar to [action1][action2]).

  2. you can even do without the _val= assignment, because that's just what default attribute propagation is.

    In order to enable default attribute propagation on a rule that semantic action(s), use operator%= to define it:

    r %= qi::double_ [ qi::_pass = (qi::_1 < 256.0) ];
    

    Live On Coliru

    That prints the same output.



来源:https://stackoverflow.com/questions/51272067/boost-spirit-qi-bounds-checking-against-primitive-data-types

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!