2010-08-12 4 views
10

Estoy tratando de escribir un analizador de lenguaje de shell en Boost.Spirit. Sin embargo, no estoy seguro acerca de algunos problemas básicos relacionados con la semántica de rule s.Copia o semántica de referencia de boost :: spirit's rule <>?

En cuanto a la documentación, hay miembros r.alias() y r.copy() de rule. IIUC, estos miembros deben devolver una referencia a la regla y una copia del contenido de la regla, respectivamente. Sin embargo, no se especifica claramente qué sucede cuando solo uso la regla en una definición de otra regla. De mis experimentos, encontré mutuamente reglas recursivas puede ser definido por:

rule<Iter> r1, r2; 
r1 = ... >> r2 >> ...; 
r2 = ... >> r1 >> ...; 

que sugiere las reglas se toman como referencia dentro de expresiones del analizador. El problema es, ¿qué hacer cuando la variable se sale del ámbito, por ejemplo:

rule<Iter> r1; 
{ 
    rule<Iter> r2; 
    r1 = ... >> r2 >> ...; 
    r2 = ... >> r1 >> ...; 
} 
... // use r1 

En la misma nota, sería asignar a una regla de una expresión de análisis que contiene un valor de lado derecho del trabajo regla de tipo (r.copy() sería un rvalue de tipo rule también, ¿no es así? p.ej.

rule<Iter> f() { return char_('a') << char_('b'); } 
rule<Iter> r1 = ... << f(); 

Puede alguien me ilumine en la semántica detalladas de copias y referencias rule 's, y posiblemente corregir cualquier malentendido en este post?

Respuesta

13

La respuesta depende de la versión de Spirit a la que se refiera.


Spirit.Classic (el anterior Spirit V1.x) implementa una semántica de copia especial para las reglas. La documentación dice:

Cuando una regla se hace referencia a cualquier parte el lado derecho de una expresión EBNF , la regla está en manos de la expresión por referencia. Es la responsabilidad del cliente asegurarse de que la regla referenciada permanece en el alcance y no se destruye mientras se está haciendo referencia a ella.

El operador de asignación hace referencia esencialmente a la regla de rhs sin crear una copia profunda también. Esto se hizo para permitir:

rule<> r1, r2; 
r1 = ...; 
r2 = r1; 

Pero esto resultó ser altamente confusión ya que impedía el manejo gobierna la misma manera que los objetos 'normales'.

Por esa razón, estaba la función de miembro rule::copy(), que permite hacer copias profundas explícitas de una regla (por ejemplo, para almacenarlas en un contenedor STL).

Al mismo tiempo esto:

r2 = r1.copy(); 

está mal llano. r2 se referiría a la copia temporal (destruida) de r1 devuelta desde la función copy().


En Spirit.Qi (es decir, Spirit V2.x), el comportamiento ha cambiado parcialmente.las reglas ahora se comportan como se espera cuando se manejan fuera de los analizadores. Puede almacenarlos normalmente en contenedores (el operador de asignación expone el comportamiento esperado). Pero cuidado, que dentro de un analizador de reglas de expresión están todavía en poder de referencia, que todavía permite hacer referencia a una regla de la misma manera que antes:

rule<> r1, r2; 
r1 = ... >> r2 >> ...; 
r2 = ... >> r1 >> ...; 

A veces es necesario hacer una copia en profundidad de la norma, por lo que hay sigue siendo el miembro functon copy.

La semántica de copia modificada tiene otro efecto secundario. Construcciones como:

r1 = r2; 

están creando una copia (de profundidad) de r2, que podría no ser lo que se espera, sobre todo si r2 tendrá su RHS asignados solamente después de haber sido 'asignado' a r1. Por eso existe la nueva función miembro alias que permiten la semántica de referencia para este caso esquina:

r1 = r2.alias(); 

En cualquier caso, en ambas versiones del Espíritu que va a terminar con referencias pendientes si parte de las reglas de referencia desde un analizador expresión fuera de alcance.

Por cierto, ninguna versión de Spirit implementa una función rule::ref().

+0

Gracias por esta respuesta. Solo tengo una pregunta de seguimiento: ¿es posible de todos modos utilizar valores r (temporales) de expresiones de analizador de algún tipo en la expresión del analizador para permitir enunciados como 'r1 = r1 | string ("abc") 'o generar reglas en una función? – jpalecek

+0

Mientras que la expresión 'r1 = r1 | string ("abc") 'es teóricamente posible, es una recursividad a la izquierda, que dará como resultado una recursión infinita ya que Spirit genera analizadores de descenso recursivos. Pero la expresión 'r1 = cadena (' abc ') | r1 'funcionará como se esperaba. Puede generar una regla en una función si se asegura de que no se refiera a ninguna otra regla, que salió del alcance. Además, en Spirit.Classic necesita devolver r.copy() de la función. – hkaiser

+0

'r1 = cadena ("abc") | r1 'es también recursión a la izquierda :) Pero lo que quería hacer es hacer que r1 coincida con lo que r1 hizo coincidir antes y "abc". Por cierto, ¿cómo puedo generar una regla en una función? Esto no funciona para mí: http://pastebin.org/482764 – jpalecek

Cuestiones relacionadas