2016-11-01 1 views
2

Je suis un débutant Boost.Qi, alors j'essaie quelques exemples simples pour essayer de me faire une idée. Je suis en train d'analyser une chaîne qui ressemble à:Boost.Qi erreur du compilateur avec l'analyseur en option

A:1  B:2   C:3 

Il y a un nombre quelconque d'espaces entre chaque composant dans la chaîne. Les portions A:, etc. sont corrigées et je voudrais analyser les valeurs entières. Le troisième composant de la chaîne, C:3 dans l'exemple ci-dessus, est facultatif. Je suis venu avec l'exemple simple suivant pour tester Boost.Qi pour cette application:

#include <boost/optional.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <iostream> 

namespace qi = boost::spirit::qi; 

int main() 
{ 
    std::string s = "A:1 B:2   C:3"; 

    int a, b; 
    boost::optional<int> c; 

    if (!qi::parse(s.begin(), s.end(), 
     qi::lit("A:") >> qi::int_ >> +qi::space >> "B:" >> qi::int_ >> 
      -(+qi::space >> "C:" >> qi::int_), a, b, c)) 
    { 
     std::cout << "failed to parse" << std::endl; 
    } 

    std::cout << a << ' ' << b << ' ' << c.value_or(-1) << std::endl; 
} 

Toutefois, cela ne peut pas compiler (en utilisant Boost v1.58 et g ++ 5.4.0 en mode 11 C de). Dans la mer typique des messages d'erreur de modèle de C, je trouve les suivantes:

spirit.cc:15:55: required from here 
/usr/include/boost/spirit/home/support/container.hpp:130:12: error: ‘int’ is not a class, struct, or union type 
    struct container_value 

et

spirit.cc:15:55: required from here 
/usr/include/boost/spirit/home/qi/detail/pass_container.hpp:316:66: error: no type named ‘type’ in ‘struct boost::spirit::traits::container_value<int, void>’ 
      typedef typename traits::container_value<Attr>::type value_type; 
                   ^
/usr/include/boost/spirit/home/qi/detail/pass_container.hpp:329:15: error: no type named ‘type’ in ‘struct boost::spirit::traits::container_value<int, void>’ 

Est-il évident à tout le monde ce que je fais mal ici?

+0

Je pense que vous devez explicitement [Omettre] (http://www.boost.org/doc/libs/1_60_0/libs/spirit/doc /html/spirit/qi/reference/directive/omit.html) les deux occurrences de '+ qi :: space', puisque son attribut ne vous intéresse pas. –

Répondre

3

Votre grammaire originale ressemble à ceci (avec une mise en forme):

qi::lit("A:") 
>> qi::int_ 
>> +qi::space 
>> qi::lit("B:") 
>> qi::int_ 
>> -( +qi::space 
    >> qi::lit("C:") 
    >> qi::int_ 
    ) 

Il est important de noter l'attribut types chacun des terminaux génère:

En outre, notez les règles pertinentes pour compound attributes.

Sur cette base, vous avez fait:

  • entier
  • vecteur de caractères (en raison de la +)
  • entier
  • en option (en raison du -) tuple (en raison du >>) de
    • vecteur de caractère (en raison du +)
    • entier

Cela ne correspond pas à ce que vous appelez parse avec.

La clé consiste à utiliser la directive omit pour supprimer les attributs qui ne vous intéressent pas.

La grammaire correcte dans ce cas serait:

qi::lit("A:") 
>> qi::int_ 
>> qi::omit[+qi::space] 
>> qi::lit("B:") 
>> qi::int_ 
>> -( qi::omit[+qi::space] 
    >> qi::lit("C:") 
    >> qi::int_ 
    ) 
+0

Excellente explication; Merci. J'ai pensé par erreur que 'qi :: space' était l'un des types d'analyseurs qui n'ont pas d'attribut associé (comme' qi :: lit'). Votre réponse est claire. –

4

Une façon de résoudre ce problème pourrait être à l'aide phrase_parse et qi::space skipper:

if (!qi::phrase_parse(s.begin(), s.end(), 
     qi::lit("A:") >> qi::int_ >> "B:" >> qi::int_ >> -("C:" >> qi::int_), qi::space, a, b, c)) 
+1

Cela fonctionne également (et est en fait une implémentation plus simple), donc c'est probablement le chemin à parcourir. J'ai accepté l'autre réponse parce qu'elle donnait une explication détaillée de la raison pour laquelle mon exemple était faux. Merci pour cette contribution. –

+0

@JasonR Oui, je dirais aussi que ce serait le chemin à suivre, car vous voulez passer les espaces de toute façon. –