Boost :: Spirit :: Qi. Como transformar expressões de analisador embutidas em gramáticas independentes e como descompactar as tuplas geradas por elas?
Estou usando QI e Phoenix e quero escrever uma gramática pequena que retorne 4 bools que serão usados como argumentos para uma chamada de função dentro de uma ação semântic
Tenho várias funções que precisam dessas coisas e, até agora, usei essa abordagem:
( qi::_bool >> qi::_bool >> qi::_bool >> qi::_bool)
[px::bind(&Bool4Function, spirit::_val, spirit::_1, spirit::_2, spirit::_3, spirit::_4)]
e enquanto estiver bem por si só, usá-lo em todo o lugar é simplesmente feio e confuso, mesmo com 'usando' as partes do espaço para nom
É por isso que eu queria extrair essa expressão em uma gramática independent
Então eu tentei isso (o crédito vai para ildjarn para o 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();
}
Isso não compila, a menos quefourBools[phx::bind(&noDice, spirit::_1)]
é substituído porfourBools[phx::bind(&worksFine, spirit::_1)]
.
Isso significa, meu problema é descompactar argumentos para corresponder à assinatura da função a ser chamada, pois o número de argumentos difere no nível da assinatura (uma tupla de quatro bools e quatro bools por conta própria
É possível descompactar diretamente usando espaços reservados phoenix, em vez de escrever wrappers que convertem tuplas em argumentos individuais para minhas funções existentes que precisam delas separadas? Se for, qual seria a sintaxe para isso? Afinal, uma versão em linha como( qi::_bool >> qi::_bool >> qi::_bool >> qi::_bool)
funciona bem quando 'descompactado' porspirit::_1 - spirit::_4,
espaços reservados.
Faz parecer que esta versão também retorna uma tupla e é de alguma forma descompactável com a abordagem acima, diferente da gramática que retorna um
Como faço para lidar com isso?