【问题标题】:How is it possible to pass attributes to child rules in boost spirit karma如何在提升精神业力中将属性传递给子规则
【发布时间】:2015-03-18 09:58:27
【问题描述】:

我正在通过 qi 将文本解析为 AST,并通过 karma 再次生成文本。这按预期工作,但需要某种方法将属性从一个规则传递到另一个规则。

从 cmets 移植

Current Code On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>

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

  struct c_struct
  {
    int value1;
  };

  struct b_struct
  {
    std::string value1;
    std::vector< c_struct > value2;
  };

  struct a_struct
  { 
    std::string value1;
    std::vector< b_struct > value2;
  };

BOOST_FUSION_ADAPT_STRUCT( c_struct,    
    (int, value1)
)

BOOST_FUSION_ADAPT_STRUCT( b_struct,    
    (std::string, value1)
    (std::vector< c_struct >, value2)
)

BOOST_FUSION_ADAPT_STRUCT( a_struct,    
    (std::string, value1)
    (std::vector< b_struct >, value2)
)

using namespace boost::spirit;
using namespace boost::spirit::qi;
using namespace boost::spirit::karma;
using namespace boost::spirit::ascii;

template <typename Iterator>
struct grammarB : karma::grammar<Iterator, a_struct()>
{
  grammarB() : grammarB::base_type(ruleA)
  {
    ruleA %= karma::string << karma::lit(' ') << +ruleB << eps;
    ruleB %= karma::string << +ruleC << karma::lit(' ') << eps;    
    ruleC %= lit("  ->  ") << karma::int_;
  }

  karma::rule<Iterator, a_struct()> ruleA;
  karma::rule<Iterator, b_struct()> ruleB;
  karma::rule<Iterator, c_struct()> ruleC;
};

template <typename Iterator>
struct grammarA : qi::grammar<Iterator, a_struct(), boost::spirit::ascii::space_type>
{
  grammarA() : grammarA::base_type(ruleA)
  {
    ruleA %= ruleString >> omit[+qi::char_('.')] >> +ruleB;
    ruleB %= ruleString >> omit[qi::char_(',')] >> (ruleC % qi::char_(',')) >> omit[qi::char_(';')];
    ruleC %= qi::int_;

    ruleString %= +qi::char_("a-z");
  }           
  qi::rule<Iterator, a_struct(), boost::spirit::ascii::space_type> ruleA;   
  qi::rule<Iterator, b_struct(), boost::spirit::ascii::space_type> ruleB;  
  qi::rule<Iterator, c_struct(), boost::spirit::ascii::space_type> ruleC;

  qi::rule<Iterator, std::string(), boost::spirit::ascii::space_type> ruleString;
};    

int main(int argc, char **argv)
{   
  std::string storage("parent ... whee,4,5,6;ahhhh,5,6;"); // We will read the contents here.

  typedef grammarA<std::string::const_iterator> grammarA_t;
  grammarA_t grammar;
  a_struct ast;

  std::string::const_iterator iter = storage.begin();
  std::string::const_iterator end = storage.end();

  bool r = phrase_parse(iter, end, grammar, boost::spirit::ascii::space, ast);

  if (r && iter == end)
  {    
    std::cout << "Parsing succeeded" << std::endl;

    typedef std::back_insert_iterator<std::string> output_iterator_type;

    std::string generated;    
    output_iterator_type sink(generated);

    typedef grammarB<output_iterator_type> grammarB_t; 
    grammarB_t generator;


    if ( generate(sink, generator, ast) )
        std::cout << generated << std::endl;
    else
        std::cout << "fail" << std::endl;
  }

  return 0;
}

打印出来

Parsing succeeded
parent whee  ->  4  ->  5  ->  6 ahhhh  ->  5  ->  6 

但我更喜欢打印出来

Parsing succeeded
parent parent whee -> parent 4 -> parent 5 -> parent 6 ahhhh -> parent 5 -> parent 6

这可能吗?如何实现?

【问题讨论】:

  • 没有 AST。没有生成器 API 调用(既不是迭代器也不是基于流的)。没有绑定属性。究竟想达到什么目的? “wheee”、“cool”和“childish”似乎已经实现了。 提示: 消除噪音,并显示 SSCCE/MVCE
  • SSCCE 根据link 的要求。
  • 如被问及我会知道是否可以从其他规则访问/传递给定的规则属性,从而能够执行与上述相同的操作。需要注意的是,我已经更改了源链接中规则的命名。
  • SSCCE 看起来很有希望。你真的应该在问题中包含它的最小化版本,但是让我看看它。我可能会在阅读过程中为您减少它:/
  • 您没有指定想要的结果。很难以梦想代码的形式“猜测”您所说的“规范”是什么意思(a)无法编译(b)没有显示您希望它实际看起来的样子(c)没有显示它会做什么,即使它是现实的代码。我会继续阅读链接的示例,以防一分钱掉在那里(但由于它确实编译,我怀疑它没有帮助)

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


【解决方案1】:

好的。输出"parent parent whee -&gt; parent 4 -&gt; parent 5 -&gt; parent 6 ahhhh -&gt; parent 5 -&gt; parent 6" 的样本实际上使事情/几乎/清楚。

我认为有不一致之处,因为要么你会期望

parent parent whee -> parent 4 -> parent 5 -> parent 6 parent ahhhh -> parent 5 -> parent 6

你会期望

parent whee -> parent 4 -> parent 5 -> parent 6 ahhhh -> parent 5 -> parent 6 

我会告诉你两个。

ruleA %= string [ _pass_along = _1 ] << +ruleB(_pass_along);
ruleB  = string << +ruleC(_inherited);
//ruleB  = lit(_inherited) << string << +ruleC(_inherited); // alternative interpretation
ruleC  = "->" << lit(_inherited) << karma::int_;

这同时使用了karma::locals&lt;&gt;inherited attributes

注意事项:

  • 我已经简化了 Qi 和 Karma 规则
  • Karma 规则中的偏好分隔符
  • 在 Qi 规则中的适当位置使用lexeme (Boost spirit skipper issues)
  • 如果您不想合成属性,请使用lit("x") 而不是string("x")
  • 删除lit(),除非选择非精神域表达式模板运算符重载
  • 使用BOOST_SPIRIT_DEBUG_NODES
  • 不要不要混合using namespaces。没有必要,它导致麻烦。

Live On Coliru

//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>

#include <boost/fusion/adapted.hpp>
#include <iostream>
#include <fstream>

struct c_struct {
    int value1;
};

struct b_struct {
    std::string value1;
    std::vector<c_struct> value2;
};

struct a_struct {
    std::string value1;
    std::vector<b_struct> value2;
};

BOOST_FUSION_ADAPT_STRUCT(c_struct, (int, value1))
BOOST_FUSION_ADAPT_STRUCT(b_struct, (std::string, value1)(std::vector<c_struct>, value2))
BOOST_FUSION_ADAPT_STRUCT(a_struct, (std::string, value1)(std::vector<b_struct>, value2))

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

template <typename Iterator> struct generator : karma::grammar<Iterator, a_struct(), karma::space_type> {
    generator() : generator::base_type(start) {
        using namespace karma;
        _a_type _pass_along;
        _r1_type _inherited;

        start = ruleA;

        ruleA %= string [ _pass_along = _1 ] << +ruleB(_pass_along);
        ruleB  = string << +ruleC(_inherited);
        //ruleB  = lit(_inherited) << string << +ruleC(_inherited); // alternative interpretation
        ruleC  = "->" << lit(_inherited) << karma::int_;

        BOOST_SPIRIT_DEBUG_NODES((start)(ruleA)(ruleB)(ruleC))
    }

    karma::rule<Iterator, a_struct(), karma::space_type> start;
    karma::rule<Iterator, a_struct(), qi::locals<std::string>, karma::space_type> ruleA;
    karma::rule<Iterator, b_struct(std::string const&), karma::space_type> ruleB;
    karma::rule<Iterator, c_struct(std::string const&), karma::space_type> ruleC;
};

template <typename Iterator> struct grammar : qi::grammar<Iterator, a_struct(), boost::spirit::ascii::space_type> {
    grammar() : grammar::base_type(ruleA) {
        using namespace qi;
        ruleA = ruleString >> lexeme[+qi::lit('.')] >> +ruleB;
        ruleB = ruleString >> ',' >> (ruleC % ',') >> ';';
        ruleC = qi::int_;

        ruleString = +qi::char_("a-z");

        BOOST_SPIRIT_DEBUG_NODES((ruleA)(ruleB)(ruleC)(ruleString))
    }
    qi::rule<Iterator, a_struct(), boost::spirit::ascii::space_type> ruleA;
    qi::rule<Iterator, b_struct(), boost::spirit::ascii::space_type> ruleB;
    qi::rule<Iterator, c_struct(), boost::spirit::ascii::space_type> ruleC;

    qi::rule<Iterator, std::string()/*, boost::spirit::ascii::space_type*/> ruleString;
};

int main() {
    typedef std::string::const_iterator It;
    std::string const storage("parent ... whee,4,5,6;ahhhh,5,6;"); // We will read the contents here.

    grammar<It> grammar;
    a_struct ast;

    It iter = storage.begin(), end = storage.end();
    bool r = phrase_parse(iter, end, grammar, ascii::space, ast);

    if (r && iter == end) {
        std::cout << "Parsing succeeded" << std::endl;

        generator<boost::spirit::ostream_iterator> generator;

        std::cout << "'parent whee  ->  4  ->  5  ->  6 ahhhh  ->  5  ->  6 ' // ORIGINAL\n";
        std::cout << "'parent parent whee -> parent 4 -> parent 5 -> parent 6 ahhhh -> parent 5 -> parent 6 ' // DESIRED/EXPECTED\n";
        std::cout << "'" << karma::format_delimited(generator, karma::space, ast) << "' // ACTUAL\n";
    }
}

输出:

Parsing succeeded
'parent whee  ->  4  ->  5  ->  6 ahhhh  ->  5  ->  6 ' // ORIGINAL
'parent parent whee -> parent 4 -> parent 5 -> parent 6 ahhhh -> parent 5 -> parent 6 ' // DESIRED/EXPECTED
'parent whee -> parent 4 -> parent 5 -> parent 6 ahhhh -> parent 5 -> parent 6 ' // ACTUAL

如果您取消注释替代 ruleB 生成器:

Live On Coliru

输出:

Parsing succeeded
'parent whee  ->  4  ->  5  ->  6 ahhhh  ->  5  ->  6 ' // ORIGINAL
'parent parent whee -> parent 4 -> parent 5 -> parent 6 ahhhh -> parent 5 -> parent 6 ' // DESIRED/EXPECTED
'parent parent whee -> parent 4 -> parent 5 -> parent 6 parent ahhhh -> parent 5 -> parent 6 ' // ACTUAL

【讨论】:

  • 有一些问题:1: "generate_delimited" 在输出中添加分隔符。除了输出中的适当间距之外,该生成器还有其他原因吗?如果不需要定界,猜测“生成”是适用的。 2: 是否可以假设使用“_a_type”/“_r1_type”和使用locals 是解决此问题的一般解决方案?似乎可以轻松扩展此实现以用于更复杂的用途。 3: 为什么不使用默认的phoenix 或spirit _a/_r1 变量?我可能遗漏了文档中的某些内容。
  • @DevDev 1: 是的,原因与您手动插入空格相同。是的,如果不需要它,就不需要它。 2: 嗯。是的。我链接到文档3:我更喜欢可读的代码。
  • 任何阅读此内容的人:这是一个非常好的和全面的反馈,它解决了我的问题。为帮助和展示如何正确提问而脱帽致敬。谢谢
  • 人力资源部。您的评论比that edit 晚了约 8 小时 :) 感谢您的好话
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-14
  • 1970-01-01
相关资源
最近更新 更多