Boost qi属性以qi::unused_type的形式出现

boost qi attribute is coming up as qi::unused_type

本文关键字:qi 属性 unused Boost type      更新时间:2023-10-16

不能弄清楚为什么这个规则unary_msg不起作用,它说属性类型是qi::unused_type,但这对我来说没有意义。boost为什么这样折磨我?

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_;
  }
};

完整代码:http://coliru.stacked-crooked.com/a/e9afef4585ce76c3

就像cv_and_he提到的那样,添加父元素。

带有许多清理建议的工作示例:

Live On Coliru

指出

  1. 不要在顶层使用using namespace
  2. 不要使用冲突的名称空间(使用stdboost很可能导致意外或冲突)
  3. 不要使用内部属性类型,如fusion::vector
  4. 使用现代风格BOOST_FUSION_ADAPT_STRUCT

  5. 一些小的样式问题

例如下面的函数

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

改为:

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

完整清单和输出

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

打印

parse ok 
(y (x 42)
)