【问题标题】:Getting compilation errors while binding a rule production to my struct members将规则生成绑定到我的结构成员时出现编译错误
【发布时间】:2015-05-02 15:01:13
【问题描述】:

使用 Phoenix bind 编写 Qi 语法我遇到了类似的编译错误

boost/spirit/home/support/context.hpp(180):错误 C2338:index_is_out_of_bounds

这里

>> ruleHandId_[phx::bind(&parseContext::handId_, qi::_r1) = qi::_1];

我只是对凤凰绑定没有太多经验,但在行中绑定了perv

ruleStart_ = ruleEncoding_[phx::bind(&parseContext::encoding_, qi::_r1) = qi::_1]

运行良好,没有编译错误

这一切都在 VS2013 的 MSVC 下,带有 boost 1.56 x86

我在编译错误的代码下做错了什么?

源代码

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

namespace sp = boost::spirit;
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

struct parseContext {
  std::string encoding_;
  uint64_t    handId_;
};

typedef boost::shared_ptr<parseContext> parseContextShPtr;

template <typename Iterator>
struct parseGrammar : qi::grammar<Iterator, void(parseContext&)> {
  parseGrammar() : parseGrammar::base_type(ruleStart_)
  {
    ruleStart_ = ruleEncoding_[phx::bind(&parseContext::encoding_, qi::_r1) = qi::_1]
      >> ruleHandHeader_;
    ruleEncoding_ = qi::lit("ABC");

    ruleHandHeader_ = qi::lit("DEF") >> qi::space
      >> qi::lit("XYZ #")
      >> ruleHandId_[phx::bind(&parseContext::handId_, qi::_r1) = qi::_1];
    ruleHandId_ = qi::long_long;
  }

  // Rules
  qi::rule<Iterator, void(parseContext&)> ruleStart_;
  qi::rule<Iterator, std::string()> ruleEncoding_;
  qi::rule<Iterator> ruleHandHeader_;
  qi::rule<Iterator, uint64_t> ruleHandId_;
};

void test()
{
  std::string s("ABCDEF XYZ #555: PQI #777");
  std::stringstream sb;
  sb.unsetf(std::ios::skipws);
  sb << s;
  const parseGrammar<sp::istream_iterator> p;
  sp::istream_iterator b(sb);
  sp::istream_iterator e;

  parseContextShPtr ctx(new parseContext);
  bool r = qi::parse(b, e, p(phx::ref(*ctx.get())));
  if (r) {
    std::cout << "Success" << std::endl;
  }
  else {
    std::cout << "Failure" << std::endl;
  }

  std::cout << std::string(b, e).substr(0, 32) << std::endl;
}

【问题讨论】:

  • 不可能告诉你出了什么问题,因为你没有显示任何相关代码。如果你隔离那些显然不能说明为什么它不起作用的东西,而是加强它应该通过类比起作用的期望,你基本上只是在抱怨/抱怨。 (您可以改为给您的编译器写一封信。它的工作效率差不多。)使其成为 SSCCE 或至少显示相关声明
  • 添加源代码,抱歉
  • 您确实意识到我们设法发布了一个答案,一个编辑建议,在您正确编辑问题的时间内改进了编辑建议 :) 并且您在此过程中恢复了格式改进...现在看

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


【解决方案1】:

部分占位符无法绑定。

这可能是因为ruleEncoding_ 没有公开属性(对于_1)(不太可能)或ruleStart_ 没有继承属性(_r1)。

我现在只能告诉你这些。

编辑是后者。 ruleHandHeader 没有声明任何属性,更不用说绑定到_r1 的继承属性了

更新评论。

这里有一些建议。根据我经常重复的避免语义动作的建议 (Boost Spirit: "Semantic actions are evil"?),我会将结构调整为融合序列:

并使用大大简化的语法规则:

    ruleStart_      = ruleEncoding_ >> ruleHandHeader_;
    ruleEncoding_   = "ABC";
    ruleHandId_     = qi::long_long;
    ruleHandHeader_ = "DEF XYZ #" >> ruleHandId_;

现在,添加BOOST_SPIRIT_DEBUG 宏并将uint64_t 修复为规则定义中的uint64_t()

Live On Coliru

#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/shared_ptr.hpp>
#include <sstream>

namespace qi = boost::spirit::qi;

struct parseContext {
    std::string encoding_;
    uint64_t    handId_;
};

BOOST_FUSION_ADAPT_STRUCT(parseContext, (std::string, encoding_)(uint64_t,handId_))

typedef boost::shared_ptr<parseContext> parseContextShPtr;

template <typename Iterator>
struct parseGrammar : qi::grammar<Iterator, parseContext()> {
    parseGrammar() : parseGrammar::base_type(ruleStart_)
    {
        ruleStart_      = ruleEncoding_ >> ruleHandHeader_;
        ruleEncoding_   = "ABC";
        ruleHandId_     = qi::long_long;
        ruleHandHeader_ = "DEF XYZ #" >> ruleHandId_;

        BOOST_SPIRIT_DEBUG_NODES((ruleStart_)(ruleEncoding_)(ruleHandId_)(ruleHandHeader_))
    }

    // Rules
    qi::rule<Iterator, parseContext()> ruleStart_;
    qi::rule<Iterator, std::string()> ruleEncoding_;
    qi::rule<Iterator, uint64_t()> ruleHandId_, ruleHandHeader_;
};

void test()
{
    std::stringstream sb("ABCDEF XYZ #555: PQI #777");
    sb.unsetf(std::ios::skipws);

    typedef boost::spirit::istream_iterator It;
    const parseGrammar<It> p;
    It b(sb), e;

    parseContextShPtr ctx(new parseContext);
    bool r = qi::parse(b, e, p, *ctx);
    if (r) {
        std::cout << "Success: " << ctx->encoding_ << ", " << ctx->handId_ << std::endl;
    }

    else {
        std::cout << "Failure" << std::endl;
    }

    if (b!=e)
        std::cout << "Remaining: '" << std::string(b, e).substr(0, 32) << "'...\n";
}

int main()
{
    test();
}

打印

Success: ABC, 555
Remaining: ': PQI #777'...

【讨论】:

  • @Epsilon.Alpha 更新了我的看法
  • 是的,谢谢,我仔细研究了你的变种,看起来比我自己的要好 :) 稍后再发帖
  • 我将我的一段 classic 语法重写到 Fusion 列表中,它几乎没有用,但我会继续使用它一段时间......但我想问更多:如何获得底层规则生成的访问权限?我应该总是将生产价值提升到 ruleStart_ 的水平吗?使用语义动作,我可以在 ruleHandId_ 级别进行设置...但是 Fusion 风格怎么样?如何用 Fusion 做这样的事情?
  • 我不明白你的意思。 “流行音乐”? “产值”? “设置”? “水平”?没有“融合风格”之类的东西。这只是自动属性传播。如果有的话,那就是精神风格。当然,您几乎可以在语义操作中做任何事情,但作为经验法则,这是远离的一个很好的理由。 (这种能力会带来 hacky 解决方案和紧密耦合的解析/处理。它也会带来微妙的错误。)。您可能只问一个关于您的意思的具体问题。请务必包含SSCCE 以及您遇到的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-11
  • 2015-01-21
  • 1970-01-01
  • 2021-02-19
  • 1970-01-01
  • 2013-12-09
相关资源
最近更新 更多