2011-01-06 3 views
6

Al igual que muchas de estas otras preguntas, estoy tratando de analizar una gramática simple en un árbol de estructuras usando Boost.Spirit.Qi.Boost.Spirit.Qi: ¿Toma el atributo de una regla y lo establece como un campo del atributo de estructura de una regla circundante?

Trataré de destilar lo que estoy tratando de hacer con el caso más simple posible. Tengo:

struct Integer { 
    int value; 
}; 
BOOST_FUSION_ADAPT_STRUCT(Integer, (int, value)) 

Más tarde, en el interior de una estructura gramatical, tengo la siguiente variable miembro:

qi::rule<Iterator, Integer> integer; 

la que estoy definiendo con

integer = qi::int_; 

cuando trato de analizar realidad un entero, sin embargo, usando

qi::phrase_parse(iter, end, g, space, myInteger); 

myInteger.value siempre se desinicializa después de un análisis correcto. Del mismo modo, me han tratado las siguientes definiciones (obviamente los que no compilan están equivocados):

integer = qi::int_[qi::_val = qi::_1]; //compiles, uninitialized value 
integer = qi::int_[qi::_r1 = qi::_1]; //doesn't compile 
integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1]; //doesn't 
integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; //doesn't 

Claramente estoy mal entendido algo de alcohol, Phoenix, o alguna otra cosa. Mi entendimiento es que qi::_1 es el primer atributo de qi::int_, aquí, y debe representar el entero analizado, cuando la parte entre corchetes se ejecuta como un objeto de función. Entonces estoy suponiendo que el objeto de función tomará el atributo integer adjunto qi::_val e intentará asignarle el entero analizado. Supongo que debido a mi llamada BOOST_FUSION_ADAPT_STRUCT, las dos serían compatibles, y ciertamente parece ser el caso desde una perspectiva de análisis estático, pero los datos no se conservan.

¿Existe una designación de referencia (&) que me falta en algún lado o algo así?

+0

acabo de encontrar otra combinación que compila, a pesar de que no se traduce en datos inicializados: He añadido un constructor de 'Integer' que toma un valor de' valor' , luego definí mi analizador 'entero 'como' integer = qi :: long_long [qi :: _ val = phx :: constructo (qi :: _ 1)]; ' – jtolds

+0

oops, quiero decir' qi :: int_' – jtolds

+0

más depuración notas. en mi código completo, en realidad tengo 'qi :: rule integer;', que parece que se rompe si reemplazo 'Integer' con' Integer() ', y todos los ejemplos tienen el final '()', que descuidé. Entonces quizás los argumentos de la plantilla a la 'regla 'se estaban arruinando. Excavación. – jtolds

Respuesta

13

Si Entero se supone que es el atributo expuesta por la regla, tiene que declarar como:

qi::rule<Iterator, Integer()> integer; 

(tenga en cuenta el paréntesis). Spirit requiere utilizar la sintaxis de declaración de función para describir la 'interfaz' de la regla. Se usa no solo en Spirit, sino también en varias otras bibliotecas (ver boost :: function por ejemplo).

La razón principal de esto es que es una buena manera concisa de especificar una interfaz de función. Si piensas qué es una regla, rápidamente te das cuenta de que es como una función: puede devolver un valor (el resultado analizado, es decir, atributo sintetizado). Además, puede tomar uno o más argumentos (los atributos heredados).

Una segunda razón menor es que Spirit necesita poder distinguir los diferentes parámetros de plantilla de una regla. Los parámetros de la plantilla se pueden especificar en cualquier orden (a excepción del iterador), por lo que se necesitan algunos medios para descubrir qué es qué. La sintaxis de declaración de función es suficientemente diferente del patrón o la codificación (los otros dos posibles parámetros de plantilla) para permitir que se reconozca en tiempo de compilación.

Vamos a echar un vistazo a sus diferentes intentos:

Esto puede hacerse funcionar si cambia la definición de la regla como se indicó anteriormente.

integer = qi::int_[qi::_val = qi::_1]; 

El _val se refiere a su Integer, mientras que el _1 se refiere a un int. Por lo tanto, es necesario definir un operador de asignación de int para hacer este trabajo:

struct Integer { 
    int value; 
    Integer& operator=(int) {...} 
};      

No es necesario para adaptarse a su tipo como una secuencia de fusión en este caso.

Pero se puede escribir aún más fácil:

integer = qi::int_ >> qi::eps; 

que es 100% equivalente (las EPS es un truco utilizado para convertir el lado derecho en una secuencia de programa de análisis, lo que permite utilizar el built-in la propagación de atributos mapeando los elementos de su secuencia Fusion adaptada a los atributos de los elementos de la secuencia).

Este:

integer = qi::int_[qi::_r1 = qi::_1]; 

no funcionará como _r1 se refiere al primer atributo heredado de una regla. Sin embargo, su regla no tiene atributos inhertados.

Esto funcionará:

integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1]; 

pero no requiere adaptar su tipo como una secuencia de fusión.

Y también esto:

integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; 
+0

oh hermoso, gracias. así que parece que tuve un error de plantilla todo el tiempo. – jtolds

+2

'git commit -a -m '¡Hartmut Kaiser es el hombre!' ' – jtolds

Cuestiones relacionadas