Question

Je suis en train d'écrire un analyseur de langage shell dans Boost.Spirit. Cependant, je ne suis pas clair au sujet des questions de base concernant la sémantique de rules.

En regardant la documentation, il y a des membres r.alias() et r.copy() de rule. IIUC, ces membres doit renvoyer une référence à la règle et une copie du contenu de la règle, respectivement. Cependant, il est pas clairement précisé ce qui se passe quand je viens d'utiliser la règle dans une définition d'une autre règle. D'après mes expériences, j'ai trouvé mutuellement des règles récursives peuvent être définies par:

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

qui suggère que les règles sont prises par référence à l'intérieur des expressions de l'analyseur. Le problème est, que fait-il lorsque la variable est hors de portée, par exemple:

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

Sur la même note, serait attribuer à une règle d'une expression d'analyse syntaxique contenant un rvalue de type travail de règle (r.copy() n'est pas un rvalue de type rule aussi)? par exemple.

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

Quelqu'un peut-il me éclairer sur la sémantique détaillée des copies de rule et des références, et éventuellement corriger les idées fausses dans ce poste?

Était-ce utile?

La solution

La réponse dépend de la version de l'Esprit vous faites référence.


Spirit.Classic (l'ex-Esprit V1.x) met en œuvre la sémantique de copie spéciales pour les règles. La documentation dit:

  

Quand est fait référence à une règle partout dans   le côté droit d'un EBNF   expression, la règle est tenue par le   expression par référence. C'est le   la responsabilité du client d'assurer   que les séjours de règles mentionnées dans   champ d'application et ne pas se destructed   alors qu'il est référencé.

L'opérateur d'affectation fait référence essentiellement les rhs règle sans créer une copie en profondeur aussi bien. Cela a été fait pour permettre:

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

Mais cela se révèle être très confusion car il a empêché les règles de manipulation de la même manière que les objets « normaux ».

Pour cette raison, il y avait la fonction membre rule::copy(), ce qui permet de faire des copies profondes explicites d'une règle (par exemple pour les stocker dans un conteneur STL).

En même temps ceci:

r2 = r1.copy();

est faux. r2 se référer à la (destructed) copie temporaire de r1 renvoyée par la fonction copy().


Dans Spirit.Qi (à savoir Spirit V2.x) le comportement est partiellement modifié. les règles sont maintenant comporte comme prévu lorsqu'il est manipulé à l'extérieur de parseurs. Vous pouvez les stocker dans des conteneurs normalement (l'opérateur d'affectation expose le comportement attendu). Mais méfiez-vous, que l'intérieur d'une des règles d'expression parser sont toujours détenus par référence, ce qui permet encore de se référer à une règle de la même manière que précédemment:

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

Il est parfois nécessaire de faire une copie en profondeur d'une règle, donc il y a encore membre functon copy.

La sémantique de copie ont changé un autre effet secondaire. Comme Constructs:

r1 = r2;

sont en train de créer une (profonde) copie de r2, ce qui pourrait ne pas être ce que vous attendez, surtout si r2 aura son rhs attribué seulement après avoir été « attribué » à r1. Pour cette raison, il y a la nouvelle alias fonction membre permettant la sémantique de référence pour ce cas d'angle:

r1 = r2.alias();

Dans tous les cas, dans les deux versions de l'Esprit vous finira avec ballants références si une partie des règles référencées à partir d'une expression de l'analyseur hors de portée.

BTW, ni la version Spirit met en œuvre une rule::ref() fonction.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top