3

I am parsing text into an AST via qi and generates text again via karma. This is working as expected, but wants some method to pass on an attribute from one rule to another.

Ported from the comments:

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

It prints

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

But I'd prefer it to print

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

Is this possible, and how?

4

1 回答 1

3

好的。输出样本"parent parent whee -> parent 4 -> parent 5 -> parent 6 ahhhh -> parent 5 -> 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<>继承的属性

笔记:

  • 我已经简化了 Qi 和 Karma 规则
  • 偏好 Karma 规则中的分隔符
  • lexeme在 Qi 规则中适当使用(提升精神船长问题
  • 如果您不想合成属性,请使用lit("x")而不是string("x")
  • lit()除非选择非精神域表达式模板运算符重载,否则丢弃
  • 利用BOOST_SPIRIT_DEBUG_NODES
  • 不要混合s using namespace。没有必要,它导致麻烦。

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
于 2015-03-18T21:42:37.057 回答