使用默认值解析为struct

时间:2014-03-29 16:54:10

标签: c++ parsing boost-spirit

我的AST节点是struct

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

适配器和语法:

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

上面的代码无法编译。首先,我得到警告

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

然后是很多错误,从

开始
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&)'

我做错了什么?感谢。

编辑: 由于宏中的','出现了宏警告。 Typedef解决了问题

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

但代码仍然无法编译。我也试过

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

但那并没有帮助。

编辑2:简化原始规则。仍然没有成功。

1 个答案:

答案 0 :(得分:1)

这里有很多问题。

  1. 消息

      

    错误:宏“BOOST_FUSION_ADAPT_STRUCT_FILLER_0”传递了3个参数,但只需2个

    是因为,的模板参数中的variant<>而发生的。您可以使用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. 您正在为枚举类型的属性分配一个int。不允许隐式转换。而是提供所需的枚举类型:

    expr = int_ [at_c<0>(qi::_val) = client::type::NUMBER, at_c<1>(qi::_val) = qi::_1];
    
  3. 此时,所有内容都会编译并运行: 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));
    

    我不认为这个解决方案是最佳的。

    考虑在可能的情况下使用Spirit指令,并远离语法操作,使语法失败,是错误/ UB的常见来源,使编译时间更长...... [1]

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

    也可以看到 Live On Coliru

    #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"?