c – 使用boost :: spirit :: qi用分隔符解析数字
我试图使用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; 如您所见,唯一的复杂性是首先从范围中删除_. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |