Pergunta

Estou tentando escrever um analisador de idioma Shell no Boost.spirit. No entanto, não estou claro sobre algumas questões básicas sobre semântica de rules.

Olhando para a documentação, existem membros r.alias() e r.copy() do rule. IIUC, esses membros devem devolver uma referência à regra e uma cópia do conteúdo da regra, respectivamente. No entanto, não é especificado claramente o que acontece quando eu apenas uso a regra em uma definição de outra regra. A partir dos meus experimentos, descobri que regras mutuamente recursivas podem ser definidas por:

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

o que sugere que as regras são tomadas por referência nas expressões de analisador. O problema é que o que faz quando a variável sai do escopo, por exemplo:

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

Na mesma nota, atribuiria a uma regra a partir de uma expressão de análise contendo um valor do trabalho de regra do tipo (r.copy() seria um valor do tipo rule também não é)? por exemplo.

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

Alguém pode me esclarecer sobre a semântica detalhada de rulecópias e referências, e possivelmente corrigindo algum equívoco neste post?

Foi útil?

Solução

A resposta depende de qual versão do espírito você está se referindo.


Spirit.Classic (o ex -Spirit V1.X) implementa a semântica de cópias especiais para as regras. A documentação diz:

Quando uma regra é referenciada em qualquer lugar do lado direito de uma expressão de EBNF, a regra é mantida pela expressão por referência. É de responsabilidade do cliente garantir que a regra referenciada permaneça no escopo e não seja destruída enquanto está sendo referenciada.

O operador de atribuição também faz referência à regra do RHS sem criar uma cópia profunda também. Isso foi feito para permitir:

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

Mas isso acabou sendo altamente confuso, pois impedia o manuseio de regras da mesma maneira que os objetos "normais".

Por esse motivo, houve a função de membro rule::copy(), permitindo fazer cópias profundas explícitas de uma regra (por exemplo, para armazená -las em um contêiner STL).

Ao mesmo tempo isso:

r2 = r1.copy();

está completamente errado. r2 se referiria à cópia temporária (destruída) de r1 devolvido da função copy().


Em Spirit.Qi (ou seja, espírito v2.x), o comportamento é parcialmente alterado. As regras agora estão se comportando como esperado quando tratadas fora dos analistas. Você pode armazená -los normalmente em contêineres (o operador de atribuição expõe o comportamento esperado). Mas cuidado, que dentro de uma expressão de analisador as regras ainda são mantidas por referência, que ainda permite se referir a uma regra da mesma maneira que antes:

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

Às vezes é necessário fazer uma cópia profunda de uma regra, então ainda há o membro Functon copy.

A semântica de cópia alterada tem outro efeito colateral. Construções como:

r1 = r2;

agora estão criando uma cópia (profunda) de r2, o que pode não ser o que você espera, especialmente se r2 receberá seu RHS atribuído somente depois de ser "atribuído" a r1. Por esse motivo, existe a nova função de membro alias permitindo a semântica de referência para este caso de canto:

r1 = r2.alias();

De qualquer forma, em ambas as versões do espírito, você acabará com referências pendentes se parte das regras referenciadas de uma expressão de analisador sair do escopo.

Btw, nenhuma versão espiritual implementa uma função rule::ref().

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