Pergunta

neste artigo sobre o boost espírito semântica ações é mencionado que

Na verdade, existem mais de 2 argumentos sendo passado:o analisador de contexto e um referência a um boolean 'hit' o parâmetro.O analisador de contexto é só fará sentido se a semântica de ação é ligado em algum lugar à direita lado de uma regra.Vamos ver mais informações sobre isso em breve.O valor booleano pode ser definida como false no interior da semântica da ação invalida o jogo em retrospectiva, fazendo com que o analisador de falhar.

Tudo bem, mas eu tenho tentado encontrar um exemplo de passagem de um objeto de função como semântica ação que usa a outros parâmetros (analisador de contexto e bater boolean), mas eu ainda não encontrei nenhuma.Eu gostaria de ver um exemplo utilizando funções regulares ou função de objetos, como eu mal pode grok o phoenix voodoo

Foi útil?

Solução

Este realmente uma boa pergunta (e também uma lata de vermes), porque chega na interface do qi e phoenix.Eu não tenha visto um exemplo, por isso, vou estender o artigo um pouco nesta direção.

Como você diz, funções para semântica ações pode levar até três parâmetros

  1. Correspondência atributo coberto no artigo
  2. Contexto - contém o qi-phoenix interface
  3. Correspondência bandeira - manipular a correspondência estado

Correspondência bandeira

Como diz o artigo, o segundo parâmetro não é significativa, a menos que a expressão é parte de uma regra, então vamos começar com o terceiro.Um espaço reservado para o segundo parâmetro é ainda necessária e, para isso, usar boost::fusion::unused_type.Assim, uma função modificada de artigo para usar o terceiro parâmetro é:

#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iostream>

void f(int attribute, const boost::fusion::unused_type& it, bool& mFlag){
    //output parameters
    std::cout << "matched integer: '" << attribute << "'" << std::endl
              << "match flag: " << mFlag << std::endl;

    //fiddle with match flag
    mFlag = false;
}

namespace qi = boost::spirit::qi;

int main(void){
   std::string input("1234 6543");
   std::string::const_iterator begin = input.begin(), end = input.end();

   bool returnVal = qi::phrase_parse(begin, end, qi::int_[f], qi::space);

   std::cout << "return: " << returnVal << std::endl;
   return 0;
}

saídas:

matched integer: '1234'
match flag: 1
return: 0

Todos este exemplo faz é mudar o jogo para um não-jogo, o que se reflete no analisador de saída.De acordo com hkaiser, no impulso de 1.44 e até fazer uma partida sinalizador como false fará com que o jogo falha em modo normal.Se as alternativas são definidos, o analisador irá recuar e tentar combiná-los, como seria de esperar.No entanto, em impulso<=1.43 um Espírito bug impede o retrocesso, o que faz com que um comportamento estranho.Para ver isso, adicione phoenix incluem boost/spirit/include/phoenix.hpp e mudar a expressão para

qi::int_[f] | qi::digit[std::cout << qi::_1 << "\n"]

Seria de esperar que, quando o qi::int analisador de falha, a alternativa qi::dígito para coincidir com o início da entrada em "1", mas o resultado é:

matched integer: '1234'
match flag: 1
6
return: 1

O 6 é o primeiro dígito do segundo int na entrada que indica a alternativa foi tirada usando o capitão e sem retrocesso.Observe também que a partida é considerada bem sucedida, com base na alternativa.

Uma vez impulso de 1,44 está fora da partida bandeira será útil para a aplicação de critérios de correspondência, que podem ser difíceis de expressar em um analisador de sequência.Nota-se que o combate bandeira pode ser manipulado em phoenix expressões usando o _pass espaço reservado.

O parâmetro de contexto

O mais interessante do parâmetro e o segundo, que contém o qi-phoenix interface, ou em qi linguagem, o contexto da semântica da ação.Para ilustrar isso, primeiro examinar uma regra:

rule<Iterator, Attribute(Arg1,Arg2,...), qi::locals<Loc1,Loc2,...>, Skipper>

O parâmetro de contexto encarna o Atributo, Arg1, ...ArgN, e qi::moradores modelo de parâmetros, envolto em um impulso::espírito::o contexto de tipo de modelo.Este atributo é diferente do parâmetro de função:o parâmetro da função de atributo é analisada valor, enquanto este atributo é o valor da regra em si.Uma semântica da ação deve mapa do primeiro para o segundo.Aqui está um exemplo de um possível tipo de contexto (phoenix expressão equivalentes indicado):

using namespace boost;
spirit::context<              //context template
    fusion::cons<             
        int&,                 //return int attribute (phoenix: _val)
        fusion::cons<
            char&,            //char argument1       (phoenix: _r1)
            fusion::cons<
                float&,       //float argument2      (phoenix: _r2) 
                fusion::nil   //end of cons list
            >,
        >,
    >,
    fusion::vector2<          //locals container
        char,                 //char local           (phoenix: _a)
        unsigned int          //unsigned int local   (phoenix: _b)
    > 
>

Observação o retorno atributo e lista de argumento assumir a forma de um lisp-lista de estilo (um contras lista).Para ter acesso a estas variáveis dentro de uma função, o acesso a attribute ou locals os membros do context estrutura do modelo com fusão::no<>().Por exemplo, para uma variável de contexto con

//assign return attribute
fusion::at_c<0>(con.attributes) = 1;

//get the second rule argument
float arg2 = fusion::at_c<2>(con.attributes);

//assign the first local
fusion::at_c<1>(con.locals) = 42;

Para modificar o artigo exemplo, para utilizar o segundo argumento, altere a definição de função e phrase_parse chamadas:

...
typedef 
    boost::spirit::context<
        boost::fusion::cons<int&, boost::fusion::nil>, 
        boost::fusion::vector0<> 
    > f_context;
void f(int attribute, const f_context& con, bool& mFlag){
   std::cout << "matched integer: '" << attribute << "'" << std::endl
             << "match flag: " << mFlag << std::endl;

   //assign output attribute from parsed value    
   boost::fusion::at_c<0>(con.attributes) = attribute;
}
...
int matchedInt;
qi::rule<std::string::const_iterator,int(void),ascii::space_type> 
    intRule = qi::int_[f];
qi::phrase_parse(begin, end, intRule, ascii::space, matchedInt);
std::cout << "matched: " << matchedInt << std::endl;
....

Este é um exemplo muito simples que apenas mapas analisado o valor para o atributo de saída valor, mas as extensões devem ser bastante aparente.Basta fazer o contexto struct parâmetros do modelo correspondem à regra de saída, de entrada e de tipos de locais.Note que este tipo de uma correspondência direta entre analisado o tipo/valor para o tipo de saída/valor pode ser feito automaticamente usando o auto de regras, com um %= em vez de um = quando definir a regra:

qi::rule<std::string::const_iterator,int(void),ascii::space_type> 
    intRule %= qi::int_;

IMHO, escrever uma função para cada ação poderia ser um pouco entediante, em comparação com o breve e legível phoenix expressão equivalentes.Eu simpatizo com o voodoo ponto de vista, mas uma vez que você trabalhar com o phoenix, por um pouco, a semântica e a sintaxe não são terrivelmente difícil.

Editar:Aceder a regra de contexto w/ Phoenix

A variável de contexto só é definido quando o analisador é parte de uma regra.Pense em um analisador como sendo qualquer expressão que consome de entrada, onde uma regra traduz o analisador de valores (qi::_1) em uma regra de valor (qi::_val).A diferença é que, muitas vezes, não trivial, por exemplo, quando qi::val tem um tipo de Classe que precisa ser construído a partir de POD valores analisados.Abaixo está um exemplo simples.

Vamos dizer que parte da nossa entrada é uma sequência de três CSV números inteiros (x1, x2, x3), e nós só a assistência de uma função aritmética desses três números inteiros (f = x0 + (x1+x2)*x3 ), onde x0 é um valor obtido em outros lugares.Uma opção é ler os números inteiros e calcular a função, ou, em alternativa, usar o phoenix para ambos.

Para este exemplo, use uma regra com um atributo de saída (o valor da função), e de entrada (x0), e local (para passar informações entre o indivíduo analisadores com a regra).Aqui está o exemplo completo.

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
#include <iostream>

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

int main(void){
   std::string input("1234, 6543, 42");
   std::string::const_iterator begin = input.begin(), end = input.end();

   qi::rule<
      std::string::const_iterator,
      int(int),                    //output (_val) and input (_r1)
      qi::locals<int>,             //local int (_a)
      ascii::space_type
   >
      intRule =
            qi::int_[qi::_a = qi::_1]             //local = x1
         >> ","
         >> qi::int_[qi::_a += qi::_1]            //local = x1 + x2
         >> ","
         >> qi::int_
            [
               qi::_val = qi::_a*qi::_1 + qi::_r1 //output = local*x3 + x0
            ];

   int ruleValue, x0 = 10;
   qi::phrase_parse(begin, end, intRule(x0), ascii::space, ruleValue);
   std::cout << "rule value: " << ruleValue << std::endl;
   return 0;
}

Em alternativa, todos os ints poderia ser analisado como um vetor, e a função avaliado com uma única semântica da ação (o % abaixo está a lista de operador e de elementos do vetor são acessados com phoenix::at):

namespace ph = boost::phoenix;
...
    qi::rule<
        std::string::const_iterator,
        int(int),
        ascii::space_type
    >
    intRule =
        (qi::int_ % ",")
        [
            qi::_val = (ph::at(qi::_1,0) + ph::at(qi::_1,1))
                      * ph::at(qi::_1,2) + qi::_r1
        ];
....

Para o acima, se a entrada está incorreta (dois ints, em vez de três), coisa ruim poderia acontecer em tempo de execução, então seria melhor para especificar o número de valores analisados explicitamente, portanto, a análise irá falhar para uma entrada incorreta.A seguir usa _1, _2, e _3 para fazer referência a primeira, a segunda e a terceira partida valor:

(qi::int_ >> "," >> qi::int_ >> "," >> qi::int_)
[
    qi::_val = (qi::_1 + qi::_2) * qi::_3 + qi::_r1
];

Este é um exemplo imaginário, mas deve dar-lhe a idéia.Eu encontrei phoenix semântica ações realmente útil na construção de objetos complexos directamente a partir da entrada;isso é possível porque você pode chamar de construtores e de funções membro dentro da semântica de ações.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top