ICode9

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

c – Boost Spirit X3无法使用变量因子编译repeat指令

2019-09-23 04:04:30  阅读:175  来源: 互联网

标签:boost-spirit-x3 c boost-spirit


我试图使用Boost Spirit X3指令重复一个可变的重复因子.基本思想是头有效载荷,其中头指定有效载荷的大小.一个简单的例子“3 1 2 3”被解释为header = 3,data = {1,2,3}(3个整数).

我只能从精神qi文档中找到例子.它使用boost phoenix引用来包装变量因子:http://www.boost.org/doc/libs/1_50_0/libs/spirit/doc/html/spirit/qi/reference/directive/repeat.html

std::string str;
int n;
test_parser_attr("\x0bHello World",
    char_[phx::ref(n) = _1] >> repeat(phx::ref(n))[char_], str);
std::cout << n << ',' << str << std::endl;  // will print "11,Hello World"

我为精神x3写了以下简单的例子,没有运气:

#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
#include <iostream>

namespace x3 = boost::spirit::x3;
using x3::uint_;
using x3::int_;
using x3::phrase_parse;
using x3::repeat;
using x3::space;
using std::string;
using std::cout;
using std::endl;

int main( int argc, char **argv )
{
  string data("3 1 2 3");
  string::iterator begin = data.begin();
  string::iterator end = data.end();

  unsigned int n = 0;

  auto f = [&n]( auto &ctx ) { n = x3::_attr(ctx); };
  bool r = phrase_parse( begin, end, uint_[f] >> repeat(boost::phoenix::ref(n))[int_], space );
  if ( r && begin == end  )
    cout << "Parse success!" << endl; 
  else
    cout << "Parse failed, remaining: " << string(begin,end) << endl;

  return 0;
}

用boost 1.59.0和clang(flags:-std = c 14)编译上面的代码给出了以下内容:

boost_1_59_0/boost/spirit/home/x3/directive/repeat.hpp:72:47: error: no matching constructor for

      initialization of 'proto_child0' (aka 'boost::reference_wrapper<unsigned int>')

            typename RepeatCountLimit::type i{};

如果我硬编码repeat(3)而不是repeat(boost :: phoenix :: ref(n))它可以正常工作,但它不是一个可能的解决方案,因为它应该支持一个可变的重复因子.

使用repeat(n)进行编译成功完成,但无法使用以下输出进行解析:
“解析失败,剩下:1 2 3”

查看boost / spirit / home / x3 / directive / repeat.hpp:72的源代码,它调用模板类型为RepeatCountLimit :: type变量i的空构造函数,然后在for循环期间分配,迭代min和max.但是由于类型是引用,它应该在构造函数中初始化,因此编译失败.查看以前库版本boost / spirit / home / qi / directive / repeat.hpp:162中的等效源代码,它直接分配:

        typename LoopIter::type i = iter.start();

我不确定我在这里做错了什么,或者x3目前是否不支持可变重复因子.我很感激帮助解决这个问题.谢谢.

解决方法:

根据我收集的信息,阅读源代码和邮件列表,Phoenix根本没有集成到X3中:原因是c 14使得大部分内容都过时了.

我同意这留下了Qi曾经拥有优雅解决方案的一些地方,例如: eps(DEFERRED_CONDITION),懒惰(* RULE_PTR)(Nabialek trick),的确如此.

Spirit X3仍在开发中,所以我们可能会看到这个增加了¹

目前,Spirit X3有一个广泛的有状态环境设施.这实质上取代了locals<>,在某些情况下替换了继承的参数,并且可以/在这个特定情况下使/得到/验证元素的数量:

> x3 ::with²

以下是您可以使用它的方法:

with<_n>(std::ref(n)) 
    [ omit[uint_[number] ] >> 
    *(eps [more] >> int_) >> eps [done] ]

这里,_n是一种标记类型,它使用get< _n>(cxtx)标识要检索的上下文元素.

Note, currently we have to use a reference-wrapper to an lvalue n because with<_n>(0u) would result in constant element inside the context. I suppose this, too, is a QoI that may be lifted as X# matures

现在,对于语义动作:

unsigned n;
struct _n{};

auto number = [](auto &ctx) { get<_n>(ctx).get() = _attr(ctx); };

这将解析的无符号数存储到上下文中. (事实上​​,由于ref(n)绑定,它现在实际上不是上下文的一部分,如上所述)

auto more   = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) >  _val(ctx).size(); };

在这里,我们检查我们实际上并非“满” – 即允许更多的整数

auto done   = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) == _val(ctx).size(); };

在这里,我们检查我们是否“满” – 即不再允许整数.

把它们放在一起:

Live On Coliru

#include <string>
#include <iostream>
#include <iomanip>

#include <boost/spirit/home/x3.hpp>

int main() {
    for (std::string const input : { 
            "3 1 2 3", // correct
            "4 1 2 3", // too few
            "2 1 2 3", // too many
            // 
            "   3 1 2 3   ",
        })
    {
        std::cout << "\nParsing " << std::left << std::setw(20) << ("'" + input + "':");

        std::vector<int> v;

        bool ok;
        {
            using namespace boost::spirit::x3;

            unsigned n;
            struct _n{};

            auto number = [](auto &ctx) { get<_n>(ctx).get() = _attr(ctx); };
            auto more   = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) >  _val(ctx).size(); };
            auto done   = [](auto &ctx) { _pass(ctx) = get<_n>(ctx) == _val(ctx).size(); };

            auto r = rule<struct _r, std::vector<int> > {} 
                  %= with<_n>(std::ref(n)) 
                        [ omit[uint_[number] ] >> *(eps [more] >> int_) >> eps [done] ];

            ok = phrase_parse(input.begin(), input.end(), r >> eoi, space, v);
        }

        if (ok) {
            std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout << v.size() << " elements: ", " "));
        } else {
            std::cout << "Parse failed";
        }
    }
}

哪个印刷品:

Parsing '3 1 2 3':          3 elements: 1 2 3 
Parsing '4 1 2 3':          Parse failed
Parsing '2 1 2 3':          Parse failed
Parsing '   3 1 2 3   ':    3 elements: 1 2 3 

¹在[精神 – 通用]邮件列表中提供支持/声音:)

²找不到合适的文档链接,但它在某些示例中使用

标签:boost-spirit-x3,c,boost-spirit
来源: https://codeday.me/bug/20190923/1813817.html

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

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

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

ICode9版权所有