質問

My AST node is struct

  struct node_type
  {
    type::code type_id; 
    boost::variant<int, std::string> value;
  };

Adapter and grammar:

BOOST_FUSION_ADAPT_STRUCT(
    client::node_type,
    (client::type::code, id)
    (boost::variant<int, std::string>, value)
)

namespace client
{  
  struct or_op
  {
    node_type left, right;
  };
  namespace type
  {
    enum code{NUMBER, STRING, BOOL};
  }      
  // Grammar
  template <typename Iterator>
  struct pair_grammar : qi::grammar<
    Iterator,
    node_type(), // Grammar generates node_type
    ascii::space_type
  >
  {
    pair_grammar() : pair_grammar::base_type(
        expr // main 'rule'
      )
    {
      using qi::lit;
      using qi::lexeme;
      using ascii::char_;
      using qi::int_;
      using ascii::string;
      using namespace qi::labels;

      using phoenix::at_c;
      using phoenix::push_back;

      expr = int_[at_c<0>(qi::_val) = 0, at_c<1>(qi::_val) = qi::_1];
    }
    qi::rule<Iterator, node_type(), ascii::space_type> expr;
  };
}

The code above doesn't compile. First of all i get warning

error: macro "BOOST_FUSION_ADAPT_STRUCT_FILLER_0" passed 3 arguments, but takes just 2

and then a lot of errors, starting with

qi/nonterminal/rule.hpp:303:17: error: no match for call to '(const function_type {aka const boost::function<bool(const char*&, const char* const&, boost::spirit::context<boost::fusion::cons<client::node_type&, boost::fusion::nil>, boost::fusion::vector0<> >&, const boost::spirit::qi::char_class<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >&)>}) (const char*&, const char* const&, boost::spirit::qi::rule<const char*, client::node_type(), boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<boost::spirit::tag::char_code<boost::spirit::tag::space, boost::spirit::char_encoding::ascii> >, 0l>, boost::spirit::unused_type, boost::spirit::unused_type>::context_type&, const boost::spirit::unused_type&)'

What am I doing wrong? Thanks.

EDIT: Macro warning appeared because of ',' in macro. Typedef solved problem

  typedef boost::variant<int, std::string> node_value_t;
  struct node_type
  {
    type::code type_id; 
    node_value_t value;
  };

BOOST_FUSION_ADAPT_STRUCT(
    client::node_type,
    (client::type::code, type_id)
    (client::node_value_t, value)
)

But code still doesn't compile. I also tried

number = int_[qi::_val = phoenix::construct<node_type>(type::NUMBER, qi::_1)];

But that didnt help.

EDIT 2: Simplified original rule. Still no success.

役に立ちましたか?

解決

A number of issues here.

  1. The message

    error: macro "BOOST_FUSION_ADAPT_STRUCT_FILLER_0" passed 3 arguments, but takes just 2

    occurs because of the , in the template arguments for variant<>. You can fix it using a typedef:

    namespace client {
        namespace type { enum code{NUMBER, STRING, BOOL}; }      
    
        struct node_type {
            type::code type_id; 
            typedef boost::variant<int, std::string> vt_type;
            vt_type value;
        };
    }
    
    BOOST_FUSION_ADAPT_STRUCT(
            client::node_type,
            (client::type::code, type_id)
            (client::node_type::vt_type, value)
            )
    
  2. You were assigning an int to the attribute of enum type. The implicit conversion is not allowed. Instead, supply the required enum type:

    expr = int_ [at_c<0>(qi::_val) = client::type::NUMBER, at_c<1>(qi::_val) = qi::_1];
    

At this point, everything compiles and works: Live On Coliru

using namespace client;
pair_grammar<std::string::const_iterator> grammar;

std::string const input = "123";
auto f(input.begin()), l(input.end());

node_type node;
bool ok = qi::phrase_parse(f, l, grammar, ascii::space, node);
assert(ok);
assert(f == l);
assert(node.type_id == type::NUMBER);
assert(node.value == node_type::vt_type(123));

I don't think this solution is optimal, though.

Consider using the Spirit directives where possible, and staying away from Semantic actions that uglify the grammar, are a frequent source of errors/UB, make compile times even longer... [1]:

    pair_grammar() : pair_grammar::base_type(expr)
    {
        expr = qi::attr(client::type::NUMBER) >> qi::int_;
    }

See that Live On Coliru too:

#include <boost/fusion/adapted/struct.hpp>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;
namespace ascii = qi::ascii;

namespace client
{
    namespace type
    {
        enum code{NUMBER, STRING, BOOL};
    }      

    struct node_type
    {
        type::code type_id; 
        typedef boost::variant<int, std::string> vt_type;
        vt_type value;
    };
}

/*Adapter and grammar:*/
BOOST_FUSION_ADAPT_STRUCT(
        client::node_type,
        (client::type::code, type_id)
        (client::node_type::vt_type, value)
        )

namespace client
{  
    struct or_op
    {
        node_type left, right;
    };
    // Grammar
    template <typename Iterator>
        struct pair_grammar : qi::grammar<
                              Iterator,
                              node_type(), // Grammar generates node_type
                              ascii::space_type
                              >
    {
        pair_grammar() : pair_grammar::base_type(expr)
        {
            expr = qi::attr(client::type::NUMBER) >> qi::int_;
        }
        qi::rule<Iterator, node_type(), ascii::space_type> expr;
    };
}

int main()
{
    using namespace client;
    pair_grammar<std::string::const_iterator> grammar;

    std::string const input = "123";
    auto f(input.begin()), l(input.end());

    node_type node;
    bool ok = qi::phrase_parse(f, l, grammar, ascii::space, node);
    assert(ok);
    assert(f == l);
    assert(node.type_id == type::NUMBER);
    assert(node.value == node_type::vt_type(123));
}

[1] Boost Spirit: "Semantic actions are evil"?

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top