Boost.Spirit.Qi: Prenez l'attribut d'une règle et le définir comme un champ d'un attribut struct de règle englobante?

StackOverflow https://stackoverflow.com/questions/4620016

Question

Comme, bon nombre de ces questions, je suis en train d'analyser une grammaire simple dans un arbre de struct, en utilisant Boost.Spirit.Qi.

Je vais essayer de distiller ce que je suis en train de faire pour le cas le plus simple possible. J'ai:

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

Plus tard, à l'intérieur d'une struct de grammaire, je la variable membre suivant:

qi::rule<Iterator, Integer> integer;

que je suis avec la définition

integer = qi::int_;

Lorsque je tente d'analyser réellement un entier, cependant, en utilisant

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

myInteger.value est toujours non initialisée après une analyse syntaxique réussie. De même, je l'ai essayé les définitions suivantes (évidemment les ceux qui ne les compile pas sont mal):

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

Il est clair que je suis malentendu quelque chose Esprit, Phoenix, ou autre chose. Je crois comprendre que qi::_1 est le premier attribut de qi::int_, ici et doit représenter l'entier analysable, lorsque la partie entre crochets est exécuté comme un objet de fonction. Je suis alors en supposant que l'objet de la fonction prendra la integer d'attribut qi::_val et renfermant essayer et attribuer l'entier analysable à lui. Je pense que était à cause de mon appel BOOST_FUSION_ADAPT_STRUCT, les deux seraient compatibles, et qui semble bien être le cas dans une perspective d'analyse statique, mais les données ne sont pas conservées.

Y at-il une référence (et) la désignation Il me manque quelque part ou quelque chose?

Était-ce utile?

La solution

Si entier est censé être l'attribut exposé par la règle, vous devez déclarer comme:

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

(notez la parenthèse). Esprit exige d'utiliser la syntaxe de déclaration de fonction pour décrire « l'interface » de la règle. Il est utilisé non seulement dans l'esprit mais par plusieurs autres bibliothèques aussi bien (voir boost :: fonction par exemple).

La raison principale est que c'est une façon concise agréable de spécifier une interface de fonction. Si vous pensez à ce que la règle est, on se rend compte rapidement qu'il est comme une fonction: il peut renvoyer une valeur (le résultat de l'analyse, à savoir l'attribut synthétisé). En outre, il peut prendre un ou plusieurs arguments (les attributs hérités).

Une seconde, mais la raison mineure est que l'Esprit doit être en mesure de distinguer les différents paramètres du modèle d'une règle. Les paramètres du modèle peuvent être spécifiés dans un ordre quelconque (à l'exception du iterator), donc il a besoin des moyens de déterminer ce qui est quoi. La syntaxe de déclaration de fonction est suffisamment différent du skipper ou le codage (les deux autres paramètres de modèles possibles) pour lui permettre d'être reconnue au moment de la compilation.

Jetons un coup d'œil à vos différentes tentatives:

Cela peut être fait au travail si vous modifiez la définition de la règle comme indiqué ci-dessus.

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

Le _val se réfère à votre Integer, alors que le _1 fait référence à un int. , Vous devez donc définir un opérateur d'affectation de int pour faire ce travail:

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

Vous n'avez pas besoin d'adapter votre type comme une séquence de fusion dans ce cas.

Mais vous pouvez l'écrire encore plus facile:

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

qui est 100% équivalente (EPS est une astuce utilisée pour convertir le côté droit en une séquence de l'analyseur, ce qui permet d'utiliser la propagation d'attribut intégré dans le mappage des éléments de votre adapté séquence Fusion aux attributs des éléments de la séquence).

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

ne fonctionne pas comme _r1 fait référence au premier attribut hérité d'une règle. Cependant, la règle n'a pas d'attributs inherted.

Cela fonctionne:

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

mais ne nécessite pas d'adapter votre type comme une séquence de fusion.

Et il en sera de ceci:

integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; 
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top