1

Writing Qi grammar with Phoenix bind I got a compilation error like

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

here

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

I just havent too much expirience with phoenix binding but perv bind in the line

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

works good without compilation errors

It's all under MSVC from VS2013 with boost 1.56 x86

Whats I do wrong under code with the compilation error?

Source Code

#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;
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • It's impossible to tell you what's wrong since you don't show any of the relevant code. If you isolate the things that obviously don't show why it wouldn't work, instead reinforcing the expectation that it should work by analogy, you're basically just whining/complaining. (You could instead write a letter to your compiler. It'll be about as productive.) Make it a SSCCE or at least show the relevant declarations – sehe May 02 '15 at 15:08
  • added source code, sorry – Epsilon.Alpha May 02 '15 at 15:11
  • You do realize that we managed to post an answer, an edit proposal, improve the edit proposal in the time it took for you to edit the question right :) And you reverted the formatting improvements in the process... Looking at it now – sehe May 02 '15 at 15:11

1 Answers1

0

Some of the placeholders cannot be bound.

This could be because ruleEncoding_ doesn't expose an attribute (for _1) (unlikely) or ruleStart_ doesn't have the inherited attribute (_r1).

That's all I can tell you right now.

Edit It was the latter. ruleHandHeader doesn't declare any attributes, let alone an inherited attribute to bind to _r1

Update To the comment.

Here are some suggestions. Much in the vein of my oft-repeated advice to avoid semantic actions (Boost Spirit: "Semantic actions are evil"?), I'd adapt the structure as a fusion sequence:

And use much simplified grammar rules:

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

Now, adding in BOOST_SPIRIT_DEBUG macros and fixing uint64_t to uint64_t() in the rule definition:

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();
}

Prints

Success: ABC, 555
Remaining: ': PQI #777'...
Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633
  • @Epsilon.Alpha Updated with my take on it – sehe May 02 '15 at 15:32
  • yeah, thank you, ill look into your variant, looks way amaizing than my own :) ill post bit later – Epsilon.Alpha May 02 '15 at 15:56
  • I rewrote piece of my *classic* grammar into Fusion lists, its barely work but i will go with it for awhile... but what i would to ask more: how to get access to underlaying rule production? should i always pop production value to the level of **ruleStart_**? using sematic actions i can get setup at level **ruleHandId_**... but how about Fusion style? how to do such thing with Fusion? – Epsilon.Alpha May 03 '15 at 14:32
  • I have no idea what you mean. "pop"? "production value"? "get setup"? "at level"? There's no such thing as "Fusion style". It's just automatic attribute propagation. If anything that's Spirit Style. Of course, you can do nearly anything in semantic actions, but that's a good reason to stay away as a rule of thumb. (The power invites hacky solutions and tightly coupled parsing/processing. Also it invites subtle bugs.). You could probably just ask a concrete question about what you mean. Be sure to incude the [SSCCE](http://sscce.org) and where you are stuck – sehe May 03 '15 at 16:25