的boost ::精神::齐。如何打开内嵌解析器前pressions到独立的语法,以及如何解开他们所产生的元组? [英] Boost::Spirit::Qi. How to turn inlined parser expressions into standalone grammars, and how to unpack the tuples generated by them?

查看:325
本文介绍了的boost ::精神::齐。如何打开内嵌解析器前pressions到独立的语法,以及如何解开他们所产生的元组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用QI和凤凰城,我想写一个小的语法返回4的bool这是被用作语义动作里面的函数调用的参数。

I'm using QI and Phoenix, and I want to write a small grammar that returns 4 bools which are to be used as arguments for a function call inside a semantic action.

我需要这些东西多种功能,到目前为止,我已经使用这个方法:

I have several functions that need those things, and so far I have used this approach:

( qi::_bool >>  qi::_bool >>  qi::_bool >>  qi::_bool)
[px::bind(&Bool4Function, spirit::_val, spirit::_1, spirit::_2, spirit::_3, spirit::_4)]

虽然它在它自己的好,用它所有的地方只是普通的丑陋和混乱,甚至与用的命名空间的部分。

and while it's okay on it's own, using it all over the place is just plain ugly and confusing, even with 'using' the namespace parts.

这就是为什么我想这个提取前pression到一个独立的语法。

That's why I wanted to extract this expression into a standalone grammar.

所以,我想这(归功于ildjarn为测试平台):

So I tried this (credit goes to ildjarn for the testbed):

///// grammar implementation /////
#include <boost/fusion/include/vector10.hpp>
#include <boost/spirit/include/qi_bool.hpp>
#include <boost/spirit/include/qi_char_.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
#include <boost/spirit/include/qi_operator.hpp>
#include <boost/spirit/include/qi_rule.hpp>
#include <boost/spirit/include/qi_string.hpp>

struct FourBools : boost::spirit::qi::grammar<
    char const*,
    boost::fusion::vector4<bool, bool, bool, bool>()
>
{
    typedef boost::fusion::vector4<bool, bool, bool, bool> attribute_type;

    FourBools() : base_type(start_)
    {
        using boost::spirit::bool_;

        start_
            =   "4bools:"
            >> bool_ >> ','
            >> bool_ >> ','
            >> bool_ >> ','
            >> bool_ >> ';'
            ;
    }

private:
    boost::spirit::qi::rule<
        base_type::iterator_type,
        base_type::sig_type
    > start_;
};
FourBools const fourBools;


///// demonstration of use /////
#include <string>
#include <ios>
#include <iostream>
#include <boost/fusion/include/at_c.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/spirit/include/qi_parse.hpp>



void noDice(bool a, bool b, bool c, bool d) 
{

}

void worksFine(boost::fusion::vector4<bool, bool, bool, bool> a)
{

}
int main()
{
    namespace phx = boost::phoenix;
    namespace spirit = boost::spirit;

    std::string const input("4bools:true,true,true,false;");


    char const* first = input.c_str();
    char const* const last = first + input.size();
    bool const success = spirit::qi::parse(
        first, last,
        fourBools[phx::bind(&noDice, spirit::_1)]
    );


    if (!success)
        std::cout << "parse() failed\n";
    else if (first != last)
        std::cout << "didn't consume all input\n";
    std::cout.flush();
}

这不能编译,除非 fourBools [PHX ::绑定(安培; noDice,精神:: _ 1)] 替换 fourBools [ PHX ::绑定。(安培; worksFine,精神:: _ 1)]

That doesn't compile unless fourBools[phx::bind(&noDice, spirit::_1)] is replaced with fourBools[phx::bind(&worksFine, spirit::_1)].

这意味着,我的问题是参数匹配函数的签名的拆包被调用,由于参数的数量在签署水平(四布尔变量,VS他们的四位布尔变量一个元组)不同。

That means, my problem is the unpacking of arguments to match the signature of the function to be called, since the number of arguments differ at signature level (one tuple of four bools, vs four bools on their own).

是否有可能直接使用,而不需要编写包装这对于需要它们分开我现有的功能转化成元组参数个人凤占位符,解压?
如果是这样,这将是该语法?
毕竟,一个内嵌版本像(气:: _布尔&GT;&GT;气虚:: _布尔&GT;&GT;气虚:: _布尔&GT;&GT;气虚:: _布尔)正常工作时,由精神解压:: _ 1 - 精神:: _ 4,占位符

Is it possible to unpack using phoenix placeholders directly, instead of writing wrappers which translate tuples into individual arguments for my existing functions that need them separate? If it is, what would be the syntax for that? After all, an inline version like ( qi::_bool >> qi::_bool >> qi::_bool >> qi::_bool) works fine when 'unpacked' by spirit::_1 - spirit::_4, placeholders.

这使得它在我看来,如果这个版本返回一个元组的欢迎,并与上述做法在某种程度上unpackable,不像返回一个语法。

That makes it appear to me as if this version returns a tuple as well, and is somehow unpackable with the above approach, unlike a grammar that returns one.

我该如何处理?

推荐答案

这是pretty太多无法诊断您的问题,如果你不张贴一个完整的,连贯的摄制;它可能是一个语法错误,这可能是一个缺少的#include ,谁知道......?

It's pretty much impossible to diagnose your issue if you don't post a complete, coherent repro; it could be a syntax error, it could be a missing #include, who knows..?

下面是一个工作示范;希望你可以使用它作为参考来找出什么是错了你的code:

Here's a working demonstration; hopefully you can use it as a reference to figure out what's wrong with your code:

///// grammar implementation /////
#include <boost/fusion/include/vector10.hpp>
#include <boost/spirit/include/qi_bool.hpp>
#include <boost/spirit/include/qi_char_.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
#include <boost/spirit/include/qi_operator.hpp>
#include <boost/spirit/include/qi_rule.hpp>
#include <boost/spirit/include/qi_string.hpp>

struct FourBools : boost::spirit::qi::grammar<
    char const*,
    boost::fusion::vector4<bool, bool, bool, bool>()
>
{
    typedef boost::fusion::vector4<bool, bool, bool, bool> attribute_type;

    FourBools() : base_type(start_)
    {
        using boost::spirit::bool_;

        start_
            =   "4bools:"
                >> bool_ >> ','
                >> bool_ >> ','
                >> bool_ >> ','
                >> bool_ >> ';'
            ;
    }

private:
    boost::spirit::qi::rule<
        base_type::iterator_type,
        base_type::sig_type
    > start_;
};
FourBools const fourBools;


///// demonstration of use /////
#include <string>
#include <ios>
#include <iostream>
#include <boost/fusion/include/at_c.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/spirit/include/qi_parse.hpp>

typedef FourBools::attribute_type attr_t;

struct verify_same
{
    explicit verify_same(attr_t const& expected) : expected_(expected) { }

    void verify(attr_t const& actual) const
    {
        using boost::fusion::at_c;

        std::cout << std::boolalpha
            << "same as expected: " << (actual == expected_)
            << "\nactual values: "
            << at_c<0>(actual) << ' '
            << at_c<1>(actual) << ' '
            << at_c<2>(actual) << ' '
            << at_c<3>(actual) << '\n';
    }

private:
    attr_t expected_;
};

int main()
{
    namespace phx = boost::phoenix;
    namespace spirit = boost::spirit;

    std::string const input("4bools:true,true,true,false;");
    verify_same const vs(attr_t(true, true, true, false));

    char const* first = input.c_str();
    char const* const last = first + input.size();
    bool const success = spirit::qi::parse(
        first, last,
        fourBools[phx::bind(&verify_same::verify, phx::cref(vs), spirit::_1)]
    );
    if (!success)
        std::cout << "parse() failed\n";
    else if (first != last)
        std::cout << "didn't consume all input\n";
    std::cout.flush();
}

顺便说一句,我认为使用带有纯粹同质类型的元组很奇怪;就个人而言,我会语法的综合属性更改为的boost ::数组&LT;布尔,4方式&gt;

修改(响应OP的编辑):有好消息和一个坏消息和更多的好消息。

EDIT (in response to OP's edit): There's good news and bad news and more good news.

下面是个好消息: Boost.Fusion 具有的功能做的正是你想要什么做到用最少的code:<一href=\"http://www.boost.org/doc/libs/release/libs/fusion/doc/html/fusion/functional/adapters/fused.html\"相对=nofollow> 的boost ::融合::融合&LT;&GT; 。这将需要一个可调用类型(包括自由函数指针和成员函数指针),这需要多个参数,敷在仿函数,需要一个融合序列可调用类型;调用此函数对象的时候,它需要融合序列,并解压缩它,转发元组的各个元素包装的可调用类型作为单独的参数。

Here's the good news: Boost.Fusion has functionality to do exactly what you want to do with minimal code: boost::fusion::fused<>. This will take a callable type (including free-function pointers and member-function pointers) that takes multiple arguments and wrap that callable type in a functor that takes a Fusion sequence; when this functor is invoked, it takes the Fusion sequence and unpacks it, forwarding the individual elements of the tuple to the wrapped callable type as separate arguments.

因此​​,考虑到我已经张贴的语法和以下内容:

So, given the grammar I already posted and the following:

#include <string>
#include <ios>
#include <iostream>
#include <boost/fusion/include/at_c.hpp>
#include <boost/fusion/include/make_fused.hpp>
#include <boost/spirit/include/phoenix_bind.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/qi_action.hpp>
#include <boost/spirit/include/qi_parse.hpp>

typedef FourBools::attribute_type attr_t;

void free_func_taking_tuple(attr_t const& tup)
{
    using boost::fusion::at_c;

    std::cout << std::boolalpha
        << "inside free_func_taking_tuple() :: "
        << at_c<0>(tup) << ' '
        << at_c<1>(tup) << ' '
        << at_c<2>(tup) << ' '
        << at_c<3>(tup) << '\n';
}

void free_func_taking_bools(
    bool const a, bool const b,
    bool const c, bool const d
)
{
    std::cout << std::boolalpha
        << "inside free_func_taking_bools() :: "
        << a << ' '
        << b << ' '
        << c << ' '
        << d << '\n';
}

的boost ::精神::气::解析()可以被称为像这样:

namespace phx = boost::phoenix;
namespace spirit = boost::spirit;
using boost::fusion::make_fused;

// calls free_func_taking_tuple, nothing new here
spirit::qi::parse(
    first, last,
    fourBools[phx::bind(free_func_taking_tuple, spirit::_1)]
);

// calls free_func_taking_bools, using boost::fusion::fused<> to unpack the tuple
// into separate arguments
spirit::qi::parse(
    first, last,
    fourBools[phx::bind(make_fused(&free_func_taking_bools), spirit::_1)]
);

下面是坏消息:Boost.Fusion的可调用类型的包装靠TR1 / C ++ 11 的result_of 协议,而Boost.Phoenix V2实现Boost.Lambda 的result_of 协议&ndash的;这些是不兼容的。这样一来,你必须自己把它解析元素:

Here's the bad news: Boost.Fusion's callable type wrappers rely on the TR1/C++11 result_of protocol, while Boost.Phoenix v2 implements the Boost.Lambda result_of protocol – these are not compatible. As a result, you must unpack the tuple elements yourself:

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

spirit::qi::parse(
    first, last,
    fourBools[phx::bind(
        free_func_taking_bools,
        phx::at_c<0>(spirit::_1),
        phx::at_c<1>(spirit::_1),
        phx::at_c<2>(spirit::_1),
        phx::at_c<3>(spirit::_1)
    )]
);

呸!但是,还有更多的好消息:Boost.Phoenix V3将会在升压1.47发布,并实现了TR1 / C ++ 11 的result_of 的协议。因此,从升压1.47你就可以使用的boost ::融合::融合&LT;方式&gt; ,并保存自己的一些繁琐的样板

Yuck! But, there's more good news: Boost.Phoenix v3 is going to be released in Boost 1.47, and it implements the TR1/C++11 result_of protocol. Consequently, starting with Boost 1.47 you'll be able to use boost::fusion::fused<> and save yourself some tedious boilerplate.

这篇关于的boost ::精神::齐。如何打开内嵌解析器前pressions到独立的语法,以及如何解开他们所产生的元组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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