Boost::Spirit::Qi. How to turn inlined parser expressions into standalone grammars, and how to unpack the tuples generated by them?

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.

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

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

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

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).

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.

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.

How do I deal with this?

9
задан Erius 30 May 2011 в 09:27
поделиться