【问题标题】:How to define the AST for this boost spirit rule?如何定义这个提升精神规则的AST?
【发布时间】:2017-06-07 17:18:46
【问题描述】:

我有一个更复杂的规则,但这个规则足以解决这个问题(我希望如此)。考虑规则:

result = double_ >> *(char_ > int_);

其中 result 是根据命名空间 ast 中的结构结果声明的:

qi::rule<Iterator, ast::result(), qi::space_type> result;

那么ast::result 应该是什么样子的呢? 根据 boost::spirit docs (http://www.boost.org/doc/libs/develop/libs/spirit/doc/html/spirit/abstracts/attributes/compound_attributes.html),属性 char_ &gt; int_tuple&lt;char, int&gt;std::pair&lt;char, int&gt;。 所以,我尝试了:

namespace ast
{

using second_type = std::vector<std::pair<char, int>>;

struct result
{
  double first;
  second_type second;
};

} // namespace ast

除了

BOOST_FUSION_ADAPT_STRUCT(
  ast::result,
  (double, first),
  (ast::second_type, second)
)

但这给了我编译错误:

error: no matching function for call to 'std::pair<char, int>::pair(const char&)'

这个规则很简单,创建将存储结果的 AST 结构也应该很简单......但是如何?

这是我尝试的完整测试程序:

 #include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <iostream>
#include <string>
#include <vector>

namespace ast
{

using second_type = std::vector<std::pair<char, int>>;

struct result
{
  double first;
  second_type second;

  friend std::ostream& operator<<(std::ostream& os, result const& result);
};

std::ostream& operator<<(std::ostream& os, second_type::value_type val)
{
  return os << val.first << ' ' << val.second;
}

std::ostream& operator<<(std::ostream& os, result const& result)
{
  os << result.first;
  for (auto& i : result.second)
      os << ' ' << i;
  return os;
}

} // namespace ast

BOOST_FUSION_ADAPT_STRUCT(
  ast::result,
  (double, first),
  (ast::second_type, second)
)

namespace client
{

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

template <typename Iterator>
class test_grammar : public qi::grammar<Iterator, ast::result(), qi::space_type>
{
 private:
  qi::rule<Iterator, ast::result(), qi::space_type> result;

 public:
  test_grammar() : test_grammar::base_type(result, "result_grammar")
  {
    using qi::double_;
    using qi::char_;
    using qi::int_;

    result = double_ >> *(char_ > int_);
  }
};

} // namespace client

int main()
{
  std::string const input{"3.4 a 5 b 6 c 7"};
  using iterator_type = std::string::const_iterator;
  using test_grammar = client::test_grammar<iterator_type>;
  namespace qi = boost::spirit::qi;

  test_grammar program;
  iterator_type iter{input.begin()};
  iterator_type const end{input.end()};
  ast::result out;
  bool r = qi::phrase_parse(iter, end, program, qi::space, out);

  if (!r || iter != end)
  {
    std::cerr << "Parsing failed." << std::endl;
    return 1;
  }
  std::cout << "Parsed: " << out << std::endl;
}

【问题讨论】:

    标签: c++11 boost-spirit


    【解决方案1】:

    SirGuy 更改了 AST 以适应默认的合成属性。代价是,确实使 AST 复杂化。

    但是,您可以通过调整std::pair 来利用属性兼容性规则。事实上,这就像包含 1 个标题一样简单:

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

    然后,一切编译,打印:

    Parsed: 3.4 a 5 b 6 c 7
    

    【讨论】:

      【解决方案2】:

      我做了以下更改:

      #include <boost/fusion/tuple.hpp>
      
      using second_type = std::vector<boost::fusion::tuple<char, int>>;
      
      std::ostream& operator<<(std::ostream& os, second_type::value_type val)
      {
          return os << boost::fusion::get<0>(val) << ' ' << boost::fusion::get<1>(val);
      }
      

      和为我编译的结果。当然还有其他可用的解决方案。

      【讨论】:

      • 如果你想走这条路,不妨加入Fusion的io.hppcoliru.stacked-crooked.com/a/ed53d098358d120e
      • 谢谢!您基本上说的和 sehe 一样,即不支持 std::pair (不包括标题)。如果不是因为文档只是简单地说明 std::pair 确实有效 - 没有提到标题,我会尝试这样做。我认为这是精神文件的普遍问题;它似乎完全忽略了这样一个事实,即除非您包含正确的标题,否则事情不会起作用,而从未谈论过(那些)标题:/.
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多