2010-10-12 23 views
2

Je viens de commencer à creuser dans Boost :: Spirit, la dernière version à ce jour - V2.4. Le Essense de mon problème est le suivant:Analyser avec Boost :: Spirit (V2.4) dans le conteneur

Je voudrais analyser des chaînes comme « 1A2 » ou « 3B4 ». La règle que j'utilise est:

(double_ >> lit('b') >> double_) 
| (double_ >> lit('a') >> double_); 

L'attribut de la règle doit être « vecteur < à double > ». Et je le lis dans le conteneur.

Le code complet:

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix_core.hpp> 
#include <boost/spirit/include/phoenix_operator.hpp> 

#include <iostream> 
#include <algorithm> 
#include <string> 
#include <vector> 
#include <cstring> 

int main(int argc, char * argv[]) 
{ 
    using namespace std; 
    using namespace boost::spirit; 
    using namespace boost::spirit::qi; 
    using boost::phoenix::arg_names::arg1; 

    char const * first = "1a2"; 
    char const * last = first + std::strlen(first); 
    vector<double> h; 

    rule<char const *, vector<double>()> or_test; 
    or_test %= (double_ >> lit('b') >> double_) 
      | (double_ >> lit('a') >> double_); 

    if (parse(first, last, or_test,h)) { 
      cout << "parse success: "; 
      for_each(h.begin(), h.end(), (cout << arg1 << " ")); 
      cout << "end\n"; 
    } else cout << "parse error\n" << endl; 
    return 0; 
} 

Je compile avec g ++ 4.4.3. Et il renvoie "1 1 2". Alors que je m'attends à "1 2".

Pour autant que je comprends cela arrive parce que l'analyseur:

  • va à la première alternative
  • lit un double_ et le stocke dans le conteneur
  • arrête alors à « un », tout en attendant éclairé ("b")
  • va à la seconde alternative
  • lit deux doubles

Ma question est - Est-ce un comportement correct, et si oui - pourquoi?

Répondre

4

C'est le comportement attendu. Pendant le retour en arrière, Spirit ne «supprime» pas les modifications apportées aux attributs. Par conséquent, vous devez utiliser la directive hold[] forçant explicitement l'analyseur à conserver une copie de l'attribut (permettant de revenir tout changement d'attribut):

or_test =  
     hold[double_ >> lit('b') >> double_)] 
    | (double_ >> lit('a') >> double_) 
    ; 

Cette directive doit être appliquée à toutes les alternatives modifiant l'attribut , sauf le dernier.

+0

Merci pour votre réponse. Désolé pour une question stupide - mais j'ai vraiment lu attentivement la documentation et n'ai rien trouvé à propos d'une telle chose. Puis-je demander un suivi - y a-t-il une meilleure façon de faire la même chose? – Kostya

+0

C'est le meilleur que vous pouvez faire, et je ne vois pas de raison de le faire différemment. Puisque 'hold []' est explicite, vous avez un contrôle total sur le surdébit induit, ce qui permet de le réduire au minimum. – hkaiser