提升精神 - 无法获得属性

时间:2014-02-07 15:05:07

标签: c++ boost boost-spirit boost-spirit-qi

我有以下代码:

#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/spirit/include/qi.hpp>

#include <iostream>
#include <string>
#include <vector>

struct parameter
{
  std::string type;
  std::string name;
};

BOOST_FUSION_ADAPT_STRUCT(
  parameter,
  (std::string, type)
  (std::string, name)
)

inline
std::ostream& operator<<(std::ostream& os, const parameter& param)
{
  os << param.type << ' ' << param.name;

  return os;
}

inline
std::ostream& operator<<(std::ostream& os, const std::vector<parameter>& parameters)
{
  for (const auto& param : parameters)
  {
    os << param;
  }

  return os;
}

struct function
{
  std::vector<parameter> parameters;
};

BOOST_FUSION_ADAPT_STRUCT(
  ::function,
  (std::vector<parameter>, parameters)
)

template <typename Iterator>
struct function_parser : boost::spirit::qi::grammar<Iterator, function(), boost::spirit::qi::ascii::space_type>
{
  function_parser() : function_parser::base_type(start)
  {
    using boost::spirit::qi::alnum;
    using boost::spirit::qi::alpha;

    string %= alpha >> *alnum;
    BOOST_SPIRIT_DEBUG_NODE(string);

    param %= string >> string;
    BOOST_SPIRIT_DEBUG_NODE(param);

    start %= *(param % ',');
    BOOST_SPIRIT_DEBUG_NODE(start);
  }

  boost::spirit::qi::rule<Iterator, std::string()> string;
  boost::spirit::qi::rule<Iterator, parameter, boost::spirit::qi::ascii::space_type> param;
  boost::spirit::qi::rule<Iterator, function(), boost::spirit::qi::ascii::space_type> start;
};

int main()
{
  std::string input_data("int bar, int baz");

  function fn;
  auto itr = input_data.begin();
  auto end = input_data.end();
  function_parser<decltype(itr)> g;
  bool res = boost::spirit::qi::phrase_parse(itr, end, g, boost::spirit::ascii::space, fn);
  if (res && itr == end)
  {
    std::cout << boost::fusion::tuple_open('[');
    std::cout << boost::fusion::tuple_close(']');
    std::cout << boost::fusion::tuple_delimiter(", ");

    std::cout << "Parsing succeeded \n";
    std::cout << "got: " << boost::fusion::as_vector(fn) << std::endl;
  }
  else
  {
    std::cout << "Parsing failed \n";
  }
}

输出

<start>
  <try>int bar, int baz</try>
  <param>
    <try>int bar, int baz</try>
    <string>
      <try>int bar, int baz</try>
      <success> bar, int baz</success>
      <attributes>[[i, n, t]]</attributes>
    </string>
    <string>
      <try>bar, int baz</try>
      <success>, int baz</success>
      <attributes>[[b, a, r]]</attributes>
    </string>
    <success>, int baz</success>
    <attributes>[]</attributes>
  </param>
  <param>
    <try> int baz</try>
    <string>
      <try>int baz</try>
      <success> baz</success>
      <attributes>[[i, n, t]]</attributes>
    </string>
    <string>
      <try>baz</try>
      <success></success>
      <attributes>[[b, a, z]]</attributes>
    </string>
    <success></success>
    <attributes>[]</attributes>
  </param>
  <param>
    <try></try>
    <string>
      <try></try>
      <fail/>
    </string>
    <fail/>
  </param>
  <success></success>
  <attributes>[[[]]]</attributes>
</start>
Parsing succeeded
got: []

解析成功后,为什么“got:”消息后没有列出任何参数?我做错了什么?

1 个答案:

答案 0 :(得分:2)

三个问题:

  1. 您在这里缺少括号:

    boost::spirit::qi::rule<Iterator, parameter(), boost::spirit::qi::ascii::space_type> param;
                                               ^^
    

    我同意,很难改进“迷路”模板参数的诊断并不容易。但是,这个是你很快习惯的东西,因为它是任何语法/规则定义的惯用语。

  2. 您的函数struct只包含一个元素,并且存在一些限制,即使用单元素元组“破坏”抽象。这是一个/非常知名/问题,应该在Spirit V3中得到缓解。现在,要么跳过结构:

    using function = std::vector<parameter>;
    

    或使用'规范'解决方法:

    start %= eps >> (params % ',');
    
  3. 你的开始规则有一个假的kleen明星。如果要允许空参数列表,请执行

    start %= eps >> -(params % ',');
    

    完全不同(允许多个连续,

    start %= eps >> (-params % ',');
    
  4. 样式的剩余元素:%=在没有语义操作的规则上是多余的

  5. 查看 Live On Coliru

    输出:

    <start>
      <try>int bar, int baz</try>
      <param>
    
        <!-- snip -->
        <attributes>[[[i, n, t], [b, a, z]]]</attributes>
      </param>
      <success></success>
      <attributes>[[[[[i, n, t], [b, a, r]], [[i, n, t], [b, a, z]]]]]</attributes>
    </start>
    Parsing succeeded 
    got: [int bar; int baz; ]
    

    完整代码

    #define BOOST_SPIRIT_DEBUG
    #include <boost/fusion/include/adapt_struct.hpp>
    #include <boost/fusion/include/io.hpp>
    #include <boost/spirit/include/qi.hpp>
    
    #include <iostream>
    #include <string>
    #include <vector>
    
    struct parameter
    {
        std::string type;
        std::string name;
    };
    
    BOOST_FUSION_ADAPT_STRUCT(
        parameter,
        (std::string, type)
        (std::string, name)
    )
    
    inline std::ostream& operator<<(std::ostream& os, const parameter& param) { return os << param.type << ' ' << param.name;  }
    inline std::ostream& operator<<(std::ostream& os, const std::vector<parameter>& parameters) {
      for (const auto& param : parameters) { os << param << "; "; }
      return os;
    }
    
    struct function
    {
        std::vector<parameter> parameters;
    };
    
    BOOST_FUSION_ADAPT_STRUCT(
        ::function,
        (std::vector<parameter>, parameters)
    )
    
    template <typename Iterator>
    struct function_parser : boost::spirit::qi::grammar<Iterator, function(), boost::spirit::qi::ascii::space_type>
    {
        function_parser() : function_parser::base_type(start)
        {
            using boost::spirit::qi::alnum;
            using boost::spirit::qi::alpha;
    
            string %= alpha >> *alnum;
            BOOST_SPIRIT_DEBUG_NODE(string);
    
            param %= string >> string;
            BOOST_SPIRIT_DEBUG_NODE(param);
    
            start = boost::spirit::qi::eps >> (param % ',');
            BOOST_SPIRIT_DEBUG_NODE(start);
        }
    
        boost::spirit::qi::rule<Iterator, std::string()> string;
        boost::spirit::qi::rule<Iterator, parameter(), boost::spirit::qi::ascii::space_type> param;
        boost::spirit::qi::rule<Iterator, function(), boost::spirit::qi::ascii::space_type> start;
    };
    
    int main()
    {
        std::string input_data("int bar, int baz");
    
        function fn;
        auto itr = input_data.begin();
        auto end = input_data.end();
        function_parser<decltype(itr)> g;
        bool res = boost::spirit::qi::phrase_parse(itr, end, g, boost::spirit::ascii::space, fn);
        if (res && itr == end)
        {
            std::cout << boost::fusion::tuple_open('[');
            std::cout << boost::fusion::tuple_close(']');
            std::cout << boost::fusion::tuple_delimiter(", ");
    
            std::cout << "Parsing succeeded \n";
            std::cout << "got: " << boost::fusion::as_vector(fn) << std::endl;
            //std::cout << "got: " << fn << std::endl;
        }
        else
        {
            std::cout << "Parsing failed \n";
        }
    }