通过属性来独生子女政策升压精神 [英] pass attribute to child rule in boost spirit

查看:90
本文介绍了通过属性来独生子女政策升压精神的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有相同属性的两个规则。

I have two rules with the same attribute.

是否有可能在matrix_规则的属性传递给孩子matrixBlock_规则?
我想保留重复指令从创建表单矢量<的属性>。相反,它应该保持写入matrix_的属性(numBlocks的时间)。
我试图通过属性为继承属性到子规则,它编译(见下文)。但是,我得到我的矢量几个鬼条目从凤凰::的push_back来不是。
另外这似乎不是我的最佳方式。是否有可能给我们matrixBlock_自动属性传播,而不是语义动作?

Is it possible to pass the attribute of the matrix_ rule to the matrixBlock_ child rule? I want to keep the repeat directive from creating an attribute of the form vector< >. Instead it should just keep writing into the attribute of matrix_ (numBlocks's times). I tried to pass the attribute as inherited attribute to the child rule and it compiles(see below). But I get several "ghost" entries in my vector which come not from the phoenix::push_back. Also this seems not to be the optimal way for me. Is it possible to us automatic attribute propagation in matrixBlock_ instead of semantic actions?

typedef vector<columnT> Matrix;
matrix_ = repeat(numBlocks)[ matrixBlock_(_val) ];
matrixBlock_ = *column[phoenix::push_back(_r1, _1)];

qi::rule<Iterator, Matrix(), ascii::space_type> matrix_;
qi::rule<Iterator, void(Matrix&), ascii::space_type> matrixBlock_;


更新

澄清的问题是:

如果我写的规则没有语义动作matrix_的综合属性会

if I write the rule with no semantic actions the synthesized attribute of matrix_ would be

vector< vector< columnT > >

-

typedef vector<columnT> Matrix;
matrix_ = repeat(numBlocks)[ matrixBlock_ ];
matrixBlock_ = *column;

qi::rule<Iterator, Matrix(), ascii::space_type> matrix_;
qi::rule<Iterator, Matrix(), ascii::space_type> matrixBlock_;

我希望它具有相同的属性类型,matrixBlock_,1 dimansional阵列。

I want it to have the same attribute type as matrixBlock_, a 1-dimansional array.

我实际的解决办法是使用只有一个规则。 (看起来容易:-))

my actual solution is to use only one rule. (looks to easy :-) )

typedef vector<columnT> Matrix;
matrix_ = repeat(numBlocks)[ *column_[ phoenix::push_back(_val, _1) ] ];
//matrixBlock_ = *column;

qi::rule<Iterator, Matrix(), ascii::space_type> matrix_;
//qi::rule<Iterator, Matrix(), ascii::space_type> matrixBlock_;


更新

我能够重现的幻影项与VS2010这code和提升1.46.1


Update

I was able to reproduce the the phantom entries with this code in vs2010 and boost 1.46.1

http://liveworkspace.org/$c$c/505091dc4631a379763567168a728e0c

产量为:42,45,-9,3,2,1,12,34,56,0,0,0

output was: 42, 45, -9, 3, 2, 1, 12, 34, 56, 0, 0, 0

我的错误使用旧版本的加速了。有没有phontoms 1.5。

My mistake was using an old Boost version. There are no phontoms with 1.5.

现在我有我的语法两个工作版本。是否有可能重新设计语法而不使用的push_back语义动作的

Now I have two working versions of my grammar. Is it possible to redesign the grammar without the use of the push_back semantic action?

推荐答案

回答您的问题编辑:是的,你可以做到这一点没有语义动作,做简单的:

Updated

Answering your edited question: Yes you can do this without semantic actions, doing simply:

template<typename It>
struct Parser : qi::grammar<It, Matrix(), qi::space_type>
{
    Parser() : Parser::base_type(matrix_)
    {
        matrixBlock_ = qi::lit(";") >> *qi::int_;
        matrix_      = qi::repeat(3)[ matrixBlock_ ];
    }
    qi::rule<It, Matrix(), qi::space_type> matrixBlock_, matrix_;
};

请注意,您的可能的要验证的行/列数。 看到我伸出样本 ,它使用一个额外的语义行动检查这(注意,从的微妙的变化* INT _ + INT _ 来避免空行):

Note that you may want to validate the number of rows/columns. See my extended sample, which uses an extra semantic action to check that (note the subtle change from *int_ to +int_ to avoid empty rows):

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

namespace qi    = boost::spirit::qi;
namespace karma = boost::spirit::karma;
namespace phx   = boost::phoenix;

typedef std::vector<int> Matrix;

template<typename It>
struct Parser : qi::grammar<It, Matrix(), qi::space_type>
{
    Parser() : Parser::base_type(matrix_)
    {
        using namespace qi;
        matrixBlock_ = lit(";") >> +int_ >> eps( 0 == (phx::size(_val) % 3));
        matrix_      = repeat(3)[ matrixBlock_ ];
    }
    qi::rule<It, Matrix(), qi::space_type> matrixBlock_, matrix_;
};

int main()
{
    std::string test = ";42 45 -9; 3 2 1; 12 34 56";

    std::string::const_iterator f(test.begin()), l(test.end());

    Parser<std::string::const_iterator> parser;
    Matrix m;

    if (qi::phrase_parse(f,l,parser,qi::space, m))
        std::cout << "Wokay\n";
    else
        std::cerr << "Uhoh\n";

    std::cout << karma::format(karma::auto_ % ", ", m) << "\n";
}


旧的答案的:

是的,你可以使用圣灵的自定义点的来对待你的用户定义类型的容器。文档录入我建议这是在这里:

Yes, you can use Spirit's customization points to treat your user-defined type as a container. The documentation entry I'd suggest for this is here:

下面是显示如何使用一个简单的例子,住:

Here is a simple example showing how to use it, live:

边注与问候虚拟项目,在一般情况:

Side note with regards to 'phantom entries', in general:

请注意,有一点与回溯语法和容器属性的常见问题。事实是,出于性能考虑,解析器不会撤销对回溯('回退')改变其基本的容器。您可以强制使用这种行为<一个href=\"http://www.boost.org/doc/libs/1_51_0/libs/spirit/doc/html/spirit/qi/reference/directive/hold.html\"相对=nofollow> 齐::持有 但它可能值得语法重新设计,以努力为

Note that there is a bit of a FAQ related to backtracking grammars and container attributes. The thing is, for performance reasons, parsers won't undo ('rollback') changes to their underlying containers on backtracking. You can force this behaviour using qi::hold but it may worth the effort to redesign the grammar to either


      
  • 避免回溯或

  •   
  • 提交到属性在稍后阶段(使用语义动作)

  •   

全部code样品:<​​/ P>

Full code sample:

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

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

struct Matrix
{
   std::vector<int> data;
};

namespace boost { namespace spirit { namespace traits {
   template <>
      struct is_container<Matrix>
      {
      };

   template <typename Attrib>
      struct push_back_container<Matrix, Attrib>
      {
         static bool call(Matrix& c, Attrib const& val)
         {
            c.data.push_back(val);
            return true;
         }
      };

   template <>
      struct container_value<Matrix>
      {
         typedef int type;
      };
} } }

template<typename It>
struct Parser : qi::grammar<It, Matrix(), qi::space_type>
{
   Parser() : Parser::base_type(start)
   {
      start = *qi::int_;
   }
   qi::rule<It, Matrix(), qi::space_type> start;
};

int main()
{
   std::string test = "42 45 -9";

   std::string::const_iterator f(test.begin()),
      l(test.end());

   Parser<std::string::const_iterator> parser;
   Matrix m;

    if (qi::phrase_parse(f,l,parser,qi::space, m))
      std::cout << "Wokay\n";
   else
      std::cerr << "Uhoh\n";

   std::cout << karma::format(karma::auto_ % ", ", m.data) << "\n";
}

输出:

Wokay
42, 45, -9


更新

一个多一点背景:


Update

A little more background:

当然,对于这样一个简单的例子,只是包装了一个标准支持的容器类型,这将是相当容易使用融合的调整的代替:(的 http://liveworkspace.org/$c$c/56aea8619867451a21cd49fddb1e93bd

Of course, for a trivial example like this, that just wraps a standard supported container type, it would be fairly easy to employ fusion adaptation instead: ( http://liveworkspace.org/code/56aea8619867451a21cd49fddb1e93bd )

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/adapted/struct.hpp>

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

struct Matrix { std::vector<int> data; }; 
BOOST_FUSION_ADAPT_STRUCT(Matrix, (std::vector<int>, data));

int main()
{
    std::string test = "42 45 -9";
    std::string::const_iterator f(test.begin()), l(test.end());

    Matrix m;
    if (qi::phrase_parse(f,l, qi::eps >> *qi::int_, qi::space, m))
        std::cout << karma::format(karma::auto_ % ", ", m.data) << "\n";
}

注意齐:: EPS 是必要的,因为与只包含一个数据元素结构中的错误(AFAICT)。例如参见<一href=\"http://boost.2283326.n4.nabble.com/BOOST-FUSION-ADAPT-STRUCT-with-single-entry-td2675332.html#a2675334\"相对=nofollow>这里的讨论(和其他一些提到)

Note that the qi::eps is necessary due to a bug (AFAICT) with structs that contain only one data element. See e.g. discussion here (and some other mentions)

这篇关于通过属性来独生子女政策升压精神的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆