IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Boost C++ Discussion :

boost::spirit utilisation des arguments


Sujet :

Boost C++

  1. #1
    Membre actif Avatar de SKone
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 333
    Points : 250
    Points
    250
    Par défaut boost::spirit utilisation des arguments
    Bonsoir,
    A la découverte de boost::spirit je me suis dit qu'un outil comme celui là ne pourrait qu'accélérer le développement de mes parsers. Mais je n'arrive pas à faire ce dont j'ai besoin. A terme je voudrais faire un parsers de fonction ( C-like ) que je pourrait appeler dans mon code. Les fonctions étant entrées dynamiquement... Bref je n'en suis pas encore là !

    Je voudrais simplement appeler une fonction voici mon parser issus d'un exemple que j'essaye d'upgrader :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    typedef std::string::const_iterator	Iterator;
    typedef float						TYPE;
     
    struct Calculator :
    	boost::spirit::qi::grammar< Iterator, TYPE() >
    {
    	Calculator() :
    		Calculator::base_type( expr )
    	{
    		using boost::spirit::qi::word;
    		using boost::spirit::qi::float_;
    		using boost::spirit::qi::_1;
    		using boost::spirit::qi::_val;
     
    		expr =
    			term					[ _val =	_1 ]
    			>>	*(	'+' >> term		[ _val +=	_1 ]
    				|	'-' >> term		[ _val -=	_1 ]
    				);
     
    		term =
    			factor					[ _val =	_1 ]
    			>>	*(	'*' >> factor	[ _val *=	_1 ]
    				|	'/' >> factor	[ _val /=	_1 ]
    				|	'^' >> factor	[ _val = Math::Pow( _val, _1 ) ]
    				);
     
    		factor =
    				float_				[ _val =  _1 ]
    			//|	func_call
    			|	'(' >> expr			[ _val =  _1 ] >> ')'
    			|	'-' >> factor		[ _val -= _1 ]
    			|	'+' >> factor		[ _val =  _1 ]
    			;
     
    		/*func_call =
    				word				[ m_sFunctionName = _1() ]
    				>> '(' >> -( expr	[ m_oParams.push( _1 ) ]
    				>> *( ',' >> expr	[ m_oParams.push( _1 ) ]	) ) >> ')';*/
    	}
     
    	boost::spirit::qi::rule< Iterator, TYPE() > expr, term, factor/*, func_call*/;
     
    private:
    	//std::stack< boost::phoenix::actor< boost::spirit::argument< 0 > > >		m_oParams;
    	//std::string												m_sFunctionName;
    };
     
    	// Dans mon Main :
    	Calculator oCalc;
    	float32 fResult;
    	Iterator oBegin = sInput.begin();
    	Iterator oEnd = sInput.end();
    	bool bRet = parse( oBegin, oEnd, oCalc, fResult );
    	if ( bRet )
    	{
    		cout << sInput << " = " << fResult << endl;
    	}
    Le problème vient de la ligne qui contient Math:ow(). En effet je ne peux pas faire cela puisque mon Pow prend soit un float, soit un double ou soit un long double. _val est de type : boost::phoenix::actor< boost::spirit::argument< 0 > >. J'ai essayé d'évalué la lambda expression avec l'opérateur (). Mais rien n'y fait je n'arrive toujours pas à retrouver la valeur.

    Voilà mon problème. Les opérateurs de base on été surchargées pour les lambdas (+, -, <<, ...). Mais comment faire pour récupérer les valeurs de mes arguments, pour les utiliser avec des types de base du C++ ?

  2. #2
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Bonjour,
    Est-ce que tu aurais un exemple *minimale et compilable* reproduisant le problème ? C'est particulièrement difficile avec Spirit de comprendre d’où provient une erreur sans pouvoir essayer et compiler soi-même.

  3. #3
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Ok, j'ai finalement réussi à comprendre quand même.

    A la découverte de boost::spirit je me suis dit qu'un outil comme celui là ne pourrait qu'accélérer le développement de mes parsers. Mais je n'arrive pas à faire ce dont j'ai besoin.
    Symptomatique de spirit.

    Ok, si je prends la ligne de ton code qui cause problème, en remplaçant Math::pow par std::pow :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    |	'^' >> factor	[ _val = std::pow( _val, _1 ) ]
    Ce genre de code est impossible. On ne peut pas insérer des fonctions classiques dans les actions de Spirit. Tout simplement car, comme tu l'as découvert, les placeholers comme _val et _1 ont leur propre type qui n'est pas du tout compatible avec std::pow qui attend des double.

    Si l'on veut pouvoir insérer ses propres fonctions dans des actions, alors il faut par un moyen ou un autre les wrapper pour en faire des fonctions compatibles phoenix. Le moyen le plus simple pour cela est d'utiliser un binder comme par exemple boost::phoenix::bind.

    Il est donc très courant de voir du code comme ci-dessous dans les actions :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    using boost::phoenix::bind;
    //...
    | '^' >> factor     [ _val = bind(&std::pow, _val, _1) ]
    Sauf que manque de bol, std::pow est un cas particulier qui ne fonctionne pas directement avec bind. Car en fait ce qu'il se passe c'est que la fonction std::pow possède de nombreuses surcharges différentes (std::pow(double, double), std::pow(float, float), std::pow(int, int) etc) donc bind se plaint car il ne sait pas laquelle de ces surcharges choisir.

    La solution est donc en fait ici de caster le pointer de fonction &std::pow vers le type de pointeur de fonction de la surcharge qui nous intéresse, c'est à dire ici double(*)(double, double) au moyen d'un static_cast :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    using boost::phoenix::bind;
    //...
    | '^' >> factor     [ _val = bind(static_cast<double(*)(double, double)(&std::pow), _val, _1) ]
    Et là ça compile.

    Une autre solution est de faire son wrapper à la main, sans passer par le raccourci de phoenix::bind :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    struct pow_imp
    {
        template <typename Arg1, typename Arg2>
        struct result { typedef Arg1 type; };
     
        template <typename Arg1, typename Arg2>
        Arg1 operator()(const Arg1& arg1, const Arg2& arg2) const
        {
    	return std::pow(arg1, arg2);
        }
    };
    boost::phoenix::function<pow_imp> pow_func;
    //...
    //...
    //...
    |	'^' >> factor	[ _val = pow_func( _val, _1 ) ]

  4. #4
    Membre actif Avatar de SKone
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 333
    Points : 250
    Points
    250
    Par défaut
    Merci. Pour le pow cela fonctionne sans problème. Mais auriez vous une solution pour mes appels de fonction ?
    Je voudrais gérer ça avec une pile d'argument (std::stack<float>) et un std::string pour le nom de la fonction. J'ai un manageur de fonction qui avec un std::string me retourne le pointeur de fonction adéquat.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    func_call =
    	word			[ m_sFunctionName = _1() ]
    	>> '(' >> -( expr	[ m_oParams.push( _1 ) ]
    	>> *( ',' >> expr	[ m_oParams.push( _1 ) ]	) )
    // Bref ici ce serait un peu plus complexe mais l'idée est là...
    	>> ')'			[ _val = bind( &FuncManager[m_sFunctionName], m_oParams.top(), ... )];
    	}
     
    	boost::spirit::qi::rule< Iterator, TYPE() > expr, term, factor, func_call;
     
    private:
    	std::stack< float > >		m_oParams;
    	std::string				m_oFunctionName;

  5. #5
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Salut

    je fais ça mais j'utilise une structure de donnée dans laquelle sont stockés les appels de fonctions, et ensuite j'exécute. Ca permet par exemple de pouvoir ré-exécuter une fonction sans avoir besoin de repasser par l'étape de parsing.

    Mon code est dispo ici : https://github.com/duckie/CppCompactExpressionParser et libre de droit
    Find me on github

  6. #6
    Membre actif Avatar de SKone
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 333
    Points : 250
    Points
    250
    Par défaut
    Ah ! J'ai regardé dans tout les sens votre code et j'aime bien la manière dont vous avez solvé mon problème. Une dernière question. Est-il possible à l'utilisateur de définir une fonction au Run-Time que l'on puisse utilisé au Run-Time. Par exemple avec votre "Master" méthode (celle qui m'intéresse le plus). Je voudrais pouvoir faire un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Expression oExp;
    std::string sInput;
    while( true )
    {
    getline( cin, sInput );
    // je remplace mes variables par les fonctions arg0, ... (les UserArg)
    // Je voudrais register cette fonction pour pouvoir l'utilisé dans le prochain 
    // passage de boucle
    }
    J'espère que vous voyez ce que je veux dire. Je voudrais savoir si c'est possible.

    Merci

  7. #7
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par SKone Voir le message
    J'espère que vous voyez ce que je veux dire. Je voudrais savoir si c'est possible.
    Ben non je vois pas très bien ce que tu veux dire.
    T'aurais un exemple de ce que peut taper l'utilisateur sur cin ?

  8. #8
    Membre actif Avatar de SKone
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 333
    Points : 250
    Points
    250
    Par défaut
    Peut-être en utilisant la lib de jblecanard. Je voudrais faire un dans le sin :
    Je voudrais associé le string "Func" avec la fonction suivante :
    2*_1 + time()*sin( _2 )/_1 // Les _1 et _2 sont les variables
    Et au prochain parsing pouvoir faire :
    2*Func( _2, 7.12 )/_1

    L'application concrète c'est que je veux pouvoir définir des fonctions dynamiquement dans un fichier XML de la manière suivante :
    <Function name="Func0" value="2*_1 + time()*sin( _2 )/_1" />
    <Function name="Func1" value="2*Func( _2, 7.12 )/_1" />
    <Function name="GaussLike" value="e()^(_1*_1)" />
    ...
    Et ainsi de suite... Le reste de mon XML me permet de définir des comportements avec ces fonctions que j'utiliserais de la manière suivante :
    <Truc Type="Func" var1="positionX" var2="positionY" value="Func1" />
    <Truc Type="Func" var1="density" value="GaussLike" />

    En gros mes truc je passerais en paramètre les positions X, Y, la densité, ... J'ai comme ça des variables à envoyé par défaut. Mais je peux aussi mettre en var1, 2, ... Des constantes. Voilà pour le parsing XML c'est fait c'est les fonctions qui me pause problème...

  9. #9
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Salut !

    Oui c'est possible, le dernier exemple montre comment réutiliser les "Arg" dans plusieurs expressions différentes, ainsi que comment changer la valeur des arguments pour les réutiliser.

    Je ne vois pas où est ce que tu coinces en fait, peux tu être plus explicite ?

    Edit : J'ai compris ce que tu veux faire. Je vais réfléchir un peu, je ne puis pas répondre par oui ou non facilement
    Edit 2 : Oui, c'est possible, c'est même pas trop difficile. Je publierais un exemple ce soir si tu veux.
    Find me on github

  10. #10
    Membre actif Avatar de SKone
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 333
    Points : 250
    Points
    250
    Par défaut
    Oui j'aimerais bien un exemple...
    Merci

  11. #11
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Salut !

    L'outil a été mis à jour avec un exemple de cette fonctionnalité. https://github.com/duckie/CppCompactExpressionParser
    Find me on github

  12. #12
    Membre actif Avatar de SKone
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2004
    Messages
    333
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2004
    Messages : 333
    Points : 250
    Points
    250
    Par défaut
    Merci...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 17/02/2013, 00h41
  2. [XL-2003] Utilisation des arguments dans Application.Run
    Par PAD095 dans le forum Macros et VBA Excel
    Réponses: 0
    Dernier message: 20/06/2011, 18h45
  3. Réponses: 6
    Dernier message: 05/05/2010, 16h21
  4. [ksh et/ou bash] Utilisation des arguments type -d
    Par novices dans le forum Shell et commandes GNU
    Réponses: 7
    Dernier message: 24/11/2007, 15h04
  5. Réponses: 6
    Dernier message: 21/12/2005, 19h52

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo