ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c – 使用boost :: spirit :: qi用分隔符解析数字

2019-07-28 07:04:40  阅读:216  来源: 互联网

标签:boost-spirit-qi c boost-spirit


我试图使用boost :: spirit :: qi进行一些解析.它实际上进展顺利,我成功地设法根据后缀在各种基础上解析数字.例子:123,c12h,777o,110101b.

然后我想添加允许完全忽略的分隔符的功能,以允许解析123_456或1101_0011b之类的值.我尝试使用跳过解析器,但我非常怀疑我完全误解了它是如何被使用的.它编译得很好,但我试图让它忽略下划线完全没有任何意义.任何关于如何使这做我想做的建议将不胜感激.我的测试代码包含在下面:

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
using qi::_val;
using qi::_1;
using qi::skip;
using qi::uint_parser;
using ascii::char_;

template <typename Iterator>
struct unsigned_parser : qi::grammar<Iterator, uint64_t()> {

    unsigned_parser() : unsigned_parser::base_type(start) {
        uint_parser<uint64_t, 10> dec_parser;
        uint_parser<uint64_t, 16> hex_parser;
        uint_parser<uint64_t, 8> oct_parser;
        uint_parser<uint64_t, 2> bin_parser;

        start = skip(char_('_'))[
            /* binary with suffix */
            (bin_parser[_val=_1] >> char_("bByY"))
            /* octal with suffix */
            | (oct_parser[_val=_1] >> char_("qQoO"))
            /* hexadecimal with suffix */
            | (hex_parser[_val=_1] >> char_("hHxX"))
            /* decimal with optional suffix */
            | (dec_parser[_val=_1] >> -char_("dDtT"))
            ];
    }

    qi::rule<Iterator, uint64_t()> start;
};

int main(int argv, const char *argc[]) {
    typedef std::string::const_iterator iter;
    unsigned_parser<iter> up;
    uint64_t val;
    if (argv != 2) {
        std::cerr << "Usage: " << argc[0] << " <input>" << std::endl;
        return 1;
    }
    std::string test(argc[1]);
    iter i = test.begin();
    iter end = test.end();
    bool rv = parse(i, end, up, val);
    if (rv && i == end) {
        std::cout << "Succeeded: " << val << std::endl;
        return 0;
    }
    if (rv) {
        std::cout << "Failed partial parse: " << val << std::endl;
        return 1;
    }
    std::cout << "Failed." << std::endl;
    return 1;
}

解决方法:

噢.除非你扩展库并实现自己的解析器指令,否则没有人应该为像Spirit解析器上下文这样的实现细节而烦恼.

直到那个时候,phoenix :: function<>,phoenix :: bind甚至BOOST_PHOENIX_ADAPT_FUNCTION都应该适合任何人.

以下是您的问题的两种方法,没有任何补丁库.

>直截了当地解析Live On Coliru

这可以被视为使用Qi和简单语义动作解析不同样式的整数的“天真”方式:

start = 
      eps [_val=0] >> +(char_("0-9a-fA-F") [ _val = _val*16 + _decode(_1) ] | '_')>>  char_("hHxX") /* hexadecimal with suffix */
    | eps [_val=0] >> +(char_("0-7")       [ _val = _val* 8 + _decode(_1) ] | '_')>>  char_("qQoO") /* octal       with suffix */
    | eps [_val=0] >> +(char_("01")        [ _val = _val* 2 + _decode(_1) ] | '_')>>  char_("bByY") /* binary      with suffix */
    | eps [_val=0] >> +(char_("0-9")       [ _val = _val*10 + _decode(_1) ] | '_')>> -char_("dDtT") /* decimal     with optional suffix */
    ;

当然,你会想知道_decode是什么样的.那么你自己定义:

struct decode {
    template <typename> struct result { typedef int type; };
    template <typename Ch> int operator()(Ch ch) const {
        if (ch>='0' && ch<='9') return ch - '0';
        if (ch>='a' && ch<='z') return ch - 'a' + 10;
        if (ch>='A' && ch<='Z') return ch - 'A' + 10;
        assert(false);
    }
};
boost::phoenix::function<decode> _decode;

>使用BOOST_PHOENIX_ADAPT_FUNCTION宏Live On Coliru

您可以使用宏来代替定义函数对象

int decode(char ch) {
    if (ch>='0' && ch<='9') return ch - '0';
    if (ch>='a' && ch<='z') return ch - 'a' + 10;
    if (ch>='A' && ch<='Z') return ch - 'A' + 10;
    assert(false);
}

BOOST_PHOENIX_ADAPT_FUNCTION(int, _decode, decode, 1)

>使用std :: strtoul Live On Coliru

当然,上面可能有点“复杂”,因为它需要你处理整数算术和数字解码的细节.

此外,如果文字是十进制值,如“101_101”,“天真”方法会做一些重复的工作.它将计算十六进制,八进制和二进制分支的子结果,然后才能实现它是小数.

所以我们可以改变顺序:

start = 
        (raw[+char_("_0-9a-fA-F")] >>  char_("hHxX")) [ _val = _strtoul(_1,16) ] /* hexadecimal with suffix */
      | (raw[+char_("_0-7")]       >>  char_("qQoO")) [ _val = _strtoul(_1, 8) ] /* octal       with suffix */
      | (raw[+char_("_01")]        >>  char_("bByY")) [ _val = _strtoul(_1, 2) ] /* binary      with suffix */
      | (raw[+char_("_0-9")]       >> -char_("dDtT")) [ _val = _strtoul(_1,10) ] /* decimal     with optional suffix */
      ;

你会很好奇我们如何实施_evaluate?它是一个函数,它从raw(它是一个迭代器范围)和base获取合成属性,然后明确知道它:

struct strtoul_f {
    template <typename, typename> struct result { typedef uint64_t type; };
    template <typename Raw, typename Int> uint64_t operator()(Raw raw, Int base) const {
        std::string s(raw.begin(), raw.end());
        s.erase(std::remove(s.begin(), s.end(), '_'), s.end());
        char *f(&s[0]), *l(f+s.size());
        return std::strtoul(f, &l, base);
    }
};
boost::phoenix::function<strtoul_f> _strtoul;

如您所见,唯一的复杂性是首先从范围中删除_.

标签:boost-spirit-qi,c,boost-spirit
来源: https://codeday.me/bug/20190728/1559370.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有