Reputation: 779
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.
Upvotes: 1
Views: 266
Reputation: 392911
A number of issues here.
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)
)
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"?
Upvotes: 1