Fowlington Downs
Fowlington Downs

Reputation: 11

boost qi attribute is coming up as qi::unused_type

Cannot figure out why this rule unary_msg doesnt work, it says the attribute type is qi::unused_type but this makes no sense to me. Why does boost torment me like this?

template<class It, class Skip= boost::spirit::ascii::space_type>
struct g3: qi::grammar<It, ast::expr(), Skip>
{
  template<typename...Args>
  using R = qi::rule<It, Args...>;

  R<ast::expr(), Skip> start, expr_, term_, unary_term;
  R<ast::intlit()> int_;
  R<std::string()> selector_;
  R<boost::fusion::vector<ast::expr, std::vector<std::string>>, Skip> unary_msg;

  g3(): g3::base_type(start)
  {
    namespace ph = boost::phoenix;
    using namespace boost::spirit::qi;

    int_ = qi::int_;
    selector_ = lexeme[+qi::alnum];

    term_ = int_;
    unary_msg = term_ >> *selector_;
    unary_term = unary_msg[ qi::_val = ph::bind(&collect_unary, qi::_1) ];
    expr_ = unary_term;

    start = expr_;
  }
};

full code: http://coliru.stacked-crooked.com/a/e9afef4585ce76c3

Upvotes: 1

Views: 85

Answers (1)

sehe
sehe

Reputation: 393114

Like cv_and_he mentions, add the parens.

Working example with many cleanup suggestions:

Live On Coliru

Notes

  1. don't use using namespace at toplevel
  2. don't use conflicting namespaces (using std and boost are very likely to lead to surprises or conflicts)
  3. don't use internal attribute types like fusion::vector
  4. use modern style BOOST_FUSION_ADAPT_STRUCT

  5. some minor style issues

For example the following function

ast::expr collect_unary (const boost::fusion::vector<ast::expr, std::vector<std::string>>& parts)
//ast::expr collect_unary (const ast::expr& a, const std::vector<std::string>& msgs)
{
    ast::expr res = boost::fusion::at_c<0>(parts);//a;
    const auto& msgs = boost::fusion::at_c<1>(parts);
    for(const auto& m: msgs)
    {
        ast::message msg;
        msg.name = m;
        msg.args.push_back(res);
        res = msg;
    }
    return res;
}

was changed into:

ast::expr collect_unary(ast::expr accum, const std::vector<std::string>& msgs) {
    for (const auto &m : msgs)
        accum = ast::message { m, { accum } };
    return accum;
}

Full Listing And Output

Live On Coliru

#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi = boost::spirit::qi;

namespace ast {
    struct intlit {
        int value;

        intlit(int i = 0) : value(i) { } 
        intlit(intlit const&other) = default;
    };

    struct nil {};
    struct message;

    using expr = boost::make_recursive_variant<nil, intlit, message>::type;

    struct message {
        std::string name;
        std::vector<ast::expr> args;
    };
}

#include <boost/fusion/include/adapt_struct.hpp>

BOOST_FUSION_ADAPT_STRUCT(ast::intlit, value)
BOOST_FUSION_ADAPT_STRUCT(ast::message, name, args)

struct ast_print {
    void operator()(ast::nil &) const     { std::cout << "nil"; }
    void operator()(ast::intlit &i) const { std::cout << i.value; }
    void operator()(ast::message &m) const {
        std::cout << "(" << m.name;
        for (auto &it : m.args) {
            std::cout << " ";
            boost::apply_visitor(ast_print(), it);
        }
        std::cout << ")" << std::endl;
    }
};

ast::expr collect_unary(ast::expr accum, const std::vector<std::string>& msgs)
{
    for (const auto &m : msgs)
        accum = ast::message { m, { accum } };
    return accum;
}

template <class It, class Skip = boost::spirit::ascii::space_type> struct g3 : qi::grammar<It, ast::expr(), Skip> {
    g3() : g3::base_type(start) {
        using namespace boost::spirit::qi;
        namespace ph = boost::phoenix;

        int_       = qi::int_;
        selector_  = +qi::alnum;

        term_      = int_;
        unary_msg  = (term_ >> *selector_) [ _val = ph::bind(collect_unary, _1, _2) ];
        unary_term = unary_msg;
        expr_      = unary_term;

        start      = expr_;
    }
  private:
    template <typename Attr, typename... Args> using R = qi::rule<It, Attr(), Args...>;

    R<ast::expr, Skip> start, expr_, term_, unary_term, unary_msg;
    R<ast::intlit>     int_;
    R<std::string>     selector_;
};

template <class Parser, typename Result> bool test(const std::string &input, const Parser &parser, Result &result) {
    auto first = input.begin(), last = input.end();
    return qi::phrase_parse(first, last, parser, boost::spirit::ascii::space, result);
}

int main() {
    std::string const input = "42 x y";
    g3<std::string::const_iterator> p;

    ast::expr res;

    if (test(input, p, res)) {
        std::cout << "parse ok " << std::endl;
        boost::apply_visitor(ast_print(), res);
    }
}

Prints

parse ok 
(y (x 42)
)

Upvotes: 1

Related Questions