Boost Spirit X3: “Attribute does not have the expe

2019-06-21 09:35发布

问题:

I am trying to write a parser with Spirit X3, but I haven't gotten very far because I'm running into a compilation error that I can't figure out. I think I know what the compiler is complaining about, but what I don't understand is why it cares. The following code compiles (clang 3.9, Boost 1.62.0) and works. (I realize it's structured poorly and that there are built-in parsers for constants; I'm just trying to demonstrate the issue.)

#define BOOST_SPIRIT_X3_DEBUG

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

using namespace std;
namespace x3 = boost::spirit::x3;

namespace lang {

    using namespace x3;

    struct Constant {
    };

    rule<class constant_id, Constant> const constant = "constant";

    auto const integer_literal = -char_('-') >> +digit;
    auto const float_literal = -char_('-') >> +digit >> -(char_('.') >> *digit);

    auto const constant_def = (integer_literal)[([](auto &ctx) { _val(ctx) = Constant(); })];

    BOOST_SPIRIT_DEFINE(constant);
}

int main(int argc, char *argv[]) {

    string s("3.14159");
    if (x3::phrase_parse(s.begin(), s.end(), lang::constant, x3::space)) {
        cout << "Ok!";
    } else {
        cout << "Error!";
    }

    return 0;
}

However, if I change constant_def to use float_literal instead of integer_literal:

auto const constant_def = (float_literal)[([](auto &ctx) { _val(ctx) = Constant(); })];

I start to get a compilation error.

sequence.hpp:143:9: error: static_assert failed "Attribute does not have the expected size."
    static_assert(
    ^

Looking at the source, I see a message:

// If you got an error here, then you are trying to pass
// a fusion sequence with the wrong number of elements
// as that expected by the (sequence) parser.

I think that the error has to do with the presence of the optional in the definition of float_literal. I believe that the attribute type of integer_literal is something like vector<char> but that the optional causes the attribute of float_literal to be something like tuple<vector<char>, optional<vector<char>>>? And somewhere I'm trying to force that to be a string or something and it's failing because it's trying to convert a 2-tuple to a 1-tuple. I suspect that the solution is to wrap the float_literal definition in raw[] so that I get the underlying string instead, which is want I want anyway. But since this is my first X3 parser, I want to understand why the compiler is raising this error so I can diagnose it if it comes up in another context.

What I really don't understand is why the compiler cares about the type of float_literal. I've attached a semantic action that generates an instance of Constant, which is the attribute type of the constant rule, without any reference to the attribute of float_literal, so why does the compiler care about the attribute of float_literal at all? Where is it trying to do the unequal-length-sequence assignment, and for what purpose?

Thanks!